1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2014 Google Inc. All rights reserved. 2*1fa6dee9SAndroid Build Coastguard Worker// 3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*1fa6dee9SAndroid Build Coastguard Worker// 7*1fa6dee9SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*1fa6dee9SAndroid Build Coastguard Worker// 9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License. 14*1fa6dee9SAndroid Build Coastguard Worker 15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint 16*1fa6dee9SAndroid Build Coastguard Worker 17*1fa6dee9SAndroid Build Coastguard Workerimport ( 18*1fa6dee9SAndroid Build Coastguard Worker "bufio" 19*1fa6dee9SAndroid Build Coastguard Worker "bytes" 20*1fa6dee9SAndroid Build Coastguard Worker "cmp" 21*1fa6dee9SAndroid Build Coastguard Worker "context" 22*1fa6dee9SAndroid Build Coastguard Worker "encoding/gob" 23*1fa6dee9SAndroid Build Coastguard Worker "encoding/json" 24*1fa6dee9SAndroid Build Coastguard Worker "errors" 25*1fa6dee9SAndroid Build Coastguard Worker "fmt" 26*1fa6dee9SAndroid Build Coastguard Worker "hash/fnv" 27*1fa6dee9SAndroid Build Coastguard Worker "io" 28*1fa6dee9SAndroid Build Coastguard Worker "io/ioutil" 29*1fa6dee9SAndroid Build Coastguard Worker "iter" 30*1fa6dee9SAndroid Build Coastguard Worker "maps" 31*1fa6dee9SAndroid Build Coastguard Worker "math" 32*1fa6dee9SAndroid Build Coastguard Worker "os" 33*1fa6dee9SAndroid Build Coastguard Worker "path/filepath" 34*1fa6dee9SAndroid Build Coastguard Worker "reflect" 35*1fa6dee9SAndroid Build Coastguard Worker "runtime" 36*1fa6dee9SAndroid Build Coastguard Worker "runtime/pprof" 37*1fa6dee9SAndroid Build Coastguard Worker "slices" 38*1fa6dee9SAndroid Build Coastguard Worker "sort" 39*1fa6dee9SAndroid Build Coastguard Worker "strconv" 40*1fa6dee9SAndroid Build Coastguard Worker "strings" 41*1fa6dee9SAndroid Build Coastguard Worker "sync" 42*1fa6dee9SAndroid Build Coastguard Worker "sync/atomic" 43*1fa6dee9SAndroid Build Coastguard Worker "text/scanner" 44*1fa6dee9SAndroid Build Coastguard Worker "text/template" 45*1fa6dee9SAndroid Build Coastguard Worker "unsafe" 46*1fa6dee9SAndroid Build Coastguard Worker 47*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/metrics" 48*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/parser" 49*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/pathtools" 50*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 51*1fa6dee9SAndroid Build Coastguard Worker) 52*1fa6dee9SAndroid Build Coastguard Worker 53*1fa6dee9SAndroid Build Coastguard Workervar ErrBuildActionsNotReady = errors.New("build actions are not ready") 54*1fa6dee9SAndroid Build Coastguard Worker 55*1fa6dee9SAndroid Build Coastguard Workerconst maxErrors = 10 56*1fa6dee9SAndroid Build Coastguard Workerconst MockModuleListFile = "bplist" 57*1fa6dee9SAndroid Build Coastguard Worker 58*1fa6dee9SAndroid Build Coastguard Workerconst OutFilePermissions = 0666 59*1fa6dee9SAndroid Build Coastguard Worker 60*1fa6dee9SAndroid Build Coastguard Workerconst BuildActionsCacheFile = "build_actions.gob" 61*1fa6dee9SAndroid Build Coastguard Workerconst OrderOnlyStringsCacheFile = "order_only_strings.gob" 62*1fa6dee9SAndroid Build Coastguard Worker 63*1fa6dee9SAndroid Build Coastguard Worker// A Context contains all the state needed to parse a set of Blueprints files 64*1fa6dee9SAndroid Build Coastguard Worker// and generate a Ninja file. The process of generating a Ninja file proceeds 65*1fa6dee9SAndroid Build Coastguard Worker// through a series of four phases. Each phase corresponds with a some methods 66*1fa6dee9SAndroid Build Coastguard Worker// on the Context object 67*1fa6dee9SAndroid Build Coastguard Worker// 68*1fa6dee9SAndroid Build Coastguard Worker// Phase Methods 69*1fa6dee9SAndroid Build Coastguard Worker// ------------ ------------------------------------------- 70*1fa6dee9SAndroid Build Coastguard Worker// 1. Registration RegisterModuleType, RegisterSingletonType 71*1fa6dee9SAndroid Build Coastguard Worker// 72*1fa6dee9SAndroid Build Coastguard Worker// 2. Parse ParseBlueprintsFiles, Parse 73*1fa6dee9SAndroid Build Coastguard Worker// 74*1fa6dee9SAndroid Build Coastguard Worker// 3. Generate ResolveDependencies, PrepareBuildActions 75*1fa6dee9SAndroid Build Coastguard Worker// 76*1fa6dee9SAndroid Build Coastguard Worker// 4. Write WriteBuildFile 77*1fa6dee9SAndroid Build Coastguard Worker// 78*1fa6dee9SAndroid Build Coastguard Worker// The registration phase prepares the context to process Blueprints files 79*1fa6dee9SAndroid Build Coastguard Worker// containing various types of modules. The parse phase reads in one or more 80*1fa6dee9SAndroid Build Coastguard Worker// Blueprints files and validates their contents against the module types that 81*1fa6dee9SAndroid Build Coastguard Worker// have been registered. The generate phase then analyzes the parsed Blueprints 82*1fa6dee9SAndroid Build Coastguard Worker// contents to create an internal representation for the build actions that must 83*1fa6dee9SAndroid Build Coastguard Worker// be performed. This phase also performs validation of the module dependencies 84*1fa6dee9SAndroid Build Coastguard Worker// and property values defined in the parsed Blueprints files. Finally, the 85*1fa6dee9SAndroid Build Coastguard Worker// write phase generates the Ninja manifest text based on the generated build 86*1fa6dee9SAndroid Build Coastguard Worker// actions. 87*1fa6dee9SAndroid Build Coastguard Workertype Context struct { 88*1fa6dee9SAndroid Build Coastguard Worker context.Context 89*1fa6dee9SAndroid Build Coastguard Worker 90*1fa6dee9SAndroid Build Coastguard Worker // Used for metrics-related event logging. 91*1fa6dee9SAndroid Build Coastguard Worker EventHandler *metrics.EventHandler 92*1fa6dee9SAndroid Build Coastguard Worker 93*1fa6dee9SAndroid Build Coastguard Worker BeforePrepareBuildActionsHook func() error 94*1fa6dee9SAndroid Build Coastguard Worker 95*1fa6dee9SAndroid Build Coastguard Worker moduleFactories map[string]ModuleFactory 96*1fa6dee9SAndroid Build Coastguard Worker nameInterface NameInterface 97*1fa6dee9SAndroid Build Coastguard Worker moduleGroups []*moduleGroup 98*1fa6dee9SAndroid Build Coastguard Worker moduleInfo map[Module]*moduleInfo 99*1fa6dee9SAndroid Build Coastguard Worker singletonInfo []*singletonInfo 100*1fa6dee9SAndroid Build Coastguard Worker mutatorInfo []*mutatorInfo 101*1fa6dee9SAndroid Build Coastguard Worker variantMutatorNames []string 102*1fa6dee9SAndroid Build Coastguard Worker 103*1fa6dee9SAndroid Build Coastguard Worker variantCreatingMutatorOrder []string 104*1fa6dee9SAndroid Build Coastguard Worker 105*1fa6dee9SAndroid Build Coastguard Worker transitionMutators []*transitionMutatorImpl 106*1fa6dee9SAndroid Build Coastguard Worker 107*1fa6dee9SAndroid Build Coastguard Worker needsUpdateDependencies uint32 // positive if a mutator modified the dependencies 108*1fa6dee9SAndroid Build Coastguard Worker 109*1fa6dee9SAndroid Build Coastguard Worker dependenciesReady bool // set to true on a successful ResolveDependencies 110*1fa6dee9SAndroid Build Coastguard Worker buildActionsReady bool // set to true on a successful PrepareBuildActions 111*1fa6dee9SAndroid Build Coastguard Worker 112*1fa6dee9SAndroid Build Coastguard Worker // set by SetIgnoreUnknownModuleTypes 113*1fa6dee9SAndroid Build Coastguard Worker ignoreUnknownModuleTypes bool 114*1fa6dee9SAndroid Build Coastguard Worker 115*1fa6dee9SAndroid Build Coastguard Worker // set by SetAllowMissingDependencies 116*1fa6dee9SAndroid Build Coastguard Worker allowMissingDependencies bool 117*1fa6dee9SAndroid Build Coastguard Worker 118*1fa6dee9SAndroid Build Coastguard Worker // set during PrepareBuildActions 119*1fa6dee9SAndroid Build Coastguard Worker nameTracker *nameTracker 120*1fa6dee9SAndroid Build Coastguard Worker liveGlobals *liveTracker 121*1fa6dee9SAndroid Build Coastguard Worker globalVariables map[Variable]*ninjaString 122*1fa6dee9SAndroid Build Coastguard Worker globalPools map[Pool]*poolDef 123*1fa6dee9SAndroid Build Coastguard Worker globalRules map[Rule]*ruleDef 124*1fa6dee9SAndroid Build Coastguard Worker 125*1fa6dee9SAndroid Build Coastguard Worker // set during PrepareBuildActions 126*1fa6dee9SAndroid Build Coastguard Worker outDir *ninjaString // The builddir special Ninja variable 127*1fa6dee9SAndroid Build Coastguard Worker requiredNinjaMajor int // For the ninja_required_version variable 128*1fa6dee9SAndroid Build Coastguard Worker requiredNinjaMinor int // For the ninja_required_version variable 129*1fa6dee9SAndroid Build Coastguard Worker requiredNinjaMicro int // For the ninja_required_version variable 130*1fa6dee9SAndroid Build Coastguard Worker 131*1fa6dee9SAndroid Build Coastguard Worker subninjas []string 132*1fa6dee9SAndroid Build Coastguard Worker 133*1fa6dee9SAndroid Build Coastguard Worker // set lazily by sortedModuleGroups 134*1fa6dee9SAndroid Build Coastguard Worker cachedSortedModuleGroups []*moduleGroup 135*1fa6dee9SAndroid Build Coastguard Worker // cache deps modified to determine whether cachedSortedModuleGroups needs to be recalculated 136*1fa6dee9SAndroid Build Coastguard Worker cachedDepsModified bool 137*1fa6dee9SAndroid Build Coastguard Worker 138*1fa6dee9SAndroid Build Coastguard Worker globs map[globKey]pathtools.GlobResult 139*1fa6dee9SAndroid Build Coastguard Worker globLock sync.Mutex 140*1fa6dee9SAndroid Build Coastguard Worker 141*1fa6dee9SAndroid Build Coastguard Worker srcDir string 142*1fa6dee9SAndroid Build Coastguard Worker fs pathtools.FileSystem 143*1fa6dee9SAndroid Build Coastguard Worker moduleListFile string 144*1fa6dee9SAndroid Build Coastguard Worker 145*1fa6dee9SAndroid Build Coastguard Worker // Mutators indexed by the ID of the provider associated with them. Not all mutators will 146*1fa6dee9SAndroid Build Coastguard Worker // have providers, and not all providers will have a mutator, or if they do the mutator may 147*1fa6dee9SAndroid Build Coastguard Worker // not be registered in this Context. 148*1fa6dee9SAndroid Build Coastguard Worker providerMutators []*mutatorInfo 149*1fa6dee9SAndroid Build Coastguard Worker 150*1fa6dee9SAndroid Build Coastguard Worker // True for the index of any mutators that have already run over all modules 151*1fa6dee9SAndroid Build Coastguard Worker finishedMutators []bool 152*1fa6dee9SAndroid Build Coastguard Worker 153*1fa6dee9SAndroid Build Coastguard Worker // If true, RunBlueprint will skip cloning modules at the end of RunBlueprint. 154*1fa6dee9SAndroid Build Coastguard Worker // Cloning modules intentionally invalidates some Module values after 155*1fa6dee9SAndroid Build Coastguard Worker // mutators run (to ensure that mutators don't set such Module values in a way 156*1fa6dee9SAndroid Build Coastguard Worker // which ruins the integrity of the graph). However, keeping Module values 157*1fa6dee9SAndroid Build Coastguard Worker // changed by mutators may be a desirable outcome (such as for tooling or tests). 158*1fa6dee9SAndroid Build Coastguard Worker SkipCloneModulesAfterMutators bool 159*1fa6dee9SAndroid Build Coastguard Worker 160*1fa6dee9SAndroid Build Coastguard Worker // String values that can be used to gate build graph traversal 161*1fa6dee9SAndroid Build Coastguard Worker includeTags *IncludeTags 162*1fa6dee9SAndroid Build Coastguard Worker 163*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs *SourceRootDirs 164*1fa6dee9SAndroid Build Coastguard Worker 165*1fa6dee9SAndroid Build Coastguard Worker // True if an incremental analysis can be attempted, i.e., there is no Soong 166*1fa6dee9SAndroid Build Coastguard Worker // code changes, no environmental variable changes and no product config 167*1fa6dee9SAndroid Build Coastguard Worker // variable changes. 168*1fa6dee9SAndroid Build Coastguard Worker incrementalAnalysis bool 169*1fa6dee9SAndroid Build Coastguard Worker 170*1fa6dee9SAndroid Build Coastguard Worker // True if the flag --incremental-build-actions is set, in which case Soong 171*1fa6dee9SAndroid Build Coastguard Worker // will try to do a incremental build. Mainly two tasks will involve here: 172*1fa6dee9SAndroid Build Coastguard Worker // caching the providers of all the participating modules, and restoring the 173*1fa6dee9SAndroid Build Coastguard Worker // providers and skip the build action generations if there is a cache hit. 174*1fa6dee9SAndroid Build Coastguard Worker // Enabling this flag will only guarantee the former task to be performed, the 175*1fa6dee9SAndroid Build Coastguard Worker // latter will depend on the flag above. 176*1fa6dee9SAndroid Build Coastguard Worker incrementalEnabled bool 177*1fa6dee9SAndroid Build Coastguard Worker 178*1fa6dee9SAndroid Build Coastguard Worker buildActionsToCache BuildActionCache 179*1fa6dee9SAndroid Build Coastguard Worker buildActionsToCacheLock sync.Mutex 180*1fa6dee9SAndroid Build Coastguard Worker buildActionsFromCache BuildActionCache 181*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStringsFromCache OrderOnlyStringsCache 182*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStringsToCache OrderOnlyStringsCache 183*1fa6dee9SAndroid Build Coastguard Worker} 184*1fa6dee9SAndroid Build Coastguard Worker 185*1fa6dee9SAndroid Build Coastguard Worker// A container for String keys. The keys can be used to gate build graph traversal 186*1fa6dee9SAndroid Build Coastguard Workertype SourceRootDirs struct { 187*1fa6dee9SAndroid Build Coastguard Worker dirs []string 188*1fa6dee9SAndroid Build Coastguard Worker} 189*1fa6dee9SAndroid Build Coastguard Worker 190*1fa6dee9SAndroid Build Coastguard Workerfunc (dirs *SourceRootDirs) Add(names ...string) { 191*1fa6dee9SAndroid Build Coastguard Worker dirs.dirs = append(dirs.dirs, names...) 192*1fa6dee9SAndroid Build Coastguard Worker} 193*1fa6dee9SAndroid Build Coastguard Worker 194*1fa6dee9SAndroid Build Coastguard Workerfunc (dirs *SourceRootDirs) SourceRootDirAllowed(path string) (bool, string) { 195*1fa6dee9SAndroid Build Coastguard Worker sort.Slice(dirs.dirs, func(i, j int) bool { 196*1fa6dee9SAndroid Build Coastguard Worker return len(dirs.dirs[i]) < len(dirs.dirs[j]) 197*1fa6dee9SAndroid Build Coastguard Worker }) 198*1fa6dee9SAndroid Build Coastguard Worker last := len(dirs.dirs) 199*1fa6dee9SAndroid Build Coastguard Worker for i := range dirs.dirs { 200*1fa6dee9SAndroid Build Coastguard Worker // iterate from longest paths (most specific) 201*1fa6dee9SAndroid Build Coastguard Worker prefix := dirs.dirs[last-i-1] 202*1fa6dee9SAndroid Build Coastguard Worker disallowedPrefix := false 203*1fa6dee9SAndroid Build Coastguard Worker if len(prefix) >= 1 && prefix[0] == '-' { 204*1fa6dee9SAndroid Build Coastguard Worker prefix = prefix[1:] 205*1fa6dee9SAndroid Build Coastguard Worker disallowedPrefix = true 206*1fa6dee9SAndroid Build Coastguard Worker } 207*1fa6dee9SAndroid Build Coastguard Worker if strings.HasPrefix(path, prefix) { 208*1fa6dee9SAndroid Build Coastguard Worker if disallowedPrefix { 209*1fa6dee9SAndroid Build Coastguard Worker return false, prefix 210*1fa6dee9SAndroid Build Coastguard Worker } else { 211*1fa6dee9SAndroid Build Coastguard Worker return true, prefix 212*1fa6dee9SAndroid Build Coastguard Worker } 213*1fa6dee9SAndroid Build Coastguard Worker } 214*1fa6dee9SAndroid Build Coastguard Worker } 215*1fa6dee9SAndroid Build Coastguard Worker return true, "" 216*1fa6dee9SAndroid Build Coastguard Worker} 217*1fa6dee9SAndroid Build Coastguard Worker 218*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) AddSourceRootDirs(dirs ...string) { 219*1fa6dee9SAndroid Build Coastguard Worker c.sourceRootDirs.Add(dirs...) 220*1fa6dee9SAndroid Build Coastguard Worker} 221*1fa6dee9SAndroid Build Coastguard Worker 222*1fa6dee9SAndroid Build Coastguard Worker// A container for String keys. The keys can be used to gate build graph traversal 223*1fa6dee9SAndroid Build Coastguard Workertype IncludeTags map[string]bool 224*1fa6dee9SAndroid Build Coastguard Worker 225*1fa6dee9SAndroid Build Coastguard Workerfunc (tags *IncludeTags) Add(names ...string) { 226*1fa6dee9SAndroid Build Coastguard Worker for _, name := range names { 227*1fa6dee9SAndroid Build Coastguard Worker (*tags)[name] = true 228*1fa6dee9SAndroid Build Coastguard Worker } 229*1fa6dee9SAndroid Build Coastguard Worker} 230*1fa6dee9SAndroid Build Coastguard Worker 231*1fa6dee9SAndroid Build Coastguard Workerfunc (tags *IncludeTags) Contains(tag string) bool { 232*1fa6dee9SAndroid Build Coastguard Worker _, exists := (*tags)[tag] 233*1fa6dee9SAndroid Build Coastguard Worker return exists 234*1fa6dee9SAndroid Build Coastguard Worker} 235*1fa6dee9SAndroid Build Coastguard Worker 236*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) AddIncludeTags(names ...string) { 237*1fa6dee9SAndroid Build Coastguard Worker c.includeTags.Add(names...) 238*1fa6dee9SAndroid Build Coastguard Worker} 239*1fa6dee9SAndroid Build Coastguard Worker 240*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ContainsIncludeTag(name string) bool { 241*1fa6dee9SAndroid Build Coastguard Worker return c.includeTags.Contains(name) 242*1fa6dee9SAndroid Build Coastguard Worker} 243*1fa6dee9SAndroid Build Coastguard Worker 244*1fa6dee9SAndroid Build Coastguard Worker// iterateAllVariants returns an iter.Seq that iterates over every variant of every module. 245*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) iterateAllVariants() iter.Seq[*moduleInfo] { 246*1fa6dee9SAndroid Build Coastguard Worker return func(yield func(*moduleInfo) bool) { 247*1fa6dee9SAndroid Build Coastguard Worker for _, group := range c.moduleGroups { 248*1fa6dee9SAndroid Build Coastguard Worker for _, module := range group.modules { 249*1fa6dee9SAndroid Build Coastguard Worker if !yield(module) { 250*1fa6dee9SAndroid Build Coastguard Worker return 251*1fa6dee9SAndroid Build Coastguard Worker } 252*1fa6dee9SAndroid Build Coastguard Worker } 253*1fa6dee9SAndroid Build Coastguard Worker } 254*1fa6dee9SAndroid Build Coastguard Worker } 255*1fa6dee9SAndroid Build Coastguard Worker} 256*1fa6dee9SAndroid Build Coastguard Worker 257*1fa6dee9SAndroid Build Coastguard Worker// An Error describes a problem that was encountered that is related to a 258*1fa6dee9SAndroid Build Coastguard Worker// particular location in a Blueprints file. 259*1fa6dee9SAndroid Build Coastguard Workertype BlueprintError struct { 260*1fa6dee9SAndroid Build Coastguard Worker Err error // the error that occurred 261*1fa6dee9SAndroid Build Coastguard Worker Pos scanner.Position // the relevant Blueprints file location 262*1fa6dee9SAndroid Build Coastguard Worker} 263*1fa6dee9SAndroid Build Coastguard Worker 264*1fa6dee9SAndroid Build Coastguard Worker// A ModuleError describes a problem that was encountered that is related to a 265*1fa6dee9SAndroid Build Coastguard Worker// particular module in a Blueprints file 266*1fa6dee9SAndroid Build Coastguard Workertype ModuleError struct { 267*1fa6dee9SAndroid Build Coastguard Worker BlueprintError 268*1fa6dee9SAndroid Build Coastguard Worker module *moduleInfo 269*1fa6dee9SAndroid Build Coastguard Worker} 270*1fa6dee9SAndroid Build Coastguard Worker 271*1fa6dee9SAndroid Build Coastguard Worker// A PropertyError describes a problem that was encountered that is related to a 272*1fa6dee9SAndroid Build Coastguard Worker// particular property in a Blueprints file 273*1fa6dee9SAndroid Build Coastguard Workertype PropertyError struct { 274*1fa6dee9SAndroid Build Coastguard Worker ModuleError 275*1fa6dee9SAndroid Build Coastguard Worker property string 276*1fa6dee9SAndroid Build Coastguard Worker} 277*1fa6dee9SAndroid Build Coastguard Worker 278*1fa6dee9SAndroid Build Coastguard Workerfunc (e *BlueprintError) Error() string { 279*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%s: %s", e.Pos, e.Err) 280*1fa6dee9SAndroid Build Coastguard Worker} 281*1fa6dee9SAndroid Build Coastguard Worker 282*1fa6dee9SAndroid Build Coastguard Workerfunc (e *ModuleError) Error() string { 283*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err) 284*1fa6dee9SAndroid Build Coastguard Worker} 285*1fa6dee9SAndroid Build Coastguard Worker 286*1fa6dee9SAndroid Build Coastguard Workerfunc (e *PropertyError) Error() string { 287*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err) 288*1fa6dee9SAndroid Build Coastguard Worker} 289*1fa6dee9SAndroid Build Coastguard Worker 290*1fa6dee9SAndroid Build Coastguard Workertype localBuildActions struct { 291*1fa6dee9SAndroid Build Coastguard Worker variables []*localVariable 292*1fa6dee9SAndroid Build Coastguard Worker rules []*localRule 293*1fa6dee9SAndroid Build Coastguard Worker buildDefs []*buildDef 294*1fa6dee9SAndroid Build Coastguard Worker} 295*1fa6dee9SAndroid Build Coastguard Worker 296*1fa6dee9SAndroid Build Coastguard Workertype moduleList []*moduleInfo 297*1fa6dee9SAndroid Build Coastguard Worker 298*1fa6dee9SAndroid Build Coastguard Workerfunc (l moduleList) firstModule() *moduleInfo { 299*1fa6dee9SAndroid Build Coastguard Worker if len(l) > 0 { 300*1fa6dee9SAndroid Build Coastguard Worker return l[0] 301*1fa6dee9SAndroid Build Coastguard Worker } 302*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("no first module!")) 303*1fa6dee9SAndroid Build Coastguard Worker} 304*1fa6dee9SAndroid Build Coastguard Worker 305*1fa6dee9SAndroid Build Coastguard Workerfunc (l moduleList) lastModule() *moduleInfo { 306*1fa6dee9SAndroid Build Coastguard Worker if len(l) > 0 { 307*1fa6dee9SAndroid Build Coastguard Worker return l[len(l)-1] 308*1fa6dee9SAndroid Build Coastguard Worker } 309*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("no last module!")) 310*1fa6dee9SAndroid Build Coastguard Worker} 311*1fa6dee9SAndroid Build Coastguard Worker 312*1fa6dee9SAndroid Build Coastguard Workertype moduleGroup struct { 313*1fa6dee9SAndroid Build Coastguard Worker name string 314*1fa6dee9SAndroid Build Coastguard Worker ninjaName string 315*1fa6dee9SAndroid Build Coastguard Worker 316*1fa6dee9SAndroid Build Coastguard Worker modules moduleList 317*1fa6dee9SAndroid Build Coastguard Worker 318*1fa6dee9SAndroid Build Coastguard Worker namespace Namespace 319*1fa6dee9SAndroid Build Coastguard Worker} 320*1fa6dee9SAndroid Build Coastguard Worker 321*1fa6dee9SAndroid Build Coastguard Workerfunc (group *moduleGroup) moduleByVariantName(name string) *moduleInfo { 322*1fa6dee9SAndroid Build Coastguard Worker for _, module := range group.modules { 323*1fa6dee9SAndroid Build Coastguard Worker if module.variant.name == name { 324*1fa6dee9SAndroid Build Coastguard Worker return module 325*1fa6dee9SAndroid Build Coastguard Worker } 326*1fa6dee9SAndroid Build Coastguard Worker } 327*1fa6dee9SAndroid Build Coastguard Worker return nil 328*1fa6dee9SAndroid Build Coastguard Worker} 329*1fa6dee9SAndroid Build Coastguard Worker 330*1fa6dee9SAndroid Build Coastguard Workertype moduleInfo struct { 331*1fa6dee9SAndroid Build Coastguard Worker // set during Parse 332*1fa6dee9SAndroid Build Coastguard Worker typeName string 333*1fa6dee9SAndroid Build Coastguard Worker factory ModuleFactory 334*1fa6dee9SAndroid Build Coastguard Worker relBlueprintsFile string 335*1fa6dee9SAndroid Build Coastguard Worker pos scanner.Position 336*1fa6dee9SAndroid Build Coastguard Worker propertyPos map[string]scanner.Position 337*1fa6dee9SAndroid Build Coastguard Worker createdBy *moduleInfo 338*1fa6dee9SAndroid Build Coastguard Worker 339*1fa6dee9SAndroid Build Coastguard Worker variant variant 340*1fa6dee9SAndroid Build Coastguard Worker 341*1fa6dee9SAndroid Build Coastguard Worker logicModule Module 342*1fa6dee9SAndroid Build Coastguard Worker group *moduleGroup 343*1fa6dee9SAndroid Build Coastguard Worker properties []interface{} 344*1fa6dee9SAndroid Build Coastguard Worker 345*1fa6dee9SAndroid Build Coastguard Worker // set during ResolveDependencies 346*1fa6dee9SAndroid Build Coastguard Worker missingDeps []string 347*1fa6dee9SAndroid Build Coastguard Worker newDirectDeps []*moduleInfo 348*1fa6dee9SAndroid Build Coastguard Worker 349*1fa6dee9SAndroid Build Coastguard Worker // set during updateDependencies 350*1fa6dee9SAndroid Build Coastguard Worker reverseDeps []*moduleInfo 351*1fa6dee9SAndroid Build Coastguard Worker forwardDeps []*moduleInfo 352*1fa6dee9SAndroid Build Coastguard Worker directDeps []depInfo 353*1fa6dee9SAndroid Build Coastguard Worker 354*1fa6dee9SAndroid Build Coastguard Worker // used by parallelVisit 355*1fa6dee9SAndroid Build Coastguard Worker waitingCount int 356*1fa6dee9SAndroid Build Coastguard Worker 357*1fa6dee9SAndroid Build Coastguard Worker // set during each runMutator 358*1fa6dee9SAndroid Build Coastguard Worker splitModules moduleList 359*1fa6dee9SAndroid Build Coastguard Worker obsoletedByNewVariants bool 360*1fa6dee9SAndroid Build Coastguard Worker 361*1fa6dee9SAndroid Build Coastguard Worker // Used by TransitionMutator implementations 362*1fa6dee9SAndroid Build Coastguard Worker transitionVariations []string 363*1fa6dee9SAndroid Build Coastguard Worker currentTransitionMutator string 364*1fa6dee9SAndroid Build Coastguard Worker requiredVariationsLock sync.Mutex 365*1fa6dee9SAndroid Build Coastguard Worker 366*1fa6dee9SAndroid Build Coastguard Worker // outgoingTransitionCache stores the final variation for each dependency, indexed by the source variation 367*1fa6dee9SAndroid Build Coastguard Worker // index in transitionVariations and then by the index of the dependency in directDeps 368*1fa6dee9SAndroid Build Coastguard Worker outgoingTransitionCache [][]string 369*1fa6dee9SAndroid Build Coastguard Worker 370*1fa6dee9SAndroid Build Coastguard Worker // set during PrepareBuildActions 371*1fa6dee9SAndroid Build Coastguard Worker actionDefs localBuildActions 372*1fa6dee9SAndroid Build Coastguard Worker 373*1fa6dee9SAndroid Build Coastguard Worker providers []interface{} 374*1fa6dee9SAndroid Build Coastguard Worker providerInitialValueHashes []uint64 375*1fa6dee9SAndroid Build Coastguard Worker 376*1fa6dee9SAndroid Build Coastguard Worker startedMutator int 377*1fa6dee9SAndroid Build Coastguard Worker finishedMutator int 378*1fa6dee9SAndroid Build Coastguard Worker 379*1fa6dee9SAndroid Build Coastguard Worker startedGenerateBuildActions bool 380*1fa6dee9SAndroid Build Coastguard Worker finishedGenerateBuildActions bool 381*1fa6dee9SAndroid Build Coastguard Worker 382*1fa6dee9SAndroid Build Coastguard Worker incrementalInfo 383*1fa6dee9SAndroid Build Coastguard Worker} 384*1fa6dee9SAndroid Build Coastguard Worker 385*1fa6dee9SAndroid Build Coastguard Workertype incrementalInfo struct { 386*1fa6dee9SAndroid Build Coastguard Worker incrementalRestored bool 387*1fa6dee9SAndroid Build Coastguard Worker buildActionCacheKey *BuildActionCacheKey 388*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStrings []string 389*1fa6dee9SAndroid Build Coastguard Worker} 390*1fa6dee9SAndroid Build Coastguard Worker 391*1fa6dee9SAndroid Build Coastguard Workertype variant struct { 392*1fa6dee9SAndroid Build Coastguard Worker name string 393*1fa6dee9SAndroid Build Coastguard Worker variations variationMap 394*1fa6dee9SAndroid Build Coastguard Worker} 395*1fa6dee9SAndroid Build Coastguard Worker 396*1fa6dee9SAndroid Build Coastguard Workertype depInfo struct { 397*1fa6dee9SAndroid Build Coastguard Worker module *moduleInfo 398*1fa6dee9SAndroid Build Coastguard Worker tag DependencyTag 399*1fa6dee9SAndroid Build Coastguard Worker} 400*1fa6dee9SAndroid Build Coastguard Worker 401*1fa6dee9SAndroid Build Coastguard Workerfunc (module *moduleInfo) Name() string { 402*1fa6dee9SAndroid Build Coastguard Worker // If this is called from a LoadHook (which is run before the module has been registered) 403*1fa6dee9SAndroid Build Coastguard Worker // then group will not be set and so the name is retrieved from logicModule.Name(). 404*1fa6dee9SAndroid Build Coastguard Worker // Usually, using that method is not safe as it does not track renames (group.name does). 405*1fa6dee9SAndroid Build Coastguard Worker // However, when called from LoadHook it is safe as there is no way to rename a module 406*1fa6dee9SAndroid Build Coastguard Worker // until after the LoadHook has run and the module has been registered. 407*1fa6dee9SAndroid Build Coastguard Worker if module.group != nil { 408*1fa6dee9SAndroid Build Coastguard Worker return module.group.name 409*1fa6dee9SAndroid Build Coastguard Worker } else { 410*1fa6dee9SAndroid Build Coastguard Worker return module.logicModule.Name() 411*1fa6dee9SAndroid Build Coastguard Worker } 412*1fa6dee9SAndroid Build Coastguard Worker} 413*1fa6dee9SAndroid Build Coastguard Worker 414*1fa6dee9SAndroid Build Coastguard Workerfunc (module *moduleInfo) String() string { 415*1fa6dee9SAndroid Build Coastguard Worker s := fmt.Sprintf("module %q", module.Name()) 416*1fa6dee9SAndroid Build Coastguard Worker if module.variant.name != "" { 417*1fa6dee9SAndroid Build Coastguard Worker s += fmt.Sprintf(" variant %q", module.variant.name) 418*1fa6dee9SAndroid Build Coastguard Worker } 419*1fa6dee9SAndroid Build Coastguard Worker if module.createdBy != nil { 420*1fa6dee9SAndroid Build Coastguard Worker s += fmt.Sprintf(" (created by %s)", module.createdBy) 421*1fa6dee9SAndroid Build Coastguard Worker } 422*1fa6dee9SAndroid Build Coastguard Worker 423*1fa6dee9SAndroid Build Coastguard Worker return s 424*1fa6dee9SAndroid Build Coastguard Worker} 425*1fa6dee9SAndroid Build Coastguard Worker 426*1fa6dee9SAndroid Build Coastguard Workerfunc (module *moduleInfo) namespace() Namespace { 427*1fa6dee9SAndroid Build Coastguard Worker return module.group.namespace 428*1fa6dee9SAndroid Build Coastguard Worker} 429*1fa6dee9SAndroid Build Coastguard Worker 430*1fa6dee9SAndroid Build Coastguard Workerfunc (module *moduleInfo) ModuleCacheKey() string { 431*1fa6dee9SAndroid Build Coastguard Worker variant := module.variant.name 432*1fa6dee9SAndroid Build Coastguard Worker if variant == "" { 433*1fa6dee9SAndroid Build Coastguard Worker variant = "none" 434*1fa6dee9SAndroid Build Coastguard Worker } 435*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%s-%s-%s-%s", 436*1fa6dee9SAndroid Build Coastguard Worker strings.ReplaceAll(filepath.Dir(module.relBlueprintsFile), "/", "."), 437*1fa6dee9SAndroid Build Coastguard Worker module.Name(), variant, module.typeName) 438*1fa6dee9SAndroid Build Coastguard Worker} 439*1fa6dee9SAndroid Build Coastguard Worker 440*1fa6dee9SAndroid Build Coastguard Worker// A Variation is a way that a variant of a module differs from other variants of the same module. 441*1fa6dee9SAndroid Build Coastguard Worker// For example, two variants of the same module might have Variation{"arch","arm"} and 442*1fa6dee9SAndroid Build Coastguard Worker// Variation{"arch","arm64"} 443*1fa6dee9SAndroid Build Coastguard Workertype Variation struct { 444*1fa6dee9SAndroid Build Coastguard Worker // Mutator is the axis on which this variation applies, i.e. "arch" or "link" 445*1fa6dee9SAndroid Build Coastguard Worker Mutator string 446*1fa6dee9SAndroid Build Coastguard Worker // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or 447*1fa6dee9SAndroid Build Coastguard Worker // "shared" or "static" for link. 448*1fa6dee9SAndroid Build Coastguard Worker Variation string 449*1fa6dee9SAndroid Build Coastguard Worker} 450*1fa6dee9SAndroid Build Coastguard Worker 451*1fa6dee9SAndroid Build Coastguard Worker// A variationMap stores a map of Mutator to Variation to specify a variant of a module. 452*1fa6dee9SAndroid Build Coastguard Workertype variationMap struct { 453*1fa6dee9SAndroid Build Coastguard Worker variations map[string]string 454*1fa6dee9SAndroid Build Coastguard Worker} 455*1fa6dee9SAndroid Build Coastguard Worker 456*1fa6dee9SAndroid Build Coastguard Workerfunc (vm variationMap) clone() variationMap { 457*1fa6dee9SAndroid Build Coastguard Worker return variationMap{ 458*1fa6dee9SAndroid Build Coastguard Worker variations: maps.Clone(vm.variations), 459*1fa6dee9SAndroid Build Coastguard Worker } 460*1fa6dee9SAndroid Build Coastguard Worker} 461*1fa6dee9SAndroid Build Coastguard Worker 462*1fa6dee9SAndroid Build Coastguard Workerfunc (vm variationMap) cloneMatching(mutators []string) variationMap { 463*1fa6dee9SAndroid Build Coastguard Worker newVariations := make(map[string]string) 464*1fa6dee9SAndroid Build Coastguard Worker for _, mutator := range mutators { 465*1fa6dee9SAndroid Build Coastguard Worker if variation, ok := vm.variations[mutator]; ok { 466*1fa6dee9SAndroid Build Coastguard Worker newVariations[mutator] = variation 467*1fa6dee9SAndroid Build Coastguard Worker } 468*1fa6dee9SAndroid Build Coastguard Worker } 469*1fa6dee9SAndroid Build Coastguard Worker return variationMap{ 470*1fa6dee9SAndroid Build Coastguard Worker variations: newVariations, 471*1fa6dee9SAndroid Build Coastguard Worker } 472*1fa6dee9SAndroid Build Coastguard Worker} 473*1fa6dee9SAndroid Build Coastguard Worker 474*1fa6dee9SAndroid Build Coastguard Worker// Compare this variationMap to another one. Returns true if the every entry in this map 475*1fa6dee9SAndroid Build Coastguard Worker// exists and has the same value in the other map. 476*1fa6dee9SAndroid Build Coastguard Workerfunc (vm variationMap) subsetOf(other variationMap) bool { 477*1fa6dee9SAndroid Build Coastguard Worker for k, v1 := range vm.variations { 478*1fa6dee9SAndroid Build Coastguard Worker if v2, ok := other.variations[k]; !ok || v1 != v2 { 479*1fa6dee9SAndroid Build Coastguard Worker return false 480*1fa6dee9SAndroid Build Coastguard Worker } 481*1fa6dee9SAndroid Build Coastguard Worker } 482*1fa6dee9SAndroid Build Coastguard Worker return true 483*1fa6dee9SAndroid Build Coastguard Worker} 484*1fa6dee9SAndroid Build Coastguard Worker 485*1fa6dee9SAndroid Build Coastguard Workerfunc (vm variationMap) equal(other variationMap) bool { 486*1fa6dee9SAndroid Build Coastguard Worker return maps.Equal(vm.variations, other.variations) 487*1fa6dee9SAndroid Build Coastguard Worker} 488*1fa6dee9SAndroid Build Coastguard Worker 489*1fa6dee9SAndroid Build Coastguard Workerfunc (vm *variationMap) set(mutator, variation string) { 490*1fa6dee9SAndroid Build Coastguard Worker if variation == "" { 491*1fa6dee9SAndroid Build Coastguard Worker if vm.variations != nil { 492*1fa6dee9SAndroid Build Coastguard Worker delete(vm.variations, mutator) 493*1fa6dee9SAndroid Build Coastguard Worker } 494*1fa6dee9SAndroid Build Coastguard Worker } else { 495*1fa6dee9SAndroid Build Coastguard Worker if vm.variations == nil { 496*1fa6dee9SAndroid Build Coastguard Worker vm.variations = make(map[string]string) 497*1fa6dee9SAndroid Build Coastguard Worker } 498*1fa6dee9SAndroid Build Coastguard Worker vm.variations[mutator] = variation 499*1fa6dee9SAndroid Build Coastguard Worker } 500*1fa6dee9SAndroid Build Coastguard Worker} 501*1fa6dee9SAndroid Build Coastguard Worker 502*1fa6dee9SAndroid Build Coastguard Workerfunc (vm variationMap) get(mutator string) string { 503*1fa6dee9SAndroid Build Coastguard Worker return vm.variations[mutator] 504*1fa6dee9SAndroid Build Coastguard Worker} 505*1fa6dee9SAndroid Build Coastguard Worker 506*1fa6dee9SAndroid Build Coastguard Workerfunc (vm variationMap) delete(mutator string) { 507*1fa6dee9SAndroid Build Coastguard Worker delete(vm.variations, mutator) 508*1fa6dee9SAndroid Build Coastguard Worker} 509*1fa6dee9SAndroid Build Coastguard Worker 510*1fa6dee9SAndroid Build Coastguard Workerfunc (vm variationMap) empty() bool { 511*1fa6dee9SAndroid Build Coastguard Worker return len(vm.variations) == 0 512*1fa6dee9SAndroid Build Coastguard Worker} 513*1fa6dee9SAndroid Build Coastguard Worker 514*1fa6dee9SAndroid Build Coastguard Worker// differenceKeysCount returns the count of keys that exist in this variationMap that don't exist in the argument. It 515*1fa6dee9SAndroid Build Coastguard Worker// ignores the values. 516*1fa6dee9SAndroid Build Coastguard Workerfunc (vm variationMap) differenceKeysCount(other variationMap) int { 517*1fa6dee9SAndroid Build Coastguard Worker divergence := 0 518*1fa6dee9SAndroid Build Coastguard Worker for mutator, _ := range vm.variations { 519*1fa6dee9SAndroid Build Coastguard Worker if _, exists := other.variations[mutator]; !exists { 520*1fa6dee9SAndroid Build Coastguard Worker divergence += 1 521*1fa6dee9SAndroid Build Coastguard Worker } 522*1fa6dee9SAndroid Build Coastguard Worker } 523*1fa6dee9SAndroid Build Coastguard Worker return divergence 524*1fa6dee9SAndroid Build Coastguard Worker} 525*1fa6dee9SAndroid Build Coastguard Worker 526*1fa6dee9SAndroid Build Coastguard Workertype singletonInfo struct { 527*1fa6dee9SAndroid Build Coastguard Worker // set during RegisterSingletonType 528*1fa6dee9SAndroid Build Coastguard Worker factory SingletonFactory 529*1fa6dee9SAndroid Build Coastguard Worker singleton Singleton 530*1fa6dee9SAndroid Build Coastguard Worker name string 531*1fa6dee9SAndroid Build Coastguard Worker parallel bool 532*1fa6dee9SAndroid Build Coastguard Worker 533*1fa6dee9SAndroid Build Coastguard Worker // set during PrepareBuildActions 534*1fa6dee9SAndroid Build Coastguard Worker actionDefs localBuildActions 535*1fa6dee9SAndroid Build Coastguard Worker} 536*1fa6dee9SAndroid Build Coastguard Worker 537*1fa6dee9SAndroid Build Coastguard Workertype mutatorInfo struct { 538*1fa6dee9SAndroid Build Coastguard Worker // set during RegisterMutator 539*1fa6dee9SAndroid Build Coastguard Worker topDownMutator TopDownMutator 540*1fa6dee9SAndroid Build Coastguard Worker bottomUpMutator BottomUpMutator 541*1fa6dee9SAndroid Build Coastguard Worker name string 542*1fa6dee9SAndroid Build Coastguard Worker index int 543*1fa6dee9SAndroid Build Coastguard Worker transitionMutator *transitionMutatorImpl 544*1fa6dee9SAndroid Build Coastguard Worker 545*1fa6dee9SAndroid Build Coastguard Worker usesRename bool 546*1fa6dee9SAndroid Build Coastguard Worker usesReverseDependencies bool 547*1fa6dee9SAndroid Build Coastguard Worker usesReplaceDependencies bool 548*1fa6dee9SAndroid Build Coastguard Worker usesCreateModule bool 549*1fa6dee9SAndroid Build Coastguard Worker mutatesDependencies bool 550*1fa6dee9SAndroid Build Coastguard Worker mutatesGlobalState bool 551*1fa6dee9SAndroid Build Coastguard Worker neverFar bool 552*1fa6dee9SAndroid Build Coastguard Worker} 553*1fa6dee9SAndroid Build Coastguard Worker 554*1fa6dee9SAndroid Build Coastguard Workerfunc newContext() *Context { 555*1fa6dee9SAndroid Build Coastguard Worker eventHandler := metrics.EventHandler{} 556*1fa6dee9SAndroid Build Coastguard Worker return &Context{ 557*1fa6dee9SAndroid Build Coastguard Worker Context: context.Background(), 558*1fa6dee9SAndroid Build Coastguard Worker EventHandler: &eventHandler, 559*1fa6dee9SAndroid Build Coastguard Worker moduleFactories: make(map[string]ModuleFactory), 560*1fa6dee9SAndroid Build Coastguard Worker nameInterface: NewSimpleNameInterface(), 561*1fa6dee9SAndroid Build Coastguard Worker moduleInfo: make(map[Module]*moduleInfo), 562*1fa6dee9SAndroid Build Coastguard Worker globs: make(map[globKey]pathtools.GlobResult), 563*1fa6dee9SAndroid Build Coastguard Worker fs: pathtools.OsFs, 564*1fa6dee9SAndroid Build Coastguard Worker includeTags: &IncludeTags{}, 565*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs: &SourceRootDirs{}, 566*1fa6dee9SAndroid Build Coastguard Worker outDir: nil, 567*1fa6dee9SAndroid Build Coastguard Worker requiredNinjaMajor: 1, 568*1fa6dee9SAndroid Build Coastguard Worker requiredNinjaMinor: 7, 569*1fa6dee9SAndroid Build Coastguard Worker requiredNinjaMicro: 0, 570*1fa6dee9SAndroid Build Coastguard Worker buildActionsToCache: make(BuildActionCache), 571*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStringsToCache: make(OrderOnlyStringsCache), 572*1fa6dee9SAndroid Build Coastguard Worker } 573*1fa6dee9SAndroid Build Coastguard Worker} 574*1fa6dee9SAndroid Build Coastguard Worker 575*1fa6dee9SAndroid Build Coastguard Worker// NewContext creates a new Context object. The created context initially has 576*1fa6dee9SAndroid Build Coastguard Worker// no module or singleton factories registered, so the RegisterModuleFactory and 577*1fa6dee9SAndroid Build Coastguard Worker// RegisterSingletonFactory methods must be called before it can do anything 578*1fa6dee9SAndroid Build Coastguard Worker// useful. 579*1fa6dee9SAndroid Build Coastguard Workerfunc NewContext() *Context { 580*1fa6dee9SAndroid Build Coastguard Worker ctx := newContext() 581*1fa6dee9SAndroid Build Coastguard Worker 582*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator) 583*1fa6dee9SAndroid Build Coastguard Worker 584*1fa6dee9SAndroid Build Coastguard Worker return ctx 585*1fa6dee9SAndroid Build Coastguard Worker} 586*1fa6dee9SAndroid Build Coastguard Worker 587*1fa6dee9SAndroid Build Coastguard Worker// A ModuleFactory function creates a new Module object. See the 588*1fa6dee9SAndroid Build Coastguard Worker// Context.RegisterModuleType method for details about how a registered 589*1fa6dee9SAndroid Build Coastguard Worker// ModuleFactory is used by a Context. 590*1fa6dee9SAndroid Build Coastguard Workertype ModuleFactory func() (m Module, propertyStructs []interface{}) 591*1fa6dee9SAndroid Build Coastguard Worker 592*1fa6dee9SAndroid Build Coastguard Worker// RegisterModuleType associates a module type name (which can appear in a 593*1fa6dee9SAndroid Build Coastguard Worker// Blueprints file) with a Module factory function. When the given module type 594*1fa6dee9SAndroid Build Coastguard Worker// name is encountered in a Blueprints file during parsing, the Module factory 595*1fa6dee9SAndroid Build Coastguard Worker// is invoked to instantiate a new Module object to handle the build action 596*1fa6dee9SAndroid Build Coastguard Worker// generation for the module. If a Mutator splits a module into multiple variants, 597*1fa6dee9SAndroid Build Coastguard Worker// the factory is invoked again to create a new Module for each variant. 598*1fa6dee9SAndroid Build Coastguard Worker// 599*1fa6dee9SAndroid Build Coastguard Worker// The module type names given here must be unique for the context. The factory 600*1fa6dee9SAndroid Build Coastguard Worker// function should be a named function so that its package and name can be 601*1fa6dee9SAndroid Build Coastguard Worker// included in the generated Ninja file for debugging purposes. 602*1fa6dee9SAndroid Build Coastguard Worker// 603*1fa6dee9SAndroid Build Coastguard Worker// The factory function returns two values. The first is the newly created 604*1fa6dee9SAndroid Build Coastguard Worker// Module object. The second is a slice of pointers to that Module object's 605*1fa6dee9SAndroid Build Coastguard Worker// properties structs. Each properties struct is examined when parsing a module 606*1fa6dee9SAndroid Build Coastguard Worker// definition of this type in a Blueprints file. Exported fields of the 607*1fa6dee9SAndroid Build Coastguard Worker// properties structs are automatically set to the property values specified in 608*1fa6dee9SAndroid Build Coastguard Worker// the Blueprints file. The properties struct field names determine the name of 609*1fa6dee9SAndroid Build Coastguard Worker// the Blueprints file properties that are used - the Blueprints property name 610*1fa6dee9SAndroid Build Coastguard Worker// matches that of the properties struct field name with the first letter 611*1fa6dee9SAndroid Build Coastguard Worker// converted to lower-case. 612*1fa6dee9SAndroid Build Coastguard Worker// 613*1fa6dee9SAndroid Build Coastguard Worker// The fields of the properties struct must be either []string, a string, or 614*1fa6dee9SAndroid Build Coastguard Worker// bool. The Context will panic if a Module gets instantiated with a properties 615*1fa6dee9SAndroid Build Coastguard Worker// struct containing a field that is not one these supported types. 616*1fa6dee9SAndroid Build Coastguard Worker// 617*1fa6dee9SAndroid Build Coastguard Worker// Any properties that appear in the Blueprints files that are not built-in 618*1fa6dee9SAndroid Build Coastguard Worker// module properties (such as "name" and "deps") and do not have a corresponding 619*1fa6dee9SAndroid Build Coastguard Worker// field in the returned module properties struct result in an error during the 620*1fa6dee9SAndroid Build Coastguard Worker// Context's parse phase. 621*1fa6dee9SAndroid Build Coastguard Worker// 622*1fa6dee9SAndroid Build Coastguard Worker// As an example, the follow code: 623*1fa6dee9SAndroid Build Coastguard Worker// 624*1fa6dee9SAndroid Build Coastguard Worker// type myModule struct { 625*1fa6dee9SAndroid Build Coastguard Worker// properties struct { 626*1fa6dee9SAndroid Build Coastguard Worker// Foo string 627*1fa6dee9SAndroid Build Coastguard Worker// Bar []string 628*1fa6dee9SAndroid Build Coastguard Worker// } 629*1fa6dee9SAndroid Build Coastguard Worker// } 630*1fa6dee9SAndroid Build Coastguard Worker// 631*1fa6dee9SAndroid Build Coastguard Worker// func NewMyModule() (blueprint.Module, []interface{}) { 632*1fa6dee9SAndroid Build Coastguard Worker// module := new(myModule) 633*1fa6dee9SAndroid Build Coastguard Worker// properties := &module.properties 634*1fa6dee9SAndroid Build Coastguard Worker// return module, []interface{}{properties} 635*1fa6dee9SAndroid Build Coastguard Worker// } 636*1fa6dee9SAndroid Build Coastguard Worker// 637*1fa6dee9SAndroid Build Coastguard Worker// func main() { 638*1fa6dee9SAndroid Build Coastguard Worker// ctx := blueprint.NewContext() 639*1fa6dee9SAndroid Build Coastguard Worker// ctx.RegisterModuleType("my_module", NewMyModule) 640*1fa6dee9SAndroid Build Coastguard Worker// // ... 641*1fa6dee9SAndroid Build Coastguard Worker// } 642*1fa6dee9SAndroid Build Coastguard Worker// 643*1fa6dee9SAndroid Build Coastguard Worker// would support parsing a module defined in a Blueprints file as follows: 644*1fa6dee9SAndroid Build Coastguard Worker// 645*1fa6dee9SAndroid Build Coastguard Worker// my_module { 646*1fa6dee9SAndroid Build Coastguard Worker// name: "myName", 647*1fa6dee9SAndroid Build Coastguard Worker// foo: "my foo string", 648*1fa6dee9SAndroid Build Coastguard Worker// bar: ["my", "bar", "strings"], 649*1fa6dee9SAndroid Build Coastguard Worker// } 650*1fa6dee9SAndroid Build Coastguard Worker// 651*1fa6dee9SAndroid Build Coastguard Worker// The factory function may be called from multiple goroutines. Any accesses 652*1fa6dee9SAndroid Build Coastguard Worker// to global variables must be synchronized. 653*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) RegisterModuleType(name string, factory ModuleFactory) { 654*1fa6dee9SAndroid Build Coastguard Worker if _, present := c.moduleFactories[name]; present { 655*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("module type %q is already registered", name)) 656*1fa6dee9SAndroid Build Coastguard Worker } 657*1fa6dee9SAndroid Build Coastguard Worker c.moduleFactories[name] = factory 658*1fa6dee9SAndroid Build Coastguard Worker} 659*1fa6dee9SAndroid Build Coastguard Worker 660*1fa6dee9SAndroid Build Coastguard Worker// A SingletonFactory function creates a new Singleton object. See the 661*1fa6dee9SAndroid Build Coastguard Worker// Context.RegisterSingletonType method for details about how a registered 662*1fa6dee9SAndroid Build Coastguard Worker// SingletonFactory is used by a Context. 663*1fa6dee9SAndroid Build Coastguard Workertype SingletonFactory func() Singleton 664*1fa6dee9SAndroid Build Coastguard Worker 665*1fa6dee9SAndroid Build Coastguard Worker// RegisterSingletonType registers a singleton type that will be invoked to 666*1fa6dee9SAndroid Build Coastguard Worker// generate build actions. Each registered singleton type is instantiated 667*1fa6dee9SAndroid Build Coastguard Worker// and invoked exactly once as part of the generate phase. 668*1fa6dee9SAndroid Build Coastguard Worker// 669*1fa6dee9SAndroid Build Coastguard Worker// Those singletons registered with parallel=true are run in parallel, after 670*1fa6dee9SAndroid Build Coastguard Worker// which the other registered singletons are run in registration order. 671*1fa6dee9SAndroid Build Coastguard Worker// 672*1fa6dee9SAndroid Build Coastguard Worker// The singleton type names given here must be unique for the context. The 673*1fa6dee9SAndroid Build Coastguard Worker// factory function should be a named function so that its package and name can 674*1fa6dee9SAndroid Build Coastguard Worker// be included in the generated Ninja file for debugging purposes. 675*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) RegisterSingletonType(name string, factory SingletonFactory, parallel bool) { 676*1fa6dee9SAndroid Build Coastguard Worker for _, s := range c.singletonInfo { 677*1fa6dee9SAndroid Build Coastguard Worker if s.name == name { 678*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("singleton %q is already registered", name)) 679*1fa6dee9SAndroid Build Coastguard Worker } 680*1fa6dee9SAndroid Build Coastguard Worker } 681*1fa6dee9SAndroid Build Coastguard Worker 682*1fa6dee9SAndroid Build Coastguard Worker c.singletonInfo = append(c.singletonInfo, &singletonInfo{ 683*1fa6dee9SAndroid Build Coastguard Worker factory: factory, 684*1fa6dee9SAndroid Build Coastguard Worker singleton: factory(), 685*1fa6dee9SAndroid Build Coastguard Worker name: name, 686*1fa6dee9SAndroid Build Coastguard Worker parallel: parallel, 687*1fa6dee9SAndroid Build Coastguard Worker }) 688*1fa6dee9SAndroid Build Coastguard Worker} 689*1fa6dee9SAndroid Build Coastguard Worker 690*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SetNameInterface(i NameInterface) { 691*1fa6dee9SAndroid Build Coastguard Worker c.nameInterface = i 692*1fa6dee9SAndroid Build Coastguard Worker} 693*1fa6dee9SAndroid Build Coastguard Worker 694*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SetIncrementalAnalysis(incremental bool) { 695*1fa6dee9SAndroid Build Coastguard Worker c.incrementalAnalysis = incremental 696*1fa6dee9SAndroid Build Coastguard Worker} 697*1fa6dee9SAndroid Build Coastguard Worker 698*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) GetIncrementalAnalysis() bool { 699*1fa6dee9SAndroid Build Coastguard Worker return c.incrementalAnalysis 700*1fa6dee9SAndroid Build Coastguard Worker} 701*1fa6dee9SAndroid Build Coastguard Worker 702*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SetIncrementalEnabled(incremental bool) { 703*1fa6dee9SAndroid Build Coastguard Worker c.incrementalEnabled = incremental 704*1fa6dee9SAndroid Build Coastguard Worker} 705*1fa6dee9SAndroid Build Coastguard Worker 706*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) GetIncrementalEnabled() bool { 707*1fa6dee9SAndroid Build Coastguard Worker return c.incrementalEnabled 708*1fa6dee9SAndroid Build Coastguard Worker} 709*1fa6dee9SAndroid Build Coastguard Worker 710*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) updateBuildActionsCache(key *BuildActionCacheKey, data *BuildActionCachedData) { 711*1fa6dee9SAndroid Build Coastguard Worker if key != nil { 712*1fa6dee9SAndroid Build Coastguard Worker c.buildActionsToCacheLock.Lock() 713*1fa6dee9SAndroid Build Coastguard Worker defer c.buildActionsToCacheLock.Unlock() 714*1fa6dee9SAndroid Build Coastguard Worker c.buildActionsToCache[*key] = data 715*1fa6dee9SAndroid Build Coastguard Worker } 716*1fa6dee9SAndroid Build Coastguard Worker} 717*1fa6dee9SAndroid Build Coastguard Worker 718*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) getBuildActionsFromCache(key *BuildActionCacheKey) *BuildActionCachedData { 719*1fa6dee9SAndroid Build Coastguard Worker if c.buildActionsFromCache != nil && key != nil { 720*1fa6dee9SAndroid Build Coastguard Worker return c.buildActionsFromCache[*key] 721*1fa6dee9SAndroid Build Coastguard Worker } 722*1fa6dee9SAndroid Build Coastguard Worker return nil 723*1fa6dee9SAndroid Build Coastguard Worker} 724*1fa6dee9SAndroid Build Coastguard Worker 725*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) CacheAllBuildActions(soongOutDir string) error { 726*1fa6dee9SAndroid Build Coastguard Worker return errors.Join(writeToCache(c, soongOutDir, BuildActionsCacheFile, &c.buildActionsToCache), 727*1fa6dee9SAndroid Build Coastguard Worker writeToCache(c, soongOutDir, OrderOnlyStringsCacheFile, &c.orderOnlyStringsToCache)) 728*1fa6dee9SAndroid Build Coastguard Worker} 729*1fa6dee9SAndroid Build Coastguard Worker 730*1fa6dee9SAndroid Build Coastguard Workerfunc writeToCache[T any](ctx *Context, soongOutDir string, fileName string, data *T) error { 731*1fa6dee9SAndroid Build Coastguard Worker file, err := ctx.fs.OpenFile(filepath.Join(ctx.SrcDir(), soongOutDir, fileName), 732*1fa6dee9SAndroid Build Coastguard Worker os.O_WRONLY|os.O_CREATE|os.O_TRUNC, OutFilePermissions) 733*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 734*1fa6dee9SAndroid Build Coastguard Worker return err 735*1fa6dee9SAndroid Build Coastguard Worker } 736*1fa6dee9SAndroid Build Coastguard Worker defer file.Close() 737*1fa6dee9SAndroid Build Coastguard Worker 738*1fa6dee9SAndroid Build Coastguard Worker encoder := gob.NewEncoder(file) 739*1fa6dee9SAndroid Build Coastguard Worker return encoder.Encode(data) 740*1fa6dee9SAndroid Build Coastguard Worker} 741*1fa6dee9SAndroid Build Coastguard Worker 742*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) RestoreAllBuildActions(soongOutDir string) error { 743*1fa6dee9SAndroid Build Coastguard Worker c.buildActionsFromCache = make(BuildActionCache) 744*1fa6dee9SAndroid Build Coastguard Worker c.orderOnlyStringsFromCache = make(OrderOnlyStringsCache) 745*1fa6dee9SAndroid Build Coastguard Worker return errors.Join(restoreFromCache(c, soongOutDir, BuildActionsCacheFile, &c.buildActionsFromCache), 746*1fa6dee9SAndroid Build Coastguard Worker restoreFromCache(c, soongOutDir, OrderOnlyStringsCacheFile, &c.orderOnlyStringsFromCache)) 747*1fa6dee9SAndroid Build Coastguard Worker} 748*1fa6dee9SAndroid Build Coastguard Worker 749*1fa6dee9SAndroid Build Coastguard Workerfunc restoreFromCache[T any](ctx *Context, soongOutDir string, fileName string, data *T) error { 750*1fa6dee9SAndroid Build Coastguard Worker file, err := ctx.fs.Open(filepath.Join(ctx.SrcDir(), soongOutDir, fileName)) 751*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 752*1fa6dee9SAndroid Build Coastguard Worker if os.IsNotExist(err) { 753*1fa6dee9SAndroid Build Coastguard Worker err = nil 754*1fa6dee9SAndroid Build Coastguard Worker } 755*1fa6dee9SAndroid Build Coastguard Worker return err 756*1fa6dee9SAndroid Build Coastguard Worker } 757*1fa6dee9SAndroid Build Coastguard Worker defer file.Close() 758*1fa6dee9SAndroid Build Coastguard Worker 759*1fa6dee9SAndroid Build Coastguard Worker decoder := gob.NewDecoder(file) 760*1fa6dee9SAndroid Build Coastguard Worker return decoder.Decode(data) 761*1fa6dee9SAndroid Build Coastguard Worker} 762*1fa6dee9SAndroid Build Coastguard Worker 763*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SetSrcDir(path string) { 764*1fa6dee9SAndroid Build Coastguard Worker c.srcDir = path 765*1fa6dee9SAndroid Build Coastguard Worker c.fs = pathtools.NewOsFs(path) 766*1fa6dee9SAndroid Build Coastguard Worker} 767*1fa6dee9SAndroid Build Coastguard Worker 768*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SrcDir() string { 769*1fa6dee9SAndroid Build Coastguard Worker return c.srcDir 770*1fa6dee9SAndroid Build Coastguard Worker} 771*1fa6dee9SAndroid Build Coastguard Worker 772*1fa6dee9SAndroid Build Coastguard Workerfunc singletonPkgPath(singleton Singleton) string { 773*1fa6dee9SAndroid Build Coastguard Worker typ := reflect.TypeOf(singleton) 774*1fa6dee9SAndroid Build Coastguard Worker for typ.Kind() == reflect.Ptr { 775*1fa6dee9SAndroid Build Coastguard Worker typ = typ.Elem() 776*1fa6dee9SAndroid Build Coastguard Worker } 777*1fa6dee9SAndroid Build Coastguard Worker return typ.PkgPath() 778*1fa6dee9SAndroid Build Coastguard Worker} 779*1fa6dee9SAndroid Build Coastguard Worker 780*1fa6dee9SAndroid Build Coastguard Workerfunc singletonTypeName(singleton Singleton) string { 781*1fa6dee9SAndroid Build Coastguard Worker typ := reflect.TypeOf(singleton) 782*1fa6dee9SAndroid Build Coastguard Worker for typ.Kind() == reflect.Ptr { 783*1fa6dee9SAndroid Build Coastguard Worker typ = typ.Elem() 784*1fa6dee9SAndroid Build Coastguard Worker } 785*1fa6dee9SAndroid Build Coastguard Worker return typ.PkgPath() + "." + typ.Name() 786*1fa6dee9SAndroid Build Coastguard Worker} 787*1fa6dee9SAndroid Build Coastguard Worker 788*1fa6dee9SAndroid Build Coastguard Worker// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info 789*1fa6dee9SAndroid Build Coastguard Worker// top-down between Modules. Each registered mutator is invoked in registration order (mixing 790*1fa6dee9SAndroid Build Coastguard Worker// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will 791*1fa6dee9SAndroid Build Coastguard Worker// have returned before it is in invoked on any of its dependencies. 792*1fa6dee9SAndroid Build Coastguard Worker// 793*1fa6dee9SAndroid Build Coastguard Worker// The mutator type names given here must be unique to all top down mutators in 794*1fa6dee9SAndroid Build Coastguard Worker// the Context. 795*1fa6dee9SAndroid Build Coastguard Worker// 796*1fa6dee9SAndroid Build Coastguard Worker// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in 797*1fa6dee9SAndroid Build Coastguard Worker// parallel while maintaining ordering. 798*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle { 799*1fa6dee9SAndroid Build Coastguard Worker for _, m := range c.mutatorInfo { 800*1fa6dee9SAndroid Build Coastguard Worker if m.name == name && m.topDownMutator != nil { 801*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("mutator %q is already registered", name)) 802*1fa6dee9SAndroid Build Coastguard Worker } 803*1fa6dee9SAndroid Build Coastguard Worker } 804*1fa6dee9SAndroid Build Coastguard Worker 805*1fa6dee9SAndroid Build Coastguard Worker info := &mutatorInfo{ 806*1fa6dee9SAndroid Build Coastguard Worker topDownMutator: mutator, 807*1fa6dee9SAndroid Build Coastguard Worker name: name, 808*1fa6dee9SAndroid Build Coastguard Worker index: len(c.mutatorInfo), 809*1fa6dee9SAndroid Build Coastguard Worker } 810*1fa6dee9SAndroid Build Coastguard Worker 811*1fa6dee9SAndroid Build Coastguard Worker c.mutatorInfo = append(c.mutatorInfo, info) 812*1fa6dee9SAndroid Build Coastguard Worker 813*1fa6dee9SAndroid Build Coastguard Worker return info 814*1fa6dee9SAndroid Build Coastguard Worker} 815*1fa6dee9SAndroid Build Coastguard Worker 816*1fa6dee9SAndroid Build Coastguard Worker// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants. 817*1fa6dee9SAndroid Build Coastguard Worker// Each registered mutator is invoked in registration order (mixing TopDownMutators and 818*1fa6dee9SAndroid Build Coastguard Worker// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all 819*1fa6dee9SAndroid Build Coastguard Worker// of the modules dependencies have returned. 820*1fa6dee9SAndroid Build Coastguard Worker// 821*1fa6dee9SAndroid Build Coastguard Worker// The mutator type names given here must be unique to all bottom up or early 822*1fa6dee9SAndroid Build Coastguard Worker// mutators in the Context. 823*1fa6dee9SAndroid Build Coastguard Worker// 824*1fa6dee9SAndroid Build Coastguard Worker// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in 825*1fa6dee9SAndroid Build Coastguard Worker// parallel while maintaining ordering. 826*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle { 827*1fa6dee9SAndroid Build Coastguard Worker for _, m := range c.variantMutatorNames { 828*1fa6dee9SAndroid Build Coastguard Worker if m == name { 829*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("mutator %q is already registered", name)) 830*1fa6dee9SAndroid Build Coastguard Worker } 831*1fa6dee9SAndroid Build Coastguard Worker } 832*1fa6dee9SAndroid Build Coastguard Worker 833*1fa6dee9SAndroid Build Coastguard Worker info := &mutatorInfo{ 834*1fa6dee9SAndroid Build Coastguard Worker bottomUpMutator: mutator, 835*1fa6dee9SAndroid Build Coastguard Worker name: name, 836*1fa6dee9SAndroid Build Coastguard Worker index: len(c.mutatorInfo), 837*1fa6dee9SAndroid Build Coastguard Worker } 838*1fa6dee9SAndroid Build Coastguard Worker c.mutatorInfo = append(c.mutatorInfo, info) 839*1fa6dee9SAndroid Build Coastguard Worker 840*1fa6dee9SAndroid Build Coastguard Worker c.variantMutatorNames = append(c.variantMutatorNames, name) 841*1fa6dee9SAndroid Build Coastguard Worker 842*1fa6dee9SAndroid Build Coastguard Worker return info 843*1fa6dee9SAndroid Build Coastguard Worker} 844*1fa6dee9SAndroid Build Coastguard Worker 845*1fa6dee9SAndroid Build Coastguard Worker// HasMutatorFinished returns true if the given mutator has finished running. 846*1fa6dee9SAndroid Build Coastguard Worker// It will panic if given an invalid mutator name. 847*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) HasMutatorFinished(mutatorName string) bool { 848*1fa6dee9SAndroid Build Coastguard Worker for _, mutator := range c.mutatorInfo { 849*1fa6dee9SAndroid Build Coastguard Worker if mutator.name == mutatorName { 850*1fa6dee9SAndroid Build Coastguard Worker return len(c.finishedMutators) > mutator.index && c.finishedMutators[mutator.index] 851*1fa6dee9SAndroid Build Coastguard Worker } 852*1fa6dee9SAndroid Build Coastguard Worker } 853*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Sprintf("unknown mutator %q", mutatorName)) 854*1fa6dee9SAndroid Build Coastguard Worker} 855*1fa6dee9SAndroid Build Coastguard Worker 856*1fa6dee9SAndroid Build Coastguard Workertype MutatorHandle interface { 857*1fa6dee9SAndroid Build Coastguard Worker // UsesRename marks the mutator as using the BottomUpMutatorContext.Rename method, which prevents 858*1fa6dee9SAndroid Build Coastguard Worker // coalescing adjacent mutators into a single mutator pass. 859*1fa6dee9SAndroid Build Coastguard Worker UsesRename() MutatorHandle 860*1fa6dee9SAndroid Build Coastguard Worker 861*1fa6dee9SAndroid Build Coastguard Worker // UsesReverseDependencies marks the mutator as using the BottomUpMutatorContext.AddReverseDependency 862*1fa6dee9SAndroid Build Coastguard Worker // method, which prevents coalescing adjacent mutators into a single mutator pass. 863*1fa6dee9SAndroid Build Coastguard Worker UsesReverseDependencies() MutatorHandle 864*1fa6dee9SAndroid Build Coastguard Worker 865*1fa6dee9SAndroid Build Coastguard Worker // UsesReplaceDependencies marks the mutator as using the BottomUpMutatorContext.ReplaceDependencies 866*1fa6dee9SAndroid Build Coastguard Worker // method, which prevents coalescing adjacent mutators into a single mutator pass. 867*1fa6dee9SAndroid Build Coastguard Worker UsesReplaceDependencies() MutatorHandle 868*1fa6dee9SAndroid Build Coastguard Worker 869*1fa6dee9SAndroid Build Coastguard Worker // UsesCreateModule marks the mutator as using the BottomUpMutatorContext.CreateModule method, 870*1fa6dee9SAndroid Build Coastguard Worker // which prevents coalescing adjacent mutators into a single mutator pass. 871*1fa6dee9SAndroid Build Coastguard Worker UsesCreateModule() MutatorHandle 872*1fa6dee9SAndroid Build Coastguard Worker 873*1fa6dee9SAndroid Build Coastguard Worker // MutatesDependencies marks the mutator as modifying properties in dependencies, which prevents 874*1fa6dee9SAndroid Build Coastguard Worker // coalescing adjacent mutators into a single mutator pass. 875*1fa6dee9SAndroid Build Coastguard Worker MutatesDependencies() MutatorHandle 876*1fa6dee9SAndroid Build Coastguard Worker 877*1fa6dee9SAndroid Build Coastguard Worker // MutatesGlobalState marks the mutator as modifying global state, which prevents coalescing 878*1fa6dee9SAndroid Build Coastguard Worker // adjacent mutators into a single mutator pass. 879*1fa6dee9SAndroid Build Coastguard Worker MutatesGlobalState() MutatorHandle 880*1fa6dee9SAndroid Build Coastguard Worker 881*1fa6dee9SAndroid Build Coastguard Worker setTransitionMutator(impl *transitionMutatorImpl) MutatorHandle 882*1fa6dee9SAndroid Build Coastguard Worker setNeverFar() MutatorHandle 883*1fa6dee9SAndroid Build Coastguard Worker} 884*1fa6dee9SAndroid Build Coastguard Worker 885*1fa6dee9SAndroid Build Coastguard Workerfunc (mutator *mutatorInfo) UsesRename() MutatorHandle { 886*1fa6dee9SAndroid Build Coastguard Worker mutator.usesRename = true 887*1fa6dee9SAndroid Build Coastguard Worker return mutator 888*1fa6dee9SAndroid Build Coastguard Worker} 889*1fa6dee9SAndroid Build Coastguard Worker 890*1fa6dee9SAndroid Build Coastguard Workerfunc (mutator *mutatorInfo) UsesReverseDependencies() MutatorHandle { 891*1fa6dee9SAndroid Build Coastguard Worker mutator.usesReverseDependencies = true 892*1fa6dee9SAndroid Build Coastguard Worker return mutator 893*1fa6dee9SAndroid Build Coastguard Worker} 894*1fa6dee9SAndroid Build Coastguard Worker 895*1fa6dee9SAndroid Build Coastguard Workerfunc (mutator *mutatorInfo) UsesReplaceDependencies() MutatorHandle { 896*1fa6dee9SAndroid Build Coastguard Worker mutator.usesReplaceDependencies = true 897*1fa6dee9SAndroid Build Coastguard Worker return mutator 898*1fa6dee9SAndroid Build Coastguard Worker} 899*1fa6dee9SAndroid Build Coastguard Worker 900*1fa6dee9SAndroid Build Coastguard Workerfunc (mutator *mutatorInfo) UsesCreateModule() MutatorHandle { 901*1fa6dee9SAndroid Build Coastguard Worker mutator.usesCreateModule = true 902*1fa6dee9SAndroid Build Coastguard Worker return mutator 903*1fa6dee9SAndroid Build Coastguard Worker} 904*1fa6dee9SAndroid Build Coastguard Worker 905*1fa6dee9SAndroid Build Coastguard Workerfunc (mutator *mutatorInfo) MutatesDependencies() MutatorHandle { 906*1fa6dee9SAndroid Build Coastguard Worker mutator.mutatesDependencies = true 907*1fa6dee9SAndroid Build Coastguard Worker return mutator 908*1fa6dee9SAndroid Build Coastguard Worker} 909*1fa6dee9SAndroid Build Coastguard Worker 910*1fa6dee9SAndroid Build Coastguard Workerfunc (mutator *mutatorInfo) MutatesGlobalState() MutatorHandle { 911*1fa6dee9SAndroid Build Coastguard Worker mutator.mutatesGlobalState = true 912*1fa6dee9SAndroid Build Coastguard Worker return mutator 913*1fa6dee9SAndroid Build Coastguard Worker} 914*1fa6dee9SAndroid Build Coastguard Worker 915*1fa6dee9SAndroid Build Coastguard Workerfunc (mutator *mutatorInfo) setTransitionMutator(impl *transitionMutatorImpl) MutatorHandle { 916*1fa6dee9SAndroid Build Coastguard Worker mutator.transitionMutator = impl 917*1fa6dee9SAndroid Build Coastguard Worker return mutator 918*1fa6dee9SAndroid Build Coastguard Worker} 919*1fa6dee9SAndroid Build Coastguard Worker 920*1fa6dee9SAndroid Build Coastguard Workerfunc (mutator *mutatorInfo) setNeverFar() MutatorHandle { 921*1fa6dee9SAndroid Build Coastguard Worker mutator.neverFar = true 922*1fa6dee9SAndroid Build Coastguard Worker return mutator 923*1fa6dee9SAndroid Build Coastguard Worker} 924*1fa6dee9SAndroid Build Coastguard Worker 925*1fa6dee9SAndroid Build Coastguard Worker// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case 926*1fa6dee9SAndroid Build Coastguard Worker// where it encounters an unknown module type while parsing Blueprints files. By 927*1fa6dee9SAndroid Build Coastguard Worker// default, the context will report unknown module types as an error. If this 928*1fa6dee9SAndroid Build Coastguard Worker// method is called with ignoreUnknownModuleTypes set to true then the context 929*1fa6dee9SAndroid Build Coastguard Worker// will silently ignore unknown module types. 930*1fa6dee9SAndroid Build Coastguard Worker// 931*1fa6dee9SAndroid Build Coastguard Worker// This method should generally not be used. It exists to facilitate the 932*1fa6dee9SAndroid Build Coastguard Worker// bootstrapping process. 933*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) { 934*1fa6dee9SAndroid Build Coastguard Worker c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes 935*1fa6dee9SAndroid Build Coastguard Worker} 936*1fa6dee9SAndroid Build Coastguard Worker 937*1fa6dee9SAndroid Build Coastguard Worker// SetAllowMissingDependencies changes the behavior of Blueprint to ignore 938*1fa6dee9SAndroid Build Coastguard Worker// unresolved dependencies. If the module's GenerateBuildActions calls 939*1fa6dee9SAndroid Build Coastguard Worker// ModuleContext.GetMissingDependencies Blueprint will not emit any errors 940*1fa6dee9SAndroid Build Coastguard Worker// for missing dependencies. 941*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) { 942*1fa6dee9SAndroid Build Coastguard Worker c.allowMissingDependencies = allowMissingDependencies 943*1fa6dee9SAndroid Build Coastguard Worker} 944*1fa6dee9SAndroid Build Coastguard Worker 945*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SetModuleListFile(listFile string) { 946*1fa6dee9SAndroid Build Coastguard Worker c.moduleListFile = listFile 947*1fa6dee9SAndroid Build Coastguard Worker} 948*1fa6dee9SAndroid Build Coastguard Worker 949*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ListModulePaths(baseDir string) (paths []string, err error) { 950*1fa6dee9SAndroid Build Coastguard Worker reader, err := c.fs.Open(c.moduleListFile) 951*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 952*1fa6dee9SAndroid Build Coastguard Worker return nil, err 953*1fa6dee9SAndroid Build Coastguard Worker } 954*1fa6dee9SAndroid Build Coastguard Worker defer reader.Close() 955*1fa6dee9SAndroid Build Coastguard Worker bytes, err := ioutil.ReadAll(reader) 956*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 957*1fa6dee9SAndroid Build Coastguard Worker return nil, err 958*1fa6dee9SAndroid Build Coastguard Worker } 959*1fa6dee9SAndroid Build Coastguard Worker text := string(bytes) 960*1fa6dee9SAndroid Build Coastguard Worker 961*1fa6dee9SAndroid Build Coastguard Worker text = strings.Trim(text, "\n") 962*1fa6dee9SAndroid Build Coastguard Worker lines := strings.Split(text, "\n") 963*1fa6dee9SAndroid Build Coastguard Worker for i := range lines { 964*1fa6dee9SAndroid Build Coastguard Worker lines[i] = filepath.Join(baseDir, lines[i]) 965*1fa6dee9SAndroid Build Coastguard Worker } 966*1fa6dee9SAndroid Build Coastguard Worker 967*1fa6dee9SAndroid Build Coastguard Worker return lines, nil 968*1fa6dee9SAndroid Build Coastguard Worker} 969*1fa6dee9SAndroid Build Coastguard Worker 970*1fa6dee9SAndroid Build Coastguard Worker// a fileParseContext tells the status of parsing a particular file 971*1fa6dee9SAndroid Build Coastguard Workertype fileParseContext struct { 972*1fa6dee9SAndroid Build Coastguard Worker // name of file 973*1fa6dee9SAndroid Build Coastguard Worker fileName string 974*1fa6dee9SAndroid Build Coastguard Worker 975*1fa6dee9SAndroid Build Coastguard Worker // scope to use when resolving variables 976*1fa6dee9SAndroid Build Coastguard Worker Scope *parser.Scope 977*1fa6dee9SAndroid Build Coastguard Worker 978*1fa6dee9SAndroid Build Coastguard Worker // pointer to the one in the parent directory 979*1fa6dee9SAndroid Build Coastguard Worker parent *fileParseContext 980*1fa6dee9SAndroid Build Coastguard Worker 981*1fa6dee9SAndroid Build Coastguard Worker // is closed once FileHandler has completed for this file 982*1fa6dee9SAndroid Build Coastguard Worker doneVisiting chan struct{} 983*1fa6dee9SAndroid Build Coastguard Worker} 984*1fa6dee9SAndroid Build Coastguard Worker 985*1fa6dee9SAndroid Build Coastguard Worker// ParseBlueprintsFiles parses a set of Blueprints files starting with the file 986*1fa6dee9SAndroid Build Coastguard Worker// at rootFile. When it encounters a Blueprints file with a set of subdirs 987*1fa6dee9SAndroid Build Coastguard Worker// listed it recursively parses any Blueprints files found in those 988*1fa6dee9SAndroid Build Coastguard Worker// subdirectories. 989*1fa6dee9SAndroid Build Coastguard Worker// 990*1fa6dee9SAndroid Build Coastguard Worker// If no errors are encountered while parsing the files, the list of paths on 991*1fa6dee9SAndroid Build Coastguard Worker// which the future output will depend is returned. This list will include both 992*1fa6dee9SAndroid Build Coastguard Worker// Blueprints file paths as well as directory paths for cases where wildcard 993*1fa6dee9SAndroid Build Coastguard Worker// subdirs are found. 994*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ParseBlueprintsFiles(rootFile string, 995*1fa6dee9SAndroid Build Coastguard Worker config interface{}) (deps []string, errs []error) { 996*1fa6dee9SAndroid Build Coastguard Worker 997*1fa6dee9SAndroid Build Coastguard Worker baseDir := filepath.Dir(rootFile) 998*1fa6dee9SAndroid Build Coastguard Worker pathsToParse, err := c.ListModulePaths(baseDir) 999*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1000*1fa6dee9SAndroid Build Coastguard Worker return nil, []error{err} 1001*1fa6dee9SAndroid Build Coastguard Worker } 1002*1fa6dee9SAndroid Build Coastguard Worker return c.ParseFileList(baseDir, pathsToParse, config) 1003*1fa6dee9SAndroid Build Coastguard Worker} 1004*1fa6dee9SAndroid Build Coastguard Worker 1005*1fa6dee9SAndroid Build Coastguard Workertype shouldVisitFileInfo struct { 1006*1fa6dee9SAndroid Build Coastguard Worker shouldVisitFile bool 1007*1fa6dee9SAndroid Build Coastguard Worker skippedModules []string 1008*1fa6dee9SAndroid Build Coastguard Worker reasonForSkip string 1009*1fa6dee9SAndroid Build Coastguard Worker errs []error 1010*1fa6dee9SAndroid Build Coastguard Worker} 1011*1fa6dee9SAndroid Build Coastguard Worker 1012*1fa6dee9SAndroid Build Coastguard Worker// Returns a boolean for whether this file should be analyzed 1013*1fa6dee9SAndroid Build Coastguard Worker// Evaluates to true if the file either 1014*1fa6dee9SAndroid Build Coastguard Worker// 1. does not contain a blueprint_package_includes 1015*1fa6dee9SAndroid Build Coastguard Worker// 2. contains a blueprint_package_includes and all requested tags are set 1016*1fa6dee9SAndroid Build Coastguard Worker// This should be processed before adding any modules to the build graph 1017*1fa6dee9SAndroid Build Coastguard Workerfunc shouldVisitFile(c *Context, file *parser.File) shouldVisitFileInfo { 1018*1fa6dee9SAndroid Build Coastguard Worker skippedModules := []string{} 1019*1fa6dee9SAndroid Build Coastguard Worker for _, def := range file.Defs { 1020*1fa6dee9SAndroid Build Coastguard Worker switch def := def.(type) { 1021*1fa6dee9SAndroid Build Coastguard Worker case *parser.Module: 1022*1fa6dee9SAndroid Build Coastguard Worker skippedModules = append(skippedModules, def.Name()) 1023*1fa6dee9SAndroid Build Coastguard Worker } 1024*1fa6dee9SAndroid Build Coastguard Worker } 1025*1fa6dee9SAndroid Build Coastguard Worker 1026*1fa6dee9SAndroid Build Coastguard Worker shouldVisit, invalidatingPrefix := c.sourceRootDirs.SourceRootDirAllowed(file.Name) 1027*1fa6dee9SAndroid Build Coastguard Worker if !shouldVisit { 1028*1fa6dee9SAndroid Build Coastguard Worker return shouldVisitFileInfo{ 1029*1fa6dee9SAndroid Build Coastguard Worker shouldVisitFile: shouldVisit, 1030*1fa6dee9SAndroid Build Coastguard Worker skippedModules: skippedModules, 1031*1fa6dee9SAndroid Build Coastguard Worker reasonForSkip: fmt.Sprintf( 1032*1fa6dee9SAndroid Build Coastguard Worker "%q is a descendant of %q, and that path prefix was not included in PRODUCT_SOURCE_ROOT_DIRS", 1033*1fa6dee9SAndroid Build Coastguard Worker file.Name, 1034*1fa6dee9SAndroid Build Coastguard Worker invalidatingPrefix, 1035*1fa6dee9SAndroid Build Coastguard Worker ), 1036*1fa6dee9SAndroid Build Coastguard Worker } 1037*1fa6dee9SAndroid Build Coastguard Worker } 1038*1fa6dee9SAndroid Build Coastguard Worker return shouldVisitFileInfo{shouldVisitFile: true} 1039*1fa6dee9SAndroid Build Coastguard Worker} 1040*1fa6dee9SAndroid Build Coastguard Worker 1041*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ParseFileList(rootDir string, filePaths []string, 1042*1fa6dee9SAndroid Build Coastguard Worker config interface{}) (deps []string, errs []error) { 1043*1fa6dee9SAndroid Build Coastguard Worker 1044*1fa6dee9SAndroid Build Coastguard Worker if len(filePaths) < 1 { 1045*1fa6dee9SAndroid Build Coastguard Worker return nil, []error{fmt.Errorf("no paths provided to parse")} 1046*1fa6dee9SAndroid Build Coastguard Worker } 1047*1fa6dee9SAndroid Build Coastguard Worker 1048*1fa6dee9SAndroid Build Coastguard Worker c.dependenciesReady = false 1049*1fa6dee9SAndroid Build Coastguard Worker 1050*1fa6dee9SAndroid Build Coastguard Worker type newModuleInfo struct { 1051*1fa6dee9SAndroid Build Coastguard Worker *moduleInfo 1052*1fa6dee9SAndroid Build Coastguard Worker deps []string 1053*1fa6dee9SAndroid Build Coastguard Worker added chan<- struct{} 1054*1fa6dee9SAndroid Build Coastguard Worker } 1055*1fa6dee9SAndroid Build Coastguard Worker 1056*1fa6dee9SAndroid Build Coastguard Worker type newSkipInfo struct { 1057*1fa6dee9SAndroid Build Coastguard Worker shouldVisitFileInfo 1058*1fa6dee9SAndroid Build Coastguard Worker file string 1059*1fa6dee9SAndroid Build Coastguard Worker } 1060*1fa6dee9SAndroid Build Coastguard Worker 1061*1fa6dee9SAndroid Build Coastguard Worker moduleCh := make(chan newModuleInfo) 1062*1fa6dee9SAndroid Build Coastguard Worker errsCh := make(chan []error) 1063*1fa6dee9SAndroid Build Coastguard Worker doneCh := make(chan struct{}) 1064*1fa6dee9SAndroid Build Coastguard Worker skipCh := make(chan newSkipInfo) 1065*1fa6dee9SAndroid Build Coastguard Worker var numErrs uint32 1066*1fa6dee9SAndroid Build Coastguard Worker var numGoroutines int32 1067*1fa6dee9SAndroid Build Coastguard Worker 1068*1fa6dee9SAndroid Build Coastguard Worker // handler must be reentrant 1069*1fa6dee9SAndroid Build Coastguard Worker handleOneFile := func(file *parser.File) { 1070*1fa6dee9SAndroid Build Coastguard Worker if atomic.LoadUint32(&numErrs) > maxErrors { 1071*1fa6dee9SAndroid Build Coastguard Worker return 1072*1fa6dee9SAndroid Build Coastguard Worker } 1073*1fa6dee9SAndroid Build Coastguard Worker 1074*1fa6dee9SAndroid Build Coastguard Worker addedCh := make(chan struct{}) 1075*1fa6dee9SAndroid Build Coastguard Worker 1076*1fa6dee9SAndroid Build Coastguard Worker var scopedModuleFactories map[string]ModuleFactory 1077*1fa6dee9SAndroid Build Coastguard Worker 1078*1fa6dee9SAndroid Build Coastguard Worker var addModule func(module *moduleInfo) []error 1079*1fa6dee9SAndroid Build Coastguard Worker addModule = func(module *moduleInfo) []error { 1080*1fa6dee9SAndroid Build Coastguard Worker // Run any load hooks immediately before it is sent to the moduleCh and is 1081*1fa6dee9SAndroid Build Coastguard Worker // registered by name. This allows load hooks to set and/or modify any aspect 1082*1fa6dee9SAndroid Build Coastguard Worker // of the module (including names) using information that is not available when 1083*1fa6dee9SAndroid Build Coastguard Worker // the module factory is called. 1084*1fa6dee9SAndroid Build Coastguard Worker newModules, newDeps, errs := runAndRemoveLoadHooks(c, config, module, &scopedModuleFactories) 1085*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1086*1fa6dee9SAndroid Build Coastguard Worker return errs 1087*1fa6dee9SAndroid Build Coastguard Worker } 1088*1fa6dee9SAndroid Build Coastguard Worker 1089*1fa6dee9SAndroid Build Coastguard Worker moduleCh <- newModuleInfo{module, newDeps, addedCh} 1090*1fa6dee9SAndroid Build Coastguard Worker <-addedCh 1091*1fa6dee9SAndroid Build Coastguard Worker for _, n := range newModules { 1092*1fa6dee9SAndroid Build Coastguard Worker errs = addModule(n) 1093*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1094*1fa6dee9SAndroid Build Coastguard Worker return errs 1095*1fa6dee9SAndroid Build Coastguard Worker } 1096*1fa6dee9SAndroid Build Coastguard Worker } 1097*1fa6dee9SAndroid Build Coastguard Worker return nil 1098*1fa6dee9SAndroid Build Coastguard Worker } 1099*1fa6dee9SAndroid Build Coastguard Worker shouldVisitInfo := shouldVisitFile(c, file) 1100*1fa6dee9SAndroid Build Coastguard Worker errs := shouldVisitInfo.errs 1101*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1102*1fa6dee9SAndroid Build Coastguard Worker atomic.AddUint32(&numErrs, uint32(len(errs))) 1103*1fa6dee9SAndroid Build Coastguard Worker errsCh <- errs 1104*1fa6dee9SAndroid Build Coastguard Worker } 1105*1fa6dee9SAndroid Build Coastguard Worker if !shouldVisitInfo.shouldVisitFile { 1106*1fa6dee9SAndroid Build Coastguard Worker skipCh <- newSkipInfo{ 1107*1fa6dee9SAndroid Build Coastguard Worker file: file.Name, 1108*1fa6dee9SAndroid Build Coastguard Worker shouldVisitFileInfo: shouldVisitInfo, 1109*1fa6dee9SAndroid Build Coastguard Worker } 1110*1fa6dee9SAndroid Build Coastguard Worker // TODO: Write a file that lists the skipped bp files 1111*1fa6dee9SAndroid Build Coastguard Worker return 1112*1fa6dee9SAndroid Build Coastguard Worker } 1113*1fa6dee9SAndroid Build Coastguard Worker 1114*1fa6dee9SAndroid Build Coastguard Worker for _, def := range file.Defs { 1115*1fa6dee9SAndroid Build Coastguard Worker switch def := def.(type) { 1116*1fa6dee9SAndroid Build Coastguard Worker case *parser.Module: 1117*1fa6dee9SAndroid Build Coastguard Worker module, errs := processModuleDef(def, file.Name, c.moduleFactories, scopedModuleFactories, c.ignoreUnknownModuleTypes) 1118*1fa6dee9SAndroid Build Coastguard Worker if len(errs) == 0 && module != nil { 1119*1fa6dee9SAndroid Build Coastguard Worker errs = addModule(module) 1120*1fa6dee9SAndroid Build Coastguard Worker } 1121*1fa6dee9SAndroid Build Coastguard Worker 1122*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1123*1fa6dee9SAndroid Build Coastguard Worker atomic.AddUint32(&numErrs, uint32(len(errs))) 1124*1fa6dee9SAndroid Build Coastguard Worker errsCh <- errs 1125*1fa6dee9SAndroid Build Coastguard Worker } 1126*1fa6dee9SAndroid Build Coastguard Worker 1127*1fa6dee9SAndroid Build Coastguard Worker case *parser.Assignment: 1128*1fa6dee9SAndroid Build Coastguard Worker // Already handled via Scope object 1129*1fa6dee9SAndroid Build Coastguard Worker default: 1130*1fa6dee9SAndroid Build Coastguard Worker panic("unknown definition type") 1131*1fa6dee9SAndroid Build Coastguard Worker } 1132*1fa6dee9SAndroid Build Coastguard Worker 1133*1fa6dee9SAndroid Build Coastguard Worker } 1134*1fa6dee9SAndroid Build Coastguard Worker } 1135*1fa6dee9SAndroid Build Coastguard Worker 1136*1fa6dee9SAndroid Build Coastguard Worker atomic.AddInt32(&numGoroutines, 1) 1137*1fa6dee9SAndroid Build Coastguard Worker go func() { 1138*1fa6dee9SAndroid Build Coastguard Worker var errs []error 1139*1fa6dee9SAndroid Build Coastguard Worker deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile) 1140*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1141*1fa6dee9SAndroid Build Coastguard Worker errsCh <- errs 1142*1fa6dee9SAndroid Build Coastguard Worker } 1143*1fa6dee9SAndroid Build Coastguard Worker doneCh <- struct{}{} 1144*1fa6dee9SAndroid Build Coastguard Worker }() 1145*1fa6dee9SAndroid Build Coastguard Worker 1146*1fa6dee9SAndroid Build Coastguard Worker var hookDeps []string 1147*1fa6dee9SAndroid Build Coastguard Workerloop: 1148*1fa6dee9SAndroid Build Coastguard Worker for { 1149*1fa6dee9SAndroid Build Coastguard Worker select { 1150*1fa6dee9SAndroid Build Coastguard Worker case newErrs := <-errsCh: 1151*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 1152*1fa6dee9SAndroid Build Coastguard Worker case module := <-moduleCh: 1153*1fa6dee9SAndroid Build Coastguard Worker newErrs := c.addModule(module.moduleInfo) 1154*1fa6dee9SAndroid Build Coastguard Worker hookDeps = append(hookDeps, module.deps...) 1155*1fa6dee9SAndroid Build Coastguard Worker if module.added != nil { 1156*1fa6dee9SAndroid Build Coastguard Worker module.added <- struct{}{} 1157*1fa6dee9SAndroid Build Coastguard Worker } 1158*1fa6dee9SAndroid Build Coastguard Worker if len(newErrs) > 0 { 1159*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 1160*1fa6dee9SAndroid Build Coastguard Worker } 1161*1fa6dee9SAndroid Build Coastguard Worker case <-doneCh: 1162*1fa6dee9SAndroid Build Coastguard Worker n := atomic.AddInt32(&numGoroutines, -1) 1163*1fa6dee9SAndroid Build Coastguard Worker if n == 0 { 1164*1fa6dee9SAndroid Build Coastguard Worker break loop 1165*1fa6dee9SAndroid Build Coastguard Worker } 1166*1fa6dee9SAndroid Build Coastguard Worker case skipped := <-skipCh: 1167*1fa6dee9SAndroid Build Coastguard Worker nctx := newNamespaceContextFromFilename(skipped.file) 1168*1fa6dee9SAndroid Build Coastguard Worker for _, name := range skipped.skippedModules { 1169*1fa6dee9SAndroid Build Coastguard Worker c.nameInterface.NewSkippedModule(nctx, name, SkippedModuleInfo{ 1170*1fa6dee9SAndroid Build Coastguard Worker filename: skipped.file, 1171*1fa6dee9SAndroid Build Coastguard Worker reason: skipped.reasonForSkip, 1172*1fa6dee9SAndroid Build Coastguard Worker }) 1173*1fa6dee9SAndroid Build Coastguard Worker } 1174*1fa6dee9SAndroid Build Coastguard Worker } 1175*1fa6dee9SAndroid Build Coastguard Worker } 1176*1fa6dee9SAndroid Build Coastguard Worker 1177*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, hookDeps...) 1178*1fa6dee9SAndroid Build Coastguard Worker return deps, errs 1179*1fa6dee9SAndroid Build Coastguard Worker} 1180*1fa6dee9SAndroid Build Coastguard Worker 1181*1fa6dee9SAndroid Build Coastguard Workertype FileHandler func(*parser.File) 1182*1fa6dee9SAndroid Build Coastguard Worker 1183*1fa6dee9SAndroid Build Coastguard Worker// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths, 1184*1fa6dee9SAndroid Build Coastguard Worker// calling the given file handler on each 1185*1fa6dee9SAndroid Build Coastguard Worker// 1186*1fa6dee9SAndroid Build Coastguard Worker// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed, 1187*1fa6dee9SAndroid Build Coastguard Worker// it recursively parses any Blueprints files found in those subdirectories. 1188*1fa6dee9SAndroid Build Coastguard Worker// 1189*1fa6dee9SAndroid Build Coastguard Worker// If any of the file paths is an ancestor directory of any other of file path, the ancestor 1190*1fa6dee9SAndroid Build Coastguard Worker// will be parsed and visited first. 1191*1fa6dee9SAndroid Build Coastguard Worker// 1192*1fa6dee9SAndroid Build Coastguard Worker// the file handler will be called from a goroutine, so it must be reentrant. 1193*1fa6dee9SAndroid Build Coastguard Worker// 1194*1fa6dee9SAndroid Build Coastguard Worker// If no errors are encountered while parsing the files, the list of paths on 1195*1fa6dee9SAndroid Build Coastguard Worker// which the future output will depend is returned. This list will include both 1196*1fa6dee9SAndroid Build Coastguard Worker// Blueprints file paths as well as directory paths for cases where wildcard 1197*1fa6dee9SAndroid Build Coastguard Worker// subdirs are found. 1198*1fa6dee9SAndroid Build Coastguard Worker// 1199*1fa6dee9SAndroid Build Coastguard Worker// visitor will be called asynchronously, and will only be called once visitor for each 1200*1fa6dee9SAndroid Build Coastguard Worker// ancestor directory has completed. 1201*1fa6dee9SAndroid Build Coastguard Worker// 1202*1fa6dee9SAndroid Build Coastguard Worker// WalkBlueprintsFiles will not return until all calls to visitor have returned. 1203*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string, 1204*1fa6dee9SAndroid Build Coastguard Worker visitor FileHandler) (deps []string, errs []error) { 1205*1fa6dee9SAndroid Build Coastguard Worker 1206*1fa6dee9SAndroid Build Coastguard Worker // make a mapping from ancestors to their descendants to facilitate parsing ancestors first 1207*1fa6dee9SAndroid Build Coastguard Worker descendantsMap, err := findBlueprintDescendants(filePaths) 1208*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1209*1fa6dee9SAndroid Build Coastguard Worker panic(err.Error()) 1210*1fa6dee9SAndroid Build Coastguard Worker } 1211*1fa6dee9SAndroid Build Coastguard Worker blueprintsSet := make(map[string]bool) 1212*1fa6dee9SAndroid Build Coastguard Worker 1213*1fa6dee9SAndroid Build Coastguard Worker // Channels to receive data back from openAndParse goroutines 1214*1fa6dee9SAndroid Build Coastguard Worker blueprintsCh := make(chan fileParseContext) 1215*1fa6dee9SAndroid Build Coastguard Worker errsCh := make(chan []error) 1216*1fa6dee9SAndroid Build Coastguard Worker depsCh := make(chan string) 1217*1fa6dee9SAndroid Build Coastguard Worker 1218*1fa6dee9SAndroid Build Coastguard Worker // Channel to notify main loop that a openAndParse goroutine has finished 1219*1fa6dee9SAndroid Build Coastguard Worker doneParsingCh := make(chan fileParseContext) 1220*1fa6dee9SAndroid Build Coastguard Worker 1221*1fa6dee9SAndroid Build Coastguard Worker // Number of outstanding goroutines to wait for 1222*1fa6dee9SAndroid Build Coastguard Worker activeCount := 0 1223*1fa6dee9SAndroid Build Coastguard Worker var pending []fileParseContext 1224*1fa6dee9SAndroid Build Coastguard Worker tooManyErrors := false 1225*1fa6dee9SAndroid Build Coastguard Worker 1226*1fa6dee9SAndroid Build Coastguard Worker // Limit concurrent calls to parseBlueprintFiles to 200 1227*1fa6dee9SAndroid Build Coastguard Worker // Darwin has a default limit of 256 open files 1228*1fa6dee9SAndroid Build Coastguard Worker maxActiveCount := 200 1229*1fa6dee9SAndroid Build Coastguard Worker 1230*1fa6dee9SAndroid Build Coastguard Worker // count the number of pending calls to visitor() 1231*1fa6dee9SAndroid Build Coastguard Worker visitorWaitGroup := sync.WaitGroup{} 1232*1fa6dee9SAndroid Build Coastguard Worker 1233*1fa6dee9SAndroid Build Coastguard Worker startParseBlueprintsFile := func(blueprint fileParseContext) { 1234*1fa6dee9SAndroid Build Coastguard Worker if blueprintsSet[blueprint.fileName] { 1235*1fa6dee9SAndroid Build Coastguard Worker return 1236*1fa6dee9SAndroid Build Coastguard Worker } 1237*1fa6dee9SAndroid Build Coastguard Worker blueprintsSet[blueprint.fileName] = true 1238*1fa6dee9SAndroid Build Coastguard Worker activeCount++ 1239*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, blueprint.fileName) 1240*1fa6dee9SAndroid Build Coastguard Worker visitorWaitGroup.Add(1) 1241*1fa6dee9SAndroid Build Coastguard Worker go func() { 1242*1fa6dee9SAndroid Build Coastguard Worker file, blueprints, deps, errs := c.openAndParse(blueprint.fileName, blueprint.Scope, rootDir, 1243*1fa6dee9SAndroid Build Coastguard Worker &blueprint) 1244*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1245*1fa6dee9SAndroid Build Coastguard Worker errsCh <- errs 1246*1fa6dee9SAndroid Build Coastguard Worker } 1247*1fa6dee9SAndroid Build Coastguard Worker for _, blueprint := range blueprints { 1248*1fa6dee9SAndroid Build Coastguard Worker blueprintsCh <- blueprint 1249*1fa6dee9SAndroid Build Coastguard Worker } 1250*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range deps { 1251*1fa6dee9SAndroid Build Coastguard Worker depsCh <- dep 1252*1fa6dee9SAndroid Build Coastguard Worker } 1253*1fa6dee9SAndroid Build Coastguard Worker doneParsingCh <- blueprint 1254*1fa6dee9SAndroid Build Coastguard Worker 1255*1fa6dee9SAndroid Build Coastguard Worker if blueprint.parent != nil && blueprint.parent.doneVisiting != nil { 1256*1fa6dee9SAndroid Build Coastguard Worker // wait for visitor() of parent to complete 1257*1fa6dee9SAndroid Build Coastguard Worker <-blueprint.parent.doneVisiting 1258*1fa6dee9SAndroid Build Coastguard Worker } 1259*1fa6dee9SAndroid Build Coastguard Worker 1260*1fa6dee9SAndroid Build Coastguard Worker if len(errs) == 0 { 1261*1fa6dee9SAndroid Build Coastguard Worker // process this file 1262*1fa6dee9SAndroid Build Coastguard Worker visitor(file) 1263*1fa6dee9SAndroid Build Coastguard Worker } 1264*1fa6dee9SAndroid Build Coastguard Worker if blueprint.doneVisiting != nil { 1265*1fa6dee9SAndroid Build Coastguard Worker close(blueprint.doneVisiting) 1266*1fa6dee9SAndroid Build Coastguard Worker } 1267*1fa6dee9SAndroid Build Coastguard Worker visitorWaitGroup.Done() 1268*1fa6dee9SAndroid Build Coastguard Worker }() 1269*1fa6dee9SAndroid Build Coastguard Worker } 1270*1fa6dee9SAndroid Build Coastguard Worker 1271*1fa6dee9SAndroid Build Coastguard Worker foundParseableBlueprint := func(blueprint fileParseContext) { 1272*1fa6dee9SAndroid Build Coastguard Worker if activeCount >= maxActiveCount { 1273*1fa6dee9SAndroid Build Coastguard Worker pending = append(pending, blueprint) 1274*1fa6dee9SAndroid Build Coastguard Worker } else { 1275*1fa6dee9SAndroid Build Coastguard Worker startParseBlueprintsFile(blueprint) 1276*1fa6dee9SAndroid Build Coastguard Worker } 1277*1fa6dee9SAndroid Build Coastguard Worker } 1278*1fa6dee9SAndroid Build Coastguard Worker 1279*1fa6dee9SAndroid Build Coastguard Worker startParseDescendants := func(blueprint fileParseContext) { 1280*1fa6dee9SAndroid Build Coastguard Worker descendants, hasDescendants := descendantsMap[blueprint.fileName] 1281*1fa6dee9SAndroid Build Coastguard Worker if hasDescendants { 1282*1fa6dee9SAndroid Build Coastguard Worker for _, descendant := range descendants { 1283*1fa6dee9SAndroid Build Coastguard Worker foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})}) 1284*1fa6dee9SAndroid Build Coastguard Worker } 1285*1fa6dee9SAndroid Build Coastguard Worker } 1286*1fa6dee9SAndroid Build Coastguard Worker } 1287*1fa6dee9SAndroid Build Coastguard Worker 1288*1fa6dee9SAndroid Build Coastguard Worker // begin parsing any files that have no ancestors 1289*1fa6dee9SAndroid Build Coastguard Worker startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil}) 1290*1fa6dee9SAndroid Build Coastguard Worker 1291*1fa6dee9SAndroid Build Coastguard Workerloop: 1292*1fa6dee9SAndroid Build Coastguard Worker for { 1293*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > maxErrors { 1294*1fa6dee9SAndroid Build Coastguard Worker tooManyErrors = true 1295*1fa6dee9SAndroid Build Coastguard Worker } 1296*1fa6dee9SAndroid Build Coastguard Worker 1297*1fa6dee9SAndroid Build Coastguard Worker select { 1298*1fa6dee9SAndroid Build Coastguard Worker case newErrs := <-errsCh: 1299*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 1300*1fa6dee9SAndroid Build Coastguard Worker case dep := <-depsCh: 1301*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, dep) 1302*1fa6dee9SAndroid Build Coastguard Worker case blueprint := <-blueprintsCh: 1303*1fa6dee9SAndroid Build Coastguard Worker if tooManyErrors { 1304*1fa6dee9SAndroid Build Coastguard Worker continue 1305*1fa6dee9SAndroid Build Coastguard Worker } 1306*1fa6dee9SAndroid Build Coastguard Worker foundParseableBlueprint(blueprint) 1307*1fa6dee9SAndroid Build Coastguard Worker case blueprint := <-doneParsingCh: 1308*1fa6dee9SAndroid Build Coastguard Worker activeCount-- 1309*1fa6dee9SAndroid Build Coastguard Worker if !tooManyErrors { 1310*1fa6dee9SAndroid Build Coastguard Worker startParseDescendants(blueprint) 1311*1fa6dee9SAndroid Build Coastguard Worker } 1312*1fa6dee9SAndroid Build Coastguard Worker if activeCount < maxActiveCount && len(pending) > 0 { 1313*1fa6dee9SAndroid Build Coastguard Worker // start to process the next one from the queue 1314*1fa6dee9SAndroid Build Coastguard Worker next := pending[len(pending)-1] 1315*1fa6dee9SAndroid Build Coastguard Worker pending = pending[:len(pending)-1] 1316*1fa6dee9SAndroid Build Coastguard Worker startParseBlueprintsFile(next) 1317*1fa6dee9SAndroid Build Coastguard Worker } 1318*1fa6dee9SAndroid Build Coastguard Worker if activeCount == 0 { 1319*1fa6dee9SAndroid Build Coastguard Worker break loop 1320*1fa6dee9SAndroid Build Coastguard Worker } 1321*1fa6dee9SAndroid Build Coastguard Worker } 1322*1fa6dee9SAndroid Build Coastguard Worker } 1323*1fa6dee9SAndroid Build Coastguard Worker 1324*1fa6dee9SAndroid Build Coastguard Worker sort.Strings(deps) 1325*1fa6dee9SAndroid Build Coastguard Worker 1326*1fa6dee9SAndroid Build Coastguard Worker // wait for every visitor() to complete 1327*1fa6dee9SAndroid Build Coastguard Worker visitorWaitGroup.Wait() 1328*1fa6dee9SAndroid Build Coastguard Worker 1329*1fa6dee9SAndroid Build Coastguard Worker return 1330*1fa6dee9SAndroid Build Coastguard Worker} 1331*1fa6dee9SAndroid Build Coastguard Worker 1332*1fa6dee9SAndroid Build Coastguard Worker// MockFileSystem causes the Context to replace all reads with accesses to the provided map of 1333*1fa6dee9SAndroid Build Coastguard Worker// filenames to contents stored as a byte slice. 1334*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) MockFileSystem(files map[string][]byte) { 1335*1fa6dee9SAndroid Build Coastguard Worker // look for a module list file 1336*1fa6dee9SAndroid Build Coastguard Worker _, ok := files[MockModuleListFile] 1337*1fa6dee9SAndroid Build Coastguard Worker if !ok { 1338*1fa6dee9SAndroid Build Coastguard Worker // no module list file specified; find every file named Blueprints 1339*1fa6dee9SAndroid Build Coastguard Worker pathsToParse := []string{} 1340*1fa6dee9SAndroid Build Coastguard Worker for candidate := range files { 1341*1fa6dee9SAndroid Build Coastguard Worker if filepath.Base(candidate) == "Android.bp" { 1342*1fa6dee9SAndroid Build Coastguard Worker pathsToParse = append(pathsToParse, candidate) 1343*1fa6dee9SAndroid Build Coastguard Worker } 1344*1fa6dee9SAndroid Build Coastguard Worker } 1345*1fa6dee9SAndroid Build Coastguard Worker if len(pathsToParse) < 1 { 1346*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files)) 1347*1fa6dee9SAndroid Build Coastguard Worker } 1348*1fa6dee9SAndroid Build Coastguard Worker // put the list of Blueprints files into a list file 1349*1fa6dee9SAndroid Build Coastguard Worker files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n")) 1350*1fa6dee9SAndroid Build Coastguard Worker } 1351*1fa6dee9SAndroid Build Coastguard Worker c.SetModuleListFile(MockModuleListFile) 1352*1fa6dee9SAndroid Build Coastguard Worker 1353*1fa6dee9SAndroid Build Coastguard Worker // mock the filesystem 1354*1fa6dee9SAndroid Build Coastguard Worker c.fs = pathtools.MockFs(files) 1355*1fa6dee9SAndroid Build Coastguard Worker} 1356*1fa6dee9SAndroid Build Coastguard Worker 1357*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SetFs(fs pathtools.FileSystem) { 1358*1fa6dee9SAndroid Build Coastguard Worker c.fs = fs 1359*1fa6dee9SAndroid Build Coastguard Worker} 1360*1fa6dee9SAndroid Build Coastguard Worker 1361*1fa6dee9SAndroid Build Coastguard Worker// openAndParse opens and parses a single Blueprints file, and returns the results 1362*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) openAndParse(filename string, scope *parser.Scope, rootDir string, 1363*1fa6dee9SAndroid Build Coastguard Worker parent *fileParseContext) (file *parser.File, 1364*1fa6dee9SAndroid Build Coastguard Worker subBlueprints []fileParseContext, deps []string, errs []error) { 1365*1fa6dee9SAndroid Build Coastguard Worker 1366*1fa6dee9SAndroid Build Coastguard Worker f, err := c.fs.Open(filename) 1367*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1368*1fa6dee9SAndroid Build Coastguard Worker // couldn't open the file; see if we can provide a clearer error than "could not open file" 1369*1fa6dee9SAndroid Build Coastguard Worker stats, statErr := c.fs.Lstat(filename) 1370*1fa6dee9SAndroid Build Coastguard Worker if statErr == nil { 1371*1fa6dee9SAndroid Build Coastguard Worker isSymlink := stats.Mode()&os.ModeSymlink != 0 1372*1fa6dee9SAndroid Build Coastguard Worker if isSymlink { 1373*1fa6dee9SAndroid Build Coastguard Worker err = fmt.Errorf("could not open symlink %v : %v", filename, err) 1374*1fa6dee9SAndroid Build Coastguard Worker target, readlinkErr := os.Readlink(filename) 1375*1fa6dee9SAndroid Build Coastguard Worker if readlinkErr == nil { 1376*1fa6dee9SAndroid Build Coastguard Worker _, targetStatsErr := c.fs.Lstat(target) 1377*1fa6dee9SAndroid Build Coastguard Worker if targetStatsErr != nil { 1378*1fa6dee9SAndroid Build Coastguard Worker err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target) 1379*1fa6dee9SAndroid Build Coastguard Worker } 1380*1fa6dee9SAndroid Build Coastguard Worker } 1381*1fa6dee9SAndroid Build Coastguard Worker } else { 1382*1fa6dee9SAndroid Build Coastguard Worker err = fmt.Errorf("%v exists but could not be opened: %v", filename, err) 1383*1fa6dee9SAndroid Build Coastguard Worker } 1384*1fa6dee9SAndroid Build Coastguard Worker } 1385*1fa6dee9SAndroid Build Coastguard Worker return nil, nil, nil, []error{err} 1386*1fa6dee9SAndroid Build Coastguard Worker } 1387*1fa6dee9SAndroid Build Coastguard Worker 1388*1fa6dee9SAndroid Build Coastguard Worker func() { 1389*1fa6dee9SAndroid Build Coastguard Worker defer func() { 1390*1fa6dee9SAndroid Build Coastguard Worker err = f.Close() 1391*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1392*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, err) 1393*1fa6dee9SAndroid Build Coastguard Worker } 1394*1fa6dee9SAndroid Build Coastguard Worker }() 1395*1fa6dee9SAndroid Build Coastguard Worker file, subBlueprints, errs = c.parseOne(rootDir, filename, f, scope, parent) 1396*1fa6dee9SAndroid Build Coastguard Worker }() 1397*1fa6dee9SAndroid Build Coastguard Worker 1398*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1399*1fa6dee9SAndroid Build Coastguard Worker return nil, nil, nil, errs 1400*1fa6dee9SAndroid Build Coastguard Worker } 1401*1fa6dee9SAndroid Build Coastguard Worker 1402*1fa6dee9SAndroid Build Coastguard Worker for _, b := range subBlueprints { 1403*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, b.fileName) 1404*1fa6dee9SAndroid Build Coastguard Worker } 1405*1fa6dee9SAndroid Build Coastguard Worker 1406*1fa6dee9SAndroid Build Coastguard Worker return file, subBlueprints, deps, nil 1407*1fa6dee9SAndroid Build Coastguard Worker} 1408*1fa6dee9SAndroid Build Coastguard Worker 1409*1fa6dee9SAndroid Build Coastguard Worker// parseOne parses a single Blueprints file from the given reader, creating Module 1410*1fa6dee9SAndroid Build Coastguard Worker// objects for each of the module definitions encountered. If the Blueprints 1411*1fa6dee9SAndroid Build Coastguard Worker// file contains an assignment to the "subdirs" variable, then the 1412*1fa6dee9SAndroid Build Coastguard Worker// subdirectories listed are searched for Blueprints files returned in the 1413*1fa6dee9SAndroid Build Coastguard Worker// subBlueprints return value. If the Blueprints file contains an assignment 1414*1fa6dee9SAndroid Build Coastguard Worker// to the "build" variable, then the file listed are returned in the 1415*1fa6dee9SAndroid Build Coastguard Worker// subBlueprints return value. 1416*1fa6dee9SAndroid Build Coastguard Worker// 1417*1fa6dee9SAndroid Build Coastguard Worker// rootDir specifies the path to the root directory of the source tree, while 1418*1fa6dee9SAndroid Build Coastguard Worker// filename specifies the path to the Blueprints file. These paths are used for 1419*1fa6dee9SAndroid Build Coastguard Worker// error reporting and for determining the module's directory. 1420*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) parseOne(rootDir, filename string, reader io.Reader, 1421*1fa6dee9SAndroid Build Coastguard Worker scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) { 1422*1fa6dee9SAndroid Build Coastguard Worker 1423*1fa6dee9SAndroid Build Coastguard Worker relBlueprintsFile, err := filepath.Rel(rootDir, filename) 1424*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1425*1fa6dee9SAndroid Build Coastguard Worker return nil, nil, []error{err} 1426*1fa6dee9SAndroid Build Coastguard Worker } 1427*1fa6dee9SAndroid Build Coastguard Worker 1428*1fa6dee9SAndroid Build Coastguard Worker scope.DontInherit("subdirs") 1429*1fa6dee9SAndroid Build Coastguard Worker scope.DontInherit("optional_subdirs") 1430*1fa6dee9SAndroid Build Coastguard Worker scope.DontInherit("build") 1431*1fa6dee9SAndroid Build Coastguard Worker file, errs = parser.ParseAndEval(filename, reader, scope) 1432*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1433*1fa6dee9SAndroid Build Coastguard Worker for i, err := range errs { 1434*1fa6dee9SAndroid Build Coastguard Worker if parseErr, ok := err.(*parser.ParseError); ok { 1435*1fa6dee9SAndroid Build Coastguard Worker err = &BlueprintError{ 1436*1fa6dee9SAndroid Build Coastguard Worker Err: parseErr.Err, 1437*1fa6dee9SAndroid Build Coastguard Worker Pos: parseErr.Pos, 1438*1fa6dee9SAndroid Build Coastguard Worker } 1439*1fa6dee9SAndroid Build Coastguard Worker errs[i] = err 1440*1fa6dee9SAndroid Build Coastguard Worker } 1441*1fa6dee9SAndroid Build Coastguard Worker } 1442*1fa6dee9SAndroid Build Coastguard Worker 1443*1fa6dee9SAndroid Build Coastguard Worker // If there were any parse errors don't bother trying to interpret the 1444*1fa6dee9SAndroid Build Coastguard Worker // result. 1445*1fa6dee9SAndroid Build Coastguard Worker return nil, nil, errs 1446*1fa6dee9SAndroid Build Coastguard Worker } 1447*1fa6dee9SAndroid Build Coastguard Worker file.Name = relBlueprintsFile 1448*1fa6dee9SAndroid Build Coastguard Worker 1449*1fa6dee9SAndroid Build Coastguard Worker build, buildPos, err := getLocalStringListFromScope(scope, "build") 1450*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1451*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, err) 1452*1fa6dee9SAndroid Build Coastguard Worker } 1453*1fa6dee9SAndroid Build Coastguard Worker for _, buildEntry := range build { 1454*1fa6dee9SAndroid Build Coastguard Worker if strings.Contains(buildEntry, "/") { 1455*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 1456*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry), 1457*1fa6dee9SAndroid Build Coastguard Worker Pos: buildPos, 1458*1fa6dee9SAndroid Build Coastguard Worker }) 1459*1fa6dee9SAndroid Build Coastguard Worker } 1460*1fa6dee9SAndroid Build Coastguard Worker } 1461*1fa6dee9SAndroid Build Coastguard Worker 1462*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1463*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, err) 1464*1fa6dee9SAndroid Build Coastguard Worker } 1465*1fa6dee9SAndroid Build Coastguard Worker 1466*1fa6dee9SAndroid Build Coastguard Worker var blueprints []string 1467*1fa6dee9SAndroid Build Coastguard Worker 1468*1fa6dee9SAndroid Build Coastguard Worker newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos) 1469*1fa6dee9SAndroid Build Coastguard Worker blueprints = append(blueprints, newBlueprints...) 1470*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 1471*1fa6dee9SAndroid Build Coastguard Worker 1472*1fa6dee9SAndroid Build Coastguard Worker subBlueprintsAndScope := make([]fileParseContext, len(blueprints)) 1473*1fa6dee9SAndroid Build Coastguard Worker for i, b := range blueprints { 1474*1fa6dee9SAndroid Build Coastguard Worker subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})} 1475*1fa6dee9SAndroid Build Coastguard Worker } 1476*1fa6dee9SAndroid Build Coastguard Worker return file, subBlueprintsAndScope, errs 1477*1fa6dee9SAndroid Build Coastguard Worker} 1478*1fa6dee9SAndroid Build Coastguard Worker 1479*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) findBuildBlueprints(dir string, build []string, 1480*1fa6dee9SAndroid Build Coastguard Worker buildPos scanner.Position) ([]string, []error) { 1481*1fa6dee9SAndroid Build Coastguard Worker 1482*1fa6dee9SAndroid Build Coastguard Worker var blueprints []string 1483*1fa6dee9SAndroid Build Coastguard Worker var errs []error 1484*1fa6dee9SAndroid Build Coastguard Worker 1485*1fa6dee9SAndroid Build Coastguard Worker for _, file := range build { 1486*1fa6dee9SAndroid Build Coastguard Worker pattern := filepath.Join(dir, file) 1487*1fa6dee9SAndroid Build Coastguard Worker var matches []string 1488*1fa6dee9SAndroid Build Coastguard Worker var err error 1489*1fa6dee9SAndroid Build Coastguard Worker 1490*1fa6dee9SAndroid Build Coastguard Worker matches, err = c.glob(pattern, nil) 1491*1fa6dee9SAndroid Build Coastguard Worker 1492*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1493*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 1494*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q: %s", pattern, err.Error()), 1495*1fa6dee9SAndroid Build Coastguard Worker Pos: buildPos, 1496*1fa6dee9SAndroid Build Coastguard Worker }) 1497*1fa6dee9SAndroid Build Coastguard Worker continue 1498*1fa6dee9SAndroid Build Coastguard Worker } 1499*1fa6dee9SAndroid Build Coastguard Worker 1500*1fa6dee9SAndroid Build Coastguard Worker if len(matches) == 0 { 1501*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 1502*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q: not found", pattern), 1503*1fa6dee9SAndroid Build Coastguard Worker Pos: buildPos, 1504*1fa6dee9SAndroid Build Coastguard Worker }) 1505*1fa6dee9SAndroid Build Coastguard Worker } 1506*1fa6dee9SAndroid Build Coastguard Worker 1507*1fa6dee9SAndroid Build Coastguard Worker for _, foundBlueprints := range matches { 1508*1fa6dee9SAndroid Build Coastguard Worker if strings.HasSuffix(foundBlueprints, "/") { 1509*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 1510*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q: is a directory", foundBlueprints), 1511*1fa6dee9SAndroid Build Coastguard Worker Pos: buildPos, 1512*1fa6dee9SAndroid Build Coastguard Worker }) 1513*1fa6dee9SAndroid Build Coastguard Worker } 1514*1fa6dee9SAndroid Build Coastguard Worker blueprints = append(blueprints, foundBlueprints) 1515*1fa6dee9SAndroid Build Coastguard Worker } 1516*1fa6dee9SAndroid Build Coastguard Worker } 1517*1fa6dee9SAndroid Build Coastguard Worker 1518*1fa6dee9SAndroid Build Coastguard Worker return blueprints, errs 1519*1fa6dee9SAndroid Build Coastguard Worker} 1520*1fa6dee9SAndroid Build Coastguard Worker 1521*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position, 1522*1fa6dee9SAndroid Build Coastguard Worker subBlueprintsName string, optional bool) ([]string, []error) { 1523*1fa6dee9SAndroid Build Coastguard Worker 1524*1fa6dee9SAndroid Build Coastguard Worker var blueprints []string 1525*1fa6dee9SAndroid Build Coastguard Worker var errs []error 1526*1fa6dee9SAndroid Build Coastguard Worker 1527*1fa6dee9SAndroid Build Coastguard Worker for _, subdir := range subdirs { 1528*1fa6dee9SAndroid Build Coastguard Worker pattern := filepath.Join(dir, subdir, subBlueprintsName) 1529*1fa6dee9SAndroid Build Coastguard Worker var matches []string 1530*1fa6dee9SAndroid Build Coastguard Worker var err error 1531*1fa6dee9SAndroid Build Coastguard Worker 1532*1fa6dee9SAndroid Build Coastguard Worker matches, err = c.glob(pattern, nil) 1533*1fa6dee9SAndroid Build Coastguard Worker 1534*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1535*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 1536*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q: %s", pattern, err.Error()), 1537*1fa6dee9SAndroid Build Coastguard Worker Pos: subdirsPos, 1538*1fa6dee9SAndroid Build Coastguard Worker }) 1539*1fa6dee9SAndroid Build Coastguard Worker continue 1540*1fa6dee9SAndroid Build Coastguard Worker } 1541*1fa6dee9SAndroid Build Coastguard Worker 1542*1fa6dee9SAndroid Build Coastguard Worker if len(matches) == 0 && !optional { 1543*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 1544*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q: not found", pattern), 1545*1fa6dee9SAndroid Build Coastguard Worker Pos: subdirsPos, 1546*1fa6dee9SAndroid Build Coastguard Worker }) 1547*1fa6dee9SAndroid Build Coastguard Worker } 1548*1fa6dee9SAndroid Build Coastguard Worker 1549*1fa6dee9SAndroid Build Coastguard Worker for _, subBlueprints := range matches { 1550*1fa6dee9SAndroid Build Coastguard Worker if strings.HasSuffix(subBlueprints, "/") { 1551*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 1552*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q: is a directory", subBlueprints), 1553*1fa6dee9SAndroid Build Coastguard Worker Pos: subdirsPos, 1554*1fa6dee9SAndroid Build Coastguard Worker }) 1555*1fa6dee9SAndroid Build Coastguard Worker } 1556*1fa6dee9SAndroid Build Coastguard Worker blueprints = append(blueprints, subBlueprints) 1557*1fa6dee9SAndroid Build Coastguard Worker } 1558*1fa6dee9SAndroid Build Coastguard Worker } 1559*1fa6dee9SAndroid Build Coastguard Worker 1560*1fa6dee9SAndroid Build Coastguard Worker return blueprints, errs 1561*1fa6dee9SAndroid Build Coastguard Worker} 1562*1fa6dee9SAndroid Build Coastguard Worker 1563*1fa6dee9SAndroid Build Coastguard Workerfunc getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) { 1564*1fa6dee9SAndroid Build Coastguard Worker if assignment := scope.GetLocal(v); assignment == nil { 1565*1fa6dee9SAndroid Build Coastguard Worker return nil, scanner.Position{}, nil 1566*1fa6dee9SAndroid Build Coastguard Worker } else { 1567*1fa6dee9SAndroid Build Coastguard Worker switch value := assignment.Value.(type) { 1568*1fa6dee9SAndroid Build Coastguard Worker case *parser.List: 1569*1fa6dee9SAndroid Build Coastguard Worker ret := make([]string, 0, len(value.Values)) 1570*1fa6dee9SAndroid Build Coastguard Worker 1571*1fa6dee9SAndroid Build Coastguard Worker for _, listValue := range value.Values { 1572*1fa6dee9SAndroid Build Coastguard Worker s, ok := listValue.(*parser.String) 1573*1fa6dee9SAndroid Build Coastguard Worker if !ok { 1574*1fa6dee9SAndroid Build Coastguard Worker // The parser should not produce this. 1575*1fa6dee9SAndroid Build Coastguard Worker panic("non-string value found in list") 1576*1fa6dee9SAndroid Build Coastguard Worker } 1577*1fa6dee9SAndroid Build Coastguard Worker 1578*1fa6dee9SAndroid Build Coastguard Worker ret = append(ret, s.Value) 1579*1fa6dee9SAndroid Build Coastguard Worker } 1580*1fa6dee9SAndroid Build Coastguard Worker 1581*1fa6dee9SAndroid Build Coastguard Worker return ret, assignment.EqualsPos, nil 1582*1fa6dee9SAndroid Build Coastguard Worker case *parser.Bool, *parser.String: 1583*1fa6dee9SAndroid Build Coastguard Worker return nil, scanner.Position{}, &BlueprintError{ 1584*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q must be a list of strings", v), 1585*1fa6dee9SAndroid Build Coastguard Worker Pos: assignment.EqualsPos, 1586*1fa6dee9SAndroid Build Coastguard Worker } 1587*1fa6dee9SAndroid Build Coastguard Worker default: 1588*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type())) 1589*1fa6dee9SAndroid Build Coastguard Worker } 1590*1fa6dee9SAndroid Build Coastguard Worker } 1591*1fa6dee9SAndroid Build Coastguard Worker} 1592*1fa6dee9SAndroid Build Coastguard Worker 1593*1fa6dee9SAndroid Build Coastguard Worker// Clones a build logic module by calling the factory method for its module type, and then cloning 1594*1fa6dee9SAndroid Build Coastguard Worker// property values. Any values stored in the module object that are not stored in properties 1595*1fa6dee9SAndroid Build Coastguard Worker// structs will be lost. 1596*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) { 1597*1fa6dee9SAndroid Build Coastguard Worker newLogicModule, newProperties := origModule.factory() 1598*1fa6dee9SAndroid Build Coastguard Worker 1599*1fa6dee9SAndroid Build Coastguard Worker if len(newProperties) != len(origModule.properties) { 1600*1fa6dee9SAndroid Build Coastguard Worker panic("mismatched properties array length in " + origModule.Name()) 1601*1fa6dee9SAndroid Build Coastguard Worker } 1602*1fa6dee9SAndroid Build Coastguard Worker 1603*1fa6dee9SAndroid Build Coastguard Worker for i := range newProperties { 1604*1fa6dee9SAndroid Build Coastguard Worker dst := reflect.ValueOf(newProperties[i]) 1605*1fa6dee9SAndroid Build Coastguard Worker src := reflect.ValueOf(origModule.properties[i]) 1606*1fa6dee9SAndroid Build Coastguard Worker 1607*1fa6dee9SAndroid Build Coastguard Worker proptools.CopyProperties(dst, src) 1608*1fa6dee9SAndroid Build Coastguard Worker } 1609*1fa6dee9SAndroid Build Coastguard Worker 1610*1fa6dee9SAndroid Build Coastguard Worker return newLogicModule, newProperties 1611*1fa6dee9SAndroid Build Coastguard Worker} 1612*1fa6dee9SAndroid Build Coastguard Worker 1613*1fa6dee9SAndroid Build Coastguard Workerfunc newVariant(module *moduleInfo, mutatorName string, variationName string) variant { 1614*1fa6dee9SAndroid Build Coastguard Worker 1615*1fa6dee9SAndroid Build Coastguard Worker newVariantName := module.variant.name 1616*1fa6dee9SAndroid Build Coastguard Worker if variationName != "" { 1617*1fa6dee9SAndroid Build Coastguard Worker if newVariantName == "" { 1618*1fa6dee9SAndroid Build Coastguard Worker newVariantName = variationName 1619*1fa6dee9SAndroid Build Coastguard Worker } else { 1620*1fa6dee9SAndroid Build Coastguard Worker newVariantName += "_" + variationName 1621*1fa6dee9SAndroid Build Coastguard Worker } 1622*1fa6dee9SAndroid Build Coastguard Worker } 1623*1fa6dee9SAndroid Build Coastguard Worker 1624*1fa6dee9SAndroid Build Coastguard Worker newVariations := module.variant.variations.clone() 1625*1fa6dee9SAndroid Build Coastguard Worker newVariations.set(mutatorName, variationName) 1626*1fa6dee9SAndroid Build Coastguard Worker 1627*1fa6dee9SAndroid Build Coastguard Worker return variant{newVariantName, newVariations} 1628*1fa6dee9SAndroid Build Coastguard Worker} 1629*1fa6dee9SAndroid Build Coastguard Worker 1630*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) createVariations(origModule *moduleInfo, mutator *mutatorInfo, 1631*1fa6dee9SAndroid Build Coastguard Worker depChooser depChooser, variationNames []string) (moduleList, []error) { 1632*1fa6dee9SAndroid Build Coastguard Worker 1633*1fa6dee9SAndroid Build Coastguard Worker if mutator.transitionMutator == nil { 1634*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("method createVariations called from mutator that was not a TransitionMutator")) 1635*1fa6dee9SAndroid Build Coastguard Worker } 1636*1fa6dee9SAndroid Build Coastguard Worker 1637*1fa6dee9SAndroid Build Coastguard Worker if len(variationNames) == 0 { 1638*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q", 1639*1fa6dee9SAndroid Build Coastguard Worker mutator.name, origModule.Name())) 1640*1fa6dee9SAndroid Build Coastguard Worker } 1641*1fa6dee9SAndroid Build Coastguard Worker 1642*1fa6dee9SAndroid Build Coastguard Worker var newModules moduleList 1643*1fa6dee9SAndroid Build Coastguard Worker 1644*1fa6dee9SAndroid Build Coastguard Worker var errs []error 1645*1fa6dee9SAndroid Build Coastguard Worker 1646*1fa6dee9SAndroid Build Coastguard Worker for i, variationName := range variationNames { 1647*1fa6dee9SAndroid Build Coastguard Worker var newLogicModule Module 1648*1fa6dee9SAndroid Build Coastguard Worker var newProperties []interface{} 1649*1fa6dee9SAndroid Build Coastguard Worker 1650*1fa6dee9SAndroid Build Coastguard Worker if i == 0 && mutator.transitionMutator == nil { 1651*1fa6dee9SAndroid Build Coastguard Worker // Reuse the existing module for the first new variant 1652*1fa6dee9SAndroid Build Coastguard Worker // This both saves creating a new module, and causes the insertion in c.moduleInfo below 1653*1fa6dee9SAndroid Build Coastguard Worker // with logicModule as the key to replace the original entry in c.moduleInfo 1654*1fa6dee9SAndroid Build Coastguard Worker newLogicModule, newProperties = origModule.logicModule, origModule.properties 1655*1fa6dee9SAndroid Build Coastguard Worker } else { 1656*1fa6dee9SAndroid Build Coastguard Worker newLogicModule, newProperties = c.cloneLogicModule(origModule) 1657*1fa6dee9SAndroid Build Coastguard Worker } 1658*1fa6dee9SAndroid Build Coastguard Worker 1659*1fa6dee9SAndroid Build Coastguard Worker m := *origModule 1660*1fa6dee9SAndroid Build Coastguard Worker newModule := &m 1661*1fa6dee9SAndroid Build Coastguard Worker newModule.directDeps = slices.Clone(origModule.directDeps) 1662*1fa6dee9SAndroid Build Coastguard Worker newModule.reverseDeps = nil 1663*1fa6dee9SAndroid Build Coastguard Worker newModule.forwardDeps = nil 1664*1fa6dee9SAndroid Build Coastguard Worker newModule.logicModule = newLogicModule 1665*1fa6dee9SAndroid Build Coastguard Worker newModule.variant = newVariant(origModule, mutator.name, variationName) 1666*1fa6dee9SAndroid Build Coastguard Worker newModule.properties = newProperties 1667*1fa6dee9SAndroid Build Coastguard Worker newModule.providers = slices.Clone(origModule.providers) 1668*1fa6dee9SAndroid Build Coastguard Worker newModule.providerInitialValueHashes = slices.Clone(origModule.providerInitialValueHashes) 1669*1fa6dee9SAndroid Build Coastguard Worker 1670*1fa6dee9SAndroid Build Coastguard Worker newModules = append(newModules, newModule) 1671*1fa6dee9SAndroid Build Coastguard Worker 1672*1fa6dee9SAndroid Build Coastguard Worker newErrs := c.convertDepsToVariation(newModule, i, depChooser) 1673*1fa6dee9SAndroid Build Coastguard Worker if len(newErrs) > 0 { 1674*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 1675*1fa6dee9SAndroid Build Coastguard Worker } 1676*1fa6dee9SAndroid Build Coastguard Worker } 1677*1fa6dee9SAndroid Build Coastguard Worker 1678*1fa6dee9SAndroid Build Coastguard Worker // Mark original variant as invalid. Modules that depend on this module will still 1679*1fa6dee9SAndroid Build Coastguard Worker // depend on origModule, but we'll fix it when the mutator is called on them. 1680*1fa6dee9SAndroid Build Coastguard Worker origModule.obsoletedByNewVariants = true 1681*1fa6dee9SAndroid Build Coastguard Worker origModule.splitModules = newModules 1682*1fa6dee9SAndroid Build Coastguard Worker 1683*1fa6dee9SAndroid Build Coastguard Worker atomic.AddUint32(&c.needsUpdateDependencies, 1) 1684*1fa6dee9SAndroid Build Coastguard Worker 1685*1fa6dee9SAndroid Build Coastguard Worker return newModules, errs 1686*1fa6dee9SAndroid Build Coastguard Worker} 1687*1fa6dee9SAndroid Build Coastguard Worker 1688*1fa6dee9SAndroid Build Coastguard Workertype depChooser func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string) 1689*1fa6dee9SAndroid Build Coastguard Worker 1690*1fa6dee9SAndroid Build Coastguard Workerfunc chooseDep(candidates moduleList, mutatorName, variationName string, defaultVariationName *string) (*moduleInfo, string) { 1691*1fa6dee9SAndroid Build Coastguard Worker for _, m := range candidates { 1692*1fa6dee9SAndroid Build Coastguard Worker if m.variant.variations.get(mutatorName) == variationName { 1693*1fa6dee9SAndroid Build Coastguard Worker return m, "" 1694*1fa6dee9SAndroid Build Coastguard Worker } 1695*1fa6dee9SAndroid Build Coastguard Worker } 1696*1fa6dee9SAndroid Build Coastguard Worker 1697*1fa6dee9SAndroid Build Coastguard Worker if defaultVariationName != nil { 1698*1fa6dee9SAndroid Build Coastguard Worker // give it a second chance; match with defaultVariationName 1699*1fa6dee9SAndroid Build Coastguard Worker for _, m := range candidates { 1700*1fa6dee9SAndroid Build Coastguard Worker if m.variant.variations.get(mutatorName) == *defaultVariationName { 1701*1fa6dee9SAndroid Build Coastguard Worker return m, "" 1702*1fa6dee9SAndroid Build Coastguard Worker } 1703*1fa6dee9SAndroid Build Coastguard Worker } 1704*1fa6dee9SAndroid Build Coastguard Worker } 1705*1fa6dee9SAndroid Build Coastguard Worker 1706*1fa6dee9SAndroid Build Coastguard Worker return nil, variationName 1707*1fa6dee9SAndroid Build Coastguard Worker} 1708*1fa6dee9SAndroid Build Coastguard Worker 1709*1fa6dee9SAndroid Build Coastguard Workerfunc chooseDepByIndexes(mutatorName string, variations [][]string) depChooser { 1710*1fa6dee9SAndroid Build Coastguard Worker return func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string) { 1711*1fa6dee9SAndroid Build Coastguard Worker desiredVariation := variations[variationIndex][depIndex] 1712*1fa6dee9SAndroid Build Coastguard Worker return chooseDep(dep.module.splitModules, mutatorName, desiredVariation, nil) 1713*1fa6dee9SAndroid Build Coastguard Worker } 1714*1fa6dee9SAndroid Build Coastguard Worker} 1715*1fa6dee9SAndroid Build Coastguard Worker 1716*1fa6dee9SAndroid Build Coastguard Workerfunc chooseDepExplicit(mutatorName string, 1717*1fa6dee9SAndroid Build Coastguard Worker variationName string, defaultVariationName *string) depChooser { 1718*1fa6dee9SAndroid Build Coastguard Worker return func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string) { 1719*1fa6dee9SAndroid Build Coastguard Worker return chooseDep(dep.module.splitModules, mutatorName, variationName, defaultVariationName) 1720*1fa6dee9SAndroid Build Coastguard Worker } 1721*1fa6dee9SAndroid Build Coastguard Worker} 1722*1fa6dee9SAndroid Build Coastguard Worker 1723*1fa6dee9SAndroid Build Coastguard Workerfunc chooseDepInherit(mutatorName string, defaultVariationName *string) depChooser { 1724*1fa6dee9SAndroid Build Coastguard Worker return func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string) { 1725*1fa6dee9SAndroid Build Coastguard Worker sourceVariation := source.variant.variations.get(mutatorName) 1726*1fa6dee9SAndroid Build Coastguard Worker return chooseDep(dep.module.splitModules, mutatorName, sourceVariation, defaultVariationName) 1727*1fa6dee9SAndroid Build Coastguard Worker } 1728*1fa6dee9SAndroid Build Coastguard Worker} 1729*1fa6dee9SAndroid Build Coastguard Worker 1730*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) convertDepsToVariation(module *moduleInfo, variationIndex int, depChooser depChooser) (errs []error) { 1731*1fa6dee9SAndroid Build Coastguard Worker for i, dep := range module.directDeps { 1732*1fa6dee9SAndroid Build Coastguard Worker if dep.module.obsoletedByNewVariants { 1733*1fa6dee9SAndroid Build Coastguard Worker newDep, missingVariation := depChooser(module, variationIndex, i, dep) 1734*1fa6dee9SAndroid Build Coastguard Worker if newDep == nil { 1735*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 1736*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("failed to find variation %q for module %q needed by %q", 1737*1fa6dee9SAndroid Build Coastguard Worker missingVariation, dep.module.Name(), module.Name()), 1738*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 1739*1fa6dee9SAndroid Build Coastguard Worker }) 1740*1fa6dee9SAndroid Build Coastguard Worker continue 1741*1fa6dee9SAndroid Build Coastguard Worker } 1742*1fa6dee9SAndroid Build Coastguard Worker module.directDeps[i].module = newDep 1743*1fa6dee9SAndroid Build Coastguard Worker } 1744*1fa6dee9SAndroid Build Coastguard Worker } 1745*1fa6dee9SAndroid Build Coastguard Worker 1746*1fa6dee9SAndroid Build Coastguard Worker return errs 1747*1fa6dee9SAndroid Build Coastguard Worker} 1748*1fa6dee9SAndroid Build Coastguard Worker 1749*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) prettyPrintVariant(variations variationMap) string { 1750*1fa6dee9SAndroid Build Coastguard Worker var names []string 1751*1fa6dee9SAndroid Build Coastguard Worker for _, m := range c.variantMutatorNames { 1752*1fa6dee9SAndroid Build Coastguard Worker if v := variations.get(m); v != "" { 1753*1fa6dee9SAndroid Build Coastguard Worker names = append(names, m+":"+v) 1754*1fa6dee9SAndroid Build Coastguard Worker } 1755*1fa6dee9SAndroid Build Coastguard Worker } 1756*1fa6dee9SAndroid Build Coastguard Worker if len(names) == 0 { 1757*1fa6dee9SAndroid Build Coastguard Worker return "<empty variant>" 1758*1fa6dee9SAndroid Build Coastguard Worker } 1759*1fa6dee9SAndroid Build Coastguard Worker 1760*1fa6dee9SAndroid Build Coastguard Worker return strings.Join(names, ",") 1761*1fa6dee9SAndroid Build Coastguard Worker} 1762*1fa6dee9SAndroid Build Coastguard Worker 1763*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) prettyPrintGroupVariants(group *moduleGroup) string { 1764*1fa6dee9SAndroid Build Coastguard Worker var variants []string 1765*1fa6dee9SAndroid Build Coastguard Worker for _, module := range group.modules { 1766*1fa6dee9SAndroid Build Coastguard Worker variants = append(variants, c.prettyPrintVariant(module.variant.variations)) 1767*1fa6dee9SAndroid Build Coastguard Worker } 1768*1fa6dee9SAndroid Build Coastguard Worker return strings.Join(variants, "\n ") 1769*1fa6dee9SAndroid Build Coastguard Worker} 1770*1fa6dee9SAndroid Build Coastguard Worker 1771*1fa6dee9SAndroid Build Coastguard Workerfunc newModule(factory ModuleFactory) *moduleInfo { 1772*1fa6dee9SAndroid Build Coastguard Worker logicModule, properties := factory() 1773*1fa6dee9SAndroid Build Coastguard Worker 1774*1fa6dee9SAndroid Build Coastguard Worker return &moduleInfo{ 1775*1fa6dee9SAndroid Build Coastguard Worker logicModule: logicModule, 1776*1fa6dee9SAndroid Build Coastguard Worker factory: factory, 1777*1fa6dee9SAndroid Build Coastguard Worker properties: properties, 1778*1fa6dee9SAndroid Build Coastguard Worker } 1779*1fa6dee9SAndroid Build Coastguard Worker} 1780*1fa6dee9SAndroid Build Coastguard Worker 1781*1fa6dee9SAndroid Build Coastguard Workerfunc processModuleDef(moduleDef *parser.Module, 1782*1fa6dee9SAndroid Build Coastguard Worker relBlueprintsFile string, moduleFactories, scopedModuleFactories map[string]ModuleFactory, ignoreUnknownModuleTypes bool) (*moduleInfo, []error) { 1783*1fa6dee9SAndroid Build Coastguard Worker 1784*1fa6dee9SAndroid Build Coastguard Worker factory, ok := moduleFactories[moduleDef.Type] 1785*1fa6dee9SAndroid Build Coastguard Worker if !ok && scopedModuleFactories != nil { 1786*1fa6dee9SAndroid Build Coastguard Worker factory, ok = scopedModuleFactories[moduleDef.Type] 1787*1fa6dee9SAndroid Build Coastguard Worker } 1788*1fa6dee9SAndroid Build Coastguard Worker if !ok { 1789*1fa6dee9SAndroid Build Coastguard Worker if ignoreUnknownModuleTypes { 1790*1fa6dee9SAndroid Build Coastguard Worker return nil, nil 1791*1fa6dee9SAndroid Build Coastguard Worker } 1792*1fa6dee9SAndroid Build Coastguard Worker 1793*1fa6dee9SAndroid Build Coastguard Worker return nil, []error{ 1794*1fa6dee9SAndroid Build Coastguard Worker &BlueprintError{ 1795*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type), 1796*1fa6dee9SAndroid Build Coastguard Worker Pos: moduleDef.TypePos, 1797*1fa6dee9SAndroid Build Coastguard Worker }, 1798*1fa6dee9SAndroid Build Coastguard Worker } 1799*1fa6dee9SAndroid Build Coastguard Worker } 1800*1fa6dee9SAndroid Build Coastguard Worker 1801*1fa6dee9SAndroid Build Coastguard Worker module := newModule(factory) 1802*1fa6dee9SAndroid Build Coastguard Worker module.typeName = moduleDef.Type 1803*1fa6dee9SAndroid Build Coastguard Worker 1804*1fa6dee9SAndroid Build Coastguard Worker module.relBlueprintsFile = relBlueprintsFile 1805*1fa6dee9SAndroid Build Coastguard Worker 1806*1fa6dee9SAndroid Build Coastguard Worker propertyMap, errs := proptools.UnpackProperties(moduleDef.Properties, module.properties...) 1807*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1808*1fa6dee9SAndroid Build Coastguard Worker for i, err := range errs { 1809*1fa6dee9SAndroid Build Coastguard Worker if unpackErr, ok := err.(*proptools.UnpackError); ok { 1810*1fa6dee9SAndroid Build Coastguard Worker err = &BlueprintError{ 1811*1fa6dee9SAndroid Build Coastguard Worker Err: unpackErr.Err, 1812*1fa6dee9SAndroid Build Coastguard Worker Pos: unpackErr.Pos, 1813*1fa6dee9SAndroid Build Coastguard Worker } 1814*1fa6dee9SAndroid Build Coastguard Worker errs[i] = err 1815*1fa6dee9SAndroid Build Coastguard Worker } 1816*1fa6dee9SAndroid Build Coastguard Worker } 1817*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 1818*1fa6dee9SAndroid Build Coastguard Worker } 1819*1fa6dee9SAndroid Build Coastguard Worker 1820*1fa6dee9SAndroid Build Coastguard Worker module.pos = moduleDef.TypePos 1821*1fa6dee9SAndroid Build Coastguard Worker module.propertyPos = make(map[string]scanner.Position) 1822*1fa6dee9SAndroid Build Coastguard Worker for name, propertyDef := range propertyMap { 1823*1fa6dee9SAndroid Build Coastguard Worker module.propertyPos[name] = propertyDef.ColonPos 1824*1fa6dee9SAndroid Build Coastguard Worker } 1825*1fa6dee9SAndroid Build Coastguard Worker 1826*1fa6dee9SAndroid Build Coastguard Worker return module, nil 1827*1fa6dee9SAndroid Build Coastguard Worker} 1828*1fa6dee9SAndroid Build Coastguard Worker 1829*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) addModule(module *moduleInfo) []error { 1830*1fa6dee9SAndroid Build Coastguard Worker name := module.logicModule.Name() 1831*1fa6dee9SAndroid Build Coastguard Worker if name == "" { 1832*1fa6dee9SAndroid Build Coastguard Worker return []error{ 1833*1fa6dee9SAndroid Build Coastguard Worker &BlueprintError{ 1834*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("property 'name' is missing from a module"), 1835*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 1836*1fa6dee9SAndroid Build Coastguard Worker }, 1837*1fa6dee9SAndroid Build Coastguard Worker } 1838*1fa6dee9SAndroid Build Coastguard Worker } 1839*1fa6dee9SAndroid Build Coastguard Worker c.moduleInfo[module.logicModule] = module 1840*1fa6dee9SAndroid Build Coastguard Worker 1841*1fa6dee9SAndroid Build Coastguard Worker group := &moduleGroup{ 1842*1fa6dee9SAndroid Build Coastguard Worker name: name, 1843*1fa6dee9SAndroid Build Coastguard Worker modules: moduleList{module}, 1844*1fa6dee9SAndroid Build Coastguard Worker } 1845*1fa6dee9SAndroid Build Coastguard Worker module.group = group 1846*1fa6dee9SAndroid Build Coastguard Worker namespace, errs := c.nameInterface.NewModule( 1847*1fa6dee9SAndroid Build Coastguard Worker newNamespaceContext(module), 1848*1fa6dee9SAndroid Build Coastguard Worker ModuleGroup{moduleGroup: group}, 1849*1fa6dee9SAndroid Build Coastguard Worker module.logicModule) 1850*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1851*1fa6dee9SAndroid Build Coastguard Worker for i := range errs { 1852*1fa6dee9SAndroid Build Coastguard Worker errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos} 1853*1fa6dee9SAndroid Build Coastguard Worker } 1854*1fa6dee9SAndroid Build Coastguard Worker return errs 1855*1fa6dee9SAndroid Build Coastguard Worker } 1856*1fa6dee9SAndroid Build Coastguard Worker group.namespace = namespace 1857*1fa6dee9SAndroid Build Coastguard Worker 1858*1fa6dee9SAndroid Build Coastguard Worker c.moduleGroups = append(c.moduleGroups, group) 1859*1fa6dee9SAndroid Build Coastguard Worker 1860*1fa6dee9SAndroid Build Coastguard Worker return nil 1861*1fa6dee9SAndroid Build Coastguard Worker} 1862*1fa6dee9SAndroid Build Coastguard Worker 1863*1fa6dee9SAndroid Build Coastguard Worker// ResolveDependencies checks that the dependencies specified by all of the 1864*1fa6dee9SAndroid Build Coastguard Worker// modules defined in the parsed Blueprints files are valid. This means that 1865*1fa6dee9SAndroid Build Coastguard Worker// the modules depended upon are defined and that no circular dependencies 1866*1fa6dee9SAndroid Build Coastguard Worker// exist. 1867*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) { 1868*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("resolve_deps") 1869*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("resolve_deps") 1870*1fa6dee9SAndroid Build Coastguard Worker return c.resolveDependencies(c.Context, config) 1871*1fa6dee9SAndroid Build Coastguard Worker} 1872*1fa6dee9SAndroid Build Coastguard Worker 1873*1fa6dee9SAndroid Build Coastguard Worker// coalesceMutators takes the list of mutators and returns a list of lists of mutators, 1874*1fa6dee9SAndroid Build Coastguard Worker// where sublist is a compatible group of mutators that can be run with relaxed 1875*1fa6dee9SAndroid Build Coastguard Worker// intra-mutator ordering. 1876*1fa6dee9SAndroid Build Coastguard Workerfunc coalesceMutators(mutators []*mutatorInfo) [][]*mutatorInfo { 1877*1fa6dee9SAndroid Build Coastguard Worker var coalescedMutators [][]*mutatorInfo 1878*1fa6dee9SAndroid Build Coastguard Worker var last *mutatorInfo 1879*1fa6dee9SAndroid Build Coastguard Worker 1880*1fa6dee9SAndroid Build Coastguard Worker // Returns true if the mutator can be coalesced with other mutators that 1881*1fa6dee9SAndroid Build Coastguard Worker // also return true. 1882*1fa6dee9SAndroid Build Coastguard Worker coalescable := func(m *mutatorInfo) bool { 1883*1fa6dee9SAndroid Build Coastguard Worker return m.bottomUpMutator != nil && 1884*1fa6dee9SAndroid Build Coastguard Worker m.transitionMutator == nil && 1885*1fa6dee9SAndroid Build Coastguard Worker !m.usesCreateModule && 1886*1fa6dee9SAndroid Build Coastguard Worker !m.usesReplaceDependencies && 1887*1fa6dee9SAndroid Build Coastguard Worker !m.usesReverseDependencies && 1888*1fa6dee9SAndroid Build Coastguard Worker !m.usesRename && 1889*1fa6dee9SAndroid Build Coastguard Worker !m.mutatesGlobalState && 1890*1fa6dee9SAndroid Build Coastguard Worker !m.mutatesDependencies 1891*1fa6dee9SAndroid Build Coastguard Worker } 1892*1fa6dee9SAndroid Build Coastguard Worker 1893*1fa6dee9SAndroid Build Coastguard Worker for _, mutator := range mutators { 1894*1fa6dee9SAndroid Build Coastguard Worker if last != nil && coalescable(last) && coalescable(mutator) { 1895*1fa6dee9SAndroid Build Coastguard Worker lastGroup := &coalescedMutators[len(coalescedMutators)-1] 1896*1fa6dee9SAndroid Build Coastguard Worker *lastGroup = append(*lastGroup, mutator) 1897*1fa6dee9SAndroid Build Coastguard Worker } else { 1898*1fa6dee9SAndroid Build Coastguard Worker coalescedMutators = append(coalescedMutators, []*mutatorInfo{mutator}) 1899*1fa6dee9SAndroid Build Coastguard Worker last = mutator 1900*1fa6dee9SAndroid Build Coastguard Worker } 1901*1fa6dee9SAndroid Build Coastguard Worker } 1902*1fa6dee9SAndroid Build Coastguard Worker 1903*1fa6dee9SAndroid Build Coastguard Worker return coalescedMutators 1904*1fa6dee9SAndroid Build Coastguard Worker} 1905*1fa6dee9SAndroid Build Coastguard Worker 1906*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) { 1907*1fa6dee9SAndroid Build Coastguard Worker pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) { 1908*1fa6dee9SAndroid Build Coastguard Worker c.initProviders() 1909*1fa6dee9SAndroid Build Coastguard Worker 1910*1fa6dee9SAndroid Build Coastguard Worker errs = c.updateDependencies() 1911*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1912*1fa6dee9SAndroid Build Coastguard Worker return 1913*1fa6dee9SAndroid Build Coastguard Worker } 1914*1fa6dee9SAndroid Build Coastguard Worker 1915*1fa6dee9SAndroid Build Coastguard Worker mutatorGroups := coalesceMutators(c.mutatorInfo) 1916*1fa6dee9SAndroid Build Coastguard Worker 1917*1fa6dee9SAndroid Build Coastguard Worker deps, errs = c.runMutators(ctx, config, mutatorGroups) 1918*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1919*1fa6dee9SAndroid Build Coastguard Worker return 1920*1fa6dee9SAndroid Build Coastguard Worker } 1921*1fa6dee9SAndroid Build Coastguard Worker 1922*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("clone_modules") 1923*1fa6dee9SAndroid Build Coastguard Worker if !c.SkipCloneModulesAfterMutators { 1924*1fa6dee9SAndroid Build Coastguard Worker c.cloneModules() 1925*1fa6dee9SAndroid Build Coastguard Worker } 1926*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("clone_modules") 1927*1fa6dee9SAndroid Build Coastguard Worker 1928*1fa6dee9SAndroid Build Coastguard Worker c.clearTransitionMutatorInputVariants() 1929*1fa6dee9SAndroid Build Coastguard Worker 1930*1fa6dee9SAndroid Build Coastguard Worker c.dependenciesReady = true 1931*1fa6dee9SAndroid Build Coastguard Worker }) 1932*1fa6dee9SAndroid Build Coastguard Worker 1933*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1934*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 1935*1fa6dee9SAndroid Build Coastguard Worker } 1936*1fa6dee9SAndroid Build Coastguard Worker 1937*1fa6dee9SAndroid Build Coastguard Worker return deps, nil 1938*1fa6dee9SAndroid Build Coastguard Worker} 1939*1fa6dee9SAndroid Build Coastguard Worker 1940*1fa6dee9SAndroid Build Coastguard Worker// Default dependencies handling. If the module implements the (deprecated) 1941*1fa6dee9SAndroid Build Coastguard Worker// DynamicDependerModule interface then this set consists of the union of those 1942*1fa6dee9SAndroid Build Coastguard Worker// module names returned by its DynamicDependencies method and those added by calling 1943*1fa6dee9SAndroid Build Coastguard Worker// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext. 1944*1fa6dee9SAndroid Build Coastguard Workerfunc blueprintDepsMutator(ctx BottomUpMutatorContext) { 1945*1fa6dee9SAndroid Build Coastguard Worker if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok { 1946*1fa6dee9SAndroid Build Coastguard Worker func() { 1947*1fa6dee9SAndroid Build Coastguard Worker defer func() { 1948*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 1949*1fa6dee9SAndroid Build Coastguard Worker ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo())) 1950*1fa6dee9SAndroid Build Coastguard Worker } 1951*1fa6dee9SAndroid Build Coastguard Worker }() 1952*1fa6dee9SAndroid Build Coastguard Worker dynamicDeps := dynamicDepender.DynamicDependencies(ctx) 1953*1fa6dee9SAndroid Build Coastguard Worker 1954*1fa6dee9SAndroid Build Coastguard Worker if ctx.Failed() { 1955*1fa6dee9SAndroid Build Coastguard Worker return 1956*1fa6dee9SAndroid Build Coastguard Worker } 1957*1fa6dee9SAndroid Build Coastguard Worker 1958*1fa6dee9SAndroid Build Coastguard Worker ctx.AddDependency(ctx.Module(), nil, dynamicDeps...) 1959*1fa6dee9SAndroid Build Coastguard Worker }() 1960*1fa6dee9SAndroid Build Coastguard Worker } 1961*1fa6dee9SAndroid Build Coastguard Worker} 1962*1fa6dee9SAndroid Build Coastguard Worker 1963*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) findReverseDependency(module *moduleInfo, config any, requestedVariations []Variation, destName string) (*moduleInfo, []error) { 1964*1fa6dee9SAndroid Build Coastguard Worker if destName == module.Name() { 1965*1fa6dee9SAndroid Build Coastguard Worker return nil, []error{&BlueprintError{ 1966*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q depends on itself", destName), 1967*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 1968*1fa6dee9SAndroid Build Coastguard Worker }} 1969*1fa6dee9SAndroid Build Coastguard Worker } 1970*1fa6dee9SAndroid Build Coastguard Worker 1971*1fa6dee9SAndroid Build Coastguard Worker possibleDeps := c.moduleGroupFromName(destName, module.namespace()) 1972*1fa6dee9SAndroid Build Coastguard Worker if possibleDeps == nil { 1973*1fa6dee9SAndroid Build Coastguard Worker return nil, []error{&BlueprintError{ 1974*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q has a reverse dependency on undefined module %q", 1975*1fa6dee9SAndroid Build Coastguard Worker module.Name(), destName), 1976*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 1977*1fa6dee9SAndroid Build Coastguard Worker }} 1978*1fa6dee9SAndroid Build Coastguard Worker } 1979*1fa6dee9SAndroid Build Coastguard Worker 1980*1fa6dee9SAndroid Build Coastguard Worker if m, _, errs := c.findVariant(module, config, possibleDeps, requestedVariations, false, true); errs != nil { 1981*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 1982*1fa6dee9SAndroid Build Coastguard Worker } else if m != nil { 1983*1fa6dee9SAndroid Build Coastguard Worker return m, nil 1984*1fa6dee9SAndroid Build Coastguard Worker } 1985*1fa6dee9SAndroid Build Coastguard Worker 1986*1fa6dee9SAndroid Build Coastguard Worker if c.allowMissingDependencies { 1987*1fa6dee9SAndroid Build Coastguard Worker // Allow missing variants. 1988*1fa6dee9SAndroid Build Coastguard Worker return nil, c.discoveredMissingDependencies(module, destName, module.variant.variations) 1989*1fa6dee9SAndroid Build Coastguard Worker } 1990*1fa6dee9SAndroid Build Coastguard Worker 1991*1fa6dee9SAndroid Build Coastguard Worker return nil, []error{&BlueprintError{ 1992*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s", 1993*1fa6dee9SAndroid Build Coastguard Worker destName, module.Name(), 1994*1fa6dee9SAndroid Build Coastguard Worker c.prettyPrintVariant(module.variant.variations), 1995*1fa6dee9SAndroid Build Coastguard Worker c.prettyPrintGroupVariants(possibleDeps)), 1996*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 1997*1fa6dee9SAndroid Build Coastguard Worker }} 1998*1fa6dee9SAndroid Build Coastguard Worker} 1999*1fa6dee9SAndroid Build Coastguard Worker 2000*1fa6dee9SAndroid Build Coastguard Worker// applyTransitions takes a variationMap being used to add a dependency on a module in a moduleGroup 2001*1fa6dee9SAndroid Build Coastguard Worker// and applies the OutgoingTransition and IncomingTransition methods of each completed TransitionMutator to 2002*1fa6dee9SAndroid Build Coastguard Worker// modify the requested variation. It finds a variant that existed before the TransitionMutator ran that is 2003*1fa6dee9SAndroid Build Coastguard Worker// a subset of the requested variant to use as the module context for IncomingTransition. 2004*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) applyTransitions(config any, module *moduleInfo, group *moduleGroup, variant variationMap, 2005*1fa6dee9SAndroid Build Coastguard Worker requestedVariations []Variation) (variationMap, []error) { 2006*1fa6dee9SAndroid Build Coastguard Worker for _, transitionMutator := range c.transitionMutators { 2007*1fa6dee9SAndroid Build Coastguard Worker explicitlyRequested := slices.ContainsFunc(requestedVariations, func(variation Variation) bool { 2008*1fa6dee9SAndroid Build Coastguard Worker return variation.Mutator == transitionMutator.name 2009*1fa6dee9SAndroid Build Coastguard Worker }) 2010*1fa6dee9SAndroid Build Coastguard Worker 2011*1fa6dee9SAndroid Build Coastguard Worker sourceVariation := variant.get(transitionMutator.name) 2012*1fa6dee9SAndroid Build Coastguard Worker outgoingVariation := sourceVariation 2013*1fa6dee9SAndroid Build Coastguard Worker 2014*1fa6dee9SAndroid Build Coastguard Worker // Apply the outgoing transition if it was not explicitly requested. 2015*1fa6dee9SAndroid Build Coastguard Worker if !explicitlyRequested { 2016*1fa6dee9SAndroid Build Coastguard Worker ctx := &outgoingTransitionContextImpl{ 2017*1fa6dee9SAndroid Build Coastguard Worker transitionContextImpl{context: c, source: module, dep: nil, 2018*1fa6dee9SAndroid Build Coastguard Worker depTag: nil, postMutator: true, config: config}, 2019*1fa6dee9SAndroid Build Coastguard Worker } 2020*1fa6dee9SAndroid Build Coastguard Worker outgoingVariation = transitionMutator.mutator.OutgoingTransition(ctx, sourceVariation) 2021*1fa6dee9SAndroid Build Coastguard Worker if len(ctx.errs) > 0 { 2022*1fa6dee9SAndroid Build Coastguard Worker return variationMap{}, ctx.errs 2023*1fa6dee9SAndroid Build Coastguard Worker } 2024*1fa6dee9SAndroid Build Coastguard Worker } 2025*1fa6dee9SAndroid Build Coastguard Worker 2026*1fa6dee9SAndroid Build Coastguard Worker earlierVariantCreatingMutators := c.variantCreatingMutatorOrder[:transitionMutator.variantCreatingMutatorIndex] 2027*1fa6dee9SAndroid Build Coastguard Worker filteredVariant := variant.cloneMatching(earlierVariantCreatingMutators) 2028*1fa6dee9SAndroid Build Coastguard Worker 2029*1fa6dee9SAndroid Build Coastguard Worker check := func(inputVariant variationMap) bool { 2030*1fa6dee9SAndroid Build Coastguard Worker filteredInputVariant := inputVariant.cloneMatching(earlierVariantCreatingMutators) 2031*1fa6dee9SAndroid Build Coastguard Worker return filteredInputVariant.equal(filteredVariant) 2032*1fa6dee9SAndroid Build Coastguard Worker } 2033*1fa6dee9SAndroid Build Coastguard Worker 2034*1fa6dee9SAndroid Build Coastguard Worker // Find an appropriate module to use as the context for the IncomingTransition. First check if any of the 2035*1fa6dee9SAndroid Build Coastguard Worker // saved inputVariants for the transition mutator match the filtered variant. 2036*1fa6dee9SAndroid Build Coastguard Worker var matchingInputVariant *moduleInfo 2037*1fa6dee9SAndroid Build Coastguard Worker for _, inputVariant := range transitionMutator.inputVariants[group] { 2038*1fa6dee9SAndroid Build Coastguard Worker if check(inputVariant.variant.variations) { 2039*1fa6dee9SAndroid Build Coastguard Worker matchingInputVariant = inputVariant 2040*1fa6dee9SAndroid Build Coastguard Worker break 2041*1fa6dee9SAndroid Build Coastguard Worker } 2042*1fa6dee9SAndroid Build Coastguard Worker } 2043*1fa6dee9SAndroid Build Coastguard Worker 2044*1fa6dee9SAndroid Build Coastguard Worker if matchingInputVariant == nil { 2045*1fa6dee9SAndroid Build Coastguard Worker // If no inputVariants match, check all the variants of the module for a match. This can happen if 2046*1fa6dee9SAndroid Build Coastguard Worker // the mutator only created a single "" variant when it ran on this module. Matching against all variants 2047*1fa6dee9SAndroid Build Coastguard Worker // is slightly worse than checking the input variants, as the selected variant could have been modified 2048*1fa6dee9SAndroid Build Coastguard Worker // by a later mutator in a way that affects the results of IncomingTransition. 2049*1fa6dee9SAndroid Build Coastguard Worker for _, module := range group.modules { 2050*1fa6dee9SAndroid Build Coastguard Worker if check(module.variant.variations) { 2051*1fa6dee9SAndroid Build Coastguard Worker matchingInputVariant = module 2052*1fa6dee9SAndroid Build Coastguard Worker break 2053*1fa6dee9SAndroid Build Coastguard Worker } 2054*1fa6dee9SAndroid Build Coastguard Worker } 2055*1fa6dee9SAndroid Build Coastguard Worker } 2056*1fa6dee9SAndroid Build Coastguard Worker 2057*1fa6dee9SAndroid Build Coastguard Worker if matchingInputVariant != nil { 2058*1fa6dee9SAndroid Build Coastguard Worker // Apply the incoming transition. 2059*1fa6dee9SAndroid Build Coastguard Worker ctx := &incomingTransitionContextImpl{ 2060*1fa6dee9SAndroid Build Coastguard Worker transitionContextImpl{context: c, source: nil, dep: matchingInputVariant, 2061*1fa6dee9SAndroid Build Coastguard Worker depTag: nil, postMutator: true, config: config}, 2062*1fa6dee9SAndroid Build Coastguard Worker } 2063*1fa6dee9SAndroid Build Coastguard Worker 2064*1fa6dee9SAndroid Build Coastguard Worker finalVariation := transitionMutator.mutator.IncomingTransition(ctx, outgoingVariation) 2065*1fa6dee9SAndroid Build Coastguard Worker if len(ctx.errs) > 0 { 2066*1fa6dee9SAndroid Build Coastguard Worker return variationMap{}, ctx.errs 2067*1fa6dee9SAndroid Build Coastguard Worker } 2068*1fa6dee9SAndroid Build Coastguard Worker variant.set(transitionMutator.name, finalVariation) 2069*1fa6dee9SAndroid Build Coastguard Worker } 2070*1fa6dee9SAndroid Build Coastguard Worker 2071*1fa6dee9SAndroid Build Coastguard Worker if (matchingInputVariant == nil && !explicitlyRequested) || variant.get(transitionMutator.name) == "" { 2072*1fa6dee9SAndroid Build Coastguard Worker // The transition mutator didn't apply anything to the target variant, remove the variation unless it 2073*1fa6dee9SAndroid Build Coastguard Worker // was explicitly requested when adding the dependency. 2074*1fa6dee9SAndroid Build Coastguard Worker variant.delete(transitionMutator.name) 2075*1fa6dee9SAndroid Build Coastguard Worker } 2076*1fa6dee9SAndroid Build Coastguard Worker } 2077*1fa6dee9SAndroid Build Coastguard Worker 2078*1fa6dee9SAndroid Build Coastguard Worker return variant, nil 2079*1fa6dee9SAndroid Build Coastguard Worker} 2080*1fa6dee9SAndroid Build Coastguard Worker 2081*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) findVariant(module *moduleInfo, config any, 2082*1fa6dee9SAndroid Build Coastguard Worker possibleDeps *moduleGroup, requestedVariations []Variation, far bool, reverse bool) (*moduleInfo, variationMap, []error) { 2083*1fa6dee9SAndroid Build Coastguard Worker 2084*1fa6dee9SAndroid Build Coastguard Worker // We can't just append variant.Variant to module.dependencyVariant.variantName and 2085*1fa6dee9SAndroid Build Coastguard Worker // compare the strings because the result won't be in mutator registration order. 2086*1fa6dee9SAndroid Build Coastguard Worker // Create a new map instead, and then deep compare the maps. 2087*1fa6dee9SAndroid Build Coastguard Worker var newVariant variationMap 2088*1fa6dee9SAndroid Build Coastguard Worker if !far { 2089*1fa6dee9SAndroid Build Coastguard Worker newVariant = module.variant.variations.clone() 2090*1fa6dee9SAndroid Build Coastguard Worker } else { 2091*1fa6dee9SAndroid Build Coastguard Worker for _, mutator := range c.mutatorInfo { 2092*1fa6dee9SAndroid Build Coastguard Worker if mutator.neverFar { 2093*1fa6dee9SAndroid Build Coastguard Worker newVariant.set(mutator.name, module.variant.variations.get(mutator.name)) 2094*1fa6dee9SAndroid Build Coastguard Worker } 2095*1fa6dee9SAndroid Build Coastguard Worker } 2096*1fa6dee9SAndroid Build Coastguard Worker } 2097*1fa6dee9SAndroid Build Coastguard Worker for _, v := range requestedVariations { 2098*1fa6dee9SAndroid Build Coastguard Worker newVariant.set(v.Mutator, v.Variation) 2099*1fa6dee9SAndroid Build Coastguard Worker } 2100*1fa6dee9SAndroid Build Coastguard Worker 2101*1fa6dee9SAndroid Build Coastguard Worker if !reverse { 2102*1fa6dee9SAndroid Build Coastguard Worker var errs []error 2103*1fa6dee9SAndroid Build Coastguard Worker newVariant, errs = c.applyTransitions(config, module, possibleDeps, newVariant, requestedVariations) 2104*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 2105*1fa6dee9SAndroid Build Coastguard Worker return nil, variationMap{}, errs 2106*1fa6dee9SAndroid Build Coastguard Worker } 2107*1fa6dee9SAndroid Build Coastguard Worker } 2108*1fa6dee9SAndroid Build Coastguard Worker 2109*1fa6dee9SAndroid Build Coastguard Worker // check returns a bool for whether the requested newVariant matches the given variant from possibleDeps, and a 2110*1fa6dee9SAndroid Build Coastguard Worker // divergence score. A score of 0 is best match, and a positive integer is a worse match. 2111*1fa6dee9SAndroid Build Coastguard Worker // For a non-far search, the score is always 0 as the match must always be exact. For a far search, 2112*1fa6dee9SAndroid Build Coastguard Worker // the score is the number of variants that are present in the given variant but not newVariant. 2113*1fa6dee9SAndroid Build Coastguard Worker check := func(variant variationMap) (bool, int) { 2114*1fa6dee9SAndroid Build Coastguard Worker if far { 2115*1fa6dee9SAndroid Build Coastguard Worker if newVariant.subsetOf(variant) { 2116*1fa6dee9SAndroid Build Coastguard Worker return true, variant.differenceKeysCount(newVariant) 2117*1fa6dee9SAndroid Build Coastguard Worker } 2118*1fa6dee9SAndroid Build Coastguard Worker } else { 2119*1fa6dee9SAndroid Build Coastguard Worker if variant.equal(newVariant) { 2120*1fa6dee9SAndroid Build Coastguard Worker return true, 0 2121*1fa6dee9SAndroid Build Coastguard Worker } 2122*1fa6dee9SAndroid Build Coastguard Worker } 2123*1fa6dee9SAndroid Build Coastguard Worker return false, math.MaxInt 2124*1fa6dee9SAndroid Build Coastguard Worker } 2125*1fa6dee9SAndroid Build Coastguard Worker 2126*1fa6dee9SAndroid Build Coastguard Worker var foundDep *moduleInfo 2127*1fa6dee9SAndroid Build Coastguard Worker bestDivergence := math.MaxInt 2128*1fa6dee9SAndroid Build Coastguard Worker for _, m := range possibleDeps.modules { 2129*1fa6dee9SAndroid Build Coastguard Worker if match, divergence := check(m.variant.variations); match && divergence < bestDivergence { 2130*1fa6dee9SAndroid Build Coastguard Worker foundDep = m 2131*1fa6dee9SAndroid Build Coastguard Worker bestDivergence = divergence 2132*1fa6dee9SAndroid Build Coastguard Worker if !far { 2133*1fa6dee9SAndroid Build Coastguard Worker // non-far dependencies use equality, so only the first match needs to be checked. 2134*1fa6dee9SAndroid Build Coastguard Worker break 2135*1fa6dee9SAndroid Build Coastguard Worker } 2136*1fa6dee9SAndroid Build Coastguard Worker } 2137*1fa6dee9SAndroid Build Coastguard Worker } 2138*1fa6dee9SAndroid Build Coastguard Worker 2139*1fa6dee9SAndroid Build Coastguard Worker return foundDep, newVariant, nil 2140*1fa6dee9SAndroid Build Coastguard Worker} 2141*1fa6dee9SAndroid Build Coastguard Worker 2142*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) addVariationDependency(module *moduleInfo, mutator *mutatorInfo, config any, variations []Variation, 2143*1fa6dee9SAndroid Build Coastguard Worker tag DependencyTag, depName string, far bool) (*moduleInfo, []error) { 2144*1fa6dee9SAndroid Build Coastguard Worker if _, ok := tag.(BaseDependencyTag); ok { 2145*1fa6dee9SAndroid Build Coastguard Worker panic("BaseDependencyTag is not allowed to be used directly!") 2146*1fa6dee9SAndroid Build Coastguard Worker } 2147*1fa6dee9SAndroid Build Coastguard Worker 2148*1fa6dee9SAndroid Build Coastguard Worker possibleDeps := c.moduleGroupFromName(depName, module.namespace()) 2149*1fa6dee9SAndroid Build Coastguard Worker if possibleDeps == nil { 2150*1fa6dee9SAndroid Build Coastguard Worker return nil, c.discoveredMissingDependencies(module, depName, variationMap{}) 2151*1fa6dee9SAndroid Build Coastguard Worker } 2152*1fa6dee9SAndroid Build Coastguard Worker 2153*1fa6dee9SAndroid Build Coastguard Worker foundDep, newVariant, errs := c.findVariant(module, config, possibleDeps, variations, far, false) 2154*1fa6dee9SAndroid Build Coastguard Worker if errs != nil { 2155*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 2156*1fa6dee9SAndroid Build Coastguard Worker } 2157*1fa6dee9SAndroid Build Coastguard Worker 2158*1fa6dee9SAndroid Build Coastguard Worker if foundDep == nil { 2159*1fa6dee9SAndroid Build Coastguard Worker if c.allowMissingDependencies { 2160*1fa6dee9SAndroid Build Coastguard Worker // Allow missing variants. 2161*1fa6dee9SAndroid Build Coastguard Worker return nil, c.discoveredMissingDependencies(module, depName, newVariant) 2162*1fa6dee9SAndroid Build Coastguard Worker } 2163*1fa6dee9SAndroid Build Coastguard Worker return nil, []error{&BlueprintError{ 2164*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s", 2165*1fa6dee9SAndroid Build Coastguard Worker depName, module.Name(), 2166*1fa6dee9SAndroid Build Coastguard Worker c.prettyPrintVariant(newVariant), 2167*1fa6dee9SAndroid Build Coastguard Worker c.prettyPrintGroupVariants(possibleDeps)), 2168*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 2169*1fa6dee9SAndroid Build Coastguard Worker }} 2170*1fa6dee9SAndroid Build Coastguard Worker } 2171*1fa6dee9SAndroid Build Coastguard Worker 2172*1fa6dee9SAndroid Build Coastguard Worker if module == foundDep { 2173*1fa6dee9SAndroid Build Coastguard Worker return nil, []error{&BlueprintError{ 2174*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q depends on itself", depName), 2175*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 2176*1fa6dee9SAndroid Build Coastguard Worker }} 2177*1fa6dee9SAndroid Build Coastguard Worker } 2178*1fa6dee9SAndroid Build Coastguard Worker // AddVariationDependency allows adding a dependency on itself, but only if 2179*1fa6dee9SAndroid Build Coastguard Worker // that module is earlier in the module list than this one, since we always 2180*1fa6dee9SAndroid Build Coastguard Worker // run GenerateBuildActions in order for the variants of a module 2181*1fa6dee9SAndroid Build Coastguard Worker if foundDep.group == module.group && beforeInModuleList(module, foundDep, module.group.modules) { 2182*1fa6dee9SAndroid Build Coastguard Worker return nil, []error{&BlueprintError{ 2183*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("%q depends on later version of itself", depName), 2184*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 2185*1fa6dee9SAndroid Build Coastguard Worker }} 2186*1fa6dee9SAndroid Build Coastguard Worker } 2187*1fa6dee9SAndroid Build Coastguard Worker 2188*1fa6dee9SAndroid Build Coastguard Worker // The mutator will pause until the newly added dependency has finished running the current mutator, 2189*1fa6dee9SAndroid Build Coastguard Worker // so it is safe to add the new dependency directly to directDeps and forwardDeps where it will be visible 2190*1fa6dee9SAndroid Build Coastguard Worker // to future calls to VisitDirectDeps. Set newDirectDeps so that at the end of the mutator the reverseDeps 2191*1fa6dee9SAndroid Build Coastguard Worker // of the dependencies can be updated to point to this module without running a full c.updateDependencies() 2192*1fa6dee9SAndroid Build Coastguard Worker module.directDeps = append(module.directDeps, depInfo{foundDep, tag}) 2193*1fa6dee9SAndroid Build Coastguard Worker module.forwardDeps = append(module.forwardDeps, foundDep) 2194*1fa6dee9SAndroid Build Coastguard Worker module.newDirectDeps = append(module.newDirectDeps, foundDep) 2195*1fa6dee9SAndroid Build Coastguard Worker return foundDep, nil 2196*1fa6dee9SAndroid Build Coastguard Worker} 2197*1fa6dee9SAndroid Build Coastguard Worker 2198*1fa6dee9SAndroid Build Coastguard Worker// findBlueprintDescendants returns a map linking parent Blueprint files to child Blueprints files 2199*1fa6dee9SAndroid Build Coastguard Worker// For example, if paths = []string{"a/b/c/Android.bp", "a/Android.bp"}, 2200*1fa6dee9SAndroid Build Coastguard Worker// then descendants = {"":[]string{"a/Android.bp"}, "a/Android.bp":[]string{"a/b/c/Android.bp"}} 2201*1fa6dee9SAndroid Build Coastguard Workerfunc findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) { 2202*1fa6dee9SAndroid Build Coastguard Worker // make mapping from dir path to file path 2203*1fa6dee9SAndroid Build Coastguard Worker filesByDir := make(map[string]string, len(paths)) 2204*1fa6dee9SAndroid Build Coastguard Worker for _, path := range paths { 2205*1fa6dee9SAndroid Build Coastguard Worker dir := filepath.Dir(path) 2206*1fa6dee9SAndroid Build Coastguard Worker _, alreadyFound := filesByDir[dir] 2207*1fa6dee9SAndroid Build Coastguard Worker if alreadyFound { 2208*1fa6dee9SAndroid Build Coastguard Worker return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path) 2209*1fa6dee9SAndroid Build Coastguard Worker } 2210*1fa6dee9SAndroid Build Coastguard Worker filesByDir[dir] = path 2211*1fa6dee9SAndroid Build Coastguard Worker } 2212*1fa6dee9SAndroid Build Coastguard Worker 2213*1fa6dee9SAndroid Build Coastguard Worker findAncestor := func(childFile string) (ancestor string) { 2214*1fa6dee9SAndroid Build Coastguard Worker prevAncestorDir := filepath.Dir(childFile) 2215*1fa6dee9SAndroid Build Coastguard Worker for { 2216*1fa6dee9SAndroid Build Coastguard Worker ancestorDir := filepath.Dir(prevAncestorDir) 2217*1fa6dee9SAndroid Build Coastguard Worker if ancestorDir == prevAncestorDir { 2218*1fa6dee9SAndroid Build Coastguard Worker // reached the root dir without any matches; assign this as a descendant of "" 2219*1fa6dee9SAndroid Build Coastguard Worker return "" 2220*1fa6dee9SAndroid Build Coastguard Worker } 2221*1fa6dee9SAndroid Build Coastguard Worker 2222*1fa6dee9SAndroid Build Coastguard Worker ancestorFile, ancestorExists := filesByDir[ancestorDir] 2223*1fa6dee9SAndroid Build Coastguard Worker if ancestorExists { 2224*1fa6dee9SAndroid Build Coastguard Worker return ancestorFile 2225*1fa6dee9SAndroid Build Coastguard Worker } 2226*1fa6dee9SAndroid Build Coastguard Worker prevAncestorDir = ancestorDir 2227*1fa6dee9SAndroid Build Coastguard Worker } 2228*1fa6dee9SAndroid Build Coastguard Worker } 2229*1fa6dee9SAndroid Build Coastguard Worker // generate the descendants map 2230*1fa6dee9SAndroid Build Coastguard Worker descendants = make(map[string][]string, len(filesByDir)) 2231*1fa6dee9SAndroid Build Coastguard Worker for _, childFile := range filesByDir { 2232*1fa6dee9SAndroid Build Coastguard Worker ancestorFile := findAncestor(childFile) 2233*1fa6dee9SAndroid Build Coastguard Worker descendants[ancestorFile] = append(descendants[ancestorFile], childFile) 2234*1fa6dee9SAndroid Build Coastguard Worker } 2235*1fa6dee9SAndroid Build Coastguard Worker return descendants, nil 2236*1fa6dee9SAndroid Build Coastguard Worker} 2237*1fa6dee9SAndroid Build Coastguard Worker 2238*1fa6dee9SAndroid Build Coastguard Workertype visitOrderer interface { 2239*1fa6dee9SAndroid Build Coastguard Worker // returns the number of modules that this module needs to wait for 2240*1fa6dee9SAndroid Build Coastguard Worker waitCount(module *moduleInfo) int 2241*1fa6dee9SAndroid Build Coastguard Worker // returns the list of modules that are waiting for this module 2242*1fa6dee9SAndroid Build Coastguard Worker propagate(module *moduleInfo) []*moduleInfo 2243*1fa6dee9SAndroid Build Coastguard Worker} 2244*1fa6dee9SAndroid Build Coastguard Worker 2245*1fa6dee9SAndroid Build Coastguard Workertype unorderedVisitorImpl struct{} 2246*1fa6dee9SAndroid Build Coastguard Worker 2247*1fa6dee9SAndroid Build Coastguard Workerfunc (unorderedVisitorImpl) waitCount(module *moduleInfo) int { 2248*1fa6dee9SAndroid Build Coastguard Worker return 0 2249*1fa6dee9SAndroid Build Coastguard Worker} 2250*1fa6dee9SAndroid Build Coastguard Worker 2251*1fa6dee9SAndroid Build Coastguard Workerfunc (unorderedVisitorImpl) propagate(module *moduleInfo) []*moduleInfo { 2252*1fa6dee9SAndroid Build Coastguard Worker return nil 2253*1fa6dee9SAndroid Build Coastguard Worker} 2254*1fa6dee9SAndroid Build Coastguard Worker 2255*1fa6dee9SAndroid Build Coastguard Workertype bottomUpVisitorImpl struct{} 2256*1fa6dee9SAndroid Build Coastguard Worker 2257*1fa6dee9SAndroid Build Coastguard Workerfunc (bottomUpVisitorImpl) waitCount(module *moduleInfo) int { 2258*1fa6dee9SAndroid Build Coastguard Worker return len(module.forwardDeps) 2259*1fa6dee9SAndroid Build Coastguard Worker} 2260*1fa6dee9SAndroid Build Coastguard Worker 2261*1fa6dee9SAndroid Build Coastguard Workerfunc (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo { 2262*1fa6dee9SAndroid Build Coastguard Worker return module.reverseDeps 2263*1fa6dee9SAndroid Build Coastguard Worker} 2264*1fa6dee9SAndroid Build Coastguard Worker 2265*1fa6dee9SAndroid Build Coastguard Workertype topDownVisitorImpl struct{} 2266*1fa6dee9SAndroid Build Coastguard Worker 2267*1fa6dee9SAndroid Build Coastguard Workerfunc (topDownVisitorImpl) waitCount(module *moduleInfo) int { 2268*1fa6dee9SAndroid Build Coastguard Worker return len(module.reverseDeps) 2269*1fa6dee9SAndroid Build Coastguard Worker} 2270*1fa6dee9SAndroid Build Coastguard Worker 2271*1fa6dee9SAndroid Build Coastguard Workerfunc (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo { 2272*1fa6dee9SAndroid Build Coastguard Worker return module.forwardDeps 2273*1fa6dee9SAndroid Build Coastguard Worker} 2274*1fa6dee9SAndroid Build Coastguard Worker 2275*1fa6dee9SAndroid Build Coastguard Workerfunc (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) { 2276*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < len(modules); i++ { 2277*1fa6dee9SAndroid Build Coastguard Worker module := modules[len(modules)-1-i] 2278*1fa6dee9SAndroid Build Coastguard Worker if visit(module, nil) { 2279*1fa6dee9SAndroid Build Coastguard Worker return 2280*1fa6dee9SAndroid Build Coastguard Worker } 2281*1fa6dee9SAndroid Build Coastguard Worker } 2282*1fa6dee9SAndroid Build Coastguard Worker} 2283*1fa6dee9SAndroid Build Coastguard Worker 2284*1fa6dee9SAndroid Build Coastguard Workervar ( 2285*1fa6dee9SAndroid Build Coastguard Worker bottomUpVisitor bottomUpVisitorImpl 2286*1fa6dee9SAndroid Build Coastguard Worker topDownVisitor topDownVisitorImpl 2287*1fa6dee9SAndroid Build Coastguard Worker) 2288*1fa6dee9SAndroid Build Coastguard Worker 2289*1fa6dee9SAndroid Build Coastguard Worker// pauseSpec describes a pause that a module needs to occur until another module has been visited, 2290*1fa6dee9SAndroid Build Coastguard Worker// at which point the unpause channel will be closed. 2291*1fa6dee9SAndroid Build Coastguard Workertype pauseSpec struct { 2292*1fa6dee9SAndroid Build Coastguard Worker paused *moduleInfo 2293*1fa6dee9SAndroid Build Coastguard Worker until *moduleInfo 2294*1fa6dee9SAndroid Build Coastguard Worker unpause unpause 2295*1fa6dee9SAndroid Build Coastguard Worker} 2296*1fa6dee9SAndroid Build Coastguard Worker 2297*1fa6dee9SAndroid Build Coastguard Workertype unpause chan struct{} 2298*1fa6dee9SAndroid Build Coastguard Worker 2299*1fa6dee9SAndroid Build Coastguard Workerconst parallelVisitLimit = 1000 2300*1fa6dee9SAndroid Build Coastguard Worker 2301*1fa6dee9SAndroid Build Coastguard Worker// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all 2302*1fa6dee9SAndroid Build Coastguard Worker// of its dependencies has finished. A visit function can write a pauseSpec to the pause channel 2303*1fa6dee9SAndroid Build Coastguard Worker// to wait for another dependency to be visited. If a visit function returns true to cancel 2304*1fa6dee9SAndroid Build Coastguard Worker// while another visitor is paused, the paused visitor will never be resumed and its goroutine 2305*1fa6dee9SAndroid Build Coastguard Worker// will stay paused forever. 2306*1fa6dee9SAndroid Build Coastguard Workerfunc parallelVisit(moduleIter iter.Seq[*moduleInfo], order visitOrderer, limit int, 2307*1fa6dee9SAndroid Build Coastguard Worker visit func(module *moduleInfo, pause chan<- pauseSpec) bool) []error { 2308*1fa6dee9SAndroid Build Coastguard Worker 2309*1fa6dee9SAndroid Build Coastguard Worker doneCh := make(chan *moduleInfo) 2310*1fa6dee9SAndroid Build Coastguard Worker cancelCh := make(chan bool) 2311*1fa6dee9SAndroid Build Coastguard Worker pauseCh := make(chan pauseSpec) 2312*1fa6dee9SAndroid Build Coastguard Worker cancel := false 2313*1fa6dee9SAndroid Build Coastguard Worker 2314*1fa6dee9SAndroid Build Coastguard Worker var backlog []*moduleInfo // Visitors that are ready to start but backlogged due to limit. 2315*1fa6dee9SAndroid Build Coastguard Worker var unpauseBacklog []pauseSpec // Visitors that are ready to unpause but backlogged due to limit. 2316*1fa6dee9SAndroid Build Coastguard Worker 2317*1fa6dee9SAndroid Build Coastguard Worker active := 0 // Number of visitors running, not counting paused visitors. 2318*1fa6dee9SAndroid Build Coastguard Worker visited := 0 // Number of finished visitors. 2319*1fa6dee9SAndroid Build Coastguard Worker 2320*1fa6dee9SAndroid Build Coastguard Worker pauseMap := make(map[*moduleInfo][]pauseSpec) 2321*1fa6dee9SAndroid Build Coastguard Worker 2322*1fa6dee9SAndroid Build Coastguard Worker for module := range moduleIter { 2323*1fa6dee9SAndroid Build Coastguard Worker module.waitingCount = order.waitCount(module) 2324*1fa6dee9SAndroid Build Coastguard Worker } 2325*1fa6dee9SAndroid Build Coastguard Worker 2326*1fa6dee9SAndroid Build Coastguard Worker // Call the visitor on a module if there are fewer active visitors than the parallelism 2327*1fa6dee9SAndroid Build Coastguard Worker // limit, otherwise add it to the backlog. 2328*1fa6dee9SAndroid Build Coastguard Worker startOrBacklog := func(module *moduleInfo) { 2329*1fa6dee9SAndroid Build Coastguard Worker if active < limit { 2330*1fa6dee9SAndroid Build Coastguard Worker active++ 2331*1fa6dee9SAndroid Build Coastguard Worker go func() { 2332*1fa6dee9SAndroid Build Coastguard Worker ret := visit(module, pauseCh) 2333*1fa6dee9SAndroid Build Coastguard Worker if ret { 2334*1fa6dee9SAndroid Build Coastguard Worker cancelCh <- true 2335*1fa6dee9SAndroid Build Coastguard Worker } 2336*1fa6dee9SAndroid Build Coastguard Worker doneCh <- module 2337*1fa6dee9SAndroid Build Coastguard Worker }() 2338*1fa6dee9SAndroid Build Coastguard Worker } else { 2339*1fa6dee9SAndroid Build Coastguard Worker backlog = append(backlog, module) 2340*1fa6dee9SAndroid Build Coastguard Worker } 2341*1fa6dee9SAndroid Build Coastguard Worker } 2342*1fa6dee9SAndroid Build Coastguard Worker 2343*1fa6dee9SAndroid Build Coastguard Worker // Unpause the already-started but paused visitor on a module if there are fewer active 2344*1fa6dee9SAndroid Build Coastguard Worker // visitors than the parallelism limit, otherwise add it to the backlog. 2345*1fa6dee9SAndroid Build Coastguard Worker unpauseOrBacklog := func(pauseSpec pauseSpec) { 2346*1fa6dee9SAndroid Build Coastguard Worker if active < limit { 2347*1fa6dee9SAndroid Build Coastguard Worker active++ 2348*1fa6dee9SAndroid Build Coastguard Worker close(pauseSpec.unpause) 2349*1fa6dee9SAndroid Build Coastguard Worker } else { 2350*1fa6dee9SAndroid Build Coastguard Worker unpauseBacklog = append(unpauseBacklog, pauseSpec) 2351*1fa6dee9SAndroid Build Coastguard Worker } 2352*1fa6dee9SAndroid Build Coastguard Worker } 2353*1fa6dee9SAndroid Build Coastguard Worker 2354*1fa6dee9SAndroid Build Coastguard Worker // Start any modules in the backlog up to the parallelism limit. Unpause paused modules first 2355*1fa6dee9SAndroid Build Coastguard Worker // since they may already be holding resources. 2356*1fa6dee9SAndroid Build Coastguard Worker unpauseOrStartFromBacklog := func() { 2357*1fa6dee9SAndroid Build Coastguard Worker for active < limit && len(unpauseBacklog) > 0 { 2358*1fa6dee9SAndroid Build Coastguard Worker unpause := unpauseBacklog[0] 2359*1fa6dee9SAndroid Build Coastguard Worker unpauseBacklog = unpauseBacklog[1:] 2360*1fa6dee9SAndroid Build Coastguard Worker unpauseOrBacklog(unpause) 2361*1fa6dee9SAndroid Build Coastguard Worker } 2362*1fa6dee9SAndroid Build Coastguard Worker for active < limit && len(backlog) > 0 { 2363*1fa6dee9SAndroid Build Coastguard Worker toVisit := backlog[0] 2364*1fa6dee9SAndroid Build Coastguard Worker backlog = backlog[1:] 2365*1fa6dee9SAndroid Build Coastguard Worker startOrBacklog(toVisit) 2366*1fa6dee9SAndroid Build Coastguard Worker } 2367*1fa6dee9SAndroid Build Coastguard Worker } 2368*1fa6dee9SAndroid Build Coastguard Worker 2369*1fa6dee9SAndroid Build Coastguard Worker toVisit := 0 2370*1fa6dee9SAndroid Build Coastguard Worker 2371*1fa6dee9SAndroid Build Coastguard Worker // Start or backlog any modules that are not waiting for any other modules. 2372*1fa6dee9SAndroid Build Coastguard Worker for module := range moduleIter { 2373*1fa6dee9SAndroid Build Coastguard Worker toVisit++ 2374*1fa6dee9SAndroid Build Coastguard Worker if module.waitingCount == 0 { 2375*1fa6dee9SAndroid Build Coastguard Worker startOrBacklog(module) 2376*1fa6dee9SAndroid Build Coastguard Worker } 2377*1fa6dee9SAndroid Build Coastguard Worker } 2378*1fa6dee9SAndroid Build Coastguard Worker 2379*1fa6dee9SAndroid Build Coastguard Worker for active > 0 { 2380*1fa6dee9SAndroid Build Coastguard Worker select { 2381*1fa6dee9SAndroid Build Coastguard Worker case <-cancelCh: 2382*1fa6dee9SAndroid Build Coastguard Worker cancel = true 2383*1fa6dee9SAndroid Build Coastguard Worker backlog = nil 2384*1fa6dee9SAndroid Build Coastguard Worker case doneModule := <-doneCh: 2385*1fa6dee9SAndroid Build Coastguard Worker active-- 2386*1fa6dee9SAndroid Build Coastguard Worker if !cancel { 2387*1fa6dee9SAndroid Build Coastguard Worker // Mark this module as done. 2388*1fa6dee9SAndroid Build Coastguard Worker doneModule.waitingCount = -1 2389*1fa6dee9SAndroid Build Coastguard Worker visited++ 2390*1fa6dee9SAndroid Build Coastguard Worker 2391*1fa6dee9SAndroid Build Coastguard Worker // Unpause or backlog any modules that were waiting for this one. 2392*1fa6dee9SAndroid Build Coastguard Worker if unpauses, ok := pauseMap[doneModule]; ok { 2393*1fa6dee9SAndroid Build Coastguard Worker delete(pauseMap, doneModule) 2394*1fa6dee9SAndroid Build Coastguard Worker for _, unpause := range unpauses { 2395*1fa6dee9SAndroid Build Coastguard Worker unpauseOrBacklog(unpause) 2396*1fa6dee9SAndroid Build Coastguard Worker } 2397*1fa6dee9SAndroid Build Coastguard Worker } 2398*1fa6dee9SAndroid Build Coastguard Worker 2399*1fa6dee9SAndroid Build Coastguard Worker // Start any backlogged modules up to limit. 2400*1fa6dee9SAndroid Build Coastguard Worker unpauseOrStartFromBacklog() 2401*1fa6dee9SAndroid Build Coastguard Worker 2402*1fa6dee9SAndroid Build Coastguard Worker // Decrement waitingCount on the next modules in the tree based 2403*1fa6dee9SAndroid Build Coastguard Worker // on propagation order, and start or backlog them if they are 2404*1fa6dee9SAndroid Build Coastguard Worker // ready to start. 2405*1fa6dee9SAndroid Build Coastguard Worker for _, module := range order.propagate(doneModule) { 2406*1fa6dee9SAndroid Build Coastguard Worker module.waitingCount-- 2407*1fa6dee9SAndroid Build Coastguard Worker if module.waitingCount == 0 { 2408*1fa6dee9SAndroid Build Coastguard Worker startOrBacklog(module) 2409*1fa6dee9SAndroid Build Coastguard Worker } 2410*1fa6dee9SAndroid Build Coastguard Worker } 2411*1fa6dee9SAndroid Build Coastguard Worker } 2412*1fa6dee9SAndroid Build Coastguard Worker case pauseSpec := <-pauseCh: 2413*1fa6dee9SAndroid Build Coastguard Worker if pauseSpec.until.waitingCount == -1 { 2414*1fa6dee9SAndroid Build Coastguard Worker // Module being paused for is already finished, resume immediately. 2415*1fa6dee9SAndroid Build Coastguard Worker close(pauseSpec.unpause) 2416*1fa6dee9SAndroid Build Coastguard Worker } else { 2417*1fa6dee9SAndroid Build Coastguard Worker // Register for unpausing. 2418*1fa6dee9SAndroid Build Coastguard Worker pauseMap[pauseSpec.until] = append(pauseMap[pauseSpec.until], pauseSpec) 2419*1fa6dee9SAndroid Build Coastguard Worker 2420*1fa6dee9SAndroid Build Coastguard Worker // Don't count paused visitors as active so that this can't deadlock 2421*1fa6dee9SAndroid Build Coastguard Worker // if 1000 visitors are paused simultaneously. 2422*1fa6dee9SAndroid Build Coastguard Worker active-- 2423*1fa6dee9SAndroid Build Coastguard Worker unpauseOrStartFromBacklog() 2424*1fa6dee9SAndroid Build Coastguard Worker } 2425*1fa6dee9SAndroid Build Coastguard Worker } 2426*1fa6dee9SAndroid Build Coastguard Worker } 2427*1fa6dee9SAndroid Build Coastguard Worker 2428*1fa6dee9SAndroid Build Coastguard Worker if !cancel { 2429*1fa6dee9SAndroid Build Coastguard Worker // Invariant check: no backlogged modules, these weren't waiting on anything except 2430*1fa6dee9SAndroid Build Coastguard Worker // the parallelism limit so they should have run. 2431*1fa6dee9SAndroid Build Coastguard Worker if len(backlog) > 0 { 2432*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("parallelVisit finished with %d backlogged visitors", len(backlog))) 2433*1fa6dee9SAndroid Build Coastguard Worker } 2434*1fa6dee9SAndroid Build Coastguard Worker 2435*1fa6dee9SAndroid Build Coastguard Worker // Invariant check: no backlogged paused modules, these weren't waiting on anything 2436*1fa6dee9SAndroid Build Coastguard Worker // except the parallelism limit so they should have run. 2437*1fa6dee9SAndroid Build Coastguard Worker if len(unpauseBacklog) > 0 { 2438*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("parallelVisit finished with %d backlogged unpaused visitors", len(unpauseBacklog))) 2439*1fa6dee9SAndroid Build Coastguard Worker } 2440*1fa6dee9SAndroid Build Coastguard Worker 2441*1fa6dee9SAndroid Build Coastguard Worker if len(pauseMap) > 0 { 2442*1fa6dee9SAndroid Build Coastguard Worker // Probably a deadlock due to a newly added dependency cycle. Start from each module in 2443*1fa6dee9SAndroid Build Coastguard Worker // the order of the input modules list and perform a depth-first search for the module 2444*1fa6dee9SAndroid Build Coastguard Worker // it is paused on, ignoring modules that are marked as done. Note this traverses from 2445*1fa6dee9SAndroid Build Coastguard Worker // modules to the modules that would have been unblocked when that module finished, i.e 2446*1fa6dee9SAndroid Build Coastguard Worker // the reverse of the visitOrderer. 2447*1fa6dee9SAndroid Build Coastguard Worker 2448*1fa6dee9SAndroid Build Coastguard Worker // In order to reduce duplicated work, once a module has been checked and determined 2449*1fa6dee9SAndroid Build Coastguard Worker // not to be part of a cycle add it and everything that depends on it to the checked 2450*1fa6dee9SAndroid Build Coastguard Worker // map. 2451*1fa6dee9SAndroid Build Coastguard Worker checked := make(map[*moduleInfo]struct{}) 2452*1fa6dee9SAndroid Build Coastguard Worker 2453*1fa6dee9SAndroid Build Coastguard Worker var check func(module, end *moduleInfo) []*moduleInfo 2454*1fa6dee9SAndroid Build Coastguard Worker check = func(module, end *moduleInfo) []*moduleInfo { 2455*1fa6dee9SAndroid Build Coastguard Worker if module.waitingCount == -1 { 2456*1fa6dee9SAndroid Build Coastguard Worker // This module was finished, it can't be part of a loop. 2457*1fa6dee9SAndroid Build Coastguard Worker return nil 2458*1fa6dee9SAndroid Build Coastguard Worker } 2459*1fa6dee9SAndroid Build Coastguard Worker if module == end { 2460*1fa6dee9SAndroid Build Coastguard Worker // This module is the end of the loop, start rolling up the cycle. 2461*1fa6dee9SAndroid Build Coastguard Worker return []*moduleInfo{module} 2462*1fa6dee9SAndroid Build Coastguard Worker } 2463*1fa6dee9SAndroid Build Coastguard Worker 2464*1fa6dee9SAndroid Build Coastguard Worker if _, alreadyChecked := checked[module]; alreadyChecked { 2465*1fa6dee9SAndroid Build Coastguard Worker return nil 2466*1fa6dee9SAndroid Build Coastguard Worker } 2467*1fa6dee9SAndroid Build Coastguard Worker 2468*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range order.propagate(module) { 2469*1fa6dee9SAndroid Build Coastguard Worker cycle := check(dep, end) 2470*1fa6dee9SAndroid Build Coastguard Worker if cycle != nil { 2471*1fa6dee9SAndroid Build Coastguard Worker return append([]*moduleInfo{module}, cycle...) 2472*1fa6dee9SAndroid Build Coastguard Worker } 2473*1fa6dee9SAndroid Build Coastguard Worker } 2474*1fa6dee9SAndroid Build Coastguard Worker for _, depPauseSpec := range pauseMap[module] { 2475*1fa6dee9SAndroid Build Coastguard Worker cycle := check(depPauseSpec.paused, end) 2476*1fa6dee9SAndroid Build Coastguard Worker if cycle != nil { 2477*1fa6dee9SAndroid Build Coastguard Worker return append([]*moduleInfo{module}, cycle...) 2478*1fa6dee9SAndroid Build Coastguard Worker } 2479*1fa6dee9SAndroid Build Coastguard Worker } 2480*1fa6dee9SAndroid Build Coastguard Worker 2481*1fa6dee9SAndroid Build Coastguard Worker checked[module] = struct{}{} 2482*1fa6dee9SAndroid Build Coastguard Worker return nil 2483*1fa6dee9SAndroid Build Coastguard Worker } 2484*1fa6dee9SAndroid Build Coastguard Worker 2485*1fa6dee9SAndroid Build Coastguard Worker // Iterate over the modules list instead of pauseMap to provide deterministic ordering. 2486*1fa6dee9SAndroid Build Coastguard Worker for module := range moduleIter { 2487*1fa6dee9SAndroid Build Coastguard Worker for _, pauseSpec := range pauseMap[module] { 2488*1fa6dee9SAndroid Build Coastguard Worker cycle := check(pauseSpec.paused, pauseSpec.until) 2489*1fa6dee9SAndroid Build Coastguard Worker if len(cycle) > 0 { 2490*1fa6dee9SAndroid Build Coastguard Worker return cycleError(cycle) 2491*1fa6dee9SAndroid Build Coastguard Worker } 2492*1fa6dee9SAndroid Build Coastguard Worker } 2493*1fa6dee9SAndroid Build Coastguard Worker } 2494*1fa6dee9SAndroid Build Coastguard Worker } 2495*1fa6dee9SAndroid Build Coastguard Worker 2496*1fa6dee9SAndroid Build Coastguard Worker // Invariant check: if there was no deadlock and no cancellation every module 2497*1fa6dee9SAndroid Build Coastguard Worker // should have been visited. 2498*1fa6dee9SAndroid Build Coastguard Worker if visited != toVisit { 2499*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("parallelVisit ran %d visitors, expected %d", visited, toVisit)) 2500*1fa6dee9SAndroid Build Coastguard Worker } 2501*1fa6dee9SAndroid Build Coastguard Worker 2502*1fa6dee9SAndroid Build Coastguard Worker // Invariant check: if there was no deadlock and no cancellation every module 2503*1fa6dee9SAndroid Build Coastguard Worker // should have been visited, so there is nothing left to be paused on. 2504*1fa6dee9SAndroid Build Coastguard Worker if len(pauseMap) > 0 { 2505*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("parallelVisit finished with %d paused visitors", len(pauseMap))) 2506*1fa6dee9SAndroid Build Coastguard Worker } 2507*1fa6dee9SAndroid Build Coastguard Worker } 2508*1fa6dee9SAndroid Build Coastguard Worker 2509*1fa6dee9SAndroid Build Coastguard Worker return nil 2510*1fa6dee9SAndroid Build Coastguard Worker} 2511*1fa6dee9SAndroid Build Coastguard Worker 2512*1fa6dee9SAndroid Build Coastguard Workerfunc cycleError(cycle []*moduleInfo) (errs []error) { 2513*1fa6dee9SAndroid Build Coastguard Worker // The cycle list is in reverse order because all the 'check' calls append 2514*1fa6dee9SAndroid Build Coastguard Worker // their own module to the list. 2515*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 2516*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf("encountered dependency cycle:"), 2517*1fa6dee9SAndroid Build Coastguard Worker Pos: cycle[len(cycle)-1].pos, 2518*1fa6dee9SAndroid Build Coastguard Worker }) 2519*1fa6dee9SAndroid Build Coastguard Worker 2520*1fa6dee9SAndroid Build Coastguard Worker // Iterate backwards through the cycle list. 2521*1fa6dee9SAndroid Build Coastguard Worker curModule := cycle[0] 2522*1fa6dee9SAndroid Build Coastguard Worker for i := len(cycle) - 1; i >= 0; i-- { 2523*1fa6dee9SAndroid Build Coastguard Worker nextModule := cycle[i] 2524*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, &BlueprintError{ 2525*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf(" %s depends on %s", 2526*1fa6dee9SAndroid Build Coastguard Worker curModule, nextModule), 2527*1fa6dee9SAndroid Build Coastguard Worker Pos: curModule.pos, 2528*1fa6dee9SAndroid Build Coastguard Worker }) 2529*1fa6dee9SAndroid Build Coastguard Worker curModule = nextModule 2530*1fa6dee9SAndroid Build Coastguard Worker } 2531*1fa6dee9SAndroid Build Coastguard Worker 2532*1fa6dee9SAndroid Build Coastguard Worker return errs 2533*1fa6dee9SAndroid Build Coastguard Worker} 2534*1fa6dee9SAndroid Build Coastguard Worker 2535*1fa6dee9SAndroid Build Coastguard Worker// updateDependencies recursively walks the module dependency graph and updates 2536*1fa6dee9SAndroid Build Coastguard Worker// additional fields based on the dependencies. It builds a sorted list of modules 2537*1fa6dee9SAndroid Build Coastguard Worker// such that dependencies of a module always appear first, and populates reverse 2538*1fa6dee9SAndroid Build Coastguard Worker// dependency links and counts of total dependencies. It also reports errors when 2539*1fa6dee9SAndroid Build Coastguard Worker// it encounters dependency cycles. This should be called after resolveDependencies, 2540*1fa6dee9SAndroid Build Coastguard Worker// as well as after any mutator pass has called addDependency 2541*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) updateDependencies() (errs []error) { 2542*1fa6dee9SAndroid Build Coastguard Worker c.cachedDepsModified = true 2543*1fa6dee9SAndroid Build Coastguard Worker visited := make(map[*moduleInfo]bool, len(c.moduleInfo)) // modules that were already checked 2544*1fa6dee9SAndroid Build Coastguard Worker checking := make(map[*moduleInfo]bool) // modules actively being checked 2545*1fa6dee9SAndroid Build Coastguard Worker 2546*1fa6dee9SAndroid Build Coastguard Worker var check func(group *moduleInfo) []*moduleInfo 2547*1fa6dee9SAndroid Build Coastguard Worker 2548*1fa6dee9SAndroid Build Coastguard Worker check = func(module *moduleInfo) []*moduleInfo { 2549*1fa6dee9SAndroid Build Coastguard Worker visited[module] = true 2550*1fa6dee9SAndroid Build Coastguard Worker checking[module] = true 2551*1fa6dee9SAndroid Build Coastguard Worker defer delete(checking, module) 2552*1fa6dee9SAndroid Build Coastguard Worker 2553*1fa6dee9SAndroid Build Coastguard Worker // Reset the forward and reverse deps without reducing their capacity to avoid reallocation. 2554*1fa6dee9SAndroid Build Coastguard Worker module.reverseDeps = module.reverseDeps[:0] 2555*1fa6dee9SAndroid Build Coastguard Worker module.forwardDeps = module.forwardDeps[:0] 2556*1fa6dee9SAndroid Build Coastguard Worker 2557*1fa6dee9SAndroid Build Coastguard Worker // Add an implicit dependency ordering on all earlier modules in the same module group 2558*1fa6dee9SAndroid Build Coastguard Worker selfIndex := slices.Index(module.group.modules, module) 2559*1fa6dee9SAndroid Build Coastguard Worker module.forwardDeps = slices.Grow(module.forwardDeps, selfIndex+len(module.directDeps)) 2560*1fa6dee9SAndroid Build Coastguard Worker module.forwardDeps = append(module.forwardDeps, module.group.modules[:selfIndex]...) 2561*1fa6dee9SAndroid Build Coastguard Worker 2562*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range module.directDeps { 2563*1fa6dee9SAndroid Build Coastguard Worker module.forwardDeps = append(module.forwardDeps, dep.module) 2564*1fa6dee9SAndroid Build Coastguard Worker } 2565*1fa6dee9SAndroid Build Coastguard Worker 2566*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range module.forwardDeps { 2567*1fa6dee9SAndroid Build Coastguard Worker if checking[dep] { 2568*1fa6dee9SAndroid Build Coastguard Worker // This is a cycle. 2569*1fa6dee9SAndroid Build Coastguard Worker return []*moduleInfo{dep, module} 2570*1fa6dee9SAndroid Build Coastguard Worker } 2571*1fa6dee9SAndroid Build Coastguard Worker 2572*1fa6dee9SAndroid Build Coastguard Worker if !visited[dep] { 2573*1fa6dee9SAndroid Build Coastguard Worker cycle := check(dep) 2574*1fa6dee9SAndroid Build Coastguard Worker if cycle != nil { 2575*1fa6dee9SAndroid Build Coastguard Worker if cycle[0] == module { 2576*1fa6dee9SAndroid Build Coastguard Worker // We are the "start" of the cycle, so we're responsible 2577*1fa6dee9SAndroid Build Coastguard Worker // for generating the errors. 2578*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, cycleError(cycle)...) 2579*1fa6dee9SAndroid Build Coastguard Worker 2580*1fa6dee9SAndroid Build Coastguard Worker // We can continue processing this module's children to 2581*1fa6dee9SAndroid Build Coastguard Worker // find more cycles. Since all the modules that were 2582*1fa6dee9SAndroid Build Coastguard Worker // part of the found cycle were marked as visited we 2583*1fa6dee9SAndroid Build Coastguard Worker // won't run into that cycle again. 2584*1fa6dee9SAndroid Build Coastguard Worker } else { 2585*1fa6dee9SAndroid Build Coastguard Worker // We're not the "start" of the cycle, so we just append 2586*1fa6dee9SAndroid Build Coastguard Worker // our module to the list and return it. 2587*1fa6dee9SAndroid Build Coastguard Worker return append(cycle, module) 2588*1fa6dee9SAndroid Build Coastguard Worker } 2589*1fa6dee9SAndroid Build Coastguard Worker } 2590*1fa6dee9SAndroid Build Coastguard Worker } 2591*1fa6dee9SAndroid Build Coastguard Worker 2592*1fa6dee9SAndroid Build Coastguard Worker dep.reverseDeps = append(dep.reverseDeps, module) 2593*1fa6dee9SAndroid Build Coastguard Worker } 2594*1fa6dee9SAndroid Build Coastguard Worker 2595*1fa6dee9SAndroid Build Coastguard Worker return nil 2596*1fa6dee9SAndroid Build Coastguard Worker } 2597*1fa6dee9SAndroid Build Coastguard Worker 2598*1fa6dee9SAndroid Build Coastguard Worker for _, module := range c.moduleInfo { 2599*1fa6dee9SAndroid Build Coastguard Worker if !visited[module] { 2600*1fa6dee9SAndroid Build Coastguard Worker cycle := check(module) 2601*1fa6dee9SAndroid Build Coastguard Worker if cycle != nil { 2602*1fa6dee9SAndroid Build Coastguard Worker if cycle[len(cycle)-1] != module { 2603*1fa6dee9SAndroid Build Coastguard Worker panic("inconceivable!") 2604*1fa6dee9SAndroid Build Coastguard Worker } 2605*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, cycleError(cycle)...) 2606*1fa6dee9SAndroid Build Coastguard Worker } 2607*1fa6dee9SAndroid Build Coastguard Worker } 2608*1fa6dee9SAndroid Build Coastguard Worker } 2609*1fa6dee9SAndroid Build Coastguard Worker 2610*1fa6dee9SAndroid Build Coastguard Worker return 2611*1fa6dee9SAndroid Build Coastguard Worker} 2612*1fa6dee9SAndroid Build Coastguard Worker 2613*1fa6dee9SAndroid Build Coastguard Workertype jsonVariations []Variation 2614*1fa6dee9SAndroid Build Coastguard Worker 2615*1fa6dee9SAndroid Build Coastguard Workertype jsonModuleName struct { 2616*1fa6dee9SAndroid Build Coastguard Worker Name string 2617*1fa6dee9SAndroid Build Coastguard Worker Variant string 2618*1fa6dee9SAndroid Build Coastguard Worker} 2619*1fa6dee9SAndroid Build Coastguard Worker 2620*1fa6dee9SAndroid Build Coastguard Workertype jsonDep struct { 2621*1fa6dee9SAndroid Build Coastguard Worker jsonModuleName 2622*1fa6dee9SAndroid Build Coastguard Worker Tag string 2623*1fa6dee9SAndroid Build Coastguard Worker} 2624*1fa6dee9SAndroid Build Coastguard Worker 2625*1fa6dee9SAndroid Build Coastguard Workertype JsonModule struct { 2626*1fa6dee9SAndroid Build Coastguard Worker jsonModuleName 2627*1fa6dee9SAndroid Build Coastguard Worker Deps []jsonDep 2628*1fa6dee9SAndroid Build Coastguard Worker Type string 2629*1fa6dee9SAndroid Build Coastguard Worker Blueprint string 2630*1fa6dee9SAndroid Build Coastguard Worker CreatedBy *string 2631*1fa6dee9SAndroid Build Coastguard Worker Module map[string]interface{} 2632*1fa6dee9SAndroid Build Coastguard Worker} 2633*1fa6dee9SAndroid Build Coastguard Worker 2634*1fa6dee9SAndroid Build Coastguard Workerfunc jsonModuleNameFromModuleInfo(m *moduleInfo) *jsonModuleName { 2635*1fa6dee9SAndroid Build Coastguard Worker return &jsonModuleName{ 2636*1fa6dee9SAndroid Build Coastguard Worker Name: m.Name(), 2637*1fa6dee9SAndroid Build Coastguard Worker Variant: m.variant.name, 2638*1fa6dee9SAndroid Build Coastguard Worker } 2639*1fa6dee9SAndroid Build Coastguard Worker} 2640*1fa6dee9SAndroid Build Coastguard Worker 2641*1fa6dee9SAndroid Build Coastguard Workertype JSONDataSupplier interface { 2642*1fa6dee9SAndroid Build Coastguard Worker AddJSONData(d *map[string]interface{}) 2643*1fa6dee9SAndroid Build Coastguard Worker} 2644*1fa6dee9SAndroid Build Coastguard Worker 2645*1fa6dee9SAndroid Build Coastguard Worker// JSONAction contains the action-related info we expose to json module graph 2646*1fa6dee9SAndroid Build Coastguard Workertype JSONAction struct { 2647*1fa6dee9SAndroid Build Coastguard Worker Inputs []string 2648*1fa6dee9SAndroid Build Coastguard Worker Outputs []string 2649*1fa6dee9SAndroid Build Coastguard Worker Desc string 2650*1fa6dee9SAndroid Build Coastguard Worker} 2651*1fa6dee9SAndroid Build Coastguard Worker 2652*1fa6dee9SAndroid Build Coastguard Worker// JSONActionSupplier allows JSON representation of additional actions that are not registered in 2653*1fa6dee9SAndroid Build Coastguard Worker// Ninja 2654*1fa6dee9SAndroid Build Coastguard Workertype JSONActionSupplier interface { 2655*1fa6dee9SAndroid Build Coastguard Worker JSONActions() []JSONAction 2656*1fa6dee9SAndroid Build Coastguard Worker} 2657*1fa6dee9SAndroid Build Coastguard Worker 2658*1fa6dee9SAndroid Build Coastguard Workerfunc jsonModuleFromModuleInfo(m *moduleInfo) *JsonModule { 2659*1fa6dee9SAndroid Build Coastguard Worker result := &JsonModule{ 2660*1fa6dee9SAndroid Build Coastguard Worker jsonModuleName: *jsonModuleNameFromModuleInfo(m), 2661*1fa6dee9SAndroid Build Coastguard Worker Deps: make([]jsonDep, 0), 2662*1fa6dee9SAndroid Build Coastguard Worker Type: m.typeName, 2663*1fa6dee9SAndroid Build Coastguard Worker Blueprint: m.relBlueprintsFile, 2664*1fa6dee9SAndroid Build Coastguard Worker Module: make(map[string]interface{}), 2665*1fa6dee9SAndroid Build Coastguard Worker } 2666*1fa6dee9SAndroid Build Coastguard Worker if m.createdBy != nil { 2667*1fa6dee9SAndroid Build Coastguard Worker n := m.createdBy.Name() 2668*1fa6dee9SAndroid Build Coastguard Worker result.CreatedBy = &n 2669*1fa6dee9SAndroid Build Coastguard Worker } 2670*1fa6dee9SAndroid Build Coastguard Worker if j, ok := m.logicModule.(JSONDataSupplier); ok { 2671*1fa6dee9SAndroid Build Coastguard Worker j.AddJSONData(&result.Module) 2672*1fa6dee9SAndroid Build Coastguard Worker } 2673*1fa6dee9SAndroid Build Coastguard Worker for _, p := range m.providers { 2674*1fa6dee9SAndroid Build Coastguard Worker if j, ok := p.(JSONDataSupplier); ok { 2675*1fa6dee9SAndroid Build Coastguard Worker j.AddJSONData(&result.Module) 2676*1fa6dee9SAndroid Build Coastguard Worker } 2677*1fa6dee9SAndroid Build Coastguard Worker } 2678*1fa6dee9SAndroid Build Coastguard Worker return result 2679*1fa6dee9SAndroid Build Coastguard Worker} 2680*1fa6dee9SAndroid Build Coastguard Worker 2681*1fa6dee9SAndroid Build Coastguard Workerfunc jsonModuleWithActionsFromModuleInfo(m *moduleInfo, nameTracker *nameTracker) *JsonModule { 2682*1fa6dee9SAndroid Build Coastguard Worker result := &JsonModule{ 2683*1fa6dee9SAndroid Build Coastguard Worker jsonModuleName: jsonModuleName{ 2684*1fa6dee9SAndroid Build Coastguard Worker Name: m.Name(), 2685*1fa6dee9SAndroid Build Coastguard Worker Variant: m.variant.name, 2686*1fa6dee9SAndroid Build Coastguard Worker }, 2687*1fa6dee9SAndroid Build Coastguard Worker Deps: make([]jsonDep, 0), 2688*1fa6dee9SAndroid Build Coastguard Worker Type: m.typeName, 2689*1fa6dee9SAndroid Build Coastguard Worker Blueprint: m.relBlueprintsFile, 2690*1fa6dee9SAndroid Build Coastguard Worker Module: make(map[string]interface{}), 2691*1fa6dee9SAndroid Build Coastguard Worker } 2692*1fa6dee9SAndroid Build Coastguard Worker var actions []JSONAction 2693*1fa6dee9SAndroid Build Coastguard Worker for _, bDef := range m.actionDefs.buildDefs { 2694*1fa6dee9SAndroid Build Coastguard Worker a := JSONAction{ 2695*1fa6dee9SAndroid Build Coastguard Worker Inputs: append(append(append( 2696*1fa6dee9SAndroid Build Coastguard Worker bDef.InputStrings, 2697*1fa6dee9SAndroid Build Coastguard Worker bDef.ImplicitStrings...), 2698*1fa6dee9SAndroid Build Coastguard Worker getNinjaStrings(bDef.Inputs, nameTracker)...), 2699*1fa6dee9SAndroid Build Coastguard Worker getNinjaStrings(bDef.Implicits, nameTracker)...), 2700*1fa6dee9SAndroid Build Coastguard Worker 2701*1fa6dee9SAndroid Build Coastguard Worker Outputs: append(append(append( 2702*1fa6dee9SAndroid Build Coastguard Worker bDef.OutputStrings, 2703*1fa6dee9SAndroid Build Coastguard Worker bDef.ImplicitOutputStrings...), 2704*1fa6dee9SAndroid Build Coastguard Worker getNinjaStrings(bDef.Outputs, nameTracker)...), 2705*1fa6dee9SAndroid Build Coastguard Worker getNinjaStrings(bDef.ImplicitOutputs, nameTracker)...), 2706*1fa6dee9SAndroid Build Coastguard Worker } 2707*1fa6dee9SAndroid Build Coastguard Worker if d, ok := bDef.Variables["description"]; ok { 2708*1fa6dee9SAndroid Build Coastguard Worker a.Desc = d.Value(nameTracker) 2709*1fa6dee9SAndroid Build Coastguard Worker } 2710*1fa6dee9SAndroid Build Coastguard Worker actions = append(actions, a) 2711*1fa6dee9SAndroid Build Coastguard Worker } 2712*1fa6dee9SAndroid Build Coastguard Worker 2713*1fa6dee9SAndroid Build Coastguard Worker if j, ok := m.logicModule.(JSONActionSupplier); ok { 2714*1fa6dee9SAndroid Build Coastguard Worker actions = append(actions, j.JSONActions()...) 2715*1fa6dee9SAndroid Build Coastguard Worker } 2716*1fa6dee9SAndroid Build Coastguard Worker for _, p := range m.providers { 2717*1fa6dee9SAndroid Build Coastguard Worker if j, ok := p.(JSONActionSupplier); ok { 2718*1fa6dee9SAndroid Build Coastguard Worker actions = append(actions, j.JSONActions()...) 2719*1fa6dee9SAndroid Build Coastguard Worker } 2720*1fa6dee9SAndroid Build Coastguard Worker } 2721*1fa6dee9SAndroid Build Coastguard Worker 2722*1fa6dee9SAndroid Build Coastguard Worker result.Module["Actions"] = actions 2723*1fa6dee9SAndroid Build Coastguard Worker return result 2724*1fa6dee9SAndroid Build Coastguard Worker} 2725*1fa6dee9SAndroid Build Coastguard Worker 2726*1fa6dee9SAndroid Build Coastguard Worker// Gets a list of strings from the given list of ninjaStrings by invoking ninjaString.Value on each. 2727*1fa6dee9SAndroid Build Coastguard Workerfunc getNinjaStrings(nStrs []*ninjaString, nameTracker *nameTracker) []string { 2728*1fa6dee9SAndroid Build Coastguard Worker var strs []string 2729*1fa6dee9SAndroid Build Coastguard Worker for _, nstr := range nStrs { 2730*1fa6dee9SAndroid Build Coastguard Worker strs = append(strs, nstr.Value(nameTracker)) 2731*1fa6dee9SAndroid Build Coastguard Worker } 2732*1fa6dee9SAndroid Build Coastguard Worker return strs 2733*1fa6dee9SAndroid Build Coastguard Worker} 2734*1fa6dee9SAndroid Build Coastguard Worker 2735*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) GetWeightedOutputsFromPredicate(predicate func(*JsonModule) (bool, int)) map[string]int { 2736*1fa6dee9SAndroid Build Coastguard Worker outputToWeight := make(map[string]int) 2737*1fa6dee9SAndroid Build Coastguard Worker for m := range c.iterateAllVariants() { 2738*1fa6dee9SAndroid Build Coastguard Worker jmWithActions := jsonModuleWithActionsFromModuleInfo(m, c.nameTracker) 2739*1fa6dee9SAndroid Build Coastguard Worker if ok, weight := predicate(jmWithActions); ok { 2740*1fa6dee9SAndroid Build Coastguard Worker for _, a := range jmWithActions.Module["Actions"].([]JSONAction) { 2741*1fa6dee9SAndroid Build Coastguard Worker for _, o := range a.Outputs { 2742*1fa6dee9SAndroid Build Coastguard Worker if val, ok := outputToWeight[o]; ok { 2743*1fa6dee9SAndroid Build Coastguard Worker if val > weight { 2744*1fa6dee9SAndroid Build Coastguard Worker continue 2745*1fa6dee9SAndroid Build Coastguard Worker } 2746*1fa6dee9SAndroid Build Coastguard Worker } 2747*1fa6dee9SAndroid Build Coastguard Worker outputToWeight[o] = weight 2748*1fa6dee9SAndroid Build Coastguard Worker } 2749*1fa6dee9SAndroid Build Coastguard Worker } 2750*1fa6dee9SAndroid Build Coastguard Worker } 2751*1fa6dee9SAndroid Build Coastguard Worker } 2752*1fa6dee9SAndroid Build Coastguard Worker return outputToWeight 2753*1fa6dee9SAndroid Build Coastguard Worker} 2754*1fa6dee9SAndroid Build Coastguard Worker 2755*1fa6dee9SAndroid Build Coastguard Worker// PrintJSONGraph prints info of modules in a JSON file. 2756*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) PrintJSONGraphAndActions(wGraph io.Writer, wActions io.Writer) { 2757*1fa6dee9SAndroid Build Coastguard Worker modulesToGraph := make([]*JsonModule, 0) 2758*1fa6dee9SAndroid Build Coastguard Worker modulesToActions := make([]*JsonModule, 0) 2759*1fa6dee9SAndroid Build Coastguard Worker for m := range c.iterateAllVariants() { 2760*1fa6dee9SAndroid Build Coastguard Worker jm := jsonModuleFromModuleInfo(m) 2761*1fa6dee9SAndroid Build Coastguard Worker jmWithActions := jsonModuleWithActionsFromModuleInfo(m, c.nameTracker) 2762*1fa6dee9SAndroid Build Coastguard Worker for _, d := range m.directDeps { 2763*1fa6dee9SAndroid Build Coastguard Worker jm.Deps = append(jm.Deps, jsonDep{ 2764*1fa6dee9SAndroid Build Coastguard Worker jsonModuleName: *jsonModuleNameFromModuleInfo(d.module), 2765*1fa6dee9SAndroid Build Coastguard Worker Tag: fmt.Sprintf("%T %+v", d.tag, d.tag), 2766*1fa6dee9SAndroid Build Coastguard Worker }) 2767*1fa6dee9SAndroid Build Coastguard Worker jmWithActions.Deps = append(jmWithActions.Deps, jsonDep{ 2768*1fa6dee9SAndroid Build Coastguard Worker jsonModuleName: jsonModuleName{ 2769*1fa6dee9SAndroid Build Coastguard Worker Name: d.module.Name(), 2770*1fa6dee9SAndroid Build Coastguard Worker }, 2771*1fa6dee9SAndroid Build Coastguard Worker }) 2772*1fa6dee9SAndroid Build Coastguard Worker 2773*1fa6dee9SAndroid Build Coastguard Worker } 2774*1fa6dee9SAndroid Build Coastguard Worker modulesToGraph = append(modulesToGraph, jm) 2775*1fa6dee9SAndroid Build Coastguard Worker modulesToActions = append(modulesToActions, jmWithActions) 2776*1fa6dee9SAndroid Build Coastguard Worker } 2777*1fa6dee9SAndroid Build Coastguard Worker writeJson(wGraph, modulesToGraph) 2778*1fa6dee9SAndroid Build Coastguard Worker writeJson(wActions, modulesToActions) 2779*1fa6dee9SAndroid Build Coastguard Worker} 2780*1fa6dee9SAndroid Build Coastguard Worker 2781*1fa6dee9SAndroid Build Coastguard Workerfunc writeJson(w io.Writer, modules []*JsonModule) { 2782*1fa6dee9SAndroid Build Coastguard Worker e := json.NewEncoder(w) 2783*1fa6dee9SAndroid Build Coastguard Worker e.SetIndent("", "\t") 2784*1fa6dee9SAndroid Build Coastguard Worker e.Encode(modules) 2785*1fa6dee9SAndroid Build Coastguard Worker} 2786*1fa6dee9SAndroid Build Coastguard Worker 2787*1fa6dee9SAndroid Build Coastguard Worker// PrepareBuildActions generates an internal representation of all the build 2788*1fa6dee9SAndroid Build Coastguard Worker// actions that need to be performed. This process involves invoking the 2789*1fa6dee9SAndroid Build Coastguard Worker// GenerateBuildActions method on each of the Module objects created during the 2790*1fa6dee9SAndroid Build Coastguard Worker// parse phase and then on each of the registered Singleton objects. 2791*1fa6dee9SAndroid Build Coastguard Worker// 2792*1fa6dee9SAndroid Build Coastguard Worker// If the ResolveDependencies method has not already been called it is called 2793*1fa6dee9SAndroid Build Coastguard Worker// automatically by this method. 2794*1fa6dee9SAndroid Build Coastguard Worker// 2795*1fa6dee9SAndroid Build Coastguard Worker// The config argument is made available to all of the Module and Singleton 2796*1fa6dee9SAndroid Build Coastguard Worker// objects via the Config method on the ModuleContext and SingletonContext 2797*1fa6dee9SAndroid Build Coastguard Worker// objects passed to GenerateBuildActions. It is also passed to the functions 2798*1fa6dee9SAndroid Build Coastguard Worker// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute 2799*1fa6dee9SAndroid Build Coastguard Worker// config-specific values. 2800*1fa6dee9SAndroid Build Coastguard Worker// 2801*1fa6dee9SAndroid Build Coastguard Worker// The returned deps is a list of the ninja files dependencies that were added 2802*1fa6dee9SAndroid Build Coastguard Worker// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(), 2803*1fa6dee9SAndroid Build Coastguard Worker// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps() 2804*1fa6dee9SAndroid Build Coastguard Worker// methods. 2805*1fa6dee9SAndroid Build Coastguard Worker 2806*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) { 2807*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("prepare_build_actions") 2808*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("prepare_build_actions") 2809*1fa6dee9SAndroid Build Coastguard Worker pprof.Do(c.Context, pprof.Labels("blueprint", "PrepareBuildActions"), func(ctx context.Context) { 2810*1fa6dee9SAndroid Build Coastguard Worker c.buildActionsReady = false 2811*1fa6dee9SAndroid Build Coastguard Worker 2812*1fa6dee9SAndroid Build Coastguard Worker c.liveGlobals = newLiveTracker(c, config) 2813*1fa6dee9SAndroid Build Coastguard Worker // Add all the global rules/variable/pools here because when we restore from 2814*1fa6dee9SAndroid Build Coastguard Worker // cache we don't have the build defs available to build the globals. 2815*1fa6dee9SAndroid Build Coastguard Worker // TODO(b/356414070): Revisit this logic once we have a clearer picture about 2816*1fa6dee9SAndroid Build Coastguard Worker // how the incremental build pieces fit together. 2817*1fa6dee9SAndroid Build Coastguard Worker if c.GetIncrementalEnabled() { 2818*1fa6dee9SAndroid Build Coastguard Worker for _, p := range packageContexts { 2819*1fa6dee9SAndroid Build Coastguard Worker for _, v := range p.scope.variables { 2820*1fa6dee9SAndroid Build Coastguard Worker err := c.liveGlobals.addVariable(v) 2821*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 2822*1fa6dee9SAndroid Build Coastguard Worker errs = []error{err} 2823*1fa6dee9SAndroid Build Coastguard Worker return 2824*1fa6dee9SAndroid Build Coastguard Worker } 2825*1fa6dee9SAndroid Build Coastguard Worker } 2826*1fa6dee9SAndroid Build Coastguard Worker for _, v := range p.scope.rules { 2827*1fa6dee9SAndroid Build Coastguard Worker _, err := c.liveGlobals.addRule(v) 2828*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 2829*1fa6dee9SAndroid Build Coastguard Worker errs = []error{err} 2830*1fa6dee9SAndroid Build Coastguard Worker return 2831*1fa6dee9SAndroid Build Coastguard Worker } 2832*1fa6dee9SAndroid Build Coastguard Worker } 2833*1fa6dee9SAndroid Build Coastguard Worker for _, v := range p.scope.pools { 2834*1fa6dee9SAndroid Build Coastguard Worker err := c.liveGlobals.addPool(v) 2835*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 2836*1fa6dee9SAndroid Build Coastguard Worker errs = []error{err} 2837*1fa6dee9SAndroid Build Coastguard Worker return 2838*1fa6dee9SAndroid Build Coastguard Worker } 2839*1fa6dee9SAndroid Build Coastguard Worker } 2840*1fa6dee9SAndroid Build Coastguard Worker } 2841*1fa6dee9SAndroid Build Coastguard Worker } 2842*1fa6dee9SAndroid Build Coastguard Worker 2843*1fa6dee9SAndroid Build Coastguard Worker if !c.dependenciesReady { 2844*1fa6dee9SAndroid Build Coastguard Worker var extraDeps []string 2845*1fa6dee9SAndroid Build Coastguard Worker extraDeps, errs = c.resolveDependencies(ctx, config) 2846*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 2847*1fa6dee9SAndroid Build Coastguard Worker return 2848*1fa6dee9SAndroid Build Coastguard Worker } 2849*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, extraDeps...) 2850*1fa6dee9SAndroid Build Coastguard Worker } 2851*1fa6dee9SAndroid Build Coastguard Worker 2852*1fa6dee9SAndroid Build Coastguard Worker var depsModules []string 2853*1fa6dee9SAndroid Build Coastguard Worker depsModules, errs = c.generateModuleBuildActions(config, c.liveGlobals) 2854*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 2855*1fa6dee9SAndroid Build Coastguard Worker return 2856*1fa6dee9SAndroid Build Coastguard Worker } 2857*1fa6dee9SAndroid Build Coastguard Worker 2858*1fa6dee9SAndroid Build Coastguard Worker var depsSingletons []string 2859*1fa6dee9SAndroid Build Coastguard Worker depsSingletons, errs = c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals) 2860*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 2861*1fa6dee9SAndroid Build Coastguard Worker return 2862*1fa6dee9SAndroid Build Coastguard Worker } 2863*1fa6dee9SAndroid Build Coastguard Worker 2864*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, depsModules...) 2865*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, depsSingletons...) 2866*1fa6dee9SAndroid Build Coastguard Worker 2867*1fa6dee9SAndroid Build Coastguard Worker if c.outDir != nil { 2868*1fa6dee9SAndroid Build Coastguard Worker err := c.liveGlobals.addNinjaStringDeps(c.outDir) 2869*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 2870*1fa6dee9SAndroid Build Coastguard Worker errs = []error{err} 2871*1fa6dee9SAndroid Build Coastguard Worker return 2872*1fa6dee9SAndroid Build Coastguard Worker } 2873*1fa6dee9SAndroid Build Coastguard Worker } 2874*1fa6dee9SAndroid Build Coastguard Worker 2875*1fa6dee9SAndroid Build Coastguard Worker pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals) 2876*1fa6dee9SAndroid Build Coastguard Worker 2877*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, depsPackages...) 2878*1fa6dee9SAndroid Build Coastguard Worker 2879*1fa6dee9SAndroid Build Coastguard Worker nameTracker := c.memoizeFullNames(c.liveGlobals, pkgNames) 2880*1fa6dee9SAndroid Build Coastguard Worker 2881*1fa6dee9SAndroid Build Coastguard Worker // This will panic if it finds a problem since it's a programming error. 2882*1fa6dee9SAndroid Build Coastguard Worker c.checkForVariableReferenceCycles(c.liveGlobals.variables, nameTracker) 2883*1fa6dee9SAndroid Build Coastguard Worker 2884*1fa6dee9SAndroid Build Coastguard Worker c.nameTracker = nameTracker 2885*1fa6dee9SAndroid Build Coastguard Worker c.globalVariables = c.liveGlobals.variables 2886*1fa6dee9SAndroid Build Coastguard Worker c.globalPools = c.liveGlobals.pools 2887*1fa6dee9SAndroid Build Coastguard Worker c.globalRules = c.liveGlobals.rules 2888*1fa6dee9SAndroid Build Coastguard Worker 2889*1fa6dee9SAndroid Build Coastguard Worker c.buildActionsReady = true 2890*1fa6dee9SAndroid Build Coastguard Worker }) 2891*1fa6dee9SAndroid Build Coastguard Worker 2892*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 2893*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 2894*1fa6dee9SAndroid Build Coastguard Worker } 2895*1fa6dee9SAndroid Build Coastguard Worker 2896*1fa6dee9SAndroid Build Coastguard Worker return deps, nil 2897*1fa6dee9SAndroid Build Coastguard Worker} 2898*1fa6dee9SAndroid Build Coastguard Worker 2899*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) runMutators(ctx context.Context, config interface{}, mutatorGroups [][]*mutatorInfo) (deps []string, errs []error) { 2900*1fa6dee9SAndroid Build Coastguard Worker c.finishedMutators = make([]bool, len(c.mutatorInfo)) 2901*1fa6dee9SAndroid Build Coastguard Worker 2902*1fa6dee9SAndroid Build Coastguard Worker pprof.Do(ctx, pprof.Labels("blueprint", "runMutators"), func(ctx context.Context) { 2903*1fa6dee9SAndroid Build Coastguard Worker for _, mutatorGroup := range mutatorGroups { 2904*1fa6dee9SAndroid Build Coastguard Worker name := mutatorGroup[0].name 2905*1fa6dee9SAndroid Build Coastguard Worker if len(mutatorGroup) > 1 { 2906*1fa6dee9SAndroid Build Coastguard Worker name += "_plus_" + strconv.Itoa(len(mutatorGroup)-1) 2907*1fa6dee9SAndroid Build Coastguard Worker } 2908*1fa6dee9SAndroid Build Coastguard Worker pprof.Do(ctx, pprof.Labels("mutator", name), func(context.Context) { 2909*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent(name) 2910*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent(name) 2911*1fa6dee9SAndroid Build Coastguard Worker var newDeps []string 2912*1fa6dee9SAndroid Build Coastguard Worker if mutatorGroup[0].topDownMutator != nil { 2913*1fa6dee9SAndroid Build Coastguard Worker newDeps, errs = c.runMutator(config, mutatorGroup, topDownMutator) 2914*1fa6dee9SAndroid Build Coastguard Worker } else if mutatorGroup[0].bottomUpMutator != nil { 2915*1fa6dee9SAndroid Build Coastguard Worker newDeps, errs = c.runMutator(config, mutatorGroup, bottomUpMutator) 2916*1fa6dee9SAndroid Build Coastguard Worker } else { 2917*1fa6dee9SAndroid Build Coastguard Worker panic("no mutator set on " + mutatorGroup[0].name) 2918*1fa6dee9SAndroid Build Coastguard Worker } 2919*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 2920*1fa6dee9SAndroid Build Coastguard Worker return 2921*1fa6dee9SAndroid Build Coastguard Worker } 2922*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, newDeps...) 2923*1fa6dee9SAndroid Build Coastguard Worker }) 2924*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 2925*1fa6dee9SAndroid Build Coastguard Worker return 2926*1fa6dee9SAndroid Build Coastguard Worker } 2927*1fa6dee9SAndroid Build Coastguard Worker } 2928*1fa6dee9SAndroid Build Coastguard Worker }) 2929*1fa6dee9SAndroid Build Coastguard Worker 2930*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 2931*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 2932*1fa6dee9SAndroid Build Coastguard Worker } 2933*1fa6dee9SAndroid Build Coastguard Worker 2934*1fa6dee9SAndroid Build Coastguard Worker return deps, nil 2935*1fa6dee9SAndroid Build Coastguard Worker} 2936*1fa6dee9SAndroid Build Coastguard Worker 2937*1fa6dee9SAndroid Build Coastguard Workertype mutatorDirection interface { 2938*1fa6dee9SAndroid Build Coastguard Worker run(mutator []*mutatorInfo, ctx *mutatorContext) 2939*1fa6dee9SAndroid Build Coastguard Worker orderer() visitOrderer 2940*1fa6dee9SAndroid Build Coastguard Worker fmt.Stringer 2941*1fa6dee9SAndroid Build Coastguard Worker} 2942*1fa6dee9SAndroid Build Coastguard Worker 2943*1fa6dee9SAndroid Build Coastguard Workertype bottomUpMutatorImpl struct{} 2944*1fa6dee9SAndroid Build Coastguard Worker 2945*1fa6dee9SAndroid Build Coastguard Workerfunc (bottomUpMutatorImpl) run(mutatorGroup []*mutatorInfo, ctx *mutatorContext) { 2946*1fa6dee9SAndroid Build Coastguard Worker for _, mutator := range mutatorGroup { 2947*1fa6dee9SAndroid Build Coastguard Worker ctx.mutator = mutator 2948*1fa6dee9SAndroid Build Coastguard Worker ctx.module.startedMutator = mutator.index 2949*1fa6dee9SAndroid Build Coastguard Worker mutator.bottomUpMutator(ctx) 2950*1fa6dee9SAndroid Build Coastguard Worker ctx.module.finishedMutator = mutator.index 2951*1fa6dee9SAndroid Build Coastguard Worker } 2952*1fa6dee9SAndroid Build Coastguard Worker} 2953*1fa6dee9SAndroid Build Coastguard Worker 2954*1fa6dee9SAndroid Build Coastguard Workerfunc (bottomUpMutatorImpl) orderer() visitOrderer { 2955*1fa6dee9SAndroid Build Coastguard Worker return bottomUpVisitor 2956*1fa6dee9SAndroid Build Coastguard Worker} 2957*1fa6dee9SAndroid Build Coastguard Worker 2958*1fa6dee9SAndroid Build Coastguard Workerfunc (bottomUpMutatorImpl) String() string { 2959*1fa6dee9SAndroid Build Coastguard Worker return "bottom up mutator" 2960*1fa6dee9SAndroid Build Coastguard Worker} 2961*1fa6dee9SAndroid Build Coastguard Worker 2962*1fa6dee9SAndroid Build Coastguard Workertype topDownMutatorImpl struct{} 2963*1fa6dee9SAndroid Build Coastguard Worker 2964*1fa6dee9SAndroid Build Coastguard Workerfunc (topDownMutatorImpl) run(mutatorGroup []*mutatorInfo, ctx *mutatorContext) { 2965*1fa6dee9SAndroid Build Coastguard Worker if len(mutatorGroup) > 1 { 2966*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("top down mutator group %s must only have 1 mutator, found %d", mutatorGroup[0].name, len(mutatorGroup))) 2967*1fa6dee9SAndroid Build Coastguard Worker } 2968*1fa6dee9SAndroid Build Coastguard Worker mutatorGroup[0].topDownMutator(ctx) 2969*1fa6dee9SAndroid Build Coastguard Worker} 2970*1fa6dee9SAndroid Build Coastguard Worker 2971*1fa6dee9SAndroid Build Coastguard Workerfunc (topDownMutatorImpl) orderer() visitOrderer { 2972*1fa6dee9SAndroid Build Coastguard Worker return topDownVisitor 2973*1fa6dee9SAndroid Build Coastguard Worker} 2974*1fa6dee9SAndroid Build Coastguard Worker 2975*1fa6dee9SAndroid Build Coastguard Workerfunc (topDownMutatorImpl) String() string { 2976*1fa6dee9SAndroid Build Coastguard Worker return "top down mutator" 2977*1fa6dee9SAndroid Build Coastguard Worker} 2978*1fa6dee9SAndroid Build Coastguard Worker 2979*1fa6dee9SAndroid Build Coastguard Workervar ( 2980*1fa6dee9SAndroid Build Coastguard Worker topDownMutator topDownMutatorImpl 2981*1fa6dee9SAndroid Build Coastguard Worker bottomUpMutator bottomUpMutatorImpl 2982*1fa6dee9SAndroid Build Coastguard Worker) 2983*1fa6dee9SAndroid Build Coastguard Worker 2984*1fa6dee9SAndroid Build Coastguard Workertype reverseDep struct { 2985*1fa6dee9SAndroid Build Coastguard Worker module *moduleInfo 2986*1fa6dee9SAndroid Build Coastguard Worker dep depInfo 2987*1fa6dee9SAndroid Build Coastguard Worker} 2988*1fa6dee9SAndroid Build Coastguard Worker 2989*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) runMutator(config interface{}, mutatorGroup []*mutatorInfo, 2990*1fa6dee9SAndroid Build Coastguard Worker direction mutatorDirection) (deps []string, errs []error) { 2991*1fa6dee9SAndroid Build Coastguard Worker 2992*1fa6dee9SAndroid Build Coastguard Worker newModuleInfo := maps.Clone(c.moduleInfo) 2993*1fa6dee9SAndroid Build Coastguard Worker 2994*1fa6dee9SAndroid Build Coastguard Worker type globalStateChange struct { 2995*1fa6dee9SAndroid Build Coastguard Worker reverse []reverseDep 2996*1fa6dee9SAndroid Build Coastguard Worker rename []rename 2997*1fa6dee9SAndroid Build Coastguard Worker replace []replace 2998*1fa6dee9SAndroid Build Coastguard Worker newModules []*moduleInfo 2999*1fa6dee9SAndroid Build Coastguard Worker deps []string 3000*1fa6dee9SAndroid Build Coastguard Worker } 3001*1fa6dee9SAndroid Build Coastguard Worker 3002*1fa6dee9SAndroid Build Coastguard Worker type newVariationPair struct { 3003*1fa6dee9SAndroid Build Coastguard Worker newVariations moduleList 3004*1fa6dee9SAndroid Build Coastguard Worker origLogicModule Module 3005*1fa6dee9SAndroid Build Coastguard Worker } 3006*1fa6dee9SAndroid Build Coastguard Worker 3007*1fa6dee9SAndroid Build Coastguard Worker reverseDeps := make(map[*moduleInfo][]depInfo) 3008*1fa6dee9SAndroid Build Coastguard Worker var rename []rename 3009*1fa6dee9SAndroid Build Coastguard Worker var replace []replace 3010*1fa6dee9SAndroid Build Coastguard Worker var newModules []*moduleInfo 3011*1fa6dee9SAndroid Build Coastguard Worker 3012*1fa6dee9SAndroid Build Coastguard Worker errsCh := make(chan []error) 3013*1fa6dee9SAndroid Build Coastguard Worker globalStateCh := make(chan globalStateChange) 3014*1fa6dee9SAndroid Build Coastguard Worker newVariationsCh := make(chan newVariationPair) 3015*1fa6dee9SAndroid Build Coastguard Worker done := make(chan bool) 3016*1fa6dee9SAndroid Build Coastguard Worker 3017*1fa6dee9SAndroid Build Coastguard Worker c.needsUpdateDependencies = 0 3018*1fa6dee9SAndroid Build Coastguard Worker 3019*1fa6dee9SAndroid Build Coastguard Worker visit := func(module *moduleInfo, pause chan<- pauseSpec) bool { 3020*1fa6dee9SAndroid Build Coastguard Worker if module.splitModules != nil { 3021*1fa6dee9SAndroid Build Coastguard Worker panic("split module found in sorted module list") 3022*1fa6dee9SAndroid Build Coastguard Worker } 3023*1fa6dee9SAndroid Build Coastguard Worker 3024*1fa6dee9SAndroid Build Coastguard Worker mctx := &mutatorContext{ 3025*1fa6dee9SAndroid Build Coastguard Worker baseModuleContext: baseModuleContext{ 3026*1fa6dee9SAndroid Build Coastguard Worker context: c, 3027*1fa6dee9SAndroid Build Coastguard Worker config: config, 3028*1fa6dee9SAndroid Build Coastguard Worker module: module, 3029*1fa6dee9SAndroid Build Coastguard Worker }, 3030*1fa6dee9SAndroid Build Coastguard Worker mutator: mutatorGroup[0], 3031*1fa6dee9SAndroid Build Coastguard Worker pauseCh: pause, 3032*1fa6dee9SAndroid Build Coastguard Worker } 3033*1fa6dee9SAndroid Build Coastguard Worker 3034*1fa6dee9SAndroid Build Coastguard Worker origLogicModule := module.logicModule 3035*1fa6dee9SAndroid Build Coastguard Worker 3036*1fa6dee9SAndroid Build Coastguard Worker module.startedMutator = mutatorGroup[0].index 3037*1fa6dee9SAndroid Build Coastguard Worker 3038*1fa6dee9SAndroid Build Coastguard Worker func() { 3039*1fa6dee9SAndroid Build Coastguard Worker defer func() { 3040*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 3041*1fa6dee9SAndroid Build Coastguard Worker in := fmt.Sprintf("%s %q for %s", direction, mutatorGroup[0].name, module) 3042*1fa6dee9SAndroid Build Coastguard Worker if err, ok := r.(panicError); ok { 3043*1fa6dee9SAndroid Build Coastguard Worker err.addIn(in) 3044*1fa6dee9SAndroid Build Coastguard Worker mctx.error(err) 3045*1fa6dee9SAndroid Build Coastguard Worker } else { 3046*1fa6dee9SAndroid Build Coastguard Worker mctx.error(newPanicErrorf(r, in)) 3047*1fa6dee9SAndroid Build Coastguard Worker } 3048*1fa6dee9SAndroid Build Coastguard Worker } 3049*1fa6dee9SAndroid Build Coastguard Worker }() 3050*1fa6dee9SAndroid Build Coastguard Worker direction.run(mutatorGroup, mctx) 3051*1fa6dee9SAndroid Build Coastguard Worker }() 3052*1fa6dee9SAndroid Build Coastguard Worker 3053*1fa6dee9SAndroid Build Coastguard Worker module.finishedMutator = mutatorGroup[len(mutatorGroup)-1].index 3054*1fa6dee9SAndroid Build Coastguard Worker 3055*1fa6dee9SAndroid Build Coastguard Worker if len(mctx.errs) > 0 { 3056*1fa6dee9SAndroid Build Coastguard Worker errsCh <- mctx.errs 3057*1fa6dee9SAndroid Build Coastguard Worker return true 3058*1fa6dee9SAndroid Build Coastguard Worker } 3059*1fa6dee9SAndroid Build Coastguard Worker 3060*1fa6dee9SAndroid Build Coastguard Worker if len(mctx.newVariations) > 0 { 3061*1fa6dee9SAndroid Build Coastguard Worker newVariationsCh <- newVariationPair{mctx.newVariations, origLogicModule} 3062*1fa6dee9SAndroid Build Coastguard Worker } 3063*1fa6dee9SAndroid Build Coastguard Worker 3064*1fa6dee9SAndroid Build Coastguard Worker if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 || len(mctx.newModules) > 0 || len(mctx.ninjaFileDeps) > 0 { 3065*1fa6dee9SAndroid Build Coastguard Worker globalStateCh <- globalStateChange{ 3066*1fa6dee9SAndroid Build Coastguard Worker reverse: mctx.reverseDeps, 3067*1fa6dee9SAndroid Build Coastguard Worker replace: mctx.replace, 3068*1fa6dee9SAndroid Build Coastguard Worker rename: mctx.rename, 3069*1fa6dee9SAndroid Build Coastguard Worker newModules: mctx.newModules, 3070*1fa6dee9SAndroid Build Coastguard Worker deps: mctx.ninjaFileDeps, 3071*1fa6dee9SAndroid Build Coastguard Worker } 3072*1fa6dee9SAndroid Build Coastguard Worker } 3073*1fa6dee9SAndroid Build Coastguard Worker 3074*1fa6dee9SAndroid Build Coastguard Worker return false 3075*1fa6dee9SAndroid Build Coastguard Worker } 3076*1fa6dee9SAndroid Build Coastguard Worker 3077*1fa6dee9SAndroid Build Coastguard Worker createdVariations := false 3078*1fa6dee9SAndroid Build Coastguard Worker var obsoleteLogicModules []Module 3079*1fa6dee9SAndroid Build Coastguard Worker 3080*1fa6dee9SAndroid Build Coastguard Worker // Process errs and reverseDeps in a single goroutine 3081*1fa6dee9SAndroid Build Coastguard Worker go func() { 3082*1fa6dee9SAndroid Build Coastguard Worker for { 3083*1fa6dee9SAndroid Build Coastguard Worker select { 3084*1fa6dee9SAndroid Build Coastguard Worker case newErrs := <-errsCh: 3085*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 3086*1fa6dee9SAndroid Build Coastguard Worker case globalStateChange := <-globalStateCh: 3087*1fa6dee9SAndroid Build Coastguard Worker for _, r := range globalStateChange.reverse { 3088*1fa6dee9SAndroid Build Coastguard Worker reverseDeps[r.module] = append(reverseDeps[r.module], r.dep) 3089*1fa6dee9SAndroid Build Coastguard Worker } 3090*1fa6dee9SAndroid Build Coastguard Worker replace = append(replace, globalStateChange.replace...) 3091*1fa6dee9SAndroid Build Coastguard Worker rename = append(rename, globalStateChange.rename...) 3092*1fa6dee9SAndroid Build Coastguard Worker newModules = append(newModules, globalStateChange.newModules...) 3093*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, globalStateChange.deps...) 3094*1fa6dee9SAndroid Build Coastguard Worker case newVariations := <-newVariationsCh: 3095*1fa6dee9SAndroid Build Coastguard Worker if newVariations.origLogicModule != newVariations.newVariations[0].logicModule { 3096*1fa6dee9SAndroid Build Coastguard Worker obsoleteLogicModules = append(obsoleteLogicModules, newVariations.origLogicModule) 3097*1fa6dee9SAndroid Build Coastguard Worker } 3098*1fa6dee9SAndroid Build Coastguard Worker for _, module := range newVariations.newVariations { 3099*1fa6dee9SAndroid Build Coastguard Worker newModuleInfo[module.logicModule] = module 3100*1fa6dee9SAndroid Build Coastguard Worker } 3101*1fa6dee9SAndroid Build Coastguard Worker createdVariations = true 3102*1fa6dee9SAndroid Build Coastguard Worker case <-done: 3103*1fa6dee9SAndroid Build Coastguard Worker return 3104*1fa6dee9SAndroid Build Coastguard Worker } 3105*1fa6dee9SAndroid Build Coastguard Worker } 3106*1fa6dee9SAndroid Build Coastguard Worker }() 3107*1fa6dee9SAndroid Build Coastguard Worker 3108*1fa6dee9SAndroid Build Coastguard Worker visitErrs := parallelVisit(c.iterateAllVariants(), direction.orderer(), parallelVisitLimit, visit) 3109*1fa6dee9SAndroid Build Coastguard Worker 3110*1fa6dee9SAndroid Build Coastguard Worker if len(visitErrs) > 0 { 3111*1fa6dee9SAndroid Build Coastguard Worker return nil, visitErrs 3112*1fa6dee9SAndroid Build Coastguard Worker } 3113*1fa6dee9SAndroid Build Coastguard Worker 3114*1fa6dee9SAndroid Build Coastguard Worker for _, mutator := range mutatorGroup { 3115*1fa6dee9SAndroid Build Coastguard Worker c.finishedMutators[mutator.index] = true 3116*1fa6dee9SAndroid Build Coastguard Worker } 3117*1fa6dee9SAndroid Build Coastguard Worker 3118*1fa6dee9SAndroid Build Coastguard Worker done <- true 3119*1fa6dee9SAndroid Build Coastguard Worker 3120*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 3121*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 3122*1fa6dee9SAndroid Build Coastguard Worker } 3123*1fa6dee9SAndroid Build Coastguard Worker 3124*1fa6dee9SAndroid Build Coastguard Worker for _, obsoleteLogicModule := range obsoleteLogicModules { 3125*1fa6dee9SAndroid Build Coastguard Worker delete(newModuleInfo, obsoleteLogicModule) 3126*1fa6dee9SAndroid Build Coastguard Worker } 3127*1fa6dee9SAndroid Build Coastguard Worker 3128*1fa6dee9SAndroid Build Coastguard Worker c.moduleInfo = newModuleInfo 3129*1fa6dee9SAndroid Build Coastguard Worker 3130*1fa6dee9SAndroid Build Coastguard Worker isTransitionMutator := mutatorGroup[0].transitionMutator != nil 3131*1fa6dee9SAndroid Build Coastguard Worker 3132*1fa6dee9SAndroid Build Coastguard Worker var transitionMutatorInputVariants map[*moduleGroup][]*moduleInfo 3133*1fa6dee9SAndroid Build Coastguard Worker if isTransitionMutator { 3134*1fa6dee9SAndroid Build Coastguard Worker transitionMutatorInputVariants = make(map[*moduleGroup][]*moduleInfo) 3135*1fa6dee9SAndroid Build Coastguard Worker } 3136*1fa6dee9SAndroid Build Coastguard Worker 3137*1fa6dee9SAndroid Build Coastguard Worker for _, group := range c.moduleGroups { 3138*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < len(group.modules); i++ { 3139*1fa6dee9SAndroid Build Coastguard Worker module := group.modules[i] 3140*1fa6dee9SAndroid Build Coastguard Worker 3141*1fa6dee9SAndroid Build Coastguard Worker // Update module group to contain newly split variants 3142*1fa6dee9SAndroid Build Coastguard Worker if module.splitModules != nil { 3143*1fa6dee9SAndroid Build Coastguard Worker if isTransitionMutator { 3144*1fa6dee9SAndroid Build Coastguard Worker // For transition mutators, save the pre-split variant for reusing later in applyTransitions. 3145*1fa6dee9SAndroid Build Coastguard Worker transitionMutatorInputVariants[group] = append(transitionMutatorInputVariants[group], module) 3146*1fa6dee9SAndroid Build Coastguard Worker } 3147*1fa6dee9SAndroid Build Coastguard Worker group.modules, i = spliceModules(group.modules, i, module.splitModules) 3148*1fa6dee9SAndroid Build Coastguard Worker } 3149*1fa6dee9SAndroid Build Coastguard Worker 3150*1fa6dee9SAndroid Build Coastguard Worker // Fix up any remaining dependencies on modules that were split into variants 3151*1fa6dee9SAndroid Build Coastguard Worker // by replacing them with the first variant 3152*1fa6dee9SAndroid Build Coastguard Worker for j, dep := range module.directDeps { 3153*1fa6dee9SAndroid Build Coastguard Worker if dep.module.obsoletedByNewVariants { 3154*1fa6dee9SAndroid Build Coastguard Worker module.directDeps[j].module = dep.module.splitModules.firstModule() 3155*1fa6dee9SAndroid Build Coastguard Worker } 3156*1fa6dee9SAndroid Build Coastguard Worker } 3157*1fa6dee9SAndroid Build Coastguard Worker 3158*1fa6dee9SAndroid Build Coastguard Worker if module.createdBy != nil && module.createdBy.obsoletedByNewVariants { 3159*1fa6dee9SAndroid Build Coastguard Worker module.createdBy = module.createdBy.splitModules.firstModule() 3160*1fa6dee9SAndroid Build Coastguard Worker } 3161*1fa6dee9SAndroid Build Coastguard Worker 3162*1fa6dee9SAndroid Build Coastguard Worker // Add any new forward dependencies to the reverse dependencies of the dependency to avoid 3163*1fa6dee9SAndroid Build Coastguard Worker // having to call a full c.updateDependencies(). 3164*1fa6dee9SAndroid Build Coastguard Worker for _, m := range module.newDirectDeps { 3165*1fa6dee9SAndroid Build Coastguard Worker m.reverseDeps = append(m.reverseDeps, module) 3166*1fa6dee9SAndroid Build Coastguard Worker } 3167*1fa6dee9SAndroid Build Coastguard Worker module.newDirectDeps = nil 3168*1fa6dee9SAndroid Build Coastguard Worker } 3169*1fa6dee9SAndroid Build Coastguard Worker } 3170*1fa6dee9SAndroid Build Coastguard Worker 3171*1fa6dee9SAndroid Build Coastguard Worker if isTransitionMutator { 3172*1fa6dee9SAndroid Build Coastguard Worker mutatorGroup[0].transitionMutator.inputVariants = transitionMutatorInputVariants 3173*1fa6dee9SAndroid Build Coastguard Worker mutatorGroup[0].transitionMutator.variantCreatingMutatorIndex = len(c.variantCreatingMutatorOrder) 3174*1fa6dee9SAndroid Build Coastguard Worker c.transitionMutators = append(c.transitionMutators, mutatorGroup[0].transitionMutator) 3175*1fa6dee9SAndroid Build Coastguard Worker } 3176*1fa6dee9SAndroid Build Coastguard Worker 3177*1fa6dee9SAndroid Build Coastguard Worker if createdVariations { 3178*1fa6dee9SAndroid Build Coastguard Worker c.variantCreatingMutatorOrder = append(c.variantCreatingMutatorOrder, mutatorGroup[0].name) 3179*1fa6dee9SAndroid Build Coastguard Worker } 3180*1fa6dee9SAndroid Build Coastguard Worker 3181*1fa6dee9SAndroid Build Coastguard Worker // Add in any new reverse dependencies that were added by the mutator 3182*1fa6dee9SAndroid Build Coastguard Worker for module, deps := range reverseDeps { 3183*1fa6dee9SAndroid Build Coastguard Worker sort.Sort(depSorter(deps)) 3184*1fa6dee9SAndroid Build Coastguard Worker module.directDeps = append(module.directDeps, deps...) 3185*1fa6dee9SAndroid Build Coastguard Worker c.needsUpdateDependencies++ 3186*1fa6dee9SAndroid Build Coastguard Worker } 3187*1fa6dee9SAndroid Build Coastguard Worker 3188*1fa6dee9SAndroid Build Coastguard Worker for _, module := range newModules { 3189*1fa6dee9SAndroid Build Coastguard Worker errs = c.addModule(module) 3190*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 3191*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 3192*1fa6dee9SAndroid Build Coastguard Worker } 3193*1fa6dee9SAndroid Build Coastguard Worker c.needsUpdateDependencies++ 3194*1fa6dee9SAndroid Build Coastguard Worker } 3195*1fa6dee9SAndroid Build Coastguard Worker 3196*1fa6dee9SAndroid Build Coastguard Worker errs = c.handleRenames(rename) 3197*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 3198*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 3199*1fa6dee9SAndroid Build Coastguard Worker } 3200*1fa6dee9SAndroid Build Coastguard Worker 3201*1fa6dee9SAndroid Build Coastguard Worker errs = c.handleReplacements(replace) 3202*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 3203*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 3204*1fa6dee9SAndroid Build Coastguard Worker } 3205*1fa6dee9SAndroid Build Coastguard Worker 3206*1fa6dee9SAndroid Build Coastguard Worker if c.needsUpdateDependencies > 0 { 3207*1fa6dee9SAndroid Build Coastguard Worker errs = c.updateDependencies() 3208*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 3209*1fa6dee9SAndroid Build Coastguard Worker return nil, errs 3210*1fa6dee9SAndroid Build Coastguard Worker } 3211*1fa6dee9SAndroid Build Coastguard Worker } 3212*1fa6dee9SAndroid Build Coastguard Worker 3213*1fa6dee9SAndroid Build Coastguard Worker return deps, errs 3214*1fa6dee9SAndroid Build Coastguard Worker} 3215*1fa6dee9SAndroid Build Coastguard Worker 3216*1fa6dee9SAndroid Build Coastguard Worker// clearTransitionMutatorInputVariants removes the inputVariants field from every 3217*1fa6dee9SAndroid Build Coastguard Worker// TransitionMutator now that all dependencies have been resolved. 3218*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) clearTransitionMutatorInputVariants() { 3219*1fa6dee9SAndroid Build Coastguard Worker for _, mutator := range c.transitionMutators { 3220*1fa6dee9SAndroid Build Coastguard Worker mutator.inputVariants = nil 3221*1fa6dee9SAndroid Build Coastguard Worker } 3222*1fa6dee9SAndroid Build Coastguard Worker} 3223*1fa6dee9SAndroid Build Coastguard Worker 3224*1fa6dee9SAndroid Build Coastguard Worker// Replaces every build logic module with a clone of itself. Prevents introducing problems where 3225*1fa6dee9SAndroid Build Coastguard Worker// a mutator sets a non-property member variable on a module, which works until a later mutator 3226*1fa6dee9SAndroid Build Coastguard Worker// creates variants of that module. 3227*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) cloneModules() { 3228*1fa6dee9SAndroid Build Coastguard Worker type update struct { 3229*1fa6dee9SAndroid Build Coastguard Worker orig Module 3230*1fa6dee9SAndroid Build Coastguard Worker clone *moduleInfo 3231*1fa6dee9SAndroid Build Coastguard Worker } 3232*1fa6dee9SAndroid Build Coastguard Worker ch := make(chan update) 3233*1fa6dee9SAndroid Build Coastguard Worker doneCh := make(chan bool) 3234*1fa6dee9SAndroid Build Coastguard Worker go func() { 3235*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(c.iterateAllVariants(), unorderedVisitorImpl{}, parallelVisitLimit, 3236*1fa6dee9SAndroid Build Coastguard Worker func(m *moduleInfo, pause chan<- pauseSpec) bool { 3237*1fa6dee9SAndroid Build Coastguard Worker origLogicModule := m.logicModule 3238*1fa6dee9SAndroid Build Coastguard Worker m.logicModule, m.properties = c.cloneLogicModule(m) 3239*1fa6dee9SAndroid Build Coastguard Worker ch <- update{origLogicModule, m} 3240*1fa6dee9SAndroid Build Coastguard Worker return false 3241*1fa6dee9SAndroid Build Coastguard Worker }) 3242*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 3243*1fa6dee9SAndroid Build Coastguard Worker panic(errs) 3244*1fa6dee9SAndroid Build Coastguard Worker } 3245*1fa6dee9SAndroid Build Coastguard Worker doneCh <- true 3246*1fa6dee9SAndroid Build Coastguard Worker }() 3247*1fa6dee9SAndroid Build Coastguard Worker 3248*1fa6dee9SAndroid Build Coastguard Worker done := false 3249*1fa6dee9SAndroid Build Coastguard Worker for !done { 3250*1fa6dee9SAndroid Build Coastguard Worker select { 3251*1fa6dee9SAndroid Build Coastguard Worker case <-doneCh: 3252*1fa6dee9SAndroid Build Coastguard Worker done = true 3253*1fa6dee9SAndroid Build Coastguard Worker case update := <-ch: 3254*1fa6dee9SAndroid Build Coastguard Worker delete(c.moduleInfo, update.orig) 3255*1fa6dee9SAndroid Build Coastguard Worker c.moduleInfo[update.clone.logicModule] = update.clone 3256*1fa6dee9SAndroid Build Coastguard Worker } 3257*1fa6dee9SAndroid Build Coastguard Worker } 3258*1fa6dee9SAndroid Build Coastguard Worker} 3259*1fa6dee9SAndroid Build Coastguard Worker 3260*1fa6dee9SAndroid Build Coastguard Worker// Removes modules[i] from the list and inserts newModules... where it was located, returning 3261*1fa6dee9SAndroid Build Coastguard Worker// the new slice and the index of the last inserted element 3262*1fa6dee9SAndroid Build Coastguard Workerfunc spliceModules(modules moduleList, i int, newModules moduleList) (moduleList, int) { 3263*1fa6dee9SAndroid Build Coastguard Worker spliceSize := len(newModules) 3264*1fa6dee9SAndroid Build Coastguard Worker newLen := len(modules) + spliceSize - 1 3265*1fa6dee9SAndroid Build Coastguard Worker var dest moduleList 3266*1fa6dee9SAndroid Build Coastguard Worker if cap(modules) >= len(modules)-1+len(newModules) { 3267*1fa6dee9SAndroid Build Coastguard Worker // We can fit the splice in the existing capacity, do everything in place 3268*1fa6dee9SAndroid Build Coastguard Worker dest = modules[:newLen] 3269*1fa6dee9SAndroid Build Coastguard Worker } else { 3270*1fa6dee9SAndroid Build Coastguard Worker dest = make(moduleList, newLen) 3271*1fa6dee9SAndroid Build Coastguard Worker copy(dest, modules[:i]) 3272*1fa6dee9SAndroid Build Coastguard Worker } 3273*1fa6dee9SAndroid Build Coastguard Worker 3274*1fa6dee9SAndroid Build Coastguard Worker // Move the end of the slice over by spliceSize-1 3275*1fa6dee9SAndroid Build Coastguard Worker copy(dest[i+spliceSize:], modules[i+1:]) 3276*1fa6dee9SAndroid Build Coastguard Worker 3277*1fa6dee9SAndroid Build Coastguard Worker // Copy the new modules into the slice 3278*1fa6dee9SAndroid Build Coastguard Worker copy(dest[i:], newModules) 3279*1fa6dee9SAndroid Build Coastguard Worker 3280*1fa6dee9SAndroid Build Coastguard Worker return dest, i + spliceSize - 1 3281*1fa6dee9SAndroid Build Coastguard Worker} 3282*1fa6dee9SAndroid Build Coastguard Worker 3283*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) generateModuleBuildActions(config interface{}, 3284*1fa6dee9SAndroid Build Coastguard Worker liveGlobals *liveTracker) ([]string, []error) { 3285*1fa6dee9SAndroid Build Coastguard Worker 3286*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("generateModuleBuildActions") 3287*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("generateModuleBuildActions") 3288*1fa6dee9SAndroid Build Coastguard Worker var deps []string 3289*1fa6dee9SAndroid Build Coastguard Worker var errs []error 3290*1fa6dee9SAndroid Build Coastguard Worker 3291*1fa6dee9SAndroid Build Coastguard Worker cancelCh := make(chan struct{}) 3292*1fa6dee9SAndroid Build Coastguard Worker errsCh := make(chan []error) 3293*1fa6dee9SAndroid Build Coastguard Worker depsCh := make(chan []string) 3294*1fa6dee9SAndroid Build Coastguard Worker 3295*1fa6dee9SAndroid Build Coastguard Worker go func() { 3296*1fa6dee9SAndroid Build Coastguard Worker for { 3297*1fa6dee9SAndroid Build Coastguard Worker select { 3298*1fa6dee9SAndroid Build Coastguard Worker case <-cancelCh: 3299*1fa6dee9SAndroid Build Coastguard Worker close(cancelCh) 3300*1fa6dee9SAndroid Build Coastguard Worker return 3301*1fa6dee9SAndroid Build Coastguard Worker case newErrs := <-errsCh: 3302*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 3303*1fa6dee9SAndroid Build Coastguard Worker case newDeps := <-depsCh: 3304*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, newDeps...) 3305*1fa6dee9SAndroid Build Coastguard Worker 3306*1fa6dee9SAndroid Build Coastguard Worker } 3307*1fa6dee9SAndroid Build Coastguard Worker } 3308*1fa6dee9SAndroid Build Coastguard Worker }() 3309*1fa6dee9SAndroid Build Coastguard Worker 3310*1fa6dee9SAndroid Build Coastguard Worker visitErrs := parallelVisit(c.iterateAllVariants(), bottomUpVisitor, parallelVisitLimit, 3311*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 3312*1fa6dee9SAndroid Build Coastguard Worker uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name) 3313*1fa6dee9SAndroid Build Coastguard Worker sanitizedName := toNinjaName(uniqueName) 3314*1fa6dee9SAndroid Build Coastguard Worker sanitizedVariant := toNinjaName(module.variant.name) 3315*1fa6dee9SAndroid Build Coastguard Worker 3316*1fa6dee9SAndroid Build Coastguard Worker prefix := moduleNamespacePrefix(sanitizedName + "_" + sanitizedVariant) 3317*1fa6dee9SAndroid Build Coastguard Worker 3318*1fa6dee9SAndroid Build Coastguard Worker // The parent scope of the moduleContext's local scope gets overridden to be that of the 3319*1fa6dee9SAndroid Build Coastguard Worker // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we 3320*1fa6dee9SAndroid Build Coastguard Worker // just set it to nil. 3321*1fa6dee9SAndroid Build Coastguard Worker scope := newLocalScope(nil, prefix) 3322*1fa6dee9SAndroid Build Coastguard Worker 3323*1fa6dee9SAndroid Build Coastguard Worker mctx := &moduleContext{ 3324*1fa6dee9SAndroid Build Coastguard Worker baseModuleContext: baseModuleContext{ 3325*1fa6dee9SAndroid Build Coastguard Worker context: c, 3326*1fa6dee9SAndroid Build Coastguard Worker config: config, 3327*1fa6dee9SAndroid Build Coastguard Worker module: module, 3328*1fa6dee9SAndroid Build Coastguard Worker }, 3329*1fa6dee9SAndroid Build Coastguard Worker scope: scope, 3330*1fa6dee9SAndroid Build Coastguard Worker handledMissingDeps: module.missingDeps == nil, 3331*1fa6dee9SAndroid Build Coastguard Worker } 3332*1fa6dee9SAndroid Build Coastguard Worker 3333*1fa6dee9SAndroid Build Coastguard Worker mctx.module.startedGenerateBuildActions = true 3334*1fa6dee9SAndroid Build Coastguard Worker 3335*1fa6dee9SAndroid Build Coastguard Worker func() { 3336*1fa6dee9SAndroid Build Coastguard Worker defer func() { 3337*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 3338*1fa6dee9SAndroid Build Coastguard Worker in := fmt.Sprintf("GenerateBuildActions for %s", module) 3339*1fa6dee9SAndroid Build Coastguard Worker if err, ok := r.(panicError); ok { 3340*1fa6dee9SAndroid Build Coastguard Worker err.addIn(in) 3341*1fa6dee9SAndroid Build Coastguard Worker mctx.error(err) 3342*1fa6dee9SAndroid Build Coastguard Worker } else { 3343*1fa6dee9SAndroid Build Coastguard Worker mctx.error(newPanicErrorf(r, in)) 3344*1fa6dee9SAndroid Build Coastguard Worker } 3345*1fa6dee9SAndroid Build Coastguard Worker } 3346*1fa6dee9SAndroid Build Coastguard Worker }() 3347*1fa6dee9SAndroid Build Coastguard Worker restored, cacheKey := mctx.restoreModuleBuildActions() 3348*1fa6dee9SAndroid Build Coastguard Worker if !restored { 3349*1fa6dee9SAndroid Build Coastguard Worker mctx.module.logicModule.GenerateBuildActions(mctx) 3350*1fa6dee9SAndroid Build Coastguard Worker } 3351*1fa6dee9SAndroid Build Coastguard Worker if cacheKey != nil { 3352*1fa6dee9SAndroid Build Coastguard Worker mctx.cacheModuleBuildActions(cacheKey) 3353*1fa6dee9SAndroid Build Coastguard Worker } 3354*1fa6dee9SAndroid Build Coastguard Worker }() 3355*1fa6dee9SAndroid Build Coastguard Worker 3356*1fa6dee9SAndroid Build Coastguard Worker mctx.module.finishedGenerateBuildActions = true 3357*1fa6dee9SAndroid Build Coastguard Worker 3358*1fa6dee9SAndroid Build Coastguard Worker if len(mctx.errs) > 0 { 3359*1fa6dee9SAndroid Build Coastguard Worker errsCh <- mctx.errs 3360*1fa6dee9SAndroid Build Coastguard Worker return true 3361*1fa6dee9SAndroid Build Coastguard Worker } 3362*1fa6dee9SAndroid Build Coastguard Worker 3363*1fa6dee9SAndroid Build Coastguard Worker if module.missingDeps != nil && !mctx.handledMissingDeps { 3364*1fa6dee9SAndroid Build Coastguard Worker var errs []error 3365*1fa6dee9SAndroid Build Coastguard Worker for _, depName := range module.missingDeps { 3366*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, c.missingDependencyError(module, depName)) 3367*1fa6dee9SAndroid Build Coastguard Worker } 3368*1fa6dee9SAndroid Build Coastguard Worker errsCh <- errs 3369*1fa6dee9SAndroid Build Coastguard Worker return true 3370*1fa6dee9SAndroid Build Coastguard Worker } 3371*1fa6dee9SAndroid Build Coastguard Worker 3372*1fa6dee9SAndroid Build Coastguard Worker depsCh <- mctx.ninjaFileDeps 3373*1fa6dee9SAndroid Build Coastguard Worker 3374*1fa6dee9SAndroid Build Coastguard Worker newErrs := c.processLocalBuildActions(&module.actionDefs, 3375*1fa6dee9SAndroid Build Coastguard Worker &mctx.actionDefs, liveGlobals) 3376*1fa6dee9SAndroid Build Coastguard Worker if len(newErrs) > 0 { 3377*1fa6dee9SAndroid Build Coastguard Worker errsCh <- newErrs 3378*1fa6dee9SAndroid Build Coastguard Worker return true 3379*1fa6dee9SAndroid Build Coastguard Worker } 3380*1fa6dee9SAndroid Build Coastguard Worker return false 3381*1fa6dee9SAndroid Build Coastguard Worker }) 3382*1fa6dee9SAndroid Build Coastguard Worker 3383*1fa6dee9SAndroid Build Coastguard Worker cancelCh <- struct{}{} 3384*1fa6dee9SAndroid Build Coastguard Worker <-cancelCh 3385*1fa6dee9SAndroid Build Coastguard Worker 3386*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, visitErrs...) 3387*1fa6dee9SAndroid Build Coastguard Worker 3388*1fa6dee9SAndroid Build Coastguard Worker return deps, errs 3389*1fa6dee9SAndroid Build Coastguard Worker} 3390*1fa6dee9SAndroid Build Coastguard Worker 3391*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) generateOneSingletonBuildActions(config interface{}, 3392*1fa6dee9SAndroid Build Coastguard Worker info *singletonInfo, liveGlobals *liveTracker) ([]string, []error) { 3393*1fa6dee9SAndroid Build Coastguard Worker 3394*1fa6dee9SAndroid Build Coastguard Worker var deps []string 3395*1fa6dee9SAndroid Build Coastguard Worker var errs []error 3396*1fa6dee9SAndroid Build Coastguard Worker 3397*1fa6dee9SAndroid Build Coastguard Worker // The parent scope of the singletonContext's local scope gets overridden to be that of the 3398*1fa6dee9SAndroid Build Coastguard Worker // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we 3399*1fa6dee9SAndroid Build Coastguard Worker // just set it to nil. 3400*1fa6dee9SAndroid Build Coastguard Worker scope := newLocalScope(nil, singletonNamespacePrefix(info.name)) 3401*1fa6dee9SAndroid Build Coastguard Worker 3402*1fa6dee9SAndroid Build Coastguard Worker sctx := &singletonContext{ 3403*1fa6dee9SAndroid Build Coastguard Worker name: info.name, 3404*1fa6dee9SAndroid Build Coastguard Worker context: c, 3405*1fa6dee9SAndroid Build Coastguard Worker config: config, 3406*1fa6dee9SAndroid Build Coastguard Worker scope: scope, 3407*1fa6dee9SAndroid Build Coastguard Worker globals: liveGlobals, 3408*1fa6dee9SAndroid Build Coastguard Worker } 3409*1fa6dee9SAndroid Build Coastguard Worker 3410*1fa6dee9SAndroid Build Coastguard Worker func() { 3411*1fa6dee9SAndroid Build Coastguard Worker defer func() { 3412*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 3413*1fa6dee9SAndroid Build Coastguard Worker in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name) 3414*1fa6dee9SAndroid Build Coastguard Worker if err, ok := r.(panicError); ok { 3415*1fa6dee9SAndroid Build Coastguard Worker err.addIn(in) 3416*1fa6dee9SAndroid Build Coastguard Worker sctx.error(err) 3417*1fa6dee9SAndroid Build Coastguard Worker } else { 3418*1fa6dee9SAndroid Build Coastguard Worker sctx.error(newPanicErrorf(r, in)) 3419*1fa6dee9SAndroid Build Coastguard Worker } 3420*1fa6dee9SAndroid Build Coastguard Worker } 3421*1fa6dee9SAndroid Build Coastguard Worker }() 3422*1fa6dee9SAndroid Build Coastguard Worker info.singleton.GenerateBuildActions(sctx) 3423*1fa6dee9SAndroid Build Coastguard Worker }() 3424*1fa6dee9SAndroid Build Coastguard Worker 3425*1fa6dee9SAndroid Build Coastguard Worker if len(sctx.errs) > 0 { 3426*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, sctx.errs...) 3427*1fa6dee9SAndroid Build Coastguard Worker return deps, errs 3428*1fa6dee9SAndroid Build Coastguard Worker } 3429*1fa6dee9SAndroid Build Coastguard Worker 3430*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, sctx.ninjaFileDeps...) 3431*1fa6dee9SAndroid Build Coastguard Worker 3432*1fa6dee9SAndroid Build Coastguard Worker newErrs := c.processLocalBuildActions(&info.actionDefs, 3433*1fa6dee9SAndroid Build Coastguard Worker &sctx.actionDefs, liveGlobals) 3434*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 3435*1fa6dee9SAndroid Build Coastguard Worker return deps, errs 3436*1fa6dee9SAndroid Build Coastguard Worker} 3437*1fa6dee9SAndroid Build Coastguard Worker 3438*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) generateParallelSingletonBuildActions(config interface{}, 3439*1fa6dee9SAndroid Build Coastguard Worker singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) { 3440*1fa6dee9SAndroid Build Coastguard Worker 3441*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("generateParallelSingletonBuildActions") 3442*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("generateParallelSingletonBuildActions") 3443*1fa6dee9SAndroid Build Coastguard Worker 3444*1fa6dee9SAndroid Build Coastguard Worker var deps []string 3445*1fa6dee9SAndroid Build Coastguard Worker var errs []error 3446*1fa6dee9SAndroid Build Coastguard Worker 3447*1fa6dee9SAndroid Build Coastguard Worker wg := sync.WaitGroup{} 3448*1fa6dee9SAndroid Build Coastguard Worker cancelCh := make(chan struct{}) 3449*1fa6dee9SAndroid Build Coastguard Worker depsCh := make(chan []string) 3450*1fa6dee9SAndroid Build Coastguard Worker errsCh := make(chan []error) 3451*1fa6dee9SAndroid Build Coastguard Worker 3452*1fa6dee9SAndroid Build Coastguard Worker go func() { 3453*1fa6dee9SAndroid Build Coastguard Worker for { 3454*1fa6dee9SAndroid Build Coastguard Worker select { 3455*1fa6dee9SAndroid Build Coastguard Worker case <-cancelCh: 3456*1fa6dee9SAndroid Build Coastguard Worker close(cancelCh) 3457*1fa6dee9SAndroid Build Coastguard Worker return 3458*1fa6dee9SAndroid Build Coastguard Worker case dep := <-depsCh: 3459*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, dep...) 3460*1fa6dee9SAndroid Build Coastguard Worker case newErrs := <-errsCh: 3461*1fa6dee9SAndroid Build Coastguard Worker if len(errs) <= maxErrors { 3462*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 3463*1fa6dee9SAndroid Build Coastguard Worker } 3464*1fa6dee9SAndroid Build Coastguard Worker } 3465*1fa6dee9SAndroid Build Coastguard Worker } 3466*1fa6dee9SAndroid Build Coastguard Worker }() 3467*1fa6dee9SAndroid Build Coastguard Worker 3468*1fa6dee9SAndroid Build Coastguard Worker for _, info := range singletons { 3469*1fa6dee9SAndroid Build Coastguard Worker if !info.parallel { 3470*1fa6dee9SAndroid Build Coastguard Worker // Skip any singletons registered with parallel=false. 3471*1fa6dee9SAndroid Build Coastguard Worker continue 3472*1fa6dee9SAndroid Build Coastguard Worker } 3473*1fa6dee9SAndroid Build Coastguard Worker wg.Add(1) 3474*1fa6dee9SAndroid Build Coastguard Worker go func(inf *singletonInfo) { 3475*1fa6dee9SAndroid Build Coastguard Worker defer wg.Done() 3476*1fa6dee9SAndroid Build Coastguard Worker newDeps, newErrs := c.generateOneSingletonBuildActions(config, inf, liveGlobals) 3477*1fa6dee9SAndroid Build Coastguard Worker depsCh <- newDeps 3478*1fa6dee9SAndroid Build Coastguard Worker errsCh <- newErrs 3479*1fa6dee9SAndroid Build Coastguard Worker }(info) 3480*1fa6dee9SAndroid Build Coastguard Worker } 3481*1fa6dee9SAndroid Build Coastguard Worker wg.Wait() 3482*1fa6dee9SAndroid Build Coastguard Worker 3483*1fa6dee9SAndroid Build Coastguard Worker cancelCh <- struct{}{} 3484*1fa6dee9SAndroid Build Coastguard Worker <-cancelCh 3485*1fa6dee9SAndroid Build Coastguard Worker 3486*1fa6dee9SAndroid Build Coastguard Worker return deps, errs 3487*1fa6dee9SAndroid Build Coastguard Worker} 3488*1fa6dee9SAndroid Build Coastguard Worker 3489*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) generateSingletonBuildActions(config interface{}, 3490*1fa6dee9SAndroid Build Coastguard Worker singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) { 3491*1fa6dee9SAndroid Build Coastguard Worker 3492*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("generateSingletonBuildActions") 3493*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("generateSingletonBuildActions") 3494*1fa6dee9SAndroid Build Coastguard Worker 3495*1fa6dee9SAndroid Build Coastguard Worker var deps []string 3496*1fa6dee9SAndroid Build Coastguard Worker var errs []error 3497*1fa6dee9SAndroid Build Coastguard Worker 3498*1fa6dee9SAndroid Build Coastguard Worker // Run one singleton. Use a variable to simplify manual validation testing. 3499*1fa6dee9SAndroid Build Coastguard Worker var runSingleton = func(info *singletonInfo) { 3500*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("singleton:" + info.name) 3501*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("singleton:" + info.name) 3502*1fa6dee9SAndroid Build Coastguard Worker newDeps, newErrs := c.generateOneSingletonBuildActions(config, info, liveGlobals) 3503*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, newDeps...) 3504*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, newErrs...) 3505*1fa6dee9SAndroid Build Coastguard Worker } 3506*1fa6dee9SAndroid Build Coastguard Worker 3507*1fa6dee9SAndroid Build Coastguard Worker // Force a resort of the module groups before running singletons so that two singletons running in parallel 3508*1fa6dee9SAndroid Build Coastguard Worker // don't cause a data race when they trigger a resort in VisitAllModules. 3509*1fa6dee9SAndroid Build Coastguard Worker c.sortedModuleGroups() 3510*1fa6dee9SAndroid Build Coastguard Worker 3511*1fa6dee9SAndroid Build Coastguard Worker // First, take care of any singletons that want to run in parallel. 3512*1fa6dee9SAndroid Build Coastguard Worker deps, errs = c.generateParallelSingletonBuildActions(config, singletons, liveGlobals) 3513*1fa6dee9SAndroid Build Coastguard Worker 3514*1fa6dee9SAndroid Build Coastguard Worker for _, info := range singletons { 3515*1fa6dee9SAndroid Build Coastguard Worker if !info.parallel { 3516*1fa6dee9SAndroid Build Coastguard Worker runSingleton(info) 3517*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > maxErrors { 3518*1fa6dee9SAndroid Build Coastguard Worker break 3519*1fa6dee9SAndroid Build Coastguard Worker } 3520*1fa6dee9SAndroid Build Coastguard Worker } 3521*1fa6dee9SAndroid Build Coastguard Worker } 3522*1fa6dee9SAndroid Build Coastguard Worker 3523*1fa6dee9SAndroid Build Coastguard Worker return deps, errs 3524*1fa6dee9SAndroid Build Coastguard Worker} 3525*1fa6dee9SAndroid Build Coastguard Worker 3526*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) processLocalBuildActions(out, in *localBuildActions, 3527*1fa6dee9SAndroid Build Coastguard Worker liveGlobals *liveTracker) []error { 3528*1fa6dee9SAndroid Build Coastguard Worker 3529*1fa6dee9SAndroid Build Coastguard Worker var errs []error 3530*1fa6dee9SAndroid Build Coastguard Worker 3531*1fa6dee9SAndroid Build Coastguard Worker // First we go through and add everything referenced by the module's 3532*1fa6dee9SAndroid Build Coastguard Worker // buildDefs to the live globals set. This will end up adding the live 3533*1fa6dee9SAndroid Build Coastguard Worker // locals to the set as well, but we'll take them out after. 3534*1fa6dee9SAndroid Build Coastguard Worker for _, def := range in.buildDefs { 3535*1fa6dee9SAndroid Build Coastguard Worker err := liveGlobals.AddBuildDefDeps(def) 3536*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 3537*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, err) 3538*1fa6dee9SAndroid Build Coastguard Worker } 3539*1fa6dee9SAndroid Build Coastguard Worker } 3540*1fa6dee9SAndroid Build Coastguard Worker 3541*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 3542*1fa6dee9SAndroid Build Coastguard Worker return errs 3543*1fa6dee9SAndroid Build Coastguard Worker } 3544*1fa6dee9SAndroid Build Coastguard Worker 3545*1fa6dee9SAndroid Build Coastguard Worker out.buildDefs = append(out.buildDefs, in.buildDefs...) 3546*1fa6dee9SAndroid Build Coastguard Worker 3547*1fa6dee9SAndroid Build Coastguard Worker // We use the now-incorrect set of live "globals" to determine which local 3548*1fa6dee9SAndroid Build Coastguard Worker // definitions are live. As we go through copying those live locals to the 3549*1fa6dee9SAndroid Build Coastguard Worker // moduleGroup we remove them from the live globals set. 3550*1fa6dee9SAndroid Build Coastguard Worker for _, v := range in.variables { 3551*1fa6dee9SAndroid Build Coastguard Worker isLive := liveGlobals.RemoveVariableIfLive(v) 3552*1fa6dee9SAndroid Build Coastguard Worker if isLive { 3553*1fa6dee9SAndroid Build Coastguard Worker out.variables = append(out.variables, v) 3554*1fa6dee9SAndroid Build Coastguard Worker } 3555*1fa6dee9SAndroid Build Coastguard Worker } 3556*1fa6dee9SAndroid Build Coastguard Worker 3557*1fa6dee9SAndroid Build Coastguard Worker for _, r := range in.rules { 3558*1fa6dee9SAndroid Build Coastguard Worker isLive := liveGlobals.RemoveRuleIfLive(r) 3559*1fa6dee9SAndroid Build Coastguard Worker if isLive { 3560*1fa6dee9SAndroid Build Coastguard Worker out.rules = append(out.rules, r) 3561*1fa6dee9SAndroid Build Coastguard Worker } 3562*1fa6dee9SAndroid Build Coastguard Worker } 3563*1fa6dee9SAndroid Build Coastguard Worker 3564*1fa6dee9SAndroid Build Coastguard Worker return nil 3565*1fa6dee9SAndroid Build Coastguard Worker} 3566*1fa6dee9SAndroid Build Coastguard Worker 3567*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) walkDeps(topModule *moduleInfo, allowDuplicates bool, 3568*1fa6dee9SAndroid Build Coastguard Worker visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) { 3569*1fa6dee9SAndroid Build Coastguard Worker 3570*1fa6dee9SAndroid Build Coastguard Worker visited := make(map[*moduleInfo]bool) 3571*1fa6dee9SAndroid Build Coastguard Worker var visiting *moduleInfo 3572*1fa6dee9SAndroid Build Coastguard Worker 3573*1fa6dee9SAndroid Build Coastguard Worker defer func() { 3574*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 3575*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s", 3576*1fa6dee9SAndroid Build Coastguard Worker topModule, funcName(visitDown), funcName(visitUp), visiting)) 3577*1fa6dee9SAndroid Build Coastguard Worker } 3578*1fa6dee9SAndroid Build Coastguard Worker }() 3579*1fa6dee9SAndroid Build Coastguard Worker 3580*1fa6dee9SAndroid Build Coastguard Worker var walk func(module *moduleInfo) 3581*1fa6dee9SAndroid Build Coastguard Worker walk = func(module *moduleInfo) { 3582*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range module.directDeps { 3583*1fa6dee9SAndroid Build Coastguard Worker if allowDuplicates || !visited[dep.module] { 3584*1fa6dee9SAndroid Build Coastguard Worker visiting = dep.module 3585*1fa6dee9SAndroid Build Coastguard Worker recurse := true 3586*1fa6dee9SAndroid Build Coastguard Worker if visitDown != nil { 3587*1fa6dee9SAndroid Build Coastguard Worker recurse = visitDown(dep, module) 3588*1fa6dee9SAndroid Build Coastguard Worker } 3589*1fa6dee9SAndroid Build Coastguard Worker if recurse && !visited[dep.module] { 3590*1fa6dee9SAndroid Build Coastguard Worker walk(dep.module) 3591*1fa6dee9SAndroid Build Coastguard Worker visited[dep.module] = true 3592*1fa6dee9SAndroid Build Coastguard Worker } 3593*1fa6dee9SAndroid Build Coastguard Worker if visitUp != nil { 3594*1fa6dee9SAndroid Build Coastguard Worker visitUp(dep, module) 3595*1fa6dee9SAndroid Build Coastguard Worker } 3596*1fa6dee9SAndroid Build Coastguard Worker } 3597*1fa6dee9SAndroid Build Coastguard Worker } 3598*1fa6dee9SAndroid Build Coastguard Worker } 3599*1fa6dee9SAndroid Build Coastguard Worker 3600*1fa6dee9SAndroid Build Coastguard Worker walk(topModule) 3601*1fa6dee9SAndroid Build Coastguard Worker} 3602*1fa6dee9SAndroid Build Coastguard Worker 3603*1fa6dee9SAndroid Build Coastguard Workertype replace struct { 3604*1fa6dee9SAndroid Build Coastguard Worker from, to *moduleInfo 3605*1fa6dee9SAndroid Build Coastguard Worker predicate ReplaceDependencyPredicate 3606*1fa6dee9SAndroid Build Coastguard Worker} 3607*1fa6dee9SAndroid Build Coastguard Worker 3608*1fa6dee9SAndroid Build Coastguard Workertype rename struct { 3609*1fa6dee9SAndroid Build Coastguard Worker group *moduleGroup 3610*1fa6dee9SAndroid Build Coastguard Worker name string 3611*1fa6dee9SAndroid Build Coastguard Worker} 3612*1fa6dee9SAndroid Build Coastguard Worker 3613*1fa6dee9SAndroid Build Coastguard Worker// moduleVariantsThatDependOn takes the name of a module and a dependency and returns the all the variants of the 3614*1fa6dee9SAndroid Build Coastguard Worker// module that depends on the dependency. 3615*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) moduleVariantsThatDependOn(name string, dep *moduleInfo) []*moduleInfo { 3616*1fa6dee9SAndroid Build Coastguard Worker group := c.moduleGroupFromName(name, dep.namespace()) 3617*1fa6dee9SAndroid Build Coastguard Worker var variants []*moduleInfo 3618*1fa6dee9SAndroid Build Coastguard Worker 3619*1fa6dee9SAndroid Build Coastguard Worker if group == nil { 3620*1fa6dee9SAndroid Build Coastguard Worker return nil 3621*1fa6dee9SAndroid Build Coastguard Worker } 3622*1fa6dee9SAndroid Build Coastguard Worker 3623*1fa6dee9SAndroid Build Coastguard Worker for _, m := range group.modules { 3624*1fa6dee9SAndroid Build Coastguard Worker for _, moduleDep := range m.directDeps { 3625*1fa6dee9SAndroid Build Coastguard Worker if moduleDep.module == dep { 3626*1fa6dee9SAndroid Build Coastguard Worker variants = append(variants, m) 3627*1fa6dee9SAndroid Build Coastguard Worker } 3628*1fa6dee9SAndroid Build Coastguard Worker } 3629*1fa6dee9SAndroid Build Coastguard Worker } 3630*1fa6dee9SAndroid Build Coastguard Worker 3631*1fa6dee9SAndroid Build Coastguard Worker return variants 3632*1fa6dee9SAndroid Build Coastguard Worker} 3633*1fa6dee9SAndroid Build Coastguard Worker 3634*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) handleRenames(renames []rename) []error { 3635*1fa6dee9SAndroid Build Coastguard Worker var errs []error 3636*1fa6dee9SAndroid Build Coastguard Worker for _, rename := range renames { 3637*1fa6dee9SAndroid Build Coastguard Worker group, name := rename.group, rename.name 3638*1fa6dee9SAndroid Build Coastguard Worker if name == group.name || len(group.modules) < 1 { 3639*1fa6dee9SAndroid Build Coastguard Worker continue 3640*1fa6dee9SAndroid Build Coastguard Worker } 3641*1fa6dee9SAndroid Build Coastguard Worker 3642*1fa6dee9SAndroid Build Coastguard Worker errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...) 3643*1fa6dee9SAndroid Build Coastguard Worker } 3644*1fa6dee9SAndroid Build Coastguard Worker 3645*1fa6dee9SAndroid Build Coastguard Worker return errs 3646*1fa6dee9SAndroid Build Coastguard Worker} 3647*1fa6dee9SAndroid Build Coastguard Worker 3648*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) handleReplacements(replacements []replace) []error { 3649*1fa6dee9SAndroid Build Coastguard Worker var errs []error 3650*1fa6dee9SAndroid Build Coastguard Worker changedDeps := false 3651*1fa6dee9SAndroid Build Coastguard Worker for _, replace := range replacements { 3652*1fa6dee9SAndroid Build Coastguard Worker for _, m := range replace.from.reverseDeps { 3653*1fa6dee9SAndroid Build Coastguard Worker for i, d := range m.directDeps { 3654*1fa6dee9SAndroid Build Coastguard Worker if d.module == replace.from { 3655*1fa6dee9SAndroid Build Coastguard Worker // If the replacement has a predicate then check it. 3656*1fa6dee9SAndroid Build Coastguard Worker if replace.predicate == nil || replace.predicate(m.logicModule, d.tag, d.module.logicModule) { 3657*1fa6dee9SAndroid Build Coastguard Worker m.directDeps[i].module = replace.to 3658*1fa6dee9SAndroid Build Coastguard Worker changedDeps = true 3659*1fa6dee9SAndroid Build Coastguard Worker } 3660*1fa6dee9SAndroid Build Coastguard Worker } 3661*1fa6dee9SAndroid Build Coastguard Worker } 3662*1fa6dee9SAndroid Build Coastguard Worker } 3663*1fa6dee9SAndroid Build Coastguard Worker 3664*1fa6dee9SAndroid Build Coastguard Worker } 3665*1fa6dee9SAndroid Build Coastguard Worker 3666*1fa6dee9SAndroid Build Coastguard Worker if changedDeps { 3667*1fa6dee9SAndroid Build Coastguard Worker c.needsUpdateDependencies++ 3668*1fa6dee9SAndroid Build Coastguard Worker } 3669*1fa6dee9SAndroid Build Coastguard Worker return errs 3670*1fa6dee9SAndroid Build Coastguard Worker} 3671*1fa6dee9SAndroid Build Coastguard Worker 3672*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string, depVariations variationMap) (errs []error) { 3673*1fa6dee9SAndroid Build Coastguard Worker if !depVariations.empty() { 3674*1fa6dee9SAndroid Build Coastguard Worker depName = depName + "{" + c.prettyPrintVariant(depVariations) + "}" 3675*1fa6dee9SAndroid Build Coastguard Worker } 3676*1fa6dee9SAndroid Build Coastguard Worker if c.allowMissingDependencies { 3677*1fa6dee9SAndroid Build Coastguard Worker module.missingDeps = append(module.missingDeps, depName) 3678*1fa6dee9SAndroid Build Coastguard Worker return nil 3679*1fa6dee9SAndroid Build Coastguard Worker } 3680*1fa6dee9SAndroid Build Coastguard Worker return []error{c.missingDependencyError(module, depName)} 3681*1fa6dee9SAndroid Build Coastguard Worker} 3682*1fa6dee9SAndroid Build Coastguard Worker 3683*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) { 3684*1fa6dee9SAndroid Build Coastguard Worker guess := namesLike(depName, module.Name(), c.moduleGroups) 3685*1fa6dee9SAndroid Build Coastguard Worker err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName, guess) 3686*1fa6dee9SAndroid Build Coastguard Worker return &BlueprintError{ 3687*1fa6dee9SAndroid Build Coastguard Worker Err: err, 3688*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 3689*1fa6dee9SAndroid Build Coastguard Worker } 3690*1fa6dee9SAndroid Build Coastguard Worker} 3691*1fa6dee9SAndroid Build Coastguard Worker 3692*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) moduleGroupFromName(name string, namespace Namespace) *moduleGroup { 3693*1fa6dee9SAndroid Build Coastguard Worker group, exists := c.nameInterface.ModuleFromName(name, namespace) 3694*1fa6dee9SAndroid Build Coastguard Worker if exists { 3695*1fa6dee9SAndroid Build Coastguard Worker return group.moduleGroup 3696*1fa6dee9SAndroid Build Coastguard Worker } 3697*1fa6dee9SAndroid Build Coastguard Worker return nil 3698*1fa6dee9SAndroid Build Coastguard Worker} 3699*1fa6dee9SAndroid Build Coastguard Worker 3700*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) sortedModuleGroups() []*moduleGroup { 3701*1fa6dee9SAndroid Build Coastguard Worker if c.cachedSortedModuleGroups == nil || c.cachedDepsModified { 3702*1fa6dee9SAndroid Build Coastguard Worker unwrap := func(wrappers []ModuleGroup) []*moduleGroup { 3703*1fa6dee9SAndroid Build Coastguard Worker result := make([]*moduleGroup, 0, len(wrappers)) 3704*1fa6dee9SAndroid Build Coastguard Worker for _, group := range wrappers { 3705*1fa6dee9SAndroid Build Coastguard Worker result = append(result, group.moduleGroup) 3706*1fa6dee9SAndroid Build Coastguard Worker } 3707*1fa6dee9SAndroid Build Coastguard Worker return result 3708*1fa6dee9SAndroid Build Coastguard Worker } 3709*1fa6dee9SAndroid Build Coastguard Worker 3710*1fa6dee9SAndroid Build Coastguard Worker c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules()) 3711*1fa6dee9SAndroid Build Coastguard Worker c.cachedDepsModified = false 3712*1fa6dee9SAndroid Build Coastguard Worker } 3713*1fa6dee9SAndroid Build Coastguard Worker 3714*1fa6dee9SAndroid Build Coastguard Worker return c.cachedSortedModuleGroups 3715*1fa6dee9SAndroid Build Coastguard Worker} 3716*1fa6dee9SAndroid Build Coastguard Worker 3717*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) visitAllModules(visit func(Module)) { 3718*1fa6dee9SAndroid Build Coastguard Worker var module *moduleInfo 3719*1fa6dee9SAndroid Build Coastguard Worker 3720*1fa6dee9SAndroid Build Coastguard Worker defer func() { 3721*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 3722*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(r, "VisitAllModules(%s) for %s", 3723*1fa6dee9SAndroid Build Coastguard Worker funcName(visit), module)) 3724*1fa6dee9SAndroid Build Coastguard Worker } 3725*1fa6dee9SAndroid Build Coastguard Worker }() 3726*1fa6dee9SAndroid Build Coastguard Worker 3727*1fa6dee9SAndroid Build Coastguard Worker for _, moduleGroup := range c.sortedModuleGroups() { 3728*1fa6dee9SAndroid Build Coastguard Worker for _, module := range moduleGroup.modules { 3729*1fa6dee9SAndroid Build Coastguard Worker visit(module.logicModule) 3730*1fa6dee9SAndroid Build Coastguard Worker } 3731*1fa6dee9SAndroid Build Coastguard Worker } 3732*1fa6dee9SAndroid Build Coastguard Worker} 3733*1fa6dee9SAndroid Build Coastguard Worker 3734*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) visitAllModulesIf(pred func(Module) bool, 3735*1fa6dee9SAndroid Build Coastguard Worker visit func(Module)) { 3736*1fa6dee9SAndroid Build Coastguard Worker 3737*1fa6dee9SAndroid Build Coastguard Worker var module *moduleInfo 3738*1fa6dee9SAndroid Build Coastguard Worker 3739*1fa6dee9SAndroid Build Coastguard Worker defer func() { 3740*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 3741*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s", 3742*1fa6dee9SAndroid Build Coastguard Worker funcName(pred), funcName(visit), module)) 3743*1fa6dee9SAndroid Build Coastguard Worker } 3744*1fa6dee9SAndroid Build Coastguard Worker }() 3745*1fa6dee9SAndroid Build Coastguard Worker 3746*1fa6dee9SAndroid Build Coastguard Worker for _, moduleGroup := range c.sortedModuleGroups() { 3747*1fa6dee9SAndroid Build Coastguard Worker for _, module := range moduleGroup.modules { 3748*1fa6dee9SAndroid Build Coastguard Worker if pred(module.logicModule) { 3749*1fa6dee9SAndroid Build Coastguard Worker visit(module.logicModule) 3750*1fa6dee9SAndroid Build Coastguard Worker } 3751*1fa6dee9SAndroid Build Coastguard Worker } 3752*1fa6dee9SAndroid Build Coastguard Worker } 3753*1fa6dee9SAndroid Build Coastguard Worker} 3754*1fa6dee9SAndroid Build Coastguard Worker 3755*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) visitAllModuleVariants(module *moduleInfo, 3756*1fa6dee9SAndroid Build Coastguard Worker visit func(Module)) { 3757*1fa6dee9SAndroid Build Coastguard Worker 3758*1fa6dee9SAndroid Build Coastguard Worker var variant *moduleInfo 3759*1fa6dee9SAndroid Build Coastguard Worker 3760*1fa6dee9SAndroid Build Coastguard Worker defer func() { 3761*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 3762*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s", 3763*1fa6dee9SAndroid Build Coastguard Worker module, funcName(visit), variant)) 3764*1fa6dee9SAndroid Build Coastguard Worker } 3765*1fa6dee9SAndroid Build Coastguard Worker }() 3766*1fa6dee9SAndroid Build Coastguard Worker 3767*1fa6dee9SAndroid Build Coastguard Worker for _, module := range module.group.modules { 3768*1fa6dee9SAndroid Build Coastguard Worker visit(module.logicModule) 3769*1fa6dee9SAndroid Build Coastguard Worker } 3770*1fa6dee9SAndroid Build Coastguard Worker} 3771*1fa6dee9SAndroid Build Coastguard Worker 3772*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) visitAllModuleInfos(visit func(*moduleInfo)) { 3773*1fa6dee9SAndroid Build Coastguard Worker var module *moduleInfo 3774*1fa6dee9SAndroid Build Coastguard Worker 3775*1fa6dee9SAndroid Build Coastguard Worker defer func() { 3776*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 3777*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(r, "VisitAllModules(%s) for %s", 3778*1fa6dee9SAndroid Build Coastguard Worker funcName(visit), module)) 3779*1fa6dee9SAndroid Build Coastguard Worker } 3780*1fa6dee9SAndroid Build Coastguard Worker }() 3781*1fa6dee9SAndroid Build Coastguard Worker 3782*1fa6dee9SAndroid Build Coastguard Worker for _, moduleGroup := range c.sortedModuleGroups() { 3783*1fa6dee9SAndroid Build Coastguard Worker for _, module := range moduleGroup.modules { 3784*1fa6dee9SAndroid Build Coastguard Worker visit(module) 3785*1fa6dee9SAndroid Build Coastguard Worker } 3786*1fa6dee9SAndroid Build Coastguard Worker } 3787*1fa6dee9SAndroid Build Coastguard Worker} 3788*1fa6dee9SAndroid Build Coastguard Worker 3789*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) requireNinjaVersion(major, minor, micro int) { 3790*1fa6dee9SAndroid Build Coastguard Worker if major != 1 { 3791*1fa6dee9SAndroid Build Coastguard Worker panic("ninja version with major version != 1 not supported") 3792*1fa6dee9SAndroid Build Coastguard Worker } 3793*1fa6dee9SAndroid Build Coastguard Worker if c.requiredNinjaMinor < minor { 3794*1fa6dee9SAndroid Build Coastguard Worker c.requiredNinjaMinor = minor 3795*1fa6dee9SAndroid Build Coastguard Worker c.requiredNinjaMicro = micro 3796*1fa6dee9SAndroid Build Coastguard Worker } 3797*1fa6dee9SAndroid Build Coastguard Worker if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro { 3798*1fa6dee9SAndroid Build Coastguard Worker c.requiredNinjaMicro = micro 3799*1fa6dee9SAndroid Build Coastguard Worker } 3800*1fa6dee9SAndroid Build Coastguard Worker} 3801*1fa6dee9SAndroid Build Coastguard Worker 3802*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) setOutDir(value *ninjaString) { 3803*1fa6dee9SAndroid Build Coastguard Worker if c.outDir == nil { 3804*1fa6dee9SAndroid Build Coastguard Worker c.outDir = value 3805*1fa6dee9SAndroid Build Coastguard Worker } 3806*1fa6dee9SAndroid Build Coastguard Worker} 3807*1fa6dee9SAndroid Build Coastguard Worker 3808*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) makeUniquePackageNames( 3809*1fa6dee9SAndroid Build Coastguard Worker liveGlobals *liveTracker) (map[*packageContext]string, []string) { 3810*1fa6dee9SAndroid Build Coastguard Worker 3811*1fa6dee9SAndroid Build Coastguard Worker pkgs := make(map[string]*packageContext) 3812*1fa6dee9SAndroid Build Coastguard Worker pkgNames := make(map[*packageContext]string) 3813*1fa6dee9SAndroid Build Coastguard Worker longPkgNames := make(map[*packageContext]bool) 3814*1fa6dee9SAndroid Build Coastguard Worker 3815*1fa6dee9SAndroid Build Coastguard Worker processPackage := func(pctx *packageContext) { 3816*1fa6dee9SAndroid Build Coastguard Worker if pctx == nil { 3817*1fa6dee9SAndroid Build Coastguard Worker // This is a built-in rule and has no package. 3818*1fa6dee9SAndroid Build Coastguard Worker return 3819*1fa6dee9SAndroid Build Coastguard Worker } 3820*1fa6dee9SAndroid Build Coastguard Worker if _, ok := pkgNames[pctx]; ok { 3821*1fa6dee9SAndroid Build Coastguard Worker // We've already processed this package. 3822*1fa6dee9SAndroid Build Coastguard Worker return 3823*1fa6dee9SAndroid Build Coastguard Worker } 3824*1fa6dee9SAndroid Build Coastguard Worker 3825*1fa6dee9SAndroid Build Coastguard Worker otherPkg, present := pkgs[pctx.shortName] 3826*1fa6dee9SAndroid Build Coastguard Worker if present { 3827*1fa6dee9SAndroid Build Coastguard Worker // Short name collision. Both this package and the one that's 3828*1fa6dee9SAndroid Build Coastguard Worker // already there need to use their full names. We leave the short 3829*1fa6dee9SAndroid Build Coastguard Worker // name in pkgNames for now so future collisions still get caught. 3830*1fa6dee9SAndroid Build Coastguard Worker longPkgNames[pctx] = true 3831*1fa6dee9SAndroid Build Coastguard Worker longPkgNames[otherPkg] = true 3832*1fa6dee9SAndroid Build Coastguard Worker } else { 3833*1fa6dee9SAndroid Build Coastguard Worker // No collision so far. Tentatively set the package's name to be 3834*1fa6dee9SAndroid Build Coastguard Worker // its short name. 3835*1fa6dee9SAndroid Build Coastguard Worker pkgNames[pctx] = pctx.shortName 3836*1fa6dee9SAndroid Build Coastguard Worker pkgs[pctx.shortName] = pctx 3837*1fa6dee9SAndroid Build Coastguard Worker } 3838*1fa6dee9SAndroid Build Coastguard Worker } 3839*1fa6dee9SAndroid Build Coastguard Worker 3840*1fa6dee9SAndroid Build Coastguard Worker // We try to give all packages their short name, but when we get collisions 3841*1fa6dee9SAndroid Build Coastguard Worker // we need to use the full unique package name. 3842*1fa6dee9SAndroid Build Coastguard Worker for v, _ := range liveGlobals.variables { 3843*1fa6dee9SAndroid Build Coastguard Worker processPackage(v.packageContext()) 3844*1fa6dee9SAndroid Build Coastguard Worker } 3845*1fa6dee9SAndroid Build Coastguard Worker for p, _ := range liveGlobals.pools { 3846*1fa6dee9SAndroid Build Coastguard Worker processPackage(p.packageContext()) 3847*1fa6dee9SAndroid Build Coastguard Worker } 3848*1fa6dee9SAndroid Build Coastguard Worker for r, _ := range liveGlobals.rules { 3849*1fa6dee9SAndroid Build Coastguard Worker processPackage(r.packageContext()) 3850*1fa6dee9SAndroid Build Coastguard Worker } 3851*1fa6dee9SAndroid Build Coastguard Worker 3852*1fa6dee9SAndroid Build Coastguard Worker // Add the packages that had collisions using their full unique names. This 3853*1fa6dee9SAndroid Build Coastguard Worker // will overwrite any short names that were added in the previous step. 3854*1fa6dee9SAndroid Build Coastguard Worker for pctx := range longPkgNames { 3855*1fa6dee9SAndroid Build Coastguard Worker pkgNames[pctx] = pctx.fullName 3856*1fa6dee9SAndroid Build Coastguard Worker } 3857*1fa6dee9SAndroid Build Coastguard Worker 3858*1fa6dee9SAndroid Build Coastguard Worker // Create deps list from calls to PackageContext.AddNinjaFileDeps 3859*1fa6dee9SAndroid Build Coastguard Worker deps := []string{} 3860*1fa6dee9SAndroid Build Coastguard Worker for _, pkg := range pkgs { 3861*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, pkg.ninjaFileDeps...) 3862*1fa6dee9SAndroid Build Coastguard Worker } 3863*1fa6dee9SAndroid Build Coastguard Worker 3864*1fa6dee9SAndroid Build Coastguard Worker return pkgNames, deps 3865*1fa6dee9SAndroid Build Coastguard Worker} 3866*1fa6dee9SAndroid Build Coastguard Worker 3867*1fa6dee9SAndroid Build Coastguard Worker// memoizeFullNames stores the full name of each live global variable, rule and pool since each is 3868*1fa6dee9SAndroid Build Coastguard Worker// guaranteed to be used at least twice, once in the definition and once for each usage, and many 3869*1fa6dee9SAndroid Build Coastguard Worker// are used much more than once. 3870*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) memoizeFullNames(liveGlobals *liveTracker, pkgNames map[*packageContext]string) *nameTracker { 3871*1fa6dee9SAndroid Build Coastguard Worker nameTracker := &nameTracker{ 3872*1fa6dee9SAndroid Build Coastguard Worker pkgNames: pkgNames, 3873*1fa6dee9SAndroid Build Coastguard Worker variables: make(map[Variable]string), 3874*1fa6dee9SAndroid Build Coastguard Worker rules: make(map[Rule]string), 3875*1fa6dee9SAndroid Build Coastguard Worker pools: make(map[Pool]string), 3876*1fa6dee9SAndroid Build Coastguard Worker } 3877*1fa6dee9SAndroid Build Coastguard Worker for v := range liveGlobals.variables { 3878*1fa6dee9SAndroid Build Coastguard Worker nameTracker.variables[v] = v.fullName(pkgNames) 3879*1fa6dee9SAndroid Build Coastguard Worker } 3880*1fa6dee9SAndroid Build Coastguard Worker for r := range liveGlobals.rules { 3881*1fa6dee9SAndroid Build Coastguard Worker nameTracker.rules[r] = r.fullName(pkgNames) 3882*1fa6dee9SAndroid Build Coastguard Worker } 3883*1fa6dee9SAndroid Build Coastguard Worker for p := range liveGlobals.pools { 3884*1fa6dee9SAndroid Build Coastguard Worker nameTracker.pools[p] = p.fullName(pkgNames) 3885*1fa6dee9SAndroid Build Coastguard Worker } 3886*1fa6dee9SAndroid Build Coastguard Worker return nameTracker 3887*1fa6dee9SAndroid Build Coastguard Worker} 3888*1fa6dee9SAndroid Build Coastguard Worker 3889*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) checkForVariableReferenceCycles( 3890*1fa6dee9SAndroid Build Coastguard Worker variables map[Variable]*ninjaString, nameTracker *nameTracker) { 3891*1fa6dee9SAndroid Build Coastguard Worker 3892*1fa6dee9SAndroid Build Coastguard Worker visited := make(map[Variable]bool) // variables that were already checked 3893*1fa6dee9SAndroid Build Coastguard Worker checking := make(map[Variable]bool) // variables actively being checked 3894*1fa6dee9SAndroid Build Coastguard Worker 3895*1fa6dee9SAndroid Build Coastguard Worker var check func(v Variable) []Variable 3896*1fa6dee9SAndroid Build Coastguard Worker 3897*1fa6dee9SAndroid Build Coastguard Worker check = func(v Variable) []Variable { 3898*1fa6dee9SAndroid Build Coastguard Worker visited[v] = true 3899*1fa6dee9SAndroid Build Coastguard Worker checking[v] = true 3900*1fa6dee9SAndroid Build Coastguard Worker defer delete(checking, v) 3901*1fa6dee9SAndroid Build Coastguard Worker 3902*1fa6dee9SAndroid Build Coastguard Worker value := variables[v] 3903*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range value.Variables() { 3904*1fa6dee9SAndroid Build Coastguard Worker if checking[dep] { 3905*1fa6dee9SAndroid Build Coastguard Worker // This is a cycle. 3906*1fa6dee9SAndroid Build Coastguard Worker return []Variable{dep, v} 3907*1fa6dee9SAndroid Build Coastguard Worker } 3908*1fa6dee9SAndroid Build Coastguard Worker 3909*1fa6dee9SAndroid Build Coastguard Worker if !visited[dep] { 3910*1fa6dee9SAndroid Build Coastguard Worker cycle := check(dep) 3911*1fa6dee9SAndroid Build Coastguard Worker if cycle != nil { 3912*1fa6dee9SAndroid Build Coastguard Worker if cycle[0] == v { 3913*1fa6dee9SAndroid Build Coastguard Worker // We are the "start" of the cycle, so we're responsible 3914*1fa6dee9SAndroid Build Coastguard Worker // for generating the errors. The cycle list is in 3915*1fa6dee9SAndroid Build Coastguard Worker // reverse order because all the 'check' calls append 3916*1fa6dee9SAndroid Build Coastguard Worker // their own module to the list. 3917*1fa6dee9SAndroid Build Coastguard Worker msgs := []string{"detected variable reference cycle:"} 3918*1fa6dee9SAndroid Build Coastguard Worker 3919*1fa6dee9SAndroid Build Coastguard Worker // Iterate backwards through the cycle list. 3920*1fa6dee9SAndroid Build Coastguard Worker curName := nameTracker.Variable(v) 3921*1fa6dee9SAndroid Build Coastguard Worker curValue := value.Value(nameTracker) 3922*1fa6dee9SAndroid Build Coastguard Worker for i := len(cycle) - 1; i >= 0; i-- { 3923*1fa6dee9SAndroid Build Coastguard Worker next := cycle[i] 3924*1fa6dee9SAndroid Build Coastguard Worker nextName := nameTracker.Variable(next) 3925*1fa6dee9SAndroid Build Coastguard Worker nextValue := variables[next].Value(nameTracker) 3926*1fa6dee9SAndroid Build Coastguard Worker 3927*1fa6dee9SAndroid Build Coastguard Worker msgs = append(msgs, fmt.Sprintf( 3928*1fa6dee9SAndroid Build Coastguard Worker " %q depends on %q", curName, nextName)) 3929*1fa6dee9SAndroid Build Coastguard Worker msgs = append(msgs, fmt.Sprintf( 3930*1fa6dee9SAndroid Build Coastguard Worker " [%s = %s]", curName, curValue)) 3931*1fa6dee9SAndroid Build Coastguard Worker 3932*1fa6dee9SAndroid Build Coastguard Worker curName = nextName 3933*1fa6dee9SAndroid Build Coastguard Worker curValue = nextValue 3934*1fa6dee9SAndroid Build Coastguard Worker } 3935*1fa6dee9SAndroid Build Coastguard Worker 3936*1fa6dee9SAndroid Build Coastguard Worker // Variable reference cycles are a programming error, 3937*1fa6dee9SAndroid Build Coastguard Worker // not the fault of the Blueprint file authors. 3938*1fa6dee9SAndroid Build Coastguard Worker panic(strings.Join(msgs, "\n")) 3939*1fa6dee9SAndroid Build Coastguard Worker } else { 3940*1fa6dee9SAndroid Build Coastguard Worker // We're not the "start" of the cycle, so we just append 3941*1fa6dee9SAndroid Build Coastguard Worker // our module to the list and return it. 3942*1fa6dee9SAndroid Build Coastguard Worker return append(cycle, v) 3943*1fa6dee9SAndroid Build Coastguard Worker } 3944*1fa6dee9SAndroid Build Coastguard Worker } 3945*1fa6dee9SAndroid Build Coastguard Worker } 3946*1fa6dee9SAndroid Build Coastguard Worker } 3947*1fa6dee9SAndroid Build Coastguard Worker 3948*1fa6dee9SAndroid Build Coastguard Worker return nil 3949*1fa6dee9SAndroid Build Coastguard Worker } 3950*1fa6dee9SAndroid Build Coastguard Worker 3951*1fa6dee9SAndroid Build Coastguard Worker for v := range variables { 3952*1fa6dee9SAndroid Build Coastguard Worker if !visited[v] { 3953*1fa6dee9SAndroid Build Coastguard Worker cycle := check(v) 3954*1fa6dee9SAndroid Build Coastguard Worker if cycle != nil { 3955*1fa6dee9SAndroid Build Coastguard Worker panic("inconceivable!") 3956*1fa6dee9SAndroid Build Coastguard Worker } 3957*1fa6dee9SAndroid Build Coastguard Worker } 3958*1fa6dee9SAndroid Build Coastguard Worker } 3959*1fa6dee9SAndroid Build Coastguard Worker} 3960*1fa6dee9SAndroid Build Coastguard Worker 3961*1fa6dee9SAndroid Build Coastguard Worker// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to 3962*1fa6dee9SAndroid Build Coastguard Worker// property structs returned by the factory for that module type. 3963*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ModuleTypePropertyStructs() map[string][]interface{} { 3964*1fa6dee9SAndroid Build Coastguard Worker ret := make(map[string][]interface{}, len(c.moduleFactories)) 3965*1fa6dee9SAndroid Build Coastguard Worker for moduleType, factory := range c.moduleFactories { 3966*1fa6dee9SAndroid Build Coastguard Worker _, ret[moduleType] = factory() 3967*1fa6dee9SAndroid Build Coastguard Worker } 3968*1fa6dee9SAndroid Build Coastguard Worker 3969*1fa6dee9SAndroid Build Coastguard Worker return ret 3970*1fa6dee9SAndroid Build Coastguard Worker} 3971*1fa6dee9SAndroid Build Coastguard Worker 3972*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ModuleTypeFactories() map[string]ModuleFactory { 3973*1fa6dee9SAndroid Build Coastguard Worker return maps.Clone(c.moduleFactories) 3974*1fa6dee9SAndroid Build Coastguard Worker} 3975*1fa6dee9SAndroid Build Coastguard Worker 3976*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ModuleName(logicModule Module) string { 3977*1fa6dee9SAndroid Build Coastguard Worker module := c.moduleInfo[logicModule] 3978*1fa6dee9SAndroid Build Coastguard Worker return module.Name() 3979*1fa6dee9SAndroid Build Coastguard Worker} 3980*1fa6dee9SAndroid Build Coastguard Worker 3981*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ModuleDir(logicModule Module) string { 3982*1fa6dee9SAndroid Build Coastguard Worker return filepath.Dir(c.BlueprintFile(logicModule)) 3983*1fa6dee9SAndroid Build Coastguard Worker} 3984*1fa6dee9SAndroid Build Coastguard Worker 3985*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ModuleSubDir(logicModule Module) string { 3986*1fa6dee9SAndroid Build Coastguard Worker module := c.moduleInfo[logicModule] 3987*1fa6dee9SAndroid Build Coastguard Worker return module.variant.name 3988*1fa6dee9SAndroid Build Coastguard Worker} 3989*1fa6dee9SAndroid Build Coastguard Worker 3990*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ModuleType(logicModule Module) string { 3991*1fa6dee9SAndroid Build Coastguard Worker module := c.moduleInfo[logicModule] 3992*1fa6dee9SAndroid Build Coastguard Worker return module.typeName 3993*1fa6dee9SAndroid Build Coastguard Worker} 3994*1fa6dee9SAndroid Build Coastguard Worker 3995*1fa6dee9SAndroid Build Coastguard Worker// ModuleProvider returns the value, if any, for the provider for a module. If the value for the 3996*1fa6dee9SAndroid Build Coastguard Worker// provider was not set it returns nil and false. The return value should always be considered read-only. 3997*1fa6dee9SAndroid Build Coastguard Worker// It panics if called before the appropriate mutator or GenerateBuildActions pass for the provider on the 3998*1fa6dee9SAndroid Build Coastguard Worker// module. The value returned may be a deep copy of the value originally passed to SetProvider. 3999*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ModuleProvider(logicModule Module, provider AnyProviderKey) (any, bool) { 4000*1fa6dee9SAndroid Build Coastguard Worker module := c.moduleInfo[logicModule] 4001*1fa6dee9SAndroid Build Coastguard Worker return c.provider(module, provider.provider()) 4002*1fa6dee9SAndroid Build Coastguard Worker} 4003*1fa6dee9SAndroid Build Coastguard Worker 4004*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) BlueprintFile(logicModule Module) string { 4005*1fa6dee9SAndroid Build Coastguard Worker module := c.moduleInfo[logicModule] 4006*1fa6dee9SAndroid Build Coastguard Worker return module.relBlueprintsFile 4007*1fa6dee9SAndroid Build Coastguard Worker} 4008*1fa6dee9SAndroid Build Coastguard Worker 4009*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) moduleErrorf(module *moduleInfo, format string, 4010*1fa6dee9SAndroid Build Coastguard Worker args ...interface{}) error { 4011*1fa6dee9SAndroid Build Coastguard Worker if module == nil { 4012*1fa6dee9SAndroid Build Coastguard Worker // This can happen if ModuleErrorf is called from a load hook 4013*1fa6dee9SAndroid Build Coastguard Worker return &BlueprintError{ 4014*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf(format, args...), 4015*1fa6dee9SAndroid Build Coastguard Worker } 4016*1fa6dee9SAndroid Build Coastguard Worker } 4017*1fa6dee9SAndroid Build Coastguard Worker 4018*1fa6dee9SAndroid Build Coastguard Worker return &ModuleError{ 4019*1fa6dee9SAndroid Build Coastguard Worker BlueprintError: BlueprintError{ 4020*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf(format, args...), 4021*1fa6dee9SAndroid Build Coastguard Worker Pos: module.pos, 4022*1fa6dee9SAndroid Build Coastguard Worker }, 4023*1fa6dee9SAndroid Build Coastguard Worker module: module, 4024*1fa6dee9SAndroid Build Coastguard Worker } 4025*1fa6dee9SAndroid Build Coastguard Worker} 4026*1fa6dee9SAndroid Build Coastguard Worker 4027*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) ModuleErrorf(logicModule Module, format string, 4028*1fa6dee9SAndroid Build Coastguard Worker args ...interface{}) error { 4029*1fa6dee9SAndroid Build Coastguard Worker return c.moduleErrorf(c.moduleInfo[logicModule], format, args...) 4030*1fa6dee9SAndroid Build Coastguard Worker} 4031*1fa6dee9SAndroid Build Coastguard Worker 4032*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) PropertyErrorf(logicModule Module, property string, format string, 4033*1fa6dee9SAndroid Build Coastguard Worker args ...interface{}) error { 4034*1fa6dee9SAndroid Build Coastguard Worker 4035*1fa6dee9SAndroid Build Coastguard Worker module := c.moduleInfo[logicModule] 4036*1fa6dee9SAndroid Build Coastguard Worker if module == nil { 4037*1fa6dee9SAndroid Build Coastguard Worker // This can happen if PropertyErrorf is called from a load hook 4038*1fa6dee9SAndroid Build Coastguard Worker return &BlueprintError{ 4039*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf(format, args...), 4040*1fa6dee9SAndroid Build Coastguard Worker } 4041*1fa6dee9SAndroid Build Coastguard Worker } 4042*1fa6dee9SAndroid Build Coastguard Worker 4043*1fa6dee9SAndroid Build Coastguard Worker pos := module.propertyPos[property] 4044*1fa6dee9SAndroid Build Coastguard Worker if !pos.IsValid() { 4045*1fa6dee9SAndroid Build Coastguard Worker pos = module.pos 4046*1fa6dee9SAndroid Build Coastguard Worker } 4047*1fa6dee9SAndroid Build Coastguard Worker 4048*1fa6dee9SAndroid Build Coastguard Worker return &PropertyError{ 4049*1fa6dee9SAndroid Build Coastguard Worker ModuleError: ModuleError{ 4050*1fa6dee9SAndroid Build Coastguard Worker BlueprintError: BlueprintError{ 4051*1fa6dee9SAndroid Build Coastguard Worker Err: fmt.Errorf(format, args...), 4052*1fa6dee9SAndroid Build Coastguard Worker Pos: pos, 4053*1fa6dee9SAndroid Build Coastguard Worker }, 4054*1fa6dee9SAndroid Build Coastguard Worker module: module, 4055*1fa6dee9SAndroid Build Coastguard Worker }, 4056*1fa6dee9SAndroid Build Coastguard Worker property: property, 4057*1fa6dee9SAndroid Build Coastguard Worker } 4058*1fa6dee9SAndroid Build Coastguard Worker} 4059*1fa6dee9SAndroid Build Coastguard Worker 4060*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) VisitAllModules(visit func(Module)) { 4061*1fa6dee9SAndroid Build Coastguard Worker c.visitAllModules(visit) 4062*1fa6dee9SAndroid Build Coastguard Worker} 4063*1fa6dee9SAndroid Build Coastguard Worker 4064*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) VisitAllModulesIf(pred func(Module) bool, 4065*1fa6dee9SAndroid Build Coastguard Worker visit func(Module)) { 4066*1fa6dee9SAndroid Build Coastguard Worker 4067*1fa6dee9SAndroid Build Coastguard Worker c.visitAllModulesIf(pred, visit) 4068*1fa6dee9SAndroid Build Coastguard Worker} 4069*1fa6dee9SAndroid Build Coastguard Worker 4070*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) VisitDirectDeps(module Module, visit func(Module)) { 4071*1fa6dee9SAndroid Build Coastguard Worker c.VisitDirectDepsWithTags(module, func(m Module, _ DependencyTag) { 4072*1fa6dee9SAndroid Build Coastguard Worker visit(m) 4073*1fa6dee9SAndroid Build Coastguard Worker }) 4074*1fa6dee9SAndroid Build Coastguard Worker} 4075*1fa6dee9SAndroid Build Coastguard Worker 4076*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) VisitDirectDepsWithTags(module Module, visit func(Module, DependencyTag)) { 4077*1fa6dee9SAndroid Build Coastguard Worker topModule := c.moduleInfo[module] 4078*1fa6dee9SAndroid Build Coastguard Worker 4079*1fa6dee9SAndroid Build Coastguard Worker var visiting *moduleInfo 4080*1fa6dee9SAndroid Build Coastguard Worker 4081*1fa6dee9SAndroid Build Coastguard Worker defer func() { 4082*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 4083*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s", 4084*1fa6dee9SAndroid Build Coastguard Worker topModule, funcName(visit), visiting)) 4085*1fa6dee9SAndroid Build Coastguard Worker } 4086*1fa6dee9SAndroid Build Coastguard Worker }() 4087*1fa6dee9SAndroid Build Coastguard Worker 4088*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range topModule.directDeps { 4089*1fa6dee9SAndroid Build Coastguard Worker visiting = dep.module 4090*1fa6dee9SAndroid Build Coastguard Worker visit(dep.module.logicModule, dep.tag) 4091*1fa6dee9SAndroid Build Coastguard Worker } 4092*1fa6dee9SAndroid Build Coastguard Worker} 4093*1fa6dee9SAndroid Build Coastguard Worker 4094*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) { 4095*1fa6dee9SAndroid Build Coastguard Worker topModule := c.moduleInfo[module] 4096*1fa6dee9SAndroid Build Coastguard Worker 4097*1fa6dee9SAndroid Build Coastguard Worker var visiting *moduleInfo 4098*1fa6dee9SAndroid Build Coastguard Worker 4099*1fa6dee9SAndroid Build Coastguard Worker defer func() { 4100*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 4101*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s", 4102*1fa6dee9SAndroid Build Coastguard Worker topModule, funcName(pred), funcName(visit), visiting)) 4103*1fa6dee9SAndroid Build Coastguard Worker } 4104*1fa6dee9SAndroid Build Coastguard Worker }() 4105*1fa6dee9SAndroid Build Coastguard Worker 4106*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range topModule.directDeps { 4107*1fa6dee9SAndroid Build Coastguard Worker visiting = dep.module 4108*1fa6dee9SAndroid Build Coastguard Worker if pred(dep.module.logicModule) { 4109*1fa6dee9SAndroid Build Coastguard Worker visit(dep.module.logicModule) 4110*1fa6dee9SAndroid Build Coastguard Worker } 4111*1fa6dee9SAndroid Build Coastguard Worker } 4112*1fa6dee9SAndroid Build Coastguard Worker} 4113*1fa6dee9SAndroid Build Coastguard Worker 4114*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) { 4115*1fa6dee9SAndroid Build Coastguard Worker topModule := c.moduleInfo[module] 4116*1fa6dee9SAndroid Build Coastguard Worker 4117*1fa6dee9SAndroid Build Coastguard Worker var visiting *moduleInfo 4118*1fa6dee9SAndroid Build Coastguard Worker 4119*1fa6dee9SAndroid Build Coastguard Worker defer func() { 4120*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 4121*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s", 4122*1fa6dee9SAndroid Build Coastguard Worker topModule, funcName(visit), visiting)) 4123*1fa6dee9SAndroid Build Coastguard Worker } 4124*1fa6dee9SAndroid Build Coastguard Worker }() 4125*1fa6dee9SAndroid Build Coastguard Worker 4126*1fa6dee9SAndroid Build Coastguard Worker c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) { 4127*1fa6dee9SAndroid Build Coastguard Worker visiting = dep.module 4128*1fa6dee9SAndroid Build Coastguard Worker visit(dep.module.logicModule) 4129*1fa6dee9SAndroid Build Coastguard Worker }) 4130*1fa6dee9SAndroid Build Coastguard Worker} 4131*1fa6dee9SAndroid Build Coastguard Worker 4132*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) { 4133*1fa6dee9SAndroid Build Coastguard Worker topModule := c.moduleInfo[module] 4134*1fa6dee9SAndroid Build Coastguard Worker 4135*1fa6dee9SAndroid Build Coastguard Worker var visiting *moduleInfo 4136*1fa6dee9SAndroid Build Coastguard Worker 4137*1fa6dee9SAndroid Build Coastguard Worker defer func() { 4138*1fa6dee9SAndroid Build Coastguard Worker if r := recover(); r != nil { 4139*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s", 4140*1fa6dee9SAndroid Build Coastguard Worker topModule, funcName(pred), funcName(visit), visiting)) 4141*1fa6dee9SAndroid Build Coastguard Worker } 4142*1fa6dee9SAndroid Build Coastguard Worker }() 4143*1fa6dee9SAndroid Build Coastguard Worker 4144*1fa6dee9SAndroid Build Coastguard Worker c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) { 4145*1fa6dee9SAndroid Build Coastguard Worker if pred(dep.module.logicModule) { 4146*1fa6dee9SAndroid Build Coastguard Worker visiting = dep.module 4147*1fa6dee9SAndroid Build Coastguard Worker visit(dep.module.logicModule) 4148*1fa6dee9SAndroid Build Coastguard Worker } 4149*1fa6dee9SAndroid Build Coastguard Worker }) 4150*1fa6dee9SAndroid Build Coastguard Worker} 4151*1fa6dee9SAndroid Build Coastguard Worker 4152*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) PrimaryModule(module Module) Module { 4153*1fa6dee9SAndroid Build Coastguard Worker return c.moduleInfo[module].group.modules.firstModule().logicModule 4154*1fa6dee9SAndroid Build Coastguard Worker} 4155*1fa6dee9SAndroid Build Coastguard Worker 4156*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) IsFinalModule(module Module) bool { 4157*1fa6dee9SAndroid Build Coastguard Worker return c.moduleInfo[module].group.modules.lastModule().logicModule == module 4158*1fa6dee9SAndroid Build Coastguard Worker} 4159*1fa6dee9SAndroid Build Coastguard Worker 4160*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) VisitAllModuleVariants(module Module, 4161*1fa6dee9SAndroid Build Coastguard Worker visit func(Module)) { 4162*1fa6dee9SAndroid Build Coastguard Worker 4163*1fa6dee9SAndroid Build Coastguard Worker c.visitAllModuleVariants(c.moduleInfo[module], visit) 4164*1fa6dee9SAndroid Build Coastguard Worker} 4165*1fa6dee9SAndroid Build Coastguard Worker 4166*1fa6dee9SAndroid Build Coastguard Worker// Singletons returns a list of all registered Singletons. 4167*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) Singletons() []Singleton { 4168*1fa6dee9SAndroid Build Coastguard Worker var ret []Singleton 4169*1fa6dee9SAndroid Build Coastguard Worker for _, s := range c.singletonInfo { 4170*1fa6dee9SAndroid Build Coastguard Worker ret = append(ret, s.singleton) 4171*1fa6dee9SAndroid Build Coastguard Worker } 4172*1fa6dee9SAndroid Build Coastguard Worker return ret 4173*1fa6dee9SAndroid Build Coastguard Worker} 4174*1fa6dee9SAndroid Build Coastguard Worker 4175*1fa6dee9SAndroid Build Coastguard Worker// SingletonName returns the name that the given singleton was registered with. 4176*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SingletonName(singleton Singleton) string { 4177*1fa6dee9SAndroid Build Coastguard Worker for _, s := range c.singletonInfo { 4178*1fa6dee9SAndroid Build Coastguard Worker if s.singleton == singleton { 4179*1fa6dee9SAndroid Build Coastguard Worker return s.name 4180*1fa6dee9SAndroid Build Coastguard Worker } 4181*1fa6dee9SAndroid Build Coastguard Worker } 4182*1fa6dee9SAndroid Build Coastguard Worker return "" 4183*1fa6dee9SAndroid Build Coastguard Worker} 4184*1fa6dee9SAndroid Build Coastguard Worker 4185*1fa6dee9SAndroid Build Coastguard Worker// Checks that the hashes of all the providers match the hashes from when they were first set. 4186*1fa6dee9SAndroid Build Coastguard Worker// Does nothing on success, returns a list of errors otherwise. It's recommended to run this 4187*1fa6dee9SAndroid Build Coastguard Worker// in a goroutine. 4188*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) VerifyProvidersWereUnchanged() []error { 4189*1fa6dee9SAndroid Build Coastguard Worker if !c.buildActionsReady { 4190*1fa6dee9SAndroid Build Coastguard Worker return []error{ErrBuildActionsNotReady} 4191*1fa6dee9SAndroid Build Coastguard Worker } 4192*1fa6dee9SAndroid Build Coastguard Worker toProcess := make(chan *moduleInfo) 4193*1fa6dee9SAndroid Build Coastguard Worker errorCh := make(chan []error) 4194*1fa6dee9SAndroid Build Coastguard Worker var wg sync.WaitGroup 4195*1fa6dee9SAndroid Build Coastguard Worker go func() { 4196*1fa6dee9SAndroid Build Coastguard Worker for m := range c.iterateAllVariants() { 4197*1fa6dee9SAndroid Build Coastguard Worker toProcess <- m 4198*1fa6dee9SAndroid Build Coastguard Worker } 4199*1fa6dee9SAndroid Build Coastguard Worker close(toProcess) 4200*1fa6dee9SAndroid Build Coastguard Worker }() 4201*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < 1000; i++ { 4202*1fa6dee9SAndroid Build Coastguard Worker wg.Add(1) 4203*1fa6dee9SAndroid Build Coastguard Worker go func() { 4204*1fa6dee9SAndroid Build Coastguard Worker var errors []error 4205*1fa6dee9SAndroid Build Coastguard Worker for m := range toProcess { 4206*1fa6dee9SAndroid Build Coastguard Worker for i, provider := range m.providers { 4207*1fa6dee9SAndroid Build Coastguard Worker if provider != nil { 4208*1fa6dee9SAndroid Build Coastguard Worker hash, err := proptools.CalculateHash(provider) 4209*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4210*1fa6dee9SAndroid Build Coastguard Worker errors = append(errors, fmt.Errorf("provider %q on module %q was modified after being set, and no longer hashable afterwards: %s", providerRegistry[i].typ, m.Name(), err.Error())) 4211*1fa6dee9SAndroid Build Coastguard Worker continue 4212*1fa6dee9SAndroid Build Coastguard Worker } 4213*1fa6dee9SAndroid Build Coastguard Worker if m.providerInitialValueHashes[i] != hash { 4214*1fa6dee9SAndroid Build Coastguard Worker errors = append(errors, fmt.Errorf("provider %q on module %q was modified after being set", providerRegistry[i].typ, m.Name())) 4215*1fa6dee9SAndroid Build Coastguard Worker } 4216*1fa6dee9SAndroid Build Coastguard Worker } else if m.providerInitialValueHashes[i] != 0 { 4217*1fa6dee9SAndroid Build Coastguard Worker // This should be unreachable, because in setProvider we check if the provider has already been set. 4218*1fa6dee9SAndroid Build Coastguard Worker errors = append(errors, fmt.Errorf("provider %q on module %q was unset somehow, this is an internal error", providerRegistry[i].typ, m.Name())) 4219*1fa6dee9SAndroid Build Coastguard Worker } 4220*1fa6dee9SAndroid Build Coastguard Worker } 4221*1fa6dee9SAndroid Build Coastguard Worker } 4222*1fa6dee9SAndroid Build Coastguard Worker if errors != nil { 4223*1fa6dee9SAndroid Build Coastguard Worker errorCh <- errors 4224*1fa6dee9SAndroid Build Coastguard Worker } 4225*1fa6dee9SAndroid Build Coastguard Worker wg.Done() 4226*1fa6dee9SAndroid Build Coastguard Worker }() 4227*1fa6dee9SAndroid Build Coastguard Worker } 4228*1fa6dee9SAndroid Build Coastguard Worker go func() { 4229*1fa6dee9SAndroid Build Coastguard Worker wg.Wait() 4230*1fa6dee9SAndroid Build Coastguard Worker close(errorCh) 4231*1fa6dee9SAndroid Build Coastguard Worker }() 4232*1fa6dee9SAndroid Build Coastguard Worker 4233*1fa6dee9SAndroid Build Coastguard Worker var errors []error 4234*1fa6dee9SAndroid Build Coastguard Worker for newErrors := range errorCh { 4235*1fa6dee9SAndroid Build Coastguard Worker errors = append(errors, newErrors...) 4236*1fa6dee9SAndroid Build Coastguard Worker } 4237*1fa6dee9SAndroid Build Coastguard Worker return errors 4238*1fa6dee9SAndroid Build Coastguard Worker} 4239*1fa6dee9SAndroid Build Coastguard Worker 4240*1fa6dee9SAndroid Build Coastguard Worker// WriteBuildFile writes the Ninja manifest text for the generated build 4241*1fa6dee9SAndroid Build Coastguard Worker// actions to w. If this is called before PrepareBuildActions successfully 4242*1fa6dee9SAndroid Build Coastguard Worker// completes then ErrBuildActionsNotReady is returned. 4243*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) WriteBuildFile(w StringWriterWriter, shardNinja bool, ninjaFileName string) error { 4244*1fa6dee9SAndroid Build Coastguard Worker var err error 4245*1fa6dee9SAndroid Build Coastguard Worker pprof.Do(c.Context, pprof.Labels("blueprint", "WriteBuildFile"), func(ctx context.Context) { 4246*1fa6dee9SAndroid Build Coastguard Worker if !c.buildActionsReady { 4247*1fa6dee9SAndroid Build Coastguard Worker err = ErrBuildActionsNotReady 4248*1fa6dee9SAndroid Build Coastguard Worker return 4249*1fa6dee9SAndroid Build Coastguard Worker } 4250*1fa6dee9SAndroid Build Coastguard Worker 4251*1fa6dee9SAndroid Build Coastguard Worker nw := newNinjaWriter(w) 4252*1fa6dee9SAndroid Build Coastguard Worker 4253*1fa6dee9SAndroid Build Coastguard Worker if err = c.writeBuildFileHeader(nw); err != nil { 4254*1fa6dee9SAndroid Build Coastguard Worker return 4255*1fa6dee9SAndroid Build Coastguard Worker } 4256*1fa6dee9SAndroid Build Coastguard Worker 4257*1fa6dee9SAndroid Build Coastguard Worker if err = c.writeNinjaRequiredVersion(nw); err != nil { 4258*1fa6dee9SAndroid Build Coastguard Worker return 4259*1fa6dee9SAndroid Build Coastguard Worker } 4260*1fa6dee9SAndroid Build Coastguard Worker 4261*1fa6dee9SAndroid Build Coastguard Worker if err = c.writeSubninjas(nw); err != nil { 4262*1fa6dee9SAndroid Build Coastguard Worker return 4263*1fa6dee9SAndroid Build Coastguard Worker } 4264*1fa6dee9SAndroid Build Coastguard Worker 4265*1fa6dee9SAndroid Build Coastguard Worker // TODO: Group the globals by package. 4266*1fa6dee9SAndroid Build Coastguard Worker 4267*1fa6dee9SAndroid Build Coastguard Worker if err = c.writeGlobalVariables(nw); err != nil { 4268*1fa6dee9SAndroid Build Coastguard Worker return 4269*1fa6dee9SAndroid Build Coastguard Worker } 4270*1fa6dee9SAndroid Build Coastguard Worker 4271*1fa6dee9SAndroid Build Coastguard Worker if err = c.writeGlobalPools(nw); err != nil { 4272*1fa6dee9SAndroid Build Coastguard Worker return 4273*1fa6dee9SAndroid Build Coastguard Worker } 4274*1fa6dee9SAndroid Build Coastguard Worker 4275*1fa6dee9SAndroid Build Coastguard Worker if err = c.writeBuildDir(nw); err != nil { 4276*1fa6dee9SAndroid Build Coastguard Worker return 4277*1fa6dee9SAndroid Build Coastguard Worker } 4278*1fa6dee9SAndroid Build Coastguard Worker 4279*1fa6dee9SAndroid Build Coastguard Worker if err = c.writeGlobalRules(nw); err != nil { 4280*1fa6dee9SAndroid Build Coastguard Worker return 4281*1fa6dee9SAndroid Build Coastguard Worker } 4282*1fa6dee9SAndroid Build Coastguard Worker 4283*1fa6dee9SAndroid Build Coastguard Worker if err = c.writeAllModuleActions(nw, shardNinja, ninjaFileName); err != nil { 4284*1fa6dee9SAndroid Build Coastguard Worker return 4285*1fa6dee9SAndroid Build Coastguard Worker } 4286*1fa6dee9SAndroid Build Coastguard Worker 4287*1fa6dee9SAndroid Build Coastguard Worker if err = c.writeAllSingletonActions(nw); err != nil { 4288*1fa6dee9SAndroid Build Coastguard Worker return 4289*1fa6dee9SAndroid Build Coastguard Worker } 4290*1fa6dee9SAndroid Build Coastguard Worker }) 4291*1fa6dee9SAndroid Build Coastguard Worker 4292*1fa6dee9SAndroid Build Coastguard Worker return err 4293*1fa6dee9SAndroid Build Coastguard Worker} 4294*1fa6dee9SAndroid Build Coastguard Worker 4295*1fa6dee9SAndroid Build Coastguard Workertype pkgAssociation struct { 4296*1fa6dee9SAndroid Build Coastguard Worker PkgName string 4297*1fa6dee9SAndroid Build Coastguard Worker PkgPath string 4298*1fa6dee9SAndroid Build Coastguard Worker} 4299*1fa6dee9SAndroid Build Coastguard Worker 4300*1fa6dee9SAndroid Build Coastguard Workertype pkgAssociationSorter struct { 4301*1fa6dee9SAndroid Build Coastguard Worker pkgs []pkgAssociation 4302*1fa6dee9SAndroid Build Coastguard Worker} 4303*1fa6dee9SAndroid Build Coastguard Worker 4304*1fa6dee9SAndroid Build Coastguard Workerfunc (s *pkgAssociationSorter) Len() int { 4305*1fa6dee9SAndroid Build Coastguard Worker return len(s.pkgs) 4306*1fa6dee9SAndroid Build Coastguard Worker} 4307*1fa6dee9SAndroid Build Coastguard Worker 4308*1fa6dee9SAndroid Build Coastguard Workerfunc (s *pkgAssociationSorter) Less(i, j int) bool { 4309*1fa6dee9SAndroid Build Coastguard Worker iName := s.pkgs[i].PkgName 4310*1fa6dee9SAndroid Build Coastguard Worker jName := s.pkgs[j].PkgName 4311*1fa6dee9SAndroid Build Coastguard Worker return iName < jName 4312*1fa6dee9SAndroid Build Coastguard Worker} 4313*1fa6dee9SAndroid Build Coastguard Worker 4314*1fa6dee9SAndroid Build Coastguard Workerfunc (s *pkgAssociationSorter) Swap(i, j int) { 4315*1fa6dee9SAndroid Build Coastguard Worker s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i] 4316*1fa6dee9SAndroid Build Coastguard Worker} 4317*1fa6dee9SAndroid Build Coastguard Worker 4318*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeBuildFileHeader(nw *ninjaWriter) error { 4319*1fa6dee9SAndroid Build Coastguard Worker headerTemplate := template.New("fileHeader") 4320*1fa6dee9SAndroid Build Coastguard Worker _, err := headerTemplate.Parse(fileHeaderTemplate) 4321*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4322*1fa6dee9SAndroid Build Coastguard Worker // This is a programming error. 4323*1fa6dee9SAndroid Build Coastguard Worker panic(err) 4324*1fa6dee9SAndroid Build Coastguard Worker } 4325*1fa6dee9SAndroid Build Coastguard Worker 4326*1fa6dee9SAndroid Build Coastguard Worker var pkgs []pkgAssociation 4327*1fa6dee9SAndroid Build Coastguard Worker maxNameLen := 0 4328*1fa6dee9SAndroid Build Coastguard Worker for pkg, name := range c.nameTracker.pkgNames { 4329*1fa6dee9SAndroid Build Coastguard Worker pkgs = append(pkgs, pkgAssociation{ 4330*1fa6dee9SAndroid Build Coastguard Worker PkgName: name, 4331*1fa6dee9SAndroid Build Coastguard Worker PkgPath: pkg.pkgPath, 4332*1fa6dee9SAndroid Build Coastguard Worker }) 4333*1fa6dee9SAndroid Build Coastguard Worker if len(name) > maxNameLen { 4334*1fa6dee9SAndroid Build Coastguard Worker maxNameLen = len(name) 4335*1fa6dee9SAndroid Build Coastguard Worker } 4336*1fa6dee9SAndroid Build Coastguard Worker } 4337*1fa6dee9SAndroid Build Coastguard Worker 4338*1fa6dee9SAndroid Build Coastguard Worker for i := range pkgs { 4339*1fa6dee9SAndroid Build Coastguard Worker pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName)) 4340*1fa6dee9SAndroid Build Coastguard Worker } 4341*1fa6dee9SAndroid Build Coastguard Worker 4342*1fa6dee9SAndroid Build Coastguard Worker sort.Sort(&pkgAssociationSorter{pkgs}) 4343*1fa6dee9SAndroid Build Coastguard Worker 4344*1fa6dee9SAndroid Build Coastguard Worker params := map[string]interface{}{ 4345*1fa6dee9SAndroid Build Coastguard Worker "Pkgs": pkgs, 4346*1fa6dee9SAndroid Build Coastguard Worker } 4347*1fa6dee9SAndroid Build Coastguard Worker 4348*1fa6dee9SAndroid Build Coastguard Worker buf := bytes.NewBuffer(nil) 4349*1fa6dee9SAndroid Build Coastguard Worker err = headerTemplate.Execute(buf, params) 4350*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4351*1fa6dee9SAndroid Build Coastguard Worker return err 4352*1fa6dee9SAndroid Build Coastguard Worker } 4353*1fa6dee9SAndroid Build Coastguard Worker 4354*1fa6dee9SAndroid Build Coastguard Worker return nw.Comment(buf.String()) 4355*1fa6dee9SAndroid Build Coastguard Worker} 4356*1fa6dee9SAndroid Build Coastguard Worker 4357*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error { 4358*1fa6dee9SAndroid Build Coastguard Worker value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor, 4359*1fa6dee9SAndroid Build Coastguard Worker c.requiredNinjaMicro) 4360*1fa6dee9SAndroid Build Coastguard Worker 4361*1fa6dee9SAndroid Build Coastguard Worker err := nw.Assign("ninja_required_version", value) 4362*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4363*1fa6dee9SAndroid Build Coastguard Worker return err 4364*1fa6dee9SAndroid Build Coastguard Worker } 4365*1fa6dee9SAndroid Build Coastguard Worker 4366*1fa6dee9SAndroid Build Coastguard Worker return nw.BlankLine() 4367*1fa6dee9SAndroid Build Coastguard Worker} 4368*1fa6dee9SAndroid Build Coastguard Worker 4369*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeSubninjas(nw *ninjaWriter) error { 4370*1fa6dee9SAndroid Build Coastguard Worker for _, subninja := range c.subninjas { 4371*1fa6dee9SAndroid Build Coastguard Worker err := nw.Subninja(subninja) 4372*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4373*1fa6dee9SAndroid Build Coastguard Worker return err 4374*1fa6dee9SAndroid Build Coastguard Worker } 4375*1fa6dee9SAndroid Build Coastguard Worker } 4376*1fa6dee9SAndroid Build Coastguard Worker return nw.BlankLine() 4377*1fa6dee9SAndroid Build Coastguard Worker} 4378*1fa6dee9SAndroid Build Coastguard Worker 4379*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeBuildDir(nw *ninjaWriter) error { 4380*1fa6dee9SAndroid Build Coastguard Worker if c.outDir != nil { 4381*1fa6dee9SAndroid Build Coastguard Worker err := nw.Assign("builddir", c.outDir.Value(c.nameTracker)) 4382*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4383*1fa6dee9SAndroid Build Coastguard Worker return err 4384*1fa6dee9SAndroid Build Coastguard Worker } 4385*1fa6dee9SAndroid Build Coastguard Worker 4386*1fa6dee9SAndroid Build Coastguard Worker err = nw.BlankLine() 4387*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4388*1fa6dee9SAndroid Build Coastguard Worker return err 4389*1fa6dee9SAndroid Build Coastguard Worker } 4390*1fa6dee9SAndroid Build Coastguard Worker } 4391*1fa6dee9SAndroid Build Coastguard Worker return nil 4392*1fa6dee9SAndroid Build Coastguard Worker} 4393*1fa6dee9SAndroid Build Coastguard Worker 4394*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeGlobalVariables(nw *ninjaWriter) error { 4395*1fa6dee9SAndroid Build Coastguard Worker visited := make(map[Variable]bool) 4396*1fa6dee9SAndroid Build Coastguard Worker 4397*1fa6dee9SAndroid Build Coastguard Worker var walk func(v Variable) error 4398*1fa6dee9SAndroid Build Coastguard Worker walk = func(v Variable) error { 4399*1fa6dee9SAndroid Build Coastguard Worker visited[v] = true 4400*1fa6dee9SAndroid Build Coastguard Worker 4401*1fa6dee9SAndroid Build Coastguard Worker // First visit variables on which this variable depends. 4402*1fa6dee9SAndroid Build Coastguard Worker value := c.globalVariables[v] 4403*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range value.Variables() { 4404*1fa6dee9SAndroid Build Coastguard Worker if !visited[dep] { 4405*1fa6dee9SAndroid Build Coastguard Worker err := walk(dep) 4406*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4407*1fa6dee9SAndroid Build Coastguard Worker return err 4408*1fa6dee9SAndroid Build Coastguard Worker } 4409*1fa6dee9SAndroid Build Coastguard Worker } 4410*1fa6dee9SAndroid Build Coastguard Worker } 4411*1fa6dee9SAndroid Build Coastguard Worker 4412*1fa6dee9SAndroid Build Coastguard Worker err := nw.Assign(c.nameTracker.Variable(v), value.Value(c.nameTracker)) 4413*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4414*1fa6dee9SAndroid Build Coastguard Worker return err 4415*1fa6dee9SAndroid Build Coastguard Worker } 4416*1fa6dee9SAndroid Build Coastguard Worker 4417*1fa6dee9SAndroid Build Coastguard Worker err = nw.BlankLine() 4418*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4419*1fa6dee9SAndroid Build Coastguard Worker return err 4420*1fa6dee9SAndroid Build Coastguard Worker } 4421*1fa6dee9SAndroid Build Coastguard Worker 4422*1fa6dee9SAndroid Build Coastguard Worker return nil 4423*1fa6dee9SAndroid Build Coastguard Worker } 4424*1fa6dee9SAndroid Build Coastguard Worker 4425*1fa6dee9SAndroid Build Coastguard Worker globalVariables := make([]Variable, 0, len(c.globalVariables)) 4426*1fa6dee9SAndroid Build Coastguard Worker for variable := range c.globalVariables { 4427*1fa6dee9SAndroid Build Coastguard Worker globalVariables = append(globalVariables, variable) 4428*1fa6dee9SAndroid Build Coastguard Worker } 4429*1fa6dee9SAndroid Build Coastguard Worker 4430*1fa6dee9SAndroid Build Coastguard Worker slices.SortFunc(globalVariables, func(a, b Variable) int { 4431*1fa6dee9SAndroid Build Coastguard Worker return cmp.Compare(c.nameTracker.Variable(a), c.nameTracker.Variable(b)) 4432*1fa6dee9SAndroid Build Coastguard Worker }) 4433*1fa6dee9SAndroid Build Coastguard Worker 4434*1fa6dee9SAndroid Build Coastguard Worker for _, v := range globalVariables { 4435*1fa6dee9SAndroid Build Coastguard Worker if !visited[v] { 4436*1fa6dee9SAndroid Build Coastguard Worker err := walk(v) 4437*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4438*1fa6dee9SAndroid Build Coastguard Worker return nil 4439*1fa6dee9SAndroid Build Coastguard Worker } 4440*1fa6dee9SAndroid Build Coastguard Worker } 4441*1fa6dee9SAndroid Build Coastguard Worker } 4442*1fa6dee9SAndroid Build Coastguard Worker 4443*1fa6dee9SAndroid Build Coastguard Worker return nil 4444*1fa6dee9SAndroid Build Coastguard Worker} 4445*1fa6dee9SAndroid Build Coastguard Worker 4446*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeGlobalPools(nw *ninjaWriter) error { 4447*1fa6dee9SAndroid Build Coastguard Worker globalPools := make([]Pool, 0, len(c.globalPools)) 4448*1fa6dee9SAndroid Build Coastguard Worker for pool := range c.globalPools { 4449*1fa6dee9SAndroid Build Coastguard Worker globalPools = append(globalPools, pool) 4450*1fa6dee9SAndroid Build Coastguard Worker } 4451*1fa6dee9SAndroid Build Coastguard Worker 4452*1fa6dee9SAndroid Build Coastguard Worker slices.SortFunc(globalPools, func(a, b Pool) int { 4453*1fa6dee9SAndroid Build Coastguard Worker return cmp.Compare(c.nameTracker.Pool(a), c.nameTracker.Pool(b)) 4454*1fa6dee9SAndroid Build Coastguard Worker }) 4455*1fa6dee9SAndroid Build Coastguard Worker 4456*1fa6dee9SAndroid Build Coastguard Worker for _, pool := range globalPools { 4457*1fa6dee9SAndroid Build Coastguard Worker name := c.nameTracker.Pool(pool) 4458*1fa6dee9SAndroid Build Coastguard Worker def := c.globalPools[pool] 4459*1fa6dee9SAndroid Build Coastguard Worker err := def.WriteTo(nw, name) 4460*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4461*1fa6dee9SAndroid Build Coastguard Worker return err 4462*1fa6dee9SAndroid Build Coastguard Worker } 4463*1fa6dee9SAndroid Build Coastguard Worker 4464*1fa6dee9SAndroid Build Coastguard Worker err = nw.BlankLine() 4465*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4466*1fa6dee9SAndroid Build Coastguard Worker return err 4467*1fa6dee9SAndroid Build Coastguard Worker } 4468*1fa6dee9SAndroid Build Coastguard Worker } 4469*1fa6dee9SAndroid Build Coastguard Worker 4470*1fa6dee9SAndroid Build Coastguard Worker return nil 4471*1fa6dee9SAndroid Build Coastguard Worker} 4472*1fa6dee9SAndroid Build Coastguard Worker 4473*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeGlobalRules(nw *ninjaWriter) error { 4474*1fa6dee9SAndroid Build Coastguard Worker globalRules := make([]Rule, 0, len(c.globalRules)) 4475*1fa6dee9SAndroid Build Coastguard Worker for rule := range c.globalRules { 4476*1fa6dee9SAndroid Build Coastguard Worker globalRules = append(globalRules, rule) 4477*1fa6dee9SAndroid Build Coastguard Worker } 4478*1fa6dee9SAndroid Build Coastguard Worker 4479*1fa6dee9SAndroid Build Coastguard Worker slices.SortFunc(globalRules, func(a, b Rule) int { 4480*1fa6dee9SAndroid Build Coastguard Worker return cmp.Compare(c.nameTracker.Rule(a), c.nameTracker.Rule(b)) 4481*1fa6dee9SAndroid Build Coastguard Worker }) 4482*1fa6dee9SAndroid Build Coastguard Worker 4483*1fa6dee9SAndroid Build Coastguard Worker for _, rule := range globalRules { 4484*1fa6dee9SAndroid Build Coastguard Worker name := c.nameTracker.Rule(rule) 4485*1fa6dee9SAndroid Build Coastguard Worker def := c.globalRules[rule] 4486*1fa6dee9SAndroid Build Coastguard Worker err := def.WriteTo(nw, name, c.nameTracker) 4487*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4488*1fa6dee9SAndroid Build Coastguard Worker return err 4489*1fa6dee9SAndroid Build Coastguard Worker } 4490*1fa6dee9SAndroid Build Coastguard Worker 4491*1fa6dee9SAndroid Build Coastguard Worker err = nw.BlankLine() 4492*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4493*1fa6dee9SAndroid Build Coastguard Worker return err 4494*1fa6dee9SAndroid Build Coastguard Worker } 4495*1fa6dee9SAndroid Build Coastguard Worker } 4496*1fa6dee9SAndroid Build Coastguard Worker 4497*1fa6dee9SAndroid Build Coastguard Worker return nil 4498*1fa6dee9SAndroid Build Coastguard Worker} 4499*1fa6dee9SAndroid Build Coastguard Worker 4500*1fa6dee9SAndroid Build Coastguard Workertype depSorter []depInfo 4501*1fa6dee9SAndroid Build Coastguard Worker 4502*1fa6dee9SAndroid Build Coastguard Workerfunc (s depSorter) Len() int { 4503*1fa6dee9SAndroid Build Coastguard Worker return len(s) 4504*1fa6dee9SAndroid Build Coastguard Worker} 4505*1fa6dee9SAndroid Build Coastguard Worker 4506*1fa6dee9SAndroid Build Coastguard Workerfunc (s depSorter) Less(i, j int) bool { 4507*1fa6dee9SAndroid Build Coastguard Worker iName := s[i].module.Name() 4508*1fa6dee9SAndroid Build Coastguard Worker jName := s[j].module.Name() 4509*1fa6dee9SAndroid Build Coastguard Worker if iName == jName { 4510*1fa6dee9SAndroid Build Coastguard Worker iName = s[i].module.variant.name 4511*1fa6dee9SAndroid Build Coastguard Worker jName = s[j].module.variant.name 4512*1fa6dee9SAndroid Build Coastguard Worker } 4513*1fa6dee9SAndroid Build Coastguard Worker return iName < jName 4514*1fa6dee9SAndroid Build Coastguard Worker} 4515*1fa6dee9SAndroid Build Coastguard Worker 4516*1fa6dee9SAndroid Build Coastguard Workerfunc (s depSorter) Swap(i, j int) { 4517*1fa6dee9SAndroid Build Coastguard Worker s[i], s[j] = s[j], s[i] 4518*1fa6dee9SAndroid Build Coastguard Worker} 4519*1fa6dee9SAndroid Build Coastguard Worker 4520*1fa6dee9SAndroid Build Coastguard Workertype moduleSorter struct { 4521*1fa6dee9SAndroid Build Coastguard Worker modules []*moduleInfo 4522*1fa6dee9SAndroid Build Coastguard Worker nameInterface NameInterface 4523*1fa6dee9SAndroid Build Coastguard Worker} 4524*1fa6dee9SAndroid Build Coastguard Worker 4525*1fa6dee9SAndroid Build Coastguard Workerfunc (s moduleSorter) Len() int { 4526*1fa6dee9SAndroid Build Coastguard Worker return len(s.modules) 4527*1fa6dee9SAndroid Build Coastguard Worker} 4528*1fa6dee9SAndroid Build Coastguard Worker 4529*1fa6dee9SAndroid Build Coastguard Workerfunc (s moduleSorter) Less(i, j int) bool { 4530*1fa6dee9SAndroid Build Coastguard Worker iMod := s.modules[i] 4531*1fa6dee9SAndroid Build Coastguard Worker jMod := s.modules[j] 4532*1fa6dee9SAndroid Build Coastguard Worker iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name) 4533*1fa6dee9SAndroid Build Coastguard Worker jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name) 4534*1fa6dee9SAndroid Build Coastguard Worker if iName == jName { 4535*1fa6dee9SAndroid Build Coastguard Worker iVariantName := s.modules[i].variant.name 4536*1fa6dee9SAndroid Build Coastguard Worker jVariantName := s.modules[j].variant.name 4537*1fa6dee9SAndroid Build Coastguard Worker if iVariantName == jVariantName { 4538*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Sprintf("duplicate module name: %s %s: %#v and %#v\n", 4539*1fa6dee9SAndroid Build Coastguard Worker iName, iVariantName, iMod.variant.variations, jMod.variant.variations)) 4540*1fa6dee9SAndroid Build Coastguard Worker } else { 4541*1fa6dee9SAndroid Build Coastguard Worker return iVariantName < jVariantName 4542*1fa6dee9SAndroid Build Coastguard Worker } 4543*1fa6dee9SAndroid Build Coastguard Worker } else { 4544*1fa6dee9SAndroid Build Coastguard Worker return iName < jName 4545*1fa6dee9SAndroid Build Coastguard Worker } 4546*1fa6dee9SAndroid Build Coastguard Worker} 4547*1fa6dee9SAndroid Build Coastguard Worker 4548*1fa6dee9SAndroid Build Coastguard Workerfunc (s moduleSorter) Swap(i, j int) { 4549*1fa6dee9SAndroid Build Coastguard Worker s.modules[i], s.modules[j] = s.modules[j], s.modules[i] 4550*1fa6dee9SAndroid Build Coastguard Worker} 4551*1fa6dee9SAndroid Build Coastguard Worker 4552*1fa6dee9SAndroid Build Coastguard Workerfunc GetNinjaShardFiles(ninjaFile string) []string { 4553*1fa6dee9SAndroid Build Coastguard Worker suffix := ".ninja" 4554*1fa6dee9SAndroid Build Coastguard Worker if !strings.HasSuffix(ninjaFile, suffix) { 4555*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("ninja file name in wrong format : %s", ninjaFile)) 4556*1fa6dee9SAndroid Build Coastguard Worker } 4557*1fa6dee9SAndroid Build Coastguard Worker base := strings.TrimSuffix(ninjaFile, suffix) 4558*1fa6dee9SAndroid Build Coastguard Worker ninjaShardCnt := 10 4559*1fa6dee9SAndroid Build Coastguard Worker fileNames := make([]string, ninjaShardCnt) 4560*1fa6dee9SAndroid Build Coastguard Worker 4561*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < ninjaShardCnt; i++ { 4562*1fa6dee9SAndroid Build Coastguard Worker fileNames[i] = fmt.Sprintf("%s.%d%s", base, i, suffix) 4563*1fa6dee9SAndroid Build Coastguard Worker } 4564*1fa6dee9SAndroid Build Coastguard Worker return fileNames 4565*1fa6dee9SAndroid Build Coastguard Worker} 4566*1fa6dee9SAndroid Build Coastguard Worker 4567*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeAllModuleActions(nw *ninjaWriter, shardNinja bool, ninjaFileName string) error { 4568*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("modules") 4569*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("modules") 4570*1fa6dee9SAndroid Build Coastguard Worker 4571*1fa6dee9SAndroid Build Coastguard Worker modules := make([]*moduleInfo, 0, len(c.moduleInfo)) 4572*1fa6dee9SAndroid Build Coastguard Worker incrementalModules := make([]*moduleInfo, 0, 200) 4573*1fa6dee9SAndroid Build Coastguard Worker 4574*1fa6dee9SAndroid Build Coastguard Worker for _, module := range c.moduleInfo { 4575*1fa6dee9SAndroid Build Coastguard Worker if module.buildActionCacheKey != nil { 4576*1fa6dee9SAndroid Build Coastguard Worker incrementalModules = append(incrementalModules, module) 4577*1fa6dee9SAndroid Build Coastguard Worker continue 4578*1fa6dee9SAndroid Build Coastguard Worker } 4579*1fa6dee9SAndroid Build Coastguard Worker modules = append(modules, module) 4580*1fa6dee9SAndroid Build Coastguard Worker } 4581*1fa6dee9SAndroid Build Coastguard Worker sort.Sort(moduleSorter{modules, c.nameInterface}) 4582*1fa6dee9SAndroid Build Coastguard Worker sort.Sort(moduleSorter{incrementalModules, c.nameInterface}) 4583*1fa6dee9SAndroid Build Coastguard Worker 4584*1fa6dee9SAndroid Build Coastguard Worker phonys := c.deduplicateOrderOnlyDeps(append(modules, incrementalModules...)) 4585*1fa6dee9SAndroid Build Coastguard Worker if err := orderOnlyForIncremental(c, incrementalModules, phonys); err != nil { 4586*1fa6dee9SAndroid Build Coastguard Worker return err 4587*1fa6dee9SAndroid Build Coastguard Worker } 4588*1fa6dee9SAndroid Build Coastguard Worker 4589*1fa6dee9SAndroid Build Coastguard Worker c.EventHandler.Do("sort_phony_builddefs", func() { 4590*1fa6dee9SAndroid Build Coastguard Worker // sorting for determinism, the phony output names are stable 4591*1fa6dee9SAndroid Build Coastguard Worker sort.Slice(phonys.buildDefs, func(i int, j int) bool { 4592*1fa6dee9SAndroid Build Coastguard Worker return phonys.buildDefs[i].OutputStrings[0] < phonys.buildDefs[j].OutputStrings[0] 4593*1fa6dee9SAndroid Build Coastguard Worker }) 4594*1fa6dee9SAndroid Build Coastguard Worker }) 4595*1fa6dee9SAndroid Build Coastguard Worker 4596*1fa6dee9SAndroid Build Coastguard Worker if err := c.writeLocalBuildActions(nw, phonys); err != nil { 4597*1fa6dee9SAndroid Build Coastguard Worker return err 4598*1fa6dee9SAndroid Build Coastguard Worker } 4599*1fa6dee9SAndroid Build Coastguard Worker 4600*1fa6dee9SAndroid Build Coastguard Worker headerTemplate := template.New("moduleHeader") 4601*1fa6dee9SAndroid Build Coastguard Worker if _, err := headerTemplate.Parse(moduleHeaderTemplate); err != nil { 4602*1fa6dee9SAndroid Build Coastguard Worker // This is a programming error. 4603*1fa6dee9SAndroid Build Coastguard Worker panic(err) 4604*1fa6dee9SAndroid Build Coastguard Worker } 4605*1fa6dee9SAndroid Build Coastguard Worker 4606*1fa6dee9SAndroid Build Coastguard Worker if shardNinja { 4607*1fa6dee9SAndroid Build Coastguard Worker var wg sync.WaitGroup 4608*1fa6dee9SAndroid Build Coastguard Worker errorCh := make(chan error) 4609*1fa6dee9SAndroid Build Coastguard Worker files := GetNinjaShardFiles(ninjaFileName) 4610*1fa6dee9SAndroid Build Coastguard Worker shardedModules := proptools.ShardByCount(modules, len(files)) 4611*1fa6dee9SAndroid Build Coastguard Worker for i, batchModules := range shardedModules { 4612*1fa6dee9SAndroid Build Coastguard Worker file := files[i] 4613*1fa6dee9SAndroid Build Coastguard Worker wg.Add(1) 4614*1fa6dee9SAndroid Build Coastguard Worker go func(file string, batchModules []*moduleInfo) { 4615*1fa6dee9SAndroid Build Coastguard Worker defer wg.Done() 4616*1fa6dee9SAndroid Build Coastguard Worker f, err := c.fs.OpenFile(JoinPath(c.SrcDir(), file), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, OutFilePermissions) 4617*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4618*1fa6dee9SAndroid Build Coastguard Worker errorCh <- fmt.Errorf("error opening Ninja file shard: %s", err) 4619*1fa6dee9SAndroid Build Coastguard Worker return 4620*1fa6dee9SAndroid Build Coastguard Worker } 4621*1fa6dee9SAndroid Build Coastguard Worker defer func() { 4622*1fa6dee9SAndroid Build Coastguard Worker err := f.Close() 4623*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4624*1fa6dee9SAndroid Build Coastguard Worker errorCh <- err 4625*1fa6dee9SAndroid Build Coastguard Worker } 4626*1fa6dee9SAndroid Build Coastguard Worker }() 4627*1fa6dee9SAndroid Build Coastguard Worker buf := bufio.NewWriterSize(f, 16*1024*1024) 4628*1fa6dee9SAndroid Build Coastguard Worker defer func() { 4629*1fa6dee9SAndroid Build Coastguard Worker err := buf.Flush() 4630*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4631*1fa6dee9SAndroid Build Coastguard Worker errorCh <- err 4632*1fa6dee9SAndroid Build Coastguard Worker } 4633*1fa6dee9SAndroid Build Coastguard Worker }() 4634*1fa6dee9SAndroid Build Coastguard Worker writer := newNinjaWriter(buf) 4635*1fa6dee9SAndroid Build Coastguard Worker err = c.writeModuleAction(batchModules, writer, headerTemplate) 4636*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4637*1fa6dee9SAndroid Build Coastguard Worker errorCh <- err 4638*1fa6dee9SAndroid Build Coastguard Worker } 4639*1fa6dee9SAndroid Build Coastguard Worker }(file, batchModules) 4640*1fa6dee9SAndroid Build Coastguard Worker nw.Subninja(file) 4641*1fa6dee9SAndroid Build Coastguard Worker } 4642*1fa6dee9SAndroid Build Coastguard Worker 4643*1fa6dee9SAndroid Build Coastguard Worker if c.GetIncrementalEnabled() { 4644*1fa6dee9SAndroid Build Coastguard Worker suffix := ".ninja" 4645*1fa6dee9SAndroid Build Coastguard Worker base := strings.TrimSuffix(ninjaFileName, suffix) 4646*1fa6dee9SAndroid Build Coastguard Worker file := fmt.Sprintf("%s.incremental%s", base, suffix) 4647*1fa6dee9SAndroid Build Coastguard Worker wg.Add(1) 4648*1fa6dee9SAndroid Build Coastguard Worker go func() { 4649*1fa6dee9SAndroid Build Coastguard Worker defer wg.Done() 4650*1fa6dee9SAndroid Build Coastguard Worker err := writeIncrementalModules(c, file, incrementalModules, headerTemplate) 4651*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4652*1fa6dee9SAndroid Build Coastguard Worker errorCh <- err 4653*1fa6dee9SAndroid Build Coastguard Worker } 4654*1fa6dee9SAndroid Build Coastguard Worker }() 4655*1fa6dee9SAndroid Build Coastguard Worker nw.Subninja(file) 4656*1fa6dee9SAndroid Build Coastguard Worker } 4657*1fa6dee9SAndroid Build Coastguard Worker 4658*1fa6dee9SAndroid Build Coastguard Worker go func() { 4659*1fa6dee9SAndroid Build Coastguard Worker wg.Wait() 4660*1fa6dee9SAndroid Build Coastguard Worker close(errorCh) 4661*1fa6dee9SAndroid Build Coastguard Worker }() 4662*1fa6dee9SAndroid Build Coastguard Worker 4663*1fa6dee9SAndroid Build Coastguard Worker var errors []error 4664*1fa6dee9SAndroid Build Coastguard Worker for newErrors := range errorCh { 4665*1fa6dee9SAndroid Build Coastguard Worker errors = append(errors, newErrors) 4666*1fa6dee9SAndroid Build Coastguard Worker } 4667*1fa6dee9SAndroid Build Coastguard Worker if len(errors) > 0 { 4668*1fa6dee9SAndroid Build Coastguard Worker return proptools.MergeErrors(errors) 4669*1fa6dee9SAndroid Build Coastguard Worker } 4670*1fa6dee9SAndroid Build Coastguard Worker return nil 4671*1fa6dee9SAndroid Build Coastguard Worker } else { 4672*1fa6dee9SAndroid Build Coastguard Worker return c.writeModuleAction(modules, nw, headerTemplate) 4673*1fa6dee9SAndroid Build Coastguard Worker } 4674*1fa6dee9SAndroid Build Coastguard Worker} 4675*1fa6dee9SAndroid Build Coastguard Worker 4676*1fa6dee9SAndroid Build Coastguard Workerfunc orderOnlyForIncremental(c *Context, modules []*moduleInfo, phonys *localBuildActions) error { 4677*1fa6dee9SAndroid Build Coastguard Worker for _, mod := range modules { 4678*1fa6dee9SAndroid Build Coastguard Worker // find the order only strings of the incremental module, it can come from 4679*1fa6dee9SAndroid Build Coastguard Worker // the cache or from buildDefs depending on if the module was skipped or not. 4680*1fa6dee9SAndroid Build Coastguard Worker var orderOnlyStrings []string 4681*1fa6dee9SAndroid Build Coastguard Worker if mod.incrementalRestored { 4682*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStrings = mod.orderOnlyStrings 4683*1fa6dee9SAndroid Build Coastguard Worker } else { 4684*1fa6dee9SAndroid Build Coastguard Worker for _, b := range mod.actionDefs.buildDefs { 4685*1fa6dee9SAndroid Build Coastguard Worker // We do similar check when creating phonys in deduplicateOrderOnlyDeps as well 4686*1fa6dee9SAndroid Build Coastguard Worker if len(b.OrderOnly) > 0 { 4687*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("order only shouldn't be used: %s", mod.Name()) 4688*1fa6dee9SAndroid Build Coastguard Worker } 4689*1fa6dee9SAndroid Build Coastguard Worker for _, str := range b.OrderOnlyStrings { 4690*1fa6dee9SAndroid Build Coastguard Worker if strings.HasPrefix(str, "dedup-") { 4691*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStrings = append(orderOnlyStrings, str) 4692*1fa6dee9SAndroid Build Coastguard Worker } 4693*1fa6dee9SAndroid Build Coastguard Worker } 4694*1fa6dee9SAndroid Build Coastguard Worker } 4695*1fa6dee9SAndroid Build Coastguard Worker } 4696*1fa6dee9SAndroid Build Coastguard Worker 4697*1fa6dee9SAndroid Build Coastguard Worker if len(orderOnlyStrings) == 0 { 4698*1fa6dee9SAndroid Build Coastguard Worker continue 4699*1fa6dee9SAndroid Build Coastguard Worker } 4700*1fa6dee9SAndroid Build Coastguard Worker 4701*1fa6dee9SAndroid Build Coastguard Worker // update the order only string cache with the info found above. 4702*1fa6dee9SAndroid Build Coastguard Worker if data, ok := c.buildActionsToCache[*mod.buildActionCacheKey]; ok { 4703*1fa6dee9SAndroid Build Coastguard Worker data.OrderOnlyStrings = orderOnlyStrings 4704*1fa6dee9SAndroid Build Coastguard Worker } 4705*1fa6dee9SAndroid Build Coastguard Worker 4706*1fa6dee9SAndroid Build Coastguard Worker if !mod.incrementalRestored { 4707*1fa6dee9SAndroid Build Coastguard Worker continue 4708*1fa6dee9SAndroid Build Coastguard Worker } 4709*1fa6dee9SAndroid Build Coastguard Worker 4710*1fa6dee9SAndroid Build Coastguard Worker // if the module is skipped, the order only string that we restored from the 4711*1fa6dee9SAndroid Build Coastguard Worker // cache might not exist anymore. For example, if two modules shared the same 4712*1fa6dee9SAndroid Build Coastguard Worker // set of order only strings initially, deduplicateOrderOnlyDeps would create 4713*1fa6dee9SAndroid Build Coastguard Worker // a dedup-* phony and replace the order only string with this phony for these 4714*1fa6dee9SAndroid Build Coastguard Worker // two modules. If one of the module had its order only strings changed, and 4715*1fa6dee9SAndroid Build Coastguard Worker // we skip the other module in the next build, the dedup-* phony would not 4716*1fa6dee9SAndroid Build Coastguard Worker // in the phony list anymore, so we need to add it here in order to avoid 4717*1fa6dee9SAndroid Build Coastguard Worker // writing the ninja statements for the skipped module, otherwise it would 4718*1fa6dee9SAndroid Build Coastguard Worker // reference a dedup-* phony that no longer exists. 4719*1fa6dee9SAndroid Build Coastguard Worker for _, dep := range orderOnlyStrings { 4720*1fa6dee9SAndroid Build Coastguard Worker // nothing changed to this phony, the cached value is still valid 4721*1fa6dee9SAndroid Build Coastguard Worker if _, ok := c.orderOnlyStringsToCache[dep]; ok { 4722*1fa6dee9SAndroid Build Coastguard Worker continue 4723*1fa6dee9SAndroid Build Coastguard Worker } 4724*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStrings, ok := c.orderOnlyStringsFromCache[dep] 4725*1fa6dee9SAndroid Build Coastguard Worker if !ok { 4726*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("no cached value found for order only dep: %s", dep) 4727*1fa6dee9SAndroid Build Coastguard Worker } 4728*1fa6dee9SAndroid Build Coastguard Worker phony := buildDef{ 4729*1fa6dee9SAndroid Build Coastguard Worker Rule: Phony, 4730*1fa6dee9SAndroid Build Coastguard Worker OutputStrings: []string{dep}, 4731*1fa6dee9SAndroid Build Coastguard Worker InputStrings: orderOnlyStrings, 4732*1fa6dee9SAndroid Build Coastguard Worker Optional: true, 4733*1fa6dee9SAndroid Build Coastguard Worker } 4734*1fa6dee9SAndroid Build Coastguard Worker phonys.buildDefs = append(phonys.buildDefs, &phony) 4735*1fa6dee9SAndroid Build Coastguard Worker c.orderOnlyStringsToCache[dep] = orderOnlyStrings 4736*1fa6dee9SAndroid Build Coastguard Worker } 4737*1fa6dee9SAndroid Build Coastguard Worker } 4738*1fa6dee9SAndroid Build Coastguard Worker return nil 4739*1fa6dee9SAndroid Build Coastguard Worker} 4740*1fa6dee9SAndroid Build Coastguard Workerfunc writeIncrementalModules(c *Context, baseFile string, modules []*moduleInfo, headerTemplate *template.Template) error { 4741*1fa6dee9SAndroid Build Coastguard Worker bf, err := c.fs.OpenFile(JoinPath(c.SrcDir(), baseFile), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, OutFilePermissions) 4742*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4743*1fa6dee9SAndroid Build Coastguard Worker return err 4744*1fa6dee9SAndroid Build Coastguard Worker } 4745*1fa6dee9SAndroid Build Coastguard Worker defer bf.Close() 4746*1fa6dee9SAndroid Build Coastguard Worker bBuf := bufio.NewWriterSize(bf, 16*1024*1024) 4747*1fa6dee9SAndroid Build Coastguard Worker defer bBuf.Flush() 4748*1fa6dee9SAndroid Build Coastguard Worker bWriter := newNinjaWriter(bBuf) 4749*1fa6dee9SAndroid Build Coastguard Worker ninjaPath := filepath.Join(filepath.Dir(baseFile), strings.ReplaceAll(filepath.Base(baseFile), ".", "_")) 4750*1fa6dee9SAndroid Build Coastguard Worker err = os.MkdirAll(JoinPath(c.SrcDir(), ninjaPath), 0755) 4751*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4752*1fa6dee9SAndroid Build Coastguard Worker return err 4753*1fa6dee9SAndroid Build Coastguard Worker } 4754*1fa6dee9SAndroid Build Coastguard Worker for _, module := range modules { 4755*1fa6dee9SAndroid Build Coastguard Worker moduleFile := filepath.Join(ninjaPath, module.ModuleCacheKey()+".ninja") 4756*1fa6dee9SAndroid Build Coastguard Worker if !module.incrementalRestored { 4757*1fa6dee9SAndroid Build Coastguard Worker err := func() error { 4758*1fa6dee9SAndroid Build Coastguard Worker mf, err := c.fs.OpenFile(JoinPath(c.SrcDir(), moduleFile), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, OutFilePermissions) 4759*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4760*1fa6dee9SAndroid Build Coastguard Worker return err 4761*1fa6dee9SAndroid Build Coastguard Worker } 4762*1fa6dee9SAndroid Build Coastguard Worker defer mf.Close() 4763*1fa6dee9SAndroid Build Coastguard Worker mBuf := bufio.NewWriterSize(mf, 4*1024*1024) 4764*1fa6dee9SAndroid Build Coastguard Worker defer mBuf.Flush() 4765*1fa6dee9SAndroid Build Coastguard Worker mWriter := newNinjaWriter(mBuf) 4766*1fa6dee9SAndroid Build Coastguard Worker return c.writeModuleAction([]*moduleInfo{module}, mWriter, headerTemplate) 4767*1fa6dee9SAndroid Build Coastguard Worker }() 4768*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4769*1fa6dee9SAndroid Build Coastguard Worker return err 4770*1fa6dee9SAndroid Build Coastguard Worker } 4771*1fa6dee9SAndroid Build Coastguard Worker } 4772*1fa6dee9SAndroid Build Coastguard Worker bWriter.Subninja(moduleFile) 4773*1fa6dee9SAndroid Build Coastguard Worker } 4774*1fa6dee9SAndroid Build Coastguard Worker return nil 4775*1fa6dee9SAndroid Build Coastguard Worker} 4776*1fa6dee9SAndroid Build Coastguard Worker 4777*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeModuleAction(modules []*moduleInfo, nw *ninjaWriter, headerTemplate *template.Template) error { 4778*1fa6dee9SAndroid Build Coastguard Worker buf := bytes.NewBuffer(nil) 4779*1fa6dee9SAndroid Build Coastguard Worker 4780*1fa6dee9SAndroid Build Coastguard Worker for _, module := range modules { 4781*1fa6dee9SAndroid Build Coastguard Worker if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 { 4782*1fa6dee9SAndroid Build Coastguard Worker continue 4783*1fa6dee9SAndroid Build Coastguard Worker } 4784*1fa6dee9SAndroid Build Coastguard Worker buf.Reset() 4785*1fa6dee9SAndroid Build Coastguard Worker 4786*1fa6dee9SAndroid Build Coastguard Worker // In order to make the bootstrap build manifest independent of the 4787*1fa6dee9SAndroid Build Coastguard Worker // build dir we need to output the Blueprints file locations in the 4788*1fa6dee9SAndroid Build Coastguard Worker // comments as paths relative to the source directory. 4789*1fa6dee9SAndroid Build Coastguard Worker relPos := module.pos 4790*1fa6dee9SAndroid Build Coastguard Worker relPos.Filename = module.relBlueprintsFile 4791*1fa6dee9SAndroid Build Coastguard Worker 4792*1fa6dee9SAndroid Build Coastguard Worker // Get the name and location of the factory function for the module. 4793*1fa6dee9SAndroid Build Coastguard Worker factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer()) 4794*1fa6dee9SAndroid Build Coastguard Worker factoryName := factoryFunc.Name() 4795*1fa6dee9SAndroid Build Coastguard Worker 4796*1fa6dee9SAndroid Build Coastguard Worker infoMap := map[string]interface{}{ 4797*1fa6dee9SAndroid Build Coastguard Worker "name": module.Name(), 4798*1fa6dee9SAndroid Build Coastguard Worker "typeName": module.typeName, 4799*1fa6dee9SAndroid Build Coastguard Worker "goFactory": factoryName, 4800*1fa6dee9SAndroid Build Coastguard Worker "pos": relPos, 4801*1fa6dee9SAndroid Build Coastguard Worker "variant": module.variant.name, 4802*1fa6dee9SAndroid Build Coastguard Worker } 4803*1fa6dee9SAndroid Build Coastguard Worker if err := headerTemplate.Execute(buf, infoMap); err != nil { 4804*1fa6dee9SAndroid Build Coastguard Worker return err 4805*1fa6dee9SAndroid Build Coastguard Worker } 4806*1fa6dee9SAndroid Build Coastguard Worker 4807*1fa6dee9SAndroid Build Coastguard Worker if err := nw.Comment(buf.String()); err != nil { 4808*1fa6dee9SAndroid Build Coastguard Worker return err 4809*1fa6dee9SAndroid Build Coastguard Worker } 4810*1fa6dee9SAndroid Build Coastguard Worker 4811*1fa6dee9SAndroid Build Coastguard Worker if err := nw.BlankLine(); err != nil { 4812*1fa6dee9SAndroid Build Coastguard Worker return err 4813*1fa6dee9SAndroid Build Coastguard Worker } 4814*1fa6dee9SAndroid Build Coastguard Worker 4815*1fa6dee9SAndroid Build Coastguard Worker if err := c.writeLocalBuildActions(nw, &module.actionDefs); err != nil { 4816*1fa6dee9SAndroid Build Coastguard Worker return err 4817*1fa6dee9SAndroid Build Coastguard Worker } 4818*1fa6dee9SAndroid Build Coastguard Worker 4819*1fa6dee9SAndroid Build Coastguard Worker if err := nw.BlankLine(); err != nil { 4820*1fa6dee9SAndroid Build Coastguard Worker return err 4821*1fa6dee9SAndroid Build Coastguard Worker } 4822*1fa6dee9SAndroid Build Coastguard Worker } 4823*1fa6dee9SAndroid Build Coastguard Worker 4824*1fa6dee9SAndroid Build Coastguard Worker return nil 4825*1fa6dee9SAndroid Build Coastguard Worker} 4826*1fa6dee9SAndroid Build Coastguard Worker 4827*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeAllSingletonActions(nw *ninjaWriter) error { 4828*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("singletons") 4829*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("singletons") 4830*1fa6dee9SAndroid Build Coastguard Worker headerTemplate := template.New("singletonHeader") 4831*1fa6dee9SAndroid Build Coastguard Worker _, err := headerTemplate.Parse(singletonHeaderTemplate) 4832*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4833*1fa6dee9SAndroid Build Coastguard Worker // This is a programming error. 4834*1fa6dee9SAndroid Build Coastguard Worker panic(err) 4835*1fa6dee9SAndroid Build Coastguard Worker } 4836*1fa6dee9SAndroid Build Coastguard Worker 4837*1fa6dee9SAndroid Build Coastguard Worker buf := bytes.NewBuffer(nil) 4838*1fa6dee9SAndroid Build Coastguard Worker 4839*1fa6dee9SAndroid Build Coastguard Worker for _, info := range c.singletonInfo { 4840*1fa6dee9SAndroid Build Coastguard Worker if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 { 4841*1fa6dee9SAndroid Build Coastguard Worker continue 4842*1fa6dee9SAndroid Build Coastguard Worker } 4843*1fa6dee9SAndroid Build Coastguard Worker 4844*1fa6dee9SAndroid Build Coastguard Worker // Get the name of the factory function for the module. 4845*1fa6dee9SAndroid Build Coastguard Worker factory := info.factory 4846*1fa6dee9SAndroid Build Coastguard Worker factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer()) 4847*1fa6dee9SAndroid Build Coastguard Worker factoryName := factoryFunc.Name() 4848*1fa6dee9SAndroid Build Coastguard Worker 4849*1fa6dee9SAndroid Build Coastguard Worker buf.Reset() 4850*1fa6dee9SAndroid Build Coastguard Worker infoMap := map[string]interface{}{ 4851*1fa6dee9SAndroid Build Coastguard Worker "name": info.name, 4852*1fa6dee9SAndroid Build Coastguard Worker "goFactory": factoryName, 4853*1fa6dee9SAndroid Build Coastguard Worker } 4854*1fa6dee9SAndroid Build Coastguard Worker err = headerTemplate.Execute(buf, infoMap) 4855*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4856*1fa6dee9SAndroid Build Coastguard Worker return err 4857*1fa6dee9SAndroid Build Coastguard Worker } 4858*1fa6dee9SAndroid Build Coastguard Worker 4859*1fa6dee9SAndroid Build Coastguard Worker err = nw.Comment(buf.String()) 4860*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4861*1fa6dee9SAndroid Build Coastguard Worker return err 4862*1fa6dee9SAndroid Build Coastguard Worker } 4863*1fa6dee9SAndroid Build Coastguard Worker 4864*1fa6dee9SAndroid Build Coastguard Worker err = nw.BlankLine() 4865*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4866*1fa6dee9SAndroid Build Coastguard Worker return err 4867*1fa6dee9SAndroid Build Coastguard Worker } 4868*1fa6dee9SAndroid Build Coastguard Worker 4869*1fa6dee9SAndroid Build Coastguard Worker err = c.writeLocalBuildActions(nw, &info.actionDefs) 4870*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4871*1fa6dee9SAndroid Build Coastguard Worker return err 4872*1fa6dee9SAndroid Build Coastguard Worker } 4873*1fa6dee9SAndroid Build Coastguard Worker 4874*1fa6dee9SAndroid Build Coastguard Worker err = nw.BlankLine() 4875*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4876*1fa6dee9SAndroid Build Coastguard Worker return err 4877*1fa6dee9SAndroid Build Coastguard Worker } 4878*1fa6dee9SAndroid Build Coastguard Worker } 4879*1fa6dee9SAndroid Build Coastguard Worker 4880*1fa6dee9SAndroid Build Coastguard Worker return nil 4881*1fa6dee9SAndroid Build Coastguard Worker} 4882*1fa6dee9SAndroid Build Coastguard Worker 4883*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) GetEventHandler() *metrics.EventHandler { 4884*1fa6dee9SAndroid Build Coastguard Worker return c.EventHandler 4885*1fa6dee9SAndroid Build Coastguard Worker} 4886*1fa6dee9SAndroid Build Coastguard Worker 4887*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) BeginEvent(name string) { 4888*1fa6dee9SAndroid Build Coastguard Worker c.EventHandler.Begin(name) 4889*1fa6dee9SAndroid Build Coastguard Worker} 4890*1fa6dee9SAndroid Build Coastguard Worker 4891*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) EndEvent(name string) { 4892*1fa6dee9SAndroid Build Coastguard Worker c.EventHandler.End(name) 4893*1fa6dee9SAndroid Build Coastguard Worker} 4894*1fa6dee9SAndroid Build Coastguard Worker 4895*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) SetBeforePrepareBuildActionsHook(hookFn func() error) { 4896*1fa6dee9SAndroid Build Coastguard Worker c.BeforePrepareBuildActionsHook = hookFn 4897*1fa6dee9SAndroid Build Coastguard Worker} 4898*1fa6dee9SAndroid Build Coastguard Worker 4899*1fa6dee9SAndroid Build Coastguard Worker// phonyCandidate represents the state of a set of deps that decides its eligibility 4900*1fa6dee9SAndroid Build Coastguard Worker// to be extracted as a phony output 4901*1fa6dee9SAndroid Build Coastguard Workertype phonyCandidate struct { 4902*1fa6dee9SAndroid Build Coastguard Worker sync.Once 4903*1fa6dee9SAndroid Build Coastguard Worker phony *buildDef // the phony buildDef that wraps the set 4904*1fa6dee9SAndroid Build Coastguard Worker first *buildDef // the first buildDef that uses this set 4905*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStrings []string // the original OrderOnlyStrings of the first buildDef that uses this set 4906*1fa6dee9SAndroid Build Coastguard Worker usedByIncremental bool // if the phony is used by any incremental module 4907*1fa6dee9SAndroid Build Coastguard Worker} 4908*1fa6dee9SAndroid Build Coastguard Worker 4909*1fa6dee9SAndroid Build Coastguard Worker// keyForPhonyCandidate gives a unique identifier for a set of deps. 4910*1fa6dee9SAndroid Build Coastguard Workerfunc keyForPhonyCandidate(stringDeps []string) uint64 { 4911*1fa6dee9SAndroid Build Coastguard Worker hasher := fnv.New64a() 4912*1fa6dee9SAndroid Build Coastguard Worker write := func(s string) { 4913*1fa6dee9SAndroid Build Coastguard Worker // The hasher doesn't retain or modify the input slice, so pass the string data directly to avoid 4914*1fa6dee9SAndroid Build Coastguard Worker // an extra allocation and copy. 4915*1fa6dee9SAndroid Build Coastguard Worker _, err := hasher.Write(unsafe.Slice(unsafe.StringData(s), len(s))) 4916*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 4917*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("write failed: %w", err)) 4918*1fa6dee9SAndroid Build Coastguard Worker } 4919*1fa6dee9SAndroid Build Coastguard Worker } 4920*1fa6dee9SAndroid Build Coastguard Worker for _, d := range stringDeps { 4921*1fa6dee9SAndroid Build Coastguard Worker write(d) 4922*1fa6dee9SAndroid Build Coastguard Worker } 4923*1fa6dee9SAndroid Build Coastguard Worker return hasher.Sum64() 4924*1fa6dee9SAndroid Build Coastguard Worker} 4925*1fa6dee9SAndroid Build Coastguard Worker 4926*1fa6dee9SAndroid Build Coastguard Worker// scanBuildDef is called for every known buildDef `b` that has a non-empty `b.OrderOnly`. 4927*1fa6dee9SAndroid Build Coastguard Worker// If `b.OrderOnly` is not present in `candidates`, it gets stored. 4928*1fa6dee9SAndroid Build Coastguard Worker// But if `b.OrderOnly` already exists in `candidates`, then `b.OrderOnly` 4929*1fa6dee9SAndroid Build Coastguard Worker// (and phonyCandidate#first.OrderOnly) will be replaced with phonyCandidate#phony.Outputs 4930*1fa6dee9SAndroid Build Coastguard Workerfunc scanBuildDef(candidates *sync.Map, b *buildDef, incremental bool) { 4931*1fa6dee9SAndroid Build Coastguard Worker key := keyForPhonyCandidate(b.OrderOnlyStrings) 4932*1fa6dee9SAndroid Build Coastguard Worker if v, loaded := candidates.LoadOrStore(key, &phonyCandidate{ 4933*1fa6dee9SAndroid Build Coastguard Worker first: b, 4934*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStrings: b.OrderOnlyStrings, 4935*1fa6dee9SAndroid Build Coastguard Worker usedByIncremental: incremental, 4936*1fa6dee9SAndroid Build Coastguard Worker }); loaded { 4937*1fa6dee9SAndroid Build Coastguard Worker m := v.(*phonyCandidate) 4938*1fa6dee9SAndroid Build Coastguard Worker if slices.Equal(m.orderOnlyStrings, b.OrderOnlyStrings) { 4939*1fa6dee9SAndroid Build Coastguard Worker m.Do(func() { 4940*1fa6dee9SAndroid Build Coastguard Worker // this is the second occurrence and hence it makes sense to 4941*1fa6dee9SAndroid Build Coastguard Worker // extract it as a phony output 4942*1fa6dee9SAndroid Build Coastguard Worker m.phony = &buildDef{ 4943*1fa6dee9SAndroid Build Coastguard Worker Rule: Phony, 4944*1fa6dee9SAndroid Build Coastguard Worker OutputStrings: []string{fmt.Sprintf("dedup-%x", key)}, 4945*1fa6dee9SAndroid Build Coastguard Worker InputStrings: m.first.OrderOnlyStrings, 4946*1fa6dee9SAndroid Build Coastguard Worker Optional: true, 4947*1fa6dee9SAndroid Build Coastguard Worker } 4948*1fa6dee9SAndroid Build Coastguard Worker // the previously recorded build-def, which first had these deps as its 4949*1fa6dee9SAndroid Build Coastguard Worker // order-only deps, should now use this phony output instead 4950*1fa6dee9SAndroid Build Coastguard Worker m.first.OrderOnlyStrings = m.phony.OutputStrings 4951*1fa6dee9SAndroid Build Coastguard Worker m.first = nil 4952*1fa6dee9SAndroid Build Coastguard Worker }) 4953*1fa6dee9SAndroid Build Coastguard Worker b.OrderOnlyStrings = m.phony.OutputStrings 4954*1fa6dee9SAndroid Build Coastguard Worker // don't override the value with false if it was set to true already 4955*1fa6dee9SAndroid Build Coastguard Worker if incremental { 4956*1fa6dee9SAndroid Build Coastguard Worker m.usedByIncremental = incremental 4957*1fa6dee9SAndroid Build Coastguard Worker } 4958*1fa6dee9SAndroid Build Coastguard Worker } 4959*1fa6dee9SAndroid Build Coastguard Worker } 4960*1fa6dee9SAndroid Build Coastguard Worker} 4961*1fa6dee9SAndroid Build Coastguard Worker 4962*1fa6dee9SAndroid Build Coastguard Worker// deduplicateOrderOnlyDeps searches for common sets of order-only dependencies across all 4963*1fa6dee9SAndroid Build Coastguard Worker// buildDef instances in the provided moduleInfo instances. Each such 4964*1fa6dee9SAndroid Build Coastguard Worker// common set forms a new buildDef representing a phony output that then becomes 4965*1fa6dee9SAndroid Build Coastguard Worker// the sole order-only dependency of those buildDef instances 4966*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) deduplicateOrderOnlyDeps(modules []*moduleInfo) *localBuildActions { 4967*1fa6dee9SAndroid Build Coastguard Worker c.BeginEvent("deduplicate_order_only_deps") 4968*1fa6dee9SAndroid Build Coastguard Worker defer c.EndEvent("deduplicate_order_only_deps") 4969*1fa6dee9SAndroid Build Coastguard Worker 4970*1fa6dee9SAndroid Build Coastguard Worker candidates := sync.Map{} //used as map[key]*candidate 4971*1fa6dee9SAndroid Build Coastguard Worker parallelVisit(slices.Values(modules), unorderedVisitorImpl{}, parallelVisitLimit, 4972*1fa6dee9SAndroid Build Coastguard Worker func(m *moduleInfo, pause chan<- pauseSpec) bool { 4973*1fa6dee9SAndroid Build Coastguard Worker incremental := m.buildActionCacheKey != nil 4974*1fa6dee9SAndroid Build Coastguard Worker for _, b := range m.actionDefs.buildDefs { 4975*1fa6dee9SAndroid Build Coastguard Worker // The dedup logic doesn't handle the case where OrderOnly is not empty 4976*1fa6dee9SAndroid Build Coastguard Worker if len(b.OrderOnly) == 0 && len(b.OrderOnlyStrings) > 0 { 4977*1fa6dee9SAndroid Build Coastguard Worker scanBuildDef(&candidates, b, incremental) 4978*1fa6dee9SAndroid Build Coastguard Worker } 4979*1fa6dee9SAndroid Build Coastguard Worker } 4980*1fa6dee9SAndroid Build Coastguard Worker return false 4981*1fa6dee9SAndroid Build Coastguard Worker }) 4982*1fa6dee9SAndroid Build Coastguard Worker 4983*1fa6dee9SAndroid Build Coastguard Worker // now collect all created phonys to return 4984*1fa6dee9SAndroid Build Coastguard Worker var phonys []*buildDef 4985*1fa6dee9SAndroid Build Coastguard Worker candidates.Range(func(_ any, v any) bool { 4986*1fa6dee9SAndroid Build Coastguard Worker candidate := v.(*phonyCandidate) 4987*1fa6dee9SAndroid Build Coastguard Worker if candidate.phony != nil { 4988*1fa6dee9SAndroid Build Coastguard Worker phonys = append(phonys, candidate.phony) 4989*1fa6dee9SAndroid Build Coastguard Worker if candidate.usedByIncremental { 4990*1fa6dee9SAndroid Build Coastguard Worker c.orderOnlyStringsToCache[candidate.phony.OutputStrings[0]] = 4991*1fa6dee9SAndroid Build Coastguard Worker candidate.phony.InputStrings 4992*1fa6dee9SAndroid Build Coastguard Worker } 4993*1fa6dee9SAndroid Build Coastguard Worker } 4994*1fa6dee9SAndroid Build Coastguard Worker return true 4995*1fa6dee9SAndroid Build Coastguard Worker }) 4996*1fa6dee9SAndroid Build Coastguard Worker 4997*1fa6dee9SAndroid Build Coastguard Worker return &localBuildActions{buildDefs: phonys} 4998*1fa6dee9SAndroid Build Coastguard Worker} 4999*1fa6dee9SAndroid Build Coastguard Worker 5000*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) writeLocalBuildActions(nw *ninjaWriter, 5001*1fa6dee9SAndroid Build Coastguard Worker defs *localBuildActions) error { 5002*1fa6dee9SAndroid Build Coastguard Worker 5003*1fa6dee9SAndroid Build Coastguard Worker // Write the local variable assignments. 5004*1fa6dee9SAndroid Build Coastguard Worker for _, v := range defs.variables { 5005*1fa6dee9SAndroid Build Coastguard Worker // A localVariable doesn't need the package names or config to 5006*1fa6dee9SAndroid Build Coastguard Worker // determine its name or value. 5007*1fa6dee9SAndroid Build Coastguard Worker name := v.fullName(nil) 5008*1fa6dee9SAndroid Build Coastguard Worker value, err := v.value(nil, nil) 5009*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5010*1fa6dee9SAndroid Build Coastguard Worker panic(err) 5011*1fa6dee9SAndroid Build Coastguard Worker } 5012*1fa6dee9SAndroid Build Coastguard Worker err = nw.Assign(name, value.Value(c.nameTracker)) 5013*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5014*1fa6dee9SAndroid Build Coastguard Worker return err 5015*1fa6dee9SAndroid Build Coastguard Worker } 5016*1fa6dee9SAndroid Build Coastguard Worker } 5017*1fa6dee9SAndroid Build Coastguard Worker 5018*1fa6dee9SAndroid Build Coastguard Worker if len(defs.variables) > 0 { 5019*1fa6dee9SAndroid Build Coastguard Worker err := nw.BlankLine() 5020*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5021*1fa6dee9SAndroid Build Coastguard Worker return err 5022*1fa6dee9SAndroid Build Coastguard Worker } 5023*1fa6dee9SAndroid Build Coastguard Worker } 5024*1fa6dee9SAndroid Build Coastguard Worker 5025*1fa6dee9SAndroid Build Coastguard Worker // Write the local rules. 5026*1fa6dee9SAndroid Build Coastguard Worker for _, r := range defs.rules { 5027*1fa6dee9SAndroid Build Coastguard Worker // A localRule doesn't need the package names or config to determine 5028*1fa6dee9SAndroid Build Coastguard Worker // its name or definition. 5029*1fa6dee9SAndroid Build Coastguard Worker name := r.fullName(nil) 5030*1fa6dee9SAndroid Build Coastguard Worker def, err := r.def(nil) 5031*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5032*1fa6dee9SAndroid Build Coastguard Worker panic(err) 5033*1fa6dee9SAndroid Build Coastguard Worker } 5034*1fa6dee9SAndroid Build Coastguard Worker 5035*1fa6dee9SAndroid Build Coastguard Worker err = def.WriteTo(nw, name, c.nameTracker) 5036*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5037*1fa6dee9SAndroid Build Coastguard Worker return err 5038*1fa6dee9SAndroid Build Coastguard Worker } 5039*1fa6dee9SAndroid Build Coastguard Worker 5040*1fa6dee9SAndroid Build Coastguard Worker err = nw.BlankLine() 5041*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5042*1fa6dee9SAndroid Build Coastguard Worker return err 5043*1fa6dee9SAndroid Build Coastguard Worker } 5044*1fa6dee9SAndroid Build Coastguard Worker } 5045*1fa6dee9SAndroid Build Coastguard Worker 5046*1fa6dee9SAndroid Build Coastguard Worker // Write the build definitions. 5047*1fa6dee9SAndroid Build Coastguard Worker for _, buildDef := range defs.buildDefs { 5048*1fa6dee9SAndroid Build Coastguard Worker err := buildDef.WriteTo(nw, c.nameTracker) 5049*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5050*1fa6dee9SAndroid Build Coastguard Worker return err 5051*1fa6dee9SAndroid Build Coastguard Worker } 5052*1fa6dee9SAndroid Build Coastguard Worker 5053*1fa6dee9SAndroid Build Coastguard Worker if len(buildDef.Args) > 0 { 5054*1fa6dee9SAndroid Build Coastguard Worker err = nw.BlankLine() 5055*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5056*1fa6dee9SAndroid Build Coastguard Worker return err 5057*1fa6dee9SAndroid Build Coastguard Worker } 5058*1fa6dee9SAndroid Build Coastguard Worker } 5059*1fa6dee9SAndroid Build Coastguard Worker } 5060*1fa6dee9SAndroid Build Coastguard Worker 5061*1fa6dee9SAndroid Build Coastguard Worker return nil 5062*1fa6dee9SAndroid Build Coastguard Worker} 5063*1fa6dee9SAndroid Build Coastguard Worker 5064*1fa6dee9SAndroid Build Coastguard Workerfunc beforeInModuleList(a, b *moduleInfo, list moduleList) bool { 5065*1fa6dee9SAndroid Build Coastguard Worker found := false 5066*1fa6dee9SAndroid Build Coastguard Worker if a == b { 5067*1fa6dee9SAndroid Build Coastguard Worker return false 5068*1fa6dee9SAndroid Build Coastguard Worker } 5069*1fa6dee9SAndroid Build Coastguard Worker for _, l := range list { 5070*1fa6dee9SAndroid Build Coastguard Worker if l == a { 5071*1fa6dee9SAndroid Build Coastguard Worker found = true 5072*1fa6dee9SAndroid Build Coastguard Worker } else if l == b { 5073*1fa6dee9SAndroid Build Coastguard Worker return found 5074*1fa6dee9SAndroid Build Coastguard Worker } 5075*1fa6dee9SAndroid Build Coastguard Worker } 5076*1fa6dee9SAndroid Build Coastguard Worker 5077*1fa6dee9SAndroid Build Coastguard Worker missing := a 5078*1fa6dee9SAndroid Build Coastguard Worker if found { 5079*1fa6dee9SAndroid Build Coastguard Worker missing = b 5080*1fa6dee9SAndroid Build Coastguard Worker } 5081*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("element %v not found in list %v", missing, list)) 5082*1fa6dee9SAndroid Build Coastguard Worker} 5083*1fa6dee9SAndroid Build Coastguard Worker 5084*1fa6dee9SAndroid Build Coastguard Workertype panicError struct { 5085*1fa6dee9SAndroid Build Coastguard Worker panic interface{} 5086*1fa6dee9SAndroid Build Coastguard Worker stack []byte 5087*1fa6dee9SAndroid Build Coastguard Worker in string 5088*1fa6dee9SAndroid Build Coastguard Worker} 5089*1fa6dee9SAndroid Build Coastguard Worker 5090*1fa6dee9SAndroid Build Coastguard Workerfunc newPanicErrorf(panic interface{}, in string, a ...interface{}) error { 5091*1fa6dee9SAndroid Build Coastguard Worker buf := make([]byte, 4096) 5092*1fa6dee9SAndroid Build Coastguard Worker count := runtime.Stack(buf, false) 5093*1fa6dee9SAndroid Build Coastguard Worker return panicError{ 5094*1fa6dee9SAndroid Build Coastguard Worker panic: panic, 5095*1fa6dee9SAndroid Build Coastguard Worker in: fmt.Sprintf(in, a...), 5096*1fa6dee9SAndroid Build Coastguard Worker stack: buf[:count], 5097*1fa6dee9SAndroid Build Coastguard Worker } 5098*1fa6dee9SAndroid Build Coastguard Worker} 5099*1fa6dee9SAndroid Build Coastguard Worker 5100*1fa6dee9SAndroid Build Coastguard Workerfunc (p panicError) Error() string { 5101*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack) 5102*1fa6dee9SAndroid Build Coastguard Worker} 5103*1fa6dee9SAndroid Build Coastguard Worker 5104*1fa6dee9SAndroid Build Coastguard Workerfunc (p *panicError) addIn(in string) { 5105*1fa6dee9SAndroid Build Coastguard Worker p.in += " in " + in 5106*1fa6dee9SAndroid Build Coastguard Worker} 5107*1fa6dee9SAndroid Build Coastguard Worker 5108*1fa6dee9SAndroid Build Coastguard Workerfunc funcName(f interface{}) string { 5109*1fa6dee9SAndroid Build Coastguard Worker return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() 5110*1fa6dee9SAndroid Build Coastguard Worker} 5111*1fa6dee9SAndroid Build Coastguard Worker 5112*1fa6dee9SAndroid Build Coastguard Worker// json representation of a dependency 5113*1fa6dee9SAndroid Build Coastguard Workertype depJson struct { 5114*1fa6dee9SAndroid Build Coastguard Worker Name string `json:"name"` 5115*1fa6dee9SAndroid Build Coastguard Worker Variant string `json:"variant"` 5116*1fa6dee9SAndroid Build Coastguard Worker TagType string `json:"tag_type"` 5117*1fa6dee9SAndroid Build Coastguard Worker TagData interface{} `json:"tag_data"` 5118*1fa6dee9SAndroid Build Coastguard Worker} 5119*1fa6dee9SAndroid Build Coastguard Worker 5120*1fa6dee9SAndroid Build Coastguard Worker// json representation of a provider 5121*1fa6dee9SAndroid Build Coastguard Workertype providerJson struct { 5122*1fa6dee9SAndroid Build Coastguard Worker Type string `json:"type"` 5123*1fa6dee9SAndroid Build Coastguard Worker Debug string `json:"debug"` // from GetDebugString on the provider data 5124*1fa6dee9SAndroid Build Coastguard Worker Fields interface{} `json:"fields"` 5125*1fa6dee9SAndroid Build Coastguard Worker} 5126*1fa6dee9SAndroid Build Coastguard Worker 5127*1fa6dee9SAndroid Build Coastguard Worker// interface for getting debug info from various data. 5128*1fa6dee9SAndroid Build Coastguard Worker// TODO: Consider having this return a json object instead 5129*1fa6dee9SAndroid Build Coastguard Workertype Debuggable interface { 5130*1fa6dee9SAndroid Build Coastguard Worker GetDebugString() string 5131*1fa6dee9SAndroid Build Coastguard Worker} 5132*1fa6dee9SAndroid Build Coastguard Worker 5133*1fa6dee9SAndroid Build Coastguard Worker// Convert a slice in a reflect.Value to a value suitable for outputting to json 5134*1fa6dee9SAndroid Build Coastguard Workerfunc debugSlice(value reflect.Value) interface{} { 5135*1fa6dee9SAndroid Build Coastguard Worker size := value.Len() 5136*1fa6dee9SAndroid Build Coastguard Worker if size == 0 { 5137*1fa6dee9SAndroid Build Coastguard Worker return nil 5138*1fa6dee9SAndroid Build Coastguard Worker } 5139*1fa6dee9SAndroid Build Coastguard Worker result := make([]interface{}, size) 5140*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < size; i++ { 5141*1fa6dee9SAndroid Build Coastguard Worker result[i] = debugValue(value.Index(i)) 5142*1fa6dee9SAndroid Build Coastguard Worker } 5143*1fa6dee9SAndroid Build Coastguard Worker return result 5144*1fa6dee9SAndroid Build Coastguard Worker} 5145*1fa6dee9SAndroid Build Coastguard Worker 5146*1fa6dee9SAndroid Build Coastguard Worker// Convert a map in a reflect.Value to a value suitable for outputting to json 5147*1fa6dee9SAndroid Build Coastguard Workerfunc debugMap(value reflect.Value) interface{} { 5148*1fa6dee9SAndroid Build Coastguard Worker if value.IsNil() { 5149*1fa6dee9SAndroid Build Coastguard Worker return nil 5150*1fa6dee9SAndroid Build Coastguard Worker } 5151*1fa6dee9SAndroid Build Coastguard Worker result := make(map[string]interface{}) 5152*1fa6dee9SAndroid Build Coastguard Worker iter := value.MapRange() 5153*1fa6dee9SAndroid Build Coastguard Worker for iter.Next() { 5154*1fa6dee9SAndroid Build Coastguard Worker // In the (hopefully) rare case of a key collision (which will happen when multiple 5155*1fa6dee9SAndroid Build Coastguard Worker // go-typed keys have the same string representation, we'll just overwrite the last 5156*1fa6dee9SAndroid Build Coastguard Worker // value. 5157*1fa6dee9SAndroid Build Coastguard Worker result[debugKey(iter.Key())] = debugValue(iter.Value()) 5158*1fa6dee9SAndroid Build Coastguard Worker } 5159*1fa6dee9SAndroid Build Coastguard Worker return result 5160*1fa6dee9SAndroid Build Coastguard Worker} 5161*1fa6dee9SAndroid Build Coastguard Worker 5162*1fa6dee9SAndroid Build Coastguard Worker// Convert a value into a string, suitable for being a json map key. 5163*1fa6dee9SAndroid Build Coastguard Workerfunc debugKey(value reflect.Value) string { 5164*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("%v", value) 5165*1fa6dee9SAndroid Build Coastguard Worker} 5166*1fa6dee9SAndroid Build Coastguard Worker 5167*1fa6dee9SAndroid Build Coastguard Worker// Convert a single value (possibly a map or slice too) in a reflect.Value to a value suitable for outputting to json 5168*1fa6dee9SAndroid Build Coastguard Workerfunc debugValue(value reflect.Value) interface{} { 5169*1fa6dee9SAndroid Build Coastguard Worker // Remember if we originally received a reflect.Interface. 5170*1fa6dee9SAndroid Build Coastguard Worker wasInterface := value.Kind() == reflect.Interface 5171*1fa6dee9SAndroid Build Coastguard Worker // Dereference pointers down to the real type 5172*1fa6dee9SAndroid Build Coastguard Worker for value.Kind() == reflect.Ptr || value.Kind() == reflect.Interface { 5173*1fa6dee9SAndroid Build Coastguard Worker // If it's nil, return nil 5174*1fa6dee9SAndroid Build Coastguard Worker if value.IsNil() { 5175*1fa6dee9SAndroid Build Coastguard Worker return nil 5176*1fa6dee9SAndroid Build Coastguard Worker } 5177*1fa6dee9SAndroid Build Coastguard Worker value = value.Elem() 5178*1fa6dee9SAndroid Build Coastguard Worker } 5179*1fa6dee9SAndroid Build Coastguard Worker 5180*1fa6dee9SAndroid Build Coastguard Worker // Skip private fields, maybe other weird corner cases of go's bizarre type system. 5181*1fa6dee9SAndroid Build Coastguard Worker if !value.CanInterface() { 5182*1fa6dee9SAndroid Build Coastguard Worker return nil 5183*1fa6dee9SAndroid Build Coastguard Worker } 5184*1fa6dee9SAndroid Build Coastguard Worker 5185*1fa6dee9SAndroid Build Coastguard Worker switch kind := value.Kind(); kind { 5186*1fa6dee9SAndroid Build Coastguard Worker case reflect.Bool, reflect.String, reflect.Int, reflect.Uint: 5187*1fa6dee9SAndroid Build Coastguard Worker return value.Interface() 5188*1fa6dee9SAndroid Build Coastguard Worker case reflect.Slice: 5189*1fa6dee9SAndroid Build Coastguard Worker return debugSlice(value) 5190*1fa6dee9SAndroid Build Coastguard Worker case reflect.Struct: 5191*1fa6dee9SAndroid Build Coastguard Worker // If we originally received an interface, and there is a String() method, call that. 5192*1fa6dee9SAndroid Build Coastguard Worker // TODO: figure out why Path doesn't work correctly otherwise (in aconfigPropagatingDeclarationsInfo) 5193*1fa6dee9SAndroid Build Coastguard Worker if s, ok := value.Interface().(interface{ String() string }); wasInterface && ok { 5194*1fa6dee9SAndroid Build Coastguard Worker return s.String() 5195*1fa6dee9SAndroid Build Coastguard Worker } 5196*1fa6dee9SAndroid Build Coastguard Worker return debugStruct(value) 5197*1fa6dee9SAndroid Build Coastguard Worker case reflect.Map: 5198*1fa6dee9SAndroid Build Coastguard Worker return debugMap(value) 5199*1fa6dee9SAndroid Build Coastguard Worker default: 5200*1fa6dee9SAndroid Build Coastguard Worker // TODO: add cases as we find them. 5201*1fa6dee9SAndroid Build Coastguard Worker return fmt.Sprintf("debugValue(Kind=%v, wasInterface=%v)", kind, wasInterface) 5202*1fa6dee9SAndroid Build Coastguard Worker } 5203*1fa6dee9SAndroid Build Coastguard Worker 5204*1fa6dee9SAndroid Build Coastguard Worker return nil 5205*1fa6dee9SAndroid Build Coastguard Worker} 5206*1fa6dee9SAndroid Build Coastguard Worker 5207*1fa6dee9SAndroid Build Coastguard Worker// Convert an object in a reflect.Value to a value suitable for outputting to json 5208*1fa6dee9SAndroid Build Coastguard Workerfunc debugStruct(value reflect.Value) interface{} { 5209*1fa6dee9SAndroid Build Coastguard Worker result := make(map[string]interface{}) 5210*1fa6dee9SAndroid Build Coastguard Worker debugStructAppend(value, &result) 5211*1fa6dee9SAndroid Build Coastguard Worker if len(result) == 0 { 5212*1fa6dee9SAndroid Build Coastguard Worker return nil 5213*1fa6dee9SAndroid Build Coastguard Worker } 5214*1fa6dee9SAndroid Build Coastguard Worker return result 5215*1fa6dee9SAndroid Build Coastguard Worker} 5216*1fa6dee9SAndroid Build Coastguard Worker 5217*1fa6dee9SAndroid Build Coastguard Worker// Convert an object to a value suiable for outputting to json 5218*1fa6dee9SAndroid Build Coastguard Workerfunc debugStructAppend(value reflect.Value, result *map[string]interface{}) { 5219*1fa6dee9SAndroid Build Coastguard Worker for value.Kind() == reflect.Ptr { 5220*1fa6dee9SAndroid Build Coastguard Worker if value.IsNil() { 5221*1fa6dee9SAndroid Build Coastguard Worker return 5222*1fa6dee9SAndroid Build Coastguard Worker } 5223*1fa6dee9SAndroid Build Coastguard Worker value = value.Elem() 5224*1fa6dee9SAndroid Build Coastguard Worker } 5225*1fa6dee9SAndroid Build Coastguard Worker if value.IsZero() { 5226*1fa6dee9SAndroid Build Coastguard Worker return 5227*1fa6dee9SAndroid Build Coastguard Worker } 5228*1fa6dee9SAndroid Build Coastguard Worker 5229*1fa6dee9SAndroid Build Coastguard Worker if value.Kind() != reflect.Struct { 5230*1fa6dee9SAndroid Build Coastguard Worker // TODO: could maybe support other types 5231*1fa6dee9SAndroid Build Coastguard Worker return 5232*1fa6dee9SAndroid Build Coastguard Worker } 5233*1fa6dee9SAndroid Build Coastguard Worker 5234*1fa6dee9SAndroid Build Coastguard Worker structType := value.Type() 5235*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < value.NumField(); i++ { 5236*1fa6dee9SAndroid Build Coastguard Worker v := debugValue(value.Field(i)) 5237*1fa6dee9SAndroid Build Coastguard Worker if v != nil { 5238*1fa6dee9SAndroid Build Coastguard Worker (*result)[structType.Field(i).Name] = v 5239*1fa6dee9SAndroid Build Coastguard Worker } 5240*1fa6dee9SAndroid Build Coastguard Worker } 5241*1fa6dee9SAndroid Build Coastguard Worker} 5242*1fa6dee9SAndroid Build Coastguard Worker 5243*1fa6dee9SAndroid Build Coastguard Workerfunc debugPropertyStruct(props interface{}, result *map[string]interface{}) { 5244*1fa6dee9SAndroid Build Coastguard Worker if props == nil { 5245*1fa6dee9SAndroid Build Coastguard Worker return 5246*1fa6dee9SAndroid Build Coastguard Worker } 5247*1fa6dee9SAndroid Build Coastguard Worker debugStructAppend(reflect.ValueOf(props), result) 5248*1fa6dee9SAndroid Build Coastguard Worker} 5249*1fa6dee9SAndroid Build Coastguard Worker 5250*1fa6dee9SAndroid Build Coastguard Worker// Get the debug json for a single module. Returns thae data as 5251*1fa6dee9SAndroid Build Coastguard Worker// flattened json text for easy concatenation by GenerateModuleDebugInfo. 5252*1fa6dee9SAndroid Build Coastguard Workerfunc getModuleDebugJson(module *moduleInfo) []byte { 5253*1fa6dee9SAndroid Build Coastguard Worker info := struct { 5254*1fa6dee9SAndroid Build Coastguard Worker Name string `json:"name"` 5255*1fa6dee9SAndroid Build Coastguard Worker SourceFile string `json:"source_file"` 5256*1fa6dee9SAndroid Build Coastguard Worker SourceLine int `json:"source_line"` 5257*1fa6dee9SAndroid Build Coastguard Worker Type string `json:"type"` 5258*1fa6dee9SAndroid Build Coastguard Worker Variant string `json:"variant"` 5259*1fa6dee9SAndroid Build Coastguard Worker Deps []depJson `json:"deps"` 5260*1fa6dee9SAndroid Build Coastguard Worker Providers []providerJson `json:"providers"` 5261*1fa6dee9SAndroid Build Coastguard Worker Debug string `json:"debug"` // from GetDebugString on the module 5262*1fa6dee9SAndroid Build Coastguard Worker Properties map[string]interface{} `json:"properties"` 5263*1fa6dee9SAndroid Build Coastguard Worker }{ 5264*1fa6dee9SAndroid Build Coastguard Worker Name: module.logicModule.Name(), 5265*1fa6dee9SAndroid Build Coastguard Worker SourceFile: module.pos.Filename, 5266*1fa6dee9SAndroid Build Coastguard Worker SourceLine: module.pos.Line, 5267*1fa6dee9SAndroid Build Coastguard Worker Type: module.typeName, 5268*1fa6dee9SAndroid Build Coastguard Worker Variant: module.variant.name, 5269*1fa6dee9SAndroid Build Coastguard Worker Deps: func() []depJson { 5270*1fa6dee9SAndroid Build Coastguard Worker result := make([]depJson, len(module.directDeps)) 5271*1fa6dee9SAndroid Build Coastguard Worker for i, dep := range module.directDeps { 5272*1fa6dee9SAndroid Build Coastguard Worker result[i] = depJson{ 5273*1fa6dee9SAndroid Build Coastguard Worker Name: dep.module.logicModule.Name(), 5274*1fa6dee9SAndroid Build Coastguard Worker Variant: dep.module.variant.name, 5275*1fa6dee9SAndroid Build Coastguard Worker } 5276*1fa6dee9SAndroid Build Coastguard Worker t := reflect.TypeOf(dep.tag) 5277*1fa6dee9SAndroid Build Coastguard Worker if t != nil { 5278*1fa6dee9SAndroid Build Coastguard Worker result[i].TagType = t.PkgPath() + "." + t.Name() 5279*1fa6dee9SAndroid Build Coastguard Worker result[i].TagData = debugStruct(reflect.ValueOf(dep.tag)) 5280*1fa6dee9SAndroid Build Coastguard Worker } 5281*1fa6dee9SAndroid Build Coastguard Worker } 5282*1fa6dee9SAndroid Build Coastguard Worker return result 5283*1fa6dee9SAndroid Build Coastguard Worker }(), 5284*1fa6dee9SAndroid Build Coastguard Worker Providers: func() []providerJson { 5285*1fa6dee9SAndroid Build Coastguard Worker result := make([]providerJson, 0, len(module.providers)) 5286*1fa6dee9SAndroid Build Coastguard Worker for _, p := range module.providers { 5287*1fa6dee9SAndroid Build Coastguard Worker pj := providerJson{} 5288*1fa6dee9SAndroid Build Coastguard Worker include := false 5289*1fa6dee9SAndroid Build Coastguard Worker 5290*1fa6dee9SAndroid Build Coastguard Worker t := reflect.TypeOf(p) 5291*1fa6dee9SAndroid Build Coastguard Worker if t != nil { 5292*1fa6dee9SAndroid Build Coastguard Worker pj.Type = t.PkgPath() + "." + t.Name() 5293*1fa6dee9SAndroid Build Coastguard Worker include = true 5294*1fa6dee9SAndroid Build Coastguard Worker } 5295*1fa6dee9SAndroid Build Coastguard Worker 5296*1fa6dee9SAndroid Build Coastguard Worker if dbg, ok := p.(Debuggable); ok { 5297*1fa6dee9SAndroid Build Coastguard Worker pj.Debug = dbg.GetDebugString() 5298*1fa6dee9SAndroid Build Coastguard Worker if pj.Debug != "" { 5299*1fa6dee9SAndroid Build Coastguard Worker include = true 5300*1fa6dee9SAndroid Build Coastguard Worker } 5301*1fa6dee9SAndroid Build Coastguard Worker } 5302*1fa6dee9SAndroid Build Coastguard Worker 5303*1fa6dee9SAndroid Build Coastguard Worker if p != nil { 5304*1fa6dee9SAndroid Build Coastguard Worker pj.Fields = debugValue(reflect.ValueOf(p)) 5305*1fa6dee9SAndroid Build Coastguard Worker include = true 5306*1fa6dee9SAndroid Build Coastguard Worker } 5307*1fa6dee9SAndroid Build Coastguard Worker 5308*1fa6dee9SAndroid Build Coastguard Worker if include { 5309*1fa6dee9SAndroid Build Coastguard Worker result = append(result, pj) 5310*1fa6dee9SAndroid Build Coastguard Worker } 5311*1fa6dee9SAndroid Build Coastguard Worker } 5312*1fa6dee9SAndroid Build Coastguard Worker return result 5313*1fa6dee9SAndroid Build Coastguard Worker }(), 5314*1fa6dee9SAndroid Build Coastguard Worker Debug: func() string { 5315*1fa6dee9SAndroid Build Coastguard Worker if dbg, ok := module.logicModule.(Debuggable); ok { 5316*1fa6dee9SAndroid Build Coastguard Worker return dbg.GetDebugString() 5317*1fa6dee9SAndroid Build Coastguard Worker } else { 5318*1fa6dee9SAndroid Build Coastguard Worker return "" 5319*1fa6dee9SAndroid Build Coastguard Worker } 5320*1fa6dee9SAndroid Build Coastguard Worker }(), 5321*1fa6dee9SAndroid Build Coastguard Worker Properties: func() map[string]interface{} { 5322*1fa6dee9SAndroid Build Coastguard Worker result := make(map[string]interface{}) 5323*1fa6dee9SAndroid Build Coastguard Worker for _, props := range module.properties { 5324*1fa6dee9SAndroid Build Coastguard Worker debugPropertyStruct(props, &result) 5325*1fa6dee9SAndroid Build Coastguard Worker } 5326*1fa6dee9SAndroid Build Coastguard Worker return result 5327*1fa6dee9SAndroid Build Coastguard Worker }(), 5328*1fa6dee9SAndroid Build Coastguard Worker } 5329*1fa6dee9SAndroid Build Coastguard Worker buf, _ := json.Marshal(info) 5330*1fa6dee9SAndroid Build Coastguard Worker return buf 5331*1fa6dee9SAndroid Build Coastguard Worker} 5332*1fa6dee9SAndroid Build Coastguard Worker 5333*1fa6dee9SAndroid Build Coastguard Worker// Generate out/soong/soong-debug-info.json Called if GENERATE_SOONG_DEBUG=true. 5334*1fa6dee9SAndroid Build Coastguard Workerfunc (this *Context) GenerateModuleDebugInfo(filename string) { 5335*1fa6dee9SAndroid Build Coastguard Worker err := os.MkdirAll(filepath.Dir(filename), 0777) 5336*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5337*1fa6dee9SAndroid Build Coastguard Worker // We expect this to be writable 5338*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Sprintf("couldn't create directory for soong module debug file %s: %s", filepath.Dir(filename), err)) 5339*1fa6dee9SAndroid Build Coastguard Worker } 5340*1fa6dee9SAndroid Build Coastguard Worker 5341*1fa6dee9SAndroid Build Coastguard Worker f, err := os.Create(filename) 5342*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 5343*1fa6dee9SAndroid Build Coastguard Worker // We expect this to be writable 5344*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Sprintf("couldn't create soong module debug file %s: %s", filename, err)) 5345*1fa6dee9SAndroid Build Coastguard Worker } 5346*1fa6dee9SAndroid Build Coastguard Worker defer f.Close() 5347*1fa6dee9SAndroid Build Coastguard Worker 5348*1fa6dee9SAndroid Build Coastguard Worker needComma := false 5349*1fa6dee9SAndroid Build Coastguard Worker f.WriteString("{\n\"modules\": [\n") 5350*1fa6dee9SAndroid Build Coastguard Worker 5351*1fa6dee9SAndroid Build Coastguard Worker // TODO: Optimize this (parallel execution, etc) if it gets slow. 5352*1fa6dee9SAndroid Build Coastguard Worker this.visitAllModuleInfos(func(module *moduleInfo) { 5353*1fa6dee9SAndroid Build Coastguard Worker if needComma { 5354*1fa6dee9SAndroid Build Coastguard Worker f.WriteString(",\n") 5355*1fa6dee9SAndroid Build Coastguard Worker } else { 5356*1fa6dee9SAndroid Build Coastguard Worker needComma = true 5357*1fa6dee9SAndroid Build Coastguard Worker } 5358*1fa6dee9SAndroid Build Coastguard Worker 5359*1fa6dee9SAndroid Build Coastguard Worker moduleData := getModuleDebugJson(module) 5360*1fa6dee9SAndroid Build Coastguard Worker f.Write(moduleData) 5361*1fa6dee9SAndroid Build Coastguard Worker }) 5362*1fa6dee9SAndroid Build Coastguard Worker 5363*1fa6dee9SAndroid Build Coastguard Worker f.WriteString("\n]\n}") 5364*1fa6dee9SAndroid Build Coastguard Worker} 5365*1fa6dee9SAndroid Build Coastguard Worker 5366*1fa6dee9SAndroid Build Coastguard Workervar fileHeaderTemplate = `****************************************************************************** 5367*1fa6dee9SAndroid Build Coastguard Worker*** This file is generated and should not be edited *** 5368*1fa6dee9SAndroid Build Coastguard Worker****************************************************************************** 5369*1fa6dee9SAndroid Build Coastguard Worker{{if .Pkgs}} 5370*1fa6dee9SAndroid Build Coastguard WorkerThis file contains variables, rules, and pools with name prefixes indicating 5371*1fa6dee9SAndroid Build Coastguard Workerthey were generated by the following Go packages: 5372*1fa6dee9SAndroid Build Coastguard Worker{{range .Pkgs}} 5373*1fa6dee9SAndroid Build Coastguard Worker {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}} 5374*1fa6dee9SAndroid Build Coastguard Worker 5375*1fa6dee9SAndroid Build Coastguard Worker` 5376*1fa6dee9SAndroid Build Coastguard Worker 5377*1fa6dee9SAndroid Build Coastguard Workervar moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 5378*1fa6dee9SAndroid Build Coastguard WorkerModule: {{.name}} 5379*1fa6dee9SAndroid Build Coastguard WorkerVariant: {{.variant}} 5380*1fa6dee9SAndroid Build Coastguard WorkerType: {{.typeName}} 5381*1fa6dee9SAndroid Build Coastguard WorkerFactory: {{.goFactory}} 5382*1fa6dee9SAndroid Build Coastguard WorkerDefined: {{.pos}} 5383*1fa6dee9SAndroid Build Coastguard Worker` 5384*1fa6dee9SAndroid Build Coastguard Worker 5385*1fa6dee9SAndroid Build Coastguard Workervar singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 5386*1fa6dee9SAndroid Build Coastguard WorkerSingleton: {{.name}} 5387*1fa6dee9SAndroid Build Coastguard WorkerFactory: {{.goFactory}} 5388*1fa6dee9SAndroid Build Coastguard Worker` 5389*1fa6dee9SAndroid Build Coastguard Worker 5390*1fa6dee9SAndroid Build Coastguard Workerfunc JoinPath(base, path string) string { 5391*1fa6dee9SAndroid Build Coastguard Worker if filepath.IsAbs(path) { 5392*1fa6dee9SAndroid Build Coastguard Worker return path 5393*1fa6dee9SAndroid Build Coastguard Worker } 5394*1fa6dee9SAndroid Build Coastguard Worker return filepath.Join(base, path) 5395*1fa6dee9SAndroid Build Coastguard Worker} 5396