diff --git a/outlet.go b/outlet.go index 39cfb82..83bb9c4 100644 --- a/outlet.go +++ b/outlet.go @@ -35,8 +35,9 @@ func (o *Outlet) Write(b []byte) (num int, err error) { defer mutex.Unlock() scanner := bufio.NewScanner(bytes.NewReader(b)) for scanner.Scan() { + formatter := fmt.Sprintf("%%-%ds | ", LongestOutletName()) ct.ChangeColor(o.Color, true, ct.None, true) - fmt.Printf("%-10s | ", o.Name) + fmt.Printf(formatter, o.Name) if (o.IsError) { ct.ChangeColor(ct.Red, true, ct.None, true) } else { @@ -49,6 +50,20 @@ func (o *Outlet) Write(b []byte) (num int, err error) { return } +var outlets = map[string]*Outlet{} + func createOutlet(name string, index int, isError bool) *Outlet { - return &Outlet{name, colors[index%len(colors)], isError} + outlets[name] = &Outlet{name, colors[index%len(colors)], isError} + return outlets[name] +} + +func LongestOutletName() (longest int) { + // kr? better way to do this? + longest = 0 + for name, _ := range outlets { + if len(name) > longest { + longest = len(name) + } + } + return } diff --git a/signal.go b/signal.go new file mode 100644 index 0000000..3306de0 --- /dev/null +++ b/signal.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "os" + "os/signal" +) + +var _ = fmt.Println // lol + +func init() { + handler := make(chan os.Signal, 1) + fmt.Println("init") + signal.Notify(handler, os.Interrupt) + go func() { + for sig := range handler { + switch (sig) { + case os.Interrupt: + ShutdownProcesses() + } + } + }() +} + diff --git a/start.go b/start.go index 6734518..8e49127 100644 --- a/start.go +++ b/start.go @@ -7,6 +7,9 @@ import ( "os/exec" "path/filepath" "sync" + "syscall" + "time" + "unsafe" ) var _ = pretty.Println // lol @@ -30,6 +33,8 @@ Examples: `, } +var processes = map[string]*exec.Cmd{} + func init() { cmdStart.Flag.StringVar(&flagProcfile, "f", "Procfile", "procfile") cmdStart.Flag.StringVar(&flagEnv, "e", "", "env") @@ -49,24 +54,56 @@ func runStart(cmd *Command, args []string) { for name, val := range env { ps_env = append(ps_env, fmt.Sprintf("%s=%s", name, val)) } - ps_env = append(ps_env, "LANG=en_US.UTF-8") for idx, proc := range pf.entries { wg.Add(1) go func(idx int, proc ProcfileEntry) { command := []string{"/bin/bash", "-c", proc.command} - ps := exec.Command(command[0], command[1:]...) - ps.Dir = root - ps.Env = ps_env - ps.Stdin = nil - ps.Stdout = createOutlet(proc.name, idx, false) - ps.Stderr = createOutlet(proc.name, idx, true) - ps.Start() - ps.Wait() + var attr syscall.ProcAttr + attr.Files = []uintptr{0,0,0} + attr.Files[1] = uintptr(unsafe.Pointer(createOutlet(proc.name, idx, false))) + attr.Files[2] = uintptr(unsafe.Pointer(createOutlet(proc.name, idx, true))) + attr.Env = ps_env + pid, err := syscall.ForkExec(command[0], command[1:], &attr) + pretty.Println("arg0", command[0], "argv", command[1:]) + fmt.Println("pid", pid, "err", err) + /* ps := exec.Command(command[0], command[1:]...)*/ + /* ps.Dir = root*/ + /* ps.Env = ps_env*/ + /* ps.Stdin = nil*/ + /* ps.Stdout = createOutlet(proc.name, idx, false)*/ + /* ps.Stderr = createOutlet(proc.name, idx, true)*/ + /* processes[proc.name] = ps*/ + /* ps.Start()*/ + /* syscall.Setpgid(ps.Process.Pid, -1 * ps.Process.Pid)*/ + fmt.Println("pid", pid) + var wait syscall.WaitStatus + var usage syscall.Rusage + syscall.Wait4(pid, &wait, 0, &usage) + fmt.Println("exitstatus", wait.ExitStatus()) fmt.Println("process died") wg.Done() + delete(processes, proc.name) }(idx, proc) } wg.Wait() fmt.Println("afterdone") } + +func ShutdownProcesses() { + for _, ps := range processes { + fmt.Println("killing", ps.Process) + group, _ := os.FindProcess(ps.Process.Pid) + group.Signal(syscall.SIGTERM) + } + go func() { + time.Sleep(1 * time.Second) + fmt.Println("really killing") + for _, ps := range processes { + fmt.Println("killing", ps.Process) + ps.Process.Signal(syscall.SIGKILL) + b, _ := os.FindProcess(-1 * ps.Process.Pid) + b.Signal(syscall.SIGKILL) + } + }() +}