blob: 6ea178ab8849ef8553a378fac9edf676f2811fae [file] [log] [blame]
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +09001package main
2
3import (
4 "bufio"
5 "encoding/binary"
6 "fmt"
7 "io"
8 "os/exec"
9 "path/filepath"
10)
11
12func btoi(b bool) int {
13 if b {
14 return 1
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +090015 }
Fumitoshi Ukai936de102015-06-08 11:21:16 +090016 return 0
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +090017}
18
19func sendMsg(w io.Writer, data []byte) {
20 for len(data) != 0 {
21 written, err := w.Write(data)
22 if err == io.EOF {
23 return
24 }
25 if err != nil {
26 panic(err)
27 }
28 data = data[written:]
29 }
30}
31
32func sendInt(w io.Writer, i int) {
33 v := int32(i)
34 binary.Write(w, binary.LittleEndian, &v)
35}
36
37func sendString(w io.Writer, s string) {
38 sendInt(w, len(s))
39 sendMsg(w, []byte(s))
40}
41
42func sendRunners(w io.Writer, runners []runner) {
43 sendInt(w, len(runners))
44 for _, r := range runners {
45 sendString(w, r.output)
46 sendString(w, r.cmd)
47 sendString(w, r.shell)
48 sendInt(w, btoi(r.echo))
49 sendInt(w, btoi(r.ignoreError))
50 }
51}
52
53type ParaResult struct {
54 output string
55 stdout string
56 stderr string
57 status int
Shinichiro Hamajia6808422015-05-13 18:00:50 +090058 signal int
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +090059}
60
61func recvInt(r *bufio.Reader) (int, error) {
62 var v int32
63 err := binary.Read(r, binary.LittleEndian, &v)
64 return int(v), err
65}
66
67func recvString(r *bufio.Reader) (string, error) {
68 l, err := recvInt(r)
69 if err != nil {
70 return "", err
71 }
72 buf := make([]byte, l)
73 read := 0
74 for read < len(buf) {
75 r, err := r.Read(buf[read:])
76 if err != nil {
77 return "", err
78 }
79 read += r
80 }
81 return string(buf), nil
82}
83
84func recvResult(r *bufio.Reader) (*ParaResult, error) {
85 output, err := recvString(r)
86 if err != nil {
87 return nil, err
88 }
89 stdout, err := recvString(r)
90 if err != nil {
91 return nil, err
92 }
93 stderr, err := recvString(r)
94 if err != nil {
95 return nil, err
96 }
97 status, err := recvInt(r)
98 if err != nil {
99 return nil, err
100 }
Shinichiro Hamajia6808422015-05-13 18:00:50 +0900101 signal, err := recvInt(r)
102 if err != nil {
103 return nil, err
104 }
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900105 return &ParaResult{
106 output: output,
107 stdout: stdout,
108 stderr: stderr,
109 status: status,
Shinichiro Hamajia6808422015-05-13 18:00:50 +0900110 signal: signal,
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900111 }, nil
112}
113
114type ParaWorker struct {
115 para *exec.Cmd
116 paraChan chan *ParaResult
117 stdin io.WriteCloser
118 stdout *bufio.Reader
119 doneChan chan bool
120}
121
122func NewParaWorker(paraChan chan *ParaResult) *ParaWorker {
123 bin := filepath.Join(katiDir, "para")
124 para := exec.Command(bin, fmt.Sprintf("-j%d", jobsFlag), "--kati")
125 stdin, err := para.StdinPipe()
126 if err != nil {
127 panic(err)
128 }
129 stdout, err := para.StdoutPipe()
130 if err != nil {
131 panic(err)
132 }
133 err = para.Start()
134 if err != nil {
135 panic(err)
136 }
137 return &ParaWorker{
138 para: para,
139 paraChan: paraChan,
140 stdin: stdin,
141 stdout: bufio.NewReader(stdout),
142 doneChan: make(chan bool),
143 }
144}
145
146func (para *ParaWorker) Run() {
147 for {
148 r, err := recvResult(para.stdout)
149 if err == io.EOF {
150 break
151 }
152 if err != nil {
153 panic(err)
154 }
155 para.paraChan <- r
156 }
157 para.para.Process.Kill()
158 para.para.Process.Wait()
159 para.doneChan <- true
160}
161
162func (para *ParaWorker) Wait() {
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900163 para.stdin.Close()
164 <-para.doneChan
165}
166
167func (para *ParaWorker) RunCommand(runners []runner) {
168 sendRunners(para.stdin, runners)
169}