xref: /aosp_15_r20/tools/treble/build/treble_build/local/ninja.go (revision 105f628577ac4ba0e277a494fbb614ed8c12a994)
1*105f6285SAndroid Build Coastguard Worker// Copyright 2022 The Android Open Source Project
2*105f6285SAndroid Build Coastguard Worker//
3*105f6285SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*105f6285SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*105f6285SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*105f6285SAndroid Build Coastguard Worker//
7*105f6285SAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*105f6285SAndroid Build Coastguard Worker//
9*105f6285SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*105f6285SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*105f6285SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*105f6285SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*105f6285SAndroid Build Coastguard Worker// limitations under the License.
14*105f6285SAndroid Build Coastguard Worker
15*105f6285SAndroid Build Coastguard Workerpackage local
16*105f6285SAndroid Build Coastguard Worker
17*105f6285SAndroid Build Coastguard Workerimport (
18*105f6285SAndroid Build Coastguard Worker	"bufio"
19*105f6285SAndroid Build Coastguard Worker	"bytes"
20*105f6285SAndroid Build Coastguard Worker	"context"
21*105f6285SAndroid Build Coastguard Worker	"errors"
22*105f6285SAndroid Build Coastguard Worker	"fmt"
23*105f6285SAndroid Build Coastguard Worker	"io"
24*105f6285SAndroid Build Coastguard Worker	"io/ioutil"
25*105f6285SAndroid Build Coastguard Worker	"os/exec"
26*105f6285SAndroid Build Coastguard Worker	"strings"
27*105f6285SAndroid Build Coastguard Worker	"time"
28*105f6285SAndroid Build Coastguard Worker
29*105f6285SAndroid Build Coastguard Worker	"tools/treble/build/report/app"
30*105f6285SAndroid Build Coastguard Worker)
31*105f6285SAndroid Build Coastguard Worker
32*105f6285SAndroid Build Coastguard Worker// Performance degrades running multiple CLIs
33*105f6285SAndroid Build Coastguard Workerconst (
34*105f6285SAndroid Build Coastguard Worker	MaxNinjaCliWorkers       = 4
35*105f6285SAndroid Build Coastguard Worker	DefaultNinjaTimeout      = "100s"
36*105f6285SAndroid Build Coastguard Worker	DefaultNinjaBuildTimeout = "30m"
37*105f6285SAndroid Build Coastguard Worker)
38*105f6285SAndroid Build Coastguard Worker
39*105f6285SAndroid Build Coastguard Worker// Separate out the executable to allow tests to override the results
40*105f6285SAndroid Build Coastguard Workertype ninjaExec interface {
41*105f6285SAndroid Build Coastguard Worker	Command(ctx context.Context, target string) (*bytes.Buffer, error)
42*105f6285SAndroid Build Coastguard Worker	Input(ctx context.Context, target string) (*bytes.Buffer, error)
43*105f6285SAndroid Build Coastguard Worker	Query(ctx context.Context, target string) (*bytes.Buffer, error)
44*105f6285SAndroid Build Coastguard Worker	Path(ctx context.Context, target string, dependency string) (*bytes.Buffer, error)
45*105f6285SAndroid Build Coastguard Worker	Paths(ctx context.Context, target string, dependency string) (*bytes.Buffer, error)
46*105f6285SAndroid Build Coastguard Worker	Deps(ctx context.Context) (*bytes.Buffer, error)
47*105f6285SAndroid Build Coastguard Worker	Build(ctx context.Context, target string) (*bytes.Buffer, error)
48*105f6285SAndroid Build Coastguard Worker}
49*105f6285SAndroid Build Coastguard Worker
50*105f6285SAndroid Build Coastguard Worker// Parse data
51*105f6285SAndroid Build Coastguard Worker
52*105f6285SAndroid Build Coastguard Worker// Add all lines to a given array removing any leading whitespace
53*105f6285SAndroid Build Coastguard Workerfunc linesToArray(s *bufio.Scanner, arr *[]string) {
54*105f6285SAndroid Build Coastguard Worker	for s.Scan() {
55*105f6285SAndroid Build Coastguard Worker		line := strings.TrimSpace(s.Text())
56*105f6285SAndroid Build Coastguard Worker		*arr = append(*arr, line)
57*105f6285SAndroid Build Coastguard Worker	}
58*105f6285SAndroid Build Coastguard Worker}
59*105f6285SAndroid Build Coastguard Worker
60*105f6285SAndroid Build Coastguard Worker// parse -t commands
61*105f6285SAndroid Build Coastguard Workerfunc parseCommand(target string, data *bytes.Buffer) (*app.BuildCommand, error) {
62*105f6285SAndroid Build Coastguard Worker	out := &app.BuildCommand{Target: target, Cmds: []string{}}
63*105f6285SAndroid Build Coastguard Worker	s := bufio.NewScanner(data)
64*105f6285SAndroid Build Coastguard Worker	// This tool returns all the commands needed to build a target.
65*105f6285SAndroid Build Coastguard Worker	// When running against a target like droid the default capacity
66*105f6285SAndroid Build Coastguard Worker	// will be overrun.   Extend the capacity here.
67*105f6285SAndroid Build Coastguard Worker	const capacity = 1024 * 1024
68*105f6285SAndroid Build Coastguard Worker	buf := make([]byte, capacity)
69*105f6285SAndroid Build Coastguard Worker	s.Buffer(buf, capacity)
70*105f6285SAndroid Build Coastguard Worker	linesToArray(s, &out.Cmds)
71*105f6285SAndroid Build Coastguard Worker	return out, nil
72*105f6285SAndroid Build Coastguard Worker}
73*105f6285SAndroid Build Coastguard Worker
74*105f6285SAndroid Build Coastguard Worker// parse -t inputs
75*105f6285SAndroid Build Coastguard Workerfunc parseInput(target string, data *bytes.Buffer) (*app.BuildInput, error) {
76*105f6285SAndroid Build Coastguard Worker	out := &app.BuildInput{Target: target, Files: []string{}}
77*105f6285SAndroid Build Coastguard Worker	s := bufio.NewScanner(data)
78*105f6285SAndroid Build Coastguard Worker	linesToArray(s, &out.Files)
79*105f6285SAndroid Build Coastguard Worker	return out, nil
80*105f6285SAndroid Build Coastguard Worker}
81*105f6285SAndroid Build Coastguard Worker
82*105f6285SAndroid Build Coastguard Worker// parse -t query
83*105f6285SAndroid Build Coastguard Workerfunc parseQuery(target string, data *bytes.Buffer) (*app.BuildQuery, error) {
84*105f6285SAndroid Build Coastguard Worker	out := &app.BuildQuery{Target: target, Inputs: []string{}, Outputs: []string{}}
85*105f6285SAndroid Build Coastguard Worker	const (
86*105f6285SAndroid Build Coastguard Worker		unknown = iota
87*105f6285SAndroid Build Coastguard Worker		inputs
88*105f6285SAndroid Build Coastguard Worker		outputs
89*105f6285SAndroid Build Coastguard Worker	)
90*105f6285SAndroid Build Coastguard Worker	state := unknown
91*105f6285SAndroid Build Coastguard Worker	s := bufio.NewScanner(data)
92*105f6285SAndroid Build Coastguard Worker	for s.Scan() {
93*105f6285SAndroid Build Coastguard Worker		line := strings.TrimSpace(s.Text())
94*105f6285SAndroid Build Coastguard Worker		if strings.HasPrefix(line, "input:") {
95*105f6285SAndroid Build Coastguard Worker			state = inputs
96*105f6285SAndroid Build Coastguard Worker		} else if strings.HasPrefix(line, "outputs:") {
97*105f6285SAndroid Build Coastguard Worker			state = outputs
98*105f6285SAndroid Build Coastguard Worker		} else {
99*105f6285SAndroid Build Coastguard Worker			switch state {
100*105f6285SAndroid Build Coastguard Worker			case inputs:
101*105f6285SAndroid Build Coastguard Worker				out.Inputs = append(out.Inputs, line)
102*105f6285SAndroid Build Coastguard Worker			case outputs:
103*105f6285SAndroid Build Coastguard Worker				out.Outputs = append(out.Outputs, line)
104*105f6285SAndroid Build Coastguard Worker			}
105*105f6285SAndroid Build Coastguard Worker		}
106*105f6285SAndroid Build Coastguard Worker	}
107*105f6285SAndroid Build Coastguard Worker	return out, nil
108*105f6285SAndroid Build Coastguard Worker}
109*105f6285SAndroid Build Coastguard Worker
110*105f6285SAndroid Build Coastguard Worker// parse -t path
111*105f6285SAndroid Build Coastguard Workerfunc parsePath(target string, dependency string, data *bytes.Buffer) (*app.BuildPath, error) {
112*105f6285SAndroid Build Coastguard Worker	out := &app.BuildPath{Target: target, Dependency: dependency, Paths: []string{}}
113*105f6285SAndroid Build Coastguard Worker	s := bufio.NewScanner(data)
114*105f6285SAndroid Build Coastguard Worker	linesToArray(s, &out.Paths)
115*105f6285SAndroid Build Coastguard Worker	return out, nil
116*105f6285SAndroid Build Coastguard Worker}
117*105f6285SAndroid Build Coastguard Worker
118*105f6285SAndroid Build Coastguard Worker// parse -t paths
119*105f6285SAndroid Build Coastguard Workerfunc parsePaths(target string, dependency string, data *bytes.Buffer) ([]*app.BuildPath, error) {
120*105f6285SAndroid Build Coastguard Worker	out := []*app.BuildPath{}
121*105f6285SAndroid Build Coastguard Worker	s := bufio.NewScanner(data)
122*105f6285SAndroid Build Coastguard Worker	for s.Scan() {
123*105f6285SAndroid Build Coastguard Worker		path := strings.Fields(s.Text())
124*105f6285SAndroid Build Coastguard Worker		out = append(out, &app.BuildPath{Target: target, Dependency: dependency, Paths: path})
125*105f6285SAndroid Build Coastguard Worker	}
126*105f6285SAndroid Build Coastguard Worker	return out, nil
127*105f6285SAndroid Build Coastguard Worker}
128*105f6285SAndroid Build Coastguard Worker
129*105f6285SAndroid Build Coastguard Worker// parse build output
130*105f6285SAndroid Build Coastguard Workerfunc parseBuild(target string, data *bytes.Buffer, success bool) *app.BuildCmdResult {
131*105f6285SAndroid Build Coastguard Worker	out := &app.BuildCmdResult{Name: target, Output: []string{}}
132*105f6285SAndroid Build Coastguard Worker	s := bufio.NewScanner(data)
133*105f6285SAndroid Build Coastguard Worker	out.Success = success
134*105f6285SAndroid Build Coastguard Worker	linesToArray(s, &out.Output)
135*105f6285SAndroid Build Coastguard Worker	return out
136*105f6285SAndroid Build Coastguard Worker}
137*105f6285SAndroid Build Coastguard Worker
138*105f6285SAndroid Build Coastguard Worker// parse deps command
139*105f6285SAndroid Build Coastguard Workerfunc parseDeps(data *bytes.Buffer) (*app.BuildDeps, error) {
140*105f6285SAndroid Build Coastguard Worker	out := &app.BuildDeps{Targets: make(map[string][]string)}
141*105f6285SAndroid Build Coastguard Worker	s := bufio.NewScanner(data)
142*105f6285SAndroid Build Coastguard Worker	curTarget := ""
143*105f6285SAndroid Build Coastguard Worker	var deps []string
144*105f6285SAndroid Build Coastguard Worker	for s.Scan() {
145*105f6285SAndroid Build Coastguard Worker		line := strings.TrimSpace(s.Text())
146*105f6285SAndroid Build Coastguard Worker		// Check if it's a new target
147*105f6285SAndroid Build Coastguard Worker		tokens := strings.Split(line, ":")
148*105f6285SAndroid Build Coastguard Worker		if len(tokens) > 1 {
149*105f6285SAndroid Build Coastguard Worker			if curTarget != "" {
150*105f6285SAndroid Build Coastguard Worker				out.Targets[curTarget] = deps
151*105f6285SAndroid Build Coastguard Worker			}
152*105f6285SAndroid Build Coastguard Worker			deps = []string{}
153*105f6285SAndroid Build Coastguard Worker			curTarget = tokens[0]
154*105f6285SAndroid Build Coastguard Worker		} else if line != "" {
155*105f6285SAndroid Build Coastguard Worker			deps = append(deps, line)
156*105f6285SAndroid Build Coastguard Worker		}
157*105f6285SAndroid Build Coastguard Worker
158*105f6285SAndroid Build Coastguard Worker	}
159*105f6285SAndroid Build Coastguard Worker	if curTarget != "" {
160*105f6285SAndroid Build Coastguard Worker		out.Targets[curTarget] = deps
161*105f6285SAndroid Build Coastguard Worker	}
162*105f6285SAndroid Build Coastguard Worker	return out, nil
163*105f6285SAndroid Build Coastguard Worker}
164*105f6285SAndroid Build Coastguard Worker
165*105f6285SAndroid Build Coastguard Worker//
166*105f6285SAndroid Build Coastguard Worker// Command line interface to ninja binary.
167*105f6285SAndroid Build Coastguard Worker//
168*105f6285SAndroid Build Coastguard Worker// This file implements the ninja.Ninja interface by querying
169*105f6285SAndroid Build Coastguard Worker// the build graph via the ninja binary.  The mapping between
170*105f6285SAndroid Build Coastguard Worker// the interface and the binary are as follows:
171*105f6285SAndroid Build Coastguard Worker//    Command()   -t commands
172*105f6285SAndroid Build Coastguard Worker//    Input()     -t inputs
173*105f6285SAndroid Build Coastguard Worker//    Query()     -t query
174*105f6285SAndroid Build Coastguard Worker//    Path()      -t path
175*105f6285SAndroid Build Coastguard Worker//    Paths()     -t paths
176*105f6285SAndroid Build Coastguard Worker//    Deps()      -t deps
177*105f6285SAndroid Build Coastguard Worker//
178*105f6285SAndroid Build Coastguard Worker//
179*105f6285SAndroid Build Coastguard Worker
180*105f6285SAndroid Build Coastguard Workertype ninjaCmd struct {
181*105f6285SAndroid Build Coastguard Worker	cmd string
182*105f6285SAndroid Build Coastguard Worker	db  string
183*105f6285SAndroid Build Coastguard Worker
184*105f6285SAndroid Build Coastguard Worker	clientMode   bool
185*105f6285SAndroid Build Coastguard Worker	timeout      time.Duration
186*105f6285SAndroid Build Coastguard Worker	buildTimeout time.Duration
187*105f6285SAndroid Build Coastguard Worker}
188*105f6285SAndroid Build Coastguard Worker
189*105f6285SAndroid Build Coastguard Workerfunc (n *ninjaCmd) runTool(ctx context.Context, tool string, targets []string) (out *bytes.Buffer, err error) {
190*105f6285SAndroid Build Coastguard Worker
191*105f6285SAndroid Build Coastguard Worker	args := []string{"-f", n.db}
192*105f6285SAndroid Build Coastguard Worker
193*105f6285SAndroid Build Coastguard Worker	if n.clientMode {
194*105f6285SAndroid Build Coastguard Worker		args = append(args, []string{
195*105f6285SAndroid Build Coastguard Worker			"-t", "client",
196*105f6285SAndroid Build Coastguard Worker			"-c", tool}...)
197*105f6285SAndroid Build Coastguard Worker	} else {
198*105f6285SAndroid Build Coastguard Worker		args = append(args, []string{"-t", tool}...)
199*105f6285SAndroid Build Coastguard Worker	}
200*105f6285SAndroid Build Coastguard Worker	args = append(args, targets...)
201*105f6285SAndroid Build Coastguard Worker	data := []byte{}
202*105f6285SAndroid Build Coastguard Worker	err, _ = runPipe(ctx, n.timeout, n.cmd, args, func(r io.Reader) {
203*105f6285SAndroid Build Coastguard Worker		data, _ = ioutil.ReadAll(r)
204*105f6285SAndroid Build Coastguard Worker	})
205*105f6285SAndroid Build Coastguard Worker	return bytes.NewBuffer(data), err
206*105f6285SAndroid Build Coastguard Worker
207*105f6285SAndroid Build Coastguard Worker}
208*105f6285SAndroid Build Coastguard Workerfunc (n *ninjaCmd) Command(ctx context.Context, target string) (*bytes.Buffer, error) {
209*105f6285SAndroid Build Coastguard Worker	return n.runTool(ctx, "commands", []string{target})
210*105f6285SAndroid Build Coastguard Worker}
211*105f6285SAndroid Build Coastguard Workerfunc (n *ninjaCmd) Input(ctx context.Context, target string) (*bytes.Buffer, error) {
212*105f6285SAndroid Build Coastguard Worker	return n.runTool(ctx, "inputs", []string{target})
213*105f6285SAndroid Build Coastguard Worker}
214*105f6285SAndroid Build Coastguard Workerfunc (n *ninjaCmd) Query(ctx context.Context, target string) (*bytes.Buffer, error) {
215*105f6285SAndroid Build Coastguard Worker	return n.runTool(ctx, "query", []string{target})
216*105f6285SAndroid Build Coastguard Worker}
217*105f6285SAndroid Build Coastguard Workerfunc (n *ninjaCmd) Path(ctx context.Context, target string, dependency string) (*bytes.Buffer, error) {
218*105f6285SAndroid Build Coastguard Worker	return n.runTool(ctx, "path", []string{target, dependency})
219*105f6285SAndroid Build Coastguard Worker}
220*105f6285SAndroid Build Coastguard Workerfunc (n *ninjaCmd) Paths(ctx context.Context, target string, dependency string) (*bytes.Buffer, error) {
221*105f6285SAndroid Build Coastguard Worker	return n.runTool(ctx, "paths", []string{target, dependency})
222*105f6285SAndroid Build Coastguard Worker}
223*105f6285SAndroid Build Coastguard Workerfunc (n *ninjaCmd) Deps(ctx context.Context) (*bytes.Buffer, error) {
224*105f6285SAndroid Build Coastguard Worker	return n.runTool(ctx, "deps", []string{})
225*105f6285SAndroid Build Coastguard Worker}
226*105f6285SAndroid Build Coastguard Worker
227*105f6285SAndroid Build Coastguard Workerfunc (n *ninjaCmd) Build(ctx context.Context, target string) (*bytes.Buffer, error) {
228*105f6285SAndroid Build Coastguard Worker
229*105f6285SAndroid Build Coastguard Worker	args := append([]string{
230*105f6285SAndroid Build Coastguard Worker		"-f", n.db,
231*105f6285SAndroid Build Coastguard Worker		target})
232*105f6285SAndroid Build Coastguard Worker	data := []byte{}
233*105f6285SAndroid Build Coastguard Worker	err, _ := runPipe(ctx, n.buildTimeout, n.cmd, args, func(r io.Reader) {
234*105f6285SAndroid Build Coastguard Worker		data, _ = ioutil.ReadAll(r)
235*105f6285SAndroid Build Coastguard Worker	})
236*105f6285SAndroid Build Coastguard Worker
237*105f6285SAndroid Build Coastguard Worker	return bytes.NewBuffer(data), err
238*105f6285SAndroid Build Coastguard Worker}
239*105f6285SAndroid Build Coastguard Worker
240*105f6285SAndroid Build Coastguard Worker// Command line ninja
241*105f6285SAndroid Build Coastguard Workertype ninjaCli struct {
242*105f6285SAndroid Build Coastguard Worker	n ninjaExec
243*105f6285SAndroid Build Coastguard Worker}
244*105f6285SAndroid Build Coastguard Worker
245*105f6285SAndroid Build Coastguard Worker// ninja -t commands
246*105f6285SAndroid Build Coastguard Workerfunc (cli *ninjaCli) Command(ctx context.Context, target string) (*app.BuildCommand, error) {
247*105f6285SAndroid Build Coastguard Worker	raw, err := cli.n.Command(ctx, target)
248*105f6285SAndroid Build Coastguard Worker	if err != nil {
249*105f6285SAndroid Build Coastguard Worker		return nil, err
250*105f6285SAndroid Build Coastguard Worker	}
251*105f6285SAndroid Build Coastguard Worker	return parseCommand(target, raw)
252*105f6285SAndroid Build Coastguard Worker}
253*105f6285SAndroid Build Coastguard Worker
254*105f6285SAndroid Build Coastguard Worker// ninja -t inputs
255*105f6285SAndroid Build Coastguard Workerfunc (cli *ninjaCli) Input(ctx context.Context, target string) (*app.BuildInput, error) {
256*105f6285SAndroid Build Coastguard Worker	raw, err := cli.n.Input(ctx, target)
257*105f6285SAndroid Build Coastguard Worker	if err != nil {
258*105f6285SAndroid Build Coastguard Worker		return nil, err
259*105f6285SAndroid Build Coastguard Worker	}
260*105f6285SAndroid Build Coastguard Worker	return parseInput(target, raw)
261*105f6285SAndroid Build Coastguard Worker}
262*105f6285SAndroid Build Coastguard Worker
263*105f6285SAndroid Build Coastguard Worker// ninja -t query
264*105f6285SAndroid Build Coastguard Workerfunc (cli *ninjaCli) Query(ctx context.Context, target string) (*app.BuildQuery, error) {
265*105f6285SAndroid Build Coastguard Worker	raw, err := cli.n.Query(ctx, target)
266*105f6285SAndroid Build Coastguard Worker	if err != nil {
267*105f6285SAndroid Build Coastguard Worker		return nil, err
268*105f6285SAndroid Build Coastguard Worker	}
269*105f6285SAndroid Build Coastguard Worker	return parseQuery(target, raw)
270*105f6285SAndroid Build Coastguard Worker}
271*105f6285SAndroid Build Coastguard Worker
272*105f6285SAndroid Build Coastguard Worker// ninja -t path
273*105f6285SAndroid Build Coastguard Workerfunc (cli *ninjaCli) Path(ctx context.Context, target string, dependency string) (*app.BuildPath, error) {
274*105f6285SAndroid Build Coastguard Worker	raw, err := cli.n.Path(ctx, target, dependency)
275*105f6285SAndroid Build Coastguard Worker	if err != nil {
276*105f6285SAndroid Build Coastguard Worker		return nil, err
277*105f6285SAndroid Build Coastguard Worker	}
278*105f6285SAndroid Build Coastguard Worker	return parsePath(target, dependency, raw)
279*105f6285SAndroid Build Coastguard Worker}
280*105f6285SAndroid Build Coastguard Worker
281*105f6285SAndroid Build Coastguard Worker// ninja -t paths
282*105f6285SAndroid Build Coastguard Workerfunc (cli *ninjaCli) Paths(ctx context.Context, target string, dependency string) ([]*app.BuildPath, error) {
283*105f6285SAndroid Build Coastguard Worker	raw, err := cli.n.Paths(ctx, target, dependency)
284*105f6285SAndroid Build Coastguard Worker	if err != nil {
285*105f6285SAndroid Build Coastguard Worker		return nil, err
286*105f6285SAndroid Build Coastguard Worker	}
287*105f6285SAndroid Build Coastguard Worker	return parsePaths(target, dependency, raw)
288*105f6285SAndroid Build Coastguard Worker}
289*105f6285SAndroid Build Coastguard Worker
290*105f6285SAndroid Build Coastguard Worker// ninja -t deps
291*105f6285SAndroid Build Coastguard Workerfunc (cli *ninjaCli) Deps(ctx context.Context) (*app.BuildDeps, error) {
292*105f6285SAndroid Build Coastguard Worker	raw, err := cli.n.Deps(ctx)
293*105f6285SAndroid Build Coastguard Worker	if err != nil {
294*105f6285SAndroid Build Coastguard Worker		return nil, err
295*105f6285SAndroid Build Coastguard Worker	}
296*105f6285SAndroid Build Coastguard Worker	return parseDeps(raw)
297*105f6285SAndroid Build Coastguard Worker}
298*105f6285SAndroid Build Coastguard Worker
299*105f6285SAndroid Build Coastguard Worker// Build given target
300*105f6285SAndroid Build Coastguard Workerfunc (cli *ninjaCli) Build(ctx context.Context, target string) *app.BuildCmdResult {
301*105f6285SAndroid Build Coastguard Worker	raw, err := cli.n.Build(ctx, target)
302*105f6285SAndroid Build Coastguard Worker	return parseBuild(target, raw, err == nil)
303*105f6285SAndroid Build Coastguard Worker
304*105f6285SAndroid Build Coastguard Worker}
305*105f6285SAndroid Build Coastguard Worker
306*105f6285SAndroid Build Coastguard Worker// Wait for server
307*105f6285SAndroid Build Coastguard Workerfunc (cli *ninjaCli) WaitForServer(ctx context.Context, maxTries int) error {
308*105f6285SAndroid Build Coastguard Worker	// Wait for server to response to an empty input request
309*105f6285SAndroid Build Coastguard Worker	fmt.Printf("Waiting for server.")
310*105f6285SAndroid Build Coastguard Worker	for i := 0; i < maxTries; i++ {
311*105f6285SAndroid Build Coastguard Worker		_, err := cli.Input(ctx, "")
312*105f6285SAndroid Build Coastguard Worker		if err == nil {
313*105f6285SAndroid Build Coastguard Worker			fmt.Printf("\nConnected\n")
314*105f6285SAndroid Build Coastguard Worker			return nil
315*105f6285SAndroid Build Coastguard Worker		}
316*105f6285SAndroid Build Coastguard Worker		fmt.Printf(".")
317*105f6285SAndroid Build Coastguard Worker		time.Sleep(time.Second)
318*105f6285SAndroid Build Coastguard Worker	}
319*105f6285SAndroid Build Coastguard Worker	fmt.Printf(" failed\n")
320*105f6285SAndroid Build Coastguard Worker	return errors.New("Failed to connect")
321*105f6285SAndroid Build Coastguard Worker}
322*105f6285SAndroid Build Coastguard Workerfunc NewNinjaCli(cmd string, db string, timeout, buildTimeout time.Duration, client bool) *ninjaCli {
323*105f6285SAndroid Build Coastguard Worker	cli := &ninjaCli{n: &ninjaCmd{cmd: cmd, db: db, timeout: timeout, buildTimeout: buildTimeout, clientMode: client}}
324*105f6285SAndroid Build Coastguard Worker	return cli
325*105f6285SAndroid Build Coastguard Worker}
326*105f6285SAndroid Build Coastguard Worker
327*105f6285SAndroid Build Coastguard Workertype ninjaServer struct {
328*105f6285SAndroid Build Coastguard Worker	cmdName string
329*105f6285SAndroid Build Coastguard Worker	db      string
330*105f6285SAndroid Build Coastguard Worker	ctx     *exec.Cmd
331*105f6285SAndroid Build Coastguard Worker}
332*105f6285SAndroid Build Coastguard Worker
333*105f6285SAndroid Build Coastguard Worker// Run server
334*105f6285SAndroid Build Coastguard Workerfunc (srv *ninjaServer) Start(ctx context.Context) error {
335*105f6285SAndroid Build Coastguard Worker	args := []string{"-f", srv.db, "-t", "server"}
336*105f6285SAndroid Build Coastguard Worker	srv.ctx = exec.CommandContext(ctx, srv.cmdName, args[0:]...)
337*105f6285SAndroid Build Coastguard Worker	err := srv.ctx.Start()
338*105f6285SAndroid Build Coastguard Worker	if err != nil {
339*105f6285SAndroid Build Coastguard Worker		return err
340*105f6285SAndroid Build Coastguard Worker	}
341*105f6285SAndroid Build Coastguard Worker	srv.ctx.Wait()
342*105f6285SAndroid Build Coastguard Worker	return nil
343*105f6285SAndroid Build Coastguard Worker}
344*105f6285SAndroid Build Coastguard Workerfunc (srv *ninjaServer) Kill() {
345*105f6285SAndroid Build Coastguard Worker	if srv.ctx != nil {
346*105f6285SAndroid Build Coastguard Worker		srv.ctx.Process.Kill()
347*105f6285SAndroid Build Coastguard Worker	}
348*105f6285SAndroid Build Coastguard Worker}
349*105f6285SAndroid Build Coastguard Workerfunc NewNinjaServer(cmd string, db string) *ninjaServer {
350*105f6285SAndroid Build Coastguard Worker	return &ninjaServer{cmdName: cmd, db: db}
351*105f6285SAndroid Build Coastguard Worker}
352