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}