private void validateServletTags(
      TreeLogger logger,
      ServletValidator servletValidator,
      ServletWriter servletWriter,
      ModuleDef module) {
    String[] servletPaths = module.getServletPaths();
    if (servletPaths.length == 0) {
      return;
    }

    TreeLogger servletLogger =
        logger.branch(
            TreeLogger.DEBUG,
            "Validating <servlet> tags for module '" + module.getName() + "'",
            null,
            new InstalledHelpInfo("servletMappings.html"));
    for (String servletPath : servletPaths) {
      String servletClass = module.findServletForPath(servletPath);
      assert (servletClass != null);
      // Prefix module name to convert module mapping to global mapping.
      servletPath = "/" + module.getName() + servletPath;
      if (servletValidator == null) {
        servletWriter.addMapping(servletClass, servletPath);
      } else {
        servletValidator.validate(servletLogger, servletClass, servletPath);
      }
    }
  }
Example #2
0
  /**
   * Creates a dummy output directory without compiling the module. Either this method or {@link
   * #precompile} should be called first.
   */
  synchronized Job.Result initWithoutPrecompile(TreeLogger logger)
      throws UnableToCompleteException {

    long startTime = System.currentTimeMillis();
    CompileDir compileDir = outboxDir.makeCompileDir(logger);
    TreeLogger compileLogger = makeCompileLogger(compileDir, logger);
    ModuleDef module;
    try {
      module = loadModule(compileLogger);

      logger.log(TreeLogger.INFO, "Loading Java files in " + inputModuleName + ".");
      CompilerOptions loadOptions = new CompilerOptionsImpl(compileDir, inputModuleName, options);
      compilerContext = compilerContextBuilder.options(loadOptions).unitCache(unitCache).build();

      // Loads and parses all the Java files in the GWT application using the JDT.
      // (This is warmup to make compiling faster later; we stop at this point to avoid
      // needing to know the binding properties.)
      module.getCompilationState(compileLogger, compilerContext);

      setUpCompileDir(compileDir, module, compileLogger);
      if (launcherDir != null) {
        launcherDir.update(module, compileDir, compileLogger);
      }

      outputModuleName.set(module.getName());
    } finally {
      // Make the compile log available no matter what happens.
      lastBuild.set(compileDir);
    }

    long elapsedTime = System.currentTimeMillis() - startTime;
    compileLogger.log(TreeLogger.Type.INFO, "Module setup completed in " + elapsedTime + " ms");

    return new Result(compileDir, module.getName(), null);
  }
  @Override
  protected synchronized void produceOutput(
      TreeLogger logger,
      StandardLinkerContext linkerStack,
      ArtifactSet artifacts,
      ModuleDef module,
      boolean isRelink)
      throws UnableToCompleteException {
    TreeLogger linkLogger =
        logger.branch(TreeLogger.DEBUG, "Linking module '" + module.getName() + "'");

    OutputFileSetOnDirectory outFileSet =
        new OutputFileSetOnDirectory(options.getWarDir(), module.getName() + "/");
    OutputFileSetOnDirectory deployFileSet =
        new OutputFileSetOnDirectory(options.getDeployDir(), module.getName() + "/");
    OutputFileSet extraFileSet = new NullOutputFileSet();
    if (options.getExtraDir() != null) {
      extraFileSet = new OutputFileSetOnDirectory(options.getExtraDir(), module.getName() + "/");
    }

    linkerStack.produceOutput(linkLogger, artifacts, Visibility.Public, outFileSet);
    linkerStack.produceOutput(linkLogger, artifacts, Visibility.Deploy, deployFileSet);
    linkerStack.produceOutput(linkLogger, artifacts, Visibility.Private, extraFileSet);

    outFileSet.close();
    deployFileSet.close();
    try {
      extraFileSet.close();
    } catch (IOException e) {
      linkLogger.log(TreeLogger.ERROR, "Error emiting extra files", e);
      throw new UnableToCompleteException();
    }
  }
  @Override
  protected boolean doSlowStartup() {
    tempWorkDir = options.getWorkDir() == null;
    if (tempWorkDir) {
      try {
        options.setWorkDir(Utility.makeTemporaryDirectory(null, "gwtc"));
      } catch (IOException e) {
        System.err.println("Unable to create hosted mode work directory");
        e.printStackTrace();
        return false;
      }
    }

    TreeLogger branch = getTopLogger().branch(TreeLogger.TRACE, "Linking modules");
    Event slowStartupEvent = SpeedTracerLogger.start(DevModeEventType.SLOW_STARTUP);
    try {
      for (ModuleDef module : startupModules.values()) {
        TreeLogger loadLogger =
            branch.branch(
                TreeLogger.DEBUG,
                "Bootstrap link for command-line module '" + module.getCanonicalName() + "'");
        link(loadLogger, module);
      }
    } catch (UnableToCompleteException e) {
      // Already logged.
      return false;
    } finally {
      slowStartupEvent.end();
    }
    return true;
  }
