Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.google.gwt.dev.codeserver.Recompiler Maven / Gradle / Ivy
/*
* Copyright 2011 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.codeserver;
import com.google.gwt.core.ext.Linker;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.linker.CrossSiteIframeLinker;
import com.google.gwt.core.linker.IFrameLinker;
import com.google.gwt.dev.Compiler;
import com.google.gwt.dev.CompilerContext;
import com.google.gwt.dev.CompilerOptions;
import com.google.gwt.dev.cfg.BindingProperty;
import com.google.gwt.dev.cfg.ConfigurationProperty;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.cfg.Property;
import com.google.gwt.dev.cfg.ResourceLoader;
import com.google.gwt.dev.cfg.ResourceLoaders;
import com.google.gwt.dev.javac.CompilationStateBuilder;
import com.google.gwt.dev.resource.impl.ResourceOracleImpl;
import com.google.gwt.dev.resource.impl.ZipFileClassPathEntry;
import com.google.gwt.dev.util.log.CompositeTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/**
* Recompiles a GWT module on demand.
*/
class Recompiler {
private final AppSpace appSpace;
private final String originalModuleName;
private final TreeLogger logger;
private String serverPrefix;
private int compilesDone = 0;
// after renaming
private AtomicReference moduleName = new AtomicReference(null);
private final AtomicReference lastBuild = new AtomicReference();
private final AtomicReference resourceLoader =
new AtomicReference();
private final CompilerContext.Builder compilerContextBuilder = new CompilerContext.Builder();
private CompilerContext compilerContext;
private Options options;
Recompiler(AppSpace appSpace, String moduleName, Options options, TreeLogger logger) {
this.appSpace = appSpace;
this.originalModuleName = moduleName;
this.options = options;
this.logger = logger;
this.serverPrefix = options.getPreferredHost() + ":" + options.getPort();
compilerContext = compilerContextBuilder.build();
}
synchronized CompileDir compile(Map bindingProperties)
throws UnableToCompleteException {
if (compilesDone == 0) {
System.setProperty("java.awt.headless", "true");
if (System.getProperty("gwt.speedtracerlog") == null) {
System.setProperty("gwt.speedtracerlog",
appSpace.getSpeedTracerLogFile().getAbsolutePath());
}
CompilationStateBuilder.init(logger, appSpace.getUnitCacheDir());
}
long startTime = System.currentTimeMillis();
int compileId = ++compilesDone;
CompileDir compileDir = makeCompileDir(compileId);
TreeLogger compileLogger = makeCompileLogger(compileDir);
boolean listenerFailed = false;
try {
options.getRecompileListener().startedCompile(originalModuleName, compileId, compileDir);
} catch (Exception e) {
compileLogger.log(TreeLogger.Type.WARN, "listener threw exception", e);
listenerFailed = true;
}
boolean success = false;
try {
CompilerOptions compilerOptions = new CompilerOptionsImpl(
compileDir, options.getModuleNames(), options.getSourceLevel(),
options.enforceStrictResources());
compilerContext = compilerContextBuilder.options(compilerOptions).build();
ModuleDef module = loadModule(compileLogger, bindingProperties);
// Propagates module rename.
String newModuleName = module.getName();
moduleName.set(newModuleName);
compilerOptions = new CompilerOptionsImpl(
compileDir, Lists.newArrayList(newModuleName), options.getSourceLevel(),
options.enforceStrictResources());
compilerContext = compilerContextBuilder.options(compilerOptions).build();
success = new Compiler(compilerOptions).run(compileLogger, module);
lastBuild.set(compileDir); // makes compile log available over HTTP
} finally {
try {
options.getRecompileListener().finishedCompile(originalModuleName, compileId, success);
} catch (Exception e) {
compileLogger.log(TreeLogger.Type.WARN, "listener threw exception", e);
listenerFailed = true;
}
}
if (!success) {
compileLogger.log(TreeLogger.Type.ERROR, "Compiler returned " + success);
throw new UnableToCompleteException();
}
long elapsedTime = System.currentTimeMillis() - startTime;
compileLogger.log(TreeLogger.Type.INFO, "Compile completed in " + elapsedTime + " ms");
if (options.isCompileTest() && listenerFailed) {
throw new UnableToCompleteException();
}
return compileDir;
}
synchronized CompileDir noCompile() throws UnableToCompleteException {
long startTime = System.currentTimeMillis();
CompileDir compileDir = makeCompileDir(++compilesDone);
TreeLogger compileLogger = makeCompileLogger(compileDir);
ModuleDef module = loadModule(compileLogger, new HashMap());
String newModuleName = module.getName(); // includes any rename.
moduleName.set(newModuleName);
lastBuild.set(compileDir);
try {
// Prepare directory.
File outputDir = new File(
compileDir.getWarDir().getCanonicalPath() + "/" + getModuleName());
if (!outputDir.exists()) {
outputDir.mkdir();
}
// Creates a "module_name.nocache.js" that just forces a recompile.
String moduleScript = PageUtil.loadResource(Recompiler.class, "nomodule.nocache.js");
moduleScript = moduleScript.replace("__MODULE_NAME__", getModuleName());
PageUtil.writeFile(outputDir.getCanonicalPath() + "/" + getModuleName() + ".nocache.js",
moduleScript);
} catch (IOException e) {
compileLogger.log(TreeLogger.Type.ERROR, "Error creating uncompiled module.", e);
}
long elapsedTime = System.currentTimeMillis() - startTime;
compileLogger.log(TreeLogger.Type.INFO, "Module setup completed in " + elapsedTime + " ms");
return compileDir;
}
/**
* Returns the log from the last compile. (It may be a failed build.)
*/
File getLastLog() {
return lastBuild.get().getLogFile();
}
String getModuleName() {
return moduleName.get();
}
ResourceLoader getResourceLoader() {
return resourceLoader.get();
}
private TreeLogger makeCompileLogger(CompileDir compileDir)
throws UnableToCompleteException {
try {
PrintWriterTreeLogger fileLogger =
new PrintWriterTreeLogger(compileDir.getLogFile());
fileLogger.setMaxDetail(TreeLogger.Type.INFO);
return new CompositeTreeLogger(logger, fileLogger);
} catch (IOException e) {
logger.log(TreeLogger.ERROR, "unable to open log file: " + compileDir.getLogFile(), e);
throw new UnableToCompleteException();
}
}
private ModuleDef loadModule(TreeLogger logger, Map bindingProperties)
throws UnableToCompleteException {
// make sure we get the latest version of any modified jar
ZipFileClassPathEntry.clearCache();
ResourceOracleImpl.clearCache();
ModuleDefLoader.clearModuleCache();
ResourceLoader resources = ResourceLoaders.forClassLoader(Thread.currentThread());
resources = ResourceLoaders.forPathAndFallback(options.getSourcePath(), resources);
this.resourceLoader.set(resources);
ModuleDef moduleDef = ModuleDefLoader.loadFromResources(
logger, compilerContext, originalModuleName, resources, true, true);
compilerContext = compilerContextBuilder.module(moduleDef).build();
// 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();
}
// Print a nice error if the superdevmode hook isn't present
if (moduleDef.getProperties().find("devModeRedirectEnabled") == null) {
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");
// Normally the GWT bootstrap script installs GWT code by calling eval() with a string of
// JavaScript, so that it can control the scope that the code runs in. Sourcemaps don't seem
// to be working in Chrome when we do this, so turn it off for now.
// TODO(cromwellian) remove when Chrome is fixed.
overrideConfig(moduleDef, "installScriptJs",
"com/google/gwt/core/ext/linker/impl/installScriptDirect.js");
overrideConfig(moduleDef, "installCode", "false");
// 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 +
WebServer.sourceMapLocationForModule(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");
for (Map.Entry entry : bindingProperties.entrySet()) {
String propName = entry.getKey();
String propValue = entry.getValue();
logger.log(TreeLogger.Type.INFO, "binding: " + propName + "=" + propValue);
maybeSetBinding(moduleDef, propName, propValue);
}
overrideBinding(moduleDef, "compiler.useSourceMaps", "true");
overrideBinding(moduleDef, "superdevmode", "on");
return moduleDef;
}
/**
* Sets a binding unless it's hard-coded in the GWT application.
*/
private static void maybeSetBinding(ModuleDef module, String propName, String newValue) {
Property prop = module.getProperties().find(propName);
if (prop instanceof BindingProperty) {
BindingProperty binding = (BindingProperty) prop;
if (binding.isAllowedValue(newValue)) {
binding.setAllowedValues(binding.getRootCondition(), newValue);
}
}
}
/**
* 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) {
Property prop = module.getProperties().find(propName);
if (prop instanceof BindingProperty) {
BindingProperty binding = (BindingProperty) prop;
binding.setAllowedValues(binding.getRootCondition(), newValue);
}
}
private static boolean maybeOverrideConfig(ModuleDef module, String propName, String newValue) {
Property prop = module.getProperties().find(propName);
if (prop instanceof ConfigurationProperty) {
ConfigurationProperty config = (ConfigurationProperty) prop;
config.setValue(newValue);
return true;
}
return false;
}
private static void overrideConfig(ModuleDef module, String propName, String newValue) {
if (!maybeOverrideConfig(module, propName, newValue)) {
throw new RuntimeException("not found: " + propName);
}
}
private CompileDir makeCompileDir(int compileId)
throws UnableToCompleteException {
return CompileDir.create(appSpace.getCompileDir(compileId), logger);
}
}