main
1package main
2
3import (
4 "flag"
5 "log"
6 "os"
7 "os/signal"
8 "strings"
9 "sync"
10 "sync/atomic"
11 "syscall"
12 "time"
13
14 "github.com/xlgmokha/minit/pkg/procfile"
15)
16
17var (
18 pidMutex sync.Mutex
19 pids []int
20 procfilePath *string
21)
22
23func init() {
24 procfilePath = flag.String("f", "Procfile", "path to Procfile")
25 flag.Parse()
26 log.SetFlags(0)
27}
28
29func addPid(pid int) {
30 pidMutex.Lock()
31 defer pidMutex.Unlock()
32 pids = append(pids, pid)
33}
34
35func removePid(pid int) {
36 pidMutex.Lock()
37 defer pidMutex.Unlock()
38
39 for i, p := range pids {
40 if p == pid {
41 pids = append(pids[:i], pids[i+1:]...)
42 break
43 }
44 }
45}
46
47func forwardSignalToAll(sig os.Signal) {
48 pidMutex.Lock()
49 defer pidMutex.Unlock()
50
51 signal := sig.(syscall.Signal)
52 for _, pid := range pids {
53 syscall.Kill(-pid, signal)
54 }
55}
56
57func main() {
58 var wg sync.WaitGroup
59 var shutdown int32
60
61 for _, path := range strings.Split(*procfilePath, ",") {
62 procs, err := procfile.ParseFile(path)
63 if err != nil {
64 log.Fatalln(err)
65 }
66
67 for _, proc := range procs {
68 wg.Add(1)
69 go func(proc *procfile.Proc) {
70 defer wg.Done()
71
72 for atomic.LoadInt32(&shutdown) == 0 {
73 cmd := proc.NewCommand()
74
75 if cmd.Start() != nil {
76 time.Sleep(2 * time.Second)
77 continue
78 }
79
80 addPid(cmd.Process.Pid)
81 cmd.Wait()
82 removePid(cmd.Process.Pid)
83 time.Sleep(time.Second)
84 }
85 }(proc)
86 }
87 }
88
89 sigChan := make(chan os.Signal, 1)
90 signal.Notify(sigChan)
91
92 go func() {
93 for sig := range sigChan {
94 if sig == syscall.SIGINT || sig == syscall.SIGTERM {
95 atomic.StoreInt32(&shutdown, 1)
96 forwardSignalToAll(sig)
97 return
98 }
99
100 forwardSignalToAll(sig)
101 }
102 }()
103
104 wg.Wait()
105}