Revision: 6497
Author: [email protected]
Date: Tue Oct 27 18:11:59 2009
Log: Refactor StandardLinkerContext output/extra/file/jar implementation to  
not suck.

Patch by: spoon
Review by: me

http://code.google.com/p/google-web-toolkit/source/detail?r=6497

Added:
  /trunk/dev/core/src/com/google/gwt/dev/util/NullOutputFileSet.java
  /trunk/dev/core/src/com/google/gwt/dev/util/OutputFileSet.java
  /trunk/dev/core/src/com/google/gwt/dev/util/OutputFileSetOnDirectory.java
  /trunk/dev/core/src/com/google/gwt/dev/util/OutputFileSetOnJar.java
Modified:
   
/trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
  /trunk/dev/core/src/com/google/gwt/dev/DevMode.java
  /trunk/dev/core/src/com/google/gwt/dev/Link.java

=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/util/NullOutputFileSet.java  Tue  
Oct 27 18:11:59 2009
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may  
not
+ * use this file except in compliance with the License. You may obtain a  
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,  
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations  
under
+ * the License.
+ */
+package com.google.gwt.dev.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An {...@link OutputFileSet} that discards all data sent to it.
+ */
+public class NullOutputFileSet extends OutputFileSet {
+  private static class NullOutputStream extends OutputStream {
+    @Override
+    public void write(byte[] b) throws IOException {
+    }
+
+    @Override
+    public void write(byte[] b, int i, int j) throws IOException {
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+    }
+  }
+
+  public NullOutputFileSet() {
+    super("NULL");
+  }
+
+  @Override
+  public void close() {
+  }
+
+  @Override
+  public OutputStream openForWrite(String path, long lastModifiedTime) {
+    return new NullOutputStream();
+  }
+}
=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/util/OutputFileSet.java      Tue Oct 
 
27 18:11:59 2009
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may  
not
+ * use this file except in compliance with the License. You may obtain a  
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,  
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations  
under
+ * the License.
+ */
+package com.google.gwt.dev.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An abstract set of files that a linker links into.
+ */
+public abstract class OutputFileSet {
+  private final String pathDescription;
+
+  protected OutputFileSet(String pathDescription) {
+    this.pathDescription = pathDescription;
+  }
+
+  public abstract void close() throws IOException;
+
+  /**
+   * Return a description of this output file set's path. The precise  
meaning is
+   * unspecified, except that it should be informative when used in log
+   * messages.
+   */
+  public String getPathDescription() {
+    return pathDescription;
+  }
+
+  public abstract OutputStream openForWrite(String path, long  
lastModifiedTime)
+      throws IOException;
+}
=======================================
--- /dev/null
+++  
/trunk/dev/core/src/com/google/gwt/dev/util/OutputFileSetOnDirectory.java       
 
