Parse environment options from the command line

Make supports specifying all types of variables on the command line
(using =, :=, +=, and other variable references. When running soong_ui
through make/makeparallel these all effectively become environment
variables.

So in preparation to remove the Make wrapper, support a simplified form
of this syntax, roughly equivalent to what the shell supports if
specified before the command (<NAME>=<VALUE>).

Test: m -j blueprint_tools
Change-Id: I08fa2b86710f282e619b0cc324a3e5bbaf62d26e
diff --git a/ui/build/config.go b/ui/build/config.go
index 925b153..a451cfe 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -176,6 +176,8 @@
 			} else {
 				ctx.Fatalln("Unknown option:", arg)
 			}
+		} else if k, v, ok := decodeKeyValue(arg); ok && len(k) > 0 {
+			c.environ.Set(k, v)
 		} else {
 			c.arguments = append(c.arguments, arg)
 		}
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index b2a4dd8..e4eab94 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -103,3 +103,72 @@
 		})
 	}
 }
+
+func TestConfigParseArgsVars(t *testing.T) {
+	ctx := testContext()
+
+	testCases := []struct {
+		env  []string
+		args []string
+
+		expectedEnv []string
+		remaining   []string
+	}{
+		{},
+		{
+			env: []string{"A=bc"},
+
+			expectedEnv: []string{"A=bc"},
+		},
+		{
+			args: []string{"abc"},
+
+			remaining: []string{"abc"},
+		},
+
+		{
+			args: []string{"A=bc"},
+
+			expectedEnv: []string{"A=bc"},
+		},
+		{
+			env:  []string{"A=a"},
+			args: []string{"A=bc"},
+
+			expectedEnv: []string{"A=bc"},
+		},
+
+		{
+			env:  []string{"A=a"},
+			args: []string{"A=", "=b"},
+
+			expectedEnv: []string{"A="},
+			remaining:   []string{"=b"},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(strings.Join(tc.args, " "), func(t *testing.T) {
+			defer logger.Recover(func(err error) {
+				t.Fatal(err)
+			})
+
+			e := Environment(tc.env)
+			c := &configImpl{
+				environ: &e,
+			}
+			c.parseArgs(ctx, tc.args)
+
+			if !reflect.DeepEqual([]string(*c.environ), tc.expectedEnv) {
+				t.Errorf("for env=%q args=%q, environment:\nwant: %q\n got: %q\n",
+					tc.env, tc.args,
+					tc.expectedEnv, []string(*c.environ))
+			}
+			if !reflect.DeepEqual(c.arguments, tc.remaining) {
+				t.Errorf("for env=%q args=%q, remaining arguments:\nwant: %q\n got: %q\n",
+					tc.env, tc.args,
+					tc.remaining, c.arguments)
+			}
+		})
+	}
+}