# HG changeset patch # User lana # Date 1407776715 25200 # Node ID 6a5d6de681afb07bbbcb14510965422ccc5d9738 # Parent 024ed9c9ed13b0a63177d4a4c938e67bd8f2d5c8# Parent 9e2489a79aca448d90b8386978028d69a6de7b9c Merge diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/.hgtags diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/src/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java --- 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(); diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java --- 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 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 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(); + } } } } diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/src/share/classes/com/sun/tools/sjavac/Main.java --- 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")) { diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/src/share/classes/com/sun/tools/sjavac/comp/JavacServiceImpl.java --- 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 ""; + } + } diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/src/share/classes/com/sun/tools/sjavac/options/Option.java --- 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; diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/src/share/classes/com/sun/tools/sjavac/options/OptionHelper.java --- 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: diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/src/share/classes/com/sun/tools/sjavac/options/Options.java --- 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 sources = new ArrayList<>(); @@ -51,7 +53,8 @@ private String logLevel = "info"; - private boolean permitUnidentifiedArtifact = false; + private Set 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 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 createSourceLocations(List paths) { List result = new ArrayList<>(); for (Path path : paths) { diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/src/share/classes/com/sun/tools/sjavac/server/JavacService.java --- 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 explicitSources, Set sourcesToCompile, Set visibleSources); + String serverSettings(); } diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/src/share/classes/com/sun/tools/sjavac/server/JavacServiceClient.java --- 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. diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/test/tools/sjavac/OptionDecoding.java --- 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 diff -r 024ed9c9ed13 -r 6a5d6de681af langtools/test/tools/sjavac/SJavac.java --- 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 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 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 new_bin_state = collectState(bin); + verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state, + "bin/alfa/omega/A.class"); + Map 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 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);