8168386: Fix jdeps verbose options

Reviewed-by: dfuchs, lancea
This commit is contained in:
Mandy Chung 2016-11-11 17:32:21 -08:00
parent 8899d19210
commit 40e24f2e56
6 changed files with 587 additions and 244 deletions

View File

@ -25,8 +25,10 @@
package com.sun.tools.jdeps; package com.sun.tools.jdeps;
import com.sun.tools.jdeps.Analyzer.Type;
import static com.sun.tools.jdeps.Analyzer.Type.*; import static com.sun.tools.jdeps.Analyzer.Type.*;
import static com.sun.tools.jdeps.JdepsWriter.*; import static com.sun.tools.jdeps.JdepsWriter.*;
import static java.util.stream.Collectors.*;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -111,6 +113,10 @@ class JdepsTask {
this.aliases = aliases; this.aliases = aliases;
} }
Option(boolean hasArg, CommandOption cmd) {
this(hasArg, cmd.names());
}
boolean isHidden() { boolean isHidden() {
return false; return false;
} }
@ -144,25 +150,46 @@ class JdepsTask {
} }
} }
enum CommandOption {
ANALYZE_DEPS(""),
GENERATE_DOT_FILE("-dotoutput", "--dot-output"),
GENERATE_MODULE_INFO("--generate-module-info"),
LIST_DEPS("--list-deps"),
LIST_REDUCED_DEPS("--list-reduced-deps"),
CHECK_MODULES("--check");
private final String[] names;
CommandOption(String... names) {
this.names = names;
}
String[] names() {
return names;
}
@Override
public String toString() {
return names[0];
}
}
static Option[] recognizedOptions = { static Option[] recognizedOptions = {
new Option(false, "-h", "-?", "-help", "--help") { new Option(false, "-h", "-?", "-help", "--help") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.help = true; task.options.help = true;
} }
}, },
new Option(true, "-dotoutput", "--dot-output") { new Option(true, CommandOption.GENERATE_DOT_FILE) {
void process(JdepsTask task, String opt, String arg) throws BadArgs { void process(JdepsTask task, String opt, String arg) throws BadArgs {
Path p = Paths.get(arg); if (task.command != null) {
if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) { throw new BadArgs("err.command.set", task.command, opt);
throw new BadArgs("err.invalid.path", arg);
} }
task.options.dotOutputDir = Paths.get(arg);; task.command = task.genDotFile(Paths.get(arg));
} }
}, },
new Option(false, "-s", "-summary") { new Option(false, "-s", "-summary") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.showSummary = true; task.options.showSummary = true;
task.options.verbose = SUMMARY;
} }
}, },
new Option(false, "-v", "-verbose", new Option(false, "-v", "-verbose",
@ -196,35 +223,48 @@ class JdepsTask {
task.options.apiOnly = true; task.options.apiOnly = true;
} }
}, },
new Option(true, "--check") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
Set<String> mods = Set.of(arg.split(","));
task.options.checkModuleDeps = mods;
task.options.addmods.addAll(mods);
}
},
new Option(true, "--generate-module-info") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
Path p = Paths.get(arg);
if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
throw new BadArgs("err.invalid.path", arg);
}
task.options.genModuleInfo = Paths.get(arg);
}
},
new Option(false, "-jdkinternals", "--jdk-internals") { new Option(false, "-jdkinternals", "--jdk-internals") {
void process(JdepsTask task, String opt, String arg) { void process(JdepsTask task, String opt, String arg) {
task.options.findJDKInternals = true; task.options.findJDKInternals = true;
task.options.verbose = CLASS;
if (task.options.includePattern == null) { if (task.options.includePattern == null) {
task.options.includePattern = Pattern.compile(".*"); task.options.includePattern = Pattern.compile(".*");
} }
} }
}, },
new Option(false, "--list-deps", "--list-reduced-deps") {
void process(JdepsTask task, String opt, String arg) { new Option(true, CommandOption.CHECK_MODULES) {
task.options.showModulesAddExports = true; void process(JdepsTask task, String opt, String arg) throws BadArgs {
task.options.reduced = opt.equals("--list-reduced-deps"); if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
Set<String> mods = Set.of(arg.split(","));
task.options.addmods.addAll(mods);
task.command = task.checkModuleDeps(mods);
}
},
new Option(true, CommandOption.GENERATE_MODULE_INFO) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.genModuleInfo(Paths.get(arg));
}
},
new Option(false, CommandOption.LIST_DEPS) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.listModuleDeps(false);
}
},
new Option(false, CommandOption.LIST_REDUCED_DEPS) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.command = task.listModuleDeps(true);
} }
}, },
@ -419,6 +459,7 @@ class JdepsTask {
private final Options options = new Options(); private final Options options = new Options();
private final List<String> inputArgs = new ArrayList<>(); private final List<String> inputArgs = new ArrayList<>();
private Command command;
private PrintWriter log; private PrintWriter log;
void setLog(PrintWriter out) { void setLog(PrintWriter out) {
log = out; log = out;
@ -445,55 +486,30 @@ class JdepsTask {
if (options.version || options.fullVersion) { if (options.version || options.fullVersion) {
showVersion(options.fullVersion); showVersion(options.fullVersion);
} }
if (options.help || options.version || options.fullVersion) {
return EXIT_OK;
}
if (!inputArgs.isEmpty() && options.rootModule != null) { if (!inputArgs.isEmpty() && options.rootModule != null) {
reportError("err.invalid.arg.for.option", "-m"); reportError("err.invalid.arg.for.option", "-m");
} }
if (inputArgs.isEmpty() && options.addmods.isEmpty() && options.includePattern == null
&& options.includeSystemModulePattern == null && options.checkModuleDeps == null) {
if (options.help || options.version || options.fullVersion) {
return EXIT_OK;
} else {
showHelp();
return EXIT_CMDERR;
}
}
if (options.genModuleInfo != null) {
if (options.dotOutputDir != null || options.classpath != null || options.hasFilter()) {
showHelp();
return EXIT_CMDERR;
}
}
if (options.numFilters() > 1) { if (options.numFilters() > 1) {
reportError("err.invalid.filters"); reportError("err.invalid.filters");
return EXIT_CMDERR; return EXIT_CMDERR;
} }
if (options.inverse && options.depth != 1) { // default command to analyze dependences
reportError("err.invalid.inverse.option", "-R"); if (command == null) {
return EXIT_CMDERR; command = analyzeDeps();
} }
if (!command.checkOptions()) {
if (options.inverse && options.numFilters() == 0) {
reportError("err.invalid.filters");
return EXIT_CMDERR;
}
if ((options.findJDKInternals) && (options.hasFilter() || options.showSummary)) {
showHelp();
return EXIT_CMDERR;
}
if (options.showSummary && options.verbose != SUMMARY) {
showHelp();
return EXIT_CMDERR;
}
if (options.checkModuleDeps != null && !inputArgs.isEmpty()) {
reportError("err.invalid.module.option", inputArgs, "--check");
return EXIT_CMDERR; return EXIT_CMDERR;
} }
boolean ok = run(); boolean ok = run();
return ok ? EXIT_OK : EXIT_ERROR; return ok ? EXIT_OK : EXIT_ERROR;
} catch (BadArgs|UncheckedBadArgs e) { } catch (BadArgs|UncheckedBadArgs e) {
reportError(e.getKey(), e.getArgs()); reportError(e.getKey(), e.getArgs());
if (e.showUsage()) { if (e.showUsage()) {
@ -515,13 +531,14 @@ class JdepsTask {
} }
boolean run() throws IOException { boolean run() throws IOException {
try (JdepsConfiguration config = buildConfig()) { try (JdepsConfiguration config = buildConfig(command.allModules())) {
// detect split packages // detect split packages
config.splitPackages().entrySet().stream() config.splitPackages().entrySet()
.stream()
.sorted(Map.Entry.comparingByKey()) .sorted(Map.Entry.comparingByKey())
.forEach(e -> System.out.format("split package: %s %s%n", e.getKey(), .forEach(e -> System.out.format("split package: %s %s%n", e.getKey(),
e.getValue().toString())); e.getValue().toString()));
// check if any module specified in --require is missing // check if any module specified in --require is missing
Stream.concat(options.addmods.stream(), options.requires.stream()) Stream.concat(options.addmods.stream(), options.requires.stream())
@ -529,38 +546,11 @@ class JdepsTask {
.forEach(mn -> config.findModule(mn).orElseThrow(() -> .forEach(mn -> config.findModule(mn).orElseThrow(() ->
new UncheckedBadArgs(new BadArgs("err.module.not.found", mn)))); new UncheckedBadArgs(new BadArgs("err.module.not.found", mn))));
// --generate-module-info return command.run(config);
if (options.genModuleInfo != null) {
return genModuleInfo(config);
}
// --check
if (options.checkModuleDeps != null) {
return new ModuleAnalyzer(config, log, options.checkModuleDeps).run();
}
if (options.showModulesAddExports) {
return new ModuleExportsAnalyzer(config,
dependencyFilter(config),
options.reduced,
log).run();
}
if (options.dotOutputDir != null &&
(options.verbose == SUMMARY || options.verbose == MODULE) &&
!options.addmods.isEmpty() && inputArgs.isEmpty()) {
return new ModuleAnalyzer(config, log).genDotFiles(options.dotOutputDir);
}
if (options.inverse) {
return analyzeInverseDeps(config);
} else {
return analyzeDeps(config);
}
} }
} }
private JdepsConfiguration buildConfig() throws IOException { private JdepsConfiguration buildConfig(boolean allModules) throws IOException {
JdepsConfiguration.Builder builder = JdepsConfiguration.Builder builder =
new JdepsConfiguration.Builder(options.systemModulePath); new JdepsConfiguration.Builder(options.systemModulePath);
@ -568,7 +558,7 @@ class JdepsTask {
.appModulePath(options.modulePath) .appModulePath(options.modulePath)
.addmods(options.addmods); .addmods(options.addmods);
if (options.checkModuleDeps != null || options.showModulesAddExports) { if (allModules) {
// check all system modules in the image // check all system modules in the image
builder.allModules(); builder.allModules();
} }
@ -592,148 +582,420 @@ class JdepsTask {
return builder.build(); return builder.build();
} }
private boolean analyzeDeps(JdepsConfiguration config) throws IOException { // ---- factory methods to create a Command
// output result
final JdepsWriter writer;
if (options.dotOutputDir != null) {
writer = new DotFileWriter(options.dotOutputDir,
options.verbose,
options.showProfile,
options.showModule,
options.showLabel);
} else {
writer = new SimpleWriter(log,
options.verbose,
options.showProfile,
options.showModule);
}
// analyze the dependencies private AnalyzeDeps analyzeDeps() throws BadArgs {
DepsAnalyzer analyzer = new DepsAnalyzer(config, return options.inverse ? new InverseAnalyzeDeps()
dependencyFilter(config), : new AnalyzeDeps();
writer,
options.verbose,
options.apiOnly);
boolean ok = analyzer.run(options.compileTimeView, options.depth);
// print skipped entries, if any
if (!options.nowarning) {
analyzer.archives()
.forEach(archive -> archive.reader()
.skippedEntries().stream()
.forEach(name -> warning("warn.skipped.entry", name)));
}
if (options.findJDKInternals && !options.nowarning) {
Map<String, String> jdkInternals = new TreeMap<>();
Set<String> deps = analyzer.dependences();
// find the ones with replacement
deps.forEach(cn -> replacementFor(cn).ifPresent(
repl -> jdkInternals.put(cn, repl))
);
if (!deps.isEmpty()) {
log.println();
warning("warn.replace.useJDKInternals", getMessage("jdeps.wiki.url"));
}
if (!jdkInternals.isEmpty()) {
log.println();
log.format("%-40s %s%n", "JDK Internal API", "Suggested Replacement");
log.format("%-40s %s%n", "----------------", "---------------------");
jdkInternals.entrySet().stream()
.forEach(e -> {
String key = e.getKey();
String[] lines = e.getValue().split("\\n");
for (String s : lines) {
log.format("%-40s %s%n", key, s);
key = "";
}
});
}
}
return ok;
} }
private boolean analyzeInverseDeps(JdepsConfiguration config) throws IOException { private GenDotFile genDotFile(Path dir) throws BadArgs {
JdepsWriter writer = new SimpleWriter(log, if (Files.exists(dir) && (!Files.isDirectory(dir) || !Files.isWritable(dir))) {
options.verbose, throw new BadArgs("err.invalid.path", dir.toString());
options.showProfile, }
options.showModule); return new GenDotFile(dir);
InverseDepsAnalyzer analyzer = new InverseDepsAnalyzer(config,
dependencyFilter(config),
writer,
options.verbose,
options.apiOnly);
boolean ok = analyzer.run();
log.println();
if (!options.requires.isEmpty())
log.format("Inverse transitive dependences on %s%n", options.requires);
else
log.format("Inverse transitive dependences matching %s%n",
options.regex != null
? options.regex.toString()
: "packages " + options.packageNames);
analyzer.inverseDependences().stream()
.sorted(Comparator.comparing(this::sortPath))
.forEach(path -> log.println(path.stream()
.map(Archive::getName)
.collect(Collectors.joining(" <- "))));
return ok;
} }
private String sortPath(Deque<Archive> path) { private GenModuleInfo genModuleInfo(Path dir) throws BadArgs {
return path.peekFirst().getName(); if (Files.exists(dir) && (!Files.isDirectory(dir) || !Files.isWritable(dir))) {
throw new BadArgs("err.invalid.path", dir.toString());
}
return new GenModuleInfo(dir);
} }
private boolean genModuleInfo(JdepsConfiguration config) throws IOException { private ListModuleDeps listModuleDeps(boolean reduced) throws BadArgs {
// check if any JAR file contains unnamed package return reduced ? new ListReducedDeps()
for (String arg : inputArgs) { : new ListModuleDeps();
try (ClassFileReader reader = ClassFileReader.newInstance(Paths.get(arg))) { }
Optional<String> classInUnnamedPackage =
reader.entries().stream()
.filter(n -> n.endsWith(".class"))
.filter(cn -> toPackageName(cn).isEmpty())
.findFirst();
if (classInUnnamedPackage.isPresent()) { private CheckModuleDeps checkModuleDeps(Set<String> mods) throws BadArgs {
if (classInUnnamedPackage.get().equals("module-info.class")) { return new CheckModuleDeps(mods);
reportError("err.genmoduleinfo.not.jarfile", arg); }
} else {
reportError("err.genmoduleinfo.unnamed.package", arg); abstract class Command {
} final CommandOption option;
protected Command(CommandOption option) {
this.option = option;
}
/**
* Returns true if the command-line options are all valid;
* otherwise, returns false.
*/
abstract boolean checkOptions();
/**
* Do analysis
*/
abstract boolean run(JdepsConfiguration config) throws IOException;
/**
* Includes all modules on system module path and application module path
*/
boolean allModules() {
return false;
}
@Override
public String toString() {
return option.toString();
}
}
/**
* Analyze dependences
*/
class AnalyzeDeps extends Command {
JdepsWriter writer;
AnalyzeDeps() {
this(CommandOption.ANALYZE_DEPS);
}
AnalyzeDeps(CommandOption option) {
super(option);
}
@Override
boolean checkOptions() {
if (options.findJDKInternals) {
// cannot set any filter, -verbose and -summary option
if (options.showSummary || options.verbose != null) {
reportError("err.invalid.options", "-summary or -verbose",
"-jdkinternals");
return false;
}
if (options.hasFilter()) {
reportError("err.invalid.options", "--package, --regex, --require",
"-jdkinternals");
return false; return false;
} }
} }
if (options.showSummary) {
// -summary cannot use with -verbose option
if (options.verbose != null) {
reportError("err.invalid.options", "-v, -verbose", "-s, -summary");
return false;
}
}
if (inputArgs.isEmpty() && !options.hasSourcePath()) {
showHelp();
return false;
}
return true;
} }
ModuleInfoBuilder builder /*
= new ModuleInfoBuilder(config, inputArgs, options.genModuleInfo); * Default is to show package-level dependencies
boolean ok = builder.run(); */
Type getAnalyzerType() {
if (options.showSummary)
return Type.SUMMARY;
if (!ok && !options.nowarning) { if (options.findJDKInternals)
log.println("ERROR: missing dependencies"); return Type.CLASS;
builder.visitMissingDeps(
new Analyzer.Visitor() { // default to package-level verbose
@Override return options.verbose != null ? options.verbose : PACKAGE;
public void visitDependence(String origin, Archive originArchive, }
String target, Archive targetArchive) {
if (builder.notFound(targetArchive)) @Override
log.format(" %-50s -> %-50s %s%n", boolean run(JdepsConfiguration config) throws IOException {
origin, target, targetArchive.getName()); Type type = getAnalyzerType();
} // default to package-level verbose
}); JdepsWriter writer = new SimpleWriter(log,
type,
options.showProfile,
options.showModule);
return run(config, writer, type);
}
boolean run(JdepsConfiguration config, JdepsWriter writer, Type type) throws IOException {
// analyze the dependencies
DepsAnalyzer analyzer = new DepsAnalyzer(config,
dependencyFilter(config),
writer,
type,
options.apiOnly);
boolean ok = analyzer.run(options.compileTimeView, options.depth);
// print skipped entries, if any
if (!options.nowarning) {
analyzer.archives()
.forEach(archive -> archive.reader()
.skippedEntries().stream()
.forEach(name -> warning("warn.skipped.entry", name)));
}
if (options.findJDKInternals && !options.nowarning) {
Map<String, String> jdkInternals = new TreeMap<>();
Set<String> deps = analyzer.dependences();
// find the ones with replacement
deps.forEach(cn -> replacementFor(cn).ifPresent(
repl -> jdkInternals.put(cn, repl))
);
if (!deps.isEmpty()) {
log.println();
warning("warn.replace.useJDKInternals", getMessage("jdeps.wiki.url"));
}
if (!jdkInternals.isEmpty()) {
log.println();
log.format("%-40s %s%n", "JDK Internal API", "Suggested Replacement");
log.format("%-40s %s%n", "----------------", "---------------------");
jdkInternals.entrySet().stream()
.forEach(e -> {
String key = e.getKey();
String[] lines = e.getValue().split("\\n");
for (String s : lines) {
log.format("%-40s %s%n", key, s);
key = "";
}
});
}
}
return ok;
} }
return ok;
} }
private String toPackageName(String name) {
int i = name.lastIndexOf('/'); class InverseAnalyzeDeps extends AnalyzeDeps {
return i > 0 ? name.replace('/', '.').substring(0, i) : ""; InverseAnalyzeDeps() {
}
@Override
boolean checkOptions() {
if (options.depth != 1) {
reportError("err.invalid.options", "-R", "--inverse");
return false;
}
if (options.numFilters() == 0) {
reportError("err.filter.not.specified");
return false;
}
if (!super.checkOptions()) {
return false;
}
return true;
}
@Override
boolean run(JdepsConfiguration config) throws IOException {
Type type = getAnalyzerType();
InverseDepsAnalyzer analyzer =
new InverseDepsAnalyzer(config,
dependencyFilter(config),
writer,
type,
options.apiOnly);
boolean ok = analyzer.run();
log.println();
if (!options.requires.isEmpty())
log.format("Inverse transitive dependences on %s%n", options.requires);
else
log.format("Inverse transitive dependences matching %s%n",
options.regex != null
? options.regex.toString()
: "packages " + options.packageNames);
analyzer.inverseDependences().stream()
.sorted(Comparator.comparing(this::sortPath))
.forEach(path -> log.println(path.stream()
.map(Archive::getName)
.collect(joining(" <- "))));
return ok;
}
private String sortPath(Deque<Archive> path) {
return path.peekFirst().getName();
}
}
class GenModuleInfo extends Command {
final Path dir;
GenModuleInfo(Path dir) {
super(CommandOption.GENERATE_MODULE_INFO);
this.dir = dir;
}
@Override
boolean checkOptions() {
if (options.classpath != null) {
reportError("err.invalid.options", "-classpath",
option);
return false;
}
if (options.hasFilter()) {
reportError("err.invalid.options", "--package, --regex, --require",
option);
return false;
}
return true;
}
@Override
boolean run(JdepsConfiguration config) throws IOException {
// check if any JAR file contains unnamed package
for (String arg : inputArgs) {
try (ClassFileReader reader = ClassFileReader.newInstance(Paths.get(arg))) {
Optional<String> classInUnnamedPackage =
reader.entries().stream()
.filter(n -> n.endsWith(".class"))
.filter(cn -> toPackageName(cn).isEmpty())
.findFirst();
if (classInUnnamedPackage.isPresent()) {
if (classInUnnamedPackage.get().equals("module-info.class")) {
reportError("err.genmoduleinfo.not.jarfile", arg);
} else {
reportError("err.genmoduleinfo.unnamed.package", arg);
}
return false;
}
}
}
ModuleInfoBuilder builder
= new ModuleInfoBuilder(config, inputArgs, dir);
boolean ok = builder.run();
if (!ok && !options.nowarning) {
log.println("ERROR: missing dependencies");
builder.visitMissingDeps(
new Analyzer.Visitor() {
@Override
public void visitDependence(String origin, Archive originArchive,
String target, Archive targetArchive) {
if (builder.notFound(targetArchive))
log.format(" %-50s -> %-50s %s%n",
origin, target, targetArchive.getName());
}
});
}
return ok;
}
private String toPackageName(String name) {
int i = name.lastIndexOf('/');
return i > 0 ? name.replace('/', '.').substring(0, i) : "";
}
}
class CheckModuleDeps extends Command {
final Set<String> modules;
CheckModuleDeps(Set<String> mods) {
super(CommandOption.CHECK_MODULES);
this.modules = mods;
}
@Override
boolean checkOptions() {
if (!inputArgs.isEmpty()) {
reportError("err.invalid.options", inputArgs, "--check");
return false;
}
return true;
}
@Override
boolean run(JdepsConfiguration config) throws IOException {
if (!config.initialArchives().isEmpty()) {
String list = config.initialArchives().stream()
.map(Archive::getPathName).collect(joining(" "));
throw new UncheckedBadArgs(new BadArgs("err.invalid.options",
list, "--check"));
}
return new ModuleAnalyzer(config, log, modules).run();
}
public boolean allModules() {
return true;
}
}
class ListReducedDeps extends ListModuleDeps {
ListReducedDeps() {
super(CommandOption.LIST_REDUCED_DEPS, true);
}
}
class ListModuleDeps extends Command {
final boolean reduced;
ListModuleDeps() {
this(CommandOption.LIST_DEPS, false);
}
ListModuleDeps(CommandOption option, boolean reduced) {
super(option);
this.reduced = reduced;
}
@Override
boolean checkOptions() {
if (options.showSummary || options.verbose != null) {
reportError("err.invalid.options", "-summary or -verbose",
option);
return false;
}
if (options.findJDKInternals) {
reportError("err.invalid.options", "-jdkinternals",
option);
return false;
}
if (inputArgs.isEmpty() && !options.hasSourcePath()) {
showHelp();
return false;
}
return true;
}
@Override
boolean run(JdepsConfiguration config) throws IOException {
return new ModuleExportsAnalyzer(config,
dependencyFilter(config),
reduced,
log).run();
}
public boolean allModules() {
return true;
}
}
class GenDotFile extends AnalyzeDeps {
final Path dotOutputDir;
GenDotFile(Path dotOutputDir) {
super(CommandOption.GENERATE_DOT_FILE);
this.dotOutputDir = dotOutputDir;
}
@Override
boolean run(JdepsConfiguration config) throws IOException {
if ((options.showSummary || options.verbose == MODULE) &&
!options.addmods.isEmpty() && inputArgs.isEmpty()) {
// print module descriptor
return new ModuleAnalyzer(config, log).genDotFiles(dotOutputDir);
}
Type type = getAnalyzerType();
JdepsWriter writer = new DotFileWriter(dotOutputDir,
type,
options.showProfile,
options.showModule,
options.showLabel);
return run(config, writer, type);
}
} }
/** /**
@ -875,14 +1137,11 @@ class JdepsTask {
boolean showLabel; boolean showLabel;
boolean findJDKInternals; boolean findJDKInternals;
boolean nowarning = false; boolean nowarning = false;
// default is to show package-level dependencies Analyzer.Type verbose;
// and filter references from same package // default filter references from same package
Analyzer.Type verbose = PACKAGE;
boolean filterSamePackage = true; boolean filterSamePackage = true;
boolean filterSameArchive = false; boolean filterSameArchive = false;
Pattern filterRegex; Pattern filterRegex;
Path dotOutputDir;
Path genModuleInfo;
String classpath; String classpath;
int depth = 1; int depth = 1;
Set<String> requires = new HashSet<>(); Set<String> requires = new HashSet<>();
@ -892,15 +1151,17 @@ class JdepsTask {
Pattern includeSystemModulePattern; Pattern includeSystemModulePattern;
boolean inverse = false; boolean inverse = false;
boolean compileTimeView = false; boolean compileTimeView = false;
Set<String> checkModuleDeps;
String systemModulePath = System.getProperty("java.home"); String systemModulePath = System.getProperty("java.home");
String upgradeModulePath; String upgradeModulePath;
String modulePath; String modulePath;
String rootModule; String rootModule;
Set<String> addmods = new HashSet<>(); Set<String> addmods = new HashSet<>();
Runtime.Version multiRelease; Runtime.Version multiRelease;
boolean showModulesAddExports;
boolean reduced; boolean hasSourcePath() {
return !addmods.isEmpty() || includePattern != null ||
includeSystemModulePattern != null;
}
boolean hasFilter() { boolean hasFilter() {
return numFilters() > 0; return numFilters() > 0;

View File

@ -70,14 +70,6 @@ public class ModuleAnalyzer {
public ModuleAnalyzer(JdepsConfiguration config, public ModuleAnalyzer(JdepsConfiguration config,
PrintWriter log, PrintWriter log,
Set<String> names) { Set<String> names) {
if (!config.initialArchives().isEmpty()) {
String list = config.initialArchives().stream()
.map(Archive::getPathName).collect(joining(" "));
throw new JdepsTask.UncheckedBadArgs(new BadArgs("err.invalid.module.option",
list, "--check"));
}
this.configuration = config; this.configuration = config;
this.log = log; this.log = log;

View File

@ -151,7 +151,9 @@ main.opt.jdkinternals=\
main.opt.list-deps=\ main.opt.list-deps=\
\ --list-deps Lists the dependences and use of JDK internal\n\ \ --list-deps Lists the dependences and use of JDK internal\n\
\ APIs.\n\ \ APIs.
main.opt.list-reduced-deps=\
\ --list-reduced-deps Same as --list-deps with not listing\n\ \ --list-reduced-deps Same as --list-deps with not listing\n\
\ the implied reads edges from the module graph\n\ \ the implied reads edges from the module graph\n\
\ If module M1 depends on M2 and M3,\n\ \ If module M1 depends on M2 and M3,\n\
@ -171,6 +173,7 @@ main.opt.multi-release=\
\ multi-release jar files. <version> should\n\ \ multi-release jar files. <version> should\n\
\ be integer >= 9 or base. \ be integer >= 9 or base.
err.command.set={0} and {1} options are specified.
err.unknown.option=unknown option: {0} err.unknown.option=unknown option: {0}
err.missing.arg=no value given for {0} err.missing.arg=no value given for {0}
err.invalid.arg.for.option=invalid argument for option: {0} err.invalid.arg.for.option=invalid argument for option: {0}
@ -180,11 +183,10 @@ err.genmoduleinfo.unnamed.package={0} contains an unnamed package that is not al
err.profiles.msg=No profile information err.profiles.msg=No profile information
err.exception.message={0} err.exception.message={0}
err.invalid.path=invalid path: {0} err.invalid.path=invalid path: {0}
err.invalid.module.option=Cannot set {0} with {1} option. err.invalid.options={0} cannot be used with {1} option
err.invalid.filters=Only one of --package (-p), --regex (-e), --require option can be set
err.module.not.found=module not found: {0} err.module.not.found=module not found: {0}
err.root.module.not.set=root module set empty err.root.module.not.set=root module set empty
err.invalid.inverse.option={0} cannot be used with --inverse option err.filter.not.specified=--package (-p), --regex (-e), --require option must be specified
err.multirelease.option.exists={0} is not a multi-release jar file, but the --multi-release option is set err.multirelease.option.exists={0} is not a multi-release jar file, but the --multi-release option is set
err.multirelease.option.notfound={0} is a multi-release jar file, but the --multi-release option is not set err.multirelease.option.notfound={0} is a multi-release jar file, but the --multi-release option is not set
err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2} err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2}

View File

@ -136,8 +136,6 @@ public class DotFileTest {
// with -P option // with -P option
List<String> argsWithDashP = new ArrayList<>(); List<String> argsWithDashP = new ArrayList<>();
argsWithDashP.add("-dotoutput");
argsWithDashP.add(dotoutput.toString());
argsWithDashP.add("-P"); argsWithDashP.add("-P");
argsWithDashP.addAll(args); argsWithDashP.addAll(args);
@ -162,8 +160,6 @@ public class DotFileTest {
// with -P option // with -P option
List<String> argsWithDashP = new ArrayList<>(); List<String> argsWithDashP = new ArrayList<>();
argsWithDashP.add("-dotoutput");
argsWithDashP.add(dotoutput.toString());
argsWithDashP.add("-P"); argsWithDashP.add("-P");
argsWithDashP.addAll(args); argsWithDashP.addAll(args);

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2016, 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 8168386
* @summary Test option validation
* @modules jdk.jdeps
* @library lib
* @build JdepsRunner
* @run testng Options
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
public class Options {
private static final String TEST_CLASSES = System.getProperty("test.classes");
@DataProvider(name = "errors")
public Object[][] errors() {
return new Object[][]{
{
new String[] { "-summary", "-v", TEST_CLASSES },
"-v, -verbose cannot be used with -s, -summary option"
},
{
new String[] { "-jdkinternal", "-summary", TEST_CLASSES },
"-summary or -verbose cannot be used with -jdkinternals option"
},
{
new String[] { "-jdkinternal", "-p", "java.lang", TEST_CLASSES },
"--package, --regex, --require cannot be used with -jdkinternals option"
},
{
new String[] { "--inverse", TEST_CLASSES },
"--package (-p), --regex (-e), --require option must be specified"
},
{
new String[] { "--inverse", "-R", TEST_CLASSES },
"-R cannot be used with --inverse option"
},
{
new String[] { "--generate-module-info", "dots", "-cp", TEST_CLASSES },
"-classpath cannot be used with --generate-module-info option"
},
{
new String[] { "--list-deps", "-summary", TEST_CLASSES },
"--list-deps and --list-reduced-deps options are specified"
},
{
new String[] { "--list-deps", "--list-reduced-deps", TEST_CLASSES },
"--list-deps and --list-reduced-deps options are specified"
},
};
}
@Test(dataProvider = "errors")
public void test(String[] options, String expected) {
jdepsError(options).outputContains(expected);
}
public static JdepsRunner jdepsError(String... args) {
JdepsRunner jdeps = new JdepsRunner(args);
assertTrue(jdeps.run(true) != 0);
return jdeps;
}
}

View File

@ -75,7 +75,7 @@ public class JdepsRunner {
} }
public boolean outputContains(String s) { public boolean outputContains(String s) {
return stdout.toString().contains(s); return stdout.toString().contains(s) || stderr.toString().contains(s);
} }
public void printStdout(PrintStream stream) { public void printStdout(PrintStream stream) {