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 main 16*105f6285SAndroid Build Coastguard Worker 17*105f6285SAndroid Build Coastguard Workerimport ( 18*105f6285SAndroid Build Coastguard Worker "bufio" 19*105f6285SAndroid Build Coastguard Worker "context" 20*105f6285SAndroid Build Coastguard Worker "encoding/json" 21*105f6285SAndroid Build Coastguard Worker "errors" 22*105f6285SAndroid Build Coastguard Worker "flag" 23*105f6285SAndroid Build Coastguard Worker "fmt" 24*105f6285SAndroid Build Coastguard Worker "io" 25*105f6285SAndroid Build Coastguard Worker "log" 26*105f6285SAndroid Build Coastguard Worker "os" 27*105f6285SAndroid Build Coastguard Worker "runtime" 28*105f6285SAndroid Build Coastguard Worker "strings" 29*105f6285SAndroid Build Coastguard Worker "time" 30*105f6285SAndroid Build Coastguard Worker 31*105f6285SAndroid Build Coastguard Worker "tools/treble/build/report/app" 32*105f6285SAndroid Build Coastguard Worker "tools/treble/build/report/local" 33*105f6285SAndroid Build Coastguard Worker "tools/treble/build/report/report" 34*105f6285SAndroid Build Coastguard Worker) 35*105f6285SAndroid Build Coastguard Worker 36*105f6285SAndroid Build Coastguard Workertype Build interface { 37*105f6285SAndroid Build Coastguard Worker Build(ctx context.Context, target string) *app.BuildCmdResult 38*105f6285SAndroid Build Coastguard Worker} 39*105f6285SAndroid Build Coastguard Worker 40*105f6285SAndroid Build Coastguard Workertype tool interface { 41*105f6285SAndroid Build Coastguard Worker Run(ctx context.Context, rtx *report.Context, rsp *response) error 42*105f6285SAndroid Build Coastguard Worker PrintText(w io.Writer, rsp *response, verbose bool) 43*105f6285SAndroid Build Coastguard Worker} 44*105f6285SAndroid Build Coastguard Workertype repoFlags []app.ProjectCommit 45*105f6285SAndroid Build Coastguard Worker 46*105f6285SAndroid Build Coastguard Workerfunc (r *repoFlags) Set(value string) error { 47*105f6285SAndroid Build Coastguard Worker commit := app.ProjectCommit{} 48*105f6285SAndroid Build Coastguard Worker items := strings.Split(value, ":") 49*105f6285SAndroid Build Coastguard Worker if len(items) > 2 { 50*105f6285SAndroid Build Coastguard Worker return (errors.New("Invalid repo value expected (proj:sha) format")) 51*105f6285SAndroid Build Coastguard Worker } 52*105f6285SAndroid Build Coastguard Worker commit.Project = items[0] 53*105f6285SAndroid Build Coastguard Worker if len(items) > 1 { 54*105f6285SAndroid Build Coastguard Worker commit.Revision = items[1] 55*105f6285SAndroid Build Coastguard Worker } 56*105f6285SAndroid Build Coastguard Worker *r = append(*r, commit) 57*105f6285SAndroid Build Coastguard Worker return nil 58*105f6285SAndroid Build Coastguard Worker} 59*105f6285SAndroid Build Coastguard Workerfunc (r *repoFlags) String() string { 60*105f6285SAndroid Build Coastguard Worker items := []string{} 61*105f6285SAndroid Build Coastguard Worker for _, fl := range *r { 62*105f6285SAndroid Build Coastguard Worker items = append(items, fmt.Sprintf("%s:%s", fl.Project, fl.Revision)) 63*105f6285SAndroid Build Coastguard Worker } 64*105f6285SAndroid Build Coastguard Worker return strings.Join(items, " ") 65*105f6285SAndroid Build Coastguard Worker} 66*105f6285SAndroid Build Coastguard Worker 67*105f6285SAndroid Build Coastguard Workervar ( 68*105f6285SAndroid Build Coastguard Worker // Common flags 69*105f6285SAndroid Build Coastguard Worker ninjaDbPtr = flag.String("ninja", local.DefNinjaDb(), "Set the .ninja file to use when building metrics") 70*105f6285SAndroid Build Coastguard Worker ninjaExcPtr = flag.String("ninja_cmd", local.DefNinjaExc(), "Set the ninja executable") 71*105f6285SAndroid Build Coastguard Worker ninjaTimeoutStr = flag.String("ninja_timeout", local.DefaultNinjaTimeout, "Default ninja timeout") 72*105f6285SAndroid Build Coastguard Worker buildTimeoutStr = flag.String("build_timeout", local.DefaultNinjaBuildTimeout, "Default build timeout") 73*105f6285SAndroid Build Coastguard Worker manifestPtr = flag.String("manifest", local.DefManifest(), "Set the location of the manifest file") 74*105f6285SAndroid Build Coastguard Worker upstreamPtr = flag.String("upstream", "", "Upstream branch to compare files against") 75*105f6285SAndroid Build Coastguard Worker repoBasePtr = flag.String("repo_base", local.DefRepoBase(), "Set the repo base directory") 76*105f6285SAndroid Build Coastguard Worker workerCountPtr = flag.Int("worker_count", runtime.NumCPU(), "Number of worker routines") 77*105f6285SAndroid Build Coastguard Worker buildWorkerCountPtr = flag.Int("build_worker_count", local.MaxNinjaCliWorkers, "Number of build worker routines") 78*105f6285SAndroid Build Coastguard Worker clientServerPtr = flag.Bool("client_server", false, "Run client server mode") 79*105f6285SAndroid Build Coastguard Worker buildPtr = flag.Bool("build", false, "Build targets") 80*105f6285SAndroid Build Coastguard Worker jsonPtr = flag.Bool("json", false, "Print json data") 81*105f6285SAndroid Build Coastguard Worker verbosePtr = flag.Bool("v", false, "Print verbose text data") 82*105f6285SAndroid Build Coastguard Worker outputPtr = flag.String("o", "", "Output to file") 83*105f6285SAndroid Build Coastguard Worker projsPtr = flag.Bool("projects", false, "Include project repo data") 84*105f6285SAndroid Build Coastguard Worker 85*105f6285SAndroid Build Coastguard Worker hostFlags = flag.NewFlagSet("host", flag.ExitOnError) 86*105f6285SAndroid Build Coastguard Worker queryFlags = flag.NewFlagSet("query", flag.ExitOnError) 87*105f6285SAndroid Build Coastguard Worker pathsFlags = flag.NewFlagSet("paths", flag.ExitOnError) 88*105f6285SAndroid Build Coastguard Worker) 89*105f6285SAndroid Build Coastguard Worker 90*105f6285SAndroid Build Coastguard Worker// Add profiling data 91*105f6285SAndroid Build Coastguard Workertype profTime struct { 92*105f6285SAndroid Build Coastguard Worker Description string `json:"description"` 93*105f6285SAndroid Build Coastguard Worker DurationSecs float64 `json:"duration"` 94*105f6285SAndroid Build Coastguard Worker} 95*105f6285SAndroid Build Coastguard Worker 96*105f6285SAndroid Build Coastguard Workertype commit struct { 97*105f6285SAndroid Build Coastguard Worker Project app.ProjectCommit `json:"project"` 98*105f6285SAndroid Build Coastguard Worker Commit *app.GitCommit `json:"commit"` 99*105f6285SAndroid Build Coastguard Worker} 100*105f6285SAndroid Build Coastguard Worker 101*105f6285SAndroid Build Coastguard Worker// Use one structure for output for now 102*105f6285SAndroid Build Coastguard Workertype response struct { 103*105f6285SAndroid Build Coastguard Worker Commits []commit `json:"commits,omitempty"` 104*105f6285SAndroid Build Coastguard Worker Inputs []string `json:"files,omitempty"` 105*105f6285SAndroid Build Coastguard Worker BuildFiles []*app.BuildCmdResult `json:"build_files,omitempty"` 106*105f6285SAndroid Build Coastguard Worker Targets []string `json:"targets,omitempty"` 107*105f6285SAndroid Build Coastguard Worker Report *app.Report `json:"report,omitempty"` 108*105f6285SAndroid Build Coastguard Worker 109*105f6285SAndroid Build Coastguard Worker // Subcommand data 110*105f6285SAndroid Build Coastguard Worker Query *app.QueryResponse `json:"query,omitempty"` 111*105f6285SAndroid Build Coastguard Worker Paths []*app.BuildPath `json:"build_paths,omitempty"` 112*105f6285SAndroid Build Coastguard Worker Host *app.HostReport `json:"host,omitempty"` 113*105f6285SAndroid Build Coastguard Worker Projects map[string]*app.GitProject `json:"projects,omitempty"` 114*105f6285SAndroid Build Coastguard Worker // Profile data 115*105f6285SAndroid Build Coastguard Worker Profile []*profTime `json:"profile"` 116*105f6285SAndroid Build Coastguard Worker} 117*105f6285SAndroid Build Coastguard Worker 118*105f6285SAndroid Build Coastguard Workerfunc main() { 119*105f6285SAndroid Build Coastguard Worker startTime := time.Now() 120*105f6285SAndroid Build Coastguard Worker ctx := context.Background() 121*105f6285SAndroid Build Coastguard Worker rsp := &response{} 122*105f6285SAndroid Build Coastguard Worker 123*105f6285SAndroid Build Coastguard Worker var addProfileData = func(desc string) { 124*105f6285SAndroid Build Coastguard Worker rsp.Profile = append(rsp.Profile, &profTime{Description: desc, DurationSecs: time.Since(startTime).Seconds()}) 125*105f6285SAndroid Build Coastguard Worker startTime = time.Now() 126*105f6285SAndroid Build Coastguard Worker } 127*105f6285SAndroid Build Coastguard Worker flag.Parse() 128*105f6285SAndroid Build Coastguard Worker 129*105f6285SAndroid Build Coastguard Worker ninjaTimeout, err := time.ParseDuration(*ninjaTimeoutStr) 130*105f6285SAndroid Build Coastguard Worker if err != nil { 131*105f6285SAndroid Build Coastguard Worker log.Fatalf("Invalid ninja timeout %s", *ninjaTimeoutStr) 132*105f6285SAndroid Build Coastguard Worker } 133*105f6285SAndroid Build Coastguard Worker 134*105f6285SAndroid Build Coastguard Worker buildTimeout, err := time.ParseDuration(*buildTimeoutStr) 135*105f6285SAndroid Build Coastguard Worker if err != nil { 136*105f6285SAndroid Build Coastguard Worker log.Fatalf("Invalid build timeout %s", *buildTimeoutStr) 137*105f6285SAndroid Build Coastguard Worker } 138*105f6285SAndroid Build Coastguard Worker 139*105f6285SAndroid Build Coastguard Worker subArgs := flag.Args() 140*105f6285SAndroid Build Coastguard Worker defBuildTarget := "droid" 141*105f6285SAndroid Build Coastguard Worker log.SetFlags(log.LstdFlags | log.Llongfile) 142*105f6285SAndroid Build Coastguard Worker 143*105f6285SAndroid Build Coastguard Worker ninja := local.NewNinjaCli(*ninjaExcPtr, *ninjaDbPtr, ninjaTimeout, buildTimeout, *clientServerPtr) 144*105f6285SAndroid Build Coastguard Worker 145*105f6285SAndroid Build Coastguard Worker if *clientServerPtr { 146*105f6285SAndroid Build Coastguard Worker ninjaServ := local.NewNinjaServer(*ninjaExcPtr, *ninjaDbPtr) 147*105f6285SAndroid Build Coastguard Worker defer ninjaServ.Kill() 148*105f6285SAndroid Build Coastguard Worker go func() { 149*105f6285SAndroid Build Coastguard Worker 150*105f6285SAndroid Build Coastguard Worker ninjaServ.Start(ctx) 151*105f6285SAndroid Build Coastguard Worker }() 152*105f6285SAndroid Build Coastguard Worker if err := ninja.WaitForServer(ctx, int(ninjaTimeout.Seconds())); err != nil { 153*105f6285SAndroid Build Coastguard Worker log.Fatalf("Failed to connect to server") 154*105f6285SAndroid Build Coastguard Worker } 155*105f6285SAndroid Build Coastguard Worker } 156*105f6285SAndroid Build Coastguard Worker rtx := &report.Context{ 157*105f6285SAndroid Build Coastguard Worker RepoBase: *repoBasePtr, 158*105f6285SAndroid Build Coastguard Worker Repo: &report.RepoMan{}, 159*105f6285SAndroid Build Coastguard Worker Build: ninja, 160*105f6285SAndroid Build Coastguard Worker Project: local.NewGitCli(), 161*105f6285SAndroid Build Coastguard Worker WorkerCount: *workerCountPtr, 162*105f6285SAndroid Build Coastguard Worker BuildWorkerCount: *buildWorkerCountPtr, 163*105f6285SAndroid Build Coastguard Worker } 164*105f6285SAndroid Build Coastguard Worker 165*105f6285SAndroid Build Coastguard Worker var subcommand tool 166*105f6285SAndroid Build Coastguard Worker var commits repoFlags 167*105f6285SAndroid Build Coastguard Worker if len(subArgs) > 0 { 168*105f6285SAndroid Build Coastguard Worker switch subArgs[0] { 169*105f6285SAndroid Build Coastguard Worker case "host": 170*105f6285SAndroid Build Coastguard Worker hostToolPathPtr := hostFlags.String("hostbin", local.DefHostBinPath(), "Set the output directory for host tools") 171*105f6285SAndroid Build Coastguard Worker hostFlags.Parse(subArgs[1:]) 172*105f6285SAndroid Build Coastguard Worker 173*105f6285SAndroid Build Coastguard Worker subcommand = &hostReport{toolPath: *hostToolPathPtr} 174*105f6285SAndroid Build Coastguard Worker rsp.Targets = hostFlags.Args() 175*105f6285SAndroid Build Coastguard Worker 176*105f6285SAndroid Build Coastguard Worker case "query": 177*105f6285SAndroid Build Coastguard Worker queryFlags.Var(&commits, "repo", "Repo:SHA to query") 178*105f6285SAndroid Build Coastguard Worker queryFlags.Parse(subArgs[1:]) 179*105f6285SAndroid Build Coastguard Worker subcommand = &queryReport{} 180*105f6285SAndroid Build Coastguard Worker rsp.Targets = queryFlags.Args() 181*105f6285SAndroid Build Coastguard Worker 182*105f6285SAndroid Build Coastguard Worker case "paths": 183*105f6285SAndroid Build Coastguard Worker pathsFlags.Var(&commits, "repo", "Repo:SHA to build") 184*105f6285SAndroid Build Coastguard Worker singlePathPtr := pathsFlags.Bool("1", false, "Get single path to output target") 185*105f6285SAndroid Build Coastguard Worker pathsFlags.Parse(subArgs[1:]) 186*105f6285SAndroid Build Coastguard Worker 187*105f6285SAndroid Build Coastguard Worker subcommand = &pathsReport{build_target: defBuildTarget, single: *singlePathPtr} 188*105f6285SAndroid Build Coastguard Worker 189*105f6285SAndroid Build Coastguard Worker rsp.Inputs = pathsFlags.Args() 190*105f6285SAndroid Build Coastguard Worker 191*105f6285SAndroid Build Coastguard Worker default: 192*105f6285SAndroid Build Coastguard Worker rsp.Targets = subArgs 193*105f6285SAndroid Build Coastguard Worker } 194*105f6285SAndroid Build Coastguard Worker } 195*105f6285SAndroid Build Coastguard Worker addProfileData("Init") 196*105f6285SAndroid Build Coastguard Worker rtx.ResolveProjectMap(ctx, *manifestPtr, *upstreamPtr) 197*105f6285SAndroid Build Coastguard Worker addProfileData("Project Map") 198*105f6285SAndroid Build Coastguard Worker 199*105f6285SAndroid Build Coastguard Worker // Add project to output if requested 200*105f6285SAndroid Build Coastguard Worker if *projsPtr == true { 201*105f6285SAndroid Build Coastguard Worker rsp.Projects = make(map[string]*app.GitProject) 202*105f6285SAndroid Build Coastguard Worker for k, p := range rtx.Info.ProjMap { 203*105f6285SAndroid Build Coastguard Worker rsp.Projects[k] = p.GitProj 204*105f6285SAndroid Build Coastguard Worker } 205*105f6285SAndroid Build Coastguard Worker } 206*105f6285SAndroid Build Coastguard Worker 207*105f6285SAndroid Build Coastguard Worker // Resolve any commits 208*105f6285SAndroid Build Coastguard Worker if len(commits) > 0 { 209*105f6285SAndroid Build Coastguard Worker log.Printf("Resolving %s", commits.String()) 210*105f6285SAndroid Build Coastguard Worker for _, c := range commits { 211*105f6285SAndroid Build Coastguard Worker commit := commit{Project: c} 212*105f6285SAndroid Build Coastguard Worker info, files, err := report.ResolveCommit(ctx, rtx, &c) 213*105f6285SAndroid Build Coastguard Worker if err != nil { 214*105f6285SAndroid Build Coastguard Worker log.Fatalf("Failed to resolve commit %s:%s", c.Project, c.Revision) 215*105f6285SAndroid Build Coastguard Worker } 216*105f6285SAndroid Build Coastguard Worker commit.Commit = info 217*105f6285SAndroid Build Coastguard Worker rsp.Commits = append(rsp.Commits, commit) 218*105f6285SAndroid Build Coastguard Worker 219*105f6285SAndroid Build Coastguard Worker // Add files to list of inputs 220*105f6285SAndroid Build Coastguard Worker rsp.Inputs = append(rsp.Inputs, files...) 221*105f6285SAndroid Build Coastguard Worker } 222*105f6285SAndroid Build Coastguard Worker addProfileData("Commit Resolution") 223*105f6285SAndroid Build Coastguard Worker } 224*105f6285SAndroid Build Coastguard Worker 225*105f6285SAndroid Build Coastguard Worker // Run any sub tools 226*105f6285SAndroid Build Coastguard Worker if subcommand != nil { 227*105f6285SAndroid Build Coastguard Worker if err := subcommand.Run(ctx, rtx, rsp); err != nil { 228*105f6285SAndroid Build Coastguard Worker log.Fatal(err) 229*105f6285SAndroid Build Coastguard Worker } 230*105f6285SAndroid Build Coastguard Worker addProfileData(subArgs[0]) 231*105f6285SAndroid Build Coastguard Worker } 232*105f6285SAndroid Build Coastguard Worker 233*105f6285SAndroid Build Coastguard Worker buildErrors := 0 234*105f6285SAndroid Build Coastguard Worker if *buildPtr { 235*105f6285SAndroid Build Coastguard Worker // Only support default builder (non server-client) 236*105f6285SAndroid Build Coastguard Worker builder := local.NewNinjaCli(local.DefNinjaExc(), *ninjaDbPtr, ninjaTimeout, buildTimeout, false /*clientMode*/) 237*105f6285SAndroid Build Coastguard Worker for _, t := range rsp.Targets { 238*105f6285SAndroid Build Coastguard Worker log.Printf("Building %s\n", t) 239*105f6285SAndroid Build Coastguard Worker res := builder.Build(ctx, t) 240*105f6285SAndroid Build Coastguard Worker addProfileData(fmt.Sprintf("Build %s", t)) 241*105f6285SAndroid Build Coastguard Worker log.Printf("%s\n", res.Output) 242*105f6285SAndroid Build Coastguard Worker if res.Success != true { 243*105f6285SAndroid Build Coastguard Worker buildErrors++ 244*105f6285SAndroid Build Coastguard Worker } 245*105f6285SAndroid Build Coastguard Worker rsp.BuildFiles = append(rsp.BuildFiles, res) 246*105f6285SAndroid Build Coastguard Worker } 247*105f6285SAndroid Build Coastguard Worker } 248*105f6285SAndroid Build Coastguard Worker 249*105f6285SAndroid Build Coastguard Worker // Generate report 250*105f6285SAndroid Build Coastguard Worker log.Printf("Generating report for targets %s", rsp.Targets) 251*105f6285SAndroid Build Coastguard Worker req := &app.ReportRequest{Targets: rsp.Targets} 252*105f6285SAndroid Build Coastguard Worker rsp.Report, err = report.RunReport(ctx, rtx, req) 253*105f6285SAndroid Build Coastguard Worker addProfileData("Report") 254*105f6285SAndroid Build Coastguard Worker if err != nil { 255*105f6285SAndroid Build Coastguard Worker log.Fatal(fmt.Sprintf("Report failure <%s>", err)) 256*105f6285SAndroid Build Coastguard Worker } 257*105f6285SAndroid Build Coastguard Worker 258*105f6285SAndroid Build Coastguard Worker if *jsonPtr { 259*105f6285SAndroid Build Coastguard Worker b, _ := json.MarshalIndent(rsp, "", "\t") 260*105f6285SAndroid Build Coastguard Worker if *outputPtr == "" { 261*105f6285SAndroid Build Coastguard Worker os.Stdout.Write(b) 262*105f6285SAndroid Build Coastguard Worker } else { 263*105f6285SAndroid Build Coastguard Worker os.WriteFile(*outputPtr, b, 0644) 264*105f6285SAndroid Build Coastguard Worker } 265*105f6285SAndroid Build Coastguard Worker } else { 266*105f6285SAndroid Build Coastguard Worker if *outputPtr == "" { 267*105f6285SAndroid Build Coastguard Worker printTextReport(os.Stdout, subcommand, rsp, *verbosePtr) 268*105f6285SAndroid Build Coastguard Worker } else { 269*105f6285SAndroid Build Coastguard Worker file, err := os.Create(*outputPtr) 270*105f6285SAndroid Build Coastguard Worker if err != nil { 271*105f6285SAndroid Build Coastguard Worker log.Fatalf("Failed to create output file %s (%s)", *outputPtr, err) 272*105f6285SAndroid Build Coastguard Worker } 273*105f6285SAndroid Build Coastguard Worker w := bufio.NewWriter(file) 274*105f6285SAndroid Build Coastguard Worker printTextReport(w, subcommand, rsp, *verbosePtr) 275*105f6285SAndroid Build Coastguard Worker w.Flush() 276*105f6285SAndroid Build Coastguard Worker } 277*105f6285SAndroid Build Coastguard Worker 278*105f6285SAndroid Build Coastguard Worker } 279*105f6285SAndroid Build Coastguard Worker 280*105f6285SAndroid Build Coastguard Worker if buildErrors > 0 { 281*105f6285SAndroid Build Coastguard Worker log.Fatal(fmt.Sprintf("Failed to build %d targets", buildErrors)) 282*105f6285SAndroid Build Coastguard Worker } 283*105f6285SAndroid Build Coastguard Worker} 284*105f6285SAndroid Build Coastguard Worker 285*105f6285SAndroid Build Coastguard Workerfunc printTextReport(w io.Writer, subcommand tool, rsp *response, verbose bool) { 286*105f6285SAndroid Build Coastguard Worker fmt.Fprintln(w, "Metric Report") 287*105f6285SAndroid Build Coastguard Worker if subcommand != nil { 288*105f6285SAndroid Build Coastguard Worker subcommand.PrintText(w, rsp, verbose) 289*105f6285SAndroid Build Coastguard Worker } 290*105f6285SAndroid Build Coastguard Worker 291*105f6285SAndroid Build Coastguard Worker if len(rsp.Commits) > 0 { 292*105f6285SAndroid Build Coastguard Worker fmt.Fprintln(w, "") 293*105f6285SAndroid Build Coastguard Worker fmt.Fprintln(w, " Commit Results") 294*105f6285SAndroid Build Coastguard Worker for _, c := range rsp.Commits { 295*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-120s : %s\n", c.Project.Project, c.Project.Revision) 296*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " SHA : %s\n", c.Commit.Sha) 297*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " Files : \n") 298*105f6285SAndroid Build Coastguard Worker for _, f := range c.Commit.Files { 299*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %s %s\n", f.Type.String(), f.Filename) 300*105f6285SAndroid Build Coastguard Worker } 301*105f6285SAndroid Build Coastguard Worker } 302*105f6285SAndroid Build Coastguard Worker } 303*105f6285SAndroid Build Coastguard Worker if len(rsp.BuildFiles) > 0 { 304*105f6285SAndroid Build Coastguard Worker fmt.Fprintln(w, "") 305*105f6285SAndroid Build Coastguard Worker fmt.Fprintln(w, " Build Files") 306*105f6285SAndroid Build Coastguard Worker for _, b := range rsp.BuildFiles { 307*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-120s : %t \n", b.Name, b.Success) 308*105f6285SAndroid Build Coastguard Worker } 309*105f6285SAndroid Build Coastguard Worker } 310*105f6285SAndroid Build Coastguard Worker 311*105f6285SAndroid Build Coastguard Worker targetPrint := func(target *app.BuildTarget) { 312*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-20s : %s\n", "Name", target.Name) 313*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-20s : %d\n", "Build Steps", target.Steps) 314*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-20s \n", "Inputs") 315*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-20s : %d\n", "Files", target.FileCount) 316*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-20s : %d\n", "Projects", len(target.Projects)) 317*105f6285SAndroid Build Coastguard Worker fmt.Fprintln(w) 318*105f6285SAndroid Build Coastguard Worker for name, proj := range target.Projects { 319*105f6285SAndroid Build Coastguard Worker forkCount := 0 320*105f6285SAndroid Build Coastguard Worker for _, file := range proj.Files { 321*105f6285SAndroid Build Coastguard Worker if file.BranchDiff != nil { 322*105f6285SAndroid Build Coastguard Worker forkCount++ 323*105f6285SAndroid Build Coastguard Worker } 324*105f6285SAndroid Build Coastguard Worker } 325*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-120s : %d ", name, len(proj.Files)) 326*105f6285SAndroid Build Coastguard Worker if forkCount != 0 { 327*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " (%d)\n", forkCount) 328*105f6285SAndroid Build Coastguard Worker } else { 329*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " \n") 330*105f6285SAndroid Build Coastguard Worker } 331*105f6285SAndroid Build Coastguard Worker 332*105f6285SAndroid Build Coastguard Worker if verbose { 333*105f6285SAndroid Build Coastguard Worker for _, file := range proj.Files { 334*105f6285SAndroid Build Coastguard Worker var fork string 335*105f6285SAndroid Build Coastguard Worker if file.BranchDiff != nil { 336*105f6285SAndroid Build Coastguard Worker fork = fmt.Sprintf("(%d+ %d-)", file.BranchDiff.AddedLines, file.BranchDiff.DeletedLines) 337*105f6285SAndroid Build Coastguard Worker } 338*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-20s %s\n", fork, file.Filename) 339*105f6285SAndroid Build Coastguard Worker } 340*105f6285SAndroid Build Coastguard Worker 341*105f6285SAndroid Build Coastguard Worker } 342*105f6285SAndroid Build Coastguard Worker } 343*105f6285SAndroid Build Coastguard Worker 344*105f6285SAndroid Build Coastguard Worker } 345*105f6285SAndroid Build Coastguard Worker fmt.Fprintln(w, " Targets") 346*105f6285SAndroid Build Coastguard Worker for _, t := range rsp.Report.Targets { 347*105f6285SAndroid Build Coastguard Worker targetPrint(t) 348*105f6285SAndroid Build Coastguard Worker } 349*105f6285SAndroid Build Coastguard Worker 350*105f6285SAndroid Build Coastguard Worker fmt.Fprintln(w, " Run Times") 351*105f6285SAndroid Build Coastguard Worker for _, p := range rsp.Profile { 352*105f6285SAndroid Build Coastguard Worker fmt.Fprintf(w, " %-30s : %f secs\n", p.Description, p.DurationSecs) 353*105f6285SAndroid Build Coastguard Worker } 354*105f6285SAndroid Build Coastguard Worker 355*105f6285SAndroid Build Coastguard Worker} 356