Package com.google.gwt.dev

Source Code of com.google.gwt.dev.Link

/*
* Copyright 2008 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;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.core.ext.linker.impl.StandardCompilationResult;
import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
import com.google.gwt.dev.CompileTaskRunner.CompileTask;
import com.google.gwt.dev.Precompile.PrecompileOptions;
import com.google.gwt.dev.cfg.BindingProperty;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.cfg.StaticPropertyOracle;
import com.google.gwt.dev.jjs.JJSOptions;
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;
import com.google.gwt.dev.util.arg.OptionExtraDir;
import com.google.gwt.dev.util.arg.OptionOutDir;
import com.google.gwt.dev.util.arg.OptionWarDir;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Performs the last phase of compilation, merging the compilation outputs.
*/
public class Link {
  /**
   * Options for Link.
   */
  @Deprecated
  public interface LegacyLinkOptions extends CompileTaskOptions, OptionOutDir {
  }

  /**
   * Options for Link.
   */
  public interface LinkOptions extends CompileTaskOptions, OptionExtraDir,
      OptionWarDir, LegacyLinkOptions {
  }

  static class ArgProcessor extends CompileArgProcessor {
    @SuppressWarnings("deprecation")
    public ArgProcessor(LinkOptions options) {
      super(options);
      registerHandler(new ArgHandlerExtraDir(options));
      registerHandler(new ArgHandlerWarDir(options));
      registerHandler(new ArgHandlerOutDirDeprecated(options));
    }

    @Override
    protected String getName() {
      return Link.class.getName();
    }
  }

  /**
   * Concrete class to implement link options.
   */
  static class LinkOptionsImpl extends CompileTaskOptionsImpl implements
      LinkOptions {

    private File extraDir;
    private File outDir;
    private File warDir;

    public LinkOptionsImpl() {
    }

    public LinkOptionsImpl(LinkOptions other) {
      copyFrom(other);
    }

    public void copyFrom(LinkOptions other) {
      super.copyFrom(other);
      setExtraDir(other.getExtraDir());
      setWarDir(other.getWarDir());
      setOutDir(other.getOutDir());
    }

    public File getExtraDir() {
      return extraDir;
    }

    @Deprecated
    public File getOutDir() {
      return outDir;
    }

    public File getWarDir() {
      return warDir;
    }

    public void setExtraDir(File extraDir) {
      this.extraDir = extraDir;
    }

    @Deprecated
    public void setOutDir(File outDir) {
      this.outDir = outDir;
    }

    public void setWarDir(File warDir) {
      this.warDir = warDir;
    }
  }

