Snap for 6405781 from 5ef2a1eeaac689e76d4d6f7ec435065ed5c7f103 to sdk-release

Change-Id: I25ccfb063ce5a623abd1a1fecf3d83819d60b53a
diff --git a/bpmodify/bpmodify.go b/bpmodify/bpmodify.go
index c0bf519..29e97d1 100644
--- a/bpmodify/bpmodify.go
+++ b/bpmodify/bpmodify.go
@@ -36,6 +36,7 @@
 	flag.Var(targetedModules, "m", "comma or whitespace separated list of modules on which to operate")
 	flag.Var(addIdents, "a", "comma or whitespace separated list of identifiers to add")
 	flag.Var(removeIdents, "r", "comma or whitespace separated list of identifiers to remove")
+	flag.Usage = usage
 }
 
 var (
@@ -48,9 +49,8 @@
 }
 
 func usage() {
-	fmt.Fprintln(os.Stderr, "usage: bpmodify [flags] [path ...]")
+	fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [flags] [path ...]\n", os.Args[0])
 	flag.PrintDefaults()
-	os.Exit(2)
 }
 
 // If in == nil, the source is the contents of the file with the given filename.
@@ -223,12 +223,18 @@
 }
 
 func main() {
+	defer func() {
+		if err := recover(); err != nil {
+			report(fmt.Errorf("error: %s", err))
+		}
+		os.Exit(exitCode)
+	}()
+
 	flag.Parse()
 
 	if flag.NArg() == 0 {
 		if *write {
-			fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input")
-			exitCode = 2
+			report(fmt.Errorf("error: cannot use -w with standard input"))
 			return
 		}
 		if err := processFile("<standard input>", os.Stdin, os.Stdout); err != nil {
diff --git a/context.go b/context.go
index e99bbcb..da86837 100644
--- a/context.go
+++ b/context.go
@@ -1548,6 +1548,11 @@
 		return nil
 	}
 
+	if c.allowMissingDependencies {
+		// Allow missing variants.
+		return c.discoveredMissingDependencies(module, depName+c.prettyPrintVariant(module.dependencyVariant))
+	}
+
 	return []error{&BlueprintError{
 		Err: fmt.Errorf("dependency %q of %q missing variant:\n  %s\navailable variants:\n  %s",
 			depName, module.Name(),
@@ -1578,6 +1583,11 @@
 		return m, nil
 	}
 
+	if c.allowMissingDependencies {
+		// Allow missing variants.
+		return module, c.discoveredMissingDependencies(module, destName+c.prettyPrintVariant(module.dependencyVariant))
+	}
+
 	return nil, []error{&BlueprintError{
 		Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n  %s\navailable variants:\n  %s",
 			destName, module.Name(),
@@ -1638,6 +1648,10 @@
 	}
 
 	if foundDep == nil {
+		if c.allowMissingDependencies {
+			// Allow missing variants.
+			return c.discoveredMissingDependencies(module, depName+c.prettyPrintVariant(newVariant))
+		}
 		return []error{&BlueprintError{
 			Err: fmt.Errorf("dependency %q of %q missing variant:\n  %s\navailable variants:\n  %s",
 				depName, module.Name(),
@@ -2605,8 +2619,8 @@
 				}
 				if recurse && !visited[dep.module] {
 					walk(dep.module)
+					visited[dep.module] = true
 				}
-				visited[dep.module] = true
 				if visitUp != nil {
 					visitUp(dep, module)
 				}
diff --git a/context_test.go b/context_test.go
index d4e9bf7..0541c06 100644
--- a/context_test.go
+++ b/context_test.go
@@ -31,11 +31,40 @@
 	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 {
 	SimpleName
 	properties struct {
-		Deps []string
-		Foo  string
+		Deps         []string
+		Ignored_deps []string
+		Foo          string
 	}
 }
 
@@ -47,10 +76,14 @@
 func (f *fooModule) GenerateBuildActions(ModuleContext) {
 }
 
-func (f *fooModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
+func (f *fooModule) Deps() []string {
 	return f.properties.Deps
 }
 
+func (f *fooModule) IgnoreDeps() []string {
+	return f.properties.Ignored_deps
+}
+
 func (f *fooModule) Foo() string {
 	return f.properties.Foo
 }
@@ -62,8 +95,9 @@
 type barModule struct {
 	SimpleName
 	properties struct {
-		Deps []string
-		Bar  bool
+		Deps         []string
+		Ignored_deps []string
+		Bar          bool
 	}
 }
 
@@ -72,10 +106,14 @@
 	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
 }
 
-func (b *barModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
+func (b *barModule) Deps() []string {
 	return b.properties.Deps
 }
 
+func (b *barModule) IgnoreDeps() []string {
+	return b.properties.Ignored_deps
+}
+
 func (b *barModule) GenerateBuildActions(ModuleContext) {
 }
 
@@ -87,6 +125,19 @@
 	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) {
 	ctx := NewContext()
 	ctx.RegisterModuleType("foo_module", newFooModule)
@@ -168,6 +219,7 @@
 
 	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:")
@@ -186,20 +238,8 @@
 		t.FailNow()
 	}
 
-	var outputDown string
-	var outputUp string
 	topModule := ctx.moduleGroupFromName("A", nil).modules[0]
-	ctx.walkDeps(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)
-		})
+	outputDown, outputUp := walkDependencyGraph(ctx, topModule, false)
 	if outputDown != "BCEFG" {
 		t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEFG", outputDown)
 	}
@@ -260,6 +300,7 @@
 
 	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:")
@@ -278,20 +319,8 @@
 		t.FailNow()
 	}
 
-	var outputDown string
-	var outputUp string
 	topModule := ctx.moduleGroupFromName("A", nil).modules[0]
-	ctx.walkDeps(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)
-		})
+	outputDown, outputUp := walkDependencyGraph(ctx, topModule, true)
 	if outputDown != "BCEGHFGG" {
 		t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEGHFGG", outputDown)
 	}
@@ -300,6 +329,75 @@
 	}
 }
 
+//                     - 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) {
 	ctx := newContext()
 	ctx.MockFileSystem(map[string][]byte{
@@ -312,7 +410,7 @@
 	})
 
 	ctx.RegisterTopDownMutator("create", createTestMutator)
-	ctx.RegisterBottomUpMutator("deps", blueprintDepsMutator)
+	ctx.RegisterBottomUpMutator("deps", depsMutator)
 
 	ctx.RegisterModuleType("foo_module", newFooModule)
 	ctx.RegisterModuleType("bar_module", newBarModule)