package python import ( "context" "fmt" "io" "kube-forge/internal/logging" "kube-forge/internal/python/data" "kube-forge/internal/resources" "os" "os/exec" "path/filepath" executable "github.com/apenella/go-ansible/v2/pkg/execute/exec" "github.com/kluctl/go-embed-python/embed_util" "github.com/kluctl/go-embed-python/python" ) type PythonExec struct { ep *python.EmbeddedPython PythonLibFsPath string ResourcesFsPath string } type CmdWrapper struct { *exec.Cmd } func (c *CmdWrapper) CombinedOutput() ([]byte, error) { return c.Cmd.CombinedOutput() } func (c *CmdWrapper) Environ() []string { return c.Cmd.Environ() } func (c *CmdWrapper) Output() ([]byte, error) { return c.Cmd.Output() } func (c *CmdWrapper) Run() error { return c.Cmd.Run() } func (c *CmdWrapper) Start() error { return c.Cmd.Start() } func (c *CmdWrapper) StderrPipe() (io.ReadCloser, error) { return c.Cmd.StderrPipe() } func (c *CmdWrapper) StdinPipe() (io.WriteCloser, error) { return c.Cmd.StdinPipe() } func (c *CmdWrapper) StdoutPipe() (io.ReadCloser, error) { return c.Cmd.StdoutPipe() } func (c *CmdWrapper) String() string { return c.Cmd.String() } func (c *CmdWrapper) Wait() error { return c.Cmd.Wait() } type ErrorCmd struct { err error } func (e *ErrorCmd) CombinedOutput() ([]byte, error) { return nil, e.err } func (e *ErrorCmd) Environ() []string { return nil } func (e *ErrorCmd) Output() ([]byte, error) { return nil, e.err } func (e *ErrorCmd) Run() error { return e.err } func (e *ErrorCmd) Start() error { return e.err } func (e *ErrorCmd) StderrPipe() (io.ReadCloser, error) { return nil, e.err } func (e *ErrorCmd) StdinPipe() (io.WriteCloser, error) { return nil, e.err } func (e *ErrorCmd) StdoutPipe() (io.ReadCloser, error) { return nil, e.err } func (e *ErrorCmd) String() string { return fmt.Sprintf("ErrorCmd: %v", e.err) } func (e *ErrorCmd) Wait() error { return e.err } func NewPythonExec() *PythonExec { tmpDir := filepath.Join(os.TempDir(), "go-ansible") pythonDir := tmpDir + "-python" pythonLibDir := tmpDir + "-python-lib" resourcesDir := tmpDir + "-resources" pythonLibFs, err := embed_util.NewEmbeddedFilesWithTmpDir(data.Data, pythonLibDir, true) if err != nil { logging.Log.Fatal(err) } pythonLibFsPath := pythonLibFs.GetExtractedPath() resourcesFs, _ := embed_util.NewEmbeddedFilesWithTmpDir(resources.Kubespray, resourcesDir, true) resourcesFsPath := resourcesFs.GetExtractedPath() ep, _ := python.NewEmbeddedPythonWithTmpDir(pythonDir, true) ep.AddPythonPath(pythonLibFs.GetExtractedPath()) ep.AddPythonPath(resourcesFs.GetExtractedPath()) return &PythonExec{ ep: ep, PythonLibFsPath: pythonLibFsPath, ResourcesFsPath: resourcesFsPath, } } func (e *PythonExec) Command(name string, arg ...string) executable.Cmder { cmd := append([]string{name}, arg...) execCmd, err := e.ep.PythonCmd2(cmd) if err != nil { return &ErrorCmd{err: fmt.Errorf("failed to create python command: %w", err)} } return &CmdWrapper{Cmd: execCmd} } func (e *PythonExec) CommandContext(ctx context.Context, name string, arg ...string) executable.Cmder { cmd := append([]string{name}, arg...) execCmd, err := e.ep.PythonCmd2(cmd) if err != nil { return &ErrorCmd{err: fmt.Errorf("failed to create python command: %w", err)} } ctxCmd := exec.CommandContext(ctx, execCmd.Path, execCmd.Args[1:]...) ctxCmd.Env = execCmd.Env ctxCmd.Dir = execCmd.Dir ctxCmd.Stdin = execCmd.Stdin ctxCmd.Stdout = execCmd.Stdout ctxCmd.Stderr = execCmd.Stderr return &CmdWrapper{Cmd: ctxCmd} }