8168386: Fix jdeps verbose options
Reviewed-by: dfuchs, lancea
This commit is contained in:
parent
8899d19210
commit
40e24f2e56
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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);
|
||||
|
||||
|
92
langtools/test/tools/jdeps/Options.java
Normal file
92
langtools/test/tools/jdeps/Options.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user