diff --git a/jps/jps.iml b/jps/jps.iml
index 37fa2efd45d3..725fd836a13f 100644
--- a/jps/jps.iml
+++ b/jps/jps.iml
@@ -14,7 +14,15 @@
-
+
+
+
+
+
+
+
+
+
diff --git a/jps/src/org/jetbrains/ether/DirectoryScanner.java b/jps/src/org/jetbrains/ether/DirectoryScanner.java
index 1e53416f293a..bc318ae1a0c7 100644
--- a/jps/src/org/jetbrains/ether/DirectoryScanner.java
+++ b/jps/src/org/jetbrains/ether/DirectoryScanner.java
@@ -89,11 +89,14 @@ public class DirectoryScanner {
}
if (alternative.length() > 0) {
- if (buf.length() > 0) {
- buf.append("|(");
- buf.append(alternative);
- buf.append(')');
- }
+ alternative.append(".*");
+
+ if (buf.length() > 0)
+ buf.append("|");
+
+ buf.append("(");
+ buf.append(alternative);
+ buf.append(')');
}
}
@@ -102,9 +105,10 @@ public class DirectoryScanner {
return new FileFilter() {
public boolean accept (File f) {
- final Matcher m = patt.matcher(f.getName());
+ final Matcher m = patt.matcher(f.getAbsolutePath());
+ final boolean ok = !m.matches();
- return !m.matches();
+ return ok;
}
};
}
diff --git a/jps/src/org/jetbrains/ether/Main.java b/jps/src/org/jetbrains/ether/Main.java
index 872fa8651656..2809ad79383b 100644
--- a/jps/src/org/jetbrains/ether/Main.java
+++ b/jps/src/org/jetbrains/ether/Main.java
@@ -1,5 +1,6 @@
package org.jetbrains.ether;
+import com.sun.corba.se.spi.ior.MakeImmutable;
import org.apache.tools.ant.types.Description;
import java.util.List;
@@ -16,6 +17,13 @@ import java.util.List;
public class Main {
private static final Options myOptions;
+ private enum Action {
+ REBUILD,
+ MAKE,
+ CLEAN,
+ NONE
+ }
+
static {
final Options.Descriptor[] descrs = {
new Options.Descriptor("inspect", "inspect", "i", Options.ArgumentSpecifier.OPTIONAL, "list relevant information for the whole project or specified module"),
@@ -25,14 +33,13 @@ public class Main {
new Options.Descriptor("make", "make", "m", Options.ArgumentSpecifier.OPTIONAL, "make the whole project or specified module"),
new Options.Descriptor("tests", "tests", "t", Options.ArgumentSpecifier.NONE, "make tests as well"),
new Options.Descriptor("force", "force", "f", Options.ArgumentSpecifier.NONE, "force actions"),
- new Options.Descriptor("help", "help", "h", Options.ArgumentSpecifier.NONE, "show help on options"),
- new Options.Descriptor("tests", "tests", "t", Options.ArgumentSpecifier.NONE, "make tests as well")
+ new Options.Descriptor("help", "help", "h", Options.ArgumentSpecifier.NONE, "show help on options")
};
myOptions = new Options(descrs);
}
- private static boolean doSave () {
+ private static boolean doSave() {
return myOptions.get("save") instanceof Options.Switch;
}
@@ -64,15 +71,56 @@ public class Main {
return myOptions.get("clean") instanceof Options.Switch;
}
+ private static void checkConsistency() {
+ int test = 0;
+
+ if (doClean()) test++;
+ if (doMake() != null) test++;
+ if (doRebuild()) test++;
+
+ if (test > 1) {
+ System.err.print("WARNING: Conflicting options (should be --make OR --rebuild OR --clean); preferring ");
+ if (doMake() != null)
+ System.err.println("make.");
+ else if (doRebuild())
+ System.err.println("rebuild.");
+ }
+
+ if (doClean() || doRebuild()) {
+ if (doTests()) {
+ System.err.println("WARNING: extra --tests option ignored.");
+ }
+ if (doForce()) {
+ System.err.println("WARNING: extra --force option ignored.");
+ }
+ }
+ }
+
+ private static Action getAction() {
+ if (doMake() != null) {
+ return Action.MAKE;
+ }
+
+ if (doRebuild())
+ return Action.REBUILD;
+
+ if (doClean())
+ return Action.CLEAN;
+
+ return Action.NONE;
+ }
+
public static void main(String[] args) {
System.out.println("JetBrains.com build server. (C) JetBrains.com, 2010.\n");
final List notes = myOptions.parse(args);
for (String note : notes) {
- System.err.println("Warning: " + note);
+ System.err.println("WARNING: " + note);
}
+ checkConsistency();
+
if (doHelp()) {
System.out.println("Usage: ??? \n");
System.out.println("Options are:");
@@ -81,7 +129,7 @@ public class Main {
final List projects = myOptions.getFree();
- if (projects.isEmpty() && ! doHelp()) {
+ if (projects.isEmpty() && !doHelp()) {
System.out.println("Nothing to do; use --help or -h option to see the help.\n");
}
@@ -89,39 +137,43 @@ public class Main {
final ProjectWrapper project = new ProjectWrapper(prj);
boolean saved = false;
- if (doClean()) {
- System.out.println("Cleaning project \"" + prj + "\"");
- project.load();
- project.clean();
- project.save();
- saved = true;
- }
+ switch (getAction()) {
+ case CLEAN:
- if (doRebuild()) {
- System.out.println("Rebuilding project \"" + prj + "\"");
- project.load();
- project.rebuild();
- project.save();
- saved = true;
- }
+ System.out.println("Cleaning project \"" + prj + "\"");
+ project.load();
+ project.clean();
+ project.save();
+ saved = true;
+ break;
- final Options.Argument make = doMake();
+ case REBUILD:
+ System.out.println("Rebuilding project \"" + prj + "\"");
+ project.load();
+ project.rebuild();
+ project.save();
+ saved = true;
+ break;
- if (make instanceof Options.Value) {
- final String module = ((Options.Value) make).get();
+ case MAKE:
+ final Options.Argument make = doMake();
- System.out.println("Making module \"" + module + "\" in project \"" + prj + "\"");
- project.load();
- project.makeModule(module, doForce(), doTests());
- project.save();
- saved = true;
- }
- else if (make instanceof Options.Switch) {
- System.out.println("Making project \"" + prj + "\"");
- project.load();
- project.make(doForce (), doTests());
- project.save();
- saved = true;
+ if (make instanceof Options.Value) {
+ final String module = ((Options.Value) make).get();
+
+ System.out.println("Making module \"" + module + "\" in project \"" + prj + "\"");
+ project.load();
+ project.makeModule(module, doForce(), doTests());
+ project.save();
+ saved = true;
+ } else if (make instanceof Options.Switch) {
+ System.out.println("Making project \"" + prj + "\"");
+ project.load();
+ project.make(doForce(), doTests());
+ project.save();
+ saved = true;
+ };
+ break;
}
final Options.Argument inspect = doInspect();
diff --git a/jps/src/org/jetbrains/ether/ModuleStatus.java b/jps/src/org/jetbrains/ether/ModuleStatus.java
index 46b072e4cd25..5435bada9639 100644
--- a/jps/src/org/jetbrains/ether/ModuleStatus.java
+++ b/jps/src/org/jetbrains/ether/ModuleStatus.java
@@ -50,7 +50,13 @@ public class ModuleStatus {
System.err.println("Error converting string \"" + s + "\" to ModuleStatus");
}
- public boolean isOutdated(){
- return (myOutputStamp <= mySourceStamp) || (myTestOutputStamp <= myTestSourceStamp);
+ private static boolean wiseCompare (long input, long output) {
+ final boolean result = (input > 0 && output == Long.MAX_VALUE) || (output <= input);
+ return result;
+ }
+
+ public boolean isOutdated(boolean tests) {
+ final boolean result = wiseCompare(mySourceStamp, myOutputStamp) || (tests && wiseCompare(myTestSourceStamp, myTestOutputStamp));
+ return result;
}
}
diff --git a/jps/src/org/jetbrains/ether/Options.java b/jps/src/org/jetbrains/ether/Options.java
index 08430c9de529..cc452bad35a6 100644
--- a/jps/src/org/jetbrains/ether/Options.java
+++ b/jps/src/org/jetbrains/ether/Options.java
@@ -165,7 +165,7 @@ public class Options {
callback.update(myKey, SWITCH);
break;
case MANDATORY:
- callback.report("option \"" + arg + "\" requires an argument, discarding");
+ callback.report("option \"" + arg + "\" requires an argument, discarding.");
}
};
@@ -181,7 +181,7 @@ public class Options {
switch (myArgumentSpecifier) {
case MANDATORY:
if (prm == null)
- callback.report("option \"" + arg + "\" requires an argument, discarding");
+ callback.report("option \"" + arg + "\" requires an argument, discarding.");
else
callback.update(myKey, new Value (prm));
break;
@@ -190,7 +190,7 @@ public class Options {
if (prm == null)
callback.update(myKey, SWITCH);
else
- callback.report("option \"" + arg + "\" does not take an argument, omitting");
+ callback.report("option \"" + arg + "\" does not take an argument, omitting.");
break;
case OPTIONAL:
@@ -239,7 +239,7 @@ public class Options {
recognized |= myDescriptors[i].proceed(cursor, cb);
if (!recognized) {
- cb.report("unrecognized option \"" + cursor.look() + "\" omitted");
+ cb.report("unrecognized option \"" + cursor.look() + "\" omitted.");
cursor.shift();
}
}
diff --git a/jps/src/org/jetbrains/ether/ProjectSnapshot.java b/jps/src/org/jetbrains/ether/ProjectSnapshot.java
index 4f37a4c1de8c..421f298272be 100644
--- a/jps/src/org/jetbrains/ether/ProjectSnapshot.java
+++ b/jps/src/org/jetbrains/ether/ProjectSnapshot.java
@@ -68,22 +68,6 @@ public class ProjectSnapshot {
}
public boolean structureChanged (final ProjectSnapshot p) {
- /*
- try {
- Writer fo1 = new BufferedWriter(new FileWriter("/home/db/tmp/1.history"));
- Writer fo2 = new BufferedWriter(new FileWriter("/home/db/tmp/2.history"));
-
- fo1.write(p.myProjectStructure);
- fo2.write(myProjectStructure);
-
- fo1.close();
- fo2.close();
- }
- catch (IOException e) {
-
- }
- */
-
return ! p.myProjectStructure.equals(myProjectStructure);
}
}
diff --git a/jps/src/org/jetbrains/ether/ProjectWrapper.java b/jps/src/org/jetbrains/ether/ProjectWrapper.java
index eaa0885631a2..eeeaaff01707 100644
--- a/jps/src/org/jetbrains/ether/ProjectWrapper.java
+++ b/jps/src/org/jetbrains/ether/ProjectWrapper.java
@@ -1,5 +1,6 @@
package org.jetbrains.ether;
+import com.sun.org.apache.xpath.internal.operations.Mod;
import org.codehaus.gant.GantBinding;
import org.jetbrains.jps.ClasspathItem;
import org.jetbrains.jps.Module;
@@ -17,7 +18,7 @@ import java.util.*;
* To change this template use File | Settings | File Templates.
*/
public class ProjectWrapper {
- // Home direcroty
+ // Home directory
private static final String myHomeDir = System.getProperty("user.home");
// JPS directory
@@ -113,7 +114,8 @@ public class ProjectWrapper {
if (m == null) {
System.out.println("No module \"" + module + "\" found in project \"");
} else {
- System.out.println("Module " + m.myName + " " + (m.isOutdated() ? "is outdated" : "is up-to-date"));
+ System.out.println("Module " + m.myName + " " + (m.isOutdated(false) ? "is outdated" : "is up-to-date"));
+ System.out.println("Module " + m.myName + " tests " + (m.isOutdated(true) ? "are outdated" : "are up-to-date"));
}
}
@@ -140,7 +142,8 @@ public class ProjectWrapper {
if (moduleReport) {
for (ModuleStatus mh : myPresent.myModuleHistories.values()) {
- System.out.println(" module " + mh.myName + " " + (mh.isOutdated() ? "is outdated" : "is up-to-date"));
+ System.out.println(" module " + mh.myName + " " + (mh.isOutdated(false) ? "is outdated" : "is up-to-date"));
+ System.out.println(" module " + mh.myName + " tests " + (mh.isOutdated(true) ? "are outdated" : "are up-to-date"));
}
}
}
@@ -167,7 +170,7 @@ public class ProjectWrapper {
final List modules = new ArrayList();
for (Map.Entry entry : myPresent.myModuleHistories.entrySet()) {
- if (entry.getValue().isOutdated())
+ if (entry.getValue().isOutdated(tests))
modules.add(myProject.getModules().get(entry.getKey()));
}
@@ -186,25 +189,37 @@ public class ProjectWrapper {
private void makeModules(final List initial, final boolean tests) {
final Set modules = new HashSet();
+ final Map> reversedDependencies = new HashMap> ();
+
+ for (Module m : myProject.getModules().values()) {
+ for (Module.ModuleDependency mdep : m.getDependencies()) {
+ final ClasspathItem cpi = mdep.getItem();
+
+ if (cpi instanceof Module) {
+ Set sm = reversedDependencies.get(cpi);
+
+ if (sm == null) {
+ sm = new HashSet ();
+ reversedDependencies.put((Module) cpi, sm);
+ }
+
+ sm.add(m);
+ }
+ }
+ }
new Object() {
- public void run(final List initial) {
+ public void run(final Collection initial) {
+ if (initial == null)
+ return;
+
for (Module module : initial) {
if (modules.contains(module))
- return;
+ continue;
modules.add(module);
- final List successors = new ArrayList();
-
- for (Module.ModuleDependency dep : module.getDependencies()) {
- final ClasspathItem cpi = dep.getItem();
-
- if (cpi instanceof Module) {
- successors.add((Module) cpi);
- }
- }
- run(successors);
+ run(reversedDependencies.get(module));
}
}
}.run(initial);
@@ -230,7 +245,7 @@ public class ProjectWrapper {
}
final ModuleStatus h = myPresent.myModuleHistories.get(modName);
- if (h != null && !h.isOutdated() && !force) {
+ if (h != null && !h.isOutdated(tests) && !force) {
System.out.println("Module \"" + modName + "\" in project \"" + myRoot + "\" is up-to-date.");
return;
}
diff --git a/jps/src/org/jetbrains/ether/Reporter.java b/jps/src/org/jetbrains/ether/Reporter.java
new file mode 100644
index 000000000000..7115847889ee
--- /dev/null
+++ b/jps/src/org/jetbrains/ether/Reporter.java
@@ -0,0 +1,74 @@
+package org.jetbrains.ether;
+
+import org.jetbrains.jps.Module;
+
+import java.io.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: db
+ * Date: 03.12.10
+ * Time: 19:39
+ * To change this template use File | Settings | File Templates.
+ */
+public class Reporter {
+ private static final String myOkFlag = ".jps.ok";
+ private static final String myFailFlag = ".jps.fail";
+
+ private static String getSafePath (final String path) {
+ final File f = new File(path);
+
+ if (! f.exists()) {
+ f.mkdir();
+ }
+
+ return path;
+ }
+
+ private static String getOkFlag(final Module m) {
+ return getSafePath (m.getOutputPath()) + File.separator + myOkFlag;
+ }
+
+ private static String getFailFlag(final Module m) {
+ return getSafePath (m.getOutputPath()) + File.separator + myFailFlag;
+ }
+
+ private static String getOkTestFlag(final Module m) {
+ return getSafePath (m.getTestOutputPath()) + File.separator + myOkFlag;
+ }
+
+ private static String getFailTestFlag(final Module m) {
+ return getSafePath(m.getTestOutputPath()) + File.separator + myFailFlag;
+ }
+
+ private static void write(final String name, final String contents) {
+ try {
+ final BufferedWriter out = new BufferedWriter(new FileWriter(name));
+ out.write(contents);
+ out.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void reportBuildSuccess(final Module m, final boolean tests) {
+ write(getOkFlag(m), "dummy");
+ if (tests) {
+ write(getOkTestFlag(m), "dummy");
+ }
+ }
+
+ public static void reportBuildFailure(final Module m, final boolean tests, final String reason) {
+ write(getFailFlag(m), reason);
+ if (tests) {
+ write(getFailTestFlag(m), reason);
+ }
+ }
+
+ public static boolean failureReported (final Module m, final boolean tests) {
+ final File o = new File(getFailFlag(m));
+ final File t = new File(getFailTestFlag(m));
+
+ return o.exists() || (tests && t.exists());
+ }
+}
diff --git a/jps/src/org/jetbrains/jps/ProjectBuilder.groovy b/jps/src/org/jetbrains/jps/ProjectBuilder.groovy
index 290eb722d444..3c691a405d36 100644
--- a/jps/src/org/jetbrains/jps/ProjectBuilder.groovy
+++ b/jps/src/org/jetbrains/jps/ProjectBuilder.groovy
@@ -7,8 +7,9 @@ import org.jetbrains.jps.listeners.BuildStatisticsListener
import org.jetbrains.jps.listeners.DefaultBuildInfoPrinter
import org.jetbrains.jps.listeners.JpsBuildListener
import org.jetbrains.jps.builders.*
+import org.jetbrains.ether.Reporter
- /**
+/**
* @author max
*/
class ProjectBuilder {
@@ -70,8 +71,8 @@ class ProjectBuilder {
buildAllModules(true)
}
- public def buildSelected (Collection modules, boolean tests) {
- buildModules (modules, tests)
+ public def buildSelected(Collection modules, boolean tests) {
+ buildModules(modules, tests)
}
public def buildProduction() {
@@ -84,12 +85,12 @@ class ProjectBuilder {
listeners*.onBuildFinished(project)
}
- private def clearChunks (Collection modules) {
+ private def clearChunks(Collection modules) {
getChunks(true).getChunkList().each {
- if (!modules.intersect(it.modules).isEmpty()) {
- clearChunk(it)
- }
- }
+ if (!modules.intersect(it.modules).isEmpty()) {
+ clearChunk(it)
+ }
+ }
}
private def buildModules(Collection modules, boolean includeTests) {
@@ -146,7 +147,7 @@ class ProjectBuilder {
buildModules(dependencies, includeTests)
}
- private def clearChunk (ModuleChunk chunk) {
+ private def clearChunk(ModuleChunk chunk) {
if (!project.dryRun) {
project.stage("Cleaning module ${chunk.name}")
chunk.modules.each {project.cleanModule it}
@@ -194,6 +195,10 @@ class ProjectBuilder {
}
private def compile(ModuleChunk chunk, boolean tests) {
+ if (chunk.toString().startsWith("ModuleChunk")) {
+ final String x = "";
+ }
+
List chunkSources = filterNonExistingFiles(tests ? chunk.testRoots : chunk.sourceRoots, true)
if (chunkSources.isEmpty()) return
@@ -202,21 +207,21 @@ class ProjectBuilder {
List chunkDependenciesSourceRoots = transitiveModuleDependenciesSourcePaths(chunk, tests)
Map states = new HashMap()
def chunkState = new ModuleBuildState(
- sourceRoots: chunkSources,
- excludes: chunk.excludes,
- classpath: chunkClasspath,
- moduleDependenciesSourceRoots: chunkDependenciesSourceRoots,
+ sourceRoots: chunkSources,
+ excludes: chunk.excludes,
+ classpath: chunkClasspath,
+ moduleDependenciesSourceRoots: chunkDependenciesSourceRoots,
)
if (arrangeModuleCyclesOutputs) {
chunk.modules.each {
List sourceRoots = filterNonExistingFiles(tests ? it.testRoots : it.sourceRoots, false)
if (!sourceRoots.isEmpty()) {
def state = new ModuleBuildState(
- sourceRoots: sourceRoots,
- excludes: it.excludes,
- classpath: chunkClasspath,
- targetFolder: createOutputFolder(it.name, it, tests),
- moduleDependenciesSourceRoots: chunkDependenciesSourceRoots
+ sourceRoots: sourceRoots,
+ excludes: it.excludes,
+ classpath: chunkClasspath,
+ targetFolder: createOutputFolder(it.name, it, tests),
+ moduleDependenciesSourceRoots: chunkDependenciesSourceRoots
)
states[state] = new ModuleChunk(it)
}
@@ -234,15 +239,27 @@ class ProjectBuilder {
}
listeners*.onCompilationStarted(chunk)
- builders().each {ModuleBuilder builder ->
- listeners*.onModuleBuilderStarted(builder, chunk)
- if (arrangeModuleCyclesOutputs && chunk.modules.size() > 1 && builder instanceof ModuleCycleBuilder) {
- ((ModuleCycleBuilder) builder).preprocessModuleCycle(chunkState, chunk, project)
+
+ try {
+ builders().each {ModuleBuilder builder ->
+ listeners*.onModuleBuilderStarted(builder, chunk)
+ if (arrangeModuleCyclesOutputs && chunk.modules.size() > 1 && builder instanceof ModuleCycleBuilder) {
+ ((ModuleCycleBuilder) builder).preprocessModuleCycle(chunkState, chunk, project)
+ }
+ states.keySet().each {
+ builder.processModule(it, states[it], project)
+ }
+ listeners*.onModuleBuilderFinished(builder, chunk)
}
- states.keySet().each {
- builder.processModule(it, states[it], project)
+ }
+ catch (Exception e) {
+ final String reason = e.toString();
+
+ chunk.modules.each {
+ Reporter.reportBuildFailure (it, tests, reason)
}
- listeners*.onModuleBuilderFinished(builder, chunk)
+
+ throw e;
}
states.keySet().each {
@@ -257,6 +274,7 @@ class ProjectBuilder {
}
chunk.modules.each {
+ Reporter.reportBuildSuccess (it, tests)
project.exportProperty("module.${it.name}.output.${tests ? "test" : "main"}", getModuleOutputFolder(it, tests))
}
}
@@ -355,7 +373,7 @@ class ProjectBuilder {
private def collectPathTransitively(Object chunkOrModule, boolean collectSources, ClasspathKind classpathKind, Set set, Set