package cmd import ( "fmt" "os" "os/exec" "strings" "sync/atomic" "github.com/docker/docker/pkg/reexec" cmap "github.com/orcaman/concurrent-map" ) var verbose bool func init() { v := os.Getenv("LOG_DOCKER") if strings.ToLower(v) == "true" { verbose = true } } type checkFunc func(buf string) // Cmd struct type Cmd struct { name string args []string isRunning uint64 cmd *exec.Cmd app *exec.Cmd checkFuncs cmap.ConcurrentMap //map[string]checkFunc // open log flag. openLog bool // error channel ErrChan chan error } // NewCmd create Cmd instance. func NewCmd(name string, params ...string) *Cmd { cmd := &Cmd{ checkFuncs: cmap.New(), name: name, args: params, ErrChan: make(chan error, 10), cmd: exec.Command(name, params...), app: &exec.Cmd{ Path: reexec.Self(), Args: append([]string{name}, params...), }, } cmd.cmd.Stdout = cmd cmd.cmd.Stderr = cmd cmd.app.Stdout = cmd cmd.app.Stderr = cmd return cmd } // RegistFunc register check func func (c *Cmd) RegistFunc(key string, check checkFunc) { c.checkFuncs.Set(key, check) } // UnRegistFunc unregister check func func (c *Cmd) UnRegistFunc(key string) { c.checkFuncs.Pop(key) } func (c *Cmd) runCmd() { fmt.Println("cmd:", append([]string{c.name}, c.args...)) if atomic.CompareAndSwapUint64(&c.isRunning, 0, 1) { c.ErrChan <- c.cmd.Run() } } // RunCmd parallel running when parallel is true. func (c *Cmd) RunCmd(parallel bool) { if parallel { go c.runCmd() } else { c.runCmd() } } // OpenLog open cmd log by this api. func (c *Cmd) OpenLog(open bool) { c.openLog = open } func (c *Cmd) Write(data []byte) (int, error) { out := string(data) if verbose || c.openLog { fmt.Printf("%s:\n\t%v", c.name, out) } else if strings.Contains(strings.ToLower(out), "error") || strings.Contains(strings.ToLower(out), "warning") { fmt.Printf("%s:\n\t%v", c.name, out) } go c.checkFuncs.IterCb(func(_ string, value interface{}) { check := value.(checkFunc) check(out) }) return len(data), nil }