Skip to content
Permalink
Browse files

Move Super Dev Mode to the open source repository.

Includes a simple "demo" target that works with the "Hello" sample app.
I've also made some linker options configurable, as necessary to make this work.
Review at http://gwt-code-reviews.appspot.com/1727804


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11016 8db76d5a-ed1c-0410-87a9-c151d255dfc7
  • Loading branch information
skybrian@google.com
skybrian@google.com committed Jun 5, 2012
1 parent 04ad546 commit cc7626f913ed8b7cd949085a3351c646749fd55c
@@ -0,0 +1,81 @@
<project name="codeserver" default="build" basedir=".">
<property name="gwt.root" location="../.." />
<property name="project.tail" value="dev/codeserver" />
<import file="${gwt.root}/common.ant.xml" />

<property.ensure name="gwt.dev.jar" location="${gwt.build.lib}/gwt-dev.jar" />

<!-- location of preprocessed source -->
<property name="src" value="${project.build}/src" />

<!--
Nasty hack to fix the source code for the open source build.
Constraint: the code in the "java/" directory is how we want it inside Google.
But outside Google, Jetty is not repackaged, so we need to fix the import statements.
(The right way to do this is probably to repackage Jetty.)
-->
<target name="preprocess">
<delete dir="${src}"/>
<mkdir dir="${src}"/>
<copy todir="${src}">
<fileset dir="java">
<include name="**/*.java"/>
</fileset>
</copy>
<replace dir="${src}" token="com.google.gwt.thirdparty.org.mortbay.jetty"
value="org.mortbay.jetty"/>
</target>

<target name="compile" depends="preprocess">
<mkdir dir="${javac.out}" />
<gwt.javac srcdir="${src}">
<classpath>
<pathelement location="${gwt.dev.jar}" />
</classpath>
</gwt.javac>
</target>

<target name="build" depends="compile" description="builds gwt-codeserver.jar">
<gwt.jar>
<fileset dir="${javac.out}"/>
<fileset dir="java">
<include name="**/*.html"/>
<include name="**/*.js"/>
</fileset>

<manifest>
<!-- why doesn't this work?
<attribute name="Class-Path" value="gwt-dev.jar gwt.user.jar" />
-->
<attribute name="Main-Class" value="com.google.gwt.dev.codeserver.CodeServer" />
</manifest>
</gwt.jar>
</target>

<!-- no-op for now -->
<target name="verify"/>

<target name="demo" depends="build" description="starts the code server with a sample app">

<!-- hack to make sourcemaps generation work in the compiler -->
<!-- See: http://code.google.com/p/google-web-toolkit/issues/detail?id=7397 -->
<property.ensure name="json.jar"
location="${gwt.tools}/redist/json/r2_20080312/json-1.5.jar" />

<property.ensure name="gwt.user.jar" location="${gwt.build.lib}/gwt-user.jar" />
<property.ensure name="sample-src" location="${gwt.root}/samples/hello/src" />

<java fork="true" failonerror="true" classname="com.google.gwt.dev.codeserver.CodeServer">
<classpath>
<pathelement location="${project.lib}"/>
<pathelement location="${gwt.dev.jar}"/>
<pathelement location="${json.jar}" />
<pathelement location="${gwt.user.jar}"/>
</classpath>
<arg value="-src"/>
<arg value="${sample-src}"/>
<arg value="com.google.gwt.sample.hello.Hello"/>
</java>
</target>

