Add Validations support to Blueprint

The Android fork of Ninja supports "validations", a node that is
added to the top level of the build graph whenever another node
is in the build graph.  Add support in Blueprint to specify them
on build statements and write them to the ninja.

Test: ninja_writer_test.go
Change-Id: I87cd1281dbd2ed113cc26a265c50d20c65118c91
diff --git a/live_tracker.go b/live_tracker.go
index 40e1930..1d48e58 100644
--- a/live_tracker.go
+++ b/live_tracker.go
@@ -68,6 +68,11 @@
 		return err
 	}
 
+	err = l.addNinjaStringListDeps(def.Validations)
+	if err != nil {
+		return err
+	}
+
 	for _, value := range def.Variables {
 		err = l.addNinjaStringDeps(value)
 		if err != nil {
diff --git a/ninja_defs.go b/ninja_defs.go
index c5d0e4b..8c5db57 100644
--- a/ninja_defs.go
+++ b/ninja_defs.go
@@ -87,6 +87,7 @@
 	Inputs          []string          // The list of explicit input dependencies.
 	Implicits       []string          // The list of implicit input dependencies.
 	OrderOnly       []string          // The list of order-only dependencies.
+	Validations     []string          // The list of validations to run when this rule runs.
 	Args            map[string]string // The variable/value pairs to set.
 	Optional        bool              // Skip outputting a default statement
 }
@@ -257,6 +258,7 @@
 	Inputs          []ninjaString
 	Implicits       []ninjaString
 	OrderOnly       []ninjaString
+	Validations     []ninjaString
 	Args            map[Variable]ninjaString
 	Variables       map[string]ninjaString
 	Optional        bool
@@ -314,6 +316,11 @@
 		return nil, fmt.Errorf("error parsing OrderOnly param: %s", err)
 	}
 
+	b.Validations, err = parseNinjaStrings(scope, params.Validations)
+	if err != nil {
+		return nil, fmt.Errorf("error parsing Validations param: %s", err)
+	}
+
 	b.Optional = params.Optional
 
 	if params.Depfile != "" {
@@ -373,6 +380,7 @@
 		explicitDeps  = valueList(b.Inputs, pkgNames, inputEscaper)
 		implicitDeps  = valueList(b.Implicits, pkgNames, inputEscaper)
 		orderOnlyDeps = valueList(b.OrderOnly, pkgNames, inputEscaper)
+		validations   = valueList(b.Validations, pkgNames, inputEscaper)
 	)
 
 	if b.RuleDef != nil {
@@ -380,7 +388,7 @@
 		orderOnlyDeps = append(valueList(b.RuleDef.CommandOrderOnly, pkgNames, inputEscaper), orderOnlyDeps...)
 	}
 
-	err := nw.Build(comment, rule, outputs, implicitOuts, explicitDeps, implicitDeps, orderOnlyDeps)
+	err := nw.Build(comment, rule, outputs, implicitOuts, explicitDeps, implicitDeps, orderOnlyDeps, validations)
 	if err != nil {
 		return err
 	}
diff --git a/ninja_writer.go b/ninja_writer.go
index 5366f3f..5e69c08 100644
--- a/ninja_writer.go
+++ b/ninja_writer.go
@@ -104,7 +104,7 @@
 }
 
 func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts,
-	explicitDeps, implicitDeps, orderOnlyDeps []string) error {
+	explicitDeps, implicitDeps, orderOnlyDeps, validations []string) error {
 
 	n.justDidBlankLine = false
 
@@ -161,6 +161,14 @@
 		}
 	}
 
+	if len(validations) > 0 {
+		wrapper.WriteStringWithSpace("|@")
+
+		for _, dep := range validations {
+			wrapper.WriteStringWithSpace(dep)
+		}
+	}
+
 	return wrapper.Flush()
 }
 
diff --git a/ninja_writer_test.go b/ninja_writer_test.go
index cc880e5..48ecb7c 100644
--- a/ninja_writer_test.go
+++ b/ninja_writer_test.go
@@ -50,9 +50,9 @@
 	{
 		input: func(w *ninjaWriter) {
 			ck(w.Build("foo comment", "foo", []string{"o1", "o2"}, []string{"io1", "io2"},
-				[]string{"e1", "e2"}, []string{"i1", "i2"}, []string{"oo1", "oo2"}))
+				[]string{"e1", "e2"}, []string{"i1", "i2"}, []string{"oo1", "oo2"}, []string{"v1", "v2"}))
 		},
-		output: "# foo comment\nbuild o1 o2 | io1 io2: foo e1 e2 | i1 i2 || oo1 oo2\n",
+		output: "# foo comment\nbuild o1 o2 | io1 io2: foo e1 e2 | i1 i2 || oo1 oo2 |@ v1 v2\n",
 	},
 	{
 		input: func(w *ninjaWriter) {
@@ -94,7 +94,7 @@
 			ck(w.ScopedAssign("command", "echo out: $out in: $in _arg: $_arg"))
 			ck(w.ScopedAssign("pool", "p"))
 			ck(w.BlankLine())
-			ck(w.Build("r comment", "r", []string{"foo.o"}, nil, []string{"foo.in"}, nil, nil))
+			ck(w.Build("r comment", "r", []string{"foo.o"}, nil, []string{"foo.in"}, nil, nil, nil))
 			ck(w.ScopedAssign("_arg", "arg value"))
 		},
 		output: `pool p