Example #5
0
  public void testTwoDimensionPermWithExpansion() {
    ModuleDef md = new ModuleDef("testTwoDimensionsWithExpansion");
    Properties properties = md.getProperties();

    {
      BindingProperty bindingProperty = properties.createBinding("user.agent");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "moz");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "ie6");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "ie8");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "opera");
    }

    {
      BindingProperty bindingProperty = properties.createBinding("stackTraces");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "false");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "true");
      // <set-property name="stackTraces" value="false" />
      bindingProperty.setValues(bindingProperty.getRootCondition(), "false");

      /*
       * <set-property name="stackTraces" value="true,false"> <when user.agent
       * is ie6 or ie 8> </set-property>
       */
      ConditionAny cond = new ConditionAny();
      cond.getConditions().add(new ConditionWhenPropertyIs("user.agent", "ie6"));
      cond.getConditions().add(new ConditionWhenPropertyIs("user.agent", "ie8"));
      bindingProperty.setValues(cond, "true", "false");
    }

    validateTwoDimensionPerm(properties, md.getActiveLinkerNames());
  }
Example #6
0
  public void testTwoDimensionPermWithRestriction() {
    // This is what you'd get with a conditional <set-property value="false">
    ModuleDef md = new ModuleDef("testTwoDimensionsWithRestriction");
    Properties properties = md.getProperties();

    {
      BindingProperty bindingProperty = properties.createBinding("user.agent");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "moz");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "ie6");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "ie8");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "opera");
    }

    {
      BindingProperty bindingProperty = properties.createBinding("stackTraces");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "false");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "true");

      ConditionAny cond = new ConditionAny();
      cond.getConditions().add(new ConditionWhenPropertyIs("user.agent", "moz"));
      cond.getConditions().add(new ConditionWhenPropertyIs("user.agent", "opera"));

      bindingProperty.setValues(cond, "false");
    }

    validateTwoDimensionPerm(properties, md.getActiveLinkerNames());
  }
Example #7
0
  /** Make sure that a cycle doesn't cause an infinite loop. */
  public void testCycle() {
    // This is what you'd get with a conditional <set-property value="false">
    ModuleDef md = new ModuleDef("testCycle");
    Properties properties = md.getProperties();

    {
      BindingProperty bindingProperty = properties.createBinding("A");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "a1");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "a2");

      bindingProperty.addDefinedValue(new ConditionWhenPropertyIs("B", "b3"), "a3");
    }

    {
      BindingProperty bindingProperty = properties.createBinding("B");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "b1");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "b2");

      bindingProperty.addDefinedValue(new ConditionWhenPropertyIs("A", "a3"), "b3");
    }

    try {
      new PropertyCombinations(properties, md.getActiveLinkerNames());
      fail();
    } catch (IllegalStateException e) {
      // OK
    }
  }
Example #8
0
  public void testOneDimensionPermWithCollapse() {
    ModuleDef md = new ModuleDef("testOneDimensionPerm");
    Properties properties = md.getProperties();

    {
      BindingProperty bindingProperty = properties.createBinding("debug");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "false");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "true");
      bindingProperty.addCollapsedValues("true", "false");
    }

    // Permutations and their values are in stable alphabetical order.
    //
    PropertyCombinations permutations =
        new PropertyCombinations(md.getProperties(), md.getActiveLinkerNames());

    List<PropertyCombinations> collapsed = permutations.collapseProperties();
    assertEquals("size", 1, collapsed.size());
    permutations = collapsed.get(0);

    String[] permutation;
    Iterator<String[]> it = permutations.iterator();

    assertTrue(it.hasNext());
    permutation = it.next();
    assertEquals("false", permutation[0]);

    assertTrue(it.hasNext());
    permutation = it.next();
    assertEquals("true", permutation[0]);
  }
