The logic to avoid rewriting compilation units into archived units failed in some build environments where the output of the CompileModule tool does not end up on the classpath.   Each resulting .gwtar file contained all compilation units, regardless of whether a nested .gwtar file already contained the units.

Review at http://gwt-code-reviews.appspot.com/1518803


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10519 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/CompileModule.java b/dev/core/src/com/google/gwt/dev/CompileModule.java
index 92b0c26..f9df91a 100644
--- a/dev/core/src/com/google/gwt/dev/CompileModule.java
+++ b/dev/core/src/com/google/gwt/dev/CompileModule.java
@@ -34,6 +34,7 @@
 import com.google.gwt.dev.util.arg.OptionStrict;
 import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
 import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
+import com.google.gwt.thirdparty.guava.common.collect.Sets;
 
 import java.io.File;
 import java.io.IOException;
@@ -191,7 +192,12 @@
     // same archive twice. Key is archive URL string. Maps to the set of unit resource paths
     // for the archive.
     Map<String, Set<String>> unitsInArchives = new HashMap<String, Set<String>>();
-
+    // Modules archived by this invocation of CompileModule.  Once a compiled module is
+    // written out as an archive file, it may or may not appear on the classpath 
+    // and come back with module.getAllCompilationUnitArchiveURLs().  Thus, use a second check
+    // so that the tool doesn't redundantly write the same compilation units into
+    // multiple archives.
+    Map<String, Set<String>> newlyCompiledModules = new HashMap<String, Set<String>>();
     File outputDir = options.getOutDir();
     if (!outputDir.isDirectory() && !outputDir.mkdirs()) {
       logger.log(Type.ERROR, "Error creating directories for ouptut: "
@@ -225,6 +231,14 @@
           }
         }
 
+        // Don't re-archive previously compiled units from this invocation of CompileModule.
+        for (String compiledModuleName : newlyCompiledModules.keySet()) {
+          if (module.isInherited(compiledModuleName)) {
+            currentModuleArchivedUnits.addAll(newlyCompiledModules.get(compiledModuleName));
+          }
+        }
+
+        // Load up previously archived modules
         for (URL archiveURL : archiveURLs) {
           String archiveURLString = archiveURL.toString();
           Set<String> unitPaths = unitsInArchives.get(archiveURLString);
@@ -277,12 +291,15 @@
         return false;
       }
 
+      Set<String> compiledUnits = Sets.newHashSet();
       CompilationUnitArchive outputArchive = new CompilationUnitArchive(moduleToCompile);
       for (CompilationUnit unit : compilationState.getCompilationUnits()) {
         if (!currentModuleArchivedUnits.contains(unit.getResourcePath())) {
           outputArchive.addUnit(unit);
+          compiledUnits.add(unit.getResourcePath());
         }
       }
+      newlyCompiledModules.put(moduleToCompile, compiledUnits);
 
       String slashedModuleName =
           module.getName().replace('.', '/') + ModuleDefLoader.COMPILATION_UNIT_ARCHIVE_SUFFIX;
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
index f0accba..3b0b812 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -113,6 +113,8 @@
 
   private final Set<File> gwtXmlFiles = new HashSet<File>();
 
+  private final Set<String> inheritedModules = new HashSet<String>();
+
   /**
    * All resources found on the public path, specified by <public> directives in
    * modules (or the implicit ./public directory). Marked 'lazy' because it does not
@@ -443,6 +445,10 @@
     return lastModified() > moduleDefCreationTime;
   }
 
+  public boolean isInherited(String moduleName) {
+    return inheritedModules.contains(moduleName);
+  }
+
   public long lastModified() {
     long lastModified = 0;
     for (File xmlFile : gwtXmlFiles) {
@@ -488,6 +494,10 @@
     archiveURLs.add(url);
   }
 
+  void addInteritedModule(String moduleName) {
+    inheritedModules.add(moduleName);
+  }
+
   /**
    * The final method to call when everything is setup. Before calling this
    * method, several of the getter methods may not be called. After calling this
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
index f214a3a..94a1f7f 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
@@ -32,9 +32,7 @@
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * The top-level API for loading module XML.
@@ -180,8 +178,6 @@
     return moduleDef;
   }
 
-  private final Set<String> alreadyLoadedModules = new HashSet<String>();
-
   private final ClassLoader classLoader;
 
   private final LoadStrategy strategy;
@@ -230,20 +226,20 @@
   void nestedLoad(TreeLogger parentLogger, String moduleName, ModuleDef moduleDef)
       throws UnableToCompleteException {
 
-    if (alreadyLoadedModules.contains(moduleName)) {
+    if (moduleDef.isInherited(moduleName)) {
       // No need to parse module again.
       return;
     }
 
     TreeLogger logger = parentLogger.branch(TreeLogger.DEBUG, "Loading inherited module '" 
         + moduleName + "'", null);
-    alreadyLoadedModules.add(moduleName);
 
     if (!ModuleDef.isValidModuleName(moduleName)) {
       logger.log(TreeLogger.ERROR, "Invalid module name: '" + moduleName + "'",
           null);
       throw new UnableToCompleteException();
     }
+    moduleDef.addInteritedModule(moduleName);
 
     // Find the specified module using the classpath.
     //