Merge pull request #5 from colincross/earlymutators

Support for early mutators
This commit is contained in:
colincross 2015-03-13 19:56:52 -07:00
commit 96555d687e
6 changed files with 635 additions and 320 deletions

File diff suppressed because it is too large Load diff

View file

@ -167,3 +167,25 @@ func (l *liveTracker) addNinjaStringDeps(str *ninjaString) error {
}
return nil
}
func (l *liveTracker) RemoveVariableIfLive(v Variable) bool {
l.Lock()
defer l.Unlock()
_, isLive := l.variables[v]
if isLive {
delete(l.variables, v)
}
return isLive
}
func (l *liveTracker) RemoveRuleIfLive(r Rule) bool {
l.Lock()
defer l.Unlock()
_, isLive := l.rules[r]
if isLive {
delete(l.rules, r)
}
return isLive
}

View file

@ -118,6 +118,8 @@ type BaseModuleContext interface {
type DynamicDependerModuleContext interface {
BaseModuleContext
AddVariationDependencies([]Variation, ...string)
}
type ModuleContext interface {
@ -149,21 +151,21 @@ var _ BaseModuleContext = (*baseModuleContext)(nil)
type baseModuleContext struct {
context *Context
config interface{}
group *moduleGroup
module *moduleInfo
errs []error
}
func (d *baseModuleContext) ModuleName() string {
return d.group.properties.Name
return d.module.properties.Name
}
func (d *baseModuleContext) ContainsProperty(name string) bool {
_, ok := d.group.propertyPos[name]
_, ok := d.module.propertyPos[name]
return ok
}
func (d *baseModuleContext) ModuleDir() string {
return filepath.Dir(d.group.relBlueprintsFile)
return filepath.Dir(d.module.relBlueprintsFile)
}
func (d *baseModuleContext) Config() interface{} {
@ -184,14 +186,14 @@ func (d *baseModuleContext) ModuleErrorf(format string,
d.errs = append(d.errs, &Error{
Err: fmt.Errorf(format, args...),
Pos: d.group.pos,
Pos: d.module.pos,
})
}
func (d *baseModuleContext) PropertyErrorf(property, format string,
args ...interface{}) {
pos, ok := d.group.propertyPos[property]
pos, ok := d.module.propertyPos[property]
if !ok {
panic(fmt.Errorf("property %q was not set for this module", property))
}
@ -210,24 +212,23 @@ var _ ModuleContext = (*moduleContext)(nil)
type moduleContext struct {
baseModuleContext
module *moduleInfo
scope *localScope
ninjaFileDeps []string
actionDefs localBuildActions
}
func (m *moduleContext) OtherModuleName(module Module) string {
info := m.context.moduleInfo[module]
return info.group.properties.Name
func (m *moduleContext) OtherModuleName(logicModule Module) string {
module := m.context.moduleInfo[logicModule]
return module.properties.Name
}
func (m *moduleContext) OtherModuleErrorf(module Module, format string,
func (m *moduleContext) OtherModuleErrorf(logicModule Module, format string,
args ...interface{}) {
info := m.context.moduleInfo[module]
module := m.context.moduleInfo[logicModule]
m.errs = append(m.errs, &Error{
Err: fmt.Errorf(format, args...),
Pos: info.group.pos,
Pos: module.pos,
})
}
@ -250,7 +251,7 @@ func (m *moduleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
}
func (m *moduleContext) ModuleSubDir() string {
return m.module.subName()
return m.module.variantName
}
func (m *moduleContext) Variable(pctx *PackageContext, name, value string) {
@ -308,13 +309,37 @@ func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
}
}
//
// DynamicDependerModuleContext
//
type dynamicDependerModuleContext struct {
baseModuleContext
module *moduleInfo
}
// 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 *dynamicDependerModuleContext) AddVariationDependencies(variations []Variation,
deps ...string) {
for _, dep := range deps {
errs := mctx.context.addVariationDependency(mctx.module, variations, dep)
if len(errs) > 0 {
mctx.errs = append(mctx.errs, errs...)
}
}
}
//
// MutatorContext
//
type mutatorContext struct {
baseModuleContext
module *moduleInfo
name string
dependenciesModified bool
}
@ -325,6 +350,13 @@ type baseMutatorContext interface {
Module() Module
}
type EarlyMutatorContext interface {
baseMutatorContext
CreateVariations(...string) []Module
CreateLocalVariations(...string) []Module
}
type TopDownMutatorContext interface {
baseMutatorContext
@ -338,12 +370,12 @@ type BottomUpMutatorContext interface {
baseMutatorContext
AddDependency(module Module, name string)
CreateVariants(...string) []Module
SetDependencyVariant(string)
CreateVariations(...string) []Module
SetDependencyVariation(string)
}
// A Mutator function is called for each Module, and can use
// MutatorContext.CreateSubVariants to split a Module into multiple Modules,
// MutatorContext.CreateVariations to split a Module into multiple Modules,
// modifying properties on the new modules to differentiate them. It is called
// after parsing all Blueprint files, but before generating any build rules,
// and is always called on dependencies before being called on the depending module.
@ -353,44 +385,59 @@ type BottomUpMutatorContext interface {
// if a second Mutator chooses to split the module a second time.
type TopDownMutator func(mctx TopDownMutatorContext)
type BottomUpMutator func(mctx BottomUpMutatorContext)
type EarlyMutator func(mctx EarlyMutatorContext)
// 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
// 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 CreateVariants with the same name, the dependency will automatically
// 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) CreateVariants(variantNames ...string) []Module {
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)
}
func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module {
ret := []Module{}
modules, errs := mctx.context.createVariants(mctx.module, mctx.name, variantNames)
modules, errs := mctx.context.createVariations(mctx.module, mctx.name, variationNames)
if len(errs) > 0 {
mctx.errs = append(mctx.errs, errs...)
}
for _, module := range modules {
for i, module := range modules {
ret = append(ret, module.logicModule)
if !local {
module.dependencyVariant[mctx.name] = variationNames[i]
}
}
if len(ret) != len(variantNames) {
if len(ret) != len(variationNames) {
panic("oops!")
}
return ret
}
// Set all dangling dependencies on the current module to point to the variant
// Set all dangling dependencies on the current module to point to the variation
// with given name.
func (mctx *mutatorContext) SetDependencyVariant(variantName string) {
subName := subName{
mutatorName: mctx.name,
variantName: variantName,
}
mctx.context.convertDepsToVariant(mctx.module, subName)
func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName)
}
func (mctx *mutatorContext) Module() Module {
@ -398,11 +445,14 @@ func (mctx *mutatorContext) Module() Module {
}
// Add a dependency to the given module. The depender can be a specific variant
// of a module, but the dependee must be a module that only has a single variant.
// of a module, but the dependee must be a module that has no variations.
// 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, depName string) {
mctx.context.addDependency(mctx.context.moduleInfo[module], depName)
errs := mctx.context.addDependency(mctx.context.moduleInfo[module], depName)
if len(errs) > 0 {
mctx.errs = append(mctx.errs, errs...)
}
mctx.dependenciesModified = true
}

View file

@ -15,6 +15,7 @@
package blueprint
import (
"bytes"
"fmt"
"strings"
)
@ -288,6 +289,26 @@ func validateNinjaName(name string) error {
return nil
}
func toNinjaName(name string) string {
ret := bytes.Buffer{}
ret.Grow(len(name))
for _, r := range name {
valid := (r >= 'a' && r <= 'z') ||
(r >= 'A' && r <= 'Z') ||
(r >= '0' && r <= '9') ||
(r == '_') ||
(r == '-') ||
(r == '.')
if valid {
ret.WriteRune(r)
} else {
ret.WriteRune('_')
}
}
return ret.String()
}
var builtinRuleArgs = []string{"out", "in"}
func validateArgName(argName string) error {

View file

@ -72,17 +72,17 @@ func (s *singletonContext) Config() interface{} {
func (s *singletonContext) ModuleName(logicModule Module) string {
module := s.context.moduleInfo[logicModule]
return module.group.properties.Name
return module.properties.Name
}
func (s *singletonContext) ModuleDir(logicModule Module) string {
module := s.context.moduleInfo[logicModule]
return filepath.Dir(module.group.relBlueprintsFile)
return filepath.Dir(module.relBlueprintsFile)
}
func (s *singletonContext) BlueprintFile(logicModule Module) string {
module := s.context.moduleInfo[logicModule]
return module.group.relBlueprintsFile
return module.relBlueprintsFile
}
func (s *singletonContext) ModuleErrorf(logicModule Module, format string,
@ -91,7 +91,7 @@ func (s *singletonContext) ModuleErrorf(logicModule Module, format string,
module := s.context.moduleInfo[logicModule]
s.errs = append(s.errs, &Error{
Err: fmt.Errorf(format, args...),
Pos: module.group.pos,
Pos: module.pos,
})
}