Example #9
0
  /**
   * Prepares a stub compile directory. It will include all "public" resources and a nocache.js file
   * that invokes the compiler.
   */
  private void setUpCompileDir(CompileDir compileDir, ModuleDef module, TreeLogger compileLogger)
      throws UnableToCompleteException {
    try {
      String currentModuleName = module.getName();

      // Create the directory.
      File outputDir =
          new File(compileDir.getWarDir().getCanonicalPath() + "/" + currentModuleName);
      if (!outputDir.exists()) {
        if (!outputDir.mkdir()) {
          compileLogger.log(Type.WARN, "cannot create directory: " + outputDir);
        }
      }
      LauncherDir.writePublicResources(outputDir, module, compileLogger);

      // write no cache that will inject recompile.nocache.js
      String stub = LauncherDir.generateStubNocacheJs(module.getName(), options);
      File noCacheJs = new File(outputDir.getCanonicalPath(), module.getName() + ".nocache.js");
      Files.write(stub, noCacheJs, Charsets.UTF_8);

      // Create a "module_name.recompile.nocache.js" that calculates the permutation
      // and forces a recompile.
      String recompileNoCache = generateModuleRecompileJs(module, compileLogger);
      writeRecompileNoCacheJs(outputDir, currentModuleName, recompileNoCache, compileLogger);
    } catch (IOException e) {
      compileLogger.log(Type.ERROR, "Error creating stub compile directory.", e);
      UnableToCompleteException wrapped = new UnableToCompleteException();
      wrapped.initCause(e);
      throw wrapped;
    }
  }
  @Override
  protected boolean doStartup() {
    // Background scan the classpath to warm the cache.
    Thread scanThread =
        new Thread(
            new Runnable() {
              public void run() {
                ResourceOracleImpl.preload(TreeLogger.NULL);
              }
            });
    scanThread.setDaemon(true);
    scanThread.setPriority((Thread.MIN_PRIORITY + Thread.NORM_PRIORITY) / 2);
    scanThread.start();

    File persistentCacheDir = null;
    if (options.getWarDir() != null && !options.getWarDir().getName().endsWith(".jar")) {
      persistentCacheDir = new File(options.getWarDir(), "../");
    }

    if (!super.doStartup(persistentCacheDir)) {
      return false;
    }

    ServletValidator servletValidator = null;
    ServletWriter servletWriter = null;
    File webXml = new File(options.getWarDir(), "WEB-INF/web.xml");
    if (!options.isNoServer()) {
      if (webXml.exists()) {
        servletValidator = ServletValidator.create(getTopLogger(), webXml);
      } else {
        servletWriter = new ServletWriter();
      }
    }

    TreeLogger branch = getTopLogger().branch(TreeLogger.TRACE, "Loading modules");
    try {
      for (String moduleName : options.getModuleNames()) {
        TreeLogger moduleBranch = branch.branch(TreeLogger.TRACE, moduleName);
        ModuleDef module = loadModule(moduleBranch, moduleName, false);
        // Create a hard reference to the module to avoid gc-ing it until we
        // actually load the module from the browser.
        startupModules.put(module.getName(), module);

        if (!options.isNoServer()) {
          validateServletTags(moduleBranch, servletValidator, servletWriter, module);
        }
      }
      if (servletWriter != null) {
        servletWriter.realize(webXml);
      }
    } catch (IOException e) {
      getTopLogger().log(TreeLogger.WARN, "Unable to generate '" + webXml.getAbsolutePath() + "'");
    } catch (UnableToCompleteException e) {
      // Already logged.
      return false;
    }
    return true;
  }
Example #11
0
  public void testTwoDimensionPerm() {
    ModuleDef md = new ModuleDef("testTwoDimensionPerm");
    Properties properties = md.getProperties();

    {
      BindingProperty bindingProperty = properties.createBinding("user.agent");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "moz");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "ie6");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "opera");
    }

    {
      BindingProperty bindingProperty = properties.createBinding("debug");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "false");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "true");
    }

    // String[]s and their values are in stable alphabetical order.
    //
    PropertyCombinations permutations =
        new PropertyCombinations(md.getProperties(), md.getActiveLinkerNames());
    String[] permutation;
    Iterator<String[]> it = permutations.iterator();

    assertTrue(it.hasNext());
    permutation = it.next();
    assertEquals("false", permutation[0]);
    assertEquals("ie6", permutation[1]);

    assertTrue(it.hasNext());
    permutation = it.next();
    assertEquals("false", permutation[0]);
    assertEquals("moz", permutation[1]);

    assertTrue(it.hasNext());
    permutation = it.next();
    assertEquals("false", permutation[0]);
    assertEquals("opera", permutation[1]);

    assertTrue(it.hasNext());
    permutation = it.next();
    assertEquals("true", permutation[0]);
    assertEquals("ie6", permutation[1]);

    assertTrue(it.hasNext());
    permutation = it.next();
    assertEquals("true", permutation[0]);
    assertEquals("moz", permutation[1]);

    assertTrue(it.hasNext());
    permutation = it.next();
    assertEquals("true", permutation[0]);
    assertEquals("opera", permutation[1]);
  }
Example #12
0
  /** Generates the nocache.js file to use when precompile is not on. */
  private static String generateModuleRecompileJs(ModuleDef module, TreeLogger compileLogger)
      throws UnableToCompleteException {

    String outputModuleName = module.getName();
    try {
      String templateJs =
          Resources.toString(
              Resources.getResource(Recompiler.class, "recompile_template.js"), Charsets.UTF_8);
      String propertyProviders = PropertiesUtil.generatePropertiesSnippet(module, compileLogger);
      String libJs =
          Resources.toString(
              Resources.getResource(Recompiler.class, "recompile_lib.js"), Charsets.UTF_8);
      String recompileJs =
          Resources.toString(
              Resources.getResource(Recompiler.class, "recompile_main.js"), Charsets.UTF_8);
      templateJs = templateJs.replace("__MODULE_NAME__", "'" + outputModuleName + "'");
      templateJs = templateJs.replace("__PROPERTY_PROVIDERS__", propertyProviders);
      templateJs = templateJs.replace("__LIB_JS__", libJs);
      templateJs = templateJs.replace("__MAIN__", recompileJs);

      return templateJs;

    } catch (IOException e) {
      compileLogger.log(Type.ERROR, "Can not generate + " + outputModuleName + " recompile js", e);
      throw new UnableToCompleteException();
    }
  }
