blob: 9ef4a11fefcc21a0896060c23a7b0ab4bab9d038 [file] [log] [blame]
Shinichiro Hamajib69bf8a2015-06-10 14:52:06 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +090015package main
16
17import (
18 "bufio"
19 "encoding/binary"
20 "fmt"
21 "io"
22 "os/exec"
23 "path/filepath"
24)
25
26func btoi(b bool) int {
27 if b {
28 return 1
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +090029 }
Fumitoshi Ukai936de102015-06-08 11:21:16 +090030 return 0
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +090031}
32
33func sendMsg(w io.Writer, data []byte) {
34 for len(data) != 0 {
35 written, err := w.Write(data)
36 if err == io.EOF {
37 return
38 }
39 if err != nil {
40 panic(err)
41 }
42 data = data[written:]
43 }
44}
45
46func sendInt(w io.Writer, i int) {
47 v := int32(i)
48 binary.Write(w, binary.LittleEndian, &v)
49}
50
51func sendString(w io.Writer, s string) {
52 sendInt(w, len(s))
53 sendMsg(w, []byte(s))
54}
55
56func sendRunners(w io.Writer, runners []runner) {
57 sendInt(w, len(runners))
58 for _, r := range runners {
59 sendString(w, r.output)
60 sendString(w, r.cmd)
61 sendString(w, r.shell)
62 sendInt(w, btoi(r.echo))
63 sendInt(w, btoi(r.ignoreError))
64 }
65}
66
67type ParaResult struct {
68 output string
69 stdout string
70 stderr string
71 status int
Shinichiro Hamajia6808422015-05-13 18:00:50 +090072 signal int
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +090073}
74
75func recvInt(r *bufio.Reader) (int, error) {
76 var v int32
77 err := binary.Read(r, binary.LittleEndian, &v)
78 return int(v), err
79}
80
81func recvString(r *bufio.Reader) (string, error) {
82 l, err := recvInt(r)
83 if err != nil {
84 return "", err
85 }
86 buf := make([]byte, l)
87 read := 0
88 for read < len(buf) {
89 r, err := r.Read(buf[read:])
90 if err != nil {
91 return "", err
92 }
93 read += r
94 }
95 return string(buf), nil
96}
97
98func recvResult(r *bufio.Reader) (*ParaResult, error) {
99 output, err := recvString(r)
100 if err != nil {
101 return nil, err
102 }
103 stdout, err := recvString(r)
104 if err != nil {
105 return nil, err
106 }
107 stderr, err := recvString(r)
108 if err != nil {
109 return nil, err
110 }
111 status, err := recvInt(r)
112 if err != nil {
113 return nil, err
114 }
Shinichiro Hamajia6808422015-05-13 18:00:50 +0900115 signal, err := recvInt(r)
116 if err != nil {
117 return nil, err
118 }
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900119 return &ParaResult{
120 output: output,
121 stdout: stdout,
122 stderr: stderr,
123 status: status,
Shinichiro Hamajia6808422015-05-13 18:00:50 +0900124 signal: signal,
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900125 }, nil
126}
127
128type ParaWorker struct {
129 para *exec.Cmd
130 paraChan chan *ParaResult
131 stdin io.WriteCloser
132 stdout *bufio.Reader
133 doneChan chan bool
134}
135
136func NewParaWorker(paraChan chan *ParaResult) *ParaWorker {
137 bin := filepath.Join(katiDir, "para")
138 para := exec.Command(bin, fmt.Sprintf("-j%d", jobsFlag), "--kati")
139 stdin, err := para.StdinPipe()
140 if err != nil {
141 panic(err)
142 }
143 stdout, err := para.StdoutPipe()
144 if err != nil {
145 panic(err)
146 }
147 err = para.Start()
148 if err != nil {
149 panic(err)
150 }
151 return &ParaWorker{
152 para: para,
153 paraChan: paraChan,
154 stdin: stdin,
155 stdout: bufio.NewReader(stdout),
156 doneChan: make(chan bool),
157 }
158}
159
160func (para *ParaWorker) Run() {
161 for {
162 r, err := recvResult(para.stdout)
163 if err == io.EOF {
164 break
165 }
166 if err != nil {
167 panic(err)
168 }
169 para.paraChan <- r
170 }
171 para.para.Process.Kill()
172 para.para.Process.Wait()
173 para.doneChan <- true
174}
175
176func (para *ParaWorker) Wait() {
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900177 para.stdin.Close()
178 <-para.doneChan
179}
180
181func (para *ParaWorker) RunCommand(runners []runner) {
182 sendRunners(para.stdin, runners)
183}