1// Copyright 2015 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 android 16 17import ( 18 "fmt" 19 "regexp" 20 "strings" 21 22 "github.com/google/blueprint" 23 "github.com/google/blueprint/proptools" 24) 25 26// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns 27// a Config instead of an interface{}, and some methods have been wrapped to use an android.Module 28// instead of a blueprint.Module, plus some extra methods that return Android-specific information 29// about the current module. 30type BaseModuleContext interface { 31 ArchModuleContext 32 EarlyModuleContext 33 34 blueprintBaseModuleContext() blueprint.BaseModuleContext 35 36 // OtherModuleName returns the name of another Module. See BaseModuleContext.ModuleName for more information. 37 // It is intended for use inside the visit functions of Visit* and WalkDeps. 38 OtherModuleName(m blueprint.Module) string 39 40 // OtherModuleDir returns the directory of another Module. See BaseModuleContext.ModuleDir for more information. 41 // It is intended for use inside the visit functions of Visit* and WalkDeps. 42 OtherModuleDir(m blueprint.Module) string 43 44 // OtherModuleErrorf reports an error on another Module. See BaseModuleContext.ModuleErrorf for more information. 45 // It is intended for use inside the visit functions of Visit* and WalkDeps. 46 OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) 47 48 // OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency 49 // on the module. When called inside a Visit* method with current module being visited, and there are multiple 50 // dependencies on the module being visited, it returns the dependency tag used for the current dependency. 51 OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag 52 53 // OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface 54 // passed to Context.SetNameInterface, or SimpleNameInterface if it was not called. 55 OtherModuleExists(name string) bool 56 57 // OtherModuleDependencyVariantExists returns true if a module with the 58 // specified name and variant exists. The variant must match the given 59 // variations. It must also match all the non-local variations of the current 60 // module. In other words, it checks for the module that AddVariationDependencies 61 // would add a dependency on with the same arguments. 62 OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool 63 64 // OtherModuleFarDependencyVariantExists returns true if a module with the 65 // specified name and variant exists. The variant must match the given 66 // variations, but not the non-local variations of the current module. In 67 // other words, it checks for the module that AddFarVariationDependencies 68 // would add a dependency on with the same arguments. 69 OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool 70 71 // OtherModuleReverseDependencyVariantExists returns true if a module with the 72 // specified name exists with the same variations as the current module. In 73 // other words, it checks for the module that AddReverseDependency would add a 74 // dependency on with the same argument. 75 OtherModuleReverseDependencyVariantExists(name string) bool 76 77 // OtherModuleType returns the type of another Module. See BaseModuleContext.ModuleType for more information. 78 // It is intended for use inside the visit functions of Visit* and WalkDeps. 79 OtherModuleType(m blueprint.Module) string 80 81 // otherModuleProvider returns the value for a provider for the given module. If the value is 82 // not set it returns nil and false. The value returned may be a deep copy of the value originally 83 // passed to SetProvider. 84 // 85 // This method shouldn't be used directly, prefer the type-safe android.OtherModuleProvider instead. 86 otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) 87 88 // Provider returns the value for a provider for the current module. If the value is 89 // not set it returns nil and false. It panics if called before the appropriate 90 // mutator or GenerateBuildActions pass for the provider. The value returned may be a deep 91 // copy of the value originally passed to SetProvider. 92 // 93 // This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead. 94 provider(provider blueprint.AnyProviderKey) (any, bool) 95 96 // setProvider sets the value for a provider for the current module. It panics if not called 97 // during the appropriate mutator or GenerateBuildActions pass for the provider, if the value 98 // is not of the appropriate type, or if the value has already been set. The value should not 99 // be modified after being passed to SetProvider. 100 // 101 // This method shouldn't be used directly, prefer the type-safe android.SetProvider instead. 102 setProvider(provider blueprint.AnyProviderKey, value any) 103 104 GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module 105 106 // GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if 107 // none exists. It panics if the dependency does not have the specified tag. It skips any 108 // dependencies that are not an android.Module. 109 GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module 110 111 // GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified 112 // name, or nil if none exists. If there are multiple dependencies on the same module it returns 113 // the first DependencyTag. 114 GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) 115 116 // VisitDirectDepsBlueprint calls visit for each direct dependency. If there are multiple 117 // direct dependencies on the same module visit will be called multiple times on that module 118 // and OtherModuleDependencyTag will return a different tag for each. 119 // 120 // The Module passed to the visit function should not be retained outside of the visit 121 // function, it may be invalidated by future mutators. 122 VisitDirectDepsBlueprint(visit func(blueprint.Module)) 123 124 // VisitDirectDepsIgnoreBlueprint calls visit for each direct dependency. If there are multiple 125 // direct dependencies on the same module visit will be called multiple times on that module 126 // and OtherModuleDependencyTag will return a different tag for each. It silently ignores any 127 // dependencies that are not an android.Module. 128 // 129 // The Module passed to the visit function should not be retained outside of the visit 130 // function, it may be invalidated by future mutators. 131 VisitDirectDepsIgnoreBlueprint(visit func(Module)) 132 133 // VisitDirectDeps calls visit for each direct dependency. If there are multiple 134 // direct dependencies on the same module visit will be called multiple times on that module 135 // and OtherModuleDependencyTag will return a different tag for each. It raises an error if any of the 136 // dependencies are not an android.Module. 137 // 138 // The Module passed to the visit function should not be retained outside of the visit 139 // function, it may be invalidated by future mutators. 140 VisitDirectDeps(visit func(Module)) 141 142 VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) 143 144 // VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit. If there are 145 // multiple direct dependencies on the same module pred and visit will be called multiple times on that module and 146 // OtherModuleDependencyTag will return a different tag for each. It skips any 147 // dependencies that are not an android.Module. 148 // 149 // The Module passed to the visit function should not be retained outside of the visit function, it may be 150 // invalidated by future mutators. 151 VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) 152 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 153 VisitDepsDepthFirst(visit func(Module)) 154 // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module 155 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) 156 157 // WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may 158 // be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the 159 // child and parent with different tags. OtherModuleDependencyTag will return the tag for the currently visited 160 // (child, parent) pair. If visit returns false WalkDeps will not continue recursing down to child. It skips 161 // any dependencies that are not an android.Module. 162 // 163 // The Modules passed to the visit function should not be retained outside of the visit function, they may be 164 // invalidated by future mutators. 165 WalkDeps(visit func(child, parent Module) bool) 166 167 // WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency 168 // tree in top down order. visit may be called multiple times for the same (child, parent) 169 // pair if there are multiple direct dependencies between the child and parent with different 170 // tags. OtherModuleDependencyTag will return the tag for the currently visited 171 // (child, parent) pair. If visit returns false WalkDeps will not continue recursing down 172 // to child. 173 // 174 // The Modules passed to the visit function should not be retained outside of the visit function, they may be 175 // invalidated by future mutators. 176 WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) 177 178 // GetWalkPath is supposed to be called in visit function passed in WalkDeps() 179 // and returns a top-down dependency path from a start module to current child module. 180 GetWalkPath() []Module 181 182 // PrimaryModule returns the first variant of the current module. Variants of a module are always visited in 183 // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the 184 // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are 185 // only done once for all variants of a module. 186 PrimaryModule() Module 187 188 // FinalModule returns the last variant of the current module. Variants of a module are always visited in 189 // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all 190 // variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform 191 // singleton actions that are only done once for all variants of a module. 192 FinalModule() Module 193 194 // VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always 195 // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read 196 // from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any 197 // data modified by the current mutator. 198 VisitAllModuleVariants(visit func(Module)) 199 200 // GetTagPath is supposed to be called in visit function passed in WalkDeps() 201 // and returns a top-down dependency tags path from a start module to current child module. 202 // It has one less entry than GetWalkPath() as it contains the dependency tags that 203 // exist between each adjacent pair of modules in the GetWalkPath(). 204 // GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1] 205 GetTagPath() []blueprint.DependencyTag 206 207 // GetPathString is supposed to be called in visit function passed in WalkDeps() 208 // and returns a multi-line string showing the modules and dependency tags 209 // among them along the top-down dependency path from a start module to current child module. 210 // skipFirst when set to true, the output doesn't include the start module, 211 // which is already printed when this function is used along with ModuleErrorf(). 212 GetPathString(skipFirst bool) string 213 214 AddMissingDependencies(missingDeps []string) 215 216 // getMissingDependencies returns the list of missing dependencies. 217 // Calling this function prevents adding new dependencies. 218 getMissingDependencies() []string 219 220 // EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context 221 // can be used to evaluate the final value of Configurable properties. 222 EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue 223} 224 225type baseModuleContext struct { 226 bp blueprint.BaseModuleContext 227 earlyModuleContext 228 archModuleContext 229 230 walkPath []Module 231 tagPath []blueprint.DependencyTag 232 233 strictVisitDeps bool // If true, enforce that all dependencies are enabled 234 235} 236 237func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string { 238 return b.bp.OtherModuleName(m) 239} 240func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) } 241func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) { 242 b.bp.OtherModuleErrorf(m, fmt, args...) 243} 244func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag { 245 return b.bp.OtherModuleDependencyTag(m) 246} 247func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) } 248func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool { 249 return b.bp.OtherModuleDependencyVariantExists(variations, name) 250} 251func (b *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool { 252 return b.bp.OtherModuleFarDependencyVariantExists(variations, name) 253} 254func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool { 255 return b.bp.OtherModuleReverseDependencyVariantExists(name) 256} 257func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { 258 return b.bp.OtherModuleType(m) 259} 260 261func (b *baseModuleContext) otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { 262 return b.bp.OtherModuleProvider(m, provider) 263} 264 265func (b *baseModuleContext) provider(provider blueprint.AnyProviderKey) (any, bool) { 266 return b.bp.Provider(provider) 267} 268 269func (b *baseModuleContext) setProvider(provider blueprint.AnyProviderKey, value any) { 270 b.bp.SetProvider(provider, value) 271} 272 273func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module { 274 return b.bp.GetDirectDepWithTag(name, tag) 275} 276 277func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext { 278 return b.bp 279} 280 281func (b *baseModuleContext) AddMissingDependencies(deps []string) { 282 if deps != nil { 283 missingDeps := &b.Module().base().commonProperties.MissingDeps 284 *missingDeps = append(*missingDeps, deps...) 285 *missingDeps = FirstUniqueStrings(*missingDeps) 286 } 287} 288 289func (b *baseModuleContext) checkedMissingDeps() bool { 290 return b.Module().base().commonProperties.CheckedMissingDeps 291} 292 293func (b *baseModuleContext) getMissingDependencies() []string { 294 checked := &b.Module().base().commonProperties.CheckedMissingDeps 295 *checked = true 296 var missingDeps []string 297 missingDeps = append(missingDeps, b.Module().base().commonProperties.MissingDeps...) 298 missingDeps = append(missingDeps, b.bp.EarlyGetMissingDependencies()...) 299 missingDeps = FirstUniqueStrings(missingDeps) 300 return missingDeps 301} 302 303type AllowDisabledModuleDependency interface { 304 blueprint.DependencyTag 305 AllowDisabledModuleDependency(target Module) bool 306} 307 308type AlwaysAllowDisabledModuleDependencyTag struct{} 309 310func (t AlwaysAllowDisabledModuleDependencyTag) AllowDisabledModuleDependency(Module) bool { 311 return true 312} 313 314func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool, ignoreBlueprint bool) Module { 315 aModule, _ := module.(Module) 316 317 if !strict { 318 return aModule 319 } 320 321 if aModule == nil { 322 if !ignoreBlueprint { 323 b.ModuleErrorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag) 324 } 325 return nil 326 } 327 328 if !aModule.Enabled(b) { 329 if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) { 330 if b.Config().AllowMissingDependencies() { 331 b.AddMissingDependencies([]string{b.OtherModuleName(aModule)}) 332 } else { 333 b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule)) 334 } 335 } 336 return nil 337 } 338 return aModule 339} 340 341type dep struct { 342 mod blueprint.Module 343 tag blueprint.DependencyTag 344} 345 346func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep { 347 var deps []dep 348 b.VisitDirectDepsBlueprint(func(module blueprint.Module) { 349 if aModule, _ := module.(Module); aModule != nil { 350 if aModule.base().BaseModuleName() == name { 351 returnedTag := b.bp.OtherModuleDependencyTag(aModule) 352 if tag == nil || returnedTag == tag { 353 deps = append(deps, dep{aModule, returnedTag}) 354 } 355 } 356 } else if b.bp.OtherModuleName(module) == name { 357 returnedTag := b.bp.OtherModuleDependencyTag(module) 358 if tag == nil || returnedTag == tag { 359 deps = append(deps, dep{module, returnedTag}) 360 } 361 } 362 }) 363 return deps 364} 365 366func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) { 367 deps := b.getDirectDepsInternal(name, tag) 368 if len(deps) == 1 { 369 return deps[0].mod, deps[0].tag 370 } else if len(deps) >= 2 { 371 panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", 372 name, b.ModuleName())) 373 } else { 374 return nil, nil 375 } 376} 377 378func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) { 379 foundDeps := b.getDirectDepsInternal(name, nil) 380 deps := map[blueprint.Module]bool{} 381 for _, dep := range foundDeps { 382 deps[dep.mod] = true 383 } 384 if len(deps) == 1 { 385 return foundDeps[0].mod, foundDeps[0].tag 386 } else if len(deps) >= 2 { 387 // this could happen if two dependencies have the same name in different namespaces 388 // TODO(b/186554727): this should not occur if namespaces are handled within 389 // getDirectDepsInternal. 390 panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", 391 name, b.ModuleName())) 392 } else { 393 return nil, nil 394 } 395} 396 397func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module { 398 var deps []Module 399 b.VisitDirectDepsBlueprint(func(module blueprint.Module) { 400 if aModule, _ := module.(Module); aModule != nil { 401 if b.bp.OtherModuleDependencyTag(aModule) == tag { 402 deps = append(deps, aModule) 403 } 404 } 405 }) 406 return deps 407} 408 409// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified 410// name, or nil if none exists. If there are multiple dependencies on the same module it returns the 411// first DependencyTag. 412func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) { 413 return b.getDirectDepFirstTag(name) 414} 415 416func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) { 417 b.bp.VisitDirectDeps(visit) 418} 419 420func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) { 421 b.visitDirectDeps(visit, false) 422} 423 424func (b *baseModuleContext) VisitDirectDepsIgnoreBlueprint(visit func(Module)) { 425 b.visitDirectDeps(visit, true) 426} 427 428func (b *baseModuleContext) visitDirectDeps(visit func(Module), ignoreBlueprint bool) { 429 b.bp.VisitDirectDeps(func(module blueprint.Module) { 430 if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, ignoreBlueprint); aModule != nil { 431 visit(aModule) 432 } 433 }) 434} 435 436func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) { 437 b.bp.VisitDirectDeps(func(module blueprint.Module) { 438 if b.bp.OtherModuleDependencyTag(module) == tag { 439 if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil { 440 visit(aModule) 441 } 442 } 443 }) 444} 445 446func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { 447 b.bp.VisitDirectDepsIf( 448 // pred 449 func(module blueprint.Module) bool { 450 if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil { 451 return pred(aModule) 452 } else { 453 return false 454 } 455 }, 456 // visit 457 func(module blueprint.Module) { 458 visit(module.(Module)) 459 }) 460} 461 462func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { 463 b.bp.VisitDepsDepthFirst(func(module blueprint.Module) { 464 if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil { 465 visit(aModule) 466 } 467 }) 468} 469 470func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) { 471 b.bp.VisitDepsDepthFirstIf( 472 // pred 473 func(module blueprint.Module) bool { 474 if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil { 475 return pred(aModule) 476 } else { 477 return false 478 } 479 }, 480 // visit 481 func(module blueprint.Module) { 482 visit(module.(Module)) 483 }) 484} 485 486func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) { 487 b.bp.WalkDeps(visit) 488} 489 490func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) { 491 b.walkPath = []Module{b.Module()} 492 b.tagPath = []blueprint.DependencyTag{} 493 b.bp.WalkDeps(func(child, parent blueprint.Module) bool { 494 childAndroidModule, _ := child.(Module) 495 parentAndroidModule, _ := parent.(Module) 496 if childAndroidModule != nil && parentAndroidModule != nil { 497 // record walkPath before visit 498 for b.walkPath[len(b.walkPath)-1] != parentAndroidModule { 499 b.walkPath = b.walkPath[0 : len(b.walkPath)-1] 500 b.tagPath = b.tagPath[0 : len(b.tagPath)-1] 501 } 502 b.walkPath = append(b.walkPath, childAndroidModule) 503 b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule)) 504 return visit(childAndroidModule, parentAndroidModule) 505 } else { 506 return false 507 } 508 }) 509} 510 511func (b *baseModuleContext) GetWalkPath() []Module { 512 return b.walkPath 513} 514 515func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { 516 return b.tagPath 517} 518 519func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) { 520 b.bp.VisitAllModuleVariants(func(module blueprint.Module) { 521 visit(module.(Module)) 522 }) 523} 524 525func (b *baseModuleContext) PrimaryModule() Module { 526 return b.bp.PrimaryModule().(Module) 527} 528 529func (b *baseModuleContext) FinalModule() Module { 530 return b.bp.FinalModule().(Module) 531} 532 533// IsMetaDependencyTag returns true for cross-cutting metadata dependencies. 534func IsMetaDependencyTag(tag blueprint.DependencyTag) bool { 535 if tag == licenseKindTag { 536 return true 537 } else if tag == licensesTag { 538 return true 539 } else if tag == AcDepTag { 540 return true 541 } 542 return false 543} 544 545// A regexp for removing boilerplate from BaseDependencyTag from the string representation of 546// a dependency tag. 547var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`) 548 549// PrettyPrintTag returns string representation of the tag, but prefers 550// custom String() method if available. 551func PrettyPrintTag(tag blueprint.DependencyTag) string { 552 // Use tag's custom String() method if available. 553 if stringer, ok := tag.(fmt.Stringer); ok { 554 return stringer.String() 555 } 556 557 // Otherwise, get a default string representation of the tag's struct. 558 tagString := fmt.Sprintf("%T: %+v", tag, tag) 559 560 // Remove the boilerplate from BaseDependencyTag as it adds no value. 561 tagString = tagCleaner.ReplaceAllString(tagString, "") 562 return tagString 563} 564 565func (b *baseModuleContext) GetPathString(skipFirst bool) string { 566 sb := strings.Builder{} 567 tagPath := b.GetTagPath() 568 walkPath := b.GetWalkPath() 569 if !skipFirst { 570 sb.WriteString(walkPath[0].String()) 571 } 572 for i, m := range walkPath[1:] { 573 sb.WriteString("\n") 574 sb.WriteString(fmt.Sprintf(" via tag %s\n", PrettyPrintTag(tagPath[i]))) 575 sb.WriteString(fmt.Sprintf(" -> %s", m.String())) 576 } 577 return sb.String() 578} 579 580func (m *baseModuleContext) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue { 581 return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(condition, property) 582} 583