Example #13
0
  public BuildResultStatus build(TreeLogger logger) {
    try {
      logger = logger.branch(TreeLogger.INFO, "Performing an incremental build");

      CompilerContext compilerContext =
          new CompilerContext.Builder()
              .compileMonolithic(false)
              .libraryGroup(LibraryGroup.fromLibraries(Lists.<Library>newArrayList(), false))
              .build();
      long beforeLoadRootModuleMs = System.currentTimeMillis();
      rootModule =
          ModuleDefLoader.loadFromResources(
              logger, compilerContext, rootModuleName, resourceLoader, false);
      finalProperties = rootModule.getProperties();
      long loadRootModuleDurationMs = System.currentTimeMillis() - beforeLoadRootModuleMs;
      logger.log(
          TreeLogger.INFO,
          String.format(
              "%.3fs -- Parsing and loading root module definition in %s",
              loadRootModuleDurationMs / 1000d, rootModuleName));

      long beforeCreateTargetGraphMs = System.currentTimeMillis();
      rootBuildTarget = createBuildTarget(logger, rootModuleName);
      rootBuildTarget.setModule(rootModule);
      long createdTargetGraphDurationMs = System.currentTimeMillis() - beforeCreateTargetGraphMs;
      logger.log(
          TreeLogger.INFO,
          String.format(
              "%.3fs -- Creating target graph (%s targets)",
              createdTargetGraphDurationMs / 1000d, buildTargetsByCanonicalModuleName.size()));

      if (!circularReferenceModuleNameLoops.isEmpty()) {
        for (List<String> circularReferenceModuleNameLoop : circularReferenceModuleNameLoops) {
          logger.log(
              TreeLogger.ERROR, formatCircularModulePathMessage(circularReferenceModuleNameLoop));
        }
        throw new UnableToCompleteException();
      }
      logLoadedBuildTargetGraph(logger, buildTargetsByCanonicalModuleName);

      long beforeComputeOutputFreshnessMs = System.currentTimeMillis();
      ModuleDefLoader.clearModuleCache();
      rootBuildTarget.computeOutputFreshness(logger);
      long computeOutputFreshnessDurationMs =
          System.currentTimeMillis() - beforeComputeOutputFreshnessMs;
      logger.log(
          TreeLogger.INFO,
          String.format(
              "%.3fs -- Computing per-target output freshness",
              computeOutputFreshnessDurationMs / 1000d));

      TreeLogger branch = logger.branch(TreeLogger.INFO, "Compiling target graph");
      boolean success = rootBuildTarget.link(branch);
      return BuildResultStatus.get(success);
    } catch (UnableToCompleteException e) {
      // The real cause has been logged.
      return BuildResultStatus.FAILED;
    }
  }
Example #14
0
 private static boolean maybeOverrideConfig(ModuleDef module, String propName, String newValue) {
   ConfigurationProperty config = module.getProperties().findConfigProp(propName);
   if (config != null) {
     config.setValue(newValue);
     return true;
   }
   return false;
 }
Example #15
0
 /** Sets a binding even if it's set to a different value in the GWT application. */
 private static void overrideBinding(ModuleDef module, String propName, String newValue) {
   BindingProperty binding = module.getProperties().findBindingProp(propName);
   if (binding != null) {
     // This sets both allowed and generated values, which is needed since the module
     // might have explicitly disallowed the value.
     // It persists over multiple compiles but that's okay since we set it the same way
     // every time.
     binding.setValues(binding.getRootCondition(), newValue);
   }
 }
Example #16
0
  public void testTwoDimensionPermWithCollapse() {
    ModuleDef md = new ModuleDef("testTwoDimensionPerm");
    Properties properties = md.getProperties();

    {
      BindingProperty bindingProperty = properties.createBinding("user.agent");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "moz");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "ie6");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "opera");
      bindingProperty.addCollapsedValues("moz", "ie6", "opera");
    }

    {
      BindingProperty bindingProperty = properties.createBinding("debug");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "false");
      bindingProperty.addDefinedValue(bindingProperty.getRootCondition(), "true");
    }

    // String[]s and their values are in stable alphabetical order.
    //
    PropertyCombinations permutations =
        new PropertyCombinations(md.getProperties(), md.getActiveLinkerNames());

    List<PropertyCombinations> collapsed = permutations.collapseProperties();
    assertEquals("size", 2, collapsed.size());

    Iterator<String[]> it = collapsed.get(0).iterator();
    assertEquals(Arrays.asList("false", "ie6"), Arrays.asList(it.next()));
    assertEquals(Arrays.asList("false", "moz"), Arrays.asList(it.next()));
    assertEquals(Arrays.asList("false", "opera"), Arrays.asList(it.next()));
    assertFalse(it.hasNext());

    it = collapsed.get(1).iterator();
    assertEquals(Arrays.asList("true", "ie6"), Arrays.asList(it.next()));
    assertEquals(Arrays.asList("true", "moz"), Arrays.asList(it.next()));
    assertEquals(Arrays.asList("true", "opera"), Arrays.asList(it.next()));
    assertFalse(it.hasNext());
  }
