8144226: Sjavac's handling of include/exclude patterns is buggy, redundant and inconsistent

Rewrote sjavac include/exclude pattern handling.

Reviewed-by: jlahoda
This commit is contained in:
Andreas Lundblad 2016-01-08 17:14:10 +01:00
parent 180c59d147
commit b345518d32
17 changed files with 462 additions and 522 deletions

View file

@ -26,11 +26,20 @@
package com.sun.tools.sjavac;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Set;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.regex.PatternSyntaxException;
/** A Source object maintains information about a source file.
* For example which package it belongs to and kind of source it is.
@ -56,8 +65,6 @@ public class Source implements Comparable<Source> {
private long lastModified;
// The source File.
private File file;
// The source root under which file resides.
private File root;
// If the source is generated.
private boolean isGenerated;
// If the source is only linked to, not compiled.
@ -78,7 +85,7 @@ public class Source implements Comparable<Source> {
return name.hashCode();
}
public Source(Module m, String n, File f, File r) {
public Source(Module m, String n, File f) {
name = n;
int dp = n.lastIndexOf(".");
if (dp != -1) {
@ -87,7 +94,6 @@ public class Source implements Comparable<Source> {
suffix = "";
}
file = f;
root = r;
lastModified = f.lastModified();
linkedOnly = false;
}
@ -102,7 +108,6 @@ public class Source implements Comparable<Source> {
suffix = "";
}
file = null;
root = null;
lastModified = lm;
linkedOnly = false;
int ls = n.lastIndexOf('/');
@ -112,7 +117,6 @@ public class Source implements Comparable<Source> {
public String suffix() { return suffix; }
public Package pkg() { return pkg; }
public File file() { return file; }
public File root() { return root; }
public long lastModified() {
return lastModified;
}
@ -183,225 +187,122 @@ public class Source implements Comparable<Source> {
*/
static public void scanRoot(File root,
Set<String> suffixes,
List<String> excludes, List<String> includes,
List<String> excludeFiles, List<String> includeFiles,
List<String> excludes,
List<String> includes,
Map<String,Source> foundFiles,
Map<String,Module> foundModules,
Module currentModule,
final Module currentModule,
boolean permitSourcesWithoutPackage,
boolean inGensrc,
boolean inLinksrc)
throws ProblemException {
throws IOException, ProblemException {
if (root == null) return;
int root_prefix = root.getPath().length()+1;
// This is the root source directory, it must not contain any Java sources files
// because we do not allow Java source files without a package.
// (Unless of course --permit-sources-without-package has been specified.)
// It might contain other source files however, (for -tr and -copy) these will
// always be included, since no package pattern can match the root directory.
currentModule = addFilesInDir(root, root_prefix, root, suffixes, permitSourcesWithoutPackage,
excludeFiles, includeFiles,
foundFiles, foundModules, currentModule,
inGensrc, inLinksrc);
if (root == null)
return;
File[] dirfiles = root.listFiles();
for (File d : dirfiles) {
if (d.isDirectory()) {
// Descend into the directory structure.
scanDirectory(d, root_prefix, root, suffixes,
excludes, includes, excludeFiles, includeFiles,
foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
}
}
FileSystem fs = root.toPath().getFileSystem();
if (includes.isEmpty()) {
includes = Collections.singletonList("**");
}
/**
* Test if a path matches any of the patterns given.
* The pattern foo/bar matches only foo/bar
* The pattern foo/* matches foo/bar and foo/bar/zoo etc
*/
static private boolean hasMatch(String path, List<String> patterns) {
List<PathMatcher> includeMatchers = createPathMatchers(fs, includes);
List<PathMatcher> excludeMatchers = createPathMatchers(fs, excludes);
// Convert Windows '\' to '/' for the sake of comparing with the patterns
path = path.replace(File.separatorChar, '/');
Files.walkFileTree(root.toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
for (String p : patterns) {
// Exact match
if (p.equals(path))
return true;
Path relToRoot = root.toPath().relativize(file);
// Single dot the end matches this package and all its subpackages.
if (p.endsWith("/*")) {
// Remove the wildcard
String patprefix = p.substring(0,p.length()-2);
// Does the path start with the pattern prefix?
if (path.startsWith(patprefix)) {
// If the path has the same length as the pattern prefix, then it is a match.
// If the path is longer, then make sure that
// the next part of the path starts with a dot (.) to prevent
// wildcard matching in the middle of a package name.
if (path.length()==patprefix.length() || path.charAt(patprefix.length())=='/') {
return true;
}
}
}
}
return false;
}
if (includeMatchers.stream().anyMatch(im -> im.matches(relToRoot))
&& excludeMatchers.stream().noneMatch(em -> em.matches(relToRoot))
&& suffixes.contains(Util.fileSuffix(file))) {
/**
* Matches patterns with the asterisk first. */
// The pattern foo/bar.java only matches foo/bar.java
// The pattern */bar.java matches foo/bar.java and zoo/bar.java etc
static private boolean hasFileMatch(String path, List<String> patterns) {
// Convert Windows '\' to '/' for the sake of comparing with the patterns
path = path.replace(File.separatorChar, '/');
// TODO: Test this.
Source existing = foundFiles.get(file);
if (existing != null) {
throw new IOException("You have already added the file "+file+" from "+existing.file().getPath());
}
existing = currentModule.lookupSource(file.toString());
if (existing != null) {
path = Util.normalizeDriveLetter(path);
for (String p : patterns) {
// Exact match
if (p.equals(path)) {
return true;
}
// Single dot the end matches this package and all its subpackages.
if (p.startsWith("*")) {
// Remove the wildcard
String patsuffix = p.substring(1);
// Does the path start with the pattern prefix?
if (path.endsWith(patsuffix)) {
return true;
}
}
}
return false;
}
/**
* Add the files in the directory, assuming that the file has not been excluded.
* Returns a fresh Module object, if this was a dir with a module-info.java file.
*/
static private Module addFilesInDir(File dir, int rootPrefix, File root,
Set<String> suffixes, boolean allow_javas,
List<String> excludeFiles, List<String> includeFiles,
Map<String,Source> foundFiles,
Map<String,Module> foundModules,
Module currentModule,
boolean inGensrc,
boolean inLinksrc)
throws ProblemException
{
for (File f : dir.listFiles()) {
if (!f.isFile())
continue;
boolean should_add =
(excludeFiles == null || excludeFiles.isEmpty() || !hasFileMatch(f.getPath(), excludeFiles))
&& (includeFiles == null || includeFiles.isEmpty() || hasFileMatch(f.getPath(), includeFiles));
if (!should_add)
continue;
if (!allow_javas && f.getName().endsWith(".java")) {
throw new ProblemException("No .java files are allowed in the source root "+dir.getPath()+
", please remove "+f.getName());
}
// Extract the file name relative the root.
String fn = f.getPath().substring(rootPrefix);
// Extract the package name.
int sp = fn.lastIndexOf(File.separatorChar);
String pkg = "";
if (sp != -1) {
pkg = fn.substring(0,sp).replace(File.separatorChar,'.');
}
// Is this a module-info.java file?
if (fn.endsWith("module-info.java")) {
// Aha! We have recursed into a module!
if (!currentModule.name().equals("")) {
throw new ProblemException("You have an extra module-info.java inside a module! Please remove "+fn);
}
String module_name = fn.substring(0,fn.length()-16);
currentModule = new Module(module_name, f.getPath());
foundModules.put(module_name, currentModule);
}
// Extract the suffix.
int dp = fn.lastIndexOf(".");
String suffix = "";
if (dp > 0) {
suffix = fn.substring(dp);
}
// Should the file be added?
if (suffixes.contains(suffix)) {
Source of = foundFiles.get(f.getPath());
if (of != null) {
throw new ProblemException("You have already added the file "+fn+" from "+of.file().getPath());
}
of = currentModule.lookupSource(f.getPath());
if (of != null) {
// Oups, the source is already added, could be ok, could be not, lets check.
if (inLinksrc) {
// So we are collecting sources for linking only.
if (of.isLinkedOnly()) {
if (existing.isLinkedOnly()) {
// Ouch, this one is also for linking only. Bad.
throw new ProblemException("You have already added the link only file "+fn+" from "+of.file().getPath());
throw new IOException("You have already added the link only file " + file + " from " + existing.file().getPath());
}
// Ok, the existing source is to be compiled. Thus this link only is redundant
// since all compiled are also linked to. Continue to the next source.
// But we need to add the source, so that it will be visible to linking,
// if not the multi core compile will fail because a JavaCompiler cannot
// find the necessary dependencies for its part of the source.
foundFiles.put(f.getPath(), of);
continue;
foundFiles.put(file.toString(), existing);
} else {
// We are looking for sources to compile, if we find an existing to be compiled
// source with the same name, it is an internal error, since we must
// find the sources to be compiled before we find the sources to be linked to.
throw new ProblemException("Internal error: Double add of file "+fn+" from "+of.file().getPath());
throw new IOException("Internal error: Double add of file " + file + " from " + existing.file().getPath());
}
} else {
//////////////////////////////////////////////////////////////
// Add source
Source s = new Source(currentModule, file.toString(), file.toFile());
if (inGensrc) {
s.markAsGenerated();
}
Source s = new Source(currentModule, f.getPath(), f, root);
if (inGensrc) s.markAsGenerated();
if (inLinksrc) {
s.markAsLinkedOnly();
}
pkg = currentModule.name()+":"+pkg;
foundFiles.put(f.getPath(), s);
String pkg = packageOfJavaFile(root.toPath(), file);
pkg = currentModule.name() + ":" + pkg;
foundFiles.put(file.toString(), s);
currentModule.addSource(pkg, s);
//////////////////////////////////////////////////////////////
}
}
return currentModule;
}
static private void scanDirectory(File dir, int rootPrefix, File root,
Set<String> suffixes,
List<String> excludes, List<String> includes,
List<String> excludeFiles, List<String> includeFiles,
Map<String,Source> foundFiles,
Map<String,Module> foundModules,
Module currentModule, boolean inGensrc, boolean inLinksrc)
throws ProblemException {
String path = "";
// Remove the root prefix from the dir path
if (dir.getPath().length() > rootPrefix) {
path = dir.getPath().substring(rootPrefix);
return FileVisitResult.CONTINUE;
}
// Should this package directory be included and not excluded?
if ((includes==null || includes.isEmpty() || hasMatch(path, includes)) &&
(excludes==null || excludes.isEmpty() || !hasMatch(path, excludes))) {
// Add the source files.
currentModule = addFilesInDir(dir, rootPrefix, root, suffixes, true, excludeFiles, includeFiles,
foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
});
}
for (File d : dir.listFiles()) {
if (d.isDirectory()) {
// Descend into the directory structure.
scanDirectory(d, rootPrefix, root, suffixes,
excludes, includes, excludeFiles, includeFiles,
foundFiles, foundModules, currentModule, inGensrc, inLinksrc);
private static List<PathMatcher> createPathMatchers(FileSystem fs, List<String> patterns) {
List<PathMatcher> matchers = new ArrayList<>();
for (String pattern : patterns) {
try {
matchers.add(fs.getPathMatcher("glob:" + pattern));
} catch (PatternSyntaxException e) {
Log.error("Invalid pattern: " + pattern);
throw e;
}
}
return matchers;
}
private static String packageOfJavaFile(Path sourceRoot, Path javaFile) {
Path javaFileDir = javaFile.getParent();
Path packageDir = sourceRoot.relativize(javaFileDir);
List<String> separateDirs = new ArrayList<>();
for (Path pathElement : packageDir) {
separateDirs.add(pathElement.getFileName().toString());
}
return String.join(".", separateDirs);
}
@Override
public String toString() {
return String.format("%s[pkg: %s, name: %s, suffix: %s, file: %s, isGenerated: %b, linkedOnly: %b]",
getClass().getSimpleName(),
pkg,
name,
suffix,
file,
isGenerated,
linkedOnly);
}
}

View file

@ -230,4 +230,10 @@ public class Util {
Function<? super T, ? extends I> indexFunction) {
return c.stream().collect(Collectors.<T, I, T>toMap(indexFunction, o -> o));
}
public static String fileSuffix(Path file) {
String fileNameStr = file.getFileName().toString();
int dotIndex = fileNameStr.indexOf('.');
return dotIndex == -1 ? "" : fileNameStr.substring(dotIndex);
}
}

View file

@ -144,6 +144,7 @@ public class SjavacImpl implements Sjavac {
Module current_module = new Module("", "");
modules.put("", current_module);
try {
// Find all sources, use the suffix rules to know which files are sources.
Map<String,Source> sources = new HashMap<>();
@ -214,7 +215,6 @@ public class SjavacImpl implements Sjavac {
// Go through all sources and taint all packages that miss artifacts.
javac_state.taintPackagesThatMissArtifacts();
try {
// Check recorded classpath public apis. Taint packages that depend on
// classpath classes whose public apis have changed.
javac_state.taintPackagesDependingOnChangedClasspathPackages();
@ -229,8 +229,16 @@ public class SjavacImpl implements Sjavac {
// (Generated sources must always have a package.)
Map<String,Source> generated_sources = new HashMap<>();
Source.scanRoot(Util.pathToFile(options.getGenSrcDir()), Util.set(".java"), null, null, null, null,
generated_sources, modules, current_module, false, true, false);
Source.scanRoot(Util.pathToFile(options.getGenSrcDir()),
Util.set(".java"),
Collections.emptyList(),
Collections.emptyList(),
generated_sources,
modules,
current_module,
false,
true,
false);
javac_state.now().flattenPackagesSourcesAndArtifacts(modules);
// Recheck the the source files and their timestamps again.
javac_state.checkSourceStatus(true);
@ -254,7 +262,10 @@ public class SjavacImpl implements Sjavac {
printRound(round);
// Clean out artifacts in tainted packages.
javac_state.deleteClassArtifactsInTaintedPackages();
again = javac_state.performJavaCompilations(compilationService, options, recently_compiled, rc);
again = javac_state.performJavaCompilations(compilationService,
options,
recently_compiled,
rc);
if (!rc[0]) {
Log.debug("Compilation failed.");
break;
@ -344,7 +355,8 @@ public class SjavacImpl implements Sjavac {
Map<String, Module> foundModules,
Module currentModule,
boolean permitSourcesInDefaultPackage,
boolean inLinksrc) {
boolean inLinksrc)
throws IOException {
for (SourceLocation source : sourceLocations) {
source.findSourceFiles(sourceTypes,

View file

@ -93,7 +93,7 @@ public enum Option {
CLASSPATH.processMatching(iter, helper);
}
},
X("-x", "Exclude directory from the subsequent source directory") {
X("-x", "Exclude files matching the given pattern") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
String pattern = getFilePatternArg(iter, helper);
@ -101,7 +101,7 @@ public enum Option {
helper.exclude(pattern);
}
},
I("-i", "Include only the given directory from the subsequent source directory") {
I("-i", "Include only files matching the given pattern") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
String pattern = getFilePatternArg(iter, helper);
@ -109,22 +109,6 @@ public enum Option {
helper.include(pattern);
}
},
XF("-xf", "Exclude a given file") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
String pattern = getFilePatternArg(iter, helper);
if (pattern != null)
helper.excludeFile(pattern);
}
},
IF("-if", "Include only the given file") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
String pattern = getFilePatternArg(iter, helper);
if (pattern != null)
helper.includeFile(pattern);
}
},
TR("-tr", "Translate resources") {
@Override
protected void processMatching(ArgumentIterator iter, OptionHelper helper) {
@ -338,7 +322,7 @@ public enum Option {
String getFilePatternArg(ArgumentIterator iter, OptionHelper helper) {
if (!iter.hasNext()) {
helper.reportError(arg + " must be followed by a file or directory pattern.");
helper.reportError(arg + " must be followed by a glob pattern.");
return null;
}

View file

@ -53,12 +53,6 @@ public abstract class OptionHelper {
/** Record a package inclusion pattern */
public abstract void include(String incl);
/** Record a file exclusion */
public abstract void excludeFile(String exclFile);
/** Record a file inclusion */
public abstract void includeFile(String inclFile);
/** Record a root of sources to be compiled */
public abstract void sourceRoots(List<Path> path);

View file

@ -220,8 +220,6 @@ public class Options {
for (SourceLocation sl : locs) {
for (String pkg : sl.includes) addArg(Option.I, pkg);
for (String pkg : sl.excludes) addArg(Option.X, pkg);
for (String f : sl.excludedFiles) addArg(Option.XF, f);
for (String f : sl.includedFiles) addArg(Option.IF, f);
addArg(opt, sl.getPath());
}
}
@ -379,18 +377,6 @@ public class Options {
includes.add(inclPattern);
}
@Override
public void excludeFile(String exclFilePattern) {
exclFilePattern = Util.normalizeDriveLetter(exclFilePattern);
excludeFiles.add(exclFilePattern);
}
@Override
public void includeFile(String inclFilePattern) {
inclFilePattern = Util.normalizeDriveLetter(inclFilePattern);
includeFiles.add(inclFilePattern);
}
@Override
public void addTransformer(String suffix, Transformer tr) {
if (trRules.containsKey(suffix)) {
@ -519,9 +505,7 @@ public class Options {
result.add(new SourceLocation(
path,
includes,
excludes,
includeFiles,
excludeFiles));
excludes));
}
resetFilters();
return result;

View file

@ -25,11 +25,13 @@
package com.sun.tools.sjavac.options;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sun.tools.sjavac.Log;
import com.sun.tools.sjavac.Module;
import com.sun.tools.sjavac.ProblemException;
import com.sun.tools.sjavac.Source;
@ -49,18 +51,14 @@ public class SourceLocation {
private Path path;
// Package include / exclude patterns and file includes / excludes.
List<String> includes, excludes, includedFiles, excludedFiles;
List<String> includes, excludes;
public SourceLocation(Path path,
List<String> includes,
List<String> excludes,
List<String> includedFiles,
List<String> excludedFiles) {
List<String> excludes) {
this.path = path;
this.includes = includes;
this.excludes = excludes;
this.includedFiles = includedFiles;
this.excludedFiles = excludedFiles;
}
@ -81,17 +79,23 @@ public class SourceLocation {
Map<String, Module> foundModules,
Module currentModule,
boolean permitSourcesInDefaultPackage,
boolean inLinksrc) {
boolean inLinksrc)
throws IOException {
try {
Source.scanRoot(path.toFile(), suffixes, excludes, includes,
excludedFiles, includedFiles, foundFiles, foundModules,
currentModule, permitSourcesInDefaultPackage, false,
Source.scanRoot(path.toFile(),
suffixes,
excludes,
includes,
foundFiles,
foundModules,
currentModule,
permitSourcesInDefaultPackage,
false,
inLinksrc);
} catch (ProblemException e) {
e.printStackTrace();
}
}
/** Get the root directory of this source location */
public Path getPath() {
return path;
@ -107,14 +111,9 @@ public class SourceLocation {
return excludes;
}
/** Get the file include patterns */
public List<String> getIncludedFiles() {
return includedFiles;
@Override
public String toString() {
return String.format("%s[\"%s\", includes: %s, excludes: %s]",
getClass().getSimpleName(), path, includes, excludes);
}
/** Get the file exclude patterns */
public List<String> getExcludedFiles() {
return excludedFiles;
}
}

View file

@ -55,9 +55,9 @@ public class CompileExcludingDependency extends SJavacTester {
tb.writeFile(GENSRC.resolve("beta/B.java"),
"package beta; public class B { }");
compile("-x", "beta",
compile("-x", "beta/*",
"-src", GENSRC.toString(),
"-x", "alfa/omega",
"-x", "alfa/omega/*",
"-sourcepath", GENSRC.toString(),
"-d", BIN.toString(),
"--state-dir=" + BIN,

View file

@ -47,8 +47,8 @@ public class CompileWithAtFile extends SJavacTester {
void test() throws Exception {
tb.writeFile(GENSRC.resolve("list.txt"),
"-if */alfa/omega/A.java\n" +
"-if */beta/B.java\n" +
"-i alfa/omega/A.java\n" +
"-i beta/B.java\n" +
GENSRC + "\n" +
"-d " + BIN + "\n" +
"--state-dir=" + BIN + "\n");

View file

@ -64,7 +64,7 @@ public class CompileWithInvisibleSources extends SJavacTester {
"package beta; public class B { }");
compile(GENSRC.toString(),
"-x", "beta",
"-x", "beta/*",
"-sourcepath", GENSRC2.toString(),
"-sourcepath", GENSRC3.toString(),
"-d", BIN.toString(),

View file

@ -62,7 +62,7 @@ public class CompileWithOverrideSources extends SJavacTester {
tb.writeFile(GENSRC2.resolve("beta/B.java"),
"package beta; public class B { }");
compile("-x", "beta",
compile("-x", "beta/*",
GENSRC.toString(),
GENSRC2.toString(),
"-d", BIN.toString(),

View file

@ -1,94 +0,0 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8037085
* @summary Ensures that sjavac can handle various exclusion patterns.
*
* @modules jdk.compiler/com.sun.tools.sjavac
* @build Wrapper
* @run main Wrapper ExclPattern
*/
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class ExclPattern {
public static void main(String[] ignore) throws IOException {
String toBeExcluded = "pkg/excl-dir/excluded.txt";
String toBeIncluded = "pkg/incl-dir/included.txt";
// Set up source directory with directory to be excluded
populate(Paths.get("srcdir"),
"pkg/SomeClass.java",
"package pkg; public class SomeClass { }",
toBeExcluded,
"This file should not end up in the dest directory.",
toBeIncluded,
"This file should end up in the dest directory.");
String[] args = {
"-x", "pkg/excl-dir/*",
"-src", "srcdir",
"-d", "dest",
"--state-dir=dest",
"-j", "1",
"-copy", ".txt",
"--server:portfile=testserver,background=false",
"--log=debug"
};
int rc = com.sun.tools.sjavac.Main.go(args);
if (rc != 0) throw new RuntimeException("Error during compile!");
if (!Files.exists(Paths.get("dest/" + toBeIncluded)))
throw new AssertionError("File missing: " + toBeIncluded);
if (Files.exists(Paths.get("dest/" + toBeExcluded)))
throw new AssertionError("File present: " + toBeExcluded);
}
static void populate(Path root, String... args) throws IOException {
if (!Files.exists(root))
Files.createDirectory(root);
for (int i = 0; i < args.length; i += 2) {
String filename = args[i];
String content = args[i+1];
Path p = root.resolve(filename);
Files.createDirectories(p.getParent());
try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(p,
Charset.defaultCharset()))) {
out.println(content);
}
}
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8144226
* @summary Ensures that excluded files are inaccessible (even for implicit
* compilation)
*
* @modules jdk.compiler/com.sun.tools.sjavac
* @library /tools/lib
* @build Wrapper ToolBox
* @run main Wrapper HiddenFiles
*/
import com.sun.tools.javac.util.Assert;
import com.sun.tools.sjavac.server.Sjavac;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class HiddenFiles extends SjavacBase {
public static void main(String[] ignore) throws Exception {
Path BIN = Paths.get("bin");
Path STATE_DIR = Paths.get("state-dir");
Path SRC = Paths.get("src");
Files.createDirectories(BIN);
Files.createDirectories(STATE_DIR);
toolbox.writeJavaFiles(SRC, "package pkg; class A { B b; }");
toolbox.writeJavaFiles(SRC, "package pkg; class B { }");
// This compilation should fail (return RC_FATAL) since A.java refers to B.java and B.java
// is excluded.
int rc = compile("-x", "pkg/B.java", SRC.toString(),
"--server:portfile=testportfile,background=false",
"-d", BIN.toString(),
"--state-dir=" + STATE_DIR);
Assert.check(rc == Sjavac.RC_FATAL, "Compilation succeeded unexpectedly.");
}
}

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8037085
* @summary Ensures that sjavac can handle various exclusion patterns.
*
* @modules jdk.compiler/com.sun.tools.sjavac
* @library /tools/lib
* @build Wrapper ToolBox
* @run main Wrapper IncludeExcludePatterns
*/
import com.sun.tools.javac.util.Assert;
import com.sun.tools.sjavac.server.Sjavac;
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.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class IncludeExcludePatterns extends SjavacBase {
final Path SRC = Paths.get("src");
final Path BIN = Paths.get("bin");
final Path STATE_DIR = Paths.get("state-dir");
// An arbitrarily but sufficiently complicated source tree.
final Path A = Paths.get("pkga/A.java");
final Path X1 = Paths.get("pkga/subpkg/Xx.java");
final Path Y = Paths.get("pkga/subpkg/subsubpkg/Y.java");
final Path B = Paths.get("pkgb/B.java");
final Path C = Paths.get("pkgc/C.java");
final Path X2 = Paths.get("pkgc/Xx.java");
final Path[] ALL_PATHS = {A, X1, Y, B, C, X2};
public static void main(String[] ignore) throws Exception {
new IncludeExcludePatterns().runTest();
}
public void runTest() throws IOException, ReflectiveOperationException {
Files.createDirectories(BIN);
Files.createDirectories(STATE_DIR);
for (Path p : ALL_PATHS) {
writeDummyClass(p);
}
// Single file
testPattern("pkga/A.java", A);
// Leading wild cards
testPattern("*/A.java", A);
testPattern("**/Xx.java", X1, X2);
testPattern("**x.java", X1, X2);
// Wild card in middle of path
testPattern("pkga/*/Xx.java", X1);
testPattern("pkga/**/Y.java", Y);
// Trailing wild cards
testPattern("pkga/*", A);
testPattern("pkga/**", A, X1, Y);
// Multiple wildcards
testPattern("pkga/*/*/Y.java", Y);
testPattern("**/*/**", X1, Y);
}
// Given "src/pkg/subpkg/A.java" this method returns "A"
String classNameOf(Path javaFile) {
return javaFile.getFileName()
.toString()
.replace(".java", "");
}
// Puts an empty (dummy) class definition in the given path.
void writeDummyClass(Path javaFile) throws IOException {
String pkg = javaFile.getParent().toString().replace('/', '.');
String cls = javaFile.getFileName().toString().replace(".java", "");
toolbox.writeFile(SRC.resolve(javaFile), "package " + pkg + "; class " + cls + " {}");
}
void testPattern(String filterArgs, Path... sourcesExpectedToBeVisible)
throws ReflectiveOperationException, IOException {
testFilter("-i " + filterArgs, Arrays.asList(sourcesExpectedToBeVisible));
Set<Path> complement = new HashSet<>(Arrays.asList(ALL_PATHS));
complement.removeAll(Arrays.asList(sourcesExpectedToBeVisible));
testFilter("-x " + filterArgs, complement);
}
void testFilter(String filterArgs, Collection<Path> sourcesExpectedToBeVisible)
throws IOException, ReflectiveOperationException {
System.out.println("Testing filter: " + filterArgs);
toolbox.cleanDirectory(BIN);
toolbox.cleanDirectory(STATE_DIR);
String args = filterArgs + " " + SRC
+ " --server:portfile=testportfile,background=false"
+ " -d " + BIN
+ " --state-dir=" + STATE_DIR;
int rc = compile((Object[]) args.split(" "));
// Compilation should always pass in these tests
Assert.check(rc == Sjavac.RC_OK, "Compilation failed unexpectedly.");
// The resulting .class files should correspond to the visible source files
Set<Path> result = allFilesInDir(BIN);
Set<Path> expected = correspondingClassFiles(sourcesExpectedToBeVisible);
if (!result.equals(expected)) {
System.out.println("Result:");
printPaths(result);
System.out.println("Expected:");
printPaths(expected);
Assert.error("Test case failed: " + filterArgs);
}
}
void printPaths(Collection<Path> paths) {
paths.stream()
.sorted()
.forEachOrdered(p -> System.out.println(" " + p));
}
// Given "pkg/A.java, pkg/B.java" this method returns "bin/pkg/A.class, bin/pkg/B.class"
Set<Path> correspondingClassFiles(Collection<Path> javaFiles) {
return javaFiles.stream()
.map(javaFile -> javaFile.resolveSibling(classNameOf(javaFile) + ".class"))
.map(BIN::resolve)
.collect(Collectors.toSet());
}
Set<Path> allFilesInDir(Path p) throws IOException {
try (Stream<Path> files = Files.walk(p).filter(Files::isRegularFile)) {
return files.collect(Collectors.toSet());
}
}
}

View file

@ -61,7 +61,6 @@ public class OptionDecoding {
public static void main(String[] args) throws IOException {
testPaths();
testDupPaths();
testSourceLocations();
testSimpleOptions();
testServerConf();
testSearchPaths();
@ -110,78 +109,6 @@ public class OptionDecoding {
}
}
// Test source locations and -x, -i, -xf, -if filters
static void testSourceLocations() throws IOException {
Path a1 = Paths.get("root/pkg1/ClassA1.java");
Path a2 = Paths.get("root/pkg1/ClassA2.java");
Path b1 = Paths.get("root/pkg1/pkg2/ClassB1.java");
Path b2 = Paths.get("root/pkg1/pkg2/ClassB2.java");
Path c1 = Paths.get("root/pkg3/ClassC1.java");
Path c2 = Paths.get("root/pkg3/ClassC2.java");
for (Path p : Arrays.asList(a1, a2, b1, b2, c1, c2)) {
Files.createDirectories(p.getParent());
Files.createFile(p);
}
// Test -if
{
Options options = Options.parseArgs("-if", "root/pkg1/ClassA1.java", "root");
Map<String, Source> foundFiles = new HashMap<>();
SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles,
new HashMap<String, Module>(), new Module("", ""), false, true);
checkFilesFound(foundFiles.keySet(), a1);
}
// Test -i
System.out.println("--------------------------- CHECKING -i ----------------");
{
Options options = Options.parseArgs("-i", "pkg1/*", "root");
Map<String, Source> foundFiles = new HashMap<>();
SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles,
new HashMap<String, Module>(), new Module("", ""), false, true);
checkFilesFound(foundFiles.keySet(), a1, a2, b1, b2);
}
System.out.println("--------------------------------------------------------");
// Test -xf
{
Options options = Options.parseArgs("-xf", "root/pkg1/ClassA1.java", "root");
Map<String, Source> foundFiles = new HashMap<>();
SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles,
new HashMap<String, Module>(), new Module("", ""), false, true);
checkFilesFound(foundFiles.keySet(), a2, b1, b2, c1, c2);
}
// Test -x
{
Options options = Options.parseArgs("-i", "pkg1/*", "root");
Map<String, Source> foundFiles = new HashMap<>();
SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles,
new HashMap<String, Module>(), new Module("", ""), false, true);
checkFilesFound(foundFiles.keySet(), a1, a2, b1, b2);
}
// Test -x and -i
{
Options options = Options.parseArgs("-i", "pkg1/*", "-x", "pkg1/pkg2/*", "root");
Map<String, Source> foundFiles = new HashMap<>();
SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles,
new HashMap<String, Module>(), new Module("", ""), false, true);
checkFilesFound(foundFiles.keySet(), a1, a2);
}
}
// Test basic options
static void testSimpleOptions() {
Options options = Options.parseArgs("-j", "17", "--log=debug");
@ -216,8 +143,8 @@ public class OptionDecoding {
List<String> i, x, iF, xF;
i = x = iF = xF = new ArrayList<>();
SourceLocation dir1 = new SourceLocation(Paths.get("dir1"), i, x, iF, xF);
SourceLocation dir2 = new SourceLocation(Paths.get("dir2"), i, x, iF, xF);
SourceLocation dir1 = new SourceLocation(Paths.get("dir1"), i, x);
SourceLocation dir2 = new SourceLocation(Paths.get("dir2"), i, x);
String dir1_PS_dir2 = "dir1" + File.pathSeparator + "dir2";
Options options = Options.parseArgs("-sourcepath", dir1_PS_dir2);

View file

@ -58,8 +58,6 @@ public class Serialization {
Option.D.arg, "dest",
Option.I.arg, "pkg/*",
Option.X.arg, "pkg/pkg/*",
Option.IF.arg, "root/pkg/MyClass1.java",
Option.XF.arg, "root/pkg/MyClass2.java",
Option.SRC.arg, "root",
Option.SOURCEPATH.arg, "sourcepath",
Option.CLASSPATH.arg, "classpath",
@ -87,8 +85,6 @@ public class Serialization {
assertEquals(sl1.getPath(), sl2.getPath());
assertEquals(sl1.getIncludes(), sl2.getIncludes());
assertEquals(sl1.getExcludes(), sl2.getExcludes());
assertEquals(sl1.getIncludedFiles(), sl2.getIncludedFiles());
assertEquals(sl1.getExcludedFiles(), sl2.getExcludedFiles());
assertEquals(options1.getClassSearchPath(), options2.getClassSearchPath());
assertEquals(options1.getSourceSearchPaths(), options2.getSourceSearchPaths());

View file

@ -62,9 +62,7 @@ public class OptionTestUtil {
if (!sl1.getPath().equals(sl2.getPath()) ||
!sl1.getIncludes().equals(sl2.getIncludes()) ||
!sl1.getExcludes().equals(sl2.getExcludes()) ||
!sl1.getIncludedFiles().equals(sl2.getIncludedFiles()) ||
!sl1.getExcludedFiles().equals(sl2.getExcludedFiles()))
!sl1.getExcludes().equals(sl2.getExcludes()))
throw new AssertionError("Expected " + sl1 + " but got " + sl2);
}
}