-
Notifications
You must be signed in to change notification settings - Fork 30
/
hivemind.go
115 lines (89 loc) · 2.17 KB
/
hivemind.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main
import (
"fmt"
"os"
"os/signal"
"path/filepath"
"sync"
"syscall"
"time"
)
var colors = []int{2, 3, 4, 5, 6, 42, 130, 103, 129, 108}
type hivemindConfig struct {
Title string
Procfile string
ProcNames string
Root string
PortBase, PortStep int
Timeout int
NoPrefix bool
PrintTimestamps bool
}
type hivemind struct {
title string
output *multiOutput
procs []*process
procWg sync.WaitGroup
done chan bool
interrupted chan os.Signal
timeout time.Duration
}
func newHivemind(conf hivemindConfig) (h *hivemind) {
h = &hivemind{timeout: time.Duration(conf.Timeout) * time.Second}
if len(conf.Title) > 0 {
h.title = conf.Title
} else {
h.title = filepath.Base(conf.Root)
}
h.output = &multiOutput{printProcName: !conf.NoPrefix, printTimestamp: conf.PrintTimestamps}
entries := parseProcfile(conf.Procfile, conf.PortBase, conf.PortStep)
h.procs = make([]*process, 0)
procNames := splitAndTrim(conf.ProcNames)
for i, entry := range entries {
if len(procNames) == 0 || stringsContain(procNames, entry.Name) {
h.procs = append(h.procs, newProcess(entry.Name, entry.Command, colors[i%len(colors)], conf.Root, entry.Port, h.output))
}
}
return
}
func (h *hivemind) runProcess(proc *process) {
h.procWg.Add(1)
go func() {
defer h.procWg.Done()
defer func() { h.done <- true }()
proc.Run()
}()
}
func (h *hivemind) waitForDoneOrInterrupt() {
select {
case <-h.done:
case <-h.interrupted:
}
}
func (h *hivemind) waitForTimeoutOrInterrupt() {
select {
case <-time.After(h.timeout):
case <-h.interrupted:
}
}
func (h *hivemind) waitForExit() {
h.waitForDoneOrInterrupt()
for _, proc := range h.procs {
go proc.Interrupt()
}
h.waitForTimeoutOrInterrupt()
for _, proc := range h.procs {
go proc.Kill()
}
}
func (h *hivemind) Run() {
fmt.Printf("\033]0;%s | hivemind\007", h.title)
h.done = make(chan bool, len(h.procs))
h.interrupted = make(chan os.Signal)
signal.Notify(h.interrupted, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
for _, proc := range h.procs {
h.runProcess(proc)
}
go h.waitForExit()
h.procWg.Wait()
}