--- a/langtools/src/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java Mon Aug 11 10:05:15 2014 -0700
@@ -86,15 +86,9 @@
boolean concurrentCompiles = true;
// Fetch the id.
- String idOpt = Util.extractStringOption("id", args.getServerConf());
- if (idOpt == null || idOpt.equals("")) {
- // No explicit id set. Create a random id so that the requests can be
- // grouped properly in the server.
- idOpt = "id"+(((new Random()).nextLong())&Long.MAX_VALUE);
- }
- final String id = idOpt;
+ final String id = Util.extractStringOption("id", javacService.serverSettings());
// Only keep portfile and sjavac settings..
- String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), args.getServerConf());
+ String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), javacService.serverSettings());
// Get maximum heap size from the server!
SysInfo sysinfo = javacService.getSysInfo();
--- a/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java Mon Aug 11 10:05:15 2014 -0700
@@ -60,7 +60,6 @@
int numCores;
// The bin_dir/javac_state
- private String javacStateFilename;
private File javacState;
// The previous build state is loaded from javac_state
@@ -99,7 +98,7 @@
private Set<String> recompiledPackages;
// The output directories filled with tasty artifacts.
- private File binDir, gensrcDir, headerDir;
+ private File binDir, gensrcDir, headerDir, stateDir;
// The current status of the file system.
private Set<File> binArtifacts;
@@ -128,7 +127,11 @@
// Where to send stdout and stderr.
private PrintStream out, err;
- JavacState(Options options, boolean removeJavacState, PrintStream o, PrintStream e) {
+ // Command line options.
+ private Options options;
+
+ JavacState(Options op, boolean removeJavacState, PrintStream o, PrintStream e) {
+ options = op;
out = o;
err = e;
numCores = options.getNumCores();
@@ -136,8 +139,8 @@
binDir = Util.pathToFile(options.getDestDir());
gensrcDir = Util.pathToFile(options.getGenSrcDir());
headerDir = Util.pathToFile(options.getHeaderDir());
- javacStateFilename = binDir.getPath()+File.separator+"javac_state";
- javacState = new File(javacStateFilename);
+ stateDir = Util.pathToFile(options.getStateDir());
+ javacState = new File(stateDir, "javac_state");
if (removeJavacState && javacState.exists()) {
javacState.delete();
}
@@ -148,7 +151,7 @@
// We do not want to risk building a broken incremental build.
// BUT since the makefiles still copy things straight into the bin_dir et al,
// we avoid deleting files here, if the option --permit-unidentified-classes was supplied.
- if (!options.isUnidentifiedArtifactPermitted()) {
+ if (!options.areUnidentifiedArtifactsPermitted()) {
deleteContents(binDir);
deleteContents(gensrcDir);
deleteContents(headerDir);
@@ -268,7 +271,7 @@
*/
public void save() throws IOException {
if (!needsSaving) return;
- try (FileWriter out = new FileWriter(javacStateFilename)) {
+ try (FileWriter out = new FileWriter(javacState)) {
StringBuilder b = new StringBuilder();
long millisNow = System.currentTimeMillis();
Date d = new Date(millisNow);
@@ -311,7 +314,7 @@
boolean newCommandLine = false;
boolean syntaxError = false;
- try (BufferedReader in = new BufferedReader(new FileReader(db.javacStateFilename))) {
+ try (BufferedReader in = new BufferedReader(new FileReader(db.javacState))) {
for (;;) {
String l = in.readLine();
if (l==null) break;
@@ -512,7 +515,8 @@
allKnownArtifacts.add(javacState);
for (File f : binArtifacts) {
- if (!allKnownArtifacts.contains(f)) {
+ if (!allKnownArtifacts.contains(f) &&
+ !options.isUnidentifiedArtifactPermitted(f.getAbsolutePath())) {
Log.debug("Removing "+f.getPath()+" since it is unknown to the javac_state.");
f.delete();
}
@@ -605,13 +609,16 @@
/**
* Recursively delete a directory and all its contents.
*/
- private static void deleteContents(File dir) {
+ private void deleteContents(File dir) {
if (dir != null && dir.exists()) {
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
deleteContents(f);
}
- f.delete();
+ if (!options.isUnidentifiedArtifactPermitted(f.getAbsolutePath())) {
+ Log.debug("Removing "+f.getAbsolutePath());
+ f.delete();
+ }
}
}
}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Main.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Main.java Mon Aug 11 10:05:15 2014 -0700
@@ -205,6 +205,9 @@
if (!createIfMissing(options.getDestDir()))
return -1;
+ if (!createIfMissing(options.getStateDir()))
+ return -1;
+
Path gensrc = options.getGenSrcDir();
if (gensrc != null && !createIfMissing(gensrc))
return -1;
@@ -302,7 +305,7 @@
// For examples, files that have been manually copied into these dirs.
// Artifacts with bad timestamps (ie the on disk timestamp does not match the timestamp
// in javac_state) have already been removed when the javac_state was loaded.
- if (!options.isUnidentifiedArtifactPermitted()) {
+ if (!options.areUnidentifiedArtifactsPermitted()) {
javac_state.removeUnidentifiedArtifacts();
}
// Go through all sources and taint all packages that miss artifacts.
@@ -345,7 +348,7 @@
// Currently sjavac always connects to a server through a socket
// regardless if sjavac runs as a background service or not.
// This will most likely change in the future.
- JavacService javacService = new JavacServiceClient(options.getServerConf());
+ JavacService javacService = new JavacServiceClient(options);
again = javac_state.performJavaCompilations(javacService, options, recently_compiled, rc);
if (!rc[0]) break;
} while (again);
@@ -375,8 +378,6 @@
err = "Please specify output directory.";
} else if (options.isJavaFilesAmongJavacArgs()) {
err = "Sjavac does not handle explicit compilation of single .java files.";
- } else if (options.isAtFilePresent()) {
- err = "Sjavac does not handle @-files.";
} else if (options.getServerConf() == null) {
err = "No server configuration provided.";
} else if (!options.getImplicitPolicy().equals("none")) {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/JavacServiceImpl.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/JavacServiceImpl.java Mon Aug 11 10:05:15 2014 -0700
@@ -143,4 +143,10 @@
return compilationResult;
}
+
+ @Override
+ public String serverSettings() {
+ return "";
+ }
+
}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/options/Option.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/options/Option.java Mon Aug 11 10:05:15 2014 -0700
@@ -231,7 +231,14 @@
helper.logLevel("info");
}
},
- PERMIT_UNIDENTIFIED_ARTIFACTS("--permit-unidentified-artifacts", "Keep unidentified artifacts in destination directory") {
+ PERMIT_ARTIFACT("--permit-artifact=", "Allow this artifact in destination directory") {
+ @Override
+ protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
+ String a = iter.current().substring(arg.length());
+ helper.permitArtifact(Paths.get(a).toFile().getAbsolutePath());
+ }
+ },
+ PERMIT_UNIDENTIFIED_ARTIFACTS("--permit-unidentified-artifacts", "Allow unidentified artifacts in destination directory") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
helper.permitUnidentifiedArtifacts();
@@ -274,8 +281,16 @@
if (dir != null)
helper.headerDir(dir);
}
+ },
+ STATE_DIR("--state-dir=", "Directory used to store sjavac state and log files.") {
+ @Override
+ protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
+ String p = iter.current().substring(arg.length());
+ helper.stateDir(Paths.get(p));
+ }
};
+
public final String arg;
final String description;
--- a/langtools/src/share/classes/com/sun/tools/sjavac/options/OptionHelper.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/options/OptionHelper.java Mon Aug 11 10:05:15 2014 -0700
@@ -25,12 +25,14 @@
package com.sun.tools.sjavac.options;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
+import com.sun.tools.javac.main.CommandLine;
import com.sun.tools.sjavac.Transformer;
/**
@@ -78,6 +80,9 @@
/** Record path for reference source list */
public abstract void compareFoundSources(Path referenceList);
+ /** Record a single permitted artifact */
+ public abstract void permitArtifact(String f);
+
/** Record the fact that unidentified artifacts are permitted */
public abstract void permitUnidentifiedArtifacts();
@@ -102,6 +107,9 @@
/** Sets the directory for generated headers */
public abstract void headerDir(Path dir);
+ /** Sets the directory for state and log files generated by sjavac */
+ public abstract void stateDir(Path dir);
+
/** Sets the implicit policy */
public abstract void implicit(String policy);
@@ -112,7 +120,11 @@
* @param args the arguments to traverse.
*/
void traverse(String[] args) {
-
+ try {
+ args = CommandLine.parse(args); // Detect @file and load it as a command line.
+ } catch (java.io.IOException e) {
+ throw new IllegalArgumentException("Problem reading @"+e.getMessage());
+ }
ArgumentIterator argIter = new ArgumentIterator(Arrays.asList(args));
nextArg:
--- a/langtools/src/share/classes/com/sun/tools/sjavac/options/Options.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/options/Options.java Mon Aug 11 10:05:15 2014 -0700
@@ -32,6 +32,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
import com.sun.tools.sjavac.Transformer;
@@ -41,7 +43,7 @@
public class Options {
// Output directories
- private Path destDir, genSrcDir, headerDir;
+ private Path destDir, genSrcDir, headerDir, stateDir;
// Input directories
private List<SourceLocation> sources = new ArrayList<>();
@@ -51,7 +53,8 @@
private String logLevel = "info";
- private boolean permitUnidentifiedArtifact = false;
+ private Set<String> permitted_artifacts = new HashSet<>();
+ private boolean permitUnidentifiedArtifacts = false;
private boolean permitSourcesInDefaultPackage = false;
private Path sourceReferenceList;
@@ -86,6 +89,11 @@
return headerDir;
}
+ /** Get the path for the state directory, defaults to destDir. */
+ public Path getStateDir() {
+ return stateDir != null ? stateDir : destDir;
+ }
+
/** Get all source locations for files to be compiled */
public List<SourceLocation> getSources() {
return sources;
@@ -114,10 +122,15 @@
return logLevel;
}
+ /** Returns true iff the artifact is permitted in the output dir. */
+ public boolean isUnidentifiedArtifactPermitted(String f) {
+ return permitted_artifacts.contains(f);
+ }
+
/** Returns true iff artifacts in the output directories should be kept,
* even if they would not be generated in a clean build. */
- public boolean isUnidentifiedArtifactPermitted() {
- return permitUnidentifiedArtifact;
+ public boolean areUnidentifiedArtifactsPermitted() {
+ return permitUnidentifiedArtifacts;
}
/** Returns true iff sources in the default package should be permitted. */
@@ -176,14 +189,6 @@
return false;
}
- /** Returns true iff an @-file is among the javac arguments */
- public boolean isAtFilePresent() {
- for (String javacArg : javacArgs)
- if (javacArg.startsWith("@"))
- return true;
- return false;
- }
-
/**
* Returns a string representation of the options that affect the result of
* the compilation. (Used for saving the state of the options used in a
@@ -239,6 +244,9 @@
if (destDir != null)
args.addArg(Option.D, destDir.normalize());
+ if (stateDir != null)
+ args.addArg(Option.STATE_DIR, stateDir.normalize());
+
// Source roots
args.addSourceLocations(Option.SRC, sources);
args.addSourceLocations(Option.SOURCEPATH, sourceSearchPaths);
@@ -249,7 +257,11 @@
if (permitSourcesInDefaultPackage)
args.addArg(Option.PERMIT_SOURCES_WITHOUT_PACKAGE);
- if (permitUnidentifiedArtifact)
+ for (String f : permitted_artifacts) {
+ args.addArg(Option.PERMIT_ARTIFACT, f);
+ }
+
+ if (permitUnidentifiedArtifacts)
args.addArg(Option.PERMIT_UNIDENTIFIED_ARTIFACTS);
// Translation rules
@@ -327,6 +339,7 @@
boolean headerProvided = false;
boolean genSrcProvided = false;
+ boolean stateProvided = false;
@Override
public void reportError(String msg) {
@@ -399,8 +412,13 @@
}
@Override
+ public void permitArtifact(String f) {
+ permitted_artifacts.add(f);
+ }
+
+ @Override
public void permitUnidentifiedArtifacts() {
- permitUnidentifiedArtifact = true;
+ permitUnidentifiedArtifacts = true;
}
@Override
@@ -465,6 +483,16 @@
headerDir = dir.toAbsolutePath();
}
+ @Override
+ public void stateDir(Path dir) {
+ if (stateProvided) {
+ reportError("State directory already specified.");
+ return;
+ }
+ stateProvided = true;
+ stateDir = dir.toAbsolutePath();
+ }
+
private List<SourceLocation> createSourceLocations(List<Path> paths) {
List<SourceLocation> result = new ArrayList<>();
for (Path path : paths) {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacService.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacService.java Mon Aug 11 10:05:15 2014 -0700
@@ -40,4 +40,5 @@
List<File> explicitSources,
Set<URI> sourcesToCompile,
Set<URI> visibleSources);
+ String serverSettings();
}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacServiceClient.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacServiceClient.java Mon Aug 11 10:05:15 2014 -0700
@@ -46,6 +46,7 @@
import java.util.Set;
import com.sun.tools.sjavac.Util;
+import com.sun.tools.sjavac.options.Options;
import static com.sun.tools.sjavac.server.CompilationResult.ERROR_BUT_TRY_AGAIN;
import static com.sun.tools.sjavac.server.CompilationResult.ERROR_FATAL;
@@ -72,19 +73,34 @@
// for example by setting: sjavac=java%20-jar%20...javac.jar%com.sun.tools.sjavac.Main
private final String sjavac;
- public JavacServiceClient(String settings) {
- id = Util.extractStringOption("id", settings);
- portfile = Util.extractStringOption("portfile", settings);
- logfile = Util.extractStringOption("logfile", settings, portfile + ".javaclog");
- stdouterrfile = Util.extractStringOption("stdouterrfile", settings, portfile + ".stdouterr");
- background = Util.extractBooleanOption("background", settings, true);
- sjavac = Util.extractStringOption("sjavac", settings, "sjavac");
- int poolsize = Util.extractIntOption("poolsize", settings);
- keepalive = Util.extractIntOption("keepalive", settings, 120);
+ // Store the server conf settings here.
+ private final String settings;
+
+ public JavacServiceClient(Options options) {
+ String tmpServerConf = options.getServerConf();
+ String serverConf = (tmpServerConf!=null)? tmpServerConf : "";
+ String tmpId = Util.extractStringOption("id", serverConf);
+ id = (tmpId!=null) ? tmpId : "id"+(((new java.util.Random()).nextLong())&Long.MAX_VALUE);
+ String p = Util.extractStringOption("portfile", serverConf);
+ portfile = (p!=null) ? p : options.getStateDir().toFile().getAbsolutePath()+File.separatorChar+"javac_server";
+ logfile = Util.extractStringOption("logfile", serverConf, portfile + ".javaclog");
+ stdouterrfile = Util.extractStringOption("stdouterrfile", serverConf, portfile + ".stdouterr");
+ background = Util.extractBooleanOption("background", serverConf, true);
+ sjavac = Util.extractStringOption("sjavac", serverConf, "sjavac");
+ int poolsize = Util.extractIntOption("poolsize", serverConf);
+ keepalive = Util.extractIntOption("keepalive", serverConf, 120);
this.poolsize = poolsize > 0 ? poolsize : Runtime.getRuntime().availableProcessors();
+ settings = (serverConf.equals("")) ? "id="+id+",portfile="+portfile : serverConf;
}
+ /**
+ * Hand out the server settings.
+ * @return The server settings, possibly a default value.
+ */
+ public String serverSettings() {
+ return settings;
+ }
/**
* Make a request to the server only to get the maximum possible heap size to use for compilations.
--- a/langtools/test/tools/sjavac/OptionDecoding.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/test/tools/sjavac/OptionDecoding.java Mon Aug 11 10:05:15 2014 -0700
@@ -25,7 +25,7 @@
/*
* @test
- * @bug 8035063
+ * @bug 8035063 8054465
* @summary Tests decoding of String[] into Options.
*
* @build Wrapper
@@ -192,13 +192,16 @@
assertEquals(17, options.getNumCores());
assertEquals("debug", options.getLogLevel());
assertEquals(false, options.isDefaultPackagePermitted());
- assertEquals(false, options.isUnidentifiedArtifactPermitted());
+ assertEquals(false, options.areUnidentifiedArtifactsPermitted());
+ assertEquals(false, options.isUnidentifiedArtifactPermitted(Paths.get("bar.txt").toFile().getAbsolutePath()));
options = Options.parseArgs("--permit-unidentified-artifacts",
+ "--permit-artifact=bar.txt",
"--permit-sources-without-package");
assertEquals("info", options.getLogLevel());
assertEquals(true, options.isDefaultPackagePermitted());
- assertEquals(true, options.isUnidentifiedArtifactPermitted());
+ assertEquals(true, options.areUnidentifiedArtifactsPermitted());
+ assertEquals(true, options.isUnidentifiedArtifactPermitted(Paths.get("bar.txt").toFile().getAbsolutePath()));
}
// Test server configuration options
--- a/langtools/test/tools/sjavac/SJavac.java Sun Aug 10 19:39:06 2014 -0700
+++ b/langtools/test/tools/sjavac/SJavac.java Mon Aug 11 10:05:15 2014 -0700
@@ -25,7 +25,7 @@
/*
* @test
* @summary Test all aspects of sjavac.
- * @bug 8004658 8042441 8042699
+ * @bug 8004658 8042441 8042699 8054461 8054474 8054465
*
* @build Wrapper
* @run main Wrapper SJavac
@@ -99,6 +99,9 @@
compileCircularSources();
compileExcludingDependency();
incrementalCompileTestFullyQualifiedRef();
+ compileWithAtFile();
+ testStateDir();
+ testPermittedArtifact();
delete(gensrc);
delete(gensrc2);
@@ -463,6 +466,98 @@
"bin/javac_state");
}
+ /**
+ * Tests @atfile
+ * @throws Exception If test fails
+ */
+ void compileWithAtFile() throws Exception {
+ System.out.println("\nTest @atfile with command line content.");
+ System.out.println("---------------------------------------");
+
+ delete(gensrc);
+ delete(gensrc2);
+ delete(bin);
+
+ populate(gensrc,
+ "list.txt",
+ "-if */alfa/omega/A.java\n-if */beta/B.java\ngensrc\n-d bin\n",
+ "alfa/omega/A.java",
+ "package alfa.omega; import beta.B; public class A { B b; }",
+ "beta/B.java",
+ "package beta; public class B { }",
+ "beta/C.java",
+ "broken");
+ previous_bin_state = collectState(bin);
+ compile("@gensrc/list.txt", "--server:portfile=testserver,background=false");
+
+ Map<String,Long> new_bin_state = collectState(bin);
+ verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
+ "bin/javac_state",
+ "bin/alfa/omega/A.class",
+ "bin/beta/B.class");
+ }
+
+ /**
+ * Tests storing javac_state into another directory.
+ * @throws Exception If test fails
+ */
+ void testStateDir() throws Exception {
+ System.out.println("\nVerify that --state-dir=bar works.");
+ System.out.println("----------------------------------");
+
+ Path bar = defaultfs.getPath("bar");
+ Files.createDirectory(bar);
+
+ delete(gensrc);
+ delete(bin);
+ delete(bar);
+ previous_bin_state = collectState(bin);
+ Map<String,Long> previous_bar_state = collectState(bar);
+
+ populate(gensrc,
+ "alfa/omega/A.java",
+ "package alfa.omega; public class A { }");
+
+ compile("--state-dir=bar", "-src", "gensrc", "-d", "bin", serverArg);
+
+ Map<String,Long> new_bin_state = collectState(bin);
+ verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
+ "bin/alfa/omega/A.class");
+ Map<String,Long> new_bar_state = collectState(bar);
+ verifyThatFilesHaveBeenAdded(previous_bar_state, new_bar_state,
+ "bar/javac_state");
+ }
+
+ /**
+ * Test white listing of external artifacts inside the destination dir.
+ * @throws Exception If test fails
+ */
+ void testPermittedArtifact() throws Exception {
+ System.out.println("\nVerify that --permit-artifact=bar works.");
+ System.out.println("-------------------------------------------");
+
+ delete(gensrc);
+ delete(bin);
+
+ previous_bin_state = collectState(bin);
+
+ populate(gensrc,
+ "alfa/omega/A.java",
+ "package alfa.omega; public class A { }");
+
+ populate(bin,
+ "alfa/omega/AA.class",
+ "Ugh, a messy build system (tobefixed) wrote this class file, sjavac must not delete it.");
+
+ compile("--log=debug", "--permit-artifact=bin/alfa/omega/AA.class", "-src", "gensrc", "-d", "bin", serverArg);
+
+ Map<String,Long> new_bin_state = collectState(bin);
+ verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state,
+ "bin/alfa/omega/A.class",
+ "bin/alfa/omega/AA.class",
+ "bin/javac_state");
+ }
+
void removeFrom(Path dir, String... args) throws IOException {
for (String filename : args) {
Path p = dir.resolve(filename);