127 boolean ignoreRest() {
128 return false;
129 }
130
131 abstract void process(JdepsTask task, String opt, String arg) throws BadArgs;
132 final boolean hasArg;
133 final String[] aliases;
134 }
135
136 static abstract class HiddenOption extends Option {
137 HiddenOption(boolean hasArg, String... aliases) {
138 super(hasArg, aliases);
139 }
140
141 boolean isHidden() {
142 return true;
143 }
144 }
145
146 static Option[] recognizedOptions = {
147 new Option(false, "-h", "-?", "-help") {
148 void process(JdepsTask task, String opt, String arg) {
149 task.options.help = true;
150 }
151 },
152 new Option(true, "-dotoutput") {
153 void process(JdepsTask task, String opt, String arg) throws BadArgs {
154 Path p = Paths.get(arg);
155 if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
156 throw new BadArgs("err.invalid.path", arg);
157 }
158 task.options.dotOutputDir = Paths.get(arg);;
159 }
160 },
161 new Option(false, "-s", "-summary") {
162 void process(JdepsTask task, String opt, String arg) {
163 task.options.showSummary = true;
164 task.options.verbose = SUMMARY;
165 }
166 },
167 new Option(false, "-v", "-verbose",
178 break;
179 case "-verbose:module":
180 task.options.verbose = MODULE;
181 break;
182 case "-verbose:package":
183 task.options.verbose = PACKAGE;
184 break;
185 case "-verbose:class":
186 task.options.verbose = CLASS;
187 break;
188 default:
189 throw new BadArgs("err.invalid.arg.for.option", opt);
190 }
191 }
192 },
193 new Option(false, "-apionly") {
194 void process(JdepsTask task, String opt, String arg) {
195 task.options.apiOnly = true;
196 }
197 },
198 new Option(true, "-check") {
199 void process(JdepsTask task, String opt, String arg) throws BadArgs {
200 Set<String> mods = Set.of(arg.split(","));
201 task.options.checkModuleDeps = mods;
202 task.options.addmods.addAll(mods);
203 }
204 },
205 new Option(true, "-genmoduleinfo") {
206 void process(JdepsTask task, String opt, String arg) throws BadArgs {
207 Path p = Paths.get(arg);
208 if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
209 throw new BadArgs("err.invalid.path", arg);
210 }
211 task.options.genModuleInfo = Paths.get(arg);
212 }
213 },
214 new Option(false, "-jdkinternals") {
215 void process(JdepsTask task, String opt, String arg) {
216 task.options.findJDKInternals = true;
217 task.options.verbose = CLASS;
218 if (task.options.includePattern == null) {
219 task.options.includePattern = Pattern.compile(".*");
220 }
221 }
222 },
223
224 // ---- paths option ----
225 new Option(true, "-cp", "-classpath") {
226 void process(JdepsTask task, String opt, String arg) {
227 task.options.classpath = arg;
228 }
229 },
230 new Option(true, "-mp", "-modulepath") {
231 void process(JdepsTask task, String opt, String arg) throws BadArgs {
232 task.options.modulePath = arg;
233 }
234 },
235 new Option(true, "-upgrademodulepath") {
236 void process(JdepsTask task, String opt, String arg) throws BadArgs {
237 task.options.upgradeModulePath = arg;
238 }
239 },
240 new Option(true, "-system") {
241 void process(JdepsTask task, String opt, String arg) throws BadArgs {
242 if (arg.equals("none")) {
243 task.options.systemModulePath = null;
244 } else {
245 Path path = Paths.get(arg);
246 if (Files.isRegularFile(path.resolve("lib").resolve("modules")))
247 task.options.systemModulePath = arg;
248 else
249 throw new BadArgs("err.invalid.path", arg);
250 }
251 }
252 },
253 new Option(true, "-addmods") {
254 void process(JdepsTask task, String opt, String arg) throws BadArgs {
255 Set<String> mods = Set.of(arg.split(","));
256 task.options.addmods.addAll(mods);
257 }
258 },
259 new Option(true, "-m") {
260 void process(JdepsTask task, String opt, String arg) throws BadArgs {
261 task.options.rootModule = arg;
262 task.options.addmods.add(arg);
263 }
264 },
265
266 // ---- Target filtering options ----
267 new Option(true, "-p", "-package") {
268 void process(JdepsTask task, String opt, String arg) {
269 task.options.packageNames.add(arg);
270 }
271 },
272 new Option(true, "-e", "-regex") {
273 void process(JdepsTask task, String opt, String arg) {
274 task.options.regex = Pattern.compile(arg);
275 }
276 },
277 new Option(true, "-requires") {
278 void process(JdepsTask task, String opt, String arg) {
279 task.options.requires.add(arg);
297 case "-filter:module":
298 task.options.filterSameArchive = true;
299 task.options.filterSamePackage = false;
300 break;
301 case "-filter:none":
302 task.options.filterSameArchive = false;
303 task.options.filterSamePackage = false;
304 break;
305 }
306 }
307 },
308
309 // ---- Source filtering options ----
310 new Option(true, "-include") {
311 void process(JdepsTask task, String opt, String arg) throws BadArgs {
312 task.options.includePattern = Pattern.compile(arg);
313 }
314 },
315
316 // Another alternative to list modules in -addmods option
317 new HiddenOption(true, "-include-system-modules") {
318 void process(JdepsTask task, String opt, String arg) throws BadArgs {
319 task.options.includeSystemModulePattern = Pattern.compile(arg);
320 }
321 },
322
323 new Option(false, "-P", "-profile") {
324 void process(JdepsTask task, String opt, String arg) throws BadArgs {
325 task.options.showProfile = true;
326 }
327 },
328
329 new Option(false, "-R", "-recursive") {
330 void process(JdepsTask task, String opt, String arg) {
331 task.options.depth = 0;
332 // turn off filtering
333 task.options.filterSameArchive = false;
334 task.options.filterSamePackage = false;
335 }
336 },
337
338 new Option(false, "-I", "-inverse") {
339 void process(JdepsTask task, String opt, String arg) {
340 task.options.inverse = true;
341 // equivalent to the inverse of compile-time view analysis
342 task.options.compileTimeView = true;
343 task.options.filterSamePackage = true;
344 task.options.filterSameArchive = true;
345 }
346 },
347
348 new Option(false, "-ct", "-compile-time") {
349 void process(JdepsTask task, String opt, String arg) {
350 task.options.compileTimeView = true;
351 task.options.filterSamePackage = true;
352 task.options.filterSameArchive = true;
353 task.options.depth = 0;
354 }
355 },
356
357 new Option(false, "-q", "-quiet") {
358 void process(JdepsTask task, String opt, String arg) {
359 task.options.nowarning = true;
360 }
361 },
362
363 new Option(false, "-version") {
364 void process(JdepsTask task, String opt, String arg) {
365 task.options.version = true;
366 }
367 },
368 new HiddenOption(false, "-fullversion") {
369 void process(JdepsTask task, String opt, String arg) {
370 task.options.fullVersion = true;
371 }
372 },
373 new HiddenOption(false, "-showlabel") {
374 void process(JdepsTask task, String opt, String arg) {
375 task.options.showLabel = true;
376 }
377 },
378 new HiddenOption(false, "-hide-module") {
379 void process(JdepsTask task, String opt, String arg) {
380 task.options.showModule = false;
381 }
382 },
383 new HiddenOption(true, "-depth") {
384 void process(JdepsTask task, String opt, String arg) throws BadArgs {
385 try {
386 task.options.depth = Integer.parseInt(arg);
387 } catch (NumberFormatException e) {
388 throw new BadArgs("err.invalid.arg.for.option", opt);
389 }
390 }
391 },
392 };
393
394 private static final String PROGNAME = "jdeps";
395 private final Options options = new Options();
396 private final List<String> inputArgs = new ArrayList<>();
397
398 private PrintWriter log;
447
448 if (options.inverse && options.depth != 1) {
449 reportError("err.invalid.inverse.option", "-R");
450 return EXIT_CMDERR;
451 }
452
453 if (options.inverse && options.numFilters() == 0) {
454 reportError("err.invalid.filters");
455 return EXIT_CMDERR;
456 }
457
458 if ((options.findJDKInternals) && (options.hasFilter() || options.showSummary)) {
459 showHelp();
460 return EXIT_CMDERR;
461 }
462 if (options.showSummary && options.verbose != SUMMARY) {
463 showHelp();
464 return EXIT_CMDERR;
465 }
466 if (options.checkModuleDeps != null && !inputArgs.isEmpty()) {
467 reportError("err.invalid.module.option", inputArgs, "-check");
468 }
469
470 boolean ok = run();
471 return ok ? EXIT_OK : EXIT_ERROR;
472 } catch (BadArgs|UncheckedBadArgs e) {
473 reportError(e.getKey(), e.getArgs());
474 if (e.showUsage()) {
475 log.println(getMessage("main.usage.summary", PROGNAME));
476 }
477 return EXIT_CMDERR;
478 } catch (ResolutionException e) {
479 reportError("err.exception.message", e.getMessage());
480 return EXIT_CMDERR;
481 } catch (IOException e) {
482 e.printStackTrace();
483 return EXIT_CMDERR;
484 } finally {
485 log.flush();
486 }
487 }
488
489 boolean run() throws IOException {
490 try (JdepsConfiguration config = buildConfig()) {
491
492 // detect split packages
493 config.splitPackages().entrySet().stream()
494 .sorted(Map.Entry.comparingByKey())
495 .forEach(e -> System.out.format("split package: %s %s%n", e.getKey(),
496 e.getValue().toString()));
497
498 // check if any module specified in -requires is missing
499 Stream.concat(options.addmods.stream(), options.requires.stream())
500 .filter(mn -> !config.isValidToken(mn))
501 .forEach(mn -> config.findModule(mn).orElseThrow(() ->
502 new UncheckedBadArgs(new BadArgs("err.module.not.found", mn))));
503
504 // -genmoduleinfo
505 if (options.genModuleInfo != null) {
506 return genModuleInfo(config);
507 }
508
509 // -check
510 if (options.checkModuleDeps != null) {
511 return new ModuleAnalyzer(config, log, options.checkModuleDeps).run();
512 }
513
514 if (options.dotOutputDir != null &&
515 (options.verbose == SUMMARY || options.verbose == MODULE) &&
516 !options.addmods.isEmpty() && inputArgs.isEmpty()) {
517 return new ModuleAnalyzer(config, log).genDotFiles(options.dotOutputDir);
518 }
519
520 if (options.inverse) {
521 return analyzeInverseDeps(config);
522 } else {
523 return analyzeDeps(config);
524 }
525 }
526 }
527
528 private JdepsConfiguration buildConfig() throws IOException {
529 JdepsConfiguration.Builder builder =
|
127 boolean ignoreRest() {
128 return false;
129 }
130
131 abstract void process(JdepsTask task, String opt, String arg) throws BadArgs;
132 final boolean hasArg;
133 final String[] aliases;
134 }
135
136 static abstract class HiddenOption extends Option {
137 HiddenOption(boolean hasArg, String... aliases) {
138 super(hasArg, aliases);
139 }
140
141 boolean isHidden() {
142 return true;
143 }
144 }
145
146 static Option[] recognizedOptions = {
147 new Option(false, "-h", "-?", "-help", "--help") {
148 void process(JdepsTask task, String opt, String arg) {
149 task.options.help = true;
150 }
151 },
152 new Option(true, "-dotoutput") {
153 void process(JdepsTask task, String opt, String arg) throws BadArgs {
154 Path p = Paths.get(arg);
155 if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
156 throw new BadArgs("err.invalid.path", arg);
157 }
158 task.options.dotOutputDir = Paths.get(arg);;
159 }
160 },
161 new Option(false, "-s", "-summary") {
162 void process(JdepsTask task, String opt, String arg) {
163 task.options.showSummary = true;
164 task.options.verbose = SUMMARY;
165 }
166 },
167 new Option(false, "-v", "-verbose",
178 break;
179 case "-verbose:module":
180 task.options.verbose = MODULE;
181 break;
182 case "-verbose:package":
183 task.options.verbose = PACKAGE;
184 break;
185 case "-verbose:class":
186 task.options.verbose = CLASS;
187 break;
188 default:
189 throw new BadArgs("err.invalid.arg.for.option", opt);
190 }
191 }
192 },
193 new Option(false, "-apionly") {
194 void process(JdepsTask task, String opt, String arg) {
195 task.options.apiOnly = true;
196 }
197 },
198 new Option(true, "--check") {
199 void process(JdepsTask task, String opt, String arg) throws BadArgs {
200 Set<String> mods = Set.of(arg.split(","));
201 task.options.checkModuleDeps = mods;
202 task.options.addmods.addAll(mods);
203 }
204 },
205 new Option(true, "--gen-module-info") {
206 void process(JdepsTask task, String opt, String arg) throws BadArgs {
207 Path p = Paths.get(arg);
208 if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
209 throw new BadArgs("err.invalid.path", arg);
210 }
211 task.options.genModuleInfo = Paths.get(arg);
212 }
213 },
214 new Option(false, "-jdkinternals") {
215 void process(JdepsTask task, String opt, String arg) {
216 task.options.findJDKInternals = true;
217 task.options.verbose = CLASS;
218 if (task.options.includePattern == null) {
219 task.options.includePattern = Pattern.compile(".*");
220 }
221 }
222 },
223
224 // ---- paths option ----
225 new Option(true, "-cp", "-classpath", "--class-path") {
226 void process(JdepsTask task, String opt, String arg) {
227 task.options.classpath = arg;
228 }
229 },
230 new Option(true, "--module-path") {
231 void process(JdepsTask task, String opt, String arg) throws BadArgs {
232 task.options.modulePath = arg;
233 }
234 },
235 new Option(true, "--upgrade-module-path") {
236 void process(JdepsTask task, String opt, String arg) throws BadArgs {
237 task.options.upgradeModulePath = arg;
238 }
239 },
240 new Option(true, "--system") {
241 void process(JdepsTask task, String opt, String arg) throws BadArgs {
242 if (arg.equals("none")) {
243 task.options.systemModulePath = null;
244 } else {
245 Path path = Paths.get(arg);
246 if (Files.isRegularFile(path.resolve("lib").resolve("modules")))
247 task.options.systemModulePath = arg;
248 else
249 throw new BadArgs("err.invalid.path", arg);
250 }
251 }
252 },
253 new Option(true, "--add-modules") {
254 void process(JdepsTask task, String opt, String arg) throws BadArgs {
255 Set<String> mods = Set.of(arg.split(","));
256 task.options.addmods.addAll(mods);
257 }
258 },
259 new Option(true, "-m", "--module") {
260 void process(JdepsTask task, String opt, String arg) throws BadArgs {
261 task.options.rootModule = arg;
262 task.options.addmods.add(arg);
263 }
264 },
265
266 // ---- Target filtering options ----
267 new Option(true, "-p", "-package") {
268 void process(JdepsTask task, String opt, String arg) {
269 task.options.packageNames.add(arg);
270 }
271 },
272 new Option(true, "-e", "-regex") {
273 void process(JdepsTask task, String opt, String arg) {
274 task.options.regex = Pattern.compile(arg);
275 }
276 },
277 new Option(true, "-requires") {
278 void process(JdepsTask task, String opt, String arg) {
279 task.options.requires.add(arg);
297 case "-filter:module":
298 task.options.filterSameArchive = true;
299 task.options.filterSamePackage = false;
300 break;
301 case "-filter:none":
302 task.options.filterSameArchive = false;
303 task.options.filterSamePackage = false;
304 break;
305 }
306 }
307 },
308
309 // ---- Source filtering options ----
310 new Option(true, "-include") {
311 void process(JdepsTask task, String opt, String arg) throws BadArgs {
312 task.options.includePattern = Pattern.compile(arg);
313 }
314 },
315
316 // Another alternative to list modules in -addmods option
317 new HiddenOption(true, "--include-system-modules") {
318 void process(JdepsTask task, String opt, String arg) throws BadArgs {
319 task.options.includeSystemModulePattern = Pattern.compile(arg);
320 }
321 },
322
323 new Option(false, "-P", "-profile") {
324 void process(JdepsTask task, String opt, String arg) throws BadArgs {
325 task.options.showProfile = true;
326 }
327 },
328
329 new Option(false, "-R", "-recursive") {
330 void process(JdepsTask task, String opt, String arg) {
331 task.options.depth = 0;
332 // turn off filtering
333 task.options.filterSameArchive = false;
334 task.options.filterSamePackage = false;
335 }
336 },
337
338 new Option(false, "-I", "-inverse") {
339 void process(JdepsTask task, String opt, String arg) {
340 task.options.inverse = true;
341 // equivalent to the inverse of compile-time view analysis
342 task.options.compileTimeView = true;
343 task.options.filterSamePackage = true;
344 task.options.filterSameArchive = true;
345 }
346 },
347
348 new Option(false, "--compile-time") {
349 void process(JdepsTask task, String opt, String arg) {
350 task.options.compileTimeView = true;
351 task.options.filterSamePackage = true;
352 task.options.filterSameArchive = true;
353 task.options.depth = 0;
354 }
355 },
356
357 new Option(false, "-q", "-quiet") {
358 void process(JdepsTask task, String opt, String arg) {
359 task.options.nowarning = true;
360 }
361 },
362
363 new Option(false, "-version") {
364 void process(JdepsTask task, String opt, String arg) {
365 task.options.version = true;
366 }
367 },
368 new HiddenOption(false, "-fullversion") {
369 void process(JdepsTask task, String opt, String arg) {
370 task.options.fullVersion = true;
371 }
372 },
373 new HiddenOption(false, "-showlabel") {
374 void process(JdepsTask task, String opt, String arg) {
375 task.options.showLabel = true;
376 }
377 },
378 new HiddenOption(false, "--hide-show-module") {
379 void process(JdepsTask task, String opt, String arg) {
380 task.options.showModule = false;
381 }
382 },
383 new HiddenOption(true, "-depth") {
384 void process(JdepsTask task, String opt, String arg) throws BadArgs {
385 try {
386 task.options.depth = Integer.parseInt(arg);
387 } catch (NumberFormatException e) {
388 throw new BadArgs("err.invalid.arg.for.option", opt);
389 }
390 }
391 },
392 };
393
394 private static final String PROGNAME = "jdeps";
395 private final Options options = new Options();
396 private final List<String> inputArgs = new ArrayList<>();
397
398 private PrintWriter log;
447
448 if (options.inverse && options.depth != 1) {
449 reportError("err.invalid.inverse.option", "-R");
450 return EXIT_CMDERR;
451 }
452
453 if (options.inverse && options.numFilters() == 0) {
454 reportError("err.invalid.filters");
455 return EXIT_CMDERR;
456 }
457
458 if ((options.findJDKInternals) && (options.hasFilter() || options.showSummary)) {
459 showHelp();
460 return EXIT_CMDERR;
461 }
462 if (options.showSummary && options.verbose != SUMMARY) {
463 showHelp();
464 return EXIT_CMDERR;
465 }
466 if (options.checkModuleDeps != null && !inputArgs.isEmpty()) {
467 reportError("err.invalid.module.option", inputArgs, "--check");
468 }
469
470 boolean ok = run();
471 return ok ? EXIT_OK : EXIT_ERROR;
472 } catch (BadArgs|UncheckedBadArgs e) {
473 reportError(e.getKey(), e.getArgs());
474 if (e.showUsage()) {
475 log.println(getMessage("main.usage.summary", PROGNAME));
476 }
477 return EXIT_CMDERR;
478 } catch (ResolutionException e) {
479 reportError("err.exception.message", e.getMessage());
480 return EXIT_CMDERR;
481 } catch (IOException e) {
482 e.printStackTrace();
483 return EXIT_CMDERR;
484 } finally {
485 log.flush();
486 }
487 }
488
489 boolean run() throws IOException {
490 try (JdepsConfiguration config = buildConfig()) {
491
492 // detect split packages
493 config.splitPackages().entrySet().stream()
494 .sorted(Map.Entry.comparingByKey())
495 .forEach(e -> System.out.format("split package: %s %s%n", e.getKey(),
496 e.getValue().toString()));
497
498 // check if any module specified in -requires is missing
499 Stream.concat(options.addmods.stream(), options.requires.stream())
500 .filter(mn -> !config.isValidToken(mn))
501 .forEach(mn -> config.findModule(mn).orElseThrow(() ->
502 new UncheckedBadArgs(new BadArgs("err.module.not.found", mn))));
503
504 // --gen-module-info
505 if (options.genModuleInfo != null) {
506 return genModuleInfo(config);
507 }
508
509 // --check
510 if (options.checkModuleDeps != null) {
511 return new ModuleAnalyzer(config, log, options.checkModuleDeps).run();
512 }
513
514 if (options.dotOutputDir != null &&
515 (options.verbose == SUMMARY || options.verbose == MODULE) &&
516 !options.addmods.isEmpty() && inputArgs.isEmpty()) {
517 return new ModuleAnalyzer(config, log).genDotFiles(options.dotOutputDir);
518 }
519
520 if (options.inverse) {
521 return analyzeInverseDeps(config);
522 } else {
523 return analyzeDeps(config);
524 }
525 }
526 }
527
528 private JdepsConfiguration buildConfig() throws IOException {
529 JdepsConfiguration.Builder builder =
|