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, ¶ms, 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, ¶ms) 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