blob: 99e642101bec232007a58dd54aa0b4f554ec79e9 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
19 "errors"
20 "fmt"
21 "io"
22 "os"
23 "path/filepath"
24 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070025 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070026 "sort"
Colin Cross6134a5c2015-02-10 11:26:26 -080027 "strconv"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070028 "strings"
29 "text/scanner"
30 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070031
32 "github.com/google/blueprint/parser"
33 "github.com/google/blueprint/pathtools"
34 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070035)
36
37var ErrBuildActionsNotReady = errors.New("build actions are not ready")
38
39const maxErrors = 10
40
Jamie Gennisd4e10182014-06-12 20:06:50 -070041// A Context contains all the state needed to parse a set of Blueprints files
42// and generate a Ninja file. The process of generating a Ninja file proceeds
43// through a series of four phases. Each phase corresponds with a some methods
44// on the Context object
45//
46// Phase Methods
47// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070048// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070049//
50// 2. Parse ParseBlueprintsFiles, Parse
51//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070052// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070053//
54// 4. Write WriteBuildFile
55//
56// The registration phase prepares the context to process Blueprints files
57// containing various types of modules. The parse phase reads in one or more
58// Blueprints files and validates their contents against the module types that
59// have been registered. The generate phase then analyzes the parsed Blueprints
60// contents to create an internal representation for the build actions that must
61// be performed. This phase also performs validation of the module dependencies
62// and property values defined in the parsed Blueprints files. Finally, the
63// write phase generates the Ninja manifest text based on the generated build
64// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070065type Context struct {
66 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070067 moduleFactories map[string]ModuleFactory
68 moduleGroups map[string]*moduleGroup
69 moduleInfo map[Module]*moduleInfo
70 modulesSorted []*moduleInfo
71 singletonInfo map[string]*singletonInfo
72 mutatorInfo []*mutatorInfo
73 earlyMutatorInfo []*earlyMutatorInfo
74 variantMutatorNames []string
75 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070076
77 dependenciesReady bool // set to true on a successful ResolveDependencies
78 buildActionsReady bool // set to true on a successful PrepareBuildActions
79
80 // set by SetIgnoreUnknownModuleTypes
81 ignoreUnknownModuleTypes bool
82
83 // set during PrepareBuildActions
Jamie Gennis2fb20952014-10-03 02:49:58 -070084 pkgNames map[*PackageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070085 globalVariables map[Variable]*ninjaString
86 globalPools map[Pool]*poolDef
87 globalRules map[Rule]*ruleDef
88
89 // set during PrepareBuildActions
90 buildDir *ninjaString // The builddir special Ninja variable
91 requiredNinjaMajor int // For the ninja_required_version variable
92 requiredNinjaMinor int // For the ninja_required_version variable
93 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070094
95 // set lazily by sortedModuleNames
96 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070097}
98
Jamie Gennisd4e10182014-06-12 20:06:50 -070099// An Error describes a problem that was encountered that is related to a
100// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700101type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700102 Err error // the error that occurred
103 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700104}
105
106type localBuildActions struct {
107 variables []*localVariable
108 rules []*localRule
109 buildDefs []*buildDef
110}
111
Colin Crossbbfa51a2014-12-17 16:12:41 -0800112type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700113 name string
114 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700115
Colin Crossbbfa51a2014-12-17 16:12:41 -0800116 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700117}
118
Colin Crossbbfa51a2014-12-17 16:12:41 -0800119type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700120 // set during Parse
121 typeName string
122 relBlueprintsFile string
123 pos scanner.Position
124 propertyPos map[string]scanner.Position
125 properties struct {
126 Name string
127 Deps []string
128 }
129
Colin Crossf5e34b92015-03-13 16:02:36 -0700130 variantName string
131 variant variationMap
132 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700133
Colin Crossc9028482014-12-18 16:28:54 -0800134 logicModule Module
135 group *moduleGroup
136 moduleProperties []interface{}
137
138 // set during ResolveDependencies
139 directDeps []*moduleInfo
140
Colin Cross7addea32015-03-11 15:43:52 -0700141 // set during updateDependencies
142 reverseDeps []*moduleInfo
143 depsCount int
144
145 // used by parallelVisitAllBottomUp
146 waitingCount int
147
Colin Crossc9028482014-12-18 16:28:54 -0800148 // set during each runMutator
149 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700150
151 // set during PrepareBuildActions
152 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800153}
154
Colin Crossf5e34b92015-03-13 16:02:36 -0700155// A Variation is a way that a variant of a module differs from other variants of the same module.
156// For example, two variants of the same module might have Variation{"arch","arm"} and
157// Variation{"arch","arm64"}
158type Variation struct {
159 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700160 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700161 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
162 // "shared" or "static" for link.
163 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700164}
165
Colin Crossf5e34b92015-03-13 16:02:36 -0700166// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
167type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700168
Colin Crossf5e34b92015-03-13 16:02:36 -0700169func (vm variationMap) clone() variationMap {
170 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700171 for k, v := range vm {
172 newVm[k] = v
173 }
174
175 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800176}
177
Colin Cross89486232015-05-08 11:14:54 -0700178// Compare this variationMap to another one. Returns true if the every entry in this map
179// is either the same in the other map or doesn't exist in the other map.
180func (vm variationMap) subset(other variationMap) bool {
181 for k, v1 := range vm {
182 if v2, ok := other[k]; ok && v1 != v2 {
183 return false
184 }
185 }
186 return true
187}
188
Colin Crossf5e34b92015-03-13 16:02:36 -0700189func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700190 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800191}
192
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700193type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700194 // set during RegisterSingletonType
195 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700196 singleton Singleton
197
198 // set during PrepareBuildActions
199 actionDefs localBuildActions
200}
201
Colin Crossc9028482014-12-18 16:28:54 -0800202type mutatorInfo struct {
203 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800204 topDownMutator TopDownMutator
205 bottomUpMutator BottomUpMutator
206 name string
Colin Crossc9028482014-12-18 16:28:54 -0800207}
208
Colin Cross65569e42015-03-10 20:08:19 -0700209type earlyMutatorInfo struct {
210 // set during RegisterEarlyMutator
211 mutator EarlyMutator
212 name string
213}
214
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700215func (e *Error) Error() string {
216
217 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
218}
219
Jamie Gennisd4e10182014-06-12 20:06:50 -0700220// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700221// no module or singleton factories registered, so the RegisterModuleFactory and
222// RegisterSingletonFactory methods must be called before it can do anything
223// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700224func NewContext() *Context {
225 return &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800226 moduleFactories: make(map[string]ModuleFactory),
227 moduleGroups: make(map[string]*moduleGroup),
228 moduleInfo: make(map[Module]*moduleInfo),
229 singletonInfo: make(map[string]*singletonInfo),
230 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700231 }
232}
233
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700234// A ModuleFactory function creates a new Module object. See the
235// Context.RegisterModuleType method for details about how a registered
236// ModuleFactory is used by a Context.
237type ModuleFactory func() (m Module, propertyStructs []interface{})
238
Jamie Gennisd4e10182014-06-12 20:06:50 -0700239// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700240// Blueprints file) with a Module factory function. When the given module type
241// name is encountered in a Blueprints file during parsing, the Module factory
242// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800243// generation for the module. If a Mutator splits a module into multiple variants,
244// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700245//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700246// The module type names given here must be unique for the context. The factory
247// function should be a named function so that its package and name can be
248// included in the generated Ninja file for debugging purposes.
249//
250// The factory function returns two values. The first is the newly created
251// Module object. The second is a slice of pointers to that Module object's
252// properties structs. Each properties struct is examined when parsing a module
253// definition of this type in a Blueprints file. Exported fields of the
254// properties structs are automatically set to the property values specified in
255// the Blueprints file. The properties struct field names determine the name of
256// the Blueprints file properties that are used - the Blueprints property name
257// matches that of the properties struct field name with the first letter
258// converted to lower-case.
259//
260// The fields of the properties struct must be either []string, a string, or
261// bool. The Context will panic if a Module gets instantiated with a properties
262// struct containing a field that is not one these supported types.
263//
264// Any properties that appear in the Blueprints files that are not built-in
265// module properties (such as "name" and "deps") and do not have a corresponding
266// field in the returned module properties struct result in an error during the
267// Context's parse phase.
268//
269// As an example, the follow code:
270//
271// type myModule struct {
272// properties struct {
273// Foo string
274// Bar []string
275// }
276// }
277//
278// func NewMyModule() (blueprint.Module, []interface{}) {
279// module := new(myModule)
280// properties := &module.properties
281// return module, []interface{}{properties}
282// }
283//
284// func main() {
285// ctx := blueprint.NewContext()
286// ctx.RegisterModuleType("my_module", NewMyModule)
287// // ...
288// }
289//
290// would support parsing a module defined in a Blueprints file as follows:
291//
292// my_module {
293// name: "myName",
294// foo: "my foo string",
295// bar: ["my", "bar", "strings"],
296// }
297//
Colin Cross7ad621c2015-01-07 16:22:45 -0800298// The factory function may be called from multiple goroutines. Any accesses
299// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700300func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
301 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700302 panic(errors.New("module type name is already registered"))
303 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700304 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700305}
306
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700307// A SingletonFactory function creates a new Singleton object. See the
308// Context.RegisterSingletonType method for details about how a registered
309// SingletonFactory is used by a Context.
310type SingletonFactory func() Singleton
311
312// RegisterSingletonType registers a singleton type that will be invoked to
313// generate build actions. Each registered singleton type is instantiated and
314// and invoked exactly once as part of the generate phase.
315//
316// The singleton type names given here must be unique for the context. The
317// factory function should be a named function so that its package and name can
318// be included in the generated Ninja file for debugging purposes.
319func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700320 if _, present := c.singletonInfo[name]; present {
321 panic(errors.New("singleton name is already registered"))
322 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700323
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700324 c.singletonInfo[name] = &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700325 factory: factory,
326 singleton: factory(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700327 }
328}
329
330func singletonPkgPath(singleton Singleton) string {
331 typ := reflect.TypeOf(singleton)
332 for typ.Kind() == reflect.Ptr {
333 typ = typ.Elem()
334 }
335 return typ.PkgPath()
336}
337
338func singletonTypeName(singleton Singleton) string {
339 typ := reflect.TypeOf(singleton)
340 for typ.Kind() == reflect.Ptr {
341 typ = typ.Elem()
342 }
343 return typ.PkgPath() + "." + typ.Name()
344}
345
Colin Crossc9028482014-12-18 16:28:54 -0800346// RegisterTopDownMutator registers a mutator that will be invoked to propagate
347// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700348// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
349// once per Module, and is invoked on a module before being invoked on any of its
350// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800351//
Colin Cross65569e42015-03-10 20:08:19 -0700352// The mutator type names given here must be unique to all top down mutators in
353// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800354func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
355 for _, m := range c.mutatorInfo {
356 if m.name == name && m.topDownMutator != nil {
357 panic(fmt.Errorf("mutator name %s is already registered", name))
358 }
359 }
360
361 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
362 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800363 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800364 })
365}
366
367// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700368// Modules into variants. Each registered mutator is invoked in registration
369// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
370// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800371//
Colin Cross65569e42015-03-10 20:08:19 -0700372// The mutator type names given here must be unique to all bottom up or early
373// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800374func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700375 for _, m := range c.variantMutatorNames {
376 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800377 panic(fmt.Errorf("mutator name %s is already registered", name))
378 }
379 }
380
381 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
382 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800383 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800384 })
Colin Cross65569e42015-03-10 20:08:19 -0700385
386 c.variantMutatorNames = append(c.variantMutatorNames, name)
387}
388
389// RegisterEarlyMutator registers a mutator that will be invoked to split
390// Modules into multiple variant Modules before any dependencies have been
391// created. Each registered mutator is invoked in registration order once
392// per Module (including each variant from previous early mutators). Module
393// order is unpredictable.
394//
395// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700396// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700397//
398// The mutator type names given here must be unique to all bottom up or early
399// mutators in the Context.
400func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
401 for _, m := range c.variantMutatorNames {
402 if m == name {
403 panic(fmt.Errorf("mutator name %s is already registered", name))
404 }
405 }
406
407 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
408 mutator: mutator,
409 name: name,
410 })
411
412 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800413}
414
Jamie Gennisd4e10182014-06-12 20:06:50 -0700415// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
416// where it encounters an unknown module type while parsing Blueprints files. By
417// default, the context will report unknown module types as an error. If this
418// method is called with ignoreUnknownModuleTypes set to true then the context
419// will silently ignore unknown module types.
420//
421// This method should generally not be used. It exists to facilitate the
422// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700423func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
424 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
425}
426
Jamie Gennisd4e10182014-06-12 20:06:50 -0700427// Parse parses a single Blueprints file from r, creating Module objects for
428// each of the module definitions encountered. If the Blueprints file contains
429// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700430// searched for Blueprints files returned in the subBlueprints return value.
431// If the Blueprints file contains an assignment to the "build" variable, then
432// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700433//
434// rootDir specifies the path to the root directory of the source tree, while
435// filename specifies the path to the Blueprints file. These paths are used for
436// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800437func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross1fef5362015-04-20 16:50:54 -0700438 scope *parser.Scope) (modules []*moduleInfo, subBlueprints []stringAndScope, deps []string,
439 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700440
Jamie Gennisec701282014-06-12 20:06:31 -0700441 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700442 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700443 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700444 }
445
Colin Crossc0dbc552015-01-02 15:19:28 -0800446 scope = parser.NewScope(scope)
447 scope.Remove("subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700448 scope.Remove("build")
Colin Cross96e56702015-03-19 17:28:06 -0700449 file, errs := parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700450 if len(errs) > 0 {
451 for i, err := range errs {
452 if parseErr, ok := err.(*parser.ParseError); ok {
453 err = &Error{
454 Err: parseErr.Err,
455 Pos: parseErr.Pos,
456 }
457 errs[i] = err
458 }
459 }
460
461 // If there were any parse errors don't bother trying to interpret the
462 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700463 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700464 }
465
Colin Crossd1facc12015-01-08 14:56:03 -0800466 for _, def := range file.Defs {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700467 var newErrs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800468 var newModule *moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700469 switch def := def.(type) {
470 case *parser.Module:
Colin Cross7ad621c2015-01-07 16:22:45 -0800471 newModule, newErrs = c.processModuleDef(def, relBlueprintsFile)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700472
473 case *parser.Assignment:
Colin Crossc0dbc552015-01-02 15:19:28 -0800474 // Already handled via Scope object
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700475 default:
476 panic("unknown definition type")
477 }
478
479 if len(newErrs) > 0 {
480 errs = append(errs, newErrs...)
481 if len(errs) > maxErrors {
482 break
483 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800484 } else if newModule != nil {
485 modules = append(modules, newModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700486 }
487 }
488
Colin Cross1fef5362015-04-20 16:50:54 -0700489 subdirs, subdirsPos, err := getStringListFromScope(scope, "subdirs")
490 if err != nil {
491 errs = append(errs, err)
492 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700493
Colin Cross1fef5362015-04-20 16:50:54 -0700494 build, buildPos, err := getStringListFromScope(scope, "build")
495 if err != nil {
496 errs = append(errs, err)
497 }
498
Colin Cross29394222015-04-27 13:18:21 -0700499 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
500
Colin Cross1fef5362015-04-20 16:50:54 -0700501 blueprints, deps, newErrs := c.findSubdirBlueprints(filepath.Dir(filename), subdirs, build,
Colin Cross29394222015-04-27 13:18:21 -0700502 subBlueprintsName, subdirsPos, buildPos)
Colin Crossc0dbc552015-01-02 15:19:28 -0800503 if len(newErrs) > 0 {
504 errs = append(errs, newErrs...)
505 }
506
Colin Cross1fef5362015-04-20 16:50:54 -0700507 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
508 for i, b := range blueprints {
509 subBlueprintsAndScope[i] = stringAndScope{b, scope}
510 }
511
512 return modules, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800513}
514
Colin Cross7ad621c2015-01-07 16:22:45 -0800515type stringAndScope struct {
516 string
517 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700518}
519
Jamie Gennisd4e10182014-06-12 20:06:50 -0700520// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
521// at rootFile. When it encounters a Blueprints file with a set of subdirs
522// listed it recursively parses any Blueprints files found in those
523// subdirectories.
524//
525// If no errors are encountered while parsing the files, the list of paths on
526// which the future output will depend is returned. This list will include both
527// Blueprints file paths as well as directory paths for cases where wildcard
528// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700529func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
530 errs []error) {
531
Colin Cross7ad621c2015-01-07 16:22:45 -0800532 c.dependenciesReady = false
533
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700534 rootDir := filepath.Dir(rootFile)
535
Colin Cross7ad621c2015-01-07 16:22:45 -0800536 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700537
Colin Cross7ad621c2015-01-07 16:22:45 -0800538 // Channels to receive data back from parseBlueprintsFile goroutines
539 blueprintsCh := make(chan stringAndScope)
540 errsCh := make(chan []error)
541 modulesCh := make(chan []*moduleInfo)
542 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700543
Colin Cross7ad621c2015-01-07 16:22:45 -0800544 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
545 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700546
Colin Cross7ad621c2015-01-07 16:22:45 -0800547 // Number of outstanding goroutines to wait for
548 count := 0
549
550 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
551 count++
552 go func() {
553 c.parseBlueprintsFile(filename, scope, rootDir,
554 errsCh, modulesCh, blueprintsCh, depsCh)
555 doneCh <- struct{}{}
556 }()
557 }
558
559 tooManyErrors := false
560
561 startParseBlueprintsFile(rootFile, nil)
562
563loop:
564 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700565 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800566 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700567 }
568
Colin Cross7ad621c2015-01-07 16:22:45 -0800569 select {
570 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700571 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800572 case dep := <-depsCh:
573 deps = append(deps, dep)
574 case modules := <-modulesCh:
575 newErrs := c.addModules(modules)
576 errs = append(errs, newErrs...)
577 case blueprint := <-blueprintsCh:
578 if tooManyErrors {
579 continue
580 }
581 if blueprintsSet[blueprint.string] {
582 continue
583 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700584
Colin Cross7ad621c2015-01-07 16:22:45 -0800585 blueprintsSet[blueprint.string] = true
586 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
587 case <-doneCh:
588 count--
589 if count == 0 {
590 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700591 }
592 }
593 }
594
Colin Cross7ad621c2015-01-07 16:22:45 -0800595 return
596}
597
598// parseBlueprintFile parses a single Blueprints file, returning any errors through
599// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
600// blueprintsCh, and any dependencies on Blueprints files or directories through
601// depsCh.
602func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
603 errsCh chan<- []error, modulesCh chan<- []*moduleInfo, blueprintsCh chan<- stringAndScope,
604 depsCh chan<- string) {
605
Colin Cross7ad621c2015-01-07 16:22:45 -0800606 file, err := os.Open(filename)
607 if err != nil {
608 errsCh <- []error{err}
609 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700610 }
611
Colin Cross1fef5362015-04-20 16:50:54 -0700612 modules, subBlueprints, deps, errs := c.parse(rootDir, filename, file, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800613 if len(errs) > 0 {
614 errsCh <- errs
615 }
616
Colin Cross1fef5362015-04-20 16:50:54 -0700617 for _, b := range subBlueprints {
618 blueprintsCh <- b
619 }
620
621 for _, d := range deps {
622 depsCh <- d
623 }
624
Colin Cross7ad621c2015-01-07 16:22:45 -0800625 err = file.Close()
626 if err != nil {
627 errsCh <- []error{err}
628 }
629
630 modulesCh <- modules
Colin Cross1fef5362015-04-20 16:50:54 -0700631}
632
Colin Cross29394222015-04-27 13:18:21 -0700633func (c *Context) findSubdirBlueprints(dir string, subdirs, build []string, subBlueprintsName string,
Colin Cross1fef5362015-04-20 16:50:54 -0700634 subdirsPos, buildPos scanner.Position) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800635
636 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700637 globPattern := filepath.Join(dir, subdir)
638 matches, matchedDirs, err := pathtools.Glob(globPattern)
639 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700640 errs = append(errs, &Error{
641 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
642 Pos: subdirsPos,
643 })
644 continue
645 }
646
647 if len(matches) == 0 {
648 errs = append(errs, &Error{
649 Err: fmt.Errorf("%q: not found", globPattern),
650 Pos: subdirsPos,
651 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700652 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800653
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700654 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700655 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800656
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700657 for _, foundSubdir := range matches {
658 fileInfo, subdirStatErr := os.Stat(foundSubdir)
659 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700660 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700661 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800662 }
663
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700664 // Skip files
665 if !fileInfo.IsDir() {
666 continue
667 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800668
Colin Cross29394222015-04-27 13:18:21 -0700669 var subBlueprints string
670 if subBlueprintsName != "" {
671 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
672 _, err = os.Stat(subBlueprints)
673 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700674
Colin Cross29394222015-04-27 13:18:21 -0700675 if os.IsNotExist(err) || subBlueprints == "" {
676 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
677 _, err = os.Stat(subBlueprints)
678 }
679
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700680 if os.IsNotExist(err) {
681 // There is no Blueprints file in this subdirectory. We
682 // need to add the directory to the list of dependencies
683 // so that if someone adds a Blueprints file in the
684 // future we'll pick it up.
Colin Cross29394222015-04-27 13:18:21 -0700685 deps = append(deps, filepath.Dir(foundSubdir))
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700686 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700687 deps = append(deps, subBlueprints)
688 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800689 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800690 }
691 }
Colin Cross1fef5362015-04-20 16:50:54 -0700692
693 for _, file := range build {
694 globPattern := filepath.Join(dir, file)
695 matches, matchedDirs, err := pathtools.Glob(globPattern)
696 if err != nil {
697 errs = append(errs, &Error{
698 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
699 Pos: buildPos,
700 })
701 continue
702 }
703
704 if len(matches) == 0 {
705 errs = append(errs, &Error{
706 Err: fmt.Errorf("%q: not found", globPattern),
707 Pos: buildPos,
708 })
709 }
710
711 // Depend on all searched directories so we pick up future changes.
712 deps = append(deps, matchedDirs...)
713
714 for _, foundBlueprints := range matches {
715 fileInfo, err := os.Stat(foundBlueprints)
716 if os.IsNotExist(err) {
717 errs = append(errs, &Error{
718 Err: fmt.Errorf("%q not found", foundBlueprints),
719 })
720 continue
721 }
722
723 if fileInfo.IsDir() {
724 errs = append(errs, &Error{
725 Err: fmt.Errorf("%q is a directory", foundBlueprints),
726 })
727 continue
728 }
729
730 blueprints = append(blueprints, foundBlueprints)
731 }
732 }
733
734 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700735}
736
Colin Cross1fef5362015-04-20 16:50:54 -0700737func getStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
738 if assignment, err := scope.Get(v); err == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700739 switch assignment.Value.Type {
740 case parser.List:
Colin Cross1fef5362015-04-20 16:50:54 -0700741 ret := make([]string, 0, len(assignment.Value.ListValue))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700742
743 for _, value := range assignment.Value.ListValue {
744 if value.Type != parser.String {
745 // The parser should not produce this.
746 panic("non-string value found in list")
747 }
748
Colin Cross1fef5362015-04-20 16:50:54 -0700749 ret = append(ret, value.StringValue)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700750 }
751
Colin Cross1fef5362015-04-20 16:50:54 -0700752 return ret, assignment.Pos, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700753 case parser.Bool, parser.String:
Colin Cross1fef5362015-04-20 16:50:54 -0700754 return nil, scanner.Position{}, &Error{
755 Err: fmt.Errorf("%q must be a list of strings", v),
756 Pos: assignment.Pos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700757 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700758 default:
759 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
760 }
761 }
762
Colin Cross1fef5362015-04-20 16:50:54 -0700763 return nil, scanner.Position{}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700764}
765
Colin Cross29394222015-04-27 13:18:21 -0700766func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
767 if assignment, err := scope.Get(v); err == nil {
768 switch assignment.Value.Type {
769 case parser.String:
770 return assignment.Value.StringValue, assignment.Pos, nil
771 case parser.Bool, parser.List:
772 return "", scanner.Position{}, &Error{
773 Err: fmt.Errorf("%q must be a string", v),
774 Pos: assignment.Pos,
775 }
776 default:
777 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
778 }
779 }
780
781 return "", scanner.Position{}, nil
782}
783
Colin Crossf5e34b92015-03-13 16:02:36 -0700784func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
785 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800786
Colin Crossf4d18a62015-03-18 17:43:15 -0700787 if len(variationNames) == 0 {
788 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400789 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700790 }
791
Colin Crossc9028482014-12-18 16:28:54 -0800792 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800793
Colin Cross174ae052015-03-03 17:37:03 -0800794 var errs []error
795
Colin Crossf5e34b92015-03-13 16:02:36 -0700796 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700797 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800798 factory, ok := c.moduleFactories[typeName]
799 if !ok {
800 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
801 }
802
803 var newLogicModule Module
804 var newProperties []interface{}
805
806 if i == 0 {
807 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700808 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
809 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800810 newLogicModule = origModule.logicModule
811 newProperties = origModule.moduleProperties
812 } else {
813 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700814 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800815 }
816 newLogicModule, newProperties = factory()
817
818 newProperties = append(props, newProperties...)
819
820 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700821 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800822 }
823
824 for i := range newProperties {
825 dst := reflect.ValueOf(newProperties[i]).Elem()
826 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
827
828 proptools.CopyProperties(dst, src)
829 }
830 }
831
Colin Crossf5e34b92015-03-13 16:02:36 -0700832 newVariant := origModule.variant.clone()
833 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800834
Colin Crossed342d92015-03-11 00:57:25 -0700835 m := *origModule
836 newModule := &m
837 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
838 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700839 newModule.variant = newVariant
840 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700841 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800842
Colin Crosse7daa222015-03-11 14:35:41 -0700843 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700844 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700845 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700846 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700847 }
848
Colin Crossc9028482014-12-18 16:28:54 -0800849 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700850
851 // Insert the new variant into the global module map. If this is the first variant then
852 // it reuses logicModule from the original module, which causes this to replace the
853 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800854 c.moduleInfo[newModule.logicModule] = newModule
855
Colin Crossf5e34b92015-03-13 16:02:36 -0700856 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800857 if len(newErrs) > 0 {
858 errs = append(errs, newErrs...)
859 }
Colin Crossc9028482014-12-18 16:28:54 -0800860 }
861
862 // Mark original variant as invalid. Modules that depend on this module will still
863 // depend on origModule, but we'll fix it when the mutator is called on them.
864 origModule.logicModule = nil
865 origModule.splitModules = newModules
866
Colin Cross174ae052015-03-03 17:37:03 -0800867 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800868}
869
Colin Crossf5e34b92015-03-13 16:02:36 -0700870func (c *Context) convertDepsToVariation(module *moduleInfo,
871 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800872
Colin Crossc9028482014-12-18 16:28:54 -0800873 for i, dep := range module.directDeps {
874 if dep.logicModule == nil {
875 var newDep *moduleInfo
876 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700877 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800878 newDep = m
879 break
880 }
881 }
882 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800883 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700884 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
885 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700886 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800887 })
888 continue
Colin Crossc9028482014-12-18 16:28:54 -0800889 }
890 module.directDeps[i] = newDep
891 }
892 }
Colin Cross174ae052015-03-03 17:37:03 -0800893
894 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800895}
896
Colin Crossf5e34b92015-03-13 16:02:36 -0700897func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -0700898 names := make([]string, 0, len(variant))
899 for _, m := range c.variantMutatorNames {
900 if v, ok := variant[m]; ok {
901 names = append(names, m+":"+v)
902 }
903 }
904
905 return strings.Join(names, ", ")
906}
907
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700908func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800909 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700910
Colin Crossd1facc12015-01-08 14:56:03 -0800911 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700912 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700913 if !ok {
914 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800915 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700916 }
917
Colin Cross7ad621c2015-01-07 16:22:45 -0800918 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700919 &Error{
920 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800921 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700922 },
923 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700924 }
925
Colin Crossbbfa51a2014-12-17 16:12:41 -0800926 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700927
928 module := &moduleInfo{
929 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700930 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700931 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700932 }
933
Jamie Gennis87622922014-09-30 11:38:25 -0700934 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700935 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700936 }
937 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -0700938 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700939
Jamie Gennis87622922014-09-30 11:38:25 -0700940 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700941 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800942 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700943 }
944
Colin Crossed342d92015-03-11 00:57:25 -0700945 module.pos = moduleDef.Type.Pos
946 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700947 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -0700948 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700949 }
950
Colin Cross7ad621c2015-01-07 16:22:45 -0800951 return module, nil
952}
953
954func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
955 for _, module := range modules {
Colin Crossed342d92015-03-11 00:57:25 -0700956 name := module.properties.Name
957 c.moduleInfo[module.logicModule] = module
958
959 if group, present := c.moduleGroups[name]; present {
Colin Cross7ad621c2015-01-07 16:22:45 -0800960 errs = append(errs, []error{
961 &Error{
962 Err: fmt.Errorf("module %q already defined", name),
Colin Crossed342d92015-03-11 00:57:25 -0700963 Pos: module.pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800964 },
965 &Error{
966 Err: fmt.Errorf("<-- previous definition here"),
Colin Crossed342d92015-03-11 00:57:25 -0700967 Pos: group.modules[0].pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800968 },
969 }...)
970 continue
Colin Crossed342d92015-03-11 00:57:25 -0700971 } else {
972 ninjaName := toNinjaName(module.properties.Name)
Colin Cross7ad621c2015-01-07 16:22:45 -0800973
Colin Crossed342d92015-03-11 00:57:25 -0700974 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
975 // already exists
976 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
977 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
978 }
979
Colin Crossed342d92015-03-11 00:57:25 -0700980 group := &moduleGroup{
981 name: module.properties.Name,
982 ninjaName: ninjaName,
983 modules: []*moduleInfo{module},
984 }
985 module.group = group
986 c.moduleGroups[name] = group
Ying Wangfe7f7c42015-05-15 17:42:15 -0700987 c.moduleNinjaNames[ninjaName] = group
Colin Crossed342d92015-03-11 00:57:25 -0700988 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800989 }
990
991 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700992}
993
Jamie Gennisd4e10182014-06-12 20:06:50 -0700994// ResolveDependencies checks that the dependencies specified by all of the
995// modules defined in the parsed Blueprints files are valid. This means that
996// the modules depended upon are defined and that no circular dependencies
997// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700998//
999// The config argument is made available to all of the DynamicDependerModule
1000// objects via the Config method on the DynamicDependerModuleContext objects
1001// passed to their DynamicDependencies method.
1002func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Cross4572edd2015-05-13 14:36:24 -07001003 errs := c.runEarlyMutators(config)
1004 if len(errs) > 0 {
1005 return errs
1006 }
1007
1008 errs = c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001009 if len(errs) > 0 {
1010 return errs
1011 }
1012
Colin Cross691a60d2015-01-07 18:08:56 -08001013 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001014 if len(errs) > 0 {
1015 return errs
1016 }
1017
1018 c.dependenciesReady = true
1019 return nil
1020}
1021
Colin Cross65569e42015-03-10 20:08:19 -07001022// moduleDeps adds dependencies to a module. If the module implements the
1023// DynamicDependerModule interface then this set consists of the union of those
1024// module names listed in its "deps" property, those returned by its
1025// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -07001026// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001027// is simply those names listed in its "deps" property.
Colin Cross65569e42015-03-10 20:08:19 -07001028func (c *Context) moduleDeps(module *moduleInfo,
1029 config interface{}) (errs []error) {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001030
1031 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -08001032 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001033
Colin Crossed342d92015-03-11 00:57:25 -07001034 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -08001035 if !depNamesSet[depName] {
1036 depNamesSet[depName] = true
1037 depNames = append(depNames, depName)
1038 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001039 }
1040
Colin Cross65569e42015-03-10 20:08:19 -07001041 dynamicDepender, ok := module.logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001042 if ok {
Colin Cross65569e42015-03-10 20:08:19 -07001043 ddmctx := &dynamicDependerModuleContext{
1044 baseModuleContext: baseModuleContext{
1045 context: c,
1046 config: config,
1047 module: module,
1048 },
1049 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001050 }
1051
1052 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
1053
1054 if len(ddmctx.errs) > 0 {
Colin Cross65569e42015-03-10 20:08:19 -07001055 return ddmctx.errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001056 }
1057
1058 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -08001059 if !depNamesSet[depName] {
1060 depNamesSet[depName] = true
1061 depNames = append(depNames, depName)
1062 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001063 }
1064 }
1065
Colin Cross65569e42015-03-10 20:08:19 -07001066 for _, depName := range depNames {
1067 newErrs := c.addDependency(module, depName)
1068 if len(newErrs) > 0 {
1069 errs = append(errs, newErrs...)
1070 }
1071 }
1072 return errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001073}
1074
Colin Cross65569e42015-03-10 20:08:19 -07001075// resolveDependencies populates the directDeps list for every module. In doing so it checks for
1076// missing dependencies and self-dependant modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001077func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001078 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -07001079 for _, module := range group.modules {
Colin Cross65569e42015-03-10 20:08:19 -07001080 module.directDeps = make([]*moduleInfo, 0, len(module.properties.Deps))
1081
1082 newErrs := c.moduleDeps(module, config)
Colin Crossc9028482014-12-18 16:28:54 -08001083 if len(newErrs) > 0 {
1084 errs = append(errs, newErrs...)
Colin Crossed342d92015-03-11 00:57:25 -07001085 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001086 }
1087 }
1088
1089 return
1090}
1091
Colin Crossc9028482014-12-18 16:28:54 -08001092func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001093 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -08001094
Colin Crossed342d92015-03-11 00:57:25 -07001095 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001096 return []error{&Error{
1097 Err: fmt.Errorf("%q depends on itself", depName),
1098 Pos: depsPos,
1099 }}
1100 }
1101
1102 depInfo, ok := c.moduleGroups[depName]
1103 if !ok {
1104 return []error{&Error{
1105 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001106 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -08001107 Pos: depsPos,
1108 }}
1109 }
1110
Colin Cross65569e42015-03-10 20:08:19 -07001111 for _, m := range module.directDeps {
1112 if m.group == depInfo {
1113 return nil
1114 }
Colin Crossc9028482014-12-18 16:28:54 -08001115 }
1116
Colin Cross65569e42015-03-10 20:08:19 -07001117 if len(depInfo.modules) == 1 {
1118 module.directDeps = append(module.directDeps, depInfo.modules[0])
1119 return nil
1120 } else {
1121 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001122 if m.variant.equal(module.dependencyVariant) {
Colin Cross65569e42015-03-10 20:08:19 -07001123 module.directDeps = append(module.directDeps, m)
1124 return nil
1125 }
1126 }
1127 }
Colin Crossc9028482014-12-18 16:28:54 -08001128
Colin Cross65569e42015-03-10 20:08:19 -07001129 return []error{&Error{
1130 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1131 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001132 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001133 Pos: depsPos,
1134 }}
1135}
1136
Colin Crossf5e34b92015-03-13 16:02:36 -07001137func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross89486232015-05-08 11:14:54 -07001138 depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001139
1140 depsPos := module.propertyPos["deps"]
1141
1142 depInfo, ok := c.moduleGroups[depName]
1143 if !ok {
1144 return []error{&Error{
1145 Err: fmt.Errorf("%q depends on undefined module %q",
1146 module.properties.Name, depName),
1147 Pos: depsPos,
1148 }}
1149 }
1150
1151 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1152 // compare the strings because the result won't be in mutator registration order.
1153 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001154 var newVariant variationMap
1155 if !far {
1156 newVariant = module.dependencyVariant.clone()
1157 } else {
1158 newVariant = make(variationMap)
1159 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001160 for _, v := range variations {
1161 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001162 }
1163
1164 for _, m := range depInfo.modules {
Colin Cross89486232015-05-08 11:14:54 -07001165 var found bool
1166 if far {
1167 found = m.variant.subset(newVariant)
1168 } else {
1169 found = m.variant.equal(newVariant)
1170 }
1171 if found {
Colin Crossf5e34b92015-03-13 16:02:36 -07001172 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001173 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001174 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001175 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1176 return []error{&Error{
1177 Err: fmt.Errorf("%q depends on later version of itself", depName),
1178 Pos: depsPos,
1179 }}
1180 }
1181 module.directDeps = append(module.directDeps, m)
1182 return nil
1183 }
1184 }
1185
1186 return []error{&Error{
1187 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1188 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001189 c.prettyPrintVariant(newVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001190 Pos: depsPos,
1191 }}
Colin Crossc9028482014-12-18 16:28:54 -08001192}
1193
Colin Cross7addea32015-03-11 15:43:52 -07001194func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1195 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001196 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001197 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001198
Colin Cross7addea32015-03-11 15:43:52 -07001199 for _, module := range c.modulesSorted {
1200 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001201 }
1202
Colin Cross7addea32015-03-11 15:43:52 -07001203 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001204 count++
1205 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001206 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001207 if ret {
1208 cancel = true
1209 }
Colin Cross7addea32015-03-11 15:43:52 -07001210 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001211 }()
1212 }
1213
Colin Cross7addea32015-03-11 15:43:52 -07001214 for _, module := range c.modulesSorted {
1215 if module.waitingCount == 0 {
1216 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001217 }
1218 }
1219
Colin Cross11e3b0d2015-02-04 10:41:00 -08001220 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001221 select {
Colin Cross7addea32015-03-11 15:43:52 -07001222 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001223 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001224 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001225 parent.waitingCount--
1226 if parent.waitingCount == 0 {
1227 visitOne(parent)
1228 }
Colin Cross691a60d2015-01-07 18:08:56 -08001229 }
1230 }
1231 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001232 }
1233 }
1234}
1235
1236// updateDependencies recursively walks the module dependency graph and updates
1237// additional fields based on the dependencies. It builds a sorted list of modules
1238// such that dependencies of a module always appear first, and populates reverse
1239// dependency links and counts of total dependencies. It also reports errors when
1240// it encounters dependency cycles. This should called after resolveDependencies,
1241// as well as after any mutator pass has called addDependency
1242func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001243 visited := make(map[*moduleInfo]bool) // modules that were already checked
1244 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001245
Colin Cross7addea32015-03-11 15:43:52 -07001246 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001247
Colin Cross7addea32015-03-11 15:43:52 -07001248 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001249
Colin Cross7addea32015-03-11 15:43:52 -07001250 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001251 // We are the "start" of the cycle, so we're responsible
1252 // for generating the errors. The cycle list is in
1253 // reverse order because all the 'check' calls append
1254 // their own module to the list.
1255 errs = append(errs, &Error{
1256 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001257 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001258 })
1259
1260 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001261 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001262 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001263 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001264 errs = append(errs, &Error{
1265 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001266 curModule.properties.Name,
1267 nextModule.properties.Name),
1268 Pos: curModule.propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001269 })
Colin Cross7addea32015-03-11 15:43:52 -07001270 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001271 }
1272 }
1273
Colin Cross7addea32015-03-11 15:43:52 -07001274 check = func(module *moduleInfo) []*moduleInfo {
1275 visited[module] = true
1276 checking[module] = true
1277 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001278
Colin Cross7addea32015-03-11 15:43:52 -07001279 deps := make(map[*moduleInfo]bool)
1280
1281 // Add an implicit dependency ordering on all earlier modules in the same module group
1282 for _, dep := range module.group.modules {
1283 if dep == module {
1284 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001285 }
Colin Cross7addea32015-03-11 15:43:52 -07001286 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001287 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001288
Colin Cross7addea32015-03-11 15:43:52 -07001289 for _, dep := range module.directDeps {
1290 deps[dep] = true
1291 }
1292
1293 module.reverseDeps = []*moduleInfo{}
1294 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001295
Colin Crossbbfa51a2014-12-17 16:12:41 -08001296 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001297 if checking[dep] {
1298 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001299 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001300 }
1301
1302 if !visited[dep] {
1303 cycle := check(dep)
1304 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001305 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001306 // We are the "start" of the cycle, so we're responsible
1307 // for generating the errors. The cycle list is in
1308 // reverse order because all the 'check' calls append
1309 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001310 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001311
1312 // We can continue processing this module's children to
1313 // find more cycles. Since all the modules that were
1314 // part of the found cycle were marked as visited we
1315 // won't run into that cycle again.
1316 } else {
1317 // We're not the "start" of the cycle, so we just append
1318 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001319 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001320 }
1321 }
1322 }
Colin Cross691a60d2015-01-07 18:08:56 -08001323
Colin Cross7addea32015-03-11 15:43:52 -07001324 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001325 }
1326
Colin Cross7addea32015-03-11 15:43:52 -07001327 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001328
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001329 return nil
1330 }
1331
Colin Cross7addea32015-03-11 15:43:52 -07001332 for _, module := range c.moduleInfo {
1333 if !visited[module] {
1334 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001335 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001336 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001337 panic("inconceivable!")
1338 }
1339 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001340 }
1341 }
1342 }
1343
Colin Cross7addea32015-03-11 15:43:52 -07001344 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001345
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001346 return
1347}
1348
Jamie Gennisd4e10182014-06-12 20:06:50 -07001349// PrepareBuildActions generates an internal representation of all the build
1350// actions that need to be performed. This process involves invoking the
1351// GenerateBuildActions method on each of the Module objects created during the
1352// parse phase and then on each of the registered Singleton objects.
1353//
1354// If the ResolveDependencies method has not already been called it is called
1355// automatically by this method.
1356//
1357// The config argument is made available to all of the Module and Singleton
1358// objects via the Config method on the ModuleContext and SingletonContext
1359// objects passed to GenerateBuildActions. It is also passed to the functions
1360// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1361// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001362//
1363// The returned deps is a list of the ninja files dependencies that were added
1364// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1365// SingletonContext.AddNinjaFileDeps() methods.
1366func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001367 c.buildActionsReady = false
1368
1369 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001370 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001371 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001372 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001373 }
1374 }
1375
Colin Crossc9028482014-12-18 16:28:54 -08001376 errs = c.runMutators(config)
1377 if len(errs) > 0 {
1378 return nil, errs
1379 }
1380
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001381 liveGlobals := newLiveTracker(config)
1382
1383 c.initSpecialVariables()
1384
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001385 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001386 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001387 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001388 }
1389
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001390 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001391 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001392 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001393 }
1394
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001395 deps = append(depsModules, depsSingletons...)
1396
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001397 if c.buildDir != nil {
1398 liveGlobals.addNinjaStringDeps(c.buildDir)
1399 }
1400
1401 pkgNames := c.makeUniquePackageNames(liveGlobals)
1402
1403 // This will panic if it finds a problem since it's a programming error.
1404 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1405
1406 c.pkgNames = pkgNames
1407 c.globalVariables = liveGlobals.variables
1408 c.globalPools = liveGlobals.pools
1409 c.globalRules = liveGlobals.rules
1410
1411 c.buildActionsReady = true
1412
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001413 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001414}
1415
Colin Cross65569e42015-03-10 20:08:19 -07001416func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1417 for _, mutator := range c.earlyMutatorInfo {
1418 for _, group := range c.moduleGroups {
1419 newModules := make([]*moduleInfo, 0, len(group.modules))
1420
1421 for _, module := range group.modules {
1422 mctx := &mutatorContext{
1423 baseModuleContext: baseModuleContext{
1424 context: c,
1425 config: config,
1426 module: module,
1427 },
1428 name: mutator.name,
1429 }
1430 mutator.mutator(mctx)
1431 if len(mctx.errs) > 0 {
1432 errs = append(errs, mctx.errs...)
1433 return errs
1434 }
1435
1436 if module.splitModules != nil {
1437 newModules = append(newModules, module.splitModules...)
1438 } else {
1439 newModules = append(newModules, module)
1440 }
1441 }
1442
1443 group.modules = newModules
1444 }
1445 }
1446
1447 return nil
1448}
1449
Colin Crossc9028482014-12-18 16:28:54 -08001450func (c *Context) runMutators(config interface{}) (errs []error) {
1451 for _, mutator := range c.mutatorInfo {
1452 if mutator.topDownMutator != nil {
1453 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1454 } else if mutator.bottomUpMutator != nil {
1455 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1456 } else {
1457 panic("no mutator set on " + mutator.name)
1458 }
1459 if len(errs) > 0 {
1460 return errs
1461 }
1462 }
1463
1464 return nil
1465}
1466
1467func (c *Context) runTopDownMutator(config interface{},
1468 name string, mutator TopDownMutator) (errs []error) {
1469
Colin Cross7addea32015-03-11 15:43:52 -07001470 for i := 0; i < len(c.modulesSorted); i++ {
1471 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1472 mctx := &mutatorContext{
1473 baseModuleContext: baseModuleContext{
1474 context: c,
1475 config: config,
1476 module: module,
1477 },
1478 name: name,
1479 }
Colin Crossc9028482014-12-18 16:28:54 -08001480
Colin Cross7addea32015-03-11 15:43:52 -07001481 mutator(mctx)
1482 if len(mctx.errs) > 0 {
1483 errs = append(errs, mctx.errs...)
1484 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001485 }
1486 }
1487
1488 return errs
1489}
1490
1491func (c *Context) runBottomUpMutator(config interface{},
1492 name string, mutator BottomUpMutator) (errs []error) {
1493
Colin Cross7addea32015-03-11 15:43:52 -07001494 for _, module := range c.modulesSorted {
1495 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001496
Jamie Gennisc7988252015-04-14 23:28:10 -04001497 if module.splitModules != nil {
1498 panic("split module found in sorted module list")
1499 }
1500
Colin Cross7addea32015-03-11 15:43:52 -07001501 mctx := &mutatorContext{
1502 baseModuleContext: baseModuleContext{
1503 context: c,
1504 config: config,
1505 module: module,
1506 },
1507 name: name,
1508 }
Colin Crossc9028482014-12-18 16:28:54 -08001509
Colin Cross7addea32015-03-11 15:43:52 -07001510 mutator(mctx)
1511 if len(mctx.errs) > 0 {
1512 errs = append(errs, mctx.errs...)
1513 return errs
1514 }
Colin Crossc9028482014-12-18 16:28:54 -08001515
Colin Cross7addea32015-03-11 15:43:52 -07001516 // Fix up any remaining dependencies on modules that were split into variants
1517 // by replacing them with the first variant
1518 for i, dep := range module.directDeps {
1519 if dep.logicModule == nil {
1520 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001521 }
1522 }
1523
Colin Cross7addea32015-03-11 15:43:52 -07001524 if module.splitModules != nil {
1525 newModules = append(newModules, module.splitModules...)
1526 } else {
1527 newModules = append(newModules, module)
1528 }
1529
1530 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001531 }
1532
Jamie Gennisc7988252015-04-14 23:28:10 -04001533 errs = c.updateDependencies()
1534 if len(errs) > 0 {
1535 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001536 }
1537
1538 return errs
1539}
1540
Colin Cross7addea32015-03-11 15:43:52 -07001541func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1542 newModules []*moduleInfo) []*moduleInfo {
1543 for i, m := range modules {
1544 if m == origModule {
1545 return spliceModulesAtIndex(modules, i, newModules)
1546 }
1547 }
1548
1549 panic("failed to find original module to splice")
1550}
1551
1552func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1553 spliceSize := len(newModules)
1554 newLen := len(modules) + spliceSize - 1
1555 var dest []*moduleInfo
1556 if cap(modules) >= len(modules)-1+len(newModules) {
1557 // We can fit the splice in the existing capacity, do everything in place
1558 dest = modules[:newLen]
1559 } else {
1560 dest = make([]*moduleInfo, newLen)
1561 copy(dest, modules[:i])
1562 }
1563
1564 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001565 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001566
1567 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001568 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001569
Colin Cross72bd1932015-03-16 00:13:59 -07001570 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001571}
1572
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001573func (c *Context) initSpecialVariables() {
1574 c.buildDir = nil
1575 c.requiredNinjaMajor = 1
1576 c.requiredNinjaMinor = 1
1577 c.requiredNinjaMicro = 0
1578}
1579
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001580func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001581 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001582
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001583 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001584 var errs []error
1585
Colin Cross691a60d2015-01-07 18:08:56 -08001586 cancelCh := make(chan struct{})
1587 errsCh := make(chan []error)
1588 depsCh := make(chan []string)
1589
1590 go func() {
1591 for {
1592 select {
1593 case <-cancelCh:
1594 close(cancelCh)
1595 return
1596 case newErrs := <-errsCh:
1597 errs = append(errs, newErrs...)
1598 case newDeps := <-depsCh:
1599 deps = append(deps, newDeps...)
1600
1601 }
1602 }
1603 }()
1604
Colin Cross7addea32015-03-11 15:43:52 -07001605 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1606 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1607 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1608 // just set it to nil.
1609 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1610 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001611
Colin Cross7addea32015-03-11 15:43:52 -07001612 mctx := &moduleContext{
1613 baseModuleContext: baseModuleContext{
1614 context: c,
1615 config: config,
1616 module: module,
1617 },
1618 scope: scope,
1619 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001620
Colin Cross7addea32015-03-11 15:43:52 -07001621 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001622
Colin Cross7addea32015-03-11 15:43:52 -07001623 if len(mctx.errs) > 0 {
1624 errsCh <- mctx.errs
1625 return true
1626 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001627
Colin Cross7addea32015-03-11 15:43:52 -07001628 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001629
Colin Crossab6d7902015-03-11 16:17:52 -07001630 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001631 &mctx.actionDefs, liveGlobals)
1632 if len(newErrs) > 0 {
1633 errsCh <- newErrs
1634 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001635 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001636 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001637 })
1638
1639 cancelCh <- struct{}{}
1640 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001641
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001642 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001643}
1644
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001645func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001646 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001647
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001648 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001649 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001650
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001651 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001652 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1653 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1654 // just set it to nil.
1655 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001656
1657 sctx := &singletonContext{
1658 context: c,
1659 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001660 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001661 }
1662
1663 info.singleton.GenerateBuildActions(sctx)
1664
1665 if len(sctx.errs) > 0 {
1666 errs = append(errs, sctx.errs...)
1667 if len(errs) > maxErrors {
1668 break
1669 }
1670 continue
1671 }
1672
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001673 deps = append(deps, sctx.ninjaFileDeps...)
1674
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001675 newErrs := c.processLocalBuildActions(&info.actionDefs,
1676 &sctx.actionDefs, liveGlobals)
1677 errs = append(errs, newErrs...)
1678 if len(errs) > maxErrors {
1679 break
1680 }
1681 }
1682
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001683 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001684}
1685
1686func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1687 liveGlobals *liveTracker) []error {
1688
1689 var errs []error
1690
1691 // First we go through and add everything referenced by the module's
1692 // buildDefs to the live globals set. This will end up adding the live
1693 // locals to the set as well, but we'll take them out after.
1694 for _, def := range in.buildDefs {
1695 err := liveGlobals.AddBuildDefDeps(def)
1696 if err != nil {
1697 errs = append(errs, err)
1698 }
1699 }
1700
1701 if len(errs) > 0 {
1702 return errs
1703 }
1704
Colin Crossc9028482014-12-18 16:28:54 -08001705 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001706
1707 // We use the now-incorrect set of live "globals" to determine which local
1708 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001709 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001710 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001711 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001712 if isLive {
1713 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001714 }
1715 }
1716
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001717 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001718 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001719 if isLive {
1720 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001721 }
1722 }
1723
1724 return nil
1725}
1726
Colin Crossbbfa51a2014-12-17 16:12:41 -08001727func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1728 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001729
Colin Crossbbfa51a2014-12-17 16:12:41 -08001730 var walk func(module *moduleInfo)
1731 walk = func(module *moduleInfo) {
1732 visited[module] = true
1733 for _, moduleDep := range module.directDeps {
1734 if !visited[moduleDep] {
1735 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001736 }
1737 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001738
Colin Crossbbfa51a2014-12-17 16:12:41 -08001739 if module != topModule {
1740 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001741 }
1742 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001743
1744 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001745}
1746
Colin Crossbbfa51a2014-12-17 16:12:41 -08001747func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001748 visit func(Module)) {
1749
Colin Crossbbfa51a2014-12-17 16:12:41 -08001750 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001751
Colin Crossbbfa51a2014-12-17 16:12:41 -08001752 var walk func(module *moduleInfo)
1753 walk = func(module *moduleInfo) {
1754 visited[module] = true
1755 for _, moduleDep := range module.directDeps {
1756 if !visited[moduleDep] {
1757 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001758 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001759 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001760
1761 if module != topModule {
1762 if pred(module.logicModule) {
1763 visit(module.logicModule)
1764 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001765 }
1766 }
1767
Colin Crossbbfa51a2014-12-17 16:12:41 -08001768 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001769}
1770
Colin Crossc9028482014-12-18 16:28:54 -08001771func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1772 for _, dep := range module.directDeps {
1773 visit(dep.logicModule)
1774 }
1775}
1776
1777func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1778 visit func(Module)) {
1779
1780 for _, dep := range module.directDeps {
1781 if pred(dep.logicModule) {
1782 visit(dep.logicModule)
1783 }
1784 }
1785}
1786
Jamie Gennisc15544d2014-09-24 20:26:52 -07001787func (c *Context) sortedModuleNames() []string {
1788 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001789 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1790 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001791 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1792 moduleName)
1793 }
1794 sort.Strings(c.cachedSortedModuleNames)
1795 }
1796
1797 return c.cachedSortedModuleNames
1798}
1799
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001800func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001801 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001802 group := c.moduleGroups[moduleName]
1803 for _, module := range group.modules {
1804 visit(module.logicModule)
1805 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001806 }
1807}
1808
1809func (c *Context) visitAllModulesIf(pred func(Module) bool,
1810 visit func(Module)) {
1811
Jamie Gennisc15544d2014-09-24 20:26:52 -07001812 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001813 group := c.moduleGroups[moduleName]
1814 for _, module := range group.modules {
1815 if pred(module.logicModule) {
1816 visit(module.logicModule)
1817 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001818 }
1819 }
1820}
1821
1822func (c *Context) requireNinjaVersion(major, minor, micro int) {
1823 if major != 1 {
1824 panic("ninja version with major version != 1 not supported")
1825 }
1826 if c.requiredNinjaMinor < minor {
1827 c.requiredNinjaMinor = minor
1828 c.requiredNinjaMicro = micro
1829 }
1830 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1831 c.requiredNinjaMicro = micro
1832 }
1833}
1834
1835func (c *Context) setBuildDir(value *ninjaString) {
1836 if c.buildDir != nil {
1837 panic("buildDir set multiple times")
1838 }
1839 c.buildDir = value
1840}
1841
1842func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001843 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001844
Jamie Gennis2fb20952014-10-03 02:49:58 -07001845 pkgs := make(map[string]*PackageContext)
1846 pkgNames := make(map[*PackageContext]string)
1847 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001848
Jamie Gennis2fb20952014-10-03 02:49:58 -07001849 processPackage := func(pctx *PackageContext) {
1850 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001851 // This is a built-in rule and has no package.
1852 return
1853 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001854 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001855 // We've already processed this package.
1856 return
1857 }
1858
Jamie Gennis2fb20952014-10-03 02:49:58 -07001859 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001860 if present {
1861 // Short name collision. Both this package and the one that's
1862 // already there need to use their full names. We leave the short
1863 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001864 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001865 longPkgNames[otherPkg] = true
1866 } else {
1867 // No collision so far. Tentatively set the package's name to be
1868 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001869 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07001870 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001871 }
1872 }
1873
1874 // We try to give all packages their short name, but when we get collisions
1875 // we need to use the full unique package name.
1876 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001877 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001878 }
1879 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001880 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001881 }
1882 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001883 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001884 }
1885
1886 // Add the packages that had collisions using their full unique names. This
1887 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001888 for pctx := range longPkgNames {
1889 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001890 }
1891
1892 return pkgNames
1893}
1894
1895func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001896 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001897
1898 visited := make(map[Variable]bool) // variables that were already checked
1899 checking := make(map[Variable]bool) // variables actively being checked
1900
1901 var check func(v Variable) []Variable
1902
1903 check = func(v Variable) []Variable {
1904 visited[v] = true
1905 checking[v] = true
1906 defer delete(checking, v)
1907
1908 value := variables[v]
1909 for _, dep := range value.variables {
1910 if checking[dep] {
1911 // This is a cycle.
1912 return []Variable{dep, v}
1913 }
1914
1915 if !visited[dep] {
1916 cycle := check(dep)
1917 if cycle != nil {
1918 if cycle[0] == v {
1919 // We are the "start" of the cycle, so we're responsible
1920 // for generating the errors. The cycle list is in
1921 // reverse order because all the 'check' calls append
1922 // their own module to the list.
1923 msgs := []string{"detected variable reference cycle:"}
1924
1925 // Iterate backwards through the cycle list.
1926 curName := v.fullName(pkgNames)
1927 curValue := value.Value(pkgNames)
1928 for i := len(cycle) - 1; i >= 0; i-- {
1929 next := cycle[i]
1930 nextName := next.fullName(pkgNames)
1931 nextValue := variables[next].Value(pkgNames)
1932
1933 msgs = append(msgs, fmt.Sprintf(
1934 " %q depends on %q", curName, nextName))
1935 msgs = append(msgs, fmt.Sprintf(
1936 " [%s = %s]", curName, curValue))
1937
1938 curName = nextName
1939 curValue = nextValue
1940 }
1941
1942 // Variable reference cycles are a programming error,
1943 // not the fault of the Blueprint file authors.
1944 panic(strings.Join(msgs, "\n"))
1945 } else {
1946 // We're not the "start" of the cycle, so we just append
1947 // our module to the list and return it.
1948 return append(cycle, v)
1949 }
1950 }
1951 }
1952 }
1953
1954 return nil
1955 }
1956
1957 for v := range variables {
1958 if !visited[v] {
1959 cycle := check(v)
1960 if cycle != nil {
1961 panic("inconceivable!")
1962 }
1963 }
1964 }
1965}
1966
Jamie Gennisaf435562014-10-27 22:34:56 -07001967// AllTargets returns a map all the build target names to the rule used to build
1968// them. This is the same information that is output by running 'ninja -t
1969// targets all'. If this is called before PrepareBuildActions successfully
1970// completes then ErrbuildActionsNotReady is returned.
1971func (c *Context) AllTargets() (map[string]string, error) {
1972 if !c.buildActionsReady {
1973 return nil, ErrBuildActionsNotReady
1974 }
1975
1976 targets := map[string]string{}
1977
1978 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07001979 for _, module := range c.moduleInfo {
1980 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07001981 ruleName := buildDef.Rule.fullName(c.pkgNames)
1982 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001983 outputValue, err := output.Eval(c.globalVariables)
1984 if err != nil {
1985 return nil, err
1986 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001987 targets[outputValue] = ruleName
1988 }
1989 }
1990 }
1991
1992 // Collect all the singleton build targets.
1993 for _, info := range c.singletonInfo {
1994 for _, buildDef := range info.actionDefs.buildDefs {
1995 ruleName := buildDef.Rule.fullName(c.pkgNames)
1996 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001997 outputValue, err := output.Eval(c.globalVariables)
1998 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001999 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002000 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002001 targets[outputValue] = ruleName
2002 }
2003 }
2004 }
2005
2006 return targets, nil
2007}
2008
Colin Cross4572edd2015-05-13 14:36:24 -07002009// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2010// property structs returned by the factory for that module type.
2011func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2012 ret := make(map[string][]interface{})
2013 for moduleType, factory := range c.moduleFactories {
2014 _, ret[moduleType] = factory()
2015 }
2016
2017 return ret
2018}
2019
2020func (c *Context) ModuleName(logicModule Module) string {
2021 module := c.moduleInfo[logicModule]
2022 return module.properties.Name
2023}
2024
2025func (c *Context) ModuleDir(logicModule Module) string {
2026 module := c.moduleInfo[logicModule]
2027 return filepath.Dir(module.relBlueprintsFile)
2028}
2029
2030func (c *Context) BlueprintFile(logicModule Module) string {
2031 module := c.moduleInfo[logicModule]
2032 return module.relBlueprintsFile
2033}
2034
2035func (c *Context) ModuleErrorf(logicModule Module, format string,
2036 args ...interface{}) error {
2037
2038 module := c.moduleInfo[logicModule]
2039 return &Error{
2040 Err: fmt.Errorf(format, args...),
2041 Pos: module.pos,
2042 }
2043}
2044
2045func (c *Context) VisitAllModules(visit func(Module)) {
2046 c.visitAllModules(visit)
2047}
2048
2049func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2050 visit func(Module)) {
2051
2052 c.visitAllModulesIf(pred, visit)
2053}
2054
2055func (c *Context) VisitDepsDepthFirst(module Module,
2056 visit func(Module)) {
2057
2058 c.visitDepsDepthFirst(c.moduleInfo[module], visit)
2059}
2060
2061func (c *Context) VisitDepsDepthFirstIf(module Module,
2062 pred func(Module) bool, visit func(Module)) {
2063
2064 c.visitDepsDepthFirstIf(c.moduleInfo[module], pred, visit)
2065}
2066
Jamie Gennisd4e10182014-06-12 20:06:50 -07002067// WriteBuildFile writes the Ninja manifeset text for the generated build
2068// actions to w. If this is called before PrepareBuildActions successfully
2069// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002070func (c *Context) WriteBuildFile(w io.Writer) error {
2071 if !c.buildActionsReady {
2072 return ErrBuildActionsNotReady
2073 }
2074
2075 nw := newNinjaWriter(w)
2076
2077 err := c.writeBuildFileHeader(nw)
2078 if err != nil {
2079 return err
2080 }
2081
2082 err = c.writeNinjaRequiredVersion(nw)
2083 if err != nil {
2084 return err
2085 }
2086
2087 // TODO: Group the globals by package.
2088
2089 err = c.writeGlobalVariables(nw)
2090 if err != nil {
2091 return err
2092 }
2093
2094 err = c.writeGlobalPools(nw)
2095 if err != nil {
2096 return err
2097 }
2098
2099 err = c.writeBuildDir(nw)
2100 if err != nil {
2101 return err
2102 }
2103
2104 err = c.writeGlobalRules(nw)
2105 if err != nil {
2106 return err
2107 }
2108
2109 err = c.writeAllModuleActions(nw)
2110 if err != nil {
2111 return err
2112 }
2113
2114 err = c.writeAllSingletonActions(nw)
2115 if err != nil {
2116 return err
2117 }
2118
2119 return nil
2120}
2121
Jamie Gennisc15544d2014-09-24 20:26:52 -07002122type pkgAssociation struct {
2123 PkgName string
2124 PkgPath string
2125}
2126
2127type pkgAssociationSorter struct {
2128 pkgs []pkgAssociation
2129}
2130
2131func (s *pkgAssociationSorter) Len() int {
2132 return len(s.pkgs)
2133}
2134
2135func (s *pkgAssociationSorter) Less(i, j int) bool {
2136 iName := s.pkgs[i].PkgName
2137 jName := s.pkgs[j].PkgName
2138 return iName < jName
2139}
2140
2141func (s *pkgAssociationSorter) Swap(i, j int) {
2142 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2143}
2144
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002145func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2146 headerTemplate := template.New("fileHeader")
2147 _, err := headerTemplate.Parse(fileHeaderTemplate)
2148 if err != nil {
2149 // This is a programming error.
2150 panic(err)
2151 }
2152
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002153 var pkgs []pkgAssociation
2154 maxNameLen := 0
2155 for pkg, name := range c.pkgNames {
2156 pkgs = append(pkgs, pkgAssociation{
2157 PkgName: name,
2158 PkgPath: pkg.pkgPath,
2159 })
2160 if len(name) > maxNameLen {
2161 maxNameLen = len(name)
2162 }
2163 }
2164
2165 for i := range pkgs {
2166 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2167 }
2168
Jamie Gennisc15544d2014-09-24 20:26:52 -07002169 sort.Sort(&pkgAssociationSorter{pkgs})
2170
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002171 params := map[string]interface{}{
2172 "Pkgs": pkgs,
2173 }
2174
2175 buf := bytes.NewBuffer(nil)
2176 err = headerTemplate.Execute(buf, params)
2177 if err != nil {
2178 return err
2179 }
2180
2181 return nw.Comment(buf.String())
2182}
2183
2184func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2185 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2186 c.requiredNinjaMicro)
2187
2188 err := nw.Assign("ninja_required_version", value)
2189 if err != nil {
2190 return err
2191 }
2192
2193 return nw.BlankLine()
2194}
2195
2196func (c *Context) writeBuildDir(nw *ninjaWriter) error {
2197 if c.buildDir != nil {
2198 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
2199 if err != nil {
2200 return err
2201 }
2202
2203 err = nw.BlankLine()
2204 if err != nil {
2205 return err
2206 }
2207 }
2208 return nil
2209}
2210
Jamie Gennisc15544d2014-09-24 20:26:52 -07002211type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002212 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002213}
2214
Jamie Gennisc15544d2014-09-24 20:26:52 -07002215type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002216 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002217 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002218}
2219
Jamie Gennisc15544d2014-09-24 20:26:52 -07002220func (s *globalEntitySorter) Len() int {
2221 return len(s.entities)
2222}
2223
2224func (s *globalEntitySorter) Less(i, j int) bool {
2225 iName := s.entities[i].fullName(s.pkgNames)
2226 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002227 return iName < jName
2228}
2229
Jamie Gennisc15544d2014-09-24 20:26:52 -07002230func (s *globalEntitySorter) Swap(i, j int) {
2231 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002232}
2233
2234func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2235 visited := make(map[Variable]bool)
2236
2237 var walk func(v Variable) error
2238 walk = func(v Variable) error {
2239 visited[v] = true
2240
2241 // First visit variables on which this variable depends.
2242 value := c.globalVariables[v]
2243 for _, dep := range value.variables {
2244 if !visited[dep] {
2245 err := walk(dep)
2246 if err != nil {
2247 return err
2248 }
2249 }
2250 }
2251
2252 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2253 if err != nil {
2254 return err
2255 }
2256
2257 err = nw.BlankLine()
2258 if err != nil {
2259 return err
2260 }
2261
2262 return nil
2263 }
2264
Jamie Gennisc15544d2014-09-24 20:26:52 -07002265 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2266 for variable := range c.globalVariables {
2267 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002268 }
2269
Jamie Gennisc15544d2014-09-24 20:26:52 -07002270 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002271
Jamie Gennisc15544d2014-09-24 20:26:52 -07002272 for _, entity := range globalVariables {
2273 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002274 if !visited[v] {
2275 err := walk(v)
2276 if err != nil {
2277 return nil
2278 }
2279 }
2280 }
2281
2282 return nil
2283}
2284
2285func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002286 globalPools := make([]globalEntity, 0, len(c.globalPools))
2287 for pool := range c.globalPools {
2288 globalPools = append(globalPools, pool)
2289 }
2290
2291 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2292
2293 for _, entity := range globalPools {
2294 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002295 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002296 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002297 err := def.WriteTo(nw, name)
2298 if err != nil {
2299 return err
2300 }
2301
2302 err = nw.BlankLine()
2303 if err != nil {
2304 return err
2305 }
2306 }
2307
2308 return nil
2309}
2310
2311func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002312 globalRules := make([]globalEntity, 0, len(c.globalRules))
2313 for rule := range c.globalRules {
2314 globalRules = append(globalRules, rule)
2315 }
2316
2317 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2318
2319 for _, entity := range globalRules {
2320 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002321 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002322 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002323 err := def.WriteTo(nw, name, c.pkgNames)
2324 if err != nil {
2325 return err
2326 }
2327
2328 err = nw.BlankLine()
2329 if err != nil {
2330 return err
2331 }
2332 }
2333
2334 return nil
2335}
2336
Colin Crossab6d7902015-03-11 16:17:52 -07002337type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002338
Colin Crossab6d7902015-03-11 16:17:52 -07002339func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002340 return len(s)
2341}
2342
Colin Crossab6d7902015-03-11 16:17:52 -07002343func (s moduleSorter) Less(i, j int) bool {
2344 iName := s[i].properties.Name
2345 jName := s[j].properties.Name
2346 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002347 iName = s[i].variantName
2348 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002349 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002350 return iName < jName
2351}
2352
Colin Crossab6d7902015-03-11 16:17:52 -07002353func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002354 s[i], s[j] = s[j], s[i]
2355}
2356
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002357func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2358 headerTemplate := template.New("moduleHeader")
2359 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2360 if err != nil {
2361 // This is a programming error.
2362 panic(err)
2363 }
2364
Colin Crossab6d7902015-03-11 16:17:52 -07002365 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2366 for _, module := range c.moduleInfo {
2367 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002368 }
Colin Crossab6d7902015-03-11 16:17:52 -07002369 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002370
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002371 buf := bytes.NewBuffer(nil)
2372
Colin Crossab6d7902015-03-11 16:17:52 -07002373 for _, module := range modules {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002374 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002375
2376 // In order to make the bootstrap build manifest independent of the
2377 // build dir we need to output the Blueprints file locations in the
2378 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002379 relPos := module.pos
2380 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002381
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002382 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002383 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002384 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2385 factoryName := factoryFunc.Name()
2386
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002387 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002388 "properties": module.properties,
2389 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002390 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002391 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002392 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002393 }
2394 err = headerTemplate.Execute(buf, infoMap)
2395 if err != nil {
2396 return err
2397 }
2398
2399 err = nw.Comment(buf.String())
2400 if err != nil {
2401 return err
2402 }
2403
2404 err = nw.BlankLine()
2405 if err != nil {
2406 return err
2407 }
2408
Colin Crossab6d7902015-03-11 16:17:52 -07002409 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002410 if err != nil {
2411 return err
2412 }
2413
2414 err = nw.BlankLine()
2415 if err != nil {
2416 return err
2417 }
2418 }
2419
2420 return nil
2421}
2422
2423func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2424 headerTemplate := template.New("singletonHeader")
2425 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2426 if err != nil {
2427 // This is a programming error.
2428 panic(err)
2429 }
2430
2431 buf := bytes.NewBuffer(nil)
2432
Jamie Gennis86179fe2014-06-11 16:27:16 -07002433 singletonNames := make([]string, 0, len(c.singletonInfo))
2434 for name := range c.singletonInfo {
2435 singletonNames = append(singletonNames, name)
2436 }
2437 sort.Strings(singletonNames)
2438
2439 for _, name := range singletonNames {
2440 info := c.singletonInfo[name]
2441
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002442 // Get the name of the factory function for the module.
2443 factory := info.factory
2444 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2445 factoryName := factoryFunc.Name()
2446
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002447 buf.Reset()
2448 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002449 "name": name,
2450 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002451 }
2452 err = headerTemplate.Execute(buf, infoMap)
2453 if err != nil {
2454 return err
2455 }
2456
2457 err = nw.Comment(buf.String())
2458 if err != nil {
2459 return err
2460 }
2461
2462 err = nw.BlankLine()
2463 if err != nil {
2464 return err
2465 }
2466
2467 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2468 if err != nil {
2469 return err
2470 }
2471
2472 err = nw.BlankLine()
2473 if err != nil {
2474 return err
2475 }
2476 }
2477
2478 return nil
2479}
2480
2481func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2482 defs *localBuildActions) error {
2483
2484 // Write the local variable assignments.
2485 for _, v := range defs.variables {
2486 // A localVariable doesn't need the package names or config to
2487 // determine its name or value.
2488 name := v.fullName(nil)
2489 value, err := v.value(nil)
2490 if err != nil {
2491 panic(err)
2492 }
2493 err = nw.Assign(name, value.Value(c.pkgNames))
2494 if err != nil {
2495 return err
2496 }
2497 }
2498
2499 if len(defs.variables) > 0 {
2500 err := nw.BlankLine()
2501 if err != nil {
2502 return err
2503 }
2504 }
2505
2506 // Write the local rules.
2507 for _, r := range defs.rules {
2508 // A localRule doesn't need the package names or config to determine
2509 // its name or definition.
2510 name := r.fullName(nil)
2511 def, err := r.def(nil)
2512 if err != nil {
2513 panic(err)
2514 }
2515
2516 err = def.WriteTo(nw, name, c.pkgNames)
2517 if err != nil {
2518 return err
2519 }
2520
2521 err = nw.BlankLine()
2522 if err != nil {
2523 return err
2524 }
2525 }
2526
2527 // Write the build definitions.
2528 for _, buildDef := range defs.buildDefs {
2529 err := buildDef.WriteTo(nw, c.pkgNames)
2530 if err != nil {
2531 return err
2532 }
2533
2534 if len(buildDef.Args) > 0 {
2535 err = nw.BlankLine()
2536 if err != nil {
2537 return err
2538 }
2539 }
2540 }
2541
2542 return nil
2543}
2544
Colin Cross65569e42015-03-10 20:08:19 -07002545func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2546 found := false
2547 for _, l := range list {
2548 if l == a {
2549 found = true
2550 } else if l == b {
2551 return found
2552 }
2553 }
2554
2555 missing := a
2556 if found {
2557 missing = b
2558 }
2559 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2560}
2561
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002562var fileHeaderTemplate = `******************************************************************************
2563*** This file is generated and should not be edited ***
2564******************************************************************************
2565{{if .Pkgs}}
2566This file contains variables, rules, and pools with name prefixes indicating
2567they were generated by the following Go packages:
2568{{range .Pkgs}}
2569 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2570
2571`
2572
2573var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2574Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002575Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002576Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002577Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002578Defined: {{.pos}}
2579`
2580
2581var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2582Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002583Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002584`