1// 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
15package blueprint
16
17import (
18	"fmt"
19	"path/filepath"
20	"strings"
21	"sync"
22	"text/scanner"
23
24	"github.com/google/blueprint/parser"
25	"github.com/google/blueprint/pathtools"
26	"github.com/google/blueprint/proptools"
27)
28
29// A Module handles generating all of the Ninja build actions needed to build a
30// single module based on properties defined in a Blueprints file.  Module
31// objects are initially created during the parse phase of a Context using one
32// of the registered module types (and the associated ModuleFactory function).
33// The Module's properties struct is automatically filled in with the property
34// values specified in the Blueprints file (see Context.RegisterModuleType for more
35// information on this).
36//
37// A Module can be split into multiple Modules by a Mutator.  All existing
38// properties set on the module will be duplicated to the new Module, and then
39// modified as necessary by the Mutator.
40//
41// The Module implementation can access the build configuration as well as any
42// modules on which on which it depends (as defined by the "deps" property
43// specified in the Blueprints file, dynamically added by implementing the
44// (deprecated) DynamicDependerModule interface, or dynamically added by a
45// BottomUpMutator) using the ModuleContext passed to GenerateBuildActions.
46// This ModuleContext is also used to create Ninja build actions and to report
47// errors to the user.
48//
49// In addition to implementing the GenerateBuildActions method, a Module should
50// implement methods that provide dependant modules and singletons information
51// they need to generate their build actions.  These methods will only be called
52// after GenerateBuildActions is called because the Context calls
53// GenerateBuildActions in dependency-order (and singletons are invoked after
54// all the Modules).  The set of methods a Module supports will determine how
55// dependant Modules interact with it.
56//
57// For example, consider a Module that is responsible for generating a library
58// that other modules can link against.  The library Module might implement the
59// following interface:
60//
61//   type LibraryProducer interface {
62//       LibraryFileName() string
63//   }
64//
65//   func IsLibraryProducer(module blueprint.Module) {
66//       _, ok := module.(LibraryProducer)
67//       return ok
68//   }
69//
70// A binary-producing Module that depends on the library Module could then do:
71//
72//   func (m *myBinaryModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
73//       ...
74//       var libraryFiles []string
75//       ctx.VisitDepsDepthFirstIf(IsLibraryProducer,
76//           func(module blueprint.Module) {
77//               libProducer := module.(LibraryProducer)
78//               libraryFiles = append(libraryFiles, libProducer.LibraryFileName())
79//           })
80//       ...
81//   }
82//
83// to build the list of library file names that should be included in its link
84// command.
85//
86// GenerateBuildActions may be called from multiple threads.  It is guaranteed to
87// be called after it has finished being called on all dependencies and on all
88// variants of that appear earlier in the ModuleContext.VisitAllModuleVariants list.
89// Any accesses to global variables or to Module objects that are not dependencies
90// or variants of the current Module must be synchronized by the implementation of
91// GenerateBuildActions.
92type Module interface {
93	// Name returns a string used to uniquely identify each module.  The return
94	// value must be unique across all modules.  It is only called once, during
95	// initial blueprint parsing.  To change the name later a mutator must call
96	// MutatorContext.Rename
97	//
98	// In most cases, Name should return the contents of a "name:" property from
99	// the blueprint file.  An embeddable SimpleName object can be used for this
100	// case.
101	Name() string
102
103	// GenerateBuildActions is called by the Context that created the Module
104	// during its generate phase.  This call should generate all Ninja build
105	// actions (rules, pools, and build statements) needed to build the module.
106	GenerateBuildActions(ModuleContext)
107}
108
109// A DynamicDependerModule is a Module that may add dependencies that do not
110// appear in its "deps" property.  Any Module that implements this interface
111// will have its DynamicDependencies method called by the Context that created
112// it during generate phase.
113//
114// Deprecated, use a BottomUpMutator instead
115type DynamicDependerModule interface {
116	Module
117
118	// DynamicDependencies is called by the Context that created the
119	// DynamicDependerModule during its generate phase.  This call should return
120	// the list of module names that the DynamicDependerModule depends on
121	// dynamically.  Module names that already appear in the "deps" property may
122	// but do not need to be included in the returned list.
123	DynamicDependencies(DynamicDependerModuleContext) []string
124}
125
126type EarlyModuleContext interface {
127	// Module returns the current module as a Module.  It should rarely be necessary, as the module already has a
128	// reference to itself.
129	Module() Module
130
131	// ModuleName returns the name of the module.  This is generally the value that was returned by Module.Name() when
132	// the module was created, but may have been modified by calls to BaseMutatorContext.Rename.
133	ModuleName() string
134
135	// ModuleDir returns the path to the directory that contains the defintion of the module.
136	ModuleDir() string
137
138	// ModuleType returns the name of the module type that was used to create the module, as specified in
139	// RegisterModuleType.
140	ModuleType() string
141
142	// BlueprintFile returns the name of the blueprint file that contains the definition of this
143	// module.
144	BlueprintsFile() string
145
146	// Config returns the config object that was passed to Context.PrepareBuildActions.
147	Config() interface{}
148
149	// ContainsProperty returns true if the specified property name was set in the module definition.
150	ContainsProperty(name string) bool
151
152	// Errorf reports an error at the specified position of the module definition file.
153	Errorf(pos scanner.Position, fmt string, args ...interface{})
154
155	// ModuleErrorf reports an error at the line number of the module type in the module definition.
156	ModuleErrorf(fmt string, args ...interface{})
157
158	// PropertyErrorf reports an error at the line number of a property in the module definition.
159	PropertyErrorf(property, fmt string, args ...interface{})
160
161	// Failed returns true if any errors have been reported.  In most cases the module can continue with generating
162	// build rules after an error, allowing it to report additional errors in a single run, but in cases where the error
163	// has prevented the module from creating necessary data it can return early when Failed returns true.
164	Failed() bool
165
166	// GlobWithDeps returns a list of files and directories that match the
167	// specified pattern but do not match any of the patterns in excludes.
168	// Any directories will have a '/' suffix.  It also adds efficient
169	// dependencies to rerun the primary builder whenever a file matching
170	// the pattern as added or removed, without rerunning if a file that
171	// does not match the pattern is added to a searched directory.
172	GlobWithDeps(pattern string, excludes []string) ([]string, error)
173
174	// Fs returns a pathtools.Filesystem that can be used to interact with files.  Using the Filesystem interface allows
175	// the module to be used in build system tests that run against a mock filesystem.
176	Fs() pathtools.FileSystem
177
178	// AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest.  The
179	// primary builder will be rerun whenever the specified files are modified.
180	AddNinjaFileDeps(deps ...string)
181
182	moduleInfo() *moduleInfo
183	error(err error)
184
185	// Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the
186	// default SimpleNameInterface if Context.SetNameInterface was not called.
187	Namespace() Namespace
188
189	// ModuleFactories returns a map of all of the global ModuleFactories by name.
190	ModuleFactories() map[string]ModuleFactory
191}
192
193type BaseModuleContext interface {
194	EarlyModuleContext
195
196	// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
197	// none exists.  It panics if the dependency does not have the specified tag.
198	GetDirectDepWithTag(name string, tag DependencyTag) Module
199
200	// GetDirectDep returns the Module and DependencyTag for the  direct dependency with the specified
201	// name, or nil if none exists.  If there are multiple dependencies on the same module it returns
202	// the first DependencyTag.
203	GetDirectDep(name string) (Module, DependencyTag)
204
205	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple direct dependencies on the same
206	// module visit will be called multiple times on that module and OtherModuleDependencyTag will return a different
207	// tag for each.
208	//
209	// The Module passed to the visit function should not be retained outside of the visit function, it may be
210	// invalidated by future mutators.
211	VisitDirectDeps(visit func(Module))
212
213	// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit.  If there are
214	// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and
215	// OtherModuleDependencyTag will return a different tag for each.
216	//
217	// The Module passed to the visit function should not be retained outside of the visit function, it may be
218	// invalidated by future mutators.
219	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
220
221	// VisitDepsDepthFirst calls visit for each transitive dependency, traversing the dependency tree in depth first
222	// order. visit will only be called once for any given module, even if there are multiple paths through the
223	// dependency tree to the module or multiple direct dependencies with different tags.  OtherModuleDependencyTag will
224	// return the tag for the first path found to the module.
225	//
226	// The Module passed to the visit function should not be retained outside of the visit function, it may be
227	// invalidated by future mutators.
228	VisitDepsDepthFirst(visit func(Module))
229
230	// VisitDepsDepthFirst calls pred for each transitive dependency, and if pred returns true calls visit, traversing
231	// the dependency tree in depth first order.  visit will only be called once for any given module, even if there are
232	// multiple paths through the dependency tree to the module or multiple direct dependencies with different tags.
233	// OtherModuleDependencyTag will return the tag for the first path found to the module.  The return value of pred
234	// does not affect which branches of the tree are traversed.
235	//
236	// The Module passed to the visit function should not be retained outside of the visit function, it may be
237	// invalidated by future mutators.
238	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
239
240	// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order.  visit may
241	// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
242	// child and parent with different tags.  OtherModuleDependencyTag will return the tag for the currently visited
243	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down to child.
244	//
245	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
246	// invalidated by future mutators.
247	WalkDeps(visit func(Module, Module) bool)
248
249	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
250	// It is intended for use inside the visit functions of Visit* and WalkDeps.
251	OtherModuleName(m Module) string
252
253	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information.
254	// It is intended for use inside the visit functions of Visit* and WalkDeps.
255	OtherModuleDir(m Module) string
256
257	// OtherModuleSubDir returns the unique subdirectory name of another Module.  See ModuleContext.ModuleSubDir for
258	// more information.
259	// It is intended for use inside the visit functions of Visit* and WalkDeps.
260	OtherModuleSubDir(m Module) string
261
262	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information.
263	// It is intended for use inside the visit functions of Visit* and WalkDeps.
264	OtherModuleType(m Module) string
265
266	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information.
267	// It is intended for use inside the visit functions of Visit* and WalkDeps.
268	OtherModuleErrorf(m Module, fmt string, args ...interface{})
269
270	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
271	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple
272	// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
273	OtherModuleDependencyTag(m Module) DependencyTag
274
275	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
276	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
277	OtherModuleExists(name string) bool
278
279	// OtherModuleDependencyVariantExists returns true if a module with the
280	// specified name and variant exists. The variant must match the given
281	// variations. It must also match all the non-local variations of the current
282	// module. In other words, it checks for the module AddVariationDependencies
283	// would add a dependency on with the same arguments.
284	OtherModuleDependencyVariantExists(variations []Variation, name string) bool
285
286	// OtherModuleReverseDependencyVariantExists returns true if a module with the
287	// specified name exists with the same variations as the current module. In
288	// other words, it checks for the module AddReverseDependency would add a
289	// dependency on with the same argument.
290	OtherModuleReverseDependencyVariantExists(name string) bool
291}
292
293type DynamicDependerModuleContext BottomUpMutatorContext
294
295type ModuleContext interface {
296	BaseModuleContext
297
298	// ModuleSubDir returns a unique name for the current variant of a module that can be used as part of the path
299	// to ensure that each variant of a module gets its own intermediates directory to write to.
300	ModuleSubDir() string
301
302	// Variable creates a new ninja variable scoped to the module.  It can be referenced by calls to Rule and Build
303	// in the same module.
304	Variable(pctx PackageContext, name, value string)
305
306	// Rule creates a new ninja rule scoped to the module.  It can be referenced by calls to Build in the same module.
307	Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule
308
309	// Build creates a new ninja build statement.
310	Build(pctx PackageContext, params BuildParams)
311
312	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in
313	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
314	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are
315	// only done once for all variants of a module.
316	PrimaryModule() Module
317
318	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in
319	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
320	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform
321	// singleton actions that are only done once for all variants of a module.
322	FinalModule() Module
323
324	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always
325	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
326	// from all variants if the current module == FinalModule().  Otherwise, care must be taken to not access any
327	// data modified by the current mutator.
328	VisitAllModuleVariants(visit func(Module))
329
330	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
331	// but do not exist.  It can be used with Context.SetAllowMissingDependencies to allow the primary builder to
332	// handle missing dependencies on its own instead of having Blueprint treat them as an error.
333	GetMissingDependencies() []string
334}
335
336var _ BaseModuleContext = (*baseModuleContext)(nil)
337
338type baseModuleContext struct {
339	context        *Context
340	config         interface{}
341	module         *moduleInfo
342	errs           []error
343	visitingParent *moduleInfo
344	visitingDep    depInfo
345	ninjaFileDeps  []string
346}
347
348func (d *baseModuleContext) moduleInfo() *moduleInfo {
349	return d.module
350}
351
352func (d *baseModuleContext) Module() Module {
353	return d.module.logicModule
354}
355
356func (d *baseModuleContext) ModuleName() string {
357	return d.module.Name()
358}
359
360func (d *baseModuleContext) ModuleType() string {
361	return d.module.typeName
362}
363
364func (d *baseModuleContext) ContainsProperty(name string) bool {
365	_, ok := d.module.propertyPos[name]
366	return ok
367}
368
369func (d *baseModuleContext) ModuleDir() string {
370	return filepath.Dir(d.module.relBlueprintsFile)
371}
372
373func (d *baseModuleContext) BlueprintsFile() string {
374	return d.module.relBlueprintsFile
375}
376
377func (d *baseModuleContext) Config() interface{} {
378	return d.config
379}
380
381func (d *baseModuleContext) error(err error) {
382	if err != nil {
383		d.errs = append(d.errs, err)
384	}
385}
386
387func (d *baseModuleContext) Errorf(pos scanner.Position,
388	format string, args ...interface{}) {
389
390	d.error(&BlueprintError{
391		Err: fmt.Errorf(format, args...),
392		Pos: pos,
393	})
394}
395
396func (d *baseModuleContext) ModuleErrorf(format string,
397	args ...interface{}) {
398
399	d.error(&ModuleError{
400		BlueprintError: BlueprintError{
401			Err: fmt.Errorf(format, args...),
402			Pos: d.module.pos,
403		},
404		module: d.module,
405	})
406}
407
408func (d *baseModuleContext) PropertyErrorf(property, format string,
409	args ...interface{}) {
410
411	pos := d.module.propertyPos[property]
412
413	if !pos.IsValid() {
414		pos = d.module.pos
415	}
416
417	d.error(&PropertyError{
418		ModuleError: ModuleError{
419			BlueprintError: BlueprintError{
420				Err: fmt.Errorf(format, args...),
421				Pos: pos,
422			},
423			module: d.module,
424		},
425		property: property,
426	})
427}
428
429func (d *baseModuleContext) Failed() bool {
430	return len(d.errs) > 0
431}
432
433func (d *baseModuleContext) GlobWithDeps(pattern string,
434	excludes []string) ([]string, error) {
435	return d.context.glob(pattern, excludes)
436}
437
438func (d *baseModuleContext) Fs() pathtools.FileSystem {
439	return d.context.fs
440}
441
442func (d *baseModuleContext) Namespace() Namespace {
443	return d.context.nameInterface.GetNamespace(newNamespaceContext(d.module))
444}
445
446var _ ModuleContext = (*moduleContext)(nil)
447
448type moduleContext struct {
449	baseModuleContext
450	scope              *localScope
451	actionDefs         localBuildActions
452	handledMissingDeps bool
453}
454
455func (m *baseModuleContext) OtherModuleName(logicModule Module) string {
456	module := m.context.moduleInfo[logicModule]
457	return module.Name()
458}
459
460func (m *baseModuleContext) OtherModuleDir(logicModule Module) string {
461	module := m.context.moduleInfo[logicModule]
462	return filepath.Dir(module.relBlueprintsFile)
463}
464
465func (m *baseModuleContext) OtherModuleSubDir(logicModule Module) string {
466	module := m.context.moduleInfo[logicModule]
467	return module.variantName
468}
469
470func (m *baseModuleContext) OtherModuleType(logicModule Module) string {
471	module := m.context.moduleInfo[logicModule]
472	return module.typeName
473}
474
475func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string,
476	args ...interface{}) {
477
478	module := m.context.moduleInfo[logicModule]
479	m.errs = append(m.errs, &ModuleError{
480		BlueprintError: BlueprintError{
481			Err: fmt.Errorf(format, args...),
482			Pos: module.pos,
483		},
484		module: module,
485	})
486}
487
488func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag {
489	// fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps
490	if logicModule == m.visitingDep.module.logicModule {
491		return m.visitingDep.tag
492	}
493
494	for _, dep := range m.visitingParent.directDeps {
495		if dep.module.logicModule == logicModule {
496			return dep.tag
497		}
498	}
499
500	return nil
501}
502
503func (m *baseModuleContext) OtherModuleExists(name string) bool {
504	_, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace())
505	return exists
506}
507
508func (m *baseModuleContext) OtherModuleDependencyVariantExists(variations []Variation, name string) bool {
509	possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace())
510	if possibleDeps == nil {
511		return false
512	}
513	found, _ := m.context.findVariant(m.module, possibleDeps, variations, false, false)
514	return found != nil
515}
516
517func (m *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
518	possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace())
519	if possibleDeps == nil {
520		return false
521	}
522	found, _ := m.context.findVariant(m.module, possibleDeps, nil, false, true)
523	return found != nil
524}
525
526func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) {
527	for _, dep := range m.module.directDeps {
528		if dep.module.Name() == name {
529			return dep.module.logicModule, dep.tag
530		}
531	}
532
533	return nil, nil
534}
535
536func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) Module {
537	var deps []depInfo
538	for _, dep := range m.module.directDeps {
539		if dep.module.Name() == name {
540			if dep.tag == tag {
541				return dep.module.logicModule
542			}
543			deps = append(deps, dep)
544		}
545	}
546
547	if len(deps) != 0 {
548		panic(fmt.Errorf("Unable to find dependency %q with requested tag %#v. Found: %#v", deps[0].module, tag, deps))
549	}
550
551	return nil
552}
553
554func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) {
555	defer func() {
556		if r := recover(); r != nil {
557			panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
558				m.module, funcName(visit), m.visitingDep.module))
559		}
560	}()
561
562	m.visitingParent = m.module
563
564	for _, dep := range m.module.directDeps {
565		m.visitingDep = dep
566		visit(dep.module.logicModule)
567	}
568
569	m.visitingParent = nil
570	m.visitingDep = depInfo{}
571}
572
573func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
574	defer func() {
575		if r := recover(); r != nil {
576			panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
577				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
578		}
579	}()
580
581	m.visitingParent = m.module
582
583	for _, dep := range m.module.directDeps {
584		m.visitingDep = dep
585		if pred(dep.module.logicModule) {
586			visit(dep.module.logicModule)
587		}
588	}
589
590	m.visitingParent = nil
591	m.visitingDep = depInfo{}
592}
593
594func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
595	defer func() {
596		if r := recover(); r != nil {
597			panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
598				m.module, funcName(visit), m.visitingDep.module))
599		}
600	}()
601
602	m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) {
603		m.visitingParent = parent
604		m.visitingDep = dep
605		visit(dep.module.logicModule)
606	})
607
608	m.visitingParent = nil
609	m.visitingDep = depInfo{}
610}
611
612func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
613	visit func(Module)) {
614
615	defer func() {
616		if r := recover(); r != nil {
617			panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
618				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
619		}
620	}()
621
622	m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) {
623		if pred(dep.module.logicModule) {
624			m.visitingParent = parent
625			m.visitingDep = dep
626			visit(dep.module.logicModule)
627		}
628	})
629
630	m.visitingParent = nil
631	m.visitingDep = depInfo{}
632}
633
634func (m *baseModuleContext) WalkDeps(visit func(child, parent Module) bool) {
635	m.context.walkDeps(m.module, true, func(dep depInfo, parent *moduleInfo) bool {
636		m.visitingParent = parent
637		m.visitingDep = dep
638		return visit(dep.module.logicModule, parent.logicModule)
639	}, nil)
640
641	m.visitingParent = nil
642	m.visitingDep = depInfo{}
643}
644
645func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) {
646	m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
647}
648
649func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory {
650	ret := make(map[string]ModuleFactory)
651	for k, v := range m.context.moduleFactories {
652		ret[k] = v
653	}
654	return ret
655}
656
657func (m *moduleContext) ModuleSubDir() string {
658	return m.module.variantName
659}
660
661func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
662	m.scope.ReparentTo(pctx)
663
664	v, err := m.scope.AddLocalVariable(name, value)
665	if err != nil {
666		panic(err)
667	}
668
669	m.actionDefs.variables = append(m.actionDefs.variables, v)
670}
671
672func (m *moduleContext) Rule(pctx PackageContext, name string,
673	params RuleParams, argNames ...string) Rule {
674
675	m.scope.ReparentTo(pctx)
676
677	r, err := m.scope.AddLocalRule(name, &params, argNames...)
678	if err != nil {
679		panic(err)
680	}
681
682	m.actionDefs.rules = append(m.actionDefs.rules, r)
683
684	return r
685}
686
687func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
688	m.scope.ReparentTo(pctx)
689
690	def, err := parseBuildParams(m.scope, &params)
691	if err != nil {
692		panic(err)
693	}
694
695	m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
696}
697
698func (m *moduleContext) PrimaryModule() Module {
699	return m.module.group.modules[0].logicModule
700}
701
702func (m *moduleContext) FinalModule() Module {
703	return m.module.group.modules[len(m.module.group.modules)-1].logicModule
704}
705
706func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
707	m.context.visitAllModuleVariants(m.module, visit)
708}
709
710func (m *moduleContext) GetMissingDependencies() []string {
711	m.handledMissingDeps = true
712	return m.module.missingDeps
713}
714
715//
716// MutatorContext
717//
718
719type mutatorContext struct {
720	baseModuleContext
721	name             string
722	reverseDeps      []reverseDep
723	rename           []rename
724	replace          []replace
725	newVariations    []*moduleInfo // new variants of existing modules
726	newModules       []*moduleInfo // brand new modules
727	defaultVariation *string
728}
729
730type BaseMutatorContext interface {
731	BaseModuleContext
732
733	// Rename all variants of a module.  The new name is not visible to calls to ModuleName,
734	// AddDependency or OtherModuleName until after this mutator pass is complete.
735	Rename(name string)
736
737	// MutatorName returns the name that this mutator was registered with.
738	MutatorName() string
739}
740
741type EarlyMutatorContext interface {
742	BaseMutatorContext
743
744	// CreateVariations splits  a module into mulitple variants, one for each name in the variationNames
745	// parameter.  It returns a list of new modules in the same order as the variationNames
746	// list.
747	//
748	// If any of the dependencies of the module being operated on were already split
749	// by calling CreateVariations with the same name, the dependency will automatically
750	// be updated to point the matching variant.
751	//
752	// If a module is split, and then a module depending on the first module is not split
753	// when the Mutator is later called on it, the dependency of the depending module will
754	// automatically be updated to point to the first variant.
755	CreateVariations(...string) []Module
756
757	// CreateLocationVariations splits a module into mulitple variants, one for each name in the variantNames
758	// parameter.  It returns a list of new modules in the same order as the variantNames
759	// list.
760	//
761	// Local variations do not affect automatic dependency resolution - dependencies added
762	// to the split module via deps or DynamicDependerModule must exactly match a variant
763	// that contains all the non-local variations.
764	CreateLocalVariations(...string) []Module
765}
766
767type TopDownMutatorContext interface {
768	BaseMutatorContext
769
770	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
771	// the specified property structs to it as if the properties were set in a blueprint file.
772	CreateModule(ModuleFactory, ...interface{}) Module
773}
774
775type BottomUpMutatorContext interface {
776	BaseMutatorContext
777
778	// AddDependency adds a dependency to the given module.
779	// Does not affect the ordering of the current mutator pass, but will be ordered
780	// correctly for all future mutator passes.
781	AddDependency(module Module, tag DependencyTag, name ...string)
782
783	// AddReverseDependency adds a dependency from the destination to the given module.
784	// Does not affect the ordering of the current mutator pass, but will be ordered
785	// correctly for all future mutator passes.  All reverse dependencies for a destination module are
786	// collected until the end of the mutator pass, sorted by name, and then appended to the destination
787	// module's dependency list.
788	AddReverseDependency(module Module, tag DependencyTag, name string)
789
790	// CreateVariations splits  a module into mulitple variants, one for each name in the variationNames
791	// parameter.  It returns a list of new modules in the same order as the variationNames
792	// list.
793	//
794	// If any of the dependencies of the module being operated on were already split
795	// by calling CreateVariations with the same name, the dependency will automatically
796	// be updated to point the matching variant.
797	//
798	// If a module is split, and then a module depending on the first module is not split
799	// when the Mutator is later called on it, the dependency of the depending module will
800	// automatically be updated to point to the first variant.
801	CreateVariations(...string) []Module
802
803	// CreateLocationVariations splits a module into mulitple variants, one for each name in the variantNames
804	// parameter.  It returns a list of new modules in the same order as the variantNames
805	// list.
806	//
807	// Local variations do not affect automatic dependency resolution - dependencies added
808	// to the split module via deps or DynamicDependerModule must exactly match a variant
809	// that contains all the non-local variations.
810	CreateLocalVariations(...string) []Module
811
812	// SetDependencyVariation sets all dangling dependencies on the current module to point to the variation
813	// with given name. This function ignores the default variation set by SetDefaultDependencyVariation.
814	SetDependencyVariation(string)
815
816	// SetDefaultDependencyVariation sets the default variation when a dangling reference is detected
817	// during the subsequent calls on Create*Variations* functions. To reset, set it to nil.
818	SetDefaultDependencyVariation(*string)
819
820	// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
821	// argument to select which variant of the dependency to use.  A variant of the dependency must
822	// exist that matches the all of the non-local variations of the current module, plus the variations
823	// argument.
824	AddVariationDependencies([]Variation, DependencyTag, ...string)
825
826	// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
827	// variations argument to select which variant of the dependency to use.  A variant of the
828	// dependency must exist that matches the variations argument, but may also have other variations.
829	// For any unspecified variation the first variant will be used.
830	//
831	// Unlike AddVariationDependencies, the variations of the current module are ignored - the
832	// dependency only needs to match the supplied variations.
833	AddFarVariationDependencies([]Variation, DependencyTag, ...string)
834
835	// AddInterVariantDependency adds a dependency between two variants of the same module.  Variants are always
836	// ordered in the same orderas they were listed in CreateVariations, and AddInterVariantDependency does not change
837	// that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps,
838	// WalkDeps, etc.
839	AddInterVariantDependency(tag DependencyTag, from, to Module)
840
841	// ReplaceDependencies replaces all dependencies on the identical variant of the module with the
842	// specified name with the current variant of this module.  Replacements don't take effect until
843	// after the mutator pass is finished.
844	ReplaceDependencies(string)
845
846	// ReplaceDependencies replaces all dependencies on the identical variant of the module with the
847	// specified name with the current variant of this module as long as the supplied predicate returns
848	// true.
849	//
850	// Replacements don't take effect until after the mutator pass is finished.
851	ReplaceDependenciesIf(string, ReplaceDependencyPredicate)
852
853	// AliasVariation takes a variationName that was passed to CreateVariations for this module, and creates an
854	// alias from the current variant to the new variant.  The alias will be valid until the next time a mutator
855	// calls CreateVariations or CreateLocalVariations on this module without also calling AliasVariation.  The
856	// alias can be used to add dependencies on the newly created variant using the variant map from before
857	// CreateVariations was run.
858	AliasVariation(variationName string)
859}
860
861// A Mutator function is called for each Module, and can use
862// MutatorContext.CreateVariations to split a Module into multiple Modules,
863// modifying properties on the new modules to differentiate them.  It is called
864// after parsing all Blueprint files, but before generating any build rules,
865// and is always called on dependencies before being called on the depending module.
866//
867// The Mutator function should only modify members of properties structs, and not
868// members of the module struct itself, to ensure the modified values are copied
869// if a second Mutator chooses to split the module a second time.
870type TopDownMutator func(mctx TopDownMutatorContext)
871type BottomUpMutator func(mctx BottomUpMutatorContext)
872type EarlyMutator func(mctx EarlyMutatorContext)
873
874// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag.  It can be
875// used to transfer information on a dependency between the mutator that called AddDependency
876// and the GenerateBuildActions method.  Variants created by CreateVariations have a copy of the
877// interface (pointing to the same concrete object) from their original module.
878type DependencyTag interface {
879	dependencyTag(DependencyTag)
880}
881
882type BaseDependencyTag struct {
883}
884
885func (BaseDependencyTag) dependencyTag(DependencyTag) {
886}
887
888var _ DependencyTag = BaseDependencyTag{}
889
890func (mctx *mutatorContext) MutatorName() string {
891	return mctx.name
892}
893
894func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module {
895	return mctx.createVariations(variationNames, false)
896}
897
898func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
899	return mctx.createVariations(variationNames, true)
900}
901
902func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module {
903	ret := []Module{}
904	modules, errs := mctx.context.createVariations(mctx.module, mctx.name, mctx.defaultVariation, variationNames)
905	if len(errs) > 0 {
906		mctx.errs = append(mctx.errs, errs...)
907	}
908
909	for i, module := range modules {
910		ret = append(ret, module.logicModule)
911		if !local {
912			if module.dependencyVariant == nil {
913				module.dependencyVariant = make(variationMap)
914			}
915			module.dependencyVariant[mctx.name] = variationNames[i]
916		}
917	}
918
919	if mctx.newVariations != nil {
920		panic("module already has variations from this mutator")
921	}
922	mctx.newVariations = modules
923
924	if len(ret) != len(variationNames) {
925		panic("oops!")
926	}
927
928	return ret
929}
930
931func (mctx *mutatorContext) AliasVariation(variationName string) {
932	if mctx.module.aliasTarget != nil {
933		panic(fmt.Errorf("AliasVariation already called"))
934	}
935
936	for _, variant := range mctx.newVariations {
937		if variant.variant[mctx.name] == variationName {
938			mctx.module.aliasTarget = variant
939			return
940		}
941	}
942
943	var foundVariations []string
944	for _, variant := range mctx.newVariations {
945		foundVariations = append(foundVariations, variant.variant[mctx.name])
946	}
947	panic(fmt.Errorf("no %q variation in module variations %q", variationName, foundVariations))
948}
949
950func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
951	mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName, nil)
952}
953
954func (mctx *mutatorContext) SetDefaultDependencyVariation(variationName *string) {
955	mctx.defaultVariation = variationName
956}
957
958func (mctx *mutatorContext) Module() Module {
959	return mctx.module.logicModule
960}
961
962func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) {
963	for _, dep := range deps {
964		modInfo := mctx.context.moduleInfo[module]
965		errs := mctx.context.addDependency(modInfo, tag, dep)
966		if len(errs) > 0 {
967			mctx.errs = append(mctx.errs, errs...)
968		}
969	}
970}
971
972func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) {
973	if _, ok := tag.(BaseDependencyTag); ok {
974		panic("BaseDependencyTag is not allowed to be used directly!")
975	}
976
977	destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName)
978	if len(errs) > 0 {
979		mctx.errs = append(mctx.errs, errs...)
980		return
981	}
982
983	mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{
984		destModule,
985		depInfo{mctx.context.moduleInfo[module], tag},
986	})
987}
988
989func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag,
990	deps ...string) {
991
992	for _, dep := range deps {
993		errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false)
994		if len(errs) > 0 {
995			mctx.errs = append(mctx.errs, errs...)
996		}
997	}
998}
999
1000func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag,
1001	deps ...string) {
1002
1003	for _, dep := range deps {
1004		errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true)
1005		if len(errs) > 0 {
1006			mctx.errs = append(mctx.errs, errs...)
1007		}
1008	}
1009}
1010
1011func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) {
1012	mctx.context.addInterVariantDependency(mctx.module, tag, from, to)
1013}
1014
1015func (mctx *mutatorContext) ReplaceDependencies(name string) {
1016	mctx.ReplaceDependenciesIf(name, nil)
1017}
1018
1019type ReplaceDependencyPredicate func(from Module, tag DependencyTag, to Module) bool
1020
1021func (mctx *mutatorContext) ReplaceDependenciesIf(name string, predicate ReplaceDependencyPredicate) {
1022	target := mctx.context.moduleMatchingVariant(mctx.module, name)
1023
1024	if target == nil {
1025		panic(fmt.Errorf("ReplaceDependencies could not find identical variant %q for module %q",
1026			mctx.module.variantName, name))
1027	}
1028
1029	mctx.replace = append(mctx.replace, replace{target, mctx.module, predicate})
1030}
1031
1032func (mctx *mutatorContext) Rename(name string) {
1033	mctx.rename = append(mctx.rename, rename{mctx.module.group, name})
1034}
1035
1036func (mctx *mutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
1037	module := newModule(factory)
1038
1039	module.relBlueprintsFile = mctx.module.relBlueprintsFile
1040	module.pos = mctx.module.pos
1041	module.propertyPos = mctx.module.propertyPos
1042	module.createdBy = mctx.module
1043
1044	for _, p := range props {
1045		err := proptools.AppendMatchingProperties(module.properties, p, nil)
1046		if err != nil {
1047			panic(err)
1048		}
1049	}
1050
1051	mctx.newModules = append(mctx.newModules, module)
1052
1053	return module.logicModule
1054}
1055
1056// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property
1057// called "name".  Modules that embed it must also add SimpleName.Properties to their property
1058// structure list.
1059type SimpleName struct {
1060	Properties struct {
1061		Name string
1062	}
1063}
1064
1065func (s *SimpleName) Name() string {
1066	return s.Properties.Name
1067}
1068
1069// Load Hooks
1070
1071type LoadHookContext interface {
1072	EarlyModuleContext
1073
1074	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
1075	// the specified property structs to it as if the properties were set in a blueprint file.
1076	CreateModule(ModuleFactory, ...interface{}) Module
1077
1078	// RegisterScopedModuleType creates a new module type that is scoped to the current Blueprints
1079	// file.
1080	RegisterScopedModuleType(name string, factory ModuleFactory)
1081}
1082
1083func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
1084	module := newModule(factory)
1085
1086	module.relBlueprintsFile = l.module.relBlueprintsFile
1087	module.pos = l.module.pos
1088	module.propertyPos = l.module.propertyPos
1089	module.createdBy = l.module
1090
1091	for _, p := range props {
1092		err := proptools.AppendMatchingProperties(module.properties, p, nil)
1093		if err != nil {
1094			panic(err)
1095		}
1096	}
1097
1098	l.newModules = append(l.newModules, module)
1099
1100	return module.logicModule
1101}
1102
1103func (l *loadHookContext) RegisterScopedModuleType(name string, factory ModuleFactory) {
1104	if _, exists := l.context.moduleFactories[name]; exists {
1105		panic(fmt.Errorf("A global module type named %q already exists", name))
1106	}
1107
1108	if _, exists := (*l.scopedModuleFactories)[name]; exists {
1109		panic(fmt.Errorf("A module type named %q already exists in this scope", name))
1110	}
1111
1112	if *l.scopedModuleFactories == nil {
1113		(*l.scopedModuleFactories) = make(map[string]ModuleFactory)
1114	}
1115
1116	(*l.scopedModuleFactories)[name] = factory
1117}
1118
1119type loadHookContext struct {
1120	baseModuleContext
1121	newModules            []*moduleInfo
1122	scopedModuleFactories *map[string]ModuleFactory
1123}
1124
1125type LoadHook func(ctx LoadHookContext)
1126
1127// Load hooks need to be added by module factories, which don't have any parameter to get to the
1128// Context, and only produce a Module interface with no base implementation, so the load hooks
1129// must be stored in a global map.  The key is a pointer allocated by the module factory, so there
1130// is no chance of collisions even if tests are running in parallel with multiple contexts.  The
1131// contents should be short-lived, they are added during a module factory and removed immediately
1132// after the module factory returns.
1133var pendingHooks sync.Map
1134
1135func AddLoadHook(module Module, hook LoadHook) {
1136	// Only one goroutine can be processing a given module, so no additional locking is required
1137	// for the slice stored in the sync.Map.
1138	v, exists := pendingHooks.Load(module)
1139	if !exists {
1140		v, _ = pendingHooks.LoadOrStore(module, new([]LoadHook))
1141	}
1142	hooks := v.(*[]LoadHook)
1143	*hooks = append(*hooks, hook)
1144}
1145
1146func runAndRemoveLoadHooks(ctx *Context, config interface{}, module *moduleInfo,
1147	scopedModuleFactories *map[string]ModuleFactory) (newModules []*moduleInfo, errs []error) {
1148
1149	if v, exists := pendingHooks.Load(module.logicModule); exists {
1150		hooks := v.(*[]LoadHook)
1151		mctx := &loadHookContext{
1152			baseModuleContext: baseModuleContext{
1153				context: ctx,
1154				config:  config,
1155				module:  module,
1156			},
1157			scopedModuleFactories: scopedModuleFactories,
1158		}
1159
1160		for _, hook := range *hooks {
1161			hook(mctx)
1162			newModules = append(newModules, mctx.newModules...)
1163			errs = append(errs, mctx.errs...)
1164		}
1165		pendingHooks.Delete(module.logicModule)
1166
1167		return newModules, errs
1168	}
1169
1170	return nil, nil
1171}
1172
1173// Check the syntax of a generated blueprint file.
1174//
1175// This is intended to perform a quick sanity check for generated blueprint
1176// code to ensure that it is syntactically correct, where syntactically correct
1177// means:
1178// * No variable definitions.
1179// * Valid module types.
1180// * Valid property names.
1181// * Valid values for the property type.
1182//
1183// It does not perform any semantic checking of properties, existence of referenced
1184// files, or dependencies.
1185//
1186// At a low level it:
1187// * Parses the contents.
1188// * Invokes relevant factory to create Module instances.
1189// * Unpacks the properties into the Module.
1190// * Does not invoke load hooks or any mutators.
1191//
1192// The filename is only used for reporting errors.
1193func CheckBlueprintSyntax(moduleFactories map[string]ModuleFactory, filename string, contents string) []error {
1194	scope := parser.NewScope(nil)
1195	file, errs := parser.Parse(filename, strings.NewReader(contents), scope)
1196	if len(errs) != 0 {
1197		return errs
1198	}
1199
1200	for _, def := range file.Defs {
1201		switch def := def.(type) {
1202		case *parser.Module:
1203			_, moduleErrs := processModuleDef(def, filename, moduleFactories, nil, false)
1204			errs = append(errs, moduleErrs...)
1205
1206		default:
1207			panic(fmt.Errorf("unknown definition type: %T", def))
1208		}
1209	}
1210
1211	return errs
1212}
1213