1// Copyright 2022 The Android Open Source Project 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 15package report 16 17import ( 18 "context" 19 "fmt" 20 "sync" 21 22 "tools/treble/build/report/app" 23) 24 25// Channel data structures, include explicit error field to reply to each input 26type buildTargetData struct { 27 input *app.BuildInput 28 buildSteps int 29 error bool 30} 31type buildSourceData struct { 32 source string 33 query *app.BuildQuery 34 error bool 35} 36type buildPathData struct { 37 filename string 38 path *app.BuildPath 39 error bool 40} 41 42// 43// create build target from using repo data 44// 45func createBuildTarget(ctx context.Context, rtx *Context, buildTarget *buildTargetData) *app.BuildTarget { 46 out := &app.BuildTarget{Name: buildTarget.input.Target, 47 Steps: buildTarget.buildSteps, 48 Projects: make(map[string]*app.GitProject), 49 FileCount: len(buildTarget.input.Files), 50 } 51 52 for _, f := range buildTarget.input.Files { 53 proj, buildFile := lookupProjectFile(ctx, rtx, f) 54 if buildFile != nil { 55 if buildProj, exists := out.Projects[proj.Name]; exists { 56 buildProj.Files[buildFile.Filename] = buildFile 57 } else { 58 out.Projects[proj.Name] = 59 &app.GitProject{ 60 RepoDir: proj.GitProj.RepoDir, 61 WorkDir: proj.GitProj.WorkDir, 62 GitDir: proj.GitProj.GitDir, 63 Remote: proj.GitProj.Remote, 64 RemoteUrl: proj.GitProj.RemoteUrl, 65 Revision: proj.GitProj.Revision, 66 Files: map[string]*app.GitTreeObj{buildFile.Filename: buildFile}} 67 } 68 } 69 } 70 return (out) 71} 72 73// Setup routines to resolve target names to app.BuildInput objects 74func targetResolvers(ctx context.Context, rtx *Context) (chan string, chan *buildTargetData) { 75 var wg sync.WaitGroup 76 inChan := make(chan string) 77 outChan := make(chan *buildTargetData) 78 for i := 0; i < rtx.BuildWorkerCount; i++ { 79 wg.Add(1) 80 go func() { 81 for targetName := range inChan { 82 var buildSteps int 83 cmds, err := rtx.Build.Command(ctx, targetName) 84 if err == nil { 85 buildSteps = len(cmds.Cmds) 86 } 87 input, err := rtx.Build.Input(ctx, targetName) 88 if input == nil { 89 fmt.Printf("Failed to get input %s (%s)\n", targetName, err) 90 } else { 91 outChan <- &buildTargetData{input: input, buildSteps: buildSteps, error: err != nil} 92 } 93 } 94 wg.Done() 95 }() 96 } 97 go func() { 98 wg.Wait() 99 close(outChan) 100 }() 101 102 return inChan, outChan 103} 104 105// 106// Setup routines to resolve build input targets to BuildTarget 107func resolveBuildInputs(ctx context.Context, rtx *Context, inChan chan *buildTargetData) chan *app.BuildTarget { 108 var wg sync.WaitGroup 109 outChan := make(chan *app.BuildTarget) 110 for i := 0; i < rtx.BuildWorkerCount; i++ { 111 wg.Add(1) 112 go func() { 113 for buildTarget := range inChan { 114 outChan <- createBuildTarget(ctx, rtx, buildTarget) 115 } 116 wg.Done() 117 }() 118 } 119 go func() { 120 wg.Wait() 121 close(outChan) 122 }() 123 return outChan 124} 125 126// Setup routines to resolve source file to query 127func queryResolvers(ctx context.Context, rtx *Context) (chan string, chan *buildSourceData) { 128 var wg sync.WaitGroup 129 inChan := make(chan string) 130 outChan := make(chan *buildSourceData) 131 for i := 0; i < rtx.BuildWorkerCount; i++ { 132 wg.Add(1) 133 go func() { 134 for srcName := range inChan { 135 query, err := rtx.Build.Query(ctx, srcName) 136 outChan <- &buildSourceData{source: srcName, query: query, error: err != nil} 137 } 138 wg.Done() 139 }() 140 } 141 go func() { 142 wg.Wait() 143 close(outChan) 144 }() 145 146 return inChan, outChan 147} 148 149// Setup routines to resolve paths 150func pathsResolvers(ctx context.Context, rtx *Context, target string, singlePath bool) (chan string, chan *buildPathData) { 151 var wg sync.WaitGroup 152 inChan := make(chan string) 153 outChan := make(chan *buildPathData) 154 for i := 0; i < rtx.BuildWorkerCount; i++ { 155 wg.Add(1) 156 go func() { 157 for dep := range inChan { 158 if singlePath { 159 path, err := rtx.Build.Path(ctx, target, dep) 160 outChan <- &buildPathData{filename: dep, path: path, error: err != nil} 161 } else { 162 paths, err := rtx.Build.Paths(ctx, target, dep) 163 if err != nil { 164 outChan <- &buildPathData{filename: dep, path: nil, error: true} 165 } else { 166 for _, path := range paths { 167 168 outChan <- &buildPathData{filename: dep, path: path, error: false} 169 } 170 } 171 } 172 } 173 wg.Done() 174 }() 175 } 176 go func() { 177 wg.Wait() 178 close(outChan) 179 }() 180 181 return inChan, outChan 182} 183