Tue Oct 27 18:11:59 2009
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may  
not
+ * use this file except in compliance with the License. You may obtain a  
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,  
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations  
under
+ * the License.
+ */
+package com.google.gwt.dev.util;
+
+import com.google.gwt.dev.util.collect.HashSet;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Set;
+
+/**
+ * An {...@link OutputFileSet} on a directory.
+ */
+public class OutputFileSetOnDirectory extends OutputFileSet {
+  private final Set<String> createdDirs = new HashSet<String>();
+  private final File dir;
+  private final String prefix;
+
+  public OutputFileSetOnDirectory(File dir, String prefix) {
+    super(dir.getAbsolutePath());
+    this.dir = dir;
+    this.prefix = prefix;
+  }
+
+  @Override
+  public void close() {
+  }
+
+  @Override
+  public OutputStream openForWrite(String path, long lastModifiedTime)
+      throws IOException {
+    File file = dir;
+    for (String part : (prefix + path).split("/")) {
+      file = new File(file, part);
+    }
+    mkdirs(file.getParentFile());
+    return new FileOutputStream(file);
+  }
+
+  /**
+   * A faster bulk version of {...@link File#mkdirs()} that avoids recreating  
the
+   * same directory multiple times.
+   */
+  private void mkdirs(File dir) {
+    if (dir == null) {
+      return;
+    }
+    String path = dir.getPath();
+    if (createdDirs.contains(path)) {
+      return;
+    }
+    createdDirs.add(path);
+    if (!dir.exists()) {
+      mkdirs(dir.getParentFile());
+      dir.mkdir();
+    }
+  }
+}
=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/util/OutputFileSetOnJar.java Tue  
Oct 27 18:11:59 2009
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may  
not
+ * use this file except in compliance with the License. You may obtain a  
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,  
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations  
under
+ * the License.
+ */
+package com.google.gwt.dev.util;
+
+import com.google.gwt.dev.util.collect.HashSet;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Set;
+import java.util.jar.JarOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * An {...@link OutputFileSet} on a jar file.
+ */
+public class OutputFileSetOnJar extends OutputFileSet {
+  /**
+   * An output stream on a jar entry for <code>jar</code>. It is assumed  
that
+   * the entry has already been written, so this class only has to forward  
the
+   * writes.
+   */
+  private final class OutputStreamOnJarEntry extends OutputStream {
+    @Override
+    public void close() throws IOException {
+      jar.closeEntry();
+    }
+
+    @Override
+    public void write(byte b[], int off, int len) throws IOException {
+      jar.write(b, off, len);
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+      jar.write(b);
+    }
+  }
+
+  /**
+   * Returns the parent path of forward-slash based partial path. Assumes  
the
+   * given path does not end with a trailing slash.
+   */
+  private static String getParentPath(String path) {
+    assert !path.endsWith("/");
+    int pos = path.lastIndexOf('/');
+    return (pos >= 0) ? path.substring(0, pos) : null;
+  }
+
+  private Set<String> createdDirs = new HashSet<String>();
+
+  private final JarOutputStream jar;
+
+  private final String pathPrefix;
+
+  public OutputFileSetOnJar(File jarFile, String pathPrefix) throws  
IOException {
+    super(jarFile.getAbsolutePath());
+    jarFile.delete();
+    jar = new JarOutputStream(new FileOutputStream(jarFile));
+    this.pathPrefix = pathPrefix;
+  }
+
+  @Override
+  public void close() throws IOException {
+    jar.close();
+  }
+
+  @Override
+  public OutputStream openForWrite(String path, long lastModifiedTime)
+      throws IOException {
+    mkzipDirs(getParentPath(pathPrefix + path));
+
+    ZipEntry zipEntry = new ZipEntry(pathPrefix + path);
+    if (lastModifiedTime >= 0) {
+      zipEntry.setTime(lastModifiedTime);
+    }
+    jar.putNextEntry(zipEntry);
+
+    return new OutputStreamOnJarEntry();
+  }
+
+  /**
+   * Creates directory entries within a zip archive. Uses
+   * <code>createdDirs</code> to avoid creating entries for the same path  
twice.
+   *
+   * @param path the path of a directory within the archive to create
+   */
+  private void mkzipDirs(String path) throws IOException {
+    if (path == null) {
+      return;
+    }
+    if (createdDirs.contains(path)) {
+      return;
+    }
+    mkzipDirs(getParentPath(path));
+    ZipEntry entry = new ZipEntry(path + '/');
+    entry.setSize(0);
+    entry.setCompressedSize(0);
+    entry.setCrc(0);
+    entry.setMethod(ZipOutputStream.STORED);
+    jar.putNextEntry(entry);
+    createdDirs.add(path);
+  }
+}
=======================================
---  
/trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
       
Tue Jul 28 12:27:56 2009
+++  
/trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardLinkerContext.java
       
Tue Oct 27 18:11:59 2009
@@ -51,29 +51,22 @@
  import com.google.gwt.dev.js.ast.JsProgram;
  import com.google.gwt.dev.js.ast.JsScope;
  import com.google.gwt.dev.util.DefaultTextOutput;
-import com.google.gwt.dev.util.FileBackedObject;
+import com.google.gwt.dev.util.OutputFileSet;
  import com.google.gwt.dev.util.Util;
-import com.google.gwt.util.tools.Utility;
-
-import java.io.BufferedOutputStream;
+
  import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
  import java.io.IOException;
+import java.io.OutputStream;
  import java.io.Reader;
  import java.io.StringReader;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.HashMap;
