Better Soong namespace support in the RBC runtime.

Includes:
* Defining namespace again should have no effect
* Allow appending to a variable defined in a namespace
* Consistent naming
* Print namespace variable assignments even if they are empty

Bug: 200297238
Test: rbcrun make/build/tests/run.rbc
Change-Id: I64aa22c4498ae89e4bc3a077d6206ad37d5c7c38
diff --git a/core/product_config.rbc b/core/product_config.rbc
index bcb031f..49a1754 100644
--- a/core/product_config.rbc
+++ b/core/product_config.rbc
@@ -83,7 +83,10 @@
                     if _options.format == "make":
                         print("SOONG_CONFIG_" + nsname, ":=", " ".join(nsvars.keys()))
                     for var, val in sorted(nsvars.items()):
-                        __print_attr("SOONG_CONFIG_%s_%s" % (nsname, var), val)
+                        if val:
+                            __print_attr("SOONG_CONFIG_%s_%s" % (nsname, var), val)
+                        else:
+                            print("SOONG_CONFIG_%s_%s :=" % (nsname, var))
             elif attr not in globals_base or globals_base[attr] != val:
                 __print_attr(attr, val)
 
@@ -279,19 +282,30 @@
     """Returns configuration item for the inherited module."""
     return (pcm_name,)
 
-def _add_soong_config_namespace(g, nsname):
-    """Adds given namespace."""
+def _soong_config_namespace(g, nsname):
+    """Adds given namespace if it does not exist."""
 
+    if g[_soong_config_namespaces_key].get(nsname):
+        return
     # A value cannot be updated, so we need to create a new dictionary
     old = g[_soong_config_namespaces_key]
     g[_soong_config_namespaces_key] = dict([(k,v) for k,v in old.items()] + [(nsname, {})])
 
-def _add_soong_config_var_value(g, nsname, var, value):
-    """Defines a variable and adds it to the given namespace."""
-    ns = g[_soong_config_namespaces_key].get(nsname)
-    if ns == None:
-        fail("no such namespace: " + nsname)
-    ns[var] = value
+def _soong_config_set(g, nsname, var, value):
+    """Assigns the value to the variable in the namespace."""
+    _soong_config_namespace(g, nsname)
+    g[_soong_config_namespaces_key][nsname][var]=value
+
+def _soong_config_append(g, nsname, var, value):
+    """Appends to the value of the variable in the namespace."""
+    _soong_config_namespace(g, nsname)
+    ns = g[_soong_config_namespaces_key][nsname]
+    oldv = ns.get(var)
+    if oldv == None:
+        ns[var] = value
+    else:
+        ns[var] += " " + value
+
 
 def _abspath(path):
     """Provided for compatibility, to be removed later."""
@@ -601,8 +615,9 @@
 # Settings used during debugging.
 _options = __get_options()
 rblf = struct(
-    add_soong_config_namespace = _add_soong_config_namespace,
-    add_soong_config_var_value = _add_soong_config_var_value,
+    soong_config_namespace = _soong_config_namespace,
+    soong_config_append = _soong_config_append,
+    soong_config_set = _soong_config_set,
     abspath = _abspath,
     addprefix = _addprefix,
     addsuffix = _addsuffix,
diff --git a/tests/device.rbc b/tests/device.rbc
index feefcf7..1aa2290 100644
--- a/tests/device.rbc
+++ b/tests/device.rbc
@@ -23,12 +23,11 @@
 ### PRODUCT_PACKAGES += dev_after
 ### PRODUCT_COPY_FILES += $(call find-copy-subdir-files,audio_platform_info*.xml,device/google/redfin/audio,$(TARGET_COPY_OUT_VENDOR)/etc) xyz:/etc/xyz
 ### PRODUCT_COPY_FILES += $(call copy-files,x.xml y.xml,/etc)
-### $(call add_soong_namespace,NS1)
-### $(call add_soong_config_var_value,NS1,v1,abc)
-### $(call add_soong_config_var_value,NS1,v2,def)
-### $(call add_soong_namespace,NS2)
+### $(call add_soong_config_namespace,NS1)
+### $(call soong_config_append,NS1,v1,abc)
+### $(call soong_config_append,NS1,v2,def)
 ### $(call add_soong_config_var_value,NS2,v3,abc)
-### $(call add_soong_config_var_value,NS2,v3,xyz)
+### $(call soong_config_set,NS2,v3,xyz)
 
 load("//build/make/core:product_config.rbc", "rblf")
 load(":part1.rbc", _part1_init = "init")
@@ -50,10 +49,9 @@
   cfg["PRODUCT_COPY_FILES"] += rblf.copy_files("x.xml y.xml", "/etc")
   cfg["PRODUCT_COPY_FILES"] += rblf.copy_files(["from/sub/x", "from/sub/y"], "to")
 
-  rblf.add_soong_config_namespace(g, "NS1")
-  rblf.add_soong_config_var_value(g, "NS1", "v1", "abc")
-  rblf.add_soong_config_var_value(g, "NS1", "v2", "def")
-  rblf.add_soong_config_namespace(g, "NS2")
-  rblf.add_soong_config_var_value(g, "NS2", "v3", "abc")
-  rblf.add_soong_config_var_value(g, "NS2", "v3", "xyz")
+  rblf.soong_config_namespace(g, "NS1")
+  rblf.soong_config_append(g, "NS1", "v1", "abc")
+  rblf.soong_config_append(g, "NS1", "v2", "def")
+  rblf.soong_config_set(g, "NS2", "v3", "abc")
+  rblf.soong_config_set(g, "NS2", "v3", "xyz")
 
diff --git a/tests/part1.rbc b/tests/part1.rbc
index 3e50751..ae79d32 100644
--- a/tests/part1.rbc
+++ b/tests/part1.rbc
@@ -26,3 +26,5 @@
   cfg["PRODUCT_COPY_FILES"] += ["part_from:part_to"]
   rblf.setdefault(handle, "PRODUCT_PRODUCT_PROPERTIES")
   cfg["PRODUCT_PRODUCT_PROPERTIES"] += ["part_properties"]
+  rblf.soong_config_namespace(g, "NS1")
+  rblf.soong_config_append(g, "NS1", "v1", "abc_part1")
diff --git a/tests/run.rbc b/tests/run.rbc
index eef217b..6dcd37c 100644
--- a/tests/run.rbc
+++ b/tests/run.rbc
@@ -80,7 +80,7 @@
 assert_eq(
     {
         "NS1": {
-            "v1": "abc",
+            "v1": "abc abc_part1",
             "v2": "def"
         },
         "NS2": {