Example #17
0
  private boolean isCircularlyReferent(String potentialDuplicateModuleName) {
    if (knownCircularlyReferentModuleNames.contains(potentialDuplicateModuleName)) {
      return true;
    }
    if (!moduleReferencePath.contains(potentialDuplicateModuleName)) {
      return false;
    }

    List<String> circularModuleReferencePath = Lists.newArrayList(moduleReferencePath);

    // Attach the duplicate module name to the end of the loop.
    circularModuleReferencePath.add(potentialDuplicateModuleName);

    List<String> annotatedCircularModuleReferencePath = Lists.newArrayList();
    // The current module path only includes libraries but the connections between libraries might
    // be silently flowing through filesets. Add filesets to the path so that the output is more
    // readable.
    for (int moduleNameIndex = 0;
        moduleNameIndex < circularModuleReferencePath.size() - 1;
        moduleNameIndex++) {
      String thisModuleName = circularModuleReferencePath.get(moduleNameIndex);
      String nextModuleName = circularModuleReferencePath.get(moduleNameIndex + 1);

      annotatedCircularModuleReferencePath.add(
          thisModuleName + (thisModuleName.equals(potentialDuplicateModuleName) ? " <loop>" : ""));

      List<String> fileSetPath = rootModule.getFileSetPathBetween(thisModuleName, nextModuleName);
      if (fileSetPath != null) {
        for (String fileSetModuleName : fileSetPath) {
          annotatedCircularModuleReferencePath.add(fileSetModuleName + " <fileset>");
        }
      }
    }

    // Attach the duplicate module name to the end of the loop.
    annotatedCircularModuleReferencePath.add(potentialDuplicateModuleName + " <loop>");

    knownCircularlyReferentModuleNames.addAll(annotatedCircularModuleReferencePath);
    circularReferenceModuleNameLoops.add(annotatedCircularModuleReferencePath);
    return true;
  }
Example #18
0
  /**
   * Attempts to set a binding property to the given value. If the value is not allowed, see if we
   * can find a value that will work. There is a special case for "locale".
   *
   * @return the value actually set, or null if unable to set the property
   */
  private static String maybeSetBinding(
      TreeLogger logger, ModuleDef module, String propName, String newValue) {

    logger = logger.branch(TreeLogger.Type.INFO, "binding: " + propName + "=" + newValue);

    BindingProperty binding = module.getProperties().findBindingProp(propName);
    if (binding == null) {
      logger.log(TreeLogger.Type.WARN, "undefined property: '" + propName + "'");
      return null;
    }

    if (!binding.isAllowedValue(newValue)) {

      String[] allowedValues = binding.getAllowedValues(binding.getRootCondition());
      logger.log(
          TreeLogger.Type.WARN, "property '" + propName + "' cannot be set to '" + newValue + "'");
      logger.log(TreeLogger.Type.INFO, "allowed values: " + Joiner.on(", ").join(allowedValues));

      // See if we can fall back on a reasonable default.
      if (allowedValues.length == 1) {
        // There is only one possibility, so use it.
        newValue = allowedValues[0];
      } else if (binding.getName().equals("locale")) {
        // TODO: come up with a more general solution. Perhaps fail
        // the compile and give the user a way to override the property?
        newValue = chooseDefault(binding, "default", "en", "en_US");
      } else {
        // There is more than one. Continue and possibly compile multiple permutations.
        logger.log(
            TreeLogger.Type.INFO, "continuing without " + propName + ". Sourcemaps may not work.");
        return null;
      }

      logger.log(TreeLogger.Type.INFO, "recovered with " + propName + "=" + newValue);
    }

    binding.setRootGeneratedValues(newValue);
    return newValue;
  }
Example #19
0
  private BuildTarget createBuildTarget(TreeLogger logger, String moduleName)
      throws UnableToCompleteException {
    if (isCircularlyReferent(moduleName)) {
      // Allow the target graph creation to continue so that all of the circular reference loops can
      // be gathered.
      return null;
    }
    if (buildTargetsByCanonicalModuleName.containsKey(moduleName)) {
      return buildTargetsByCanonicalModuleName.get(moduleName);
    }

    logger.log(TreeLogger.SPAM, String.format("Adding target %s to build graph.", moduleName));
    moduleReferencePath.add(moduleName);

    List<BuildTarget> dependencyBuildTargets = Lists.newArrayList();
    for (String dependencyModuleName : rootModule.getDirectDependencies(moduleName)) {
      dependencyBuildTargets.add(createBuildTarget(logger, dependencyModuleName));
    }
    moduleReferencePath.remove(moduleName);

    return createBuildTarget(moduleName, dependencyBuildTargets.toArray(new BuildTarget[0]));
  }
