|
23 | 23 | import javax.xml.transform.stream.StreamResult; |
24 | 24 | import javax.xml.transform.stream.StreamSource; |
25 | 25 | import java.io.*; |
| 26 | +import java.lang.module.ModuleDescriptor; |
26 | 27 | import java.lang.module.ModuleFinder; |
| 28 | +import java.lang.module.ModuleReference; |
27 | 29 | import java.net.Authenticator; |
28 | 30 | import java.net.PasswordAuthentication; |
29 | 31 | import java.net.URI; |
30 | 32 | import java.net.URISyntaxException; |
31 | 33 | import java.net.http.HttpClient; |
32 | 34 | import java.net.http.HttpRequest; |
33 | 35 | import java.net.http.HttpResponse; |
34 | | -import java.nio.file.Files; |
35 | | -import java.nio.file.Path; |
36 | | -import java.nio.file.Paths; |
37 | | -import java.nio.file.StandardCopyOption; |
| 36 | +import java.nio.file.*; |
| 37 | +import java.nio.file.attribute.BasicFileAttributes; |
38 | 38 | import java.util.*; |
39 | 39 | import java.util.concurrent.Callable; |
40 | | -import java.util.function.Consumer; |
41 | 40 | import java.util.function.Function; |
| 41 | +import java.util.stream.Collectors; |
42 | 42 |
|
43 | 43 | @CommandLine.Command( |
44 | 44 | name = "jresolve", |
45 | 45 | mixinStandardHelpOptions = true, |
46 | | - version = "v2024.07.24", |
| 46 | + version = "v2024.07.27", |
47 | 47 | description = "Resolves dependencies for the JVM." |
48 | 48 | ) |
49 | 49 | public final class CliMain implements Callable<Integer> { |
@@ -107,9 +107,22 @@ public final class CliMain implements Callable<Integer> { |
107 | 107 | ) |
108 | 108 | public File cachePath = null; |
109 | 109 |
|
| 110 | + @CommandLine.Option( |
| 111 | + names = {"--use-module-names"}, |
| 112 | + description = "Save files in the output directory using the module names the jars represent." |
| 113 | + ) |
| 114 | + public boolean useModuleNames = false; |
| 115 | + |
| 116 | + @CommandLine.Option( |
| 117 | + names = "--purge-output-directory", |
| 118 | + description = "Purges the specified output directory on run" |
| 119 | + ) |
| 120 | + public boolean purgeOutputDirectory = false; |
| 121 | + |
110 | 122 | @CommandLine.Parameters(paramLabel = "dependencies", description = "Package urls of dependencies") |
111 | 123 | public String[] dependencies = new String[]{}; |
112 | 124 |
|
| 125 | + |
113 | 126 | public CliMain(PrintWriter out, PrintWriter err) { |
114 | 127 | this.out = out; |
115 | 128 | this.err = err; |
@@ -320,9 +333,10 @@ protected PasswordAuthentication getPasswordAuthentication() { |
320 | 333 |
|
321 | 334 | if (enrichPom != null) { |
322 | 335 | var pomContents = Files.readString(enrichPom.toPath()); |
| 336 | + var factory = DocumentBuilderFactory.newDefaultInstance(); |
323 | 337 | Document document; |
324 | 338 | try { |
325 | | - document = DocumentBuilderFactory.newDefaultInstance() |
| 339 | + document = factory |
326 | 340 | .newDocumentBuilder() |
327 | 341 | .parse(new InputSource(new StringReader(pomContents))); |
328 | 342 | } catch (SAXException | IOException e) { |
@@ -499,29 +513,91 @@ protected PasswordAuthentication getPasswordAuthentication() { |
499 | 513 | } |
500 | 514 | } |
501 | 515 |
|
| 516 | + if (outputDirectory != null && purgeOutputDirectory) { |
| 517 | + Files.walkFileTree(outputDirectory.toPath(), new SimpleFileVisitor<>() { |
| 518 | + @Override |
| 519 | + public FileVisitResult visitFile(Path file, |
| 520 | + BasicFileAttributes attrs) throws IOException { |
| 521 | + Files.delete(file); |
| 522 | + return FileVisitResult.CONTINUE; |
| 523 | + } |
| 524 | + |
| 525 | + @Override |
| 526 | + public FileVisitResult postVisitDirectory(Path dir, |
| 527 | + IOException e) throws IOException { |
| 528 | + if (e == null) { |
| 529 | + Files.delete(dir); |
| 530 | + return FileVisitResult.CONTINUE; |
| 531 | + } else { |
| 532 | + throw e; |
| 533 | + } |
| 534 | + } |
| 535 | + |
| 536 | + }); |
| 537 | + } |
| 538 | + |
502 | 539 | if (outputDirectory != null && (!deps.libraries().isEmpty() || !extraPaths.isEmpty())) { |
503 | 540 | Files.createDirectories(outputDirectory.toPath()); |
504 | 541 |
|
505 | 542 |
|
506 | 543 | var artifacts = new LinkedHashMap<String, Path>(); |
507 | 544 |
|
508 | | - Consumer<Path> addPath = (path) -> { |
509 | | - var fileName = path.getFileName() |
510 | | - .toString(); |
511 | | - if (artifacts.containsKey(fileName)) { |
512 | | - err.println("Duplicate file: " + fileName + ". Need to rename."); |
513 | | - err.flush(); |
514 | | - fileName = UUID.randomUUID() + "-" + fileName; |
| 545 | + Function<Path, Integer> addPath = (path) -> { |
| 546 | + if (useModuleNames) { |
| 547 | + var modules = ModuleFinder.of(path).findAll().toArray(ModuleReference[]::new); |
| 548 | + if (modules.length == 0) { |
| 549 | + err.println("No module found: " + path); |
| 550 | + err.flush(); |
| 551 | + return 1; |
| 552 | + } |
| 553 | + if (modules.length > 1) { |
| 554 | + err.println("More than one module found: " + path); |
| 555 | + err.println( |
| 556 | + Arrays.stream(modules) |
| 557 | + .map(ModuleReference::descriptor) |
| 558 | + .map(ModuleDescriptor::name) |
| 559 | + .collect(Collectors.joining(", ")) |
| 560 | + ); |
| 561 | + err.flush(); |
| 562 | + return 1; |
| 563 | + } |
| 564 | + |
| 565 | + var module = modules[0]; |
| 566 | + |
| 567 | + var fileName = module.descriptor().name() + ".jar"; |
| 568 | + if (artifacts.containsKey(fileName)) { |
| 569 | + err.println("Duplicate module: " + module.descriptor().name()); |
| 570 | + err.flush(); |
| 571 | + return 1; |
| 572 | + } |
| 573 | + artifacts.put(fileName, path); |
| 574 | + } else { |
| 575 | + var fileName = path.getFileName() |
| 576 | + .toString(); |
| 577 | + if (artifacts.containsKey(fileName)) { |
| 578 | + err.println("Duplicate file: " + fileName + ". Need to rename."); |
| 579 | + err.flush(); |
| 580 | + fileName = UUID.randomUUID() + "-" + fileName; |
| 581 | + } |
| 582 | + artifacts.put(fileName, path); |
515 | 583 | } |
516 | | - artifacts.put(fileName, path); |
| 584 | + |
| 585 | + return 0; |
517 | 586 | }; |
518 | 587 |
|
519 | | - deps.libraries() |
520 | | - .forEach((library, path) -> { |
521 | | - addPath.accept(path); |
522 | | - }); |
| 588 | + for (var path : deps.libraries().values()) { |
| 589 | + int status = addPath.apply(path); |
| 590 | + if (status != 0) { |
| 591 | + return status; |
| 592 | + } |
| 593 | + } |
523 | 594 |
|
524 | | - extraPaths.forEach(addPath); |
| 595 | + for (var extraPath : extraPaths) { |
| 596 | + int status = addPath.apply(extraPath); |
| 597 | + if (status != 0) { |
| 598 | + return status; |
| 599 | + } |
| 600 | + } |
525 | 601 |
|
526 | 602 | artifacts.forEach((fileName, path) -> { |
527 | 603 | try { |
|
0 commit comments