Keep the first and last snapshot of variables.

So we can compare our reconstruction of the variable state.

Test: treehugger
Change-Id: I9c1995f8969dcf95256aa7c05a01d0431e36caa2
diff --git a/core/dumpconfig.mk b/core/dumpconfig.mk
index cb7fbcb..dd3ef43 100644
--- a/core/dumpconfig.mk
+++ b/core/dumpconfig.mk
@@ -79,11 +79,19 @@
 #   $(2): Root nodes to import
 #   $(3): All variable names
 #   $(4): Single-value variables
-define dump-product-var-names
+#   $(5): Makefile being processed
+define dump-phase-start
 $(eval $(file >> $(DUMPCONFIG_FILE),phase,$(strip $(1)),$(strip $(2)))) \
 $(foreach var,$(3), \
     $(eval $(file >> $(DUMPCONFIG_FILE),var,$(if $(filter $(4),$(var)),single,list),$(var))) \
-)
+) \
+$(call dump-config-vals,$(strip $(5)),initial)
+endef
+
+# Args:
+#   $(1): Makefile being processed
+define dump-phase-end
+$(call dump-config-vals,$(strip $(1)),final)
 endef
 
 define dump-debug
@@ -110,7 +118,7 @@
 
 # Args:
 #   $(1): Makefile that was included
-#   $(2): block (before,import,after)
+#   $(2): block (before,import,after,initial,final)
 define dump-config-vals
 $(foreach var,$(filter-out $(DUMPCONFIG_SKIP_VARS),$(.KATI_SYMBOLS)),\
     $(eval $(file >> $(DUMPCONFIG_FILE),val,$(call escape-for-csv,$(1)),$(2),$(call escape-for-csv,$(var)),$(call escape-for-csv,$($(var))),$(call escape-for-csv,$(KATI_variable_location $(var))))) \
diff --git a/core/node_fns.mk b/core/node_fns.mk
index 878a4dd..8d20160 100644
--- a/core/node_fns.mk
+++ b/core/node_fns.mk
@@ -254,13 +254,13 @@
 #       of the default list semantics
 #
 define import-nodes
+$(call dump-phase-start,$(1),$(2),$(3),$(4),build/make/core/node_fns.mk) \
 $(if \
   $(foreach _in,$(2), \
     $(eval _node_import_context := _nic.$(1).[[$(_in)]]) \
     $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
                 should be empty here: $(_include_stack))),) \
     $(eval _include_stack := ) \
-    $(call dump-product-var-names,$(1),$(2),$(3),$(4)) \
     $(call _import-nodes-inner,$(_node_import_context),$(_in),$(3),$(4)) \
     $(call move-var-list,$(_node_import_context).$(_in),$(1).$(_in),$(3)) \
     $(eval _node_import_context :=) \
@@ -268,5 +268,6 @@
     $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
                 should be empty here: $(_include_stack))),) \
    ) \
-,)
+,) \
+$(call dump-phase-end,build/make/core/node_fns.mk)
 endef
diff --git a/tools/product_config/src/com/android/build/config/ConfigBase.java b/tools/product_config/src/com/android/build/config/ConfigBase.java
index 0c67d16..eb21219 100644
--- a/tools/product_config/src/com/android/build/config/ConfigBase.java
+++ b/tools/product_config/src/com/android/build/config/ConfigBase.java
@@ -18,6 +18,7 @@
 
 import java.io.PrintStream;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
@@ -30,6 +31,17 @@
     protected List<String> mRootNodes;
 
     /**
+     * State of the make varaible environment from before the first config file.
+     */
+    protected Map<String, Str> mInitialVariables = new HashMap();
+
+    /**
+     * State of the make varaible environment from after the first config file.
+     */
+    protected Map<String, Str> mFinalVariables = new HashMap();
+
+
+    /**
      * The variables that are handled specially.
      */
     protected final TreeMap<String, VarType> mProductVars = new TreeMap();
