Merge pull request #61 from yuchenericwu2/master

Add walkDeps to context and module_ctx.
diff --git a/context.go b/context.go
index dd2dc1d..982cf72 100644
--- a/context.go
+++ b/context.go
@@ -1825,6 +1825,27 @@
 	return nil
 }
 
+func (c *Context) walkDeps(topModule *moduleInfo,
+	visit func(Module, Module) bool) {
+
+	visited := make(map[*moduleInfo]bool)
+
+	var walk func(module *moduleInfo)
+	walk = func(module *moduleInfo) {
+		visited[module] = true
+
+		for _, moduleDep := range module.directDeps {
+			if !visited[moduleDep] {
+				if visit(moduleDep.logicModule, module.logicModule) {
+					walk(moduleDep)
+				}
+			}
+		}
+	}
+
+	walk(topModule)
+}
+
 func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
 	visited := make(map[*moduleInfo]bool)
 
diff --git a/context_test.go b/context_test.go
index 1c4303b..8877be9 100644
--- a/context_test.go
+++ b/context_test.go
@@ -19,6 +19,10 @@
 	"testing"
 )
 
+type Walker interface {
+	Walk() bool
+}
+
 type fooModule struct {
 	properties struct {
 		Foo string
@@ -37,6 +41,10 @@
 	return f.properties.Foo
 }
 
+func (f *fooModule) Walk() bool {
+	return true
+}
+
 type barModule struct {
 	properties struct {
 		Bar bool
@@ -55,6 +63,10 @@
 	return b.properties.Bar
 }
 
+func (b *barModule) Walk() bool {
+	return false
+}
+
 func TestContextParse(t *testing.T) {
 	ctx := NewContext()
 	ctx.RegisterModuleType("foo_module", newFooModule)
@@ -99,3 +111,30 @@
 	}
 
 }
+
+// |---B===D       - represents a non-walkable edge
+// A               = represents a walkable edge
+// |===C---E===G
+//     |       |   A should not be visited because it's the root node.
+//     |===F===|   B, D and E should not be walked.
+func TestWalkDeps(t *testing.T) {
+	ctx := NewContext()
+	ctx.RegisterModuleType("foo_module", newFooModule)
+	ctx.RegisterModuleType("bar_module", newBarModule)
+	ctx.ParseBlueprintsFiles("context_test_Blueprints")
+	ctx.ResolveDependencies(nil)
+
+	var output string
+	topModule := ctx.moduleGroups["A"].modules[0]
+	ctx.walkDeps(topModule,
+		func(module, parent Module) bool {
+			if module.(Walker).Walk() {
+				output += ctx.ModuleName(module)
+				return true
+			}
+			return false
+		})
+	if output != "CFG" {
+		t.Fatalf("unexpected walkDeps behaviour: %s\nshould be: CFG", output)
+	}
+}
diff --git a/context_test_Blueprints b/context_test_Blueprints
new file mode 100644
index 0000000..6cac8b2
--- /dev/null
+++ b/context_test_Blueprints
@@ -0,0 +1,32 @@
+foo_module {
+    name: "A",
+    deps: ["B", "C"],
+}
+
+bar_module {
+    name: "B",
+    deps: ["D"],
+}
+
+foo_module {
+    name: "C",
+    deps: ["E", "F"],
+}
+
+foo_module {
+    name: "D",
+}
+
+bar_module {
+    name: "E",
+    deps: ["G"],
+}
+
+foo_module {
+    name: "F",
+    deps: ["G"],
+}
+
+foo_module {
+    name: "G",
+}
diff --git a/module_ctx.go b/module_ctx.go
index 6254596..94db01e 100644
--- a/module_ctx.go
+++ b/module_ctx.go
@@ -133,6 +133,7 @@
 	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)
 
 	ModuleSubDir() string
 
@@ -251,6 +252,10 @@
 	m.context.visitDepsDepthFirstIf(m.module, pred, visit)
 }
 
+func (m *moduleContext) WalkDeps(visit func(Module, Module) bool) {
+	m.context.walkDeps(m.module, visit)
+}
+
 func (m *moduleContext) ModuleSubDir() string {
 	return m.module.variantName
 }
@@ -382,6 +387,7 @@
 	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 {
@@ -501,3 +507,7 @@
 
 	mctx.context.visitDepsDepthFirstIf(mctx.module, pred, visit)
 }
+
+func (mctx *mutatorContext) WalkDeps(visit func(Module, Module) bool) {
+	mctx.context.walkDeps(mctx.module, visit)
+}