• 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	"text/scanner"
21
22	"github.com/google/blueprint/pathtools"
23)
24
25// A Module handles generating all of the Ninja build actions needed to build a
26// single module based on properties defined in a Blueprints file.  Module
27// objects are initially created during the parse phase of a Context using one
28// of the registered module types (and the associated ModuleFactory function).
29// The Module's properties struct is automatically filled in with the property
30// values specified in the Blueprints file (see Context.RegisterModuleType for more
31// information on this).
32//
33// A Module can be split into multiple Modules by a Mutator.  All existing
34// properties set on the module will be duplicated to the new Module, and then
35// modified as necessary by the Mutator.
36//
37// The Module implementation can access the build configuration as well as any
38// modules on which on which it depends (as defined by the "deps" property
39// specified in the Blueprints file, dynamically added by implementing the
40// (deprecated) DynamicDependerModule interface, or dynamically added by a
41// BottomUpMutator) using the ModuleContext passed to GenerateBuildActions.
42// This ModuleContext is also used to create Ninja build actions and to report
43// errors to the user.
44//
45// In addition to implementing the GenerateBuildActions method, a Module should
46// implement methods that provide dependant modules and singletons information
47// they need to generate their build actions.  These methods will only be called
48// after GenerateBuildActions is called because the Context calls
49// GenerateBuildActions in dependency-order (and singletons are invoked after
50// all the Modules).  The set of methods a Module supports will determine how
51// dependant Modules interact with it.
52//
53// For example, consider a Module that is responsible for generating a library
54// that other modules can link against.  The library Module might implement the
55// following interface:
56//
57//   type LibraryProducer interface {
58//       LibraryFileName() string
59//   }
60//
61//   func IsLibraryProducer(module blueprint.Module) {
62//       _, ok := module.(LibraryProducer)
63//       return ok
64//   }
65//
66// A binary-producing Module that depends on the library Module could then do:
67//
68//   func (m *myBinaryModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
69//       ...
70//       var libraryFiles []string
71//       ctx.VisitDepsDepthFirstIf(IsLibraryProducer,
72//           func(module blueprint.Module) {
73//               libProducer := module.(LibraryProducer)
74//               libraryFiles = append(libraryFiles, libProducer.LibraryFileName())
75//           })
76//       ...
77//   }
78//
79// to build the list of library file names that should be included in its link
80// command.
81//
82// GenerateBuildActions may be called from multiple threads.  It is guaranteed to
83// be called after it has finished being called on all dependencies and on all
84// variants of that appear earlier in the ModuleContext.VisitAllModuleVariants list.
85// Any accesses to global variables or to Module objects that are not dependencies
86// or variants of the current Module must be synchronized by the implementation of
87// GenerateBuildActions.
88type Module interface {
89	// Name returns a string used to uniquely identify each module.  The return
90	// value must be unique across all modules.  It is only called once, during
91	// initial blueprint parsing.  To change the name later a mutator must call
92	// MutatorContext.Rename
93	//
94	// In most cases, Name should return the contents of a "name:" property from
95	// the blueprint file.  An embeddable SimpleName object can be used for this
96	// case.
97	Name() string
98
99	// GenerateBuildActions is called by the Context that created the Module
100	// during its generate phase.  This call should generate all Ninja build
101	// actions (rules, pools, and build statements) needed to build the module.
102	GenerateBuildActions(ModuleContext)
103}
104
105// A DynamicDependerModule is a Module that may add dependencies that do not
106// appear in its "deps" property.  Any Module that implements this interface
107// will have its DynamicDependencies method called by the Context that created
108// it during generate phase.
109//
110// Deprecated, use a BottomUpMutator instead
111type DynamicDependerModule interface {
112	Module
113
114	// DynamicDependencies is called by the Context that created the
115	// DynamicDependerModule during its generate phase.  This call should return
116	// the list of module names that the DynamicDependerModule depends on
117	// dynamically.  Module names that already appear in the "deps" property may
118	// but do not need to be included in the returned list.
119	DynamicDependencies(DynamicDependerModuleContext) []string
120}
121
122type BaseModuleContext interface {
123	ModuleName() string
124	ModuleDir() string
125	Config() interface{}
126
127	ContainsProperty(name string) bool
128	Errorf(pos scanner.Position, fmt string, args ...interface{})
129	ModuleErrorf(fmt string, args ...interface{})
130	PropertyErrorf(property, fmt string, args ...interface{})
131	Failed() bool
132
133	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
134	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
135	// builder whenever a file matching the pattern as added or removed, without rerunning if a
136	// file that does not match the pattern is added to a searched directory.
137	GlobWithDeps(pattern string, excludes []string) ([]string, error)
138
139	Fs() pathtools.FileSystem
140
141	moduleInfo() *moduleInfo
142	error(err error)
143}
144
145type DynamicDependerModuleContext BottomUpMutatorContext
146
147type ModuleContext interface {
148	BaseModuleContext
149
150	OtherModuleName(m Module) string
151	OtherModuleErrorf(m Module, fmt string, args ...interface{})
152	OtherModuleDependencyTag(m Module) DependencyTag
153
154	GetDirectDepWithTag(name string, tag DependencyTag) Module
155	GetDirectDep(name string) (Module, DependencyTag)
156
157	VisitDirectDeps(visit func(Module))
158	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
159	VisitDepsDepthFirst(visit func(Module))
160	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
161	WalkDeps(visit func(Module, Module) bool)
162
163	ModuleSubDir() string
164
165	Variable(pctx PackageContext, name, value string)
166	Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule
167	Build(pctx PackageContext, params BuildParams)
168
169	AddNinjaFileDeps(deps ...string)
170
171	PrimaryModule() Module
172	FinalModule() Module
173	VisitAllModuleVariants(visit func(Module))
174
175	GetMissingDependencies() []string
176}
177
178var _ BaseModuleContext = (*baseModuleContext)(nil)
179
180type baseModuleContext struct {
181	context        *Context
182	config         interface{}
183	module         *moduleInfo
184	errs           []error
185	visitingParent *moduleInfo
186	visitingDep    depInfo
187}
188
189func (d *baseModuleContext) moduleInfo() *moduleInfo {
190	return d.module
191}
192
193func (d *baseModuleContext) ModuleName() string {
194	return d.module.Name()
195}
196
197func (d *baseModuleContext) ContainsProperty(name string) bool {
198	_, ok := d.module.propertyPos[name]
199	return ok
200}
201
202func (d *baseModuleContext) ModuleDir() string {
203	return filepath.Dir(d.module.relBlueprintsFile)
204}
205
206func (d *baseModuleContext) Config() interface{} {
207	return d.config
208}
209
210func (d *baseModuleContext) error(err error) {
211	if err != nil {
212		d.errs = append(d.errs, err)
213	}
214}
215
216func (d *baseModuleContext) Errorf(pos scanner.Position,
217	format string, args ...interface{}) {
218
219	d.error(&BlueprintError{
220		Err: fmt.Errorf(format, args...),
221		Pos: pos,
222	})
223}
224
225func (d *baseModuleContext) ModuleErrorf(format string,
226	args ...interface{}) {
227
228	d.error(&ModuleError{
229		BlueprintError: BlueprintError{
230			Err: fmt.Errorf(format, args...),
231			Pos: d.module.pos,
232		},
233		module: d.module,
234	})
235}
236
237func (d *baseModuleContext) PropertyErrorf(property, format string,
238	args ...interface{}) {
239
240	pos := d.module.propertyPos[property]
241
242	if !pos.IsValid() {
243		pos = d.module.pos
244	}
245
246	d.error(&PropertyError{
247		ModuleError: ModuleError{
248			BlueprintError: BlueprintError{
249				Err: fmt.Errorf(format, args...),
250				Pos: pos,
251			},
252			module: d.module,
253		},
254		property: property,
255	})
256}
257
258func (d *baseModuleContext) Failed() bool {
259	return len(d.errs) > 0
260}
261
262func (d *baseModuleContext) GlobWithDeps(pattern string,
263	excludes []string) ([]string, error) {
264	return d.context.glob(pattern, excludes)
265}
266
267func (d *baseModuleContext) Fs() pathtools.FileSystem {
268	return d.context.fs
269}
270
271var _ ModuleContext = (*moduleContext)(nil)
272
273type moduleContext struct {
274	baseModuleContext
275	scope              *localScope
276	ninjaFileDeps      []string
277	actionDefs         localBuildActions
278	handledMissingDeps bool
279}
280
281func (m *baseModuleContext) OtherModuleName(logicModule Module) string {
282	module := m.context.moduleInfo[logicModule]
283	return module.Name()
284}
285
286func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string,
287	args ...interface{}) {
288
289	module := m.context.moduleInfo[logicModule]
290	m.errs = append(m.errs, &ModuleError{
291		BlueprintError: BlueprintError{
292			Err: fmt.Errorf(format, args...),
293			Pos: module.pos,
294		},
295		module: module,
296	})
297}
298
299func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag {
300	// fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps
301	if logicModule == m.visitingDep.module.logicModule {
302		return m.visitingDep.tag
303	}
304
305	for _, dep := range m.visitingParent.directDeps {
306		if dep.module.logicModule == logicModule {
307			return dep.tag
308		}
309	}
310
311	return nil
312}
313
314// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified
315// name, or nil if none exists.
316func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) {
317	for _, dep := range m.module.directDeps {
318		if dep.module.Name() == name {
319			return dep.module.logicModule, dep.tag
320		}
321	}
322
323	return nil, nil
324}
325
326// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
327// none exists.  It panics if the dependency does not have the specified tag.
328func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) Module {
329	for _, dep := range m.module.directDeps {
330		if dep.module.Name() == name {
331			if dep.tag != tag {
332				panic(fmt.Errorf("found dependency %q with tag %#v, expected tag %#v",
333					dep.module, dep.tag, tag))
334			}
335			return dep.module.logicModule
336		}
337	}
338
339	return nil
340}
341
342func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) {
343	defer func() {
344		if r := recover(); r != nil {
345			panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
346				m.module, funcName(visit), m.visitingDep.module))
347		}
348	}()
349
350	m.visitingParent = m.module
351
352	for _, dep := range m.module.directDeps {
353		m.visitingDep = dep
354		visit(dep.module.logicModule)
355	}
356
357	m.visitingParent = nil
358	m.visitingDep = depInfo{}
359}
360
361func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
362	defer func() {
363		if r := recover(); r != nil {
364			panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
365				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
366		}
367	}()
368
369	m.visitingParent = m.module
370
371	for _, dep := range m.module.directDeps {
372		m.visitingDep = dep
373		if pred(dep.module.logicModule) {
374			visit(dep.module.logicModule)
375		}
376	}
377
378	m.visitingParent = nil
379	m.visitingDep = depInfo{}
380}
381
382func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
383	defer func() {
384		if r := recover(); r != nil {
385			panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
386				m.module, funcName(visit), m.visitingDep.module))
387		}
388	}()
389
390	m.context.walkDeps(m.module, nil, func(dep depInfo, parent *moduleInfo) {
391		m.visitingParent = parent
392		m.visitingDep = dep
393		visit(dep.module.logicModule)
394	})
395
396	m.visitingParent = nil
397	m.visitingDep = depInfo{}
398}
399
400func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
401	visit func(Module)) {
402
403	defer func() {
404		if r := recover(); r != nil {
405			panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
406				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
407		}
408	}()
409
410	m.context.walkDeps(m.module, nil, func(dep depInfo, parent *moduleInfo) {
411		if pred(dep.module.logicModule) {
412			m.visitingParent = parent
413			m.visitingDep = dep
414			visit(dep.module.logicModule)
415		}
416	})
417
418	m.visitingParent = nil
419	m.visitingDep = depInfo{}
420}
421
422func (m *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
423	m.context.walkDeps(m.module, func(dep depInfo, parent *moduleInfo) bool {
424		m.visitingParent = parent
425		m.visitingDep = dep
426		return visit(dep.module.logicModule, parent.logicModule)
427	}, nil)
428
429	m.visitingParent = nil
430	m.visitingDep = depInfo{}
431}
432
433func (m *moduleContext) ModuleSubDir() string {
434	return m.module.variantName
435}
436
437func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
438	m.scope.ReparentTo(pctx)
439
440	v, err := m.scope.AddLocalVariable(name, value)
441	if err != nil {
442		panic(err)
443	}
444
445	m.actionDefs.variables = append(m.actionDefs.variables, v)
446}
447
448func (m *moduleContext) Rule(pctx PackageContext, name string,
449	params RuleParams, argNames ...string) Rule {
450
451	m.scope.ReparentTo(pctx)
452
453	r, err := m.scope.AddLocalRule(name, &params, argNames...)
454	if err != nil {
455		panic(err)
456	}
457
458	m.actionDefs.rules = append(m.actionDefs.rules, r)
459
460	return r
461}
462
463func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
464	m.scope.ReparentTo(pctx)
465
466	def, err := parseBuildParams(m.scope, &params)
467	if err != nil {
468		panic(err)
469	}
470
471	m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
472}
473
474func (m *moduleContext) AddNinjaFileDeps(deps ...string) {
475	m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
476}
477
478func (m *moduleContext) PrimaryModule() Module {
479	return m.module.group.modules[0].logicModule
480}
481
482func (m *moduleContext) FinalModule() Module {
483	return m.module.group.modules[len(m.module.group.modules)-1].logicModule
484}
485
486func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
487	m.context.visitAllModuleVariants(m.module, visit)
488}
489
490func (m *moduleContext) GetMissingDependencies() []string {
491	m.handledMissingDeps = true
492	return m.module.missingDeps
493}
494
495//
496// MutatorContext
497//
498
499type mutatorContext struct {
500	baseModuleContext
501	name        string
502	reverseDeps []reverseDep
503	rename      []rename
504	replace     []replace
505	newModules  []*moduleInfo
506}
507
508type baseMutatorContext interface {
509	BaseModuleContext
510
511	OtherModuleExists(name string) bool
512	Rename(name string)
513	Module() Module
514}
515
516type EarlyMutatorContext interface {
517	baseMutatorContext
518
519	CreateVariations(...string) []Module
520	CreateLocalVariations(...string) []Module
521}
522
523type TopDownMutatorContext interface {
524	baseMutatorContext
525
526	OtherModuleName(m Module) string
527	OtherModuleErrorf(m Module, fmt string, args ...interface{})
528	OtherModuleDependencyTag(m Module) DependencyTag
529
530	GetDirectDepWithTag(name string, tag DependencyTag) Module
531	GetDirectDep(name string) (Module, DependencyTag)
532
533	VisitDirectDeps(visit func(Module))
534	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
535	VisitDepsDepthFirst(visit func(Module))
536	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
537	WalkDeps(visit func(Module, Module) bool)
538}
539
540type BottomUpMutatorContext interface {
541	baseMutatorContext
542
543	AddDependency(module Module, tag DependencyTag, name ...string)
544	AddReverseDependency(module Module, tag DependencyTag, name string)
545	CreateVariations(...string) []Module
546	CreateLocalVariations(...string) []Module
547	SetDependencyVariation(string)
548	AddVariationDependencies([]Variation, DependencyTag, ...string)
549	AddFarVariationDependencies([]Variation, DependencyTag, ...string)
550	AddInterVariantDependency(tag DependencyTag, from, to Module)
551	ReplaceDependencies(string)
552}
553
554// A Mutator function is called for each Module, and can use
555// MutatorContext.CreateVariations to split a Module into multiple Modules,
556// modifying properties on the new modules to differentiate them.  It is called
557// after parsing all Blueprint files, but before generating any build rules,
558// and is always called on dependencies before being called on the depending module.
559//
560// The Mutator function should only modify members of properties structs, and not
561// members of the module struct itself, to ensure the modified values are copied
562// if a second Mutator chooses to split the module a second time.
563type TopDownMutator func(mctx TopDownMutatorContext)
564type BottomUpMutator func(mctx BottomUpMutatorContext)
565type EarlyMutator func(mctx EarlyMutatorContext)
566
567// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag.  It can be
568// used to transfer information on a dependency between the mutator that called AddDependency
569// and the GenerateBuildActions method.  Variants created by CreateVariations have a copy of the
570// interface (pointing to the same concrete object) from their original module.
571type DependencyTag interface {
572	dependencyTag(DependencyTag)
573}
574
575type BaseDependencyTag struct {
576}
577
578func (BaseDependencyTag) dependencyTag(DependencyTag) {
579}
580
581var _ DependencyTag = BaseDependencyTag{}
582
583// Split a module into mulitple variants, one for each name in the variationNames
584// parameter.  It returns a list of new modules in the same order as the variationNames
585// list.
586//
587// If any of the dependencies of the module being operated on were already split
588// by calling CreateVariations with the same name, the dependency will automatically
589// be updated to point the matching variant.
590//
591// If a module is split, and then a module depending on the first module is not split
592// when the Mutator is later called on it, the dependency of the depending module will
593// automatically be updated to point to the first variant.
594func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module {
595	return mctx.createVariations(variationNames, false)
596}
597
598// Split a module into mulitple variants, one for each name in the variantNames
599// parameter.  It returns a list of new modules in the same order as the variantNames
600// list.
601//
602// Local variations do not affect automatic dependency resolution - dependencies added
603// to the split module via deps or DynamicDependerModule must exactly match a variant
604// that contains all the non-local variations.
605func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
606	return mctx.createVariations(variationNames, true)
607}
608
609func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module {
610	ret := []Module{}
611	modules, errs := mctx.context.createVariations(mctx.module, mctx.name, variationNames)
612	if len(errs) > 0 {
613		mctx.errs = append(mctx.errs, errs...)
614	}
615
616	for i, module := range modules {
617		ret = append(ret, module.logicModule)
618		if !local {
619			module.dependencyVariant[mctx.name] = variationNames[i]
620		}
621	}
622
623	if mctx.newModules != nil {
624		panic("module already has variations from this mutator")
625	}
626	mctx.newModules = modules
627
628	if len(ret) != len(variationNames) {
629		panic("oops!")
630	}
631
632	return ret
633}
634
635// Set all dangling dependencies on the current module to point to the variation
636// with given name.
637func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
638	mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName)
639}
640
641func (mctx *mutatorContext) Module() Module {
642	return mctx.module.logicModule
643}
644
645// Add a dependency to the given module.
646// Does not affect the ordering of the current mutator pass, but will be ordered
647// correctly for all future mutator passes.
648func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) {
649	for _, dep := range deps {
650		errs := mctx.context.addDependency(mctx.context.moduleInfo[module], tag, dep)
651		if len(errs) > 0 {
652			mctx.errs = append(mctx.errs, errs...)
653		}
654	}
655}
656
657// Add a dependency from the destination to the given module.
658// Does not affect the ordering of the current mutator pass, but will be ordered
659// correctly for all future mutator passes.  All reverse dependencies for a destination module are
660// collected until the end of the mutator pass, sorted by name, and then appended to the destination
661// module's dependency list.
662func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) {
663	if _, ok := tag.(BaseDependencyTag); ok {
664		panic("BaseDependencyTag is not allowed to be used directly!")
665	}
666
667	destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName)
668	if len(errs) > 0 {
669		mctx.errs = append(mctx.errs, errs...)
670		return
671	}
672
673	mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{
674		destModule,
675		depInfo{mctx.context.moduleInfo[module], tag},
676	})
677}
678
679// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
680// argument to select which variant of the dependency to use.  A variant of the dependency must
681// exist that matches the all of the non-local variations of the current module, plus the variations
682// argument.
683func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag,
684	deps ...string) {
685
686	for _, dep := range deps {
687		errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false)
688		if len(errs) > 0 {
689			mctx.errs = append(mctx.errs, errs...)
690		}
691	}
692}
693
694// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
695// variations argument to select which variant of the dependency to use.  A variant of the
696// dependency must exist that matches the variations argument, but may also have other variations.
697// For any unspecified variation the first variant will be used.
698//
699// Unlike AddVariationDependencies, the variations of the current module are ignored - the
700// depdendency only needs to match the supplied variations.
701func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag,
702	deps ...string) {
703
704	for _, dep := range deps {
705		errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true)
706		if len(errs) > 0 {
707			mctx.errs = append(mctx.errs, errs...)
708		}
709	}
710}
711
712func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) {
713	mctx.context.addInterVariantDependency(mctx.module, tag, from, to)
714}
715
716// ReplaceDependencies replaces all dependencies on the identical variant of the module with the
717// specified name with the current variant of this module.  Replacements don't take effect until
718// after the mutator pass is finished.
719func (mctx *mutatorContext) ReplaceDependencies(name string) {
720	target := mctx.context.moduleMatchingVariant(mctx.module, name)
721
722	if target == nil {
723		panic(fmt.Errorf("ReplaceDependencies could not find identical variant %q for module %q",
724			mctx.module.variantName, name))
725	}
726
727	mctx.replace = append(mctx.replace, replace{target, mctx.module})
728}
729
730func (mctx *mutatorContext) OtherModuleExists(name string) bool {
731	return mctx.context.moduleNames[name] != nil
732}
733
734// Rename all variants of a module.  The new name is not visible to calls to ModuleName,
735// AddDependency or OtherModuleName until after this mutator pass is complete.
736func (mctx *mutatorContext) Rename(name string) {
737	mctx.rename = append(mctx.rename, rename{mctx.module.group, name})
738}
739
740// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property
741// called "name".  Modules that embed it must also add SimpleName.Properties to their property
742// structure list.
743type SimpleName struct {
744	Properties struct {
745		Name string
746	}
747}
748
749func (s *SimpleName) Name() string {
750	return s.Properties.Name
751}
752