Example #1
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 #2
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 #3
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 #4
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 #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 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 #7
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 #8
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 #9
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 #10
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 #11
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;
  }