func normalize(config *Config) (*Config, error) { if len(config.Action) == 0 { return nil, errors.New("no action specified, please specify an action") } // Set up a default dir config to listen for everything. if len(config.Matchers) == 0 { config.Matchers = []Matcher{{ Patterns: []string{"*"}, }} } config.configsMap = make(map[string]*Matcher) for i := range config.Matchers { if len(config.Matchers[i].ExcludeDirs) == 0 { config.Matchers[i].excludeDirMap = defaultExcludeDirMap } else { m := make(map[string]bool) for _, dir := range argPatterns(config.Matchers[i].ExcludeDirs) { m[dir] = true } config.Matchers[i].excludeDirMap = m } } if config.ChangeTimeout == 0 { config.ChangeTimeout = defaultChangeTimeout } if config.KillTimeout == 0 { config.KillTimeout = defaultKillTimeout } log.V("Initializing with config: %+v", config) return config, nil }
// Kill kills all child processes of pgid, since there is no way to kill a process // group in Windows. func (t *Task) Kill() error { log.V("Kill task") // In case killing all child processes fails. defer t.process.Kill() parentMap, err := loadProcessMap() if err != nil { return err } if errs := killChildProcesses(parentMap, uint32(t.process.Pid)); len(errs) > 0 { log.L("killChildProcesses errors: %v", errs) return fmt.Errorf("failed to kill child processes: %v", errs) } return nil }
func (t *SM) startTask() error { var err error t.Task, err = New(t.c.BaseDir, t.c.StdOut, t.c.StdErr, t.c.Action) if err != nil { return err } t.blockRequests.Done() stdinCloser := make(chan struct{}) go copyStdin(t.Task.stdinPipe, stdinCloser) go func() { t.Task.process.Wait() log.V("Task is no longer running") t.done.Write(true) t.Reprocess <- struct{}{} t.reloadEnded <- struct{}{} stdinCloser <- struct{}{} }() return nil }
// New starts the binary specified in args, and returns a Task for the process. func New(baseDir string, outFile string, errFile string, args []string) (*Task, error) { if !log.V("Starting task: %v", args) { log.L("Starting task") } cmd := exec.Command(args[0], args[1:]...) // Use a separate process group so we can kill the whole group. cmd.Dir = baseDir cmd.SysProcAttr = getSysProcAttrs() var err error if cmd.Stdout, err = getOutFile(outFile, os.Stdout); err != nil { return nil, err } if cmd.Stderr, err = getOutFile(errFile, os.Stderr); err != nil { return nil, err } stdinPipe, err := cmd.StdinPipe() if err != nil { return nil, err } if err := cmd.Start(); err != nil { return nil, fmt.Errorf("error starting command: %v", err) } pgid, err := getPgID(cmd) if err != nil { // If we cannot get the pgid, kill the process and return an error. cmd.Process.Kill() return nil, err } return &Task{ process: cmd.Process, pgid: pgid, stdinPipe: stdinPipe, }, nil }
// Kill sends a KILL signal to the task. func (t *Task) Kill() error { log.V("Kill task") return syscall.Kill(-t.pgid, syscall.SIGKILL) }