1
0
mirror of https://github.com/go-task/task.git synced 2024-12-14 10:52:43 +02:00
task/internal/execext/exec.go

102 lines
2.0 KiB
Go
Raw Normal View History

2017-03-12 22:18:59 +02:00
package execext
import (
"context"
"errors"
"io"
"os"
"path/filepath"
"strings"
2019-09-09 02:55:02 +02:00
"mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/interp"
"mvdan.cc/sh/v3/shell"
"mvdan.cc/sh/v3/syntax"
2017-03-12 22:18:59 +02:00
)
2017-04-24 15:25:38 +02:00
// RunCommandOptions is the options for the RunCommand func
type RunCommandOptions struct {
Command string
Dir string
Env []string
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
}
2017-03-12 22:18:59 +02:00
var (
// ErrNilOptions is returned when a nil options is given
ErrNilOptions = errors.New("execext: nil options given")
setMinusE *syntax.File
2017-03-12 22:18:59 +02:00
)
func init() {
var err error
setMinusE, err = syntax.NewParser().Parse(strings.NewReader("set -e"), "")
if err != nil {
panic(err)
}
}
// RunCommand runs a shell command
2018-09-01 16:02:23 +02:00
func RunCommand(ctx context.Context, opts *RunCommandOptions) error {
if opts == nil {
return ErrNilOptions
}
p, err := syntax.NewParser().Parse(strings.NewReader(opts.Command), "")
if err != nil {
return err
}
2017-03-12 22:18:59 +02:00
environ := opts.Env
if len(environ) == 0 {
environ = os.Environ()
}
2018-09-01 16:02:23 +02:00
r, err := interp.New(
interp.Dir(opts.Dir),
2018-12-15 19:43:40 +02:00
interp.Env(expand.ListEnviron(environ...)),
2020-12-27 21:49:51 +02:00
interp.OpenHandler(openHandler),
2018-09-01 16:02:23 +02:00
interp.StdIO(opts.Stdin, opts.Stdout, opts.Stderr),
)
if err != nil {
2017-08-05 19:20:44 +02:00
return err
}
if err = r.Run(ctx, setMinusE); err != nil {
return err
}
2018-09-01 16:02:23 +02:00
return r.Run(ctx, p)
}
// IsExitError returns true the given error is an exis status error
func IsExitError(err error) bool {
2019-11-25 00:17:09 +02:00
if _, ok := interp.IsExitStatus(err); ok {
2018-09-01 16:02:23 +02:00
return true
}
2019-11-25 00:17:09 +02:00
return false
2017-03-12 22:18:59 +02:00
}
// Expand is a helper to mvdan.cc/shell.Fields that returns the first field
// if available.
func Expand(s string) (string, error) {
s = filepath.ToSlash(s)
s = strings.Replace(s, " ", `\ `, -1)
fields, err := shell.Fields(s, nil)
if err != nil {
return "", err
}
if len(fields) > 0 {
return fields[0], nil
}
return "", nil
}
2020-12-27 21:49:51 +02:00
func openHandler(ctx context.Context, path string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
if path == "/dev/null" {
return devNull{}, nil
}
return interp.DefaultOpenHandler()(ctx, path, flag, perm)
}