• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 definition 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	// Context.RegisterModuleType().
140	ModuleType() string
141
142	// BlueprintsFile 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	// VisitDepsDepthFirstIf 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	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in
250	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
251	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are
252	// only done once for all variants of a module.
253	PrimaryModule() Module
254
255	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in
256	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
257	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform
258	// singleton actions that are only done once for all variants of a module.
259	FinalModule() Module
260
261	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always
262	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
263	// from all variants if the current module == FinalModule().  Otherwise, care must be taken to not access any
264	// data modified by the current mutator.
265	VisitAllModuleVariants(visit func(Module))
266
267	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
268	// It is intended for use inside the visit functions of Visit* and WalkDeps.
269	OtherModuleName(m Module) string
270
271	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information.
272	// It is intended for use inside the visit functions of Visit* and WalkDeps.
273	OtherModuleDir(m Module) string
274
275	// OtherModuleSubDir returns the unique subdirectory name of another Module.  See ModuleContext.ModuleSubDir for
276	// more information.
277	// It is intended for use inside the visit functions of Visit* and WalkDeps.
278	OtherModuleSubDir(m Module) string
279
280	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information.
281	// It is intended for use inside the visit functions of Visit* and WalkDeps.
282	OtherModuleType(m Module) string
283
284	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information.
285	// It is intended for use inside the visit functions of Visit* and WalkDeps.
286	OtherModuleErrorf(m Module, fmt string, args ...interface{})
287
288	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
289	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple
290	// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
291	OtherModuleDependencyTag(m Module) DependencyTag
292
293	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
294	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
295	OtherModuleExists(name string) bool
296
297	// ModuleFromName returns (module, true) if a module exists by the given name and same context namespace,
298	// or (nil, false) if it does not exist. It panics if there is either more than one
299	// module of the given name, or if the given name refers to an alias instead of a module.
300	// There are no guarantees about which variant of the module will be returned.
301	// Prefer retrieving the module using GetDirectDep or a visit function, when possible, as
302	// this will guarantee the appropriate module-variant dependency is returned.
303	//
304	// WARNING: This should _only_ be used within the context of bp2build, where variants and
305	// dependencies are not created.
306	ModuleFromName(name string) (Module, bool)
307
308	// OtherModuleDependencyVariantExists returns true if a module with the
309	// specified name and variant exists. The variant must match the given
310	// variations. It must also match all the non-local variations of the current
311	// module. In other words, it checks for the module that AddVariationDependencies
312	// would add a dependency on with the same arguments.
313	OtherModuleDependencyVariantExists(variations []Variation, name string) bool
314
315	// OtherModuleFarDependencyVariantExists returns true if a module with the
316	// specified name and variant exists. The variant must match the given
317	// variations, but not the non-local variations of the current module. In
318	// other words, it checks for the module that AddFarVariationDependencies
319	// would add a dependency on with the same arguments.
320	OtherModuleFarDependencyVariantExists(variations []Variation, name string) bool
321
322	// OtherModuleReverseDependencyVariantExists returns true if a module with the
323	// specified name exists with the same variations as the current module. In
324	// other words, it checks for the module that AddReverseDependency would add a
325	// dependency on with the same argument.
326	OtherModuleReverseDependencyVariantExists(name string) bool
327
328	// OtherModuleProvider returns the value for a provider for the given module.  If the value is
329	// not set it returns the zero value of the type of the provider, so the return value can always
330	// be type asserted to the type of the provider.  The value returned may be a deep copy of the
331	// value originally passed to SetProvider.
332	OtherModuleProvider(m Module, provider ProviderKey) interface{}
333
334	// OtherModuleHasProvider returns true if the provider for the given module has been set.
335	OtherModuleHasProvider(m Module, provider ProviderKey) bool
336
337	// Provider returns the value for a provider for the current module.  If the value is
338	// not set it returns the zero value of the type of the provider, so the return value can always
339	// be type asserted to the type of the provider.  It panics if called before the appropriate
340	// mutator or GenerateBuildActions pass for the provider.  The value returned may be a deep
341	// copy of the value originally passed to SetProvider.
342	Provider(provider ProviderKey) interface{}
343
344	// HasProvider returns true if the provider for the current module has been set.
345	HasProvider(provider ProviderKey) bool
346
347	// SetProvider sets the value for a provider for the current module.  It panics if not called
348	// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
349	// is not of the appropriate type, or if the value has already been set.  The value should not
350	// be modified after being passed to SetProvider.
351	SetProvider(provider ProviderKey, value interface{})
352}
353
354type DynamicDependerModuleContext BottomUpMutatorContext
355
356type ModuleContext interface {
357	BaseModuleContext
358
359	// ModuleSubDir returns a unique name for the current variant of a module that can be used as part of the path
360	// to ensure that each variant of a module gets its own intermediates directory to write to.
361	ModuleSubDir() string
362
363	// Variable creates a new ninja variable scoped to the module.  It can be referenced by calls to Rule and Build
364	// in the same module.
365	Variable(pctx PackageContext, name, value string)
366
367	// Rule creates a new ninja rule scoped to the module.  It can be referenced by calls to Build in the same module.
368	Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule
369
370	// Build creates a new ninja build statement.
371	Build(pctx PackageContext, params BuildParams)
372
373	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
374	// but do not exist.  It can be used with Context.SetAllowMissingDependencies to allow the primary builder to
375	// handle missing dependencies on its own instead of having Blueprint treat them as an error.
376	GetMissingDependencies() []string
377}
378
379var _ BaseModuleContext = (*baseModuleContext)(nil)
380
381type baseModuleContext struct {
382	context        *Context
383	config         interface{}
384	module         *moduleInfo
385	errs           []error
386	visitingParent *moduleInfo
387	visitingDep    depInfo
388	ninjaFileDeps  []string
389}
390
391func (d *baseModuleContext) moduleInfo() *moduleInfo {
392	return d.module
393}
394
395func (d *baseModuleContext) Module() Module {
396	return d.module.logicModule
397}
398
399func (d *baseModuleContext) ModuleName() string {
400	return d.module.Name()
401}
402
403func (d *baseModuleContext) ModuleType() string {
404	return d.module.typeName
405}
406
407func (d *baseModuleContext) ContainsProperty(name string) bool {
408	_, ok := d.module.propertyPos[name]
409	return ok
410}
411
412func (d *baseModuleContext) ModuleDir() string {
413	return filepath.Dir(d.module.relBlueprintsFile)
414}
415
416func (d *baseModuleContext) BlueprintsFile() string {
417	return d.module.relBlueprintsFile
418}
419
420func (d *baseModuleContext) Config() interface{} {
421	return d.config
422}
423
424func (d *baseModuleContext) error(err error) {
425	if err != nil {
426		d.errs = append(d.errs, err)
427	}
428}
429
430func (d *baseModuleContext) Errorf(pos scanner.Position,
431	format string, args ...interface{}) {
432
433	d.error(&BlueprintError{
434		Err: fmt.Errorf(format, args...),
435		Pos: pos,
436	})
437}
438
439func (d *baseModuleContext) ModuleErrorf(format string,
440	args ...interface{}) {
441
442	d.error(&ModuleError{
443		BlueprintError: BlueprintError{
444			Err: fmt.Errorf(format, args...),
445			Pos: d.module.pos,
446		},
447		module: d.module,
448	})
449}
450
451func (d *baseModuleContext) PropertyErrorf(property, format string,
452	args ...interface{}) {
453
454	pos := d.module.propertyPos[property]
455
456	if !pos.IsValid() {
457		pos = d.module.pos
458	}
459
460	d.error(&PropertyError{
461		ModuleError: ModuleError{
462			BlueprintError: BlueprintError{
463				Err: fmt.Errorf(format, args...),
464				Pos: pos,
465			},
466			module: d.module,
467		},
468		property: property,
469	})
470}
471
472func (d *baseModuleContext) Failed() bool {
473	return len(d.errs) > 0
474}
475
476func (d *baseModuleContext) GlobWithDeps(pattern string,
477	excludes []string) ([]string, error) {
478	return d.context.glob(pattern, excludes)
479}
480
481func (d *baseModuleContext) Fs() pathtools.FileSystem {
482	return d.context.fs
483}
484
485func (d *baseModuleContext) Namespace() Namespace {
486	return d.context.nameInterface.GetNamespace(newNamespaceContext(d.module))
487}
488
489var _ ModuleContext = (*moduleContext)(nil)
490
491type moduleContext struct {
492	baseModuleContext
493	scope              *localScope
494	actionDefs         localBuildActions
495	handledMissingDeps bool
496}
497
498func (m *baseModuleContext) OtherModuleName(logicModule Module) string {
499	module := m.context.moduleInfo[logicModule]
500	return module.Name()
501}
502
503func (m *baseModuleContext) OtherModuleDir(logicModule Module) string {
504	module := m.context.moduleInfo[logicModule]
505	return filepath.Dir(module.relBlueprintsFile)
506}
507
508func (m *baseModuleContext) OtherModuleSubDir(logicModule Module) string {
509	module := m.context.moduleInfo[logicModule]
510	return module.variant.name
511}
512
513func (m *baseModuleContext) OtherModuleType(logicModule Module) string {
514	module := m.context.moduleInfo[logicModule]
515	return module.typeName
516}
517
518func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string,
519	args ...interface{}) {
520
521	module := m.context.moduleInfo[logicModule]
522	m.errs = append(m.errs, &ModuleError{
523		BlueprintError: BlueprintError{
524			Err: fmt.Errorf(format, args...),
525			Pos: module.pos,
526		},
527		module: module,
528	})
529}
530
531func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag {
532	// fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps
533	if logicModule == m.visitingDep.module.logicModule {
534		return m.visitingDep.tag
535	}
536
537	for _, dep := range m.visitingParent.directDeps {
538		if dep.module.logicModule == logicModule {
539			return dep.tag
540		}
541	}
542
543	return nil
544}
545
546func (m *baseModuleContext) ModuleFromName(name string) (Module, bool) {
547	moduleGroup, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace())
548	if exists {
549		if len(moduleGroup.modules) != 1 {
550			panic(fmt.Errorf("Expected exactly one module named %q, but got %d", name, len(moduleGroup.modules)))
551		}
552		moduleInfo := moduleGroup.modules[0].module()
553		if moduleInfo != nil {
554			return moduleInfo.logicModule, true
555		} else {
556			panic(fmt.Errorf(`Expected actual module named %q, but group did not contain a module.
557    There may instead be an alias by that name.`, name))
558		}
559	}
560	return nil, exists
561}
562
563func (m *baseModuleContext) OtherModuleExists(name string) bool {
564	_, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace())
565	return exists
566}
567
568func (m *baseModuleContext) OtherModuleDependencyVariantExists(variations []Variation, name string) bool {
569	possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace())
570	if possibleDeps == nil {
571		return false
572	}
573	found, _ := findVariant(m.module, possibleDeps, variations, false, false)
574	return found != nil
575}
576
577func (m *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []Variation, name string) bool {
578	possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace())
579	if possibleDeps == nil {
580		return false
581	}
582	found, _ := findVariant(m.module, possibleDeps, variations, true, false)
583	return found != nil
584}
585
586func (m *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
587	possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace())
588	if possibleDeps == nil {
589		return false
590	}
591	found, _ := findVariant(m.module, possibleDeps, nil, false, true)
592	return found != nil
593}
594
595func (m *baseModuleContext) OtherModuleProvider(logicModule Module, provider ProviderKey) interface{} {
596	module := m.context.moduleInfo[logicModule]
597	value, _ := m.context.provider(module, provider)
598	return value
599}
600
601func (m *baseModuleContext) OtherModuleHasProvider(logicModule Module, provider ProviderKey) bool {
602	module := m.context.moduleInfo[logicModule]
603	_, ok := m.context.provider(module, provider)
604	return ok
605}
606
607func (m *baseModuleContext) Provider(provider ProviderKey) interface{} {
608	value, _ := m.context.provider(m.module, provider)
609	return value
610}
611
612func (m *baseModuleContext) HasProvider(provider ProviderKey) bool {
613	_, ok := m.context.provider(m.module, provider)
614	return ok
615}
616
617func (m *baseModuleContext) SetProvider(provider ProviderKey, value interface{}) {
618	m.context.setProvider(m.module, provider, value)
619}
620
621func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) {
622	for _, dep := range m.module.directDeps {
623		if dep.module.Name() == name {
624			return dep.module.logicModule, dep.tag
625		}
626	}
627
628	return nil, nil
629}
630
631func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) Module {
632	var deps []depInfo
633	for _, dep := range m.module.directDeps {
634		if dep.module.Name() == name {
635			if dep.tag == tag {
636				return dep.module.logicModule
637			}
638			deps = append(deps, dep)
639		}
640	}
641
642	if len(deps) != 0 {
643		panic(fmt.Errorf("Unable to find dependency %q with requested tag %#v. Found: %#v", deps[0].module, tag, deps))
644	}
645
646	return nil
647}
648
649func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) {
650	defer func() {
651		if r := recover(); r != nil {
652			panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
653				m.module, funcName(visit), m.visitingDep.module))
654		}
655	}()
656
657	m.visitingParent = m.module
658
659	for _, dep := range m.module.directDeps {
660		m.visitingDep = dep
661		visit(dep.module.logicModule)
662	}
663
664	m.visitingParent = nil
665	m.visitingDep = depInfo{}
666}
667
668func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
669	defer func() {
670		if r := recover(); r != nil {
671			panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
672				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
673		}
674	}()
675
676	m.visitingParent = m.module
677
678	for _, dep := range m.module.directDeps {
679		m.visitingDep = dep
680		if pred(dep.module.logicModule) {
681			visit(dep.module.logicModule)
682		}
683	}
684
685	m.visitingParent = nil
686	m.visitingDep = depInfo{}
687}
688
689func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
690	defer func() {
691		if r := recover(); r != nil {
692			panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
693				m.module, funcName(visit), m.visitingDep.module))
694		}
695	}()
696
697	m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) {
698		m.visitingParent = parent
699		m.visitingDep = dep
700		visit(dep.module.logicModule)
701	})
702
703	m.visitingParent = nil
704	m.visitingDep = depInfo{}
705}
706
707func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
708	visit func(Module)) {
709
710	defer func() {
711		if r := recover(); r != nil {
712			panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
713				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
714		}
715	}()
716
717	m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) {
718		if pred(dep.module.logicModule) {
719			m.visitingParent = parent
720			m.visitingDep = dep
721			visit(dep.module.logicModule)
722		}
723	})
724
725	m.visitingParent = nil
726	m.visitingDep = depInfo{}
727}
728
729func (m *baseModuleContext) WalkDeps(visit func(child, parent Module) bool) {
730	m.context.walkDeps(m.module, true, func(dep depInfo, parent *moduleInfo) bool {
731		m.visitingParent = parent
732		m.visitingDep = dep
733		return visit(dep.module.logicModule, parent.logicModule)
734	}, nil)
735
736	m.visitingParent = nil
737	m.visitingDep = depInfo{}
738}
739
740func (m *baseModuleContext) PrimaryModule() Module {
741	return m.module.group.modules.firstModule().logicModule
742}
743
744func (m *baseModuleContext) FinalModule() Module {
745	return m.module.group.modules.lastModule().logicModule
746}
747
748func (m *baseModuleContext) VisitAllModuleVariants(visit func(Module)) {
749	m.context.visitAllModuleVariants(m.module, visit)
750}
751
752func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) {
753	m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
754}
755
756func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory {
757	ret := make(map[string]ModuleFactory)
758	for k, v := range m.context.moduleFactories {
759		ret[k] = v
760	}
761	return ret
762}
763
764func (m *moduleContext) ModuleSubDir() string {
765	return m.module.variant.name
766}
767
768func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
769	m.scope.ReparentTo(pctx)
770
771	v, err := m.scope.AddLocalVariable(name, value)
772	if err != nil {
773		panic(err)
774	}
775
776	m.actionDefs.variables = append(m.actionDefs.variables, v)
777}
778
779func (m *moduleContext) Rule(pctx PackageContext, name string,
780	params RuleParams, argNames ...string) Rule {
781
782	m.scope.ReparentTo(pctx)
783
784	r, err := m.scope.AddLocalRule(name, &params, argNames...)
785	if err != nil {
786		panic(err)
787	}
788
789	m.actionDefs.rules = append(m.actionDefs.rules, r)
790
791	return r
792}
793
794func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
795	m.scope.ReparentTo(pctx)
796
797	def, err := parseBuildParams(m.scope, &params)
798	if err != nil {
799		panic(err)
800	}
801
802	m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
803}
804
805func (m *moduleContext) GetMissingDependencies() []string {
806	m.handledMissingDeps = true
807	return m.module.missingDeps
808}
809
810//
811// MutatorContext
812//
813
814type mutatorContext struct {
815	baseModuleContext
816	name             string
817	reverseDeps      []reverseDep
818	rename           []rename
819	replace          []replace
820	newVariations    modulesOrAliases // new variants of existing modules
821	newModules       []*moduleInfo    // brand new modules
822	defaultVariation *string
823	pauseCh          chan<- pauseSpec
824}
825
826type BaseMutatorContext interface {
827	BaseModuleContext
828
829	// Rename all variants of a module.  The new name is not visible to calls to ModuleName,
830	// AddDependency or OtherModuleName until after this mutator pass is complete.
831	Rename(name string)
832
833	// MutatorName returns the name that this mutator was registered with.
834	MutatorName() string
835}
836
837type TopDownMutatorContext interface {
838	BaseMutatorContext
839
840	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
841	// the specified property structs to it as if the properties were set in a blueprint file.
842	CreateModule(ModuleFactory, string, ...interface{}) Module
843}
844
845type BottomUpMutatorContext interface {
846	BaseMutatorContext
847
848	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
849	// dependency (some entries may be nil).  Does not affect the ordering of the current mutator
850	// pass, but will be ordered correctly for all future mutator passes.
851	//
852	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
853	// new dependencies have had the current mutator called on them.  If the mutator is not
854	// parallel this method does not affect the ordering of the current mutator pass, but will
855	// be ordered correctly for all future mutator passes.
856	AddDependency(module Module, tag DependencyTag, name ...string) []Module
857
858	// AddReverseDependency adds a dependency from the destination to the given module.
859	// Does not affect the ordering of the current mutator pass, but will be ordered
860	// correctly for all future mutator passes.  All reverse dependencies for a destination module are
861	// collected until the end of the mutator pass, sorted by name, and then appended to the destination
862	// module's dependency list.
863	AddReverseDependency(module Module, tag DependencyTag, name string)
864
865	// CreateVariations splits  a module into multiple variants, one for each name in the variationNames
866	// parameter.  It returns a list of new modules in the same order as the variationNames
867	// list.
868	//
869	// If any of the dependencies of the module being operated on were already split
870	// by calling CreateVariations with the same name, the dependency will automatically
871	// be updated to point the matching variant.
872	//
873	// If a module is split, and then a module depending on the first module is not split
874	// when the Mutator is later called on it, the dependency of the depending module will
875	// automatically be updated to point to the first variant.
876	CreateVariations(variationNames ...string) []Module
877
878	// CreateLocalVariations splits a module into multiple variants, one for each name in the variationNames
879	// parameter.  It returns a list of new modules in the same order as the variantNames
880	// list.
881	//
882	// Local variations do not affect automatic dependency resolution - dependencies added
883	// to the split module via deps or DynamicDependerModule must exactly match a variant
884	// that contains all the non-local variations.
885	CreateLocalVariations(variationNames ...string) []Module
886
887	// SetDependencyVariation sets all dangling dependencies on the current module to point to the variation
888	// with given name. This function ignores the default variation set by SetDefaultDependencyVariation.
889	SetDependencyVariation(string)
890
891	// SetDefaultDependencyVariation sets the default variation when a dangling reference is detected
892	// during the subsequent calls on Create*Variations* functions. To reset, set it to nil.
893	SetDefaultDependencyVariation(*string)
894
895	// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
896	// argument to select which variant of the dependency to use.  It returns a slice of modules for
897	// each dependency (some entries may be nil).  A variant of the dependency must exist that matches
898	// the all of the non-local variations of the current module, plus the variations argument.
899	//
900	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
901	// new dependencies have had the current mutator called on them.  If the mutator is not
902	// parallel this method does not affect the ordering of the current mutator pass, but will
903	// be ordered correctly for all future mutator passes.
904	AddVariationDependencies([]Variation, DependencyTag, ...string) []Module
905
906	// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
907	// variations argument to select which variant of the dependency to use.  It returns a slice of
908	// modules for each dependency (some entries may be nil).  A variant of the dependency must
909	// exist that matches the variations argument, but may also have other variations.
910	// For any unspecified variation the first variant will be used.
911	//
912	// Unlike AddVariationDependencies, the variations of the current module are ignored - the
913	// dependency only needs to match the supplied variations.
914	//
915	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
916	// new dependencies have had the current mutator called on them.  If the mutator is not
917	// parallel this method does not affect the ordering of the current mutator pass, but will
918	// be ordered correctly for all future mutator passes.
919	AddFarVariationDependencies([]Variation, DependencyTag, ...string) []Module
920
921	// AddInterVariantDependency adds a dependency between two variants of the same module.  Variants are always
922	// ordered in the same order as they were listed in CreateVariations, and AddInterVariantDependency does not change
923	// that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps,
924	// WalkDeps, etc.
925	AddInterVariantDependency(tag DependencyTag, from, to Module)
926
927	// ReplaceDependencies replaces all dependencies on the identical variant of the module with the
928	// specified name with the current variant of this module.  Replacements don't take effect until
929	// after the mutator pass is finished.
930	ReplaceDependencies(string)
931
932	// ReplaceDependenciesIf replaces all dependencies on the identical variant of the module with the
933	// specified name with the current variant of this module as long as the supplied predicate returns
934	// true.
935	//
936	// Replacements don't take effect until after the mutator pass is finished.
937	ReplaceDependenciesIf(string, ReplaceDependencyPredicate)
938
939	// AliasVariation takes a variationName that was passed to CreateVariations for this module,
940	// and creates an alias from the current variant (before the mutator has run) to the new
941	// variant.  The alias will be valid until the next time a mutator calls CreateVariations or
942	// CreateLocalVariations on this module without also calling AliasVariation.  The alias can
943	// be used to add dependencies on the newly created variant using the variant map from
944	// before CreateVariations was run.
945	AliasVariation(variationName string)
946
947	// CreateAliasVariation takes a toVariationName that was passed to CreateVariations for this
948	// module, and creates an alias from a new fromVariationName variant the toVariationName
949	// variant.  The alias will be valid until the next time a mutator calls CreateVariations or
950	// CreateLocalVariations on this module without also calling AliasVariation.  The alias can
951	// be used to add dependencies on the toVariationName variant using the fromVariationName
952	// variant.
953	CreateAliasVariation(fromVariationName, toVariationName string)
954
955	// SetVariationProvider sets the value for a provider for the given newly created variant of
956	// the current module, i.e. one of the Modules returned by CreateVariations..  It panics if
957	// not called during the appropriate mutator or GenerateBuildActions pass for the provider,
958	// if the value is not of the appropriate type, or if the module is not a newly created
959	// variant of the current module.  The value should not be modified after being passed to
960	// SetVariationProvider.
961	SetVariationProvider(module Module, provider ProviderKey, value interface{})
962}
963
964// A Mutator function is called for each Module, and can use
965// MutatorContext.CreateVariations to split a Module into multiple Modules,
966// modifying properties on the new modules to differentiate them.  It is called
967// after parsing all Blueprint files, but before generating any build rules,
968// and is always called on dependencies before being called on the depending module.
969//
970// The Mutator function should only modify members of properties structs, and not
971// members of the module struct itself, to ensure the modified values are copied
972// if a second Mutator chooses to split the module a second time.
973type TopDownMutator func(mctx TopDownMutatorContext)
974type BottomUpMutator func(mctx BottomUpMutatorContext)
975
976// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag.  It can be
977// used to transfer information on a dependency between the mutator that called AddDependency
978// and the GenerateBuildActions method.  Variants created by CreateVariations have a copy of the
979// interface (pointing to the same concrete object) from their original module.
980type DependencyTag interface {
981	dependencyTag(DependencyTag)
982}
983
984type BaseDependencyTag struct {
985}
986
987func (BaseDependencyTag) dependencyTag(DependencyTag) {
988}
989
990var _ DependencyTag = BaseDependencyTag{}
991
992func (mctx *mutatorContext) MutatorName() string {
993	return mctx.name
994}
995
996func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module {
997	depChooser := chooseDepInherit(mctx.name, mctx.defaultVariation)
998	return mctx.createVariations(variationNames, depChooser, false)
999}
1000
1001func (mctx *mutatorContext) createVariationsWithTransition(transition Transition, variationNames ...string) []Module {
1002	return mctx.createVariations(variationNames, chooseDepByTransition(mctx.name, transition), false)
1003}
1004
1005func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
1006	depChooser := chooseDepInherit(mctx.name, mctx.defaultVariation)
1007	return mctx.createVariations(variationNames, depChooser, true)
1008}
1009
1010func (mctx *mutatorContext) SetVariationProvider(module Module, provider ProviderKey, value interface{}) {
1011	for _, variant := range mctx.newVariations {
1012		if m := variant.module(); m != nil && m.logicModule == module {
1013			mctx.context.setProvider(m, provider, value)
1014			return
1015		}
1016	}
1017	panic(fmt.Errorf("module %q is not a newly created variant of %q", module, mctx.module))
1018}
1019
1020func (mctx *mutatorContext) createVariations(variationNames []string, depChooser depChooser, local bool) []Module {
1021	var ret []Module
1022	modules, errs := mctx.context.createVariations(mctx.module, mctx.name, depChooser, variationNames, local)
1023	if len(errs) > 0 {
1024		mctx.errs = append(mctx.errs, errs...)
1025	}
1026
1027	for _, module := range modules {
1028		ret = append(ret, module.module().logicModule)
1029	}
1030
1031	if mctx.newVariations != nil {
1032		panic("module already has variations from this mutator")
1033	}
1034	mctx.newVariations = modules
1035
1036	if len(ret) != len(variationNames) {
1037		panic("oops!")
1038	}
1039
1040	return ret
1041}
1042
1043func (mctx *mutatorContext) AliasVariation(variationName string) {
1044	for _, moduleOrAlias := range mctx.module.splitModules {
1045		if alias := moduleOrAlias.alias(); alias != nil {
1046			if alias.variant.variations.equal(mctx.module.variant.variations) {
1047				panic(fmt.Errorf("AliasVariation already called"))
1048			}
1049		}
1050	}
1051
1052	for _, variant := range mctx.newVariations {
1053		if variant.moduleOrAliasVariant().variations[mctx.name] == variationName {
1054			alias := &moduleAlias{
1055				variant: mctx.module.variant,
1056				target:  variant.moduleOrAliasTarget(),
1057			}
1058			// Prepend the alias so that AddFarVariationDependencies subset match matches
1059			// the alias before matching the first variation.
1060			mctx.module.splitModules = append(modulesOrAliases{alias}, mctx.module.splitModules...)
1061			return
1062		}
1063	}
1064
1065	var foundVariations []string
1066	for _, variant := range mctx.newVariations {
1067		foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name])
1068	}
1069	panic(fmt.Errorf("no %q variation in module variations %q", variationName, foundVariations))
1070}
1071
1072func (mctx *mutatorContext) CreateAliasVariation(aliasVariationName, targetVariationName string) {
1073	newVariant := newVariant(mctx.module, mctx.name, aliasVariationName, false)
1074
1075	for _, moduleOrAlias := range mctx.module.splitModules {
1076		if moduleOrAlias.moduleOrAliasVariant().variations.equal(newVariant.variations) {
1077			if alias := moduleOrAlias.alias(); alias != nil {
1078				panic(fmt.Errorf("can't alias %q to %q, already aliased to %q", aliasVariationName, targetVariationName, alias.target.variant.name))
1079			} else {
1080				panic(fmt.Errorf("can't alias %q to %q, there is already a variant with that name", aliasVariationName, targetVariationName))
1081			}
1082		}
1083	}
1084
1085	for _, variant := range mctx.newVariations {
1086		if variant.moduleOrAliasVariant().variations[mctx.name] == targetVariationName {
1087			// Append the alias here so that it comes after any aliases created by AliasVariation.
1088			mctx.module.splitModules = append(mctx.module.splitModules, &moduleAlias{
1089				variant: newVariant,
1090				target:  variant.moduleOrAliasTarget(),
1091			})
1092			return
1093		}
1094	}
1095
1096	var foundVariations []string
1097	for _, variant := range mctx.newVariations {
1098		foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name])
1099	}
1100	panic(fmt.Errorf("no %q variation in module variations %q", targetVariationName, foundVariations))
1101}
1102
1103func (mctx *mutatorContext) applyTransition(transition Transition) {
1104	mctx.context.convertDepsToVariation(mctx.module, chooseDepByTransition(mctx.name, transition))
1105}
1106
1107func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
1108	mctx.context.convertDepsToVariation(mctx.module, chooseDepExplicit(
1109		mctx.name, variationName, nil))
1110}
1111
1112func (mctx *mutatorContext) SetDefaultDependencyVariation(variationName *string) {
1113	mctx.defaultVariation = variationName
1114}
1115
1116func (mctx *mutatorContext) Module() Module {
1117	return mctx.module.logicModule
1118}
1119
1120func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) []Module {
1121	depInfos := make([]Module, 0, len(deps))
1122	for _, dep := range deps {
1123		modInfo := mctx.context.moduleInfo[module]
1124		depInfo, errs := mctx.context.addDependency(modInfo, tag, dep)
1125		if len(errs) > 0 {
1126			mctx.errs = append(mctx.errs, errs...)
1127		}
1128		if !mctx.pause(depInfo) {
1129			// Pausing not supported by this mutator, new dependencies can't be returned.
1130			depInfo = nil
1131		}
1132		depInfos = append(depInfos, maybeLogicModule(depInfo))
1133	}
1134	return depInfos
1135}
1136
1137func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) {
1138	if _, ok := tag.(BaseDependencyTag); ok {
1139		panic("BaseDependencyTag is not allowed to be used directly!")
1140	}
1141
1142	destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName)
1143	if len(errs) > 0 {
1144		mctx.errs = append(mctx.errs, errs...)
1145		return
1146	}
1147
1148	mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{
1149		destModule,
1150		depInfo{mctx.context.moduleInfo[module], tag},
1151	})
1152}
1153
1154func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag,
1155	deps ...string) []Module {
1156
1157	depInfos := make([]Module, 0, len(deps))
1158	for _, dep := range deps {
1159		depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false)
1160		if len(errs) > 0 {
1161			mctx.errs = append(mctx.errs, errs...)
1162		}
1163		if !mctx.pause(depInfo) {
1164			// Pausing not supported by this mutator, new dependencies can't be returned.
1165			depInfo = nil
1166		}
1167		depInfos = append(depInfos, maybeLogicModule(depInfo))
1168	}
1169	return depInfos
1170}
1171
1172func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag,
1173	deps ...string) []Module {
1174
1175	depInfos := make([]Module, 0, len(deps))
1176	for _, dep := range deps {
1177		depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true)
1178		if len(errs) > 0 {
1179			mctx.errs = append(mctx.errs, errs...)
1180		}
1181		if !mctx.pause(depInfo) {
1182			// Pausing not supported by this mutator, new dependencies can't be returned.
1183			depInfo = nil
1184		}
1185		depInfos = append(depInfos, maybeLogicModule(depInfo))
1186	}
1187	return depInfos
1188}
1189
1190func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) {
1191	mctx.context.addInterVariantDependency(mctx.module, tag, from, to)
1192}
1193
1194func (mctx *mutatorContext) ReplaceDependencies(name string) {
1195	mctx.ReplaceDependenciesIf(name, nil)
1196}
1197
1198type ReplaceDependencyPredicate func(from Module, tag DependencyTag, to Module) bool
1199
1200func (mctx *mutatorContext) ReplaceDependenciesIf(name string, predicate ReplaceDependencyPredicate) {
1201	target := mctx.context.moduleMatchingVariant(mctx.module, name)
1202
1203	if target == nil {
1204		panic(fmt.Errorf("ReplaceDependencies could not find identical variant {%s} for module %s\n"+
1205			"available variants:\n  %s",
1206			mctx.context.prettyPrintVariant(mctx.module.variant.variations),
1207			name,
1208			mctx.context.prettyPrintGroupVariants(mctx.context.moduleGroupFromName(name, mctx.module.namespace()))))
1209	}
1210
1211	mctx.replace = append(mctx.replace, replace{target, mctx.module, predicate})
1212}
1213
1214func (mctx *mutatorContext) Rename(name string) {
1215	mctx.rename = append(mctx.rename, rename{mctx.module.group, name})
1216}
1217
1218func (mctx *mutatorContext) CreateModule(factory ModuleFactory, typeName string, props ...interface{}) Module {
1219	module := newModule(factory)
1220
1221	module.relBlueprintsFile = mctx.module.relBlueprintsFile
1222	module.pos = mctx.module.pos
1223	module.propertyPos = mctx.module.propertyPos
1224	module.createdBy = mctx.module
1225	module.typeName = typeName
1226
1227	for _, p := range props {
1228		err := proptools.AppendMatchingProperties(module.properties, p, nil)
1229		if err != nil {
1230			panic(err)
1231		}
1232	}
1233
1234	mctx.newModules = append(mctx.newModules, module)
1235
1236	return module.logicModule
1237}
1238
1239// pause waits until the given dependency has been visited by the mutator's parallelVisit call.
1240// It returns true if the pause was supported, false if the pause was not supported and did not
1241// occur, which will happen when the mutator is not parallelizable.  If the dependency is nil
1242// it returns true if pausing is supported or false if it is not.
1243func (mctx *mutatorContext) pause(dep *moduleInfo) bool {
1244	if mctx.pauseCh != nil {
1245		if dep != nil {
1246			unpause := make(unpause)
1247			mctx.pauseCh <- pauseSpec{
1248				paused:  mctx.module,
1249				until:   dep,
1250				unpause: unpause,
1251			}
1252			<-unpause
1253		}
1254		return true
1255	}
1256	return false
1257}
1258
1259// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property
1260// called "name".  Modules that embed it must also add SimpleName.Properties to their property
1261// structure list.
1262type SimpleName struct {
1263	Properties struct {
1264		Name string
1265	}
1266}
1267
1268func (s *SimpleName) Name() string {
1269	return s.Properties.Name
1270}
1271
1272// Load Hooks
1273
1274type LoadHookContext interface {
1275	EarlyModuleContext
1276
1277	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
1278	// the specified property structs to it as if the properties were set in a blueprint file.
1279	CreateModule(ModuleFactory, string, ...interface{}) Module
1280
1281	// RegisterScopedModuleType creates a new module type that is scoped to the current Blueprints
1282	// file.
1283	RegisterScopedModuleType(name string, factory ModuleFactory)
1284}
1285
1286func (l *loadHookContext) CreateModule(factory ModuleFactory, typeName string, props ...interface{}) Module {
1287	module := newModule(factory)
1288
1289	module.relBlueprintsFile = l.module.relBlueprintsFile
1290	module.pos = l.module.pos
1291	module.propertyPos = l.module.propertyPos
1292	module.createdBy = l.module
1293	module.typeName = typeName
1294
1295	for _, p := range props {
1296		err := proptools.AppendMatchingProperties(module.properties, p, nil)
1297		if err != nil {
1298			panic(err)
1299		}
1300	}
1301
1302	l.newModules = append(l.newModules, module)
1303
1304	return module.logicModule
1305}
1306
1307func (l *loadHookContext) RegisterScopedModuleType(name string, factory ModuleFactory) {
1308	if _, exists := l.context.moduleFactories[name]; exists {
1309		panic(fmt.Errorf("A global module type named %q already exists", name))
1310	}
1311
1312	if _, exists := (*l.scopedModuleFactories)[name]; exists {
1313		panic(fmt.Errorf("A module type named %q already exists in this scope", name))
1314	}
1315
1316	if *l.scopedModuleFactories == nil {
1317		*l.scopedModuleFactories = make(map[string]ModuleFactory)
1318	}
1319
1320	(*l.scopedModuleFactories)[name] = factory
1321}
1322
1323type loadHookContext struct {
1324	baseModuleContext
1325	newModules            []*moduleInfo
1326	scopedModuleFactories *map[string]ModuleFactory
1327}
1328
1329type LoadHook func(ctx LoadHookContext)
1330
1331// Load hooks need to be added by module factories, which don't have any parameter to get to the
1332// Context, and only produce a Module interface with no base implementation, so the load hooks
1333// must be stored in a global map.  The key is a pointer allocated by the module factory, so there
1334// is no chance of collisions even if tests are running in parallel with multiple contexts.  The
1335// contents should be short-lived, they are added during a module factory and removed immediately
1336// after the module factory returns.
1337var pendingHooks sync.Map
1338
1339func AddLoadHook(module Module, hook LoadHook) {
1340	// Only one goroutine can be processing a given module, so no additional locking is required
1341	// for the slice stored in the sync.Map.
1342	v, exists := pendingHooks.Load(module)
1343	if !exists {
1344		v, _ = pendingHooks.LoadOrStore(module, new([]LoadHook))
1345	}
1346	hooks := v.(*[]LoadHook)
1347	*hooks = append(*hooks, hook)
1348}
1349
1350func runAndRemoveLoadHooks(ctx *Context, config interface{}, module *moduleInfo,
1351	scopedModuleFactories *map[string]ModuleFactory) (newModules []*moduleInfo, deps []string, errs []error) {
1352
1353	if v, exists := pendingHooks.Load(module.logicModule); exists {
1354		hooks := v.(*[]LoadHook)
1355
1356		for _, hook := range *hooks {
1357			mctx := &loadHookContext{
1358				baseModuleContext: baseModuleContext{
1359					context: ctx,
1360					config:  config,
1361					module:  module,
1362				},
1363				scopedModuleFactories: scopedModuleFactories,
1364			}
1365			hook(mctx)
1366			newModules = append(newModules, mctx.newModules...)
1367			deps = append(deps, mctx.ninjaFileDeps...)
1368			errs = append(errs, mctx.errs...)
1369		}
1370		pendingHooks.Delete(module.logicModule)
1371
1372		return newModules, deps, errs
1373	}
1374
1375	return nil, nil, nil
1376}
1377
1378// Check the syntax of a generated blueprint file.
1379//
1380// This is intended to perform a quick syntactic check for generated blueprint
1381// code, where syntactically correct means:
1382// * No variable definitions.
1383// * Valid module types.
1384// * Valid property names.
1385// * Valid values for the property type.
1386//
1387// It does not perform any semantic checking of properties, existence of referenced
1388// files, or dependencies.
1389//
1390// At a low level it:
1391// * Parses the contents.
1392// * Invokes relevant factory to create Module instances.
1393// * Unpacks the properties into the Module.
1394// * Does not invoke load hooks or any mutators.
1395//
1396// The filename is only used for reporting errors.
1397func CheckBlueprintSyntax(moduleFactories map[string]ModuleFactory, filename string, contents string) []error {
1398	scope := parser.NewScope(nil)
1399	file, errs := parser.Parse(filename, strings.NewReader(contents), scope)
1400	if len(errs) != 0 {
1401		return errs
1402	}
1403
1404	for _, def := range file.Defs {
1405		switch def := def.(type) {
1406		case *parser.Module:
1407			_, moduleErrs := processModuleDef(def, filename, moduleFactories, nil, false)
1408			errs = append(errs, moduleErrs...)
1409
1410		default:
1411			panic(fmt.Errorf("unknown definition type: %T", def))
1412		}
1413	}
1414
1415	return errs
1416}
1417
1418func maybeLogicModule(module *moduleInfo) Module {
1419	if module != nil {
1420		return module.logicModule
1421	} else {
1422		return nil
1423	}
1424}
1425