@@ -81,6 +93,20 @@
     }
 
     /**
+     * Return the state the make variable environment from before the first config file.
+     */
+    public Map<String, Str> getInitialVariables() {
+        return mInitialVariables;
+    }
+
+    /**
+     * Return the state the make variable environment from before the first config file.
+     */
+    public Map<String, Str> getFinalVariables() {
+        return mFinalVariables;
+    }
+
+    /**
      * Copy common base class fields from that to this.
      */
     public void copyFrom(ConfigBase that) {
@@ -89,5 +115,7 @@
         for (Map.Entry<String, ConfigBase.VarType> entry: that.getProductVars().entrySet()) {
             addProductVar(entry.getKey(), entry.getValue());
         }
+        mInitialVariables = new HashMap(that.getInitialVariables());
+        mFinalVariables = new HashMap(that.getFinalVariables());
     }
 }
diff --git a/tools/product_config/src/com/android/build/config/DumpConfigParser.java b/tools/product_config/src/com/android/build/config/DumpConfigParser.java
index 94bf205..06663ca 100644
--- a/tools/product_config/src/com/android/build/config/DumpConfigParser.java
+++ b/tools/product_config/src/com/android/build/config/DumpConfigParser.java
@@ -54,10 +54,6 @@
 
     private static final Pattern LIST_SEPARATOR = Pattern.compile("\\s+");
 
-    public class BuildPhase {
-
-    }
-
     /**
      * Constructor.
      */
@@ -120,6 +116,8 @@
         MakeConfig makeConfig = new MakeConfig();
         MakeConfig.ConfigFile configFile = new MakeConfig.ConfigFile("<ignored>");
         MakeConfig.Block block = new MakeConfig.Block(MakeConfig.BlockType.UNSET);