</project>
@@ -0,0 +1,74 @@
/*
* 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.dev.util.Util;

import java.io.File;
import java.io.IOException;

/**
* The directory tree where Super Dev Mode keeps all the files for one GWT app.
* Each time we recompile the app, we create a new subdirectory (see {@link CompileDir}).
* In addition, there are some files that are shared between recompiles, such as
* the unit cache.
*/
class AppSpace {

static final String COMPILE_DIR_PREFIX = "compile-";
private final File root;

/**
* @see #create
*/
private AppSpace(File root) {
this.root = root;
}

File getSpeedTracerLogFile() {
return new File(root, "speedtracer.html");
}

File getUnitCacheDir() {
return new File(root, "gwt-unitcache");
}

File getCompileDir(int compileId) {
return new File(root, COMPILE_DIR_PREFIX + compileId);
}

/**
* Creates an app directory, doing any cleanup needed.
* @param dir the directory to use. It need not exist, but
* the parent dir should exist.
*/
static AppSpace create(File dir) throws IOException {
if (!dir.exists() && !dir.mkdir()) {
throw new IOException("can't create app directory: " + dir);
}

// clean up existing subdirectories
for (File candidate : dir.listFiles()) {
if (candidate.getName().startsWith(COMPILE_DIR_PREFIX)) {
System.err.println("deleting: " + candidate);
Util.recursiveDelete(candidate, false);
}
}

return new AppSpace(dir);
}
}
@@ -0,0 +1,112 @@
/*
* 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.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import com.google.gwt.util.tools.Utility;

import java.io.File;
import java.io.IOException;

/**
* <p>This class contains the {@link #main main method} that starts the code server for
* "Super Dev Mode", a replacement for developer mode that doesn't require
* browser plugins.</p>
*
* <p>This tool is EXPERIMENTAL. There is no authentication, no encryption, no XSS
* protection, and it makes all source code on the GWT compiler's classpath available
* via HTTP. It is only safe to run on localhost (the default).</p>
*/
public class CodeServer {

/**
* Starts the code server. Shuts down the JVM if startup fails.
* @param args Command-line options that can be parsed by {@link Options}.
*/
public static void main(String[] args) throws Exception {

Options options = new Options();
if (!options.parseArgs(args)) {
System.exit(1);
}

try {
start(options);

System.out.println();
System.out.println("The code server is ready.");
System.out.println("Next, visit: http://localhost:" + options.getPort() + "/");
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}

/**
* Starts the code server with the given command line options. To shut it down, see
* {@link WebServer#stop}.
*
* <p>Only one code server should be started at a time because the GWT compiler uses
* a lot of static variables.</p>
*/
public static WebServer start(Options options) throws IOException, UnableToCompleteException {
if (options.getModuleNames().isEmpty()) {
throw new IllegalArgumentException("Usage: at least one module must be supplied");
}

PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
logger.setMaxDetail(TreeLogger.Type.INFO);
Modules modules = new Modules();

File workDir = ensureWorkDir(options);
System.out.println("workDir: " + workDir);

for (String moduleName : options.getModuleNames()) {
AppSpace appSpace = AppSpace.create(new File(workDir, moduleName));

Recompiler recompiler = new Recompiler(appSpace, moduleName,
options.getSourcePath(), logger);
modules.addModuleState(new ModuleState(recompiler, logger));
}

SourceHandler sourceHandler = new SourceHandler(modules, logger);

WebServer webServer = new WebServer(sourceHandler, modules,
options.getPort(), logger);
webServer.start();

return webServer;
}

/**
* Ensures that we have a work directory. If specified via a flag, the
* directory must already exist. Otherwise, create a temp directory.
*/
private static File ensureWorkDir(Options options) throws IOException {
File workDir = options.getWorkDir();
if (workDir == null) {
workDir = Utility.makeTemporaryDirectory(null, "gwt-codeserver-");
} else {
if (!workDir.isDirectory()) {
throw new IOException("workspace directory doesn't exist: " + workDir);
}
}
return workDir;
}
}
@@ -0,0 +1,106 @@
/*
* 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.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;

import java.io.File;

/**
* Defines a directory tree used for compiling a GWT app one time. Each time we recompile
* the app, we will create a new, empty CompileDir. This way, a failed compile doesn't
* modify the last good compile.
*
* The CompileDir gets created within the appropriate {@link AppSpace} for the app
* being compiled.
*/
class CompileDir {
private final File dir;

/**
* @see #create
*/
private CompileDir(File dir) {
this.dir = dir;
}

File getWarDir() {
return new File(dir, "war");
}

File getDeployDir() {
return new File(getWarDir(), "WEB-INF/deploy");
}

File getExtraDir() {
return new File(dir, "extras");
}

File getGenDir() {
return new File(dir, "gen");
}

File getWorkDir() {
return new File(dir, "work");
}

File getLogFile() {
return new File(dir, "compile.log");
}

File findSymbolMapDir(String moduleName) {
// The JUnit module moves the symbolMaps directory in a post linker.
// TODO(skybrian) query this information from the compiler somehow?
File[] candidates = {
new File(getExtraDir(), moduleName + "/symbolMaps"),
new File(getWarDir(), moduleName + "/.junit_symbolMaps")
};

for (File candidate : candidates) {
if (candidate.isDirectory()) {
return candidate;
}
}

return null;
}

/**
* Creates a new compileDir directory structure. The directory must not already exist,
* but its parent should exist.
* @throws UnableToCompleteException if unable to create the directory
*/
static CompileDir create(File dir, TreeLogger logger)
throws UnableToCompleteException {

CompileDir result = new CompileDir(dir);

mkdir(dir, logger);
mkdir(result.getWarDir(), logger);

return result;
}

private static void mkdir(File dirToCreate, TreeLogger logger)
throws UnableToCompleteException {
if (!dirToCreate.mkdir()) {
logger.log(TreeLogger.Type.ERROR, "unable to create directory: " + dirToCreate);
throw new UnableToCompleteException();
}
}
}

0 comments on commit cc7626f

Please sign in to comment.
You can’t perform that action at this time.