Example #20
0
  public boolean run(TreeLogger logger, ModuleDef... modules) throws UnableToCompleteException {
    boolean tempWorkDir = false;
    try {
      if (options.getWorkDir() == null) {
        options.setWorkDir(Utility.makeTemporaryDirectory(null, "gwtc"));
        tempWorkDir = true;
      }
      if (options.isSoycEnabled() && options.getExtraDir() == null) {
        options.setExtraDir(new File("extras"));
      }

      File persistentUnitCacheDir = null;
      if (options.getWarDir() != null && !options.getWarDir().getName().endsWith(".jar")) {
        persistentUnitCacheDir = new File(options.getWarDir(), "../");
      }
      CompilationStateBuilder.init(logger, persistentUnitCacheDir);

      for (ModuleDef module : modules) {
        String moduleName = module.getCanonicalName();
        if (options.isValidateOnly()) {
          if (!Precompile.validate(logger, options, module, options.getGenDir())) {
            return false;
          }
        } else {
          long compileStart = System.currentTimeMillis();
          TreeLogger branch = logger.branch(TreeLogger.INFO, "Compiling module " + moduleName);

          // Optimize early since permutation compiles will run in process.
          options.setOptimizePrecompile(true);
          Precompilation precompilation =
              Precompile.precompile(branch, options, module, options.getGenDir());
          if (precompilation == null) {
            return false;
          }

          Event compilePermutationsEvent =
              SpeedTracerLogger.start(CompilerEventType.COMPILE_PERMUTATIONS);
          Permutation[] allPerms = precompilation.getPermutations();
          List<FileBackedObject<PermutationResult>> resultFiles =
              CompilePerms.makeResultFiles(options.getCompilerWorkDir(moduleName), allPerms);
          CompilePerms.compile(
              branch, precompilation, allPerms, options.getLocalWorkers(), resultFiles);
          compilePermutationsEvent.end();

          ArtifactSet generatedArtifacts = precompilation.getGeneratedArtifacts();
          JJSOptions precompileOptions = precompilation.getUnifiedAst().getOptions();

          precompilation = null; // No longer needed, so save the memory

          Event linkEvent = SpeedTracerLogger.start(CompilerEventType.LINK);
          File absPath = new File(options.getWarDir(), module.getName());
          absPath = absPath.getAbsoluteFile();

          String logMessage = "Linking into " + absPath;
          if (options.getExtraDir() != null) {
            File absExtrasPath = new File(options.getExtraDir(), module.getName());
            absExtrasPath = absExtrasPath.getAbsoluteFile();
            logMessage += "; Writing extras to " + absExtrasPath;
          }
          Link.link(
              logger.branch(TreeLogger.TRACE, logMessage),
              module,
              generatedArtifacts,
              allPerms,
              resultFiles,
              options.getWarDir(),
              options.getDeployDir(),
              options.getExtraDir(),
              precompileOptions);

          linkEvent.end();
          long compileDone = System.currentTimeMillis();
          long delta = compileDone - compileStart;
          if (branch.isLoggable(TreeLogger.INFO)) {
            branch.log(
                TreeLogger.INFO,
                "Compilation succeeded -- " + String.format("%.3f", delta / 1000d) + "s");
          }
        }
      }

    } catch (IOException e) {
      logger.log(TreeLogger.ERROR, "Unable to create compiler work directory", e);
      return false;
    } finally {
      if (tempWorkDir) {
        Util.recursiveDelete(options.getWorkDir(), false);
      }
    }
    return true;
  }
