Initial QSfera import
This commit is contained in:
+490
@@ -0,0 +1,490 @@
|
||||
package cmdr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gookit/goutil"
|
||||
"github.com/gookit/goutil/arrutil"
|
||||
"github.com/gookit/goutil/cliutil/cmdline"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
)
|
||||
|
||||
// Cmd struct
|
||||
type Cmd struct {
|
||||
*exec.Cmd
|
||||
// Name of the command
|
||||
Name string
|
||||
// DryRun setting. if True, not really execute command
|
||||
DryRun bool
|
||||
// Vars mapping TODO
|
||||
Vars map[string]string
|
||||
// PrintLine placeholder for print command cline.
|
||||
PrintLine string
|
||||
|
||||
// BeforeRun hook
|
||||
BeforeRun func(c *Cmd)
|
||||
// AfterRun hook
|
||||
AfterRun func(c *Cmd, err error)
|
||||
}
|
||||
|
||||
// NewGitCmd instance
|
||||
func NewGitCmd(subCmd string, args ...string) *Cmd {
|
||||
return NewCmd("git", subCmd).AddArgs(args)
|
||||
}
|
||||
|
||||
// NewCmdline instance
|
||||
//
|
||||
// see exec.Command
|
||||
func NewCmdline(line string) *Cmd {
|
||||
bin, args := cmdline.NewParser(line).WithParseEnv().BinAndArgs()
|
||||
return NewCmd(bin, args...)
|
||||
}
|
||||
|
||||
// NewCmd instance
|
||||
//
|
||||
// see exec.Command
|
||||
func NewCmd(bin string, args ...string) *Cmd {
|
||||
return WrapGoCmd(exec.Command(bin, args...))
|
||||
}
|
||||
|
||||
// CmdWithCtx create new instance with context.
|
||||
//
|
||||
// see exec.CommandContext
|
||||
func CmdWithCtx(ctx context.Context, bin string, args ...string) *Cmd {
|
||||
return WrapGoCmd(exec.CommandContext(ctx, bin, args...))
|
||||
}
|
||||
|
||||
// WrapGoCmd instance
|
||||
func WrapGoCmd(cmd *exec.Cmd) *Cmd {
|
||||
return &Cmd{
|
||||
Cmd: cmd,
|
||||
Vars: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
// config the command
|
||||
// -------------------------------------------------
|
||||
|
||||
// Config the command
|
||||
func (c *Cmd) Config(fn func(c *Cmd)) *Cmd {
|
||||
fn(c)
|
||||
return c
|
||||
}
|
||||
|
||||
// WithDryRun on exec command
|
||||
func (c *Cmd) WithDryRun(dryRun bool) *Cmd {
|
||||
c.DryRun = dryRun
|
||||
return c
|
||||
}
|
||||
|
||||
// PrintCmdline on exec command
|
||||
func (c *Cmd) PrintCmdline() *Cmd {
|
||||
c.BeforeRun = PrintCmdline
|
||||
return c
|
||||
}
|
||||
|
||||
// PrintCmdline2 on exec command
|
||||
func (c *Cmd) PrintCmdline2() *Cmd {
|
||||
c.BeforeRun = PrintCmdline2
|
||||
return c
|
||||
}
|
||||
|
||||
// OnBefore exec add hook
|
||||
func (c *Cmd) OnBefore(fn func(c *Cmd)) *Cmd {
|
||||
c.BeforeRun = fn
|
||||
return c
|
||||
}
|
||||
|
||||
// OnAfter exec add hook
|
||||
func (c *Cmd) OnAfter(fn func(c *Cmd, err error)) *Cmd {
|
||||
c.AfterRun = fn
|
||||
return c
|
||||
}
|
||||
|
||||
// WithBin name returns the current object
|
||||
func (c *Cmd) WithBin(name string) *Cmd {
|
||||
c.Args[0] = name
|
||||
c.lookPath(name)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Cmd) lookPath(name string) {
|
||||
if filepath.Base(name) == name {
|
||||
lp, err := exec.LookPath(name)
|
||||
if lp != "" {
|
||||
// Update cmd.Path even if err is non-nil.
|
||||
// If err is ErrDot (especially on Windows), lp may include a resolved
|
||||
// extension (like .exe or .bat) that should be preserved.
|
||||
c.Path = lp
|
||||
}
|
||||
if err != nil {
|
||||
goutil.Panicf("cmdr: look %q path error: %v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithGoCmd and returns the current instance.
|
||||
func (c *Cmd) WithGoCmd(ec *exec.Cmd) *Cmd {
|
||||
c.Cmd = ec
|
||||
return c
|
||||
}
|
||||
|
||||
// WithWorkDir returns the current object
|
||||
func (c *Cmd) WithWorkDir(dir string) *Cmd {
|
||||
c.Dir = dir
|
||||
return c
|
||||
}
|
||||
|
||||
// WorkDirOnNE set workdir on input is not empty
|
||||
func (c *Cmd) WorkDirOnNE(dir string) *Cmd {
|
||||
if dir != "" {
|
||||
c.Dir = dir
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// WithEnvMap override set new ENV for run
|
||||
func (c *Cmd) WithEnvMap(mp map[string]string) *Cmd {
|
||||
if ln := len(mp); ln > 0 {
|
||||
c.Env = make([]string, 0, ln)
|
||||
for key, val := range mp {
|
||||
c.Env = append(c.Env, key+"="+val)
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// AppendEnv to the os ENV for run command
|
||||
func (c *Cmd) AppendEnv(mp map[string]string) *Cmd {
|
||||
if len(mp) > 0 {
|
||||
// init env data
|
||||
if c.Env == nil {
|
||||
c.Env = os.Environ()
|
||||
}
|
||||
|
||||
for name, val := range mp {
|
||||
c.Env = append(c.Env, name+"="+val)
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// OutputToOS output to OS stdout and error
|
||||
func (c *Cmd) OutputToOS() *Cmd { return c.ToOSStdoutStderr() }
|
||||
|
||||
// ToOSStdoutStderr output to OS stdout and error
|
||||
func (c *Cmd) ToOSStdoutStderr() *Cmd {
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
return c
|
||||
}
|
||||
|
||||
// ToOSStdout output to OS stdout
|
||||
func (c *Cmd) ToOSStdout() *Cmd {
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stdout
|
||||
return c
|
||||
}
|
||||
|
||||
// WithStdin returns the current argument
|
||||
func (c *Cmd) WithStdin(in io.Reader) *Cmd {
|
||||
c.Stdin = in
|
||||
return c
|
||||
}
|
||||
|
||||
// WithOutput returns the current instance
|
||||
func (c *Cmd) WithOutput(out, errOut io.Writer) *Cmd {
|
||||
c.Stdout = out
|
||||
if errOut != nil {
|
||||
c.Stderr = errOut
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// WithAnyArgs add args and returns the current object.
|
||||
func (c *Cmd) WithAnyArgs(args ...any) *Cmd {
|
||||
c.Args = append(c.Args, arrutil.SliceToStrings(args)...)
|
||||
return c
|
||||
}
|
||||
|
||||
// AddArg add args and return the current object
|
||||
func (c *Cmd) AddArg(args ...string) *Cmd { return c.WithArg(args...) }
|
||||
|
||||
// WithArg add args and return the current object. alias of the WithArg()
|
||||
func (c *Cmd) WithArg(args ...string) *Cmd {
|
||||
c.Args = append(c.Args, args...)
|
||||
return c
|
||||
}
|
||||
|
||||
// AddArgf add args and return the current object. alias of the WithArgf()
|
||||
func (c *Cmd) AddArgf(format string, args ...any) *Cmd { return c.WithArgf(format, args...) }
|
||||
|
||||
// WithArgf add arg and return the current object
|
||||
func (c *Cmd) WithArgf(format string, args ...any) *Cmd {
|
||||
c.Args = append(c.Args, fmt.Sprintf(format, args...))
|
||||
return c
|
||||
}
|
||||
|
||||
// ArgIf add arg and return the current object
|
||||
func (c *Cmd) ArgIf(arg string, exprOk bool) *Cmd {
|
||||
if exprOk {
|
||||
c.Args = append(c.Args, arg)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// WithArgIf add arg and return the current object
|
||||
func (c *Cmd) WithArgIf(arg string, exprOk bool) *Cmd {
|
||||
return c.ArgIf(arg, exprOk)
|
||||
}
|
||||
|
||||
// AddArgs for the git. alias of WithArgs()
|
||||
func (c *Cmd) AddArgs(args []string) *Cmd { return c.WithArgs(args) }
|
||||
|
||||
// WithArgs for the git
|
||||
func (c *Cmd) WithArgs(args []string) *Cmd {
|
||||
if len(args) > 0 {
|
||||
c.Args = append(c.Args, args...)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// WithArgsIf add arg and return the current object
|
||||
func (c *Cmd) WithArgsIf(args []string, exprOk bool) *Cmd {
|
||||
if exprOk && len(args) > 0 {
|
||||
c.Args = append(c.Args, args...)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// WithVars add vars and return the current object
|
||||
func (c *Cmd) WithVars(vs map[string]string) *Cmd {
|
||||
if len(vs) > 0 {
|
||||
c.Vars = vs
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// SetVar add var and return the current object
|
||||
func (c *Cmd) SetVar(name, val string) *Cmd {
|
||||
c.Vars[name] = val
|
||||
return c
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
// helper command
|
||||
// -------------------------------------------------
|
||||
|
||||
// IDString of the command
|
||||
func (c *Cmd) IDString() string {
|
||||
if c.Name != "" {
|
||||
return c.Name
|
||||
}
|
||||
return c.BinOrPath()
|
||||
}
|
||||
|
||||
// BinName of the command
|
||||
func (c *Cmd) BinName() string {
|
||||
if len(c.Args) > 0 {
|
||||
return c.Args[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// BinOrPath of the command
|
||||
func (c *Cmd) BinOrPath() string {
|
||||
if len(c.Args) > 0 {
|
||||
return c.Args[0]
|
||||
}
|
||||
return c.Path
|
||||
}
|
||||
|
||||
// OnlyArgs of the command, not contains bin name.
|
||||
func (c *Cmd) OnlyArgs() (ss []string) {
|
||||
if len(c.Args) > 1 {
|
||||
return c.Args[1:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ResetArgs for command, but will keep bin name.
|
||||
func (c *Cmd) ResetArgs() {
|
||||
if len(c.Args) > 0 {
|
||||
c.Args = c.Args[0:1]
|
||||
} else {
|
||||
c.Args = c.Args[:0]
|
||||
}
|
||||
}
|
||||
|
||||
// Workdir of the command
|
||||
func (c *Cmd) Workdir() string { return c.Dir }
|
||||
|
||||
// Cmdline to command line
|
||||
func (c *Cmd) Cmdline() string { return comfunc.Cmdline(c.Args) }
|
||||
|
||||
// RawLine raw command line for print show.
|
||||
func (c *Cmd) RawLine() string {
|
||||
if c.PrintLine != "" {
|
||||
return c.PrintLine
|
||||
}
|
||||
return comfunc.Cmdline(c.Args)
|
||||
}
|
||||
|
||||
// Copy new instance from current command, with new args.
|
||||
func (c *Cmd) Copy(args ...string) *Cmd {
|
||||
nc := *c
|
||||
|
||||
// copy bin name.
|
||||
if len(c.Args) > 0 {
|
||||
nc.Args = append([]string{c.Args[0]}, args...)
|
||||
} else {
|
||||
nc.Args = args
|
||||
}
|
||||
|
||||
return &nc
|
||||
}
|
||||
|
||||
// GoCmd get exec.Cmd
|
||||
func (c *Cmd) GoCmd() *exec.Cmd { return c.Cmd }
|
||||
|
||||
// -------------------------------------------------
|
||||
// run command
|
||||
// -------------------------------------------------
|
||||
|
||||
// Success run and return whether success
|
||||
func (c *Cmd) Success() bool {
|
||||
return c.Run() == nil
|
||||
}
|
||||
|
||||
// HasStdout output setting.
|
||||
func (c *Cmd) HasStdout() bool {
|
||||
return c.Stdout != nil
|
||||
}
|
||||
|
||||
// SafeLines run and return output as lines
|
||||
func (c *Cmd) SafeLines() []string {
|
||||
ss, _ := c.OutputLines()
|
||||
return ss
|
||||
}
|
||||
|
||||
// OutputLines run and return output as lines
|
||||
func (c *Cmd) OutputLines() ([]string, error) {
|
||||
out, err := c.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return OutputLines(out), err
|
||||
}
|
||||
|
||||
// SafeOutput run and return output
|
||||
func (c *Cmd) SafeOutput() string {
|
||||
out, err := c.Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Output run and return output
|
||||
func (c *Cmd) Output() (string, error) {
|
||||
if c.BeforeRun != nil {
|
||||
c.BeforeRun(c)
|
||||
}
|
||||
|
||||
if c.DryRun {
|
||||
return "DRY-RUN: ok", nil
|
||||
}
|
||||
|
||||
bs, err := c.Cmd.Output()
|
||||
|
||||
if c.AfterRun != nil {
|
||||
c.AfterRun(c, err)
|
||||
}
|
||||
return string(bs), err
|
||||
}
|
||||
|
||||
// AllOutput run and return output, will combine stderr and stdout output
|
||||
func (c *Cmd) AllOutput() (string, error) {
|
||||
return c.CombinedOutput()
|
||||
}
|
||||
|
||||
// CombinedOutput run and return output, will combine stderr and stdout output
|
||||
func (c *Cmd) CombinedOutput() (string, error) {
|
||||
if c.BeforeRun != nil {
|
||||
c.BeforeRun(c)
|
||||
}
|
||||
|
||||
if c.DryRun {
|
||||
return "DRY-RUN: ok", nil
|
||||
}
|
||||
|
||||
bs, err := c.Cmd.CombinedOutput()
|
||||
if c.AfterRun != nil {
|
||||
c.AfterRun(c, err)
|
||||
}
|
||||
return string(bs), err
|
||||
}
|
||||
|
||||
// MustRun a command. will panic on error
|
||||
func (c *Cmd) MustRun() {
|
||||
if err := c.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// FlushRun runs command and flush output to stdout
|
||||
func (c *Cmd) FlushRun() error {
|
||||
return c.ToOSStdoutStderr().Run()
|
||||
}
|
||||
|
||||
// Run runs command
|
||||
func (c *Cmd) Run() error {
|
||||
if c.BeforeRun != nil {
|
||||
c.BeforeRun(c)
|
||||
}
|
||||
|
||||
if c.DryRun {
|
||||
return nil
|
||||
}
|
||||
|
||||
// do running
|
||||
err := c.Cmd.Run()
|
||||
if c.AfterRun != nil {
|
||||
c.AfterRun(c, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// if IsWindows() {
|
||||
// return c.Spawn()
|
||||
// }
|
||||
// return c.Exec()
|
||||
|
||||
// Spawn runs command with spawn(3)
|
||||
// func (c *Cmd) Spawn() error {
|
||||
// return c.Cmd.Run()
|
||||
// }
|
||||
//
|
||||
// // Exec runs command with exec(3)
|
||||
// // Note that Windows doesn't support exec(3): http://golang.org/src/pkg/syscall/exec_windows.go#L339
|
||||
// func (c *Cmd) Exec() error {
|
||||
// binary, err := exec.LookPath(c.Path)
|
||||
// if err != nil {
|
||||
// return &exec.Error{
|
||||
// Name: c.Path,
|
||||
// Err: errorx.Newf("%s not found in the system", c.Path),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// args := []string{binary}
|
||||
// args = append(args, c.Args...)
|
||||
//
|
||||
// return syscall.Exec(binary, args, os.Environ())
|
||||
// }
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// Package cmdr Provide for quick build and run a cmd, batch run multi cmd tasks
|
||||
package cmdr
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/x/ccolor"
|
||||
)
|
||||
|
||||
// PrintCmdline on before exec
|
||||
func PrintCmdline(c *Cmd) {
|
||||
if c.DryRun {
|
||||
ccolor.Yellowln("DRY-RUN>", c.RawLine())
|
||||
} else {
|
||||
ccolor.Yellowln(">", c.RawLine())
|
||||
}
|
||||
}
|
||||
|
||||
// PrintCmdline2 on before exec
|
||||
func PrintCmdline2(c *Cmd) {
|
||||
if c.Dir != "" {
|
||||
ccolor.Magentaln("> Workdir:", c.Dir)
|
||||
}
|
||||
if c.DryRun {
|
||||
ccolor.Yellowln("DRY-RUN>", c.RawLine())
|
||||
} else {
|
||||
ccolor.Yellowln(">", c.RawLine())
|
||||
}
|
||||
}
|
||||
|
||||
// OutputLines split output to lines
|
||||
func OutputLines(output string) []string {
|
||||
output = strings.TrimSuffix(output, "\n")
|
||||
if output == "" {
|
||||
return nil
|
||||
}
|
||||
return strings.Split(output, "\n")
|
||||
}
|
||||
|
||||
// FirstLine from command output
|
||||
func FirstLine(output string) string {
|
||||
if i := strings.Index(output, "\n"); i >= 0 {
|
||||
return output[0:i]
|
||||
}
|
||||
return output
|
||||
}
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
package cmdr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/arrutil"
|
||||
"github.com/gookit/goutil/cliutil/cmdline"
|
||||
"github.com/gookit/goutil/errorx"
|
||||
"github.com/gookit/goutil/maputil"
|
||||
"github.com/gookit/goutil/mathutil"
|
||||
"github.com/gookit/goutil/strutil/textutil"
|
||||
"github.com/gookit/goutil/x/ccolor"
|
||||
)
|
||||
|
||||
// Task struct
|
||||
type Task struct {
|
||||
err error
|
||||
index int
|
||||
|
||||
// ID for task
|
||||
ID string
|
||||
Cmd *Cmd
|
||||
|
||||
// BeforeRun hook
|
||||
BeforeRun func(t *Task)
|
||||
PrevCond func(prev *Task) bool
|
||||
}
|
||||
|
||||
// NewTask instance
|
||||
func NewTask(cmd *Cmd) *Task {
|
||||
return &Task{
|
||||
Cmd: cmd,
|
||||
}
|
||||
}
|
||||
|
||||
// get task id by cmd.Name
|
||||
func (t *Task) ensureID(idx int) {
|
||||
t.index = idx
|
||||
if t.ID != "" {
|
||||
return
|
||||
}
|
||||
|
||||
id := t.Cmd.IDString()
|
||||
if t.Cmd.Name == "" {
|
||||
id += mathutil.String(idx)
|
||||
}
|
||||
t.ID = id
|
||||
}
|
||||
|
||||
var rpl = textutil.NewVarReplacer("$").DisableFlatten()
|
||||
|
||||
// RunWith command
|
||||
func (t *Task) RunWith(ctx maputil.Data) error {
|
||||
cmdVars := ctx.StringMap("cmdVars")
|
||||
|
||||
if len(cmdVars) > 0 {
|
||||
// rpl := strutil.NewReplacer(cmdVars)
|
||||
for i, val := range t.Cmd.Args {
|
||||
if strings.ContainsRune(val, '$') {
|
||||
t.Cmd.Args[i] = rpl.RenderSimple(val, cmdVars)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return t.Run()
|
||||
}
|
||||
|
||||
// Run command
|
||||
func (t *Task) Run() error {
|
||||
if t.BeforeRun != nil {
|
||||
t.BeforeRun(t)
|
||||
}
|
||||
|
||||
t.err = t.Cmd.Run()
|
||||
return t.err
|
||||
}
|
||||
|
||||
// Err get
|
||||
func (t *Task) Err() error {
|
||||
return t.err
|
||||
}
|
||||
|
||||
// Index get
|
||||
func (t *Task) Index() int {
|
||||
return t.index
|
||||
}
|
||||
|
||||
// Cmdline get
|
||||
func (t *Task) Cmdline() string {
|
||||
return t.Cmd.Cmdline()
|
||||
}
|
||||
|
||||
// IsSuccess of task
|
||||
func (t *Task) IsSuccess() bool {
|
||||
return t.err == nil
|
||||
}
|
||||
|
||||
// RunnerHookFn func
|
||||
type RunnerHookFn func(r *Runner, t *Task) bool
|
||||
|
||||
// Runner use for batch run multi task commands
|
||||
type Runner struct {
|
||||
prev *Task
|
||||
// task name to index
|
||||
idMap map[string]int
|
||||
tasks []*Task
|
||||
// Errs on run tasks, key is Task.ID
|
||||
Errs errorx.ErrMap
|
||||
|
||||
// TODO Concurrent run
|
||||
|
||||
// Workdir common workdir
|
||||
Workdir string
|
||||
// EnvMap will append to task.Cmd on run
|
||||
EnvMap map[string]string
|
||||
|
||||
// Params for add custom params
|
||||
Params maputil.Map
|
||||
|
||||
// DryRun dry run all commands
|
||||
DryRun bool
|
||||
// OutToStd stdout and stderr
|
||||
OutToStd bool
|
||||
// IgnoreErr continue on error
|
||||
IgnoreErr bool
|
||||
// BeforeRun hooks on each task. return false to skip current task.
|
||||
BeforeRun func(r *Runner, t *Task) bool
|
||||
// AfterRun hook on each task. return false to stop running.
|
||||
AfterRun func(r *Runner, t *Task) bool
|
||||
}
|
||||
|
||||
// NewRunner instance with config func
|
||||
func NewRunner(fns ...func(rr *Runner)) *Runner {
|
||||
rr := &Runner{
|
||||
idMap: make(map[string]int, 0),
|
||||
tasks: make([]*Task, 0),
|
||||
Errs: make(errorx.ErrMap),
|
||||
Params: make(maputil.Map),
|
||||
}
|
||||
|
||||
rr.OutToStd = true
|
||||
for _, fn := range fns {
|
||||
fn(rr)
|
||||
}
|
||||
return rr
|
||||
}
|
||||
|
||||
// WithOutToStd set
|
||||
func (r *Runner) WithOutToStd() *Runner {
|
||||
r.OutToStd = true
|
||||
return r
|
||||
}
|
||||
|
||||
// Add multitask at once
|
||||
func (r *Runner) Add(tasks ...*Task) *Runner {
|
||||
for _, task := range tasks {
|
||||
r.AddTask(task)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// AddTask add one task
|
||||
func (r *Runner) AddTask(task *Task) *Runner {
|
||||
if task.Cmd == nil {
|
||||
panic("task command cannot be empty")
|
||||
}
|
||||
|
||||
idx := len(r.tasks)
|
||||
task.ensureID(idx)
|
||||
|
||||
// TODO check id repeat
|
||||
r.idMap[task.ID] = idx
|
||||
r.tasks = append(r.tasks, task)
|
||||
return r
|
||||
}
|
||||
|
||||
// AddCmd commands
|
||||
func (r *Runner) AddCmd(cmds ...*Cmd) *Runner {
|
||||
for _, cmd := range cmds {
|
||||
r.AddTask(&Task{Cmd: cmd})
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// GitCmd quick a git command task
|
||||
func (r *Runner) GitCmd(subCmd string, args ...string) *Runner {
|
||||
return r.AddTask(&Task{
|
||||
Cmd: NewGitCmd(subCmd, args...),
|
||||
})
|
||||
}
|
||||
|
||||
// CmdWithArgs a command task
|
||||
func (r *Runner) CmdWithArgs(cmdName string, args ...string) *Runner {
|
||||
return r.AddTask(&Task{
|
||||
Cmd: NewCmd(cmdName, args...),
|
||||
})
|
||||
}
|
||||
|
||||
// CmdWithAnys a command task
|
||||
func (r *Runner) CmdWithAnys(cmdName string, args ...any) *Runner {
|
||||
return r.AddTask(&Task{
|
||||
Cmd: NewCmd(cmdName, arrutil.SliceToStrings(args)...),
|
||||
})
|
||||
}
|
||||
|
||||
// AddCmdline as a command task
|
||||
func (r *Runner) AddCmdline(line string) *Runner {
|
||||
bin, args := cmdline.NewParser(line).BinAndArgs()
|
||||
|
||||
return r.AddTask(&Task{
|
||||
Cmd: NewCmd(bin, args...),
|
||||
})
|
||||
}
|
||||
|
||||
// Run all tasks
|
||||
func (r *Runner) Run() error {
|
||||
// do run tasks
|
||||
for i, task := range r.tasks {
|
||||
if r.BeforeRun != nil && !r.BeforeRun(r, task) {
|
||||
continue
|
||||
}
|
||||
|
||||
if r.prev != nil && task.PrevCond != nil && !task.PrevCond(r.prev) {
|
||||
continue
|
||||
}
|
||||
|
||||
if r.DryRun {
|
||||
ccolor.Infof("DRY-RUN: task#%d execute completed\n\n", i+1)
|
||||
continue
|
||||
}
|
||||
|
||||
if !r.RunTask(task) {
|
||||
break
|
||||
}
|
||||
fmt.Println() // with newline.
|
||||
}
|
||||
|
||||
if len(r.Errs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return r.Errs
|
||||
}
|
||||
|
||||
// StepRun one command
|
||||
func (r *Runner) StepRun() error {
|
||||
return nil // TODO
|
||||
}
|
||||
|
||||
// RunTask command
|
||||
func (r *Runner) RunTask(task *Task) (goon bool) {
|
||||
if len(r.EnvMap) > 0 {
|
||||
task.Cmd.AppendEnv(r.EnvMap)
|
||||
}
|
||||
|
||||
if r.OutToStd && !task.Cmd.HasStdout() {
|
||||
task.Cmd.ToOSStdoutStderr()
|
||||
}
|
||||
|
||||
// common workdir
|
||||
if r.Workdir != "" && task.Cmd.Dir == "" {
|
||||
task.Cmd.WithWorkDir(r.Workdir)
|
||||
}
|
||||
|
||||
// do running
|
||||
if err := task.RunWith(r.Params); err != nil {
|
||||
r.Errs[task.ID] = err
|
||||
ccolor.Errorf("Task#%d run error: %s\n", task.Index()+1, err)
|
||||
|
||||
// not ignore error, stop.
|
||||
if !r.IgnoreErr {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if r.AfterRun != nil && !r.AfterRun(r, task) {
|
||||
return false
|
||||
}
|
||||
|
||||
// store prev
|
||||
r.prev = task
|
||||
return true
|
||||
}
|
||||
|
||||
// Len of tasks
|
||||
func (r *Runner) Len() int {
|
||||
return len(r.tasks)
|
||||
}
|
||||
|
||||
// Reset instance
|
||||
func (r *Runner) Reset() *Runner {
|
||||
r.prev = nil
|
||||
r.tasks = make([]*Task, 0)
|
||||
r.idMap = make(map[string]int, 0)
|
||||
return r
|
||||
}
|
||||
|
||||
// TaskIDs get
|
||||
func (r *Runner) TaskIDs() []string {
|
||||
ss := make([]string, 0, len(r.idMap))
|
||||
for id := range r.idMap {
|
||||
ss = append(ss, id)
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
// Prev task instance after running
|
||||
func (r *Runner) Prev() *Task {
|
||||
return r.prev
|
||||
}
|
||||
|
||||
// Task get by id name
|
||||
func (r *Runner) Task(id string) (*Task, error) {
|
||||
if idx, ok := r.idMap[id]; ok {
|
||||
return r.tasks[idx], nil
|
||||
}
|
||||
return nil, fmt.Errorf("task %q is not exists", id)
|
||||
}
|
||||
Reference in New Issue
Block a user