diff --git a/cmd/system_update.go b/cmd/system_update.go index 8f86528..0c301e1 100644 --- a/cmd/system_update.go +++ b/cmd/system_update.go @@ -9,6 +9,7 @@ import ( "github.com/FAU-CDI/wisski-distillery/internal/cli" "github.com/FAU-CDI/wisski-distillery/internal/dis/component" "github.com/FAU-CDI/wisski-distillery/pkg/environment" + "github.com/FAU-CDI/wisski-distillery/pkg/execx" "github.com/FAU-CDI/wisski-distillery/pkg/fsx" "github.com/FAU-CDI/wisski-distillery/pkg/logging" "github.com/tkw1536/goprogram/exit" @@ -195,7 +196,7 @@ func (si systemupdate) mustExec(context wisski_distillery.Context, workdir strin if workdir == "" { workdir = dis.Config.Paths.Root } - code := dis.Still.Environment.Exec(context.Context, context.IOStream, workdir, exe, argv...)() + code := execx.Exec(context.Context, context.IOStream, workdir, exe, argv...)() if code != 0 { err := errMustExecFailed.WithMessageF(code) err.ExitCode = exit.ExitCode(code) diff --git a/internal/config/paths.go b/internal/config/paths.go index 5fd94a6..24f9226 100644 --- a/internal/config/paths.go +++ b/internal/config/paths.go @@ -1,6 +1,7 @@ package config import ( + "os" "path/filepath" "github.com/FAU-CDI/wisski-distillery/internal/bootstrap" @@ -34,7 +35,7 @@ func (pcfg PathsConfig) ExecutablePath() string { // UsingDistilleryExecutable checks if the current process is using the distillery executable func (pcfg PathsConfig) UsingDistilleryExecutable(env environment.Environment) bool { - exe, err := env.Executable() + exe, err := os.Executable() if err != nil { return false } @@ -44,7 +45,7 @@ func (pcfg PathsConfig) UsingDistilleryExecutable(env environment.Environment) b // CurrentExecutable returns the path to the current executable being used. // When it does not exist, falls back to the default executable. func (pcfg PathsConfig) CurrentExecutable(env environment.Environment) string { - exe, err := env.Executable() + exe, err := os.Executable() if err != nil || !fsx.IsFile(env, exe) { return pcfg.ExecutablePath() } diff --git a/internal/dis/component/stack.go b/internal/dis/component/stack.go index bae6a94..7d36489 100644 --- a/internal/dis/component/stack.go +++ b/internal/dis/component/stack.go @@ -10,6 +10,7 @@ import ( "path/filepath" "github.com/FAU-CDI/wisski-distillery/pkg/environment" + "github.com/FAU-CDI/wisski-distillery/pkg/execx" "github.com/FAU-CDI/wisski-distillery/pkg/fsx" "github.com/FAU-CDI/wisski-distillery/pkg/logging" "github.com/FAU-CDI/wisski-distillery/pkg/unpack" @@ -170,12 +171,12 @@ func (ds Stack) Down(ctx context.Context, progress io.Writer) error { func (ds Stack) compose(ctx context.Context, io stream.IOStream, args ...string) func() int { if ds.DockerExecutable == "" { var err error - ds.DockerExecutable, err = ds.Env.LookPathAbs("docker") + ds.DockerExecutable, err = execx.LookPathAbs("docker") if err != nil { return environment.ExecCommandErrorFunc } } - return ds.Env.Exec(ctx, io, ds.Dir, ds.DockerExecutable, append([]string{"compose"}, args...)...) + return execx.Exec(ctx, io, ds.Dir, ds.DockerExecutable, append([]string{"compose"}, args...)...) } // StackWithResources represents a Stack that can be automatically installed from a set of resources. diff --git a/pkg/environment/environment.go b/pkg/environment/environment.go index 68c47f0..66544af 100644 --- a/pkg/environment/environment.go +++ b/pkg/environment/environment.go @@ -6,8 +6,6 @@ import ( "io/fs" "net" "time" - - "github.com/tkw1536/goprogram/stream" ) // Environment represents an environment that a program can run it. @@ -43,10 +41,6 @@ type Environment interface { Listen(network, address string) (net.Listener, error) DialContext(context context.Context, network, address string) (net.Conn, error) - - Executable() (string, error) - Exec(ctx context.Context, io stream.IOStream, workdir string, exe string, argv ...string) func() int - LookPathAbs(name string) (string, error) } type WritableFile interface { diff --git a/pkg/environment/globals.go b/pkg/environment/globals.go index 7e4891d..91e3eb7 100644 --- a/pkg/environment/globals.go +++ b/pkg/environment/globals.go @@ -1,12 +1,10 @@ package environment import ( - "context" "io" "io/fs" "os" - "github.com/tkw1536/goprogram/stream" "github.com/tkw1536/pkglib/pools" ) @@ -70,8 +68,3 @@ func ReadFile(env Environment, path string) ([]byte, error) { // return the buffer contents! return buffer.Bytes(), nil } - -// MustExec is like Exec, except that it returns true if the command exited successfully, and else false. -func MustExec(ctx context.Context, env Environment, io stream.IOStream, workdir string, exe string, argv ...string) bool { - return env.Exec(ctx, io, workdir, exe, argv...)() == 0 -} diff --git a/pkg/environment/native_exec.go b/pkg/execx/execx.go similarity index 63% rename from pkg/environment/native_exec.go rename to pkg/execx/execx.go index f3b0fca..c7c347a 100644 --- a/pkg/environment/native_exec.go +++ b/pkg/execx/execx.go @@ -1,13 +1,24 @@ -package environment +// Package execx provides thin wrappers around the os.Exec package. +package execx + +// TODO: Move this to an external package import ( "context" "os/exec" + "path/filepath" "github.com/rs/zerolog" "github.com/tkw1536/goprogram/stream" ) +// CommandError is returned by Exec when a command could not be executed. +// This typically hints that the executable cannot be found, but may have other causes. +const CommandError = 127 + +// CommandErrorFunc always returns CommandError. +func CommandErrorFunc() int { return CommandError } + // Exec executes a system command with the specified input/output streams, working directory, and arguments. // // The command is started immediatly. @@ -15,7 +26,7 @@ import ( // // If the command executes, the returns the exit code as soon as the process executes. // If the command can not be executed, the returned function is [ExecCommandErrorFunc] and returns [ExecCommandError]. -func (*Native) Exec(ctx context.Context, io stream.IOStream, workdir string, exe string, argv ...string) func() int { +func Exec(ctx context.Context, io stream.IOStream, workdir string, exe string, argv ...string) func() int { // setup the command cmd := exec.Command(exe, argv...) cmd.Dir = workdir @@ -25,14 +36,14 @@ func (*Native) Exec(ctx context.Context, io stream.IOStream, workdir string, exe // context is already cancelled, don't run it! if err := ctx.Err(); err != nil { - return ExecCommandErrorFunc + return CommandErrorFunc } // start the command, but if something happens, return nil err := cmd.Start() zerolog.Ctx(ctx).Debug().Str("exe", exe).Strs("argv", argv).Err(err).Msg("exec.Command.Start") if err != nil { - return ExecCommandErrorFunc + return CommandErrorFunc } waitdone := make(chan struct{}) // closed once Wait() below returns @@ -65,17 +76,23 @@ func (*Native) Exec(ctx context.Context, io stream.IOStream, workdir string, exe } if err != nil { - return ExecCommandError + return CommandError } return 0 } } -func (n *Native) LookPathAbs(file string) (string, error) { +// MustExec is like Exec, except that it returns true if the command exited successfully, and else false. +func MustExec(ctx context.Context, io stream.IOStream, workdir string, exe string, argv ...string) bool { + return Exec(ctx, io, workdir, exe, argv...)() == 0 +} + +// LookPathAbs looks for the path named "file" and then resolves this path absolutely. +func LookPathAbs(file string) (string, error) { path, err := exec.LookPath(file) if err != nil { return "", err } - return n.Abs(path) + return filepath.Abs(path) }