+        Map<String, Str> initialVariables = new HashMap();
+        Map<String, Str> finalVariables = new HashMap();
 
         // Number of "phases" we've seen so far.
         for (; index < lineCount; index++) {
@@ -128,10 +126,13 @@
             final String lineType = fields.get(0);
 
             if (matchLineType(line, "phase", 2)) {
+                // Start the new one
                 makeConfig = new MakeConfig();
                 makeConfig.setPhase(fields.get(1));
                 makeConfig.setRootNodes(splitList(fields.get(2)));
                 mResults.add(makeConfig);
+                initialVariables = makeConfig.getInitialVariables();
+                finalVariables = makeConfig.getFinalVariables();
 
                 if (DEBUG) {
                     System.out.println("PHASE:");
@@ -216,32 +217,41 @@
                 }
             } else if (matchLineType(line, "val", 5)) {
                 final String productMakefile = fields.get(1);
-                final MakeConfig.BlockType blockType = parseBlockType(line, fields.get(2));
+                final String blockTypeString = fields.get(2);
                 final String varName = fields.get(3);
                 final String varValue = fields.get(4);
                 final Position pos = Position.parse(fields.get(5));
+                final Str str = new Str(pos, varValue);
 
-                if (!productMakefile.equals(configFile.getFilename())) {
-                    mErrors.WARNING_DUMPCONFIG.add(
-                            new Position(mFilename, line.getLine()),
-                            "Mismatched 'val' product makefile."
-                                + " Expected: " + configFile.getFilename()
-                                + " Saw: " + productMakefile);
-                    continue;
+                if (blockTypeString.equals("initial")) {
+                    initialVariables.put(varName, str);
+                } else if (blockTypeString.equals("final")) {
+                    finalVariables.put(varName, str);
+                } else {
+                    if (!productMakefile.equals(configFile.getFilename())) {
+                        mErrors.WARNING_DUMPCONFIG.add(
+                                new Position(mFilename, line.getLine()),
+                                "Mismatched 'val' product makefile."
+                                    + " Expected: " + configFile.getFilename()
+                                    + " Saw: " + productMakefile);
+                        continue;
+                    }
+
+                    final MakeConfig.BlockType blockType = parseBlockType(line, blockTypeString);
+                    if (blockType == null) {
+                        continue;
+                    }
+                    if (blockType != block.getBlockType()) {
+                        mErrors.WARNING_DUMPCONFIG.add(
+                                new Position(mFilename, line.getLine()),
+                                "Mismatched 'val' block type."
+                                    + " Expected: " + block.getBlockType()
+                                    + " Saw: " + blockType);
+                    }
+
+                    // Add the variable to the block in progress
+                    block.addVar(varName, str);
                 }
-                if (blockType == null) {
-                    continue;
-                }
-                if (blockType != block.getBlockType()) {
-                    mErrors.WARNING_DUMPCONFIG.add(
-                            new Position(mFilename, line.getLine()),
-                            "Mismatched 'val' block type."
-                                + " Expected: " + block.getBlockType()
-                                + " Saw: " + blockType);
-                }
-                
-                // Add the variable to the block in progress
-                block.addVar(varName, new Str(pos, varValue));
             } else {
                 if (DEBUG) {
                     System.out.print("# ");
diff --git a/tools/product_config/src/com/android/build/config/MakeWriter.java b/tools/product_config/src/com/android/build/config/MakeWriter.java
index 8c79c46..58dfcc0 100644
--- a/tools/product_config/src/com/android/build/config/MakeWriter.java
+++ b/tools/product_config/src/com/android/build/config/MakeWriter.java
@@ -17,7 +17,10 @@
 package com.android.build.config;
 
 import java.io.PrintStream;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 public class MakeWriter {
     public static final int FLAG_WRITE_HEADER = 1;
@@ -43,6 +46,11 @@
             writeFile(out, config, file);
             out.println();
         }
+        out.println("---------------------------------------------------------");
+        out.println("VARIABLES TOUCHED BY MAKE BASED CONFIG:");
+        out.println("---------------------------------------------------------");
+        writeStrVars(out, getModifiedVars(config.getInitialVariables(),
+                                          config.getFinalVariables()), config);
     }
 
     private void writeFile(PrintStream out, GenericConfig config, GenericConfig.ConfigFile file) {
@@ -100,4 +108,48 @@
         }
         out.println();
     }
+
+    private static Map<String, Str> getModifiedVars(Map<String, Str> before,
+            Map<String, Str> after) {
+        final HashMap<String, Str> result = new HashMap();
+        // Entries that were added or changed.
+        for (Map.Entry<String, Str> afterEntry: after.entrySet()) {
+            final String varName = afterEntry.getKey();
+            final Str afterValue = afterEntry.getValue();
+            final Str beforeValue = before.get(varName);
+            if (beforeValue == null || !beforeValue.equals(afterValue)) {
+                result.put(varName, afterValue);
+            }
+        }
+        // removed Entries that were removed, we just treat them as  
+        for (Map.Entry<String, Str> beforeEntry: before.entrySet()) {
+            final String varName = beforeEntry.getKey();
+            if (!after.containsKey(varName)) {
+                result.put(varName, new Str(""));
+            }
+        }
+        return result;
+    }
+
+    private static class Var {
+        Var(String name, Str val) {
+            this.name = name;
+            this.val = val;
+        }
+        final String name;
+        final Str val;
+    }
+
+    private static void writeStrVars(PrintStream out, Map<String, Str> vars, ConfigBase config) {
+        // Sort by file name and var name
+        TreeMap<String, Var> sorted = new TreeMap();
+        for (Map.Entry<String, Str> entry: vars.entrySet()) {
+            sorted.put(entry.getValue().getPosition().toString() + " " + entry.getKey(),
+                    new Var(entry.getKey(), entry.getValue()));
+        }
+        // Print it
+        for (Var var: sorted.values()) {
+            out.println(var.val.getPosition() + var.name + " := " + var.val);
+        }
+    }
 }