Example #21
0
  /**
   * according to .gwt.xml files generates a LinkedMap which has interfaces as keys array of
   * generators as values keys are sorted according order of <generate-with> elements in .gwt.xml
   * files
   *
   * @param context
   * @throws UnableToCompleteException
   */
  private void fillUpGeneratorChainMap(TreeLogger logger, GeneratorContext context)
      throws UnableToCompleteException {

    GeneratorChain.customGenerators = new LinkedList<AbstractGenerator>();
    GeneratorChain.replacers = new LinkedList<AbstractGenerator>();
    GeneratorChain.thirdPartyGenerators = new LinkedHashMap<Generator, AbstractGenerator>();
    ModuleDef moduleDef =
        ((CompilerContext) getPrivateField(context, "compilerContext")).getModule();
    Rules rules = moduleDef.getRules();
    Iterator<Rule> rulesIter = rules.iterator();
    while (rulesIter.hasNext()) {
      Rule rul = rulesIter.next();
      Generator gen = null;

      // =================replace with
      if (rul instanceof RuleReplaceWith) {
        String replaceClass = (String) getPrivateField(rul, "replacementTypeName");
        gen = new ReplaceByGenerator(replaceClass);
        // gen = null;

        // =================generate with
      } else if (rul instanceof RuleGenerateWith) {
        Class<? extends Generator> generatorClass =
            (Class<? extends Generator>) getPrivateField(rul, "generatorClass");
        Constructor<?> constructor;
        try {
          constructor = generatorClass.getDeclaredConstructor();
        } catch (Exception e) {
          logger.log(
              Type.ERROR, "Unable to obtain default constructor of generator " + generatorClass);
          throw new UnableToCompleteException();
        }
        constructor.setAccessible(true);
        try {
          gen = (Generator) constructor.newInstance();
        } catch (Exception e) {
          logger.log(Type.ERROR, "Unable to create instance of generator " + generatorClass);
          throw new UnableToCompleteException();
        }
      }

      if (gen != null) {
        if (gen instanceof AbstractGenerator) {
          GenPredicGroup newGroup = null;
          AbstractGenerator myGen = (AbstractGenerator) gen;
          if (GeneratorChain.customGenerators.contains(gen)
              || GeneratorChain.replacers.contains(gen)) {
            newGroup = addPredicsToExisting(rul, myGen.getConditions());
            myGen.setConditions(newGroup);
          } else {
            newGroup = getGroupConditions(rul.getRootCondition().getConditions(), null);
            myGen.setConditions(newGroup);
            if (gen instanceof ReplaceByGenerator) {
              GeneratorChain.replacers.addFirst(myGen);
            } else {
              GeneratorChain.customGenerators.addFirst(myGen);
            }
          }

        } else {
          if (GeneratorChain.thirdPartyGenerators.containsKey(gen)) {
            AbstractGenerator myGen = GeneratorChain.thirdPartyGenerators.get(gen);
            GenPredicGroup newGroup = addPredicsToExisting(rul, myGen.getConditions());
            myGen.setConditions(newGroup);
            GeneratorChain.thirdPartyGenerators.put(gen, myGen);
          } else {
            AbstractGenerator myGen =
                new AbstractGenerator() {

                  @Override
                  public String doGenerate(
                      TreeLogger logger, GeneratorContext context, String typeName)
                      throws UnableToCompleteException {
                    return null;
                  }
                };
            myGen.setConditions(getGroupConditions(rul.getRootCondition().getConditions(), null));
            GeneratorChain.thirdPartyGenerators.put(gen, myGen);
          }
        }
      }
    }
  }
Example #22
0
  /** Loads the module and configures it for SuperDevMode. (Does not restrict permutations.) */
  private ModuleDef loadModule(TreeLogger logger) throws UnableToCompleteException {

    // make sure we get the latest version of any modified jar
    ZipFileClassPathEntry.clearCache();
    ResourceOracleImpl.clearCache();

    ResourceLoader resources = ResourceLoaders.forClassLoader(Thread.currentThread());
    resources = ResourceLoaders.forPathAndFallback(options.getSourcePath(), resources);
    this.resourceLoader.set(resources);

    // ModuleDefLoader.loadFromResources() checks for modified .gwt.xml files.
    ModuleDef moduleDef =
        ModuleDefLoader.loadFromResources(
            logger, compilerContext, inputModuleName, resources, true);
    compilerContext = compilerContextBuilder.module(moduleDef).build();

    // Undo all permutation restriction customizations from previous compiles.
    for (BindingProperty bindingProperty : moduleDef.getProperties().getBindingProperties()) {
      String[] allowedValues = bindingProperty.getAllowedValues(bindingProperty.getRootCondition());
      bindingProperty.setRootGeneratedValues(allowedValues);
    }

    // A snapshot of the module's configuration before we modified it.
    ConfigProps config = new ConfigProps(moduleDef);

    // We need a cross-site linker. Automatically replace the default linker.
    if (IFrameLinker.class.isAssignableFrom(moduleDef.getActivePrimaryLinker())) {
      moduleDef.addLinker("xsiframe");
    }

    // Check that we have a compatible linker.
    Class<? extends Linker> linker = moduleDef.getActivePrimaryLinker();
    if (!CrossSiteIframeLinker.class.isAssignableFrom(linker)) {
      logger.log(
          TreeLogger.ERROR,
          "linkers other than CrossSiteIFrameLinker aren't supported. Found: " + linker.getName());
      throw new UnableToCompleteException();
    }

    // Deactivate precompress linker.
    if (moduleDef.deactivateLinker("precompress")) {
      logger.log(TreeLogger.WARN, "Deactivated PrecompressLinker");
    }

    // Print a nice error if the superdevmode hook isn't present
    if (config.getStrings("devModeRedirectEnabled").isEmpty()) {
      throw new RuntimeException(
          "devModeRedirectEnabled isn't set for module: " + moduleDef.getName());
    }

    // Disable the redirect hook here to make sure we don't have an infinite loop.
    // (There is another check in the JavaScript, but just in case.)
    overrideConfig(moduleDef, "devModeRedirectEnabled", "false");

    // Turn off "installCode" if it's on because it makes debugging harder.
    // (If it's already off, don't change anything.)
    if (config.getBoolean("installCode", true)) {
      overrideConfig(moduleDef, "installCode", "false");
      // Make sure installScriptJs is set to the default for compiling without installCode.
      overrideConfig(
          moduleDef,
          "installScriptJs",
          "com/google/gwt/core/ext/linker/impl/installScriptDirect.js");
    }

    // override computeScriptBase.js to enable the "Compile" button
    overrideConfig(
        moduleDef, "computeScriptBaseJs", "com/google/gwt/dev/codeserver/computeScriptBase.js");
    // Fix bug with SDM and Chrome 24+ where //@ sourceURL directives cause X-SourceMap header to be
    // ignored
    // Frustratingly, Chrome won't canonicalize a relative URL
    overrideConfig(
        moduleDef,
        "includeSourceMapUrl",
        "http://" + serverPrefix + SourceHandler.sourceMapLocationTemplate(moduleDef.getName()));

    // If present, set some config properties back to defaults.
    // (Needed for Google's server-side linker.)
    maybeOverrideConfig(moduleDef, "includeBootstrapInPrimaryFragment", "false");
    maybeOverrideConfig(
        moduleDef, "permutationsJs", "com/google/gwt/core/ext/linker/impl/permutations.js");
    maybeOverrideConfig(
        moduleDef, "propertiesJs", "com/google/gwt/core/ext/linker/impl/properties.js");

    if (options.isIncrementalCompileEnabled()) {
      // CSSResourceGenerator needs to produce stable, unique naming for its input.
      // Currently on default settings CssResourceGenerator's obfuscation depends on
      // whole world knowledge and thus will produce collision in obfuscated mode, since in
      // incremental compiles that information is not available.
      //
      // TODO(dankurka): Once we do proper stable hashing of classes in CssResourceGenerator, we
      // can probably replace / remove this.
      maybeOverrideConfig(moduleDef, "CssResource.style", "stable");
    }

    overrideBinding(moduleDef, "compiler.useSourceMaps", "true");
    overrideBinding(moduleDef, "compiler.useSymbolMaps", "false");
    overrideBinding(moduleDef, "superdevmode", "on");

    return moduleDef;
  }