  public static void legacyLink(TreeLogger logger, ModuleDef module,
      ArtifactSet generatedArtifacts,
      List<FileBackedObject<PermutationResult>> resultFiles, File outDir,
      JJSOptions precompileOptions) throws UnableToCompleteException,
      IOException {
    StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
        module, precompileOptions);
    ArtifactSet artifacts = doLink(logger, linkerContext, generatedArtifacts,
        resultFiles);
    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,
      List<FileBackedObject<PermutationResult>> resultFiles, File outDir,
      File extrasDir, JJSOptions precompileOptions)
      throws UnableToCompleteException, IOException {
    StandardLinkerContext linkerContext = new StandardLinkerContext(logger,
        module, precompileOptions);
    ArtifactSet artifacts = doLink(logger, linkerContext, generatedArtifacts,
        resultFiles);
    doProduceOutput(logger, artifacts, linkerContext, chooseOutputFileSet(
        outDir, module.getName() + "/"), chooseOutputFileSet(extrasDir,
        module.getName() + "/"));
  }

  public static void main(String[] args) {
    /*
     * NOTE: main always exits with a call to System.exit to terminate any
     * non-daemon threads that were started in Generators. Typically, this is to
     * shutdown AWT related threads, since the contract for their termination is
     * still implementation-dependent.
     */
    final LinkOptions options = new LinkOptionsImpl();

    if (new ArgProcessor(options).processArgs(args)) {
      CompileTask task = new CompileTask() {
        public boolean run(TreeLogger logger) throws UnableToCompleteException {
          return new Link(options).run(logger);
        }
      };
      if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
        // Exit w/ success code.
        System.exit(0);
      }
    }
    // Exit w/ non-success code.
    System.exit(1);
  }

  /**
   * Add to a compilation result all of the selection permutations from its
   * associated permutation.
   */
  private static void addSelectionPermutations(
      StandardCompilationResult compilation, Permutation perm,
      StandardLinkerContext linkerContext) {
    for (StaticPropertyOracle propOracle : perm.getPropertyOracles()) {
      compilation.addSelectionPermutation(computeSelectionPermutation(
          linkerContext, propOracle));
    }
  }

  /**
   * 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);
    }
  }

  /**
   * Return a map giving the value of each non-trivial selection property.
   */
  private static Map<SelectionProperty, String> computeSelectionPermutation(
      StandardLinkerContext linkerContext, StaticPropertyOracle propOracle) {
    BindingProperty[] orderedProps = propOracle.getOrderedProps();
    String[] orderedPropValues = propOracle.getOrderedPropValues();
    Map<SelectionProperty, String> unboundProperties = new HashMap<SelectionProperty, String>();
    for (int i = 0; i < orderedProps.length; i++) {
      SelectionProperty key = linkerContext.getProperty(orderedProps[i].getName());
      if (key.tryGetValue() != null) {
        /*
         * The view of the Permutation doesn't include properties with defined
         * values.
         */
        continue;
      } else if (key.isDerived()) {
        /*
         * The property provider does not need to be invoked, because the value
         * is determined entirely by other properties.
         */
        continue;
      }
      unboundProperties.put(key, orderedPropValues[i]);
    }
    return unboundProperties;
  }

  private static ArtifactSet doLink(TreeLogger logger,
      StandardLinkerContext linkerContext, ArtifactSet generatedArtifacts,
      List<FileBackedObject<PermutationResult>> resultFiles)
      throws UnableToCompleteException {
    linkerContext.addOrReplaceArtifacts(generatedArtifacts);
    for (FileBackedObject<PermutationResult> resultFile : resultFiles) {
      PermutationResult result = resultFile.newInstance(logger);
      finishPermutation(logger, result.getPermutation(), result, linkerContext);
    }
    return linkerContext.invokeLink(logger);
  }

  /**
   * Emit final output.
   */
  private static void doProduceOutput(TreeLogger logger, ArtifactSet artifacts,
      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");
  }

  /**
   * Add a compilation to a linker context.
   */
  private static void finishPermutation(TreeLogger logger, Permutation perm,
      PermutationResult permResult, StandardLinkerContext linkerContext) {
    StandardCompilationResult compilation = linkerContext.getCompilation(permResult);
    addSelectionPermutations(compilation, perm, linkerContext);
    logScriptSize(logger, perm.getId(), compilation);
  }

  /**
   * Logs the total script size for this permutation, as calculated by
   * {@link CodeSplitter#totalScriptSize(int[])}.
   */
  private static void logScriptSize(TreeLogger logger, int permId,
      StandardCompilationResult compilation) {
    if (!logger.isLoggable(TreeLogger.TRACE)) {
      return;
    }

    String[] javaScript = compilation.getJavaScript();

    int[] jsLengths = new int[javaScript.length];
    for (int i = 0; i < javaScript.length; i++) {
      jsLengths[i] = javaScript[i].length();
    }

    int totalSize = CodeSplitter.totalScriptSize(jsLengths);

    logger.log(TreeLogger.TRACE, "Permutation " + permId + " (strong name "
        + compilation.getStrongName() + ") has an initial download size of "
        + javaScript[0].length() + " and total script size of " + totalSize);
  }

  private final LinkOptionsImpl options;

  public Link(LinkOptions options) {
    this.options = new LinkOptionsImpl(options);
  }

  public boolean run(TreeLogger logger) throws UnableToCompleteException {
    for (String moduleName : options.getModuleNames()) {
      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();
      }

      List<Permutation> permsList = new ArrayList<Permutation>();
      ArtifactSet generatedArtifacts = new ArtifactSet();
      JJSOptions precompileOptions = null;

      File compilerWorkDir = options.getCompilerWorkDir(moduleName);
      List<Integer> permutationIds = new ArrayList<Integer>();
      PrecompilationResult precompileResults;
      try {
        precompileResults = Util.readFileAsObject(new File(compilerWorkDir,
            Precompile.PRECOMPILE_FILENAME), PrecompilationResult.class);
      } catch (ClassNotFoundException e) {
        logger.log(TreeLogger.ERROR, "Error reading "
            + Precompile.PRECOMPILE_FILENAME);
        return false;
      } catch (IOException e) {
        logger.log(TreeLogger.ERROR, "Error reading "
            + Precompile.PRECOMPILE_FILENAME);
        return false;
      }

      if (precompileResults instanceof PrecompileOptions) {
        /**
         * Precompiling happened on the shards.
         */
        precompileOptions = (JJSOptions) precompileResults;
        int numPermutations = module.getProperties().numPermutations();
        for (int i = 0; i < numPermutations; ++i) {
          permutationIds.add(i);
        }
      } else {
        /**
         * Precompiling happened on the start node.
         */
        Precompilation precompilation = (Precompilation) precompileResults;
        permsList.addAll(Arrays.asList(precompilation.getPermutations()));
        generatedArtifacts.addAll(precompilation.getGeneratedArtifacts());
        precompileOptions = precompilation.getUnifiedAst().getOptions();

        for (Permutation perm : precompilation.getPermutations()) {
          permutationIds.add(perm.getId());
        }
      }

      List<FileBackedObject<PermutationResult>> resultFiles = new ArrayList<FileBackedObject<PermutationResult>>(
          permutationIds.size());
      for (int id : permutationIds) {
        File f = CompilePerms.makePermFilename(compilerWorkDir, id);
        if (!f.exists()) {
          logger.log(TreeLogger.ERROR, "File not found '" + f.getAbsolutePath()
              + "'; please compile all permutations");
          return false;
        }
        resultFiles.add(new FileBackedObject<PermutationResult>(
            PermutationResult.class, f));
      }

      TreeLogger branch = logger.branch(TreeLogger.INFO, "Linking module "
          + module.getName());
      StandardLinkerContext linkerContext = new StandardLinkerContext(branch,
          module, precompileOptions);

      ArtifactSet artifacts = doLink(branch, linkerContext, generatedArtifacts,
          resultFiles);
      try {
        doProduceOutput(branch, artifacts, linkerContext, outFileSet,
            extraFileSet);
      } catch (IOException e) {
        logger.log(TreeLogger.ERROR,
            "Unexpected exception while producing output", e);
      }
    }
    return true;
  }
}
TOP

Related Classes of com.google.gwt.dev.Link

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.