-import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
-import java.util.Set;
  import java.util.SortedSet;
  import java.util.TreeSet;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;

  /**
   * An implementation of {...@link LinkerContext} that is initialized from a
@@ -117,67 +110,6 @@
        return o1.getName().compareTo(o2.getName());
      }
    };
-
-  /**
-   * Returns the parent path of forward-slash based partial path. Assumes  
the
-   * given path does not end with a trailing slash.
-   */
-  private static String getParentPath(String path) {
-    assert !path.endsWith("/");
-    int pos = path.lastIndexOf('/');
-    return (pos >= 0) ? path.substring(0, pos) : null;
-  }
-
-  /**
-   * A faster bulk version of {...@link File#mkdirs()} that takes advantage of
-   * cached state to avoid a lot of file system access.
-   */
-  private static boolean mkdirs(File dir, Set<String> createdDirs) {
-    if (dir == null) {
-      return true;
-    }
-    String path = dir.getPath();
-    if (createdDirs.contains(path)) {
-      return true;
-    }
-    if (!dir.exists()) {
-      if (!mkdirs(dir.getParentFile(), createdDirs)) {
-        return false;
-      }
-      if (!dir.mkdir()) {
-        return false;
-      }
-    }
-    createdDirs.add(path);
-    return true;
-  }
-
-  /**
-   * Creates directory entries within a zip archive. This is consistent  
with how
-   * most tools operate.
-   *
-   * @param path the path of a directory within the archive to create
-   * @param zipOutputStream the archive we're creating
-   * @param createdDirs the set of already-created directories to avoid
-   *          duplication
-   */
-  private static void mkzipDirs(String path, ZipOutputStream  
zipOutputStream,
-      Set<String> createdDirs) throws IOException {
-    if (path == null) {
-      return;
-    }
-    if (createdDirs.contains(path)) {
-      return;
-    }
-    mkzipDirs(getParentPath(path), zipOutputStream, createdDirs);
-    ZipEntry entry = new ZipEntry(path + '/');
-    entry.setSize(0);
-    entry.setCompressedSize(0);
-    entry.setCrc(0);
-    entry.setMethod(ZipOutputStream.STORED);
-    zipOutputStream.putNextEntry(entry);
-    createdDirs.add(path);
-  }

    private final ArtifactSet artifacts = new ArtifactSet();

@@ -294,24 +226,9 @@
        configurationProperties =  
Collections.unmodifiableSortedSet(mutableConfigurationProperties);
      }

-    {
-      int index = 0;
-      for (Script script : module.getScripts()) {
-        artifacts.add(new StandardScriptReference(script.getSrc(),  
index++));
-        logger.log(TreeLogger.SPAM, "Added script " + script.getSrc(),  
null);
-      }
-    }
-
-    {
-      int index = 0;
-      for (String style : module.getStyles()) {
-        artifacts.add(new StandardStylesheetReference(style, index++));
-        logger.log(TreeLogger.SPAM, "Added style " + style, null);
-      }
-    }
-
-    // Generated files should be passed in via addArtifacts()
-
+    /*
+     * Add static resources in the specified module as artifacts.
+     */
      for (String path : module.getAllPublicFiles()) {
        String partialPath = path.replace(File.separatorChar, '/');
        PublicResource resource = new StandardPublicResource(partialPath,
@@ -319,6 +236,8 @@
        artifacts.add(resource);
        logger.log(TreeLogger.SPAM, "Added public resource " + resource,  
null);
      }
+
+    recordStaticReferences(logger, module);
    }

    /**
@@ -340,27 +259,20 @@
    /**
     * Gets or creates a CompilationResult for the given JavaScript program.
     */
-  public StandardCompilationResult getCompilation(TreeLogger logger,
-      FileBackedObject<PermutationResult> resultFile)
-      throws UnableToCompleteException {
-    PermutationResult permutationResult = resultFile.newInstance(logger);
-
+  public StandardCompilationResult getCompilation(
+      PermutationResult permutationResult) {
      byte[][] js = permutationResult.getJs();
      String strongName = Util.computeStrongName(js);
      StandardCompilationResult result = resultsByStrongName.get(strongName);
      if (result == null) {
        result = new StandardCompilationResult(strongName, js,
            permutationResult.getSerializedSymbolMap(),
-          permutationResult.getStatementRanges(),  
permutationResult.getPermutationId());
+          permutationResult.getStatementRanges(),
+          permutationResult.getPermutationId());
        resultsByStrongName.put(result.getStrongName(), result);
        artifacts.add(result);
-
-      // Add any other Permutations
-      ArtifactSet otherArtifacts = permutationResult.getArtifacts();
-      if (otherArtifacts != null) {
-        artifacts.addAll(otherArtifacts);
-      }
-    }
+    }
+    artifacts.addAll(permutationResult.getArtifacts());
      return result;
    }