Example #23
0
 InputSummary(Map<String, String> bindingProperties, ModuleDef module) {
   this.bindingProperties = ImmutableMap.copyOf(bindingProperties);
   this.moduleLastModified = module.lastModified();
   this.resourcesLastModified = module.getResourceLastModified();
   this.filenameHash = module.getInputFilenameHash();
 }
Example #24
0
 public String getRootModuleName() {
   if (rootModule == null) {
     return "UNKNOWN";
   }
   return rootModule.getName();
 }
Example #25
0
  private boolean doCompile(TreeLogger compileLogger, CompileDir compileDir, Job job)
      throws UnableToCompleteException {

    job.onProgress("Loading modules");

    CompilerOptions loadOptions = new CompilerOptionsImpl(compileDir, inputModuleName, options);
    compilerContext = compilerContextBuilder.options(loadOptions).build();

    ModuleDef module = loadModule(compileLogger);
    if (!Compiler.maybeRestrictProperties(compileLogger, module, loadOptions.getProperties())) {
      return false;
    }

    // We need to generate the stub before restricting permutations
    String recompileJs = generateModuleRecompileJs(module, compileLogger);

    Map<String, String> bindingProperties =
        restrictPermutations(compileLogger, module, job.getBindingProperties());

    // Propagates module rename.
    String newModuleName = module.getName();
    outputModuleName.set(newModuleName);

    // Check if we can skip the compile altogether.
    InputSummary input = new InputSummary(bindingProperties, module);
    if (input.equals(lastBuildInput)) {
      compileLogger.log(Type.INFO, "skipped compile because no input files have changed");
      job.setCompileStrategy(CompileStrategy.SKIPPED);
      return true;
    }
    // Force a recompile if we don't succeed.
    lastBuildInput = null;

    job.onProgress("Compiling");
    // TODO: use speed tracer to get more compiler events?

    CompilerOptions runOptions = new CompilerOptionsImpl(compileDir, newModuleName, options);
    compilerContext = compilerContextBuilder.options(runOptions).build();

    MinimalRebuildCache minimalRebuildCache = new NullRebuildCache();
    if (options.isIncrementalCompileEnabled()) {
      // Returns a copy of the intended cache, which is safe to modify in this compile.
      minimalRebuildCache = minimalRebuildCacheManager.getCache(inputModuleName, bindingProperties);
    }
    job.setCompileStrategy(
        minimalRebuildCache.isPopulated() ? CompileStrategy.INCREMENTAL : CompileStrategy.FULL);

    boolean success = new Compiler(runOptions, minimalRebuildCache).run(compileLogger, module);
    if (success) {
      publishedCompileDir = compileDir;
      lastBuildInput = input;
      if (options.isIncrementalCompileEnabled()) {
        minimalRebuildCacheManager.putCache(
            inputModuleName, bindingProperties, minimalRebuildCache);
      }
      String moduleName = outputModuleName.get();
      writeRecompileNoCacheJs(
          new File(publishedCompileDir.getWarDir(), moduleName),
          moduleName,
          recompileJs,
          compileLogger);
      if (launcherDir != null) {
        launcherDir.update(module, compileDir, compileLogger);
      }
    }

    return success;
  }