switch to go vendoring

This commit is contained in:
Michael Barz
2023-04-19 20:24:34 +02:00
parent 632fa05ef9
commit afc6ed1e41
8527 changed files with 3004916 additions and 2 deletions
+388
View File
@@ -0,0 +1,388 @@
package cmdr
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"github.com/gookit/color"
"github.com/gookit/goutil"
"github.com/gookit/goutil/arrutil"
"github.com/gookit/goutil/internal/comfunc"
)
// Cmd struct
type Cmd struct {
*exec.Cmd
// Name of the command
Name string
// inited bool
// BeforeRun hook
BeforeRun func(c *Cmd)
// AfterRun hook
AfterRun func(c *Cmd, err error)
}
// WrapGoCmd instance
func WrapGoCmd(cmd *exec.Cmd) *Cmd {
return &Cmd{Cmd: cmd}
}
// NewGitCmd instance
func NewGitCmd(subCmd string, args ...string) *Cmd {
return NewCmd("git", subCmd).AddArgs(args)
}
// NewCmd instance
//
// see exec.Command
func NewCmd(bin string, args ...string) *Cmd {
return &Cmd{
Cmd: exec.Command(bin, args...),
}
}
// CmdWithCtx create new instance with context.
//
// see exec.CommandContext
func CmdWithCtx(ctx context.Context, bin string, args ...string) *Cmd {
return &Cmd{
Cmd: exec.CommandContext(ctx, bin, args...),
}
}
// PrintCmdline on before exec
func PrintCmdline(c *Cmd) {
color.Yellowln(">", c.Cmdline())
}
// -------------------------------------------------
// config the command
// -------------------------------------------------
// Config the command
func (c *Cmd) Config(fn func(c *Cmd)) *Cmd {
fn(c)
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("look %q path error: %s", name, err.Error())
}
}
}
// 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
}
// WorkDirOnNot set, returns the current object
func (c *Cmd) WorkDirOnNot(dir string) *Cmd {
if c.Dir == "" {
c.Dir = dir
}
return c
}
// OutputToStd output to OS stdout and error
func (c *Cmd) OutputToStd() *Cmd {
c.Stdout = os.Stdout
c.Stderr = os.Stderr
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 returns the current object
func (c *Cmd) AddArg(args ...string) *Cmd { return c.WithArg(args...) }
// WithArg add args and returns 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 returns 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 returns 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 returns 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 returns 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 returns 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
}
// -------------------------------------------------
// 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]
}
}
// Cmdline to command line
func (c *Cmd) Cmdline() string {
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
}
// 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)
}
output, err := c.Cmd.Output()
if c.AfterRun != nil {
c.AfterRun(c, err)
}
return string(output), err
}
// CombinedOutput run and return output, will combine stderr and stdout output
func (c *Cmd) CombinedOutput() (string, error) {
if c.BeforeRun != nil {
c.BeforeRun(c)
}
output, err := c.Cmd.CombinedOutput()
if c.AfterRun != nil {
c.AfterRun(c, err)
}
return string(output), 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 {
c.OutputToStd()
return c.Run()
}
// Run runs command
func (c *Cmd) Run() error {
if c.BeforeRun != nil {
c.BeforeRun(c)
}
// 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())
// }
+21
View File
@@ -0,0 +1,21 @@
// Package cmdr Provide for quick build and run a cmd, batch run multi cmd tasks
package cmdr
import "strings"
// 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
}
+248
View File
@@ -0,0 +1,248 @@
package cmdr
import (
"fmt"
"github.com/gookit/color"
"github.com/gookit/goutil/arrutil"
"github.com/gookit/goutil/errorx"
"github.com/gookit/goutil/maputil"
"github.com/gookit/goutil/mathutil"
)
// 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
}
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
}
// 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
}
// 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
// common workdir
// wordDir string
// Params for add custom params
Params maputil.Map
// DryRun dry run all commands
DryRun 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),
}
for _, fn := range fns {
fn(rr)
}
return rr
}
// 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 {
r.AddTask(&Task{
Cmd: NewGitCmd(subCmd, args...),
})
return r
}
// CmdWithArgs a command task
func (r *Runner) CmdWithArgs(cmdName string, args ...string) *Runner {
r.AddTask(&Task{
Cmd: NewCmd(cmdName, args...),
})
return r
}
// CmdWithAnys a command task
func (r *Runner) CmdWithAnys(cmdName string, args ...any) *Runner {
r.AddTask(&Task{
Cmd: NewCmd(cmdName, arrutil.SliceToStrings(args)...),
})
return r
}
// 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 {
color.Infof("DRY-RUN: task #%d execute completed\n", i+1)
continue
}
if !r.RunTask(task) {
break
}
}
if len(r.Errs) == 0 {
return nil
}
return r.Errs
}
// RunTask command
func (r *Runner) RunTask(task *Task) (goon bool) {
// do running
if err := task.Run(); err != nil {
r.Errs[task.ID] = err
color.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)
}
// 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)
}