Merge pull request #63 from colincross/deprecate

Deprecate EarlyMutator and DynamicDependencies
diff --git a/context.go b/context.go
index 982cf72..ee9beb6 100644
--- a/context.go
+++ b/context.go
@@ -224,12 +224,16 @@
 // RegisterSingletonFactory methods must be called before it can do anything
 // useful.
 func NewContext() *Context {
-	return &Context{
+	ctx := &Context{
 		moduleFactories:  make(map[string]ModuleFactory),
 		moduleGroups:     make(map[string]*moduleGroup),
 		moduleInfo:       make(map[Module]*moduleInfo),
 		moduleNinjaNames: make(map[string]*moduleGroup),
 	}
+
+	ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
+
+	return ctx
 }
 
 // A ModuleFactory function creates a new Module object.  See the
@@ -402,6 +406,10 @@
 //
 // The mutator type names given here must be unique to all bottom up or early
 // mutators in the Context.
+//
+// Deprecated, use a BottomUpMutator instead.  The only difference between
+// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
+// deprecated DynamicDependencies.
 func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
 	for _, m := range c.variantMutatorNames {
 		if m == name {
@@ -1057,27 +1065,8 @@
 // modules defined in the parsed Blueprints files are valid.  This means that
 // the modules depended upon are defined and that no circular dependencies
 // exist.
-//
-// The config argument is made available to all of the DynamicDependerModule
-// objects via the Config method on the DynamicDependerModuleContext objects
-// passed to their DynamicDependencies method.
 func (c *Context) ResolveDependencies(config interface{}) []error {
-	errs := c.runEarlyMutators(config)
-	if len(errs) > 0 {
-		return errs
-	}
-
-	errs = c.resolveDependencies(config)
-	if len(errs) > 0 {
-		return errs
-	}
-
-	errs = c.updateDependencies()
-	if len(errs) > 0 {
-		return errs
-	}
-
-	errs = c.runMutators(config)
+	errs := c.runMutators(config)
 	if len(errs) > 0 {
 		return errs
 	}
@@ -1086,74 +1075,24 @@
 	return nil
 }
 
-// moduleDeps adds dependencies to a module.  If the module implements the
+// Default dependencies handling.  If the module implements the (deprecated)
 // DynamicDependerModule interface then this set consists of the union of those
 // module names listed in its "deps" property, those returned by its
 // DynamicDependencies method, and those added by calling AddDependencies or
 // AddVariationDependencies on DynamicDependencyModuleContext.  Otherwise it
 // is simply those names listed in its "deps" property.
-func (c *Context) moduleDeps(module *moduleInfo,
-	config interface{}) (errs []error) {
+func blueprintDepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), ctx.moduleInfo().properties.Deps...)
 
-	depNamesSet := make(map[string]bool)
-	depNames := []string{}
+	if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
+		dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
 
-	for _, depName := range module.properties.Deps {
-		if !depNamesSet[depName] {
-			depNamesSet[depName] = true
-			depNames = append(depNames, depName)
+		if ctx.Failed() {
+			return
 		}
+
+		ctx.AddDependency(ctx.Module(), dynamicDeps...)
 	}
-
-	dynamicDepender, ok := module.logicModule.(DynamicDependerModule)
-	if ok {
-		ddmctx := &dynamicDependerModuleContext{
-			baseModuleContext: baseModuleContext{
-				context: c,
-				config:  config,
-				module:  module,
-			},
-			module: module,
-		}
-
-		dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
-
-		if len(ddmctx.errs) > 0 {
-			return ddmctx.errs
-		}
-
-		for _, depName := range dynamicDeps {
-			if !depNamesSet[depName] {
-				depNamesSet[depName] = true
-				depNames = append(depNames, depName)
-			}
-		}
-	}
-
-	for _, depName := range depNames {
-		newErrs := c.addDependency(module, depName)
-		if len(newErrs) > 0 {
-			errs = append(errs, newErrs...)
-		}
-	}
-	return errs
-}
-
-// resolveDependencies populates the directDeps list for every module.  In doing so it checks for
-// missing dependencies and self-dependant modules.
-func (c *Context) resolveDependencies(config interface{}) (errs []error) {
-	for _, group := range c.moduleGroups {
-		for _, module := range group.modules {
-			module.directDeps = make([]*moduleInfo, 0, len(module.properties.Deps))
-
-			newErrs := c.moduleDeps(module, config)
-			if len(newErrs) > 0 {
-				errs = append(errs, newErrs...)
-			}
-		}
-	}
-
-	return
 }
 
 // findMatchingVariant searches the moduleGroup for a module with the same variant as module,
@@ -1545,10 +1484,20 @@
 		}
 	}
 