@@ -500,140 +412,47 @@
    }

    /**
-   * Writes artifacts into the extra directory in the standard way.
+   * Emit EmittedArtifacts artifacts onto <code>out</code>. Does not close
+   * <code>out</code>.
     *
-   * @param logger logs the operation
-   * @param artifacts the set of artifacts to write
-   * @param extraPath optional extra path for non-deployable artifacts
-   * @throws UnableToCompleteException
+   * @param logger where to log progress
+   * @param artifacts the artifacts to emit
+   * @param emitPrivates whether to emit the private artifacts only, vs.  
the
+   *          public artifacts only
+   * @param out where to emit the artifact contents
     */
-  public void produceExtraDirectory(TreeLogger logger, ArtifactSet  
artifacts,
-      File extraPath) throws UnableToCompleteException {
-    extraPath = extraPath.getAbsoluteFile();
-    logger = logger.branch(TreeLogger.TRACE, "Writing extras into "
-        + extraPath.getPath(), null);
-
-    Set<String> createdDirs = new HashSet<String>();
+  public void produceOutput(TreeLogger logger, ArtifactSet artifacts,
+      boolean emitPrivates, OutputFileSet out) throws  
UnableToCompleteException {
+    String publicness = emitPrivates ? "private" : "public";
+    logger = logger.branch(TreeLogger.TRACE, "Linking " + publicness
+        + " artifacts into " + out.getPathDescription(), null);
+
      for (EmittedArtifact artifact : artifacts.find(EmittedArtifact.class))  
{
        TreeLogger artifactLogger = logger.branch(TreeLogger.DEBUG,
            "Emitting resource " + artifact.getPartialPath(), null);

-      if (!artifact.isPrivate()) {
+      if (artifact.isPrivate() != emitPrivates) {
          continue;
        }

-      File outFile = new File(extraPath, getExtraPathForLinker(
-          artifact.getLinker(), artifact.getPartialPath()));
-      writeArtifactToFile(artifactLogger, artifact, outFile, createdDirs);
-    }
-  }
-
-  /**
-   * Writes artifacts into an extra zip in the standard way.
-   *
-   * @param logger logs the operation
-   * @param artifacts the set of artifacts to write
-   * @param extraZip the output zip for deployable artifacts
-   * @param pathPrefix path within the zip to write into; if non-empty  
must end
-   *          with a trailing slash
-   * @throws UnableToCompleteException
-   */
-  public void produceExtraZip(TreeLogger logger, ArtifactSet artifacts,
-      File extraZip, String pathPrefix) throws UnableToCompleteException {
-    extraZip = extraZip.getAbsoluteFile();
-    logger = logger.branch(TreeLogger.TRACE, "Linking compilation into "
-        + extraZip.getPath(), null);
-
-    try {
-      Set<String> createdDirs = new HashSet<String>();
-      ZipOutputStream zipOutputStream = new ZipOutputStream(
-          new BufferedOutputStream(new FileOutputStream(extraZip)));
-      for (EmittedArtifact artifact :  
artifacts.find(EmittedArtifact.class)) {
-        TreeLogger artifactLogger = logger.branch(TreeLogger.DEBUG,
-            "Emitting resource " + artifact.getPartialPath(), null);
-
-        if (!artifact.isPrivate()) {
-          continue;
-        }
-        String path = pathPrefix
-            + getExtraPathForLinker(artifact.getLinker(),
-                artifact.getPartialPath());
-        writeArtifactToZip(artifactLogger, artifact, path, zipOutputStream,
-            createdDirs);
-      }
-      Utility.close(zipOutputStream);
-    } catch (FileNotFoundException e) {
-      logger.log(TreeLogger.ERROR, "Unable to create extra archive "
-          + extraZip.getPath(), e);
-      throw new UnableToCompleteException();
-    }
-  }
-
-  /**
-   * Writes artifacts into output directory in the standard way.
-   *
-   * @param logger logs the operation
-   * @param artifacts the set of artifacts to write
-   * @param outputPath the output path for deployable artifacts
-   * @throws UnableToCompleteException
-   */
-  public void produceOutputDirectory(TreeLogger logger, ArtifactSet  
artifacts,
-      File outputPath) throws UnableToCompleteException {
-    outputPath = outputPath.getAbsoluteFile();
-    logger = logger.branch(TreeLogger.TRACE, "Linking compilation into "
-        + outputPath.getPath(), null);
-
-    Set<String> createdDirs = new HashSet<String>();
-    for (EmittedArtifact artifact : artifacts.find(EmittedArtifact.class))  
{
-      TreeLogger artifactLogger = logger.branch(TreeLogger.DEBUG,
-          "Emitting resource " + artifact.getPartialPath(), null);
-
-      if (artifact.isPrivate()) {
-        continue;
-      }
-      File outFile = new File(outputPath, artifact.getPartialPath());
-      writeArtifactToFile(artifactLogger, artifact, outFile, createdDirs);
+      String partialPath = artifact.getPartialPath();
+      if (artifact.isPrivate()) {
+        partialPath = getExtraPathForLinker(artifact.getLinker(),  
partialPath);
+        if (partialPath.startsWith("/")) {
+          partialPath = partialPath.substring(1);
+        }
+      }
+      try {
+        OutputStream artifactStream = out.openForWrite(partialPath,
+            artifact.getLastModified());
+        artifact.writeTo(artifactLogger, artifactStream);
+        artifactStream.close();
+      } catch (IOException e) {
+        artifactLogger.log(TreeLogger.ERROR,
+            "Fatal error emitting this artifact", e);
+      }
      }
    }
-
-  /**
-   * Writes artifacts into an output zip in the standard way.
-   *
-   * @param logger logs the operation
-   * @param artifacts the set of artifacts to write
-   * @param outZip the output zip for deployable artifacts
-   * @param pathPrefix path within the zip to write into; if non-empty  
must end
-   *          with a trailing slash
-   * @throws UnableToCompleteException
-   */
-  public void produceOutputZip(TreeLogger logger, ArtifactSet artifacts,
-      File outZip, String pathPrefix) throws UnableToCompleteException {
-    outZip = outZip.getAbsoluteFile();
-    logger = logger.branch(TreeLogger.TRACE, "Linking compilation into "
-        + outZip.getPath(), null);
-
-    try {
-      ZipOutputStream zipOutputStream = new ZipOutputStream(
-          new BufferedOutputStream(new FileOutputStream(outZip)));
-      Set<String> createdDirs = new HashSet<String>();
-      for (EmittedArtifact artifact :  
artifacts.find(EmittedArtifact.class)) {
-        TreeLogger artifactLogger = logger.branch(TreeLogger.DEBUG,
-            "Emitting resource " + artifact.getPartialPath(), null);
-
-        if (artifact.isPrivate()) {
-          continue;
-        }
-        String path = pathPrefix + artifact.getPartialPath();
-        writeArtifactToZip(artifactLogger, artifact, path, zipOutputStream,
-            createdDirs);
-      }
-      Utility.close(zipOutputStream);
-    } catch (FileNotFoundException e) {
-      logger.log(TreeLogger.ERROR, "Unable to create output archive "
-          + outZip.getPath(), e);
-      throw new UnableToCompleteException();
-    }
-  }

    /**
     * Creates a linker-specific subdirectory in the module's auxiliary  
output
@@ -646,42 +465,26 @@
      return linkerShortNames.get(linkerType) + '/' + partialPath;
    }

-  private void writeArtifactToFile(TreeLogger logger, EmittedArtifact  
artifact,
-      File outFile, Set<String> createdDirs) throws  
UnableToCompleteException {
-    if (!outFile.exists()
-        || (outFile.lastModified() < artifact.getLastModified())) {
-      if (!mkdirs(outFile.getParentFile(), createdDirs)) {
-        logger.log(TreeLogger.ERROR, "Unable to create directory for  
file '"
-            + outFile.getAbsolutePath() + "'");
-      } else {
-        try {
-          FileOutputStream out = new FileOutputStream(outFile);
-          artifact.writeTo(logger, out);
-          out.close();
-        } catch (IOException e) {
-          logger.log(TreeLogger.ERROR, "Unable to create file '"
-              + outFile.getAbsolutePath() + "'", e);
-          throw new UnableToCompleteException();
-        }
-        outFile.setLastModified(artifact.getLastModified());
+  /**
+   * Record script references and CSS references that are listed in the  
module
+   * file.
+   */
+  private void recordStaticReferences(TreeLogger logger, ModuleDef module)  
{
+    {
+      int index = 0;
+      for (Script script : module.getScripts()) {
+        String url = script.getSrc();
+        artifacts.add(new StandardScriptReference(url, index++));
+        logger.log(TreeLogger.SPAM, "Added script " + url, null);
        }
      }
-  }
-
-  private void writeArtifactToZip(TreeLogger logger, EmittedArtifact  
artifact,
-      String path, ZipOutputStream zipOutputStream, Set<String>  
createdDirs)
-      throws UnableToCompleteException {
-    try {
-      mkzipDirs(getParentPath(path), zipOutputStream, createdDirs);
-      ZipEntry zipEntry = new ZipEntry(path);
-      zipEntry.setTime(artifact.getLastModified());
-      zipOutputStream.putNextEntry(zipEntry);
-      artifact.writeTo(logger, zipOutputStream);
-      zipOutputStream.closeEntry();
-    } catch (IOException e) {
-      logger.log(TreeLogger.ERROR, "Unable to write out artifact '"
-          + artifact.getPartialPath() + "'", e);
-      throw new UnableToCompleteException();
+
+    {
+      int index = 0;
+      for (String style : module.getStyles()) {
+        artifacts.add(new StandardStylesheetReference(style, index++));
+        logger.log(TreeLogger.SPAM, "Added style " + style, null);
+      }
      }
    }
  }
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/DevMode.java Fri Oct 16 20:54:44  
2009
+++ /trunk/dev/core/src/com/google/gwt/dev/DevMode.java Tue Oct 27 18:11:59  
2009
@@ -28,6 +28,9 @@
  import com.google.gwt.dev.ui.RestartServerCallback;
  import com.google.gwt.dev.ui.RestartServerEvent;
  import com.google.gwt.dev.util.InstalledHelpInfo;
+import com.google.gwt.dev.util.NullOutputFileSet;
+import com.google.gwt.dev.util.OutputFileSet;
+import com.google.gwt.dev.util.OutputFileSetOnDirectory;
  import com.google.gwt.dev.util.Util;
  import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
  import com.google.gwt.dev.util.arg.ArgHandlerLocalWorkers;
@@ -486,11 +489,26 @@
    private void produceOutput(TreeLogger logger,
        StandardLinkerContext linkerStack, ArtifactSet artifacts, ModuleDef  
module)
        throws UnableToCompleteException {
-    File moduleOutDir = new File(options.getWarDir(), module.getName());
-    linkerStack.produceOutputDirectory(logger, artifacts, moduleOutDir);
-    if (options.getExtraDir() != null) {
-      File moduleExtraDir = new File(options.getExtraDir(),  
module.getName());
-      linkerStack.produceExtraDirectory(logger, artifacts, moduleExtraDir);
+    TreeLogger linkLogger = logger.branch(TreeLogger.DEBUG, "Linking  
module '"
+        + module.getName() + "'");
+
+    try {
+      OutputFileSetOnDirectory outFileSet = new OutputFileSetOnDirectory(
+          options.getWarDir(), module.getName() + "/");
+      OutputFileSet extraFileSet = new NullOutputFileSet();
+      if (options.getExtraDir() != null) {
+        extraFileSet = new OutputFileSetOnDirectory(options.getExtraDir(),
+            module.getName() + "/");
+      }
+
+      linkerStack.produceOutput(linkLogger, artifacts, false, outFileSet);
+      linkerStack.produceOutput(linkLogger, artifacts, true, extraFileSet);
+
+      outFileSet.close();
+      extraFileSet.close();
+    } catch (IOException e) {
+      linkLogger.log(TreeLogger.ERROR, "I/O exception", e);
+      throw new UnableToCompleteException();
      }
    }

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/Link.java    Mon Aug 17 09:47:12  
2009
+++ /trunk/dev/core/src/com/google/gwt/dev/Link.java    Tue Oct 27 18:11:59  
2009
@@ -30,6 +30,10 @@
  import com.google.gwt.dev.jjs.PermutationResult;
  import com.google.gwt.dev.jjs.impl.CodeSplitter;
  import com.google.gwt.dev.util.FileBackedObject;
+import com.google.gwt.dev.util.NullOutputFileSet;
+import com.google.gwt.dev.util.OutputFileSet;
+import com.google.gwt.dev.util.OutputFileSetOnDirectory;
+import com.google.gwt.dev.util.OutputFileSetOnJar;
  import com.google.gwt.dev.util.Util;
  import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
  import com.google.gwt.dev.util.arg.ArgHandlerWarDir;
@@ -86,8 +90,8 @@
        LinkOptions {

      private File extraDir;
-    private File warDir;
      private File outDir;
+    private File warDir;

      public LinkOptionsImpl() {
      }
@@ -133,24 +137,31 @@
    public static void legacyLink(TreeLogger logger, ModuleDef module,
        ArtifactSet generatedArtifacts, Permutation[] permutations,
        List<FileBackedObject<PermutationResult>> resultFiles, File outDir,
-      JJSOptions precompileOptions) throws UnableToCompleteException {
+      JJSOptions precompileOptions) throws UnableToCompleteException,
+      IOException {
      StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
          module, precompileOptions);
      ArtifactSet artifacts = doLink(logger, linkerContext,  
generatedArtifacts,
          permutations, resultFiles);
-    doProduceLegacyOutput(logger, artifacts, linkerContext, module,  
outDir);
+    OutputFileSet outFileSet = new OutputFileSetOnDirectory(outDir,
+        module.getName() + "/");
+    OutputFileSet extraFileSet = new OutputFileSetOnDirectory(outDir,
+        module.getName() + "-aux/");
+    doProduceOutput(logger, artifacts, linkerContext, outFileSet,  
extraFileSet);
    }

    public static void link(TreeLogger logger, ModuleDef module,
        ArtifactSet generatedArtifacts, Permutation[] permutations,
        List<FileBackedObject<PermutationResult>> resultFiles, File outDir,
        File extrasDir, JJSOptions precompileOptions)
-      throws UnableToCompleteException {
+      throws UnableToCompleteException, IOException {
      StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
          module, precompileOptions);
      ArtifactSet artifacts = doLink(logger, linkerContext,  
generatedArtifacts,
          permutations, resultFiles);
-    doProduceOutput(logger, artifacts, linkerContext, module, outDir,  
extrasDir);
+    doProduceOutput(logger, artifacts, linkerContext, chooseOutputFileSet(
+        outDir, module.getName() + "/"), chooseOutputFileSet(extrasDir,
+        module.getName() + "/"));
    }

    public static void main(String[] args) {
@@ -176,6 +187,37 @@
      // Exit w/ non-success code.
      System.exit(1);
    }
+
+  /**
+   * Choose an output file set for the given <code>dirOrJar</code> based on
+   * its name, whether it's null, and whether it already exists as a  
directory.
+   */
+  private static OutputFileSet chooseOutputFileSet(File dirOrJar,
+      String pathPrefix) throws IOException {
+    return chooseOutputFileSet(dirOrJar, pathPrefix, pathPrefix);
+  }
+
+  /**
+   * A version of {...@link #chooseOutputFileSet(File, String)} that allows
+   * choosing a separate path prefix depending on whether the output is a
+   * directory or a jar file.
+   */
+  private static OutputFileSet chooseOutputFileSet(File dirOrJar,
+      String jarPathPrefix, String dirPathPrefix) throws IOException {
+
+    if (dirOrJar == null) {
+      return new NullOutputFileSet();
+    }
+
+    String name = dirOrJar.getName();
+    if (!dirOrJar.isDirectory()
+        && (name.endsWith(".war") || name.endsWith(".jar") ||  
name.endsWith(".zip"))) {
+      return new OutputFileSetOnJar(dirOrJar, jarPathPrefix);
+    } else {
+      Util.recursiveDelete(new File(dirOrJar, dirPathPrefix), true);
+      return new OutputFileSetOnDirectory(dirOrJar, dirPathPrefix);
+    }
+  }

    private static ArtifactSet doLink(TreeLogger logger,
        StandardLinkerContext linkerContext, ArtifactSet generatedArtifacts,
@@ -194,52 +236,26 @@
      return linkerContext.invokeLink(logger);
    }

-  private static void doProduceLegacyOutput(TreeLogger logger,
-      ArtifactSet artifacts, StandardLinkerContext linkerContext,
-      ModuleDef module, File outDir) throws UnableToCompleteException {
-    File moduleOutDir = new File(outDir, module.getName());
-    File moduleExtraDir = new File(outDir, module.getName() + "-aux");
-    Util.recursiveDelete(moduleOutDir, true);
-    Util.recursiveDelete(moduleExtraDir, true);
-    linkerContext.produceOutputDirectory(logger, artifacts, moduleOutDir);
-    linkerContext.produceExtraDirectory(logger, artifacts, moduleExtraDir);
-    logger.log(TreeLogger.INFO, "Link succeeded");
-  }
-
+  /**
+   * Emit final output.
+   */
    private static void doProduceOutput(TreeLogger logger, ArtifactSet  
artifacts,
-      StandardLinkerContext linkerContext, ModuleDef module, File outDir,
-      File extraDir) throws UnableToCompleteException {
-    String outPath = outDir.getPath();
-    if (!outDir.isDirectory()
-        && (outPath.endsWith(".war") || outPath.endsWith(".jar") ||  
outPath.endsWith(".zip"))) {
-      linkerContext.produceOutputZip(logger, artifacts, outDir,
-          module.getName() + '/');
-    } else {
-      File moduleOutDir = new File(outDir, module.getName());
-      Util.recursiveDelete(moduleOutDir, true);
-      linkerContext.produceOutputDirectory(logger, artifacts,  
moduleOutDir);
-    }
-
-    if (extraDir != null) {
-      String extraPath = extraDir.getPath();
-      if (!extraDir.isDirectory()
-          && (extraPath.endsWith(".war") || extraPath.endsWith(".jar") ||  
extraPath.endsWith(".zip"))) {
-        linkerContext.produceExtraZip(logger, artifacts, extraDir,
-            module.getName() + '/');
-      } else {
-        File moduleExtraDir = new File(extraDir, module.getName());
-        Util.recursiveDelete(moduleExtraDir, true);
-        linkerContext.produceExtraDirectory(logger, artifacts,  
moduleExtraDir);
-      }
-    }
+      StandardLinkerContext linkerContext, OutputFileSet outFileSet,
+      OutputFileSet extraFileSet) throws UnableToCompleteException,  
IOException {
+    linkerContext.produceOutput(logger, artifacts, false, outFileSet);
+    linkerContext.produceOutput(logger, artifacts, true, extraFileSet);
+
+    outFileSet.close();
+    extraFileSet.close();
+
      logger.log(TreeLogger.INFO, "Link succeeded");
    }

    private static void finishPermuation(TreeLogger logger, Permutation perm,
        FileBackedObject<PermutationResult> resultFile,
        StandardLinkerContext linkerContext) throws  
UnableToCompleteException {
-    StandardCompilationResult compilation = linkerContext.getCompilation(
-        logger, resultFile);
+    PermutationResult permutationResult = resultFile.newInstance(logger);
+    StandardCompilationResult compilation =  
linkerContext.getCompilation(permutationResult);
      StaticPropertyOracle[] propOracles = perm.getPropertyOracles();
      for (StaticPropertyOracle propOracle : propOracles) {
        BindingProperty[] orderedProps = propOracle.getOrderedProps();
@@ -311,6 +327,35 @@
        }

        ModuleDef module = ModuleDefLoader.loadFromClassPath(logger,  
moduleName);
+
+      OutputFileSet outFileSet;
+      OutputFileSet extraFileSet;
+      try {
+        if (options.getOutDir() == null) {
+          outFileSet = chooseOutputFileSet(options.getWarDir(),
+              module.getName() + "/");
+          extraFileSet = chooseOutputFileSet(options.getExtraDir(),
+              module.getName() + "/");
+        } else {
+          outFileSet = chooseOutputFileSet(options.getOutDir(),
+              module.getName() + "/");
+          if (options.getExtraDir() != null) {
+            extraFileSet = chooseOutputFileSet(options.getExtraDir(),
+                module.getName() + "-aux/", "");
+          } else if (outFileSet instanceof OutputFileSetOnDirectory) {
+            // Automatically emit extras into the output directory, if  
it's in
+            // fact a directory
+            extraFileSet = chooseOutputFileSet(options.getOutDir(),
+                module.getName() + "-aux/");
+          } else {
+            extraFileSet = new NullOutputFileSet();
+          }
+        }
+      } catch (IOException e) {
+        logger.log(TreeLogger.ERROR,
+            "Unexpected exception while producing output", e);
+        throw new UnableToCompleteException();
+      }

        if (precomps.isEmpty()) {
          logger.log(TreeLogger.ERROR, "No precompilation files found in '"
@@ -359,12 +404,12 @@
        ArtifactSet artifacts = doLink(branch, linkerContext,  
generatedArtifacts,
            perms, resultFiles);

-      if (options.getOutDir() == null) {
-        doProduceOutput(branch, artifacts, linkerContext, module,
-            options.getWarDir(), options.getExtraDir());
-      } else {
-        doProduceLegacyOutput(branch, artifacts, linkerContext, module,
-            options.getOutDir());
+      try {
+        doProduceOutput(branch, artifacts, linkerContext, outFileSet,
+            extraFileSet);
+      } catch (IOException e) {
+        logger.log(TreeLogger.ERROR,
+            "Unexpected exception while producing output", e);
        }
      }
      return true;

--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to