Merge pull request #293 from paulduffin/master

WalkDeps - only record module visited when it has been recursed into
This commit is contained in:
colincross 2020-04-02 12:58:05 -07:00 committed by GitHub
commit 6957a46d38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 132 additions and 34 deletions

View file

@ -2619,8 +2619,8 @@ func (c *Context) walkDeps(topModule *moduleInfo, allowDuplicates bool,
} }
if recurse && !visited[dep.module] { if recurse && !visited[dep.module] {
walk(dep.module) walk(dep.module)
visited[dep.module] = true
} }
visited[dep.module] = true
if visitUp != nil { if visitUp != nil {
visitUp(dep, module) visitUp(dep, module)
} }

View file

@ -31,11 +31,40 @@ type Walker interface {
Walk() bool Walk() bool
} }
func walkDependencyGraph(ctx *Context, topModule *moduleInfo, allowDuplicates bool) (string, string) {
var outputDown string
var outputUp string
ctx.walkDeps(topModule, allowDuplicates,
func(dep depInfo, parent *moduleInfo) bool {
outputDown += ctx.ModuleName(dep.module.logicModule)
if tag, ok := dep.tag.(walkerDepsTag); ok {
if !tag.follow {
return false
}
}
if dep.module.logicModule.(Walker).Walk() {
return true
}
return false
},
func(dep depInfo, parent *moduleInfo) {
outputUp += ctx.ModuleName(dep.module.logicModule)
})
return outputDown, outputUp
}
type depsProvider interface {
Deps() []string
IgnoreDeps() []string
}
type fooModule struct { type fooModule struct {
SimpleName SimpleName
properties struct { properties struct {
Deps []string Deps []string
Foo string Ignored_deps []string
Foo string
} }
} }
@ -47,10 +76,14 @@ func newFooModule() (Module, []interface{}) {
func (f *fooModule) GenerateBuildActions(ModuleContext) { func (f *fooModule) GenerateBuildActions(ModuleContext) {
} }
func (f *fooModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string { func (f *fooModule) Deps() []string {
return f.properties.Deps return f.properties.Deps
} }
func (f *fooModule) IgnoreDeps() []string {
return f.properties.Ignored_deps
}
func (f *fooModule) Foo() string { func (f *fooModule) Foo() string {
return f.properties.Foo return f.properties.Foo
} }
@ -62,8 +95,9 @@ func (f *fooModule) Walk() bool {
type barModule struct { type barModule struct {
SimpleName SimpleName
properties struct { properties struct {
Deps []string Deps []string
Bar bool Ignored_deps []string
Bar bool
} }
} }
@ -72,10 +106,14 @@ func newBarModule() (Module, []interface{}) {
return m, []interface{}{&m.properties, &m.SimpleName.Properties} return m, []interface{}{&m.properties, &m.SimpleName.Properties}
} }
func (b *barModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string { func (b *barModule) Deps() []string {
return b.properties.Deps return b.properties.Deps
} }
func (b *barModule) IgnoreDeps() []string {
return b.properties.Ignored_deps
}
func (b *barModule) GenerateBuildActions(ModuleContext) { func (b *barModule) GenerateBuildActions(ModuleContext) {
} }
@ -87,6 +125,19 @@ func (b *barModule) Walk() bool {
return false return false
} }
type walkerDepsTag struct {
BaseDependencyTag
// True if the dependency should be followed, false otherwise.
follow bool
}
func depsMutator(mctx BottomUpMutatorContext) {
if m, ok := mctx.Module().(depsProvider); ok {
mctx.AddDependency(mctx.Module(), walkerDepsTag{follow: false}, m.IgnoreDeps()...)
mctx.AddDependency(mctx.Module(), walkerDepsTag{follow: true}, m.Deps()...)
}
}
func TestContextParse(t *testing.T) { func TestContextParse(t *testing.T) {
ctx := NewContext() ctx := NewContext()
ctx.RegisterModuleType("foo_module", newFooModule) ctx.RegisterModuleType("foo_module", newFooModule)
@ -168,6 +219,7 @@ func TestWalkDeps(t *testing.T) {
ctx.RegisterModuleType("foo_module", newFooModule) ctx.RegisterModuleType("foo_module", newFooModule)
ctx.RegisterModuleType("bar_module", newBarModule) ctx.RegisterModuleType("bar_module", newBarModule)
ctx.RegisterBottomUpMutator("deps", depsMutator)
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil) _, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
if len(errs) > 0 { if len(errs) > 0 {
t.Errorf("unexpected parse errors:") t.Errorf("unexpected parse errors:")
@ -186,20 +238,8 @@ func TestWalkDeps(t *testing.T) {
t.FailNow() t.FailNow()
} }
var outputDown string
var outputUp string
topModule := ctx.moduleGroupFromName("A", nil).modules[0] topModule := ctx.moduleGroupFromName("A", nil).modules[0]
ctx.walkDeps(topModule, false, outputDown, outputUp := walkDependencyGraph(ctx, topModule, false)
func(dep depInfo, parent *moduleInfo) bool {
outputDown += ctx.ModuleName(dep.module.logicModule)
if dep.module.logicModule.(Walker).Walk() {
return true
}
return false
},
func(dep depInfo, parent *moduleInfo) {
outputUp += ctx.ModuleName(dep.module.logicModule)
})
if outputDown != "BCEFG" { if outputDown != "BCEFG" {
t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEFG", outputDown) t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEFG", outputDown)
} }
@ -260,6 +300,7 @@ func TestWalkDepsDuplicates(t *testing.T) {
ctx.RegisterModuleType("foo_module", newFooModule) ctx.RegisterModuleType("foo_module", newFooModule)
ctx.RegisterModuleType("bar_module", newBarModule) ctx.RegisterModuleType("bar_module", newBarModule)
ctx.RegisterBottomUpMutator("deps", depsMutator)
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil) _, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
if len(errs) > 0 { if len(errs) > 0 {
t.Errorf("unexpected parse errors:") t.Errorf("unexpected parse errors:")
@ -278,20 +319,8 @@ func TestWalkDepsDuplicates(t *testing.T) {
t.FailNow() t.FailNow()
} }
var outputDown string
var outputUp string
topModule := ctx.moduleGroupFromName("A", nil).modules[0] topModule := ctx.moduleGroupFromName("A", nil).modules[0]
ctx.walkDeps(topModule, true, outputDown, outputUp := walkDependencyGraph(ctx, topModule, true)
func(dep depInfo, parent *moduleInfo) bool {
outputDown += ctx.ModuleName(dep.module.logicModule)
if dep.module.logicModule.(Walker).Walk() {
return true
}
return false
},
func(dep depInfo, parent *moduleInfo) {
outputUp += ctx.ModuleName(dep.module.logicModule)
})
if outputDown != "BCEGHFGG" { if outputDown != "BCEGHFGG" {
t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEGHFGG", outputDown) t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEGHFGG", outputDown)
} }
@ -300,6 +329,75 @@ func TestWalkDepsDuplicates(t *testing.T) {
} }
} }
// - represents a non-walkable edge
// A = represents a walkable edge
// |===B-------\ A should not be visited because it's the root node.
// | | B -> D should not be walked.
// |===C===D===E B -> C -> D -> E should be walked
func TestWalkDepsDuplicates_IgnoreFirstPath(t *testing.T) {
ctx := NewContext()
ctx.MockFileSystem(map[string][]byte{
"Blueprints": []byte(`
foo_module {
name: "A",
deps: ["B"],
}
foo_module {
name: "B",
deps: ["C"],
ignored_deps: ["D"],
}
foo_module {
name: "C",
deps: ["D"],
}
foo_module {
name: "D",
deps: ["E"],
}
foo_module {
name: "E",
}
`),
})
ctx.RegisterModuleType("foo_module", newFooModule)
ctx.RegisterModuleType("bar_module", newBarModule)
ctx.RegisterBottomUpMutator("deps", depsMutator)
_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
if len(errs) > 0 {
t.Errorf("unexpected parse errors:")
for _, err := range errs {
t.Errorf(" %s", err)
}
t.FailNow()
}
_, errs = ctx.ResolveDependencies(nil)
if len(errs) > 0 {
t.Errorf("unexpected dep errors:")
for _, err := range errs {
t.Errorf(" %s", err)
}
t.FailNow()
}
topModule := ctx.moduleGroupFromName("A", nil).modules[0]
outputDown, outputUp := walkDependencyGraph(ctx, topModule, true)
expectedDown := "BDCDE"
if outputDown != expectedDown {
t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: %s", outputDown, expectedDown)
}
expectedUp := "DEDCB"
if outputUp != expectedUp {
t.Errorf("unexpected walkDeps behaviour: %s\nup should be: %s", outputUp, expectedUp)
}
}
func TestCreateModule(t *testing.T) { func TestCreateModule(t *testing.T) {
ctx := newContext() ctx := newContext()
ctx.MockFileSystem(map[string][]byte{ ctx.MockFileSystem(map[string][]byte{
@ -312,7 +410,7 @@ func TestCreateModule(t *testing.T) {
}) })
ctx.RegisterTopDownMutator("create", createTestMutator) ctx.RegisterTopDownMutator("create", createTestMutator)
ctx.RegisterBottomUpMutator("deps", blueprintDepsMutator) ctx.RegisterBottomUpMutator("deps", depsMutator)
ctx.RegisterModuleType("foo_module", newFooModule) ctx.RegisterModuleType("foo_module", newFooModule)
ctx.RegisterModuleType("bar_module", newBarModule) ctx.RegisterModuleType("bar_module", newBarModule)