+	errs = c.updateDependencies()
+	if len(errs) > 0 {
+		return errs
+	}
+
 	return nil
 }
 
 func (c *Context) runMutators(config interface{}) (errs []error) {
+	errs = c.runEarlyMutators(config)
+	if len(errs) > 0 {
+		return errs
+	}
+
 	for _, mutator := range c.mutatorInfo {
 		if mutator.topDownMutator != nil {
 			errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
diff --git a/context_test.go b/context_test.go
index 8877be9..acf0c1c 100644
--- a/context_test.go
+++ b/context_test.go
@@ -92,7 +92,7 @@
 		t.FailNow()
 	}
 
-	errs = ctx.resolveDependencies(nil)
+	errs = ctx.ResolveDependencies(nil)
 	if len(errs) > 0 {
 		t.Errorf("unexpected dep errors:")
 		for _, err := range errs {
@@ -100,16 +100,6 @@
 		}
 		t.FailNow()
 	}
-
-	errs = ctx.updateDependencies()
-	if len(errs) > 0 {
-		t.Errorf("unexpected dep cycle errors:")
-		for _, err := range errs {
-			t.Errorf("  %s", err)
-		}
-		t.FailNow()
-	}
-
 }
 
 // |---B===D       - represents a non-walkable edge
diff --git a/module_ctx.go b/module_ctx.go
index 94db01e..7af26d2 100644
--- a/module_ctx.go
+++ b/module_ctx.go
@@ -34,10 +34,11 @@
 //
 // The Module implementation can access the build configuration as well as any
 // modules on which on which it depends (as defined by the "deps" property
-// specified in the Blueprints file or dynamically added by implementing the
-// DynamicDependerModule interface) using the ModuleContext passed to
-// GenerateBuildActions.  This ModuleContext is also used to create Ninja build
-// actions and to report errors to the user.
+// specified in the Blueprints file, dynamically added by implementing the
+// (deprecated) DynamicDependerModule interface, or dynamically added by a
+// BottomUpMutator) using the ModuleContext passed to GenerateBuildActions.
+// This ModuleContext is also used to create Ninja build actions and to report
+// errors to the user.
 //
 // In addition to implementing the GenerateBuildActions method, a Module should
 // implement methods that provide dependant modules and singletons information
@@ -93,6 +94,8 @@
 // appear in its "deps" property.  Any Module that implements this interface
 // will have its DynamicDependencies method called by the Context that created
 // it during generate phase.
+//
+// Deprecated, use a BottomUpMutator instead
 type DynamicDependerModule interface {
 	Module
 
@@ -114,14 +117,11 @@
 	ModuleErrorf(fmt string, args ...interface{})
 	PropertyErrorf(property, fmt string, args ...interface{})
 	Failed() bool
+
+	moduleInfo() *moduleInfo
 }
 
-type DynamicDependerModuleContext interface {
-	BaseModuleContext
-
-	AddVariationDependencies([]Variation, ...string)
-	AddFarVariationDependencies([]Variation, ...string)
-}
+type DynamicDependerModuleContext BottomUpMutatorContext
 
 type ModuleContext interface {
 	BaseModuleContext
@@ -157,6 +157,10 @@
 	errs    []error
 }
 
+func (d *baseModuleContext) moduleInfo() *moduleInfo {
+	return d.module
+}
+
 func (d *baseModuleContext) ModuleName() string {
 	return d.module.properties.Name
 }
@@ -316,49 +320,6 @@
 }
 
 //
-// 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, false)
-		if len(errs) > 0 {
-			mctx.errs = append(mctx.errs, errs...)
-		}
-	}
-}
-
-// 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 *dynamicDependerModuleContext) AddFarVariationDependencies(variations []Variation,
-	deps ...string) {
-
-	for _, dep := range deps {
-		errs := mctx.context.addVariationDependency(mctx.module, variations, dep, true)
-		if len(errs) > 0 {
-			mctx.errs = append(mctx.errs, errs...)
-		}
-	}
-}
-
-//
 // MutatorContext
 //
 
@@ -393,11 +354,13 @@
 type BottomUpMutatorContext interface {
 	baseMutatorContext
 
-	AddDependency(module Module, name string)
+	AddDependency(module Module, name ...string)
 	AddReverseDependency(module Module, name string)
 	CreateVariations(...string) []Module
 	CreateLocalVariations(...string) []Module
 	SetDependencyVariation(string)
+	AddVariationDependencies([]Variation, ...string)
+	AddFarVariationDependencies([]Variation, ...string)
 }
 
 // A Mutator function is called for each Module, and can use
@@ -473,10 +436,12 @@
 // 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, depName string) {
-	errs := mctx.context.addDependency(mctx.context.moduleInfo[module], depName)
-	if len(errs) > 0 {
-		mctx.errs = append(mctx.errs, errs...)
+func (mctx *mutatorContext) AddDependency(module Module, deps ...string) {
+	for _, dep := range deps {
+		errs := mctx.context.addDependency(mctx.context.moduleInfo[module], dep)
+		if len(errs) > 0 {
+			mctx.errs = append(mctx.errs, errs...)
+		}
 	}
 }
 
@@ -484,12 +449,45 @@
 // Does not affect the ordering of the current mutator pass, but will be ordered
 // correctly for all future mutator passes.
 func (mctx *mutatorContext) AddReverseDependency(module Module, destName string) {
-	errs := mctx.context.addReverseDependency(mctx.context.moduleInfo[module], destName)
+	errs := mctx.context.addReverseDependency(mctx.module, destName)
 	if len(errs) > 0 {
 		mctx.errs = append(mctx.errs, errs...)
 	}
 }
 
+// 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,
+	deps ...string) {
+
+	for _, dep := range deps {
+		errs := mctx.context.addVariationDependency(mctx.module, variations, dep, false)
+		if len(errs) > 0 {
+			mctx.errs = append(mctx.errs, errs...)
+		}
+	}
+}
+
+// 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,
+	deps ...string) {
+
+	for _, dep := range deps {
+		errs := mctx.context.addVariationDependency(mctx.module, variations, dep, true)
+		if len(errs) > 0 {
+			mctx.errs = append(mctx.errs, errs...)
+		}
+	}
+}
+
 func (mctx *mutatorContext) VisitDirectDeps(visit func(Module)) {
 	mctx.context.visitDirectDeps(mctx.module, visit)
 }