pkg/environment: Remove exec related functions
This commit starts the migration to remove the environment package. It introduced an abstraction that is not being used, and removing it makes the code simpler to maintain. This commit removes all 'exec' related package.
This commit is contained in:
parent
066390e30d
commit
14bb7f1086
6 changed files with 32 additions and 25 deletions
98
pkg/execx/execx.go
Normal file
98
pkg/execx/execx.go
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// 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.
|
||||
// The returned function is guaranteed to be non-nil and returns an exit code.
|
||||
//
|
||||
// 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 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
|
||||
cmd.Stdin = io.Stdin
|
||||
cmd.Stdout = io.Stdout
|
||||
cmd.Stderr = io.Stderr
|
||||
|
||||
// context is already cancelled, don't run it!
|
||||
if err := ctx.Err(); err != nil {
|
||||
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 CommandErrorFunc
|
||||
}
|
||||
|
||||
waitdone := make(chan struct{}) // closed once Wait() below returns
|
||||
alldone := make(chan struct{}) // closed once the kill goroutine exits
|
||||
go func() {
|
||||
defer close(alldone)
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err := cmd.Process.Kill()
|
||||
zerolog.Ctx(ctx).Debug().Str("exe", exe).Strs("argv", argv).Err(err).Msg("exec.Command.Kill")
|
||||
case <-waitdone:
|
||||
}
|
||||
}()
|
||||
|
||||
// create a new command
|
||||
return func() int {
|
||||
defer func() {
|
||||
// wait for the goroutine to exit
|
||||
close(waitdone)
|
||||
<-alldone
|
||||
}()
|
||||
|
||||
err := cmd.Wait()
|
||||
zerolog.Ctx(ctx).Debug().Str("exe", exe).Strs("argv", argv).Err(err).Msg("exec.Command.Wait")
|
||||
|
||||
// non-zero exit
|
||||
if err, ok := err.(*exec.ExitError); ok {
|
||||
return err.ExitCode()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return CommandError
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// 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 filepath.Abs(path)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue