Super Dev Mode: skip directory if unable to create it
Also rename AppSpace => OutboxDir
Bug: issue 8619
Change-Id: Id937cadb4251f90beed25202816fd095a7a11be7
Review-Link: https://gwt-review.googlesource.com/#/c/9610/
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/AppSpace.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/AppSpace.java
deleted file mode 100644
index bd4eccf..0000000
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/AppSpace.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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);
- }
-}
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
index c83ce74..aeb7ebb 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
@@ -144,9 +144,9 @@
int nextOutboxId = 1;
OutboxTable outboxes = new OutboxTable();
for (String moduleName : options.getModuleNames()) {
- AppSpace appSpace = AppSpace.create(new File(workDir, moduleName));
+ OutboxDir outboxDir = OutboxDir.create(new File(workDir, moduleName), logger);
- Recompiler recompiler = new Recompiler(appSpace, launcherDir, moduleName, options);
+ Recompiler recompiler = new Recompiler(outboxDir, launcherDir, moduleName, options);
// The id should be treated as an opaque string since we will change it again.
// TODO: change outbox id to include binding properties.
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/CompileDir.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/CompileDir.java
index 25ec834..6509cc0 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/CompileDir.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/CompileDir.java
@@ -31,7 +31,7 @@
* the app, we will create a new, empty CompileDir. This way, a failed compile doesn't
* modify the last good compile.
*
- * <p>The CompileDir gets created within the appropriate {@link AppSpace} for the app
+ * <p>The CompileDir gets created within the appropriate {@link OutboxDir} for the app
* being compiled.
*/
public class CompileDir {
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/OutboxDir.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/OutboxDir.java
new file mode 100644
index 0000000..ee15477
--- /dev/null
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/OutboxDir.java
@@ -0,0 +1,103 @@
+/*
+ * 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.TreeLogger.Type;
+import com.google.gwt.core.ext.UnableToCompleteException;
+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 OutboxDir {
+ private static final String COMPILE_DIR_PREFIX = "compile-";
+ private static final int MAX_CREATE_DIRECTORY_RETRIES = 50;
+
+ private final File root;
+ private int nextCompileId = 1;
+
+ /**
+ * @see #create
+ */
+ private OutboxDir(File root) {
+ this.root = root;
+ }
+
+ File getSpeedTracerLogFile() {
+ return new File(root, "speedtracer.html");
+ }
+
+ File getUnitCacheDir() {
+ return new File(root, "gwt-unitcache");
+ }
+
+ /**
+ * Creates a fresh, empty compile directory.
+ */
+ CompileDir makeCompileDir(TreeLogger logger)
+ throws UnableToCompleteException {
+
+ for (int i = 0; i < MAX_CREATE_DIRECTORY_RETRIES; i++) {
+ int candidateId = nextCompileId++;
+ File candidate = new File(root, COMPILE_DIR_PREFIX + candidateId);
+ try {
+ return CompileDir.create(candidate, logger);
+ } catch (UnableToCompleteException e) {
+ // try again
+ }
+ }
+
+ logger.log(Type.ERROR, "Gave up trying to create a compile directory.");
+ throw new UnableToCompleteException();
+ }
+
+ /**
+ * Creates an outbox directory, doing any cleanup needed.
+ * @param dir the directory to use. It need not exist, but
+ * the parent dir should exist.
+ */
+ static OutboxDir create(File dir, TreeLogger logger) throws IOException {
+ if (!dir.isDirectory() && !dir.mkdir()) {
+ throw new IOException("can't create app directory: " + dir);
+ }
+
+ File[] children = dir.listFiles();
+ if (children == null) {
+ throw new IOException("unable to list files in " + dir);
+ }
+
+ // Try to clean up existing subdirectories.
+ // (This is not guaranteed to delete all directories on Windows if a directory is locked.)
+ for (File candidate : children) {
+ if (candidate.getName().startsWith(COMPILE_DIR_PREFIX)) {
+ Util.recursiveDelete(candidate, false);
+ if (candidate.exists()) {
+ logger.log(Type.WARN, "unable to delete '" + candidate + "' (skipped)");
+ }
+ }
+ }
+
+ return new OutboxDir(dir);
+ }
+}
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
index 7093603..4f90ad0 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
@@ -61,7 +61,7 @@
*/
class Recompiler {
- private final AppSpace appSpace;
+ private final OutboxDir outboxDir;
private final LauncherDir launcherDir;
private final String inputModuleName;
@@ -84,8 +84,8 @@
private CompilerContext compilerContext;
private Options options;
- Recompiler(AppSpace appSpace, LauncherDir launcherDir, String inputModuleName, Options options) {
- this.appSpace = appSpace;
+ Recompiler(OutboxDir outboxDir, LauncherDir launcherDir, String inputModuleName, Options options) {
+ this.outboxDir = outboxDir;
this.launcherDir = launcherDir;
this.inputModuleName = inputModuleName;
this.options = options;
@@ -148,15 +148,15 @@
System.setProperty("java.awt.headless", "true");
if (System.getProperty("gwt.speedtracerlog") == null) {
System.setProperty("gwt.speedtracerlog",
- appSpace.getSpeedTracerLogFile().getAbsolutePath());
+ outboxDir.getSpeedTracerLogFile().getAbsolutePath());
}
compilerContext = compilerContextBuilder.unitCache(
- UnitCacheSingleton.get(job.getLogger(), appSpace.getUnitCacheDir())).build();
+ UnitCacheSingleton.get(job.getLogger(), outboxDir.getUnitCacheDir())).build();
}
long startTime = System.currentTimeMillis();
int compileId = ++compilesDone;
- CompileDir compileDir = makeCompileDir(compileId, job.getLogger());
+ CompileDir compileDir = outboxDir.makeCompileDir(job.getLogger());
TreeLogger compileLogger = makeCompileLogger(compileDir, job.getLogger());
job.onStarted(compileId, compileDir);
@@ -182,7 +182,7 @@
throws UnableToCompleteException {
long startTime = System.currentTimeMillis();
- CompileDir compileDir = makeCompileDir(++compilesDone, logger);
+ CompileDir compileDir = outboxDir.makeCompileDir(logger);
TreeLogger compileLogger = makeCompileLogger(compileDir, logger);
ModuleDef module = loadModule(Sets.<String>newHashSet(), compileLogger);
@@ -619,11 +619,6 @@
}
}
- private CompileDir makeCompileDir(int compileId, TreeLogger logger)
- throws UnableToCompleteException {
- return CompileDir.create(appSpace.getCompileDir(compileId), logger);
- }
-
/**
* Summarizes the inputs to a GWT compile. (Immutable.)
* Two summaries should be equal if the compiler's inputs are equal (with high probability).
diff --git a/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java
index 2e6aba9..9cc7656 100644
--- a/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java
+++ b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/RecompilerTest.java
@@ -113,8 +113,9 @@
fooResource);
writeResourcesTo(originalResources, sourcePath);
- Recompiler recompiler = new Recompiler(AppSpace.create(Files.createTempDir()), null,
- "com.foo.SimpleModule", options);
+ Recompiler recompiler =
+ new Recompiler(OutboxDir.create(Files.createTempDir(), logger), null,
+ "com.foo.SimpleModule", options);
Outbox outbox = new Outbox("Transactional Cache", recompiler, options, logger);
OutboxTable outboxes = new OutboxTable();
outboxes.addOutbox(outbox);