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;
import com.sun.tools.jdeps.Analyzer.Type;
import static com.sun.tools.jdeps.Analyzer.Type.*;
import static com.sun.tools.jdeps.JdepsWriter.*;
import static java.util.stream.Collectors.*;
import java.io.IOException;
import java.io.PrintWriter;
@ -111,6 +113,10 @@ class JdepsTask {
this.aliases = aliases;
}
Option(boolean hasArg, CommandOption cmd) {
this(hasArg, cmd.names());
}
boolean isHidden() {
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 = {
new Option(false, "-h", "-?", "-help", "--help") {
void process(JdepsTask task, String opt, String arg) {
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 {
Path p = Paths.get(arg);
if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
throw new BadArgs("err.invalid.path", arg);
if (task.command != null) {
throw new BadArgs("err.command.set", task.command, opt);
}
task.options.dotOutputDir = Paths.get(arg);;
task.command = task.genDotFile(Paths.get(arg));
}
},
new Option(false, "-s", "-summary") {
void process(JdepsTask task, String opt, String arg) {
task.options.showSummary = true;
task.options.verbose = SUMMARY;
}
},
new Option(false, "-v", "-verbose",
@ -196,35 +223,48 @@ class JdepsTask {
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") {
void process(JdepsTask task, String opt, String arg) {
task.options.findJDKInternals = true;
task.options.verbose = CLASS;
if (task.options.includePattern == null) {
task.options.includePattern = Pattern.compile(".*");
}
}
},
new Option(false, "--list-deps", "--list-reduced-deps") {
void process(JdepsTask task, String opt, String arg) {
task.options.showModulesAddExports = true;
task.options.reduced = opt.equals("--list-reduced-deps");
new Option(true, CommandOption.CHECK_MODULES) {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
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 List<String> inputArgs = new ArrayList<>();
private Command command;
private PrintWriter log;
void setLog(PrintWriter out) {
log = out;
@ -445,55 +486,30 @@ class JdepsTask {
if (options.version || options.fullVersion) {
showVersion(options.fullVersion);
}
if (options.help || options.version || options.fullVersion) {
return EXIT_OK;
}
if (!inputArgs.isEmpty() && options.rootModule != null) {
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) {
reportError("err.invalid.filters");
return EXIT_CMDERR;
}
if (options.inverse && options.depth != 1) {
reportError("err.invalid.inverse.option", "-R");
return EXIT_CMDERR;
// default command to analyze dependences
if (command == null) {
command = analyzeDeps();
}
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");
if (!command.checkOptions()) {
return EXIT_CMDERR;
}
boolean ok = run();
return ok ? EXIT_OK : EXIT_ERROR;
} catch (BadArgs|UncheckedBadArgs e) {
reportError(e.getKey(), e.getArgs());
if (e.showUsage()) {
@ -515,13 +531,14 @@ class JdepsTask {
}
boolean run() throws IOException {
try (JdepsConfiguration config = buildConfig()) {
try (JdepsConfiguration config = buildConfig(command.allModules())) {
// detect split packages
config.splitPackages().entrySet().stream()
config.splitPackages().entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.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
Stream.concat(options.addmods.stream(), options.requires.stream())
@ -529,38 +546,11 @@ class JdepsTask {
.forEach(mn -> config.findModule(mn).orElseThrow(() ->
new UncheckedBadArgs(new BadArgs("err.module.not.found", mn))));
// --generate-module-info
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);
}
return command.run(config);
}
}
private JdepsConfiguration buildConfig() throws IOException {
private JdepsConfiguration buildConfig(boolean allModules) throws IOException {
JdepsConfiguration.Builder builder =
new JdepsConfiguration.Builder(options.systemModulePath);
@ -568,7 +558,7 @@ class JdepsTask {
.appModulePath(options.modulePath)
.addmods(options.addmods);
if (options.checkModuleDeps != null || options.showModulesAddExports) {
if (allModules) {
// check all system modules in the image
builder.allModules();
}
@ -592,148 +582,420 @@ class JdepsTask {
return builder.build();
}
private boolean analyzeDeps(JdepsConfiguration config) throws IOException {
// 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);
}
// ---- factory methods to create a Command
// analyze the dependencies
DepsAnalyzer analyzer = new DepsAnalyzer(config,
dependencyFilter(config),
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 AnalyzeDeps analyzeDeps() throws BadArgs {
return options.inverse ? new InverseAnalyzeDeps()
: new AnalyzeDeps();
}
private boolean analyzeInverseDeps(JdepsConfiguration config) throws IOException {
JdepsWriter writer = new SimpleWriter(log,
options.verbose,
options.showProfile,
options.showModule);
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 GenDotFile genDotFile(Path dir) throws BadArgs {
if (Files.exists(dir) && (!Files.isDirectory(dir) || !Files.isWritable(dir))) {
throw new BadArgs("err.invalid.path", dir.toString());
}
return new GenDotFile(dir);
}
private String sortPath(Deque<Archive> path) {
return path.peekFirst().getName();
private GenModuleInfo genModuleInfo(Path dir) throws BadArgs {
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 {
// 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();
private ListModuleDeps listModuleDeps(boolean reduced) throws BadArgs {
return reduced ? new ListReducedDeps()
: new ListModuleDeps();
}
if (classInUnnamedPackage.isPresent()) {
if (classInUnnamedPackage.get().equals("module-info.class")) {
reportError("err.genmoduleinfo.not.jarfile", arg);
} else {
reportError("err.genmoduleinfo.unnamed.package", arg);
}
private CheckModuleDeps checkModuleDeps(Set<String> mods) throws BadArgs {
return new CheckModuleDeps(mods);
}
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;
}
}
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);
boolean ok = builder.run();
/*
* Default is to show package-level dependencies
*/
Type getAnalyzerType() {
if (options.showSummary)
return Type.SUMMARY;
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());
}
});
if (options.findJDKInternals)
return Type.CLASS;
// default to package-level verbose
return options.verbose != null ? options.verbose : PACKAGE;
}
@Override
boolean run(JdepsConfiguration config) throws IOException {
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('/');
return i > 0 ? name.replace('/', '.').substring(0, i) : "";
class InverseAnalyzeDeps extends AnalyzeDeps {
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 findJDKInternals;
boolean nowarning = false;
// default is to show package-level dependencies
// and filter references from same package
Analyzer.Type verbose = PACKAGE;
Analyzer.Type verbose;
// default filter references from same package
boolean filterSamePackage = true;
boolean filterSameArchive = false;
Pattern filterRegex;
Path dotOutputDir;
Path genModuleInfo;
String classpath;
int depth = 1;
Set<String> requires = new HashSet<>();
@ -892,15 +1151,17 @@ class JdepsTask {
Pattern includeSystemModulePattern;
boolean inverse = false;
boolean compileTimeView = false;
Set<String> checkModuleDeps;
String systemModulePath = System.getProperty("java.home");
String upgradeModulePath;
String modulePath;
String rootModule;
Set<String> addmods = new HashSet<>();
Runtime.Version multiRelease;
boolean showModulesAddExports;
boolean reduced;
boolean hasSourcePath() {
return !addmods.isEmpty() || includePattern != null ||
includeSystemModulePattern != null;
}
boolean hasFilter() {
return numFilters() > 0;

View File

@ -70,14 +70,6 @@ public class ModuleAnalyzer {
public ModuleAnalyzer(JdepsConfiguration config,
PrintWriter log,
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.log = log;

View File

@ -151,7 +151,9 @@ main.opt.jdkinternals=\
main.opt.list-deps=\
\ --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\
\ the implied reads edges from the module graph\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\
\ be integer >= 9 or base.
err.command.set={0} and {1} options are specified.
err.unknown.option=unknown option: {0}
err.missing.arg=no value given for {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.exception.message={0}
err.invalid.path=invalid path: {0}
err.invalid.module.option=Cannot set {0} with {1} option.
err.invalid.filters=Only one of --package (-p), --regex (-e), --require option can be set
err.invalid.options={0} cannot be used with {1} option
err.module.not.found=module not found: {0}
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.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}

View File

@ -136,8 +136,6 @@ public class DotFileTest {
// with -P option
List<String> argsWithDashP = new ArrayList<>();
argsWithDashP.add("-dotoutput");
argsWithDashP.add(dotoutput.toString());
argsWithDashP.add("-P");
argsWithDashP.addAll(args);
@ -162,8 +160,6 @@ public class DotFileTest {
// with -P option
List<String> argsWithDashP = new ArrayList<>();
argsWithDashP.add("-dotoutput");
argsWithDashP.add(dotoutput.toString());
argsWithDashP.add("-P");
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) {
return stdout.toString().contains(s);
return stdout.toString().contains(s) || stderr.toString().contains(s);
}
public void printStdout(PrintStream stream) {