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