From 818af3bfe0b42adada3a5cc00b49639e5991d170 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 25 Mar 2019 15:04:09 -0700 Subject: [PATCH 1/4] Fix panic message in SingletonContext.VisitAllModules The panic should be printing the module info string from the moduleInfo, not trying to Stringify the Module interface. Test: manual Change-Id: I1a2b7c15c4216518c76b909b25d50ac2eb7d1baa --- singleton_ctx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singleton_ctx.go b/singleton_ctx.go index 5ca8ee6..de5bae7 100644 --- a/singleton_ctx.go +++ b/singleton_ctx.go @@ -223,7 +223,7 @@ func (s *singletonContext) VisitAllModules(visit func(Module)) { defer func() { if r := recover(); r != nil { panic(newPanicErrorf(r, "VisitAllModules(%s) for module %s", - funcName(visit), visitingModule)) + funcName(visit), s.context.moduleInfo[visitingModule])) } }() From 99bdb2ab4fd5168a71a20aecf10611425be47ec4 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 29 Mar 2019 16:35:02 -0700 Subject: [PATCH 2/4] Consolidate mutator contexts Move most of the mutator context methods into BaseModuleContext so they are available to both top down and bottom up mutators. Only CreateModule is unique to TopDownMutatorContext, and the dependency and variation adding methods are unique to the BottomUpMutatorContext. The dependency visiting methods are now available on BottomUpMutatorContext, which requires delaying making newly added dependencies visible to maintain the invariant that the mutator has been called on the dependency before the dependency can be visited by its parents. Test: m checkbuild Change-Id: Ie14afc02ac76d0b5a66b0e52de2aa9e17fd1bec0 --- context.go | 16 ++++++++---- module_ctx.go | 70 +++++++++++++++++++++------------------------------ 2 files changed, 40 insertions(+), 46 deletions(-) diff --git a/context.go b/context.go index 324d1ec..dcfda83 100644 --- a/context.go +++ b/context.go @@ -183,12 +183,13 @@ type moduleInfo struct { properties []interface{} // set during ResolveDependencies - directDeps []depInfo - missingDeps []string + missingDeps []string + newDirectDeps []depInfo // set during updateDependencies reverseDeps []*moduleInfo forwardDeps []*moduleInfo + directDeps []depInfo // used by parallelVisitAllBottomUp waitingCount int @@ -1427,7 +1428,7 @@ func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName s } if m := c.findMatchingVariant(module, possibleDeps); m != nil { - module.directDeps = append(module.directDeps, depInfo{m, tag}) + module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag}) atomic.AddUint32(&c.depsModified, 1) return nil } @@ -1530,7 +1531,7 @@ func (c *Context) addVariationDependency(module *moduleInfo, variations []Variat Pos: module.pos, }} } - module.directDeps = append(module.directDeps, depInfo{m, tag}) + module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag}) atomic.AddUint32(&c.depsModified, 1) return nil } @@ -1575,7 +1576,7 @@ func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag Dependen origModule.Name())) } - fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag}) + fromInfo.newDirectDeps = append(fromInfo.newDirectDeps, depInfo{toInfo, tag}) atomic.AddUint32(&c.depsModified, 1) } @@ -2149,9 +2150,14 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo, module.directDeps[j].module = dep.module.splitModules[0] } } + + // Add in any new direct dependencies that were added by the mutator + module.directDeps = append(module.directDeps, module.newDirectDeps...) + module.newDirectDeps = nil } } + // Add in any new reverse dependencies that were added by the mutator for module, deps := range reverseDeps { sort.Sort(depSorter(deps)) module.directDeps = append(module.directDeps, deps...) diff --git a/module_ctx.go b/module_ctx.go index d127c0e..b3db1c3 100644 --- a/module_ctx.go +++ b/module_ctx.go @@ -121,6 +121,7 @@ type DynamicDependerModule interface { } type BaseModuleContext interface { + Module() Module ModuleName() string ModuleDir() string ModuleType() string @@ -147,19 +148,6 @@ type BaseModuleContext interface { error(err error) Namespace() Namespace -} - -type DynamicDependerModuleContext BottomUpMutatorContext - -type ModuleContext interface { - BaseModuleContext - - OtherModuleName(m Module) string - OtherModuleDir(m Module) string - OtherModuleSubDir(m Module) string - OtherModuleType(m Module) string - OtherModuleErrorf(m Module, fmt string, args ...interface{}) - OtherModuleDependencyTag(m Module) DependencyTag GetDirectDepWithTag(name string, tag DependencyTag) Module GetDirectDep(name string) (Module, DependencyTag) @@ -168,7 +156,21 @@ type ModuleContext interface { VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) VisitDepsDepthFirst(visit func(Module)) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) - WalkDeps(visit func(child, parent Module) bool) + WalkDeps(visit func(Module, Module) bool) + + OtherModuleName(m Module) string + OtherModuleDir(m Module) string + OtherModuleSubDir(m Module) string + OtherModuleType(m Module) string + OtherModuleErrorf(m Module, fmt string, args ...interface{}) + OtherModuleDependencyTag(m Module) DependencyTag + OtherModuleExists(name string) bool +} + +type DynamicDependerModuleContext BottomUpMutatorContext + +type ModuleContext interface { + BaseModuleContext ModuleSubDir() string @@ -199,6 +201,10 @@ func (d *baseModuleContext) moduleInfo() *moduleInfo { return d.module } +func (d *baseModuleContext) Module() Module { + return d.module.logicModule +} + func (d *baseModuleContext) ModuleName() string { return d.module.Name() } @@ -345,6 +351,11 @@ func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) Depende return nil } +func (m *baseModuleContext) OtherModuleExists(name string) bool { + _, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace()) + return exists +} + // GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified // name, or nil if none exists. If there are multiple dependencies on the same module it returns // the first DependencyTag. @@ -563,45 +574,27 @@ type mutatorContext struct { newModules []*moduleInfo // brand new modules } -type baseMutatorContext interface { +type BaseMutatorContext interface { BaseModuleContext - OtherModuleExists(name string) bool Rename(name string) - Module() Module } type EarlyMutatorContext interface { - baseMutatorContext + BaseMutatorContext CreateVariations(...string) []Module CreateLocalVariations(...string) []Module } type TopDownMutatorContext interface { - baseMutatorContext - - OtherModuleName(m Module) string - OtherModuleDir(m Module) string - OtherModuleSubDir(m Module) string - OtherModuleType(m Module) string - OtherModuleErrorf(m Module, fmt string, args ...interface{}) - OtherModuleDependencyTag(m Module) DependencyTag + BaseMutatorContext CreateModule(ModuleFactory, ...interface{}) - - GetDirectDepWithTag(name string, tag DependencyTag) Module - GetDirectDep(name string) (Module, DependencyTag) - - VisitDirectDeps(visit func(Module)) - VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) - VisitDepsDepthFirst(visit func(Module)) - VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) - WalkDeps(visit func(Module, Module) bool) } type BottomUpMutatorContext interface { - baseMutatorContext + BaseMutatorContext AddDependency(module Module, tag DependencyTag, name ...string) AddReverseDependency(module Module, tag DependencyTag, name string) @@ -791,11 +784,6 @@ func (mctx *mutatorContext) ReplaceDependencies(name string) { mctx.replace = append(mctx.replace, replace{target, mctx.module}) } -func (mctx *mutatorContext) OtherModuleExists(name string) bool { - _, exists := mctx.context.nameInterface.ModuleFromName(name, mctx.module.namespace()) - return exists -} - // Rename all variants of a module. The new name is not visible to calls to ModuleName, // AddDependency or OtherModuleName until after this mutator pass is complete. func (mctx *mutatorContext) Rename(name string) { From 7bcc256daced91c588fd03ad71f51d184ec44a1b Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 20 May 2019 14:51:55 -0700 Subject: [PATCH 3/4] Move module and singleton godoc from the implementation to the interface The interface is visible in godoc, not the implementation, so move the documentation onto the interface methods. Test: view godoc Change-Id: I3460003eed6bf57d8ae4dabe70ab306f049a0060 --- module_ctx.go | 270 ++++++++++++++++++++++++++++++++++------------- singleton_ctx.go | 50 +++++++++ 2 files changed, 248 insertions(+), 72 deletions(-) diff --git a/module_ctx.go b/module_ctx.go index b3db1c3..6570b82 100644 --- a/module_ctx.go +++ b/module_ctx.go @@ -121,16 +121,39 @@ type DynamicDependerModule interface { } type BaseModuleContext interface { + // Module returns the current module as a Module. It should rarely be necessary, as the module already has a + // reference to itself. Module() Module + + // ModuleName returns the name of the module. This is generally the value that was returned by Module.Name() when + // the module was created, but may have been modified by calls to BaseMutatorContext.Rename. ModuleName() string + + // ModuleDir returns the path to the directory that contains the defintion of the module. ModuleDir() string + + // ModuleType returns the name of the module type that was used to create the module, as specified in + // RegisterModuleType. ModuleType() string + + // Config returns the config object that was passed to Context.PrepareBuildActions. Config() interface{} + // ContainsProperty returns true if the specified property name was set in the module definition. ContainsProperty(name string) bool + + // Errorf reports an error at the specified position of the module definition file. Errorf(pos scanner.Position, fmt string, args ...interface{}) + + // ModuleErrorf reports an error at the line number of the module type in the module definition. ModuleErrorf(fmt string, args ...interface{}) + + // PropertyErrorf reports an error at the line number of a property in the module definition. PropertyErrorf(property, fmt string, args ...interface{}) + + // Failed returns true if any errors have been reported. In most cases the module can continue with generating + // build rules after an error, allowing it to report additional errors in a single run, but in cases where the error + // has prevented the module from creating necessary data it can return early when Failed returns true. Failed() bool // GlobWithDeps returns a list of files and directories that match the @@ -141,29 +164,102 @@ type BaseModuleContext interface { // does not match the pattern is added to a searched directory. GlobWithDeps(pattern string, excludes []string) ([]string, error) + // Fs returns a pathtools.Filesystem that can be used to interact with files. Using the Filesystem interface allows + // the module to be used in build system tests that run against a mock filesystem. Fs() pathtools.FileSystem + + // AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest. The + // primary builder will be rerun whenever the specified files are modified. AddNinjaFileDeps(deps ...string) moduleInfo() *moduleInfo error(err error) + // Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the + // default SimpleNameInterface if Context.SetNameInterface was not called. Namespace() Namespace + // GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if + // none exists. It panics if the dependency does not have the specified tag. GetDirectDepWithTag(name string, tag DependencyTag) Module + + // GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified + // name, or nil if none exists. If there are multiple dependencies on the same module it returns + // the first DependencyTag. GetDirectDep(name string) (Module, DependencyTag) + // VisitDirectDeps calls visit for each direct dependency. If there are multiple direct dependencies on the same + // module visit will be called multiple times on that module and OtherModuleDependencyTag will return a different + // tag for each. + // + // The Module passed to the visit function should not be retained outside of the visit function, it may be + // invalidated by future mutators. VisitDirectDeps(visit func(Module)) + + // VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit. If there are + // multiple direct dependencies on the same module pred and visit will be called multiple times on that module and + // OtherModuleDependencyTag will return a different tag for each. + // + // The Module passed to the visit function should not be retained outside of the visit function, it may be + // invalidated by future mutators. VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) + + // VisitDepsDepthFirst calls visit for each transitive dependency, traversing the dependency tree in depth first + // order. visit will only be called once for any given module, even if there are multiple paths through the + // dependency tree to the module or multiple direct dependencies with different tags. OtherModuleDependencyTag will + // return the tag for the first path found to the module. + // + // The Module passed to the visit function should not be retained outside of the visit function, it may be + // invalidated by future mutators. VisitDepsDepthFirst(visit func(Module)) + + // VisitDepsDepthFirst calls pred for each transitive dependency, and if pred returns true calls visit, traversing + // the dependency tree in depth first order. visit will only be called once for any given module, even if there are + // multiple paths through the dependency tree to the module or multiple direct dependencies with different tags. + // OtherModuleDependencyTag will return the tag for the first path found to the module. The return value of pred + // does not affect which branches of the tree are traversed. + // + // The Module passed to the visit function should not be retained outside of the visit function, it may be + // invalidated by future mutators. VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) + + // WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may + // be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the + // child and parent with different tags. OtherModuleDependencyTag will return the tag for the currently visited + // (child, parent) pair. If visit returns false WalkDeps will not continue recursing down to child. + // + // The Modules passed to the visit function should not be retained outside of the visit function, they may be + // invalidated by future mutators. WalkDeps(visit func(Module, Module) bool) + // OtherModuleName returns the name of another Module. See BaseModuleContext.ModuleName for more information. + // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleName(m Module) string + + // OtherModuleDir returns the directory of another Module. See BaseModuleContext.ModuleDir for more information. + // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleDir(m Module) string + + // OtherModuleSubDir returns the unique subdirectory name of another Module. See ModuleContext.ModuleSubDir for + // more information. + // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleSubDir(m Module) string + + // OtherModuleType returns the type of another Module. See BaseModuleContext.ModuleType for more information. + // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleType(m Module) string + + // OtherModuleErrorf reports an error on another Module. See BaseModuleContext.ModuleErrorf for more information. + // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleErrorf(m Module, fmt string, args ...interface{}) + + // OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency + // on the module. When called inside a Visit* method with current module being visited, and there are multiple + // dependencies on the module being visited, it returns the dependency tag used for the current dependency. OtherModuleDependencyTag(m Module) DependencyTag + + // OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface + // passed to Context.SetNameInterface, or SimpleNameInterface if it was not called. OtherModuleExists(name string) bool } @@ -172,16 +268,41 @@ type DynamicDependerModuleContext BottomUpMutatorContext type ModuleContext interface { BaseModuleContext + // ModuleSubDir returns a unique name for the current variant of a module that can be used as part of the path + // to ensure that each variant of a module gets its own intermediates directory to write to. ModuleSubDir() string + // Variable creates a new ninja variable scoped to the module. It can be referenced by calls to Rule and Build + // in the same module. Variable(pctx PackageContext, name, value string) + + // Rule creates a new ninja rule scoped to the module. It can be referenced by calls to Build in the same module. Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule + + // Build creates a new ninja build statement. Build(pctx PackageContext, params BuildParams) + // PrimaryModule returns the first variant of the current module. Variants of a module are always visited in + // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the + // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are + // only done once for all variants of a module. PrimaryModule() Module + + // FinalModule returns the last variant of the current module. Variants of a module are always visited in + // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all + // variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform + // singleton actions that are only done once for all variants of a module. FinalModule() Module + + // VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always + // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read + // from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any + // data modified by the current mutator. VisitAllModuleVariants(visit func(Module)) + // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods, + // but do not exist. It can be used with Context.SetAllowMissingDependencies to allow the primary builder to + // handle missing dependencies on its own instead of having Blueprint treat them as an error. GetMissingDependencies() []string } @@ -333,9 +454,6 @@ func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string, }) } -// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency -// on the module. When called inside a Visit* method with current module being visited, and there are multiple -// dependencies on the module being visited, it returns the dependency tag used for the current dependency. func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag { // fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps if logicModule == m.visitingDep.module.logicModule { @@ -356,9 +474,6 @@ func (m *baseModuleContext) OtherModuleExists(name string) bool { return exists } -// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified -// name, or nil if none exists. If there are multiple dependencies on the same module it returns -// the first DependencyTag. func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) { for _, dep := range m.module.directDeps { if dep.module.Name() == name { @@ -369,8 +484,6 @@ func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) { return nil, nil } -// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if -// none exists. It panics if the dependency does not have the specified tag. func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) Module { var deps []depInfo for _, dep := range m.module.directDeps { @@ -389,8 +502,6 @@ func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) return nil } -// VisitDirectDeps calls visit for each direct dependency. If there are multiple direct dependencies on the same module -// visit will be called multiple times on that module and OtherModuleDependencyTag will return a different tag for each. func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) { defer func() { if r := recover(); r != nil { @@ -410,9 +521,6 @@ func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) { m.visitingDep = depInfo{} } -// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit. If there are multiple -// direct dependencies on the same module pred and visit will be called multiple times on that module and -// OtherModuleDependencyTag will return a different tag for each. func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { defer func() { if r := recover(); r != nil { @@ -434,10 +542,6 @@ func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func m.visitingDep = depInfo{} } -// VisitDepsDepthFirst calls visit for each transitive dependency, traversing the dependency tree in depth first order. -// visit will only be called once for any given module, even if there are multiple paths through the dependency tree -// to the module or multiple direct dependencies with different tags. OtherModuleDependencyTag will return the tag for -// the first path found to the module. func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { defer func() { if r := recover(); r != nil { @@ -456,11 +560,6 @@ func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { m.visitingDep = depInfo{} } -// VisitDepsDepthFirst calls pred for each transitive dependency, and if pred returns true calls visit, traversing the -// dependency tree in depth first order. visit will only be called once for any given module, even if there are -// multiple paths through the dependency tree to the module or multiple direct dependencies with different tags. -// OtherModuleDependencyTag will return the tag for the first path found to the module. The return value of pred does -// not affect which branches of the tree are traversed. func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) { @@ -483,10 +582,6 @@ func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, m.visitingDep = depInfo{} } -// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may be -// called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the -// child and parent with different tags. OtherModuleDependencyTag will return the tag for the currently visited -// (child, parent) pair. If visit returns false WalkDeps will not continue recursing down to child. func (m *baseModuleContext) WalkDeps(visit func(child, parent Module) bool) { m.context.walkDeps(m.module, true, func(dep depInfo, parent *moduleInfo) bool { m.visitingParent = parent @@ -577,33 +672,110 @@ type mutatorContext struct { type BaseMutatorContext interface { BaseModuleContext + // Rename all variants of a module. The new name is not visible to calls to ModuleName, + // AddDependency or OtherModuleName until after this mutator pass is complete. Rename(name string) } type EarlyMutatorContext interface { BaseMutatorContext + // CreateVariations splits a module into mulitple variants, one for each name in the variationNames + // parameter. It returns a list of new modules in the same order as the variationNames + // list. + // + // If any of the dependencies of the module being operated on were already split + // by calling CreateVariations with the same name, the dependency will automatically + // be updated to point the matching variant. + // + // If a module is split, and then a module depending on the first module is not split + // when the Mutator is later called on it, the dependency of the depending module will + // automatically be updated to point to the first variant. CreateVariations(...string) []Module + + // CreateLocationVariations splits a module into mulitple variants, one for each name in the variantNames + // parameter. It returns a list of new modules in the same order as the variantNames + // list. + // + // Local variations do not affect automatic dependency resolution - dependencies added + // to the split module via deps or DynamicDependerModule must exactly match a variant + // that contains all the non-local variations. CreateLocalVariations(...string) []Module } type TopDownMutatorContext interface { BaseMutatorContext + // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies + // the specified property structs to it as if the properties were set in a blueprint file. CreateModule(ModuleFactory, ...interface{}) } type BottomUpMutatorContext interface { BaseMutatorContext + // AddDependency adds a dependency to the given module. + // Does not affect the ordering of the current mutator pass, but will be ordered + // correctly for all future mutator passes. AddDependency(module Module, tag DependencyTag, name ...string) + + // AddReverseDependency adds a dependency from the destination to the given module. + // Does not affect the ordering of the current mutator pass, but will be ordered + // correctly for all future mutator passes. All reverse dependencies for a destination module are + // collected until the end of the mutator pass, sorted by name, and then appended to the destination + // module's dependency list. AddReverseDependency(module Module, tag DependencyTag, name string) + + // CreateVariations splits a module into mulitple variants, one for each name in the variationNames + // parameter. It returns a list of new modules in the same order as the variationNames + // list. + // + // If any of the dependencies of the module being operated on were already split + // by calling CreateVariations with the same name, the dependency will automatically + // be updated to point the matching variant. + // + // If a module is split, and then a module depending on the first module is not split + // when the Mutator is later called on it, the dependency of the depending module will + // automatically be updated to point to the first variant. CreateVariations(...string) []Module + + // CreateLocationVariations splits a module into mulitple variants, one for each name in the variantNames + // parameter. It returns a list of new modules in the same order as the variantNames + // list. + // + // Local variations do not affect automatic dependency resolution - dependencies added + // to the split module via deps or DynamicDependerModule must exactly match a variant + // that contains all the non-local variations. CreateLocalVariations(...string) []Module + + // SetDependencyVariation sets all dangling dependencies on the current module to point to the variation + // with given name. SetDependencyVariation(string) + + // AddVariationDependencies adds deps as dependencies of the current module, but uses the variations + // argument to select which variant of the dependency to use. A variant of the dependency must + // exist that matches the all of the non-local variations of the current module, plus the variations + // argument. AddVariationDependencies([]Variation, DependencyTag, ...string) + + // AddFarVariationDependencies adds deps as dependencies of the current module, but uses the + // variations argument to select which variant of the dependency to use. A variant of the + // dependency must exist that matches the variations argument, but may also have other variations. + // For any unspecified variation the first variant will be used. + // + // Unlike AddVariationDependencies, the variations of the current module are ignored - the + // dependency only needs to match the supplied variations. AddFarVariationDependencies([]Variation, DependencyTag, ...string) + + // AddInterVariantDependency adds a dependency between two variants of the same module. Variants are always + // ordered in the same orderas they were listed in CreateVariations, and AddInterVariantDependency does not change + // that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps, + // WalkDeps, etc. AddInterVariantDependency(tag DependencyTag, from, to Module) + + // ReplaceDependencies replaces all dependencies on the identical variant of the module with the + // specified name with the current variant of this module. Replacements don't take effect until + // after the mutator pass is finished. ReplaceDependencies(string) } @@ -636,28 +808,10 @@ func (BaseDependencyTag) dependencyTag(DependencyTag) { var _ DependencyTag = BaseDependencyTag{} -// Split a module into mulitple variants, one for each name in the variationNames -// parameter. It returns a list of new modules in the same order as the variationNames -// list. -// -// If any of the dependencies of the module being operated on were already split -// by calling CreateVariations with the same name, the dependency will automatically -// be updated to point the matching variant. -// -// If a module is split, and then a module depending on the first module is not split -// when the Mutator is later called on it, the dependency of the depending module will -// automatically be updated to point to the first variant. func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module { return mctx.createVariations(variationNames, false) } -// Split a module into mulitple variants, one for each name in the variantNames -// parameter. It returns a list of new modules in the same order as the variantNames -// list. -// -// Local variations do not affect automatic dependency resolution - dependencies added -// to the split module via deps or DynamicDependerModule must exactly match a variant -// that contains all the non-local variations. func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module { return mctx.createVariations(variationNames, true) } @@ -688,8 +842,6 @@ func (mctx *mutatorContext) createVariations(variationNames []string, local bool return ret } -// Set all dangling dependencies on the current module to point to the variation -// with given name. func (mctx *mutatorContext) SetDependencyVariation(variationName string) { mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName) } @@ -698,9 +850,6 @@ func (mctx *mutatorContext) Module() Module { return mctx.module.logicModule } -// Add a dependency to the given module. -// Does not affect the ordering of the current mutator pass, but will be ordered -// correctly for all future mutator passes. func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) { for _, dep := range deps { modInfo := mctx.context.moduleInfo[module] @@ -711,11 +860,6 @@ func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps } } -// Add a dependency from the destination to the given module. -// Does not affect the ordering of the current mutator pass, but will be ordered -// correctly for all future mutator passes. All reverse dependencies for a destination module are -// collected until the end of the mutator pass, sorted by name, and then appended to the destination -// module's dependency list. func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) { if _, ok := tag.(BaseDependencyTag); ok { panic("BaseDependencyTag is not allowed to be used directly!") @@ -733,10 +877,6 @@ func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTa }) } -// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations -// argument to select which variant of the dependency to use. A variant of the dependency must -// exist that matches the all of the non-local variations of the current module, plus the variations -// argument. func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag, deps ...string) { @@ -748,13 +888,6 @@ func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag } } -// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the -// variations argument to select which variant of the dependency to use. A variant of the -// dependency must exist that matches the variations argument, but may also have other variations. -// For any unspecified variation the first variant will be used. -// -// Unlike AddVariationDependencies, the variations of the current module are ignored - the -// depdendency only needs to match the supplied variations. func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag, deps ...string) { @@ -770,9 +903,6 @@ func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, t mctx.context.addInterVariantDependency(mctx.module, tag, from, to) } -// ReplaceDependencies replaces all dependencies on the identical variant of the module with the -// specified name with the current variant of this module. Replacements don't take effect until -// after the mutator pass is finished. func (mctx *mutatorContext) ReplaceDependencies(name string) { target := mctx.context.moduleMatchingVariant(mctx.module, name) @@ -784,14 +914,10 @@ func (mctx *mutatorContext) ReplaceDependencies(name string) { mctx.replace = append(mctx.replace, replace{target, mctx.module}) } -// Rename all variants of a module. The new name is not visible to calls to ModuleName, -// AddDependency or OtherModuleName until after this mutator pass is complete. func (mctx *mutatorContext) Rename(name string) { mctx.rename = append(mctx.rename, rename{mctx.module.group, name}) } -// Create a new module by calling the factory method for the specified moduleType, and apply -// the specified property structs to it as if the properties were set in a blueprint file. func (mctx *mutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) { module := mctx.context.newModule(factory) diff --git a/singleton_ctx.go b/singleton_ctx.go index de5bae7..cc58e06 100644 --- a/singleton_ctx.go +++ b/singleton_ctx.go @@ -25,23 +25,51 @@ type Singleton interface { } type SingletonContext interface { + // Config returns the config object that was passed to Context.PrepareBuildActions. Config() interface{} + // Name returns the name of the current singleton passed to Context.RegisterSingletonType Name() string + // ModuleName returns the name of the given Module. See BaseModuleContext.ModuleName for more information. ModuleName(module Module) string + + // ModuleDir returns the directory of the given Module. See BaseModuleContext.ModuleDir for more information. ModuleDir(module Module) string + + // ModuleSubDir returns the unique subdirectory name of the given Module. See ModuleContext.ModuleSubDir for + // more information. ModuleSubDir(module Module) string + + // ModuleType returns the type of the given Module. See BaseModuleContext.ModuleType for more information. ModuleType(module Module) string + + // BlueprintFile returns the path of the Blueprint file that defined the given module. BlueprintFile(module Module) string + // ModuleErrorf reports an error at the line number of the module type in the module definition. ModuleErrorf(module Module, format string, args ...interface{}) + + // Errorf reports an error at the specified position of the module definition file. Errorf(format string, args ...interface{}) + + // Failed returns true if any errors have been reported. In most cases the singleton can continue with generating + // build rules after an error, allowing it to report additional errors in a single run, but in cases where the error + // has prevented the singleton from creating necessary data it can return early when Failed returns true. Failed() bool + // Variable creates a new ninja variable scoped to the singleton. It can be referenced by calls to Rule and Build + // in the same singleton. Variable(pctx PackageContext, name, value string) + + // Rule creates a new ninja rule scoped to the singleton. It can be referenced by calls to Build in the same + // singleton. Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule + + // Build creates a new ninja build statement. Build(pctx PackageContext, params BuildParams) + + // RequireNinjaVersion sets the generated ninja manifest to require at least the specified version of ninja. RequireNinjaVersion(major, minor, micro int) // SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable @@ -58,17 +86,37 @@ type SingletonContext interface { // are expanded in the scope of the PackageContext. Eval(pctx PackageContext, ninjaStr string) (string, error) + // VisitAllModules calls visit for each defined variant of each module in an unspecified order. VisitAllModules(visit func(Module)) + + // VisitAllModules calls pred for each defined variant of each module in an unspecified order, and if pred returns + // true calls visit. VisitAllModulesIf(pred func(Module) bool, visit func(Module)) + + // VisitDepsDepthFirst calls visit for each transitive dependency, traversing the dependency tree in depth first + // order. visit will only be called once for any given module, even if there are multiple paths through the + // dependency tree to the module or multiple direct dependencies with different tags. VisitDepsDepthFirst(module Module, visit func(Module)) + + // VisitDepsDepthFirst calls pred for each transitive dependency, and if pred returns true calls visit, traversing + // the dependency tree in depth first order. visit will only be called once for any given module, even if there are + // multiple paths through the dependency tree to the module or multiple direct dependencies with different tags. VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) + // VisitAllModuleVariants calls visit for each variant of the given module. VisitAllModuleVariants(module Module, visit func(Module)) + // PrimaryModule returns the first variant of the given module. This can be used to perform + // // singleton actions that are only done once for all variants of a module. PrimaryModule(module Module) Module + + // FinalModule returns the last variant of the given module. This can be used to perform + // singleton actions that are only done once for all variants of a module. FinalModule(module Module) Module + // AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest. The + // primary builder will be rerun whenever the specified files are modified. AddNinjaFileDeps(deps ...string) // GlobWithDeps returns a list of files and directories that match the @@ -79,6 +127,8 @@ type SingletonContext interface { // does not match the pattern is added to a searched directory. GlobWithDeps(pattern string, excludes []string) ([]string, error) + // Fs returns a pathtools.Filesystem that can be used to interact with files. Using the Filesystem interface allows + // the singleton to be used in build system tests that run against a mock filesystem. Fs() pathtools.FileSystem } From 322cc018035a0200e1a662d40db1a65a4ba88391 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 20 May 2019 13:55:14 -0700 Subject: [PATCH 4/4] Report creating modules in errors on created modules Bug: 133172285 Change-Id: I0782c722f5877508691868f96dbf7dc0bed3f9f4 --- context.go | 9 +++++++++ module_ctx.go | 2 ++ 2 files changed, 11 insertions(+) diff --git a/context.go b/context.go index dcfda83..6a61861 100644 --- a/context.go +++ b/context.go @@ -173,6 +173,7 @@ type moduleInfo struct { relBlueprintsFile string pos scanner.Position propertyPos map[string]scanner.Position + createdBy *moduleInfo variantName string variant variationMap @@ -215,6 +216,10 @@ func (module *moduleInfo) String() string { if module.variantName != "" { s += fmt.Sprintf(" variant %q", module.variantName) } + if module.createdBy != nil { + s += fmt.Sprintf(" (created by %s)", module.createdBy) + } + return s } @@ -2151,6 +2156,10 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo, } } + if module.createdBy != nil && module.createdBy.logicModule == nil { + module.createdBy = module.createdBy.splitModules[0] + } + // Add in any new direct dependencies that were added by the mutator module.directDeps = append(module.directDeps, module.newDirectDeps...) module.newDirectDeps = nil diff --git a/module_ctx.go b/module_ctx.go index 6570b82..f72451b 100644 --- a/module_ctx.go +++ b/module_ctx.go @@ -923,6 +923,8 @@ func (mctx *mutatorContext) CreateModule(factory ModuleFactory, props ...interfa module.relBlueprintsFile = mctx.module.relBlueprintsFile module.pos = mctx.module.pos + module.propertyPos = mctx.module.propertyPos + module.createdBy = mctx.module for _, p := range props { err := proptools.AppendMatchingProperties(module.properties, p, nil)