< prev index next >

src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java

Print this page




  83 import java.util.jar.JarOutputStream;
  84 import java.util.stream.Collectors;
  85 import java.util.regex.Pattern;
  86 import java.util.regex.PatternSyntaxException;
  87 import java.util.stream.Stream;
  88 import java.util.zip.ZipEntry;
  89 import java.util.zip.ZipException;
  90 import java.util.zip.ZipFile;
  91 
  92 import jdk.internal.jmod.JmodFile;
  93 import jdk.internal.jmod.JmodFile.Section;
  94 import jdk.internal.joptsimple.BuiltinHelpFormatter;
  95 import jdk.internal.joptsimple.NonOptionArgumentSpec;
  96 import jdk.internal.joptsimple.OptionDescriptor;
  97 import jdk.internal.joptsimple.OptionException;
  98 import jdk.internal.joptsimple.OptionParser;
  99 import jdk.internal.joptsimple.OptionSet;
 100 import jdk.internal.joptsimple.OptionSpec;
 101 import jdk.internal.joptsimple.ValueConverter;
 102 import jdk.internal.loader.ResourceHelper;
 103 import jdk.internal.misc.JavaLangModuleAccess;
 104 import jdk.internal.misc.SharedSecrets;
 105 import jdk.internal.module.ModuleHashes;

 106 import jdk.internal.module.ModuleInfoExtender;


 107 import jdk.tools.jlink.internal.Utils;
 108 
 109 import static java.util.stream.Collectors.joining;
 110 
 111 /**
 112  * Implementation for the jmod tool.
 113  */
 114 public class JmodTask {
 115 
 116     static class CommandException extends RuntimeException {
 117         private static final long serialVersionUID = 0L;
 118         boolean showUsage;
 119 
 120         CommandException(String key, Object... args) {
 121             super(getMessageOrKey(key, args));
 122         }
 123 
 124         CommandException showUsage(boolean b) {
 125             showUsage = b;
 126             return this;


 159     };
 160 
 161     static class Options {
 162         Mode mode;
 163         Path jmodFile;
 164         boolean help;
 165         boolean version;
 166         List<Path> classpath;
 167         List<Path> cmds;
 168         List<Path> configs;
 169         List<Path> libs;
 170         List<Path> headerFiles;
 171         List<Path> manPages;
 172         ModuleFinder moduleFinder;
 173         Version moduleVersion;
 174         String mainClass;
 175         String osName;
 176         String osArch;
 177         String osVersion;
 178         Pattern modulesToHash;

 179         boolean dryrun;
 180         List<PathMatcher> excludes;
 181     }
 182 
 183     public int run(String[] args) {
 184 
 185         try {
 186             handleOptions(args);
 187             if (options == null) {
 188                 showUsageSummary();
 189                 return EXIT_CMDERR;
 190             }
 191             if (options.help) {
 192                 showHelp();
 193                 return EXIT_OK;
 194             }
 195             if (options.version) {
 196                 showVersion();
 197                 return EXIT_OK;
 198             }


 238             } catch (IOException x) {
 239                 throw new IOException("error opening jmod file", x);
 240             }
 241 
 242             // Trivially print the archive entries for now, pending a more complete implementation
 243             zip.stream().forEach(e -> out.println(e.getName()));
 244             return true;
 245         } finally {
 246             if (zip != null)
 247                 zip.close();
 248         }
 249     }
 250 
 251     private boolean hashModules() {
 252         return new Hasher(options.moduleFinder).run();
 253     }
 254 
 255     private boolean describe() throws IOException {
 256         try (JmodFile jf = new JmodFile(options.jmodFile)) {
 257             try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
 258                 ModuleDescriptor md = ModuleDescriptor.read(in);
 259                 printModuleDescriptor(md);
 260                 return true;
 261             } catch (IOException e) {
 262                 throw new CommandException("err.module.descriptor.not.found");
 263             }
 264         }
 265     }
 266 
 267     static <T> String toString(Collection<T> c) {
 268         if (c.isEmpty()) { return ""; }
 269         return c.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
 270                   .collect(joining(" "));
 271     }
 272 
 273     private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
 274 
 275     private void printModuleDescriptor(ModuleDescriptor md)
 276         throws IOException
 277     {
 278         StringBuilder sb = new StringBuilder();
 279         sb.append("\n").append(md.toNameAndVersion());
 280 
 281         md.requires().stream()
 282             .sorted(Comparator.comparing(Requires::name))
 283             .forEach(r -> {
 284                 sb.append("\n  requires ");
 285                 if (!r.modifiers().isEmpty())
 286                     sb.append(toString(r.modifiers())).append(" ");
 287                 sb.append(r.name());
 288             });
 289 
 290         md.uses().stream().sorted()
 291             .forEach(s -> sb.append("\n  uses ").append(s));
 292 
 293         md.exports().stream()
 294             .sorted(Comparator.comparing(Exports::source))
 295             .forEach(p -> sb.append("\n  exports ").append(p));


 301         Set<String> concealed = new HashSet<>(md.packages());
 302         md.exports().stream().map(Exports::source).forEach(concealed::remove);
 303         md.opens().stream().map(Opens::source).forEach(concealed::remove);
 304         concealed.stream().sorted()
 305                  .forEach(p -> sb.append("\n  contains ").append(p));
 306 
 307         md.provides().stream()
 308             .sorted(Comparator.comparing(Provides::service))
 309             .forEach(p -> sb.append("\n  provides ").append(p.service())
 310                             .append(" with ")
 311                             .append(toString(p.providers())));
 312 
 313         md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
 314 
 315         md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
 316 
 317         md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
 318 
 319         md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 320 
 321         JLMA.hashes(md).ifPresent(
 322             hashes -> hashes.names().stream().sorted().forEach(
 323                 mod -> sb.append("\n  hashes ").append(mod).append(" ")
 324                          .append(hashes.algorithm()).append(" ")
 325                          .append(hashes.hashFor(mod))));

 326 
 327         out.println(sb.toString());
 328     }
 329 








 330     private boolean create() throws IOException {
 331         JmodFileWriter jmod = new JmodFileWriter();
 332 
 333         // create jmod with temporary name to avoid it being examined
 334         // when scanning the module path
 335         Path target = options.jmodFile;
 336         Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
 337         try {
 338             try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) {
 339                 jmod.write(jos);
 340             }
 341             Files.move(tempTarget, target);
 342         } catch (Exception e) {
 343             if (Files.exists(tempTarget)) {
 344                 try {
 345                     Files.delete(tempTarget);
 346                 } catch (IOException ioe) {
 347                     e.addSuppressed(ioe);
 348                 }
 349             }
 350             throw e;
 351         }
 352         return true;
 353     }
 354 
 355     private class JmodFileWriter {
 356         final List<Path> cmds = options.cmds;
 357         final List<Path> libs = options.libs;
 358         final List<Path> configs = options.configs;
 359         final List<Path> classpath = options.classpath;
 360         final List<Path> headerFiles = options.headerFiles;
 361         final List<Path> manPages = options.manPages;
 362 
 363         final Version moduleVersion = options.moduleVersion;
 364         final String mainClass = options.mainClass;
 365         final String osName = options.osName;
 366         final String osArch = options.osArch;
 367         final String osVersion = options.osVersion;
 368         final List<PathMatcher> excludes = options.excludes;
 369         final Hasher hasher = hasher();

 370 
 371         JmodFileWriter() { }
 372 
 373         /**
 374          * Writes the jmod to the given output stream.
 375          */
 376         void write(JmodOutputStream out) throws IOException {
 377             // module-info.class
 378             writeModuleInfo(out, findPackages(classpath));
 379 
 380             // classes
 381             processClasses(out, classpath);
 382 
 383             processSection(out, Section.NATIVE_CMDS, cmds);
 384             processSection(out, Section.NATIVE_LIBS, libs);
 385             processSection(out, Section.CONFIG, configs);
 386             processSection(out, Section.HEADER_FILES, headerFiles);
 387             processSection(out, Section.MAN_PAGES, manPages);
 388 
 389         }


 458                 if (mainClass != null)
 459                     extender.mainClass(mainClass);
 460 
 461                 // --os-name, --os-arch, --os-version
 462                 if (osName != null || osArch != null || osVersion != null)
 463                     extender.targetPlatform(osName, osArch, osVersion);
 464 
 465                 // --module-version
 466                 if (moduleVersion != null)
 467                     extender.version(moduleVersion);
 468 
 469                 if (hasher != null) {
 470                     ModuleHashes moduleHashes = hasher.computeHashes(descriptor.name());
 471                     if (moduleHashes != null) {
 472                         extender.hashes(moduleHashes);
 473                     } else {
 474                         warning("warn.no.module.hashes", descriptor.name());
 475                     }
 476                 }
 477 




 478                 // write the (possibly extended or modified) module-info.class
 479                 out.writeEntry(extender.toByteArray(), Section.CLASSES, MODULE_INFO);
 480             }
 481         }
 482 
 483         /*
 484          * Hasher resolves a module graph using the --hash-modules PATTERN
 485          * as the roots.
 486          *
 487          * The jmod file is being created and does not exist in the
 488          * given modulepath.
 489          */
 490         private Hasher hasher() {
 491             if (options.modulesToHash == null)
 492                 return null;
 493 
 494             try {
 495                 Supplier<InputStream> miSupplier = newModuleInfoSupplier();
 496                 if (miSupplier == null) {
 497                     throw new IOException(MODULE_INFO + " not found");
 498                 }
 499 
 500                 ModuleDescriptor descriptor;
 501                 try (InputStream in = miSupplier.get()) {
 502                     descriptor = ModuleDescriptor.read(in);
 503                 }
 504 
 505                 URI uri = options.jmodFile.toUri();
 506                 ModuleReference mref = new ModuleReference(descriptor, uri, new Supplier<>() {
 507                     @Override
 508                     public ModuleReader get() {
 509                         throw new UnsupportedOperationException();
 510                     }
 511                 });
 512 
 513                 // compose a module finder with the module path and also
 514                 // a module finder that can find the jmod file being created
 515                 ModuleFinder finder = ModuleFinder.compose(options.moduleFinder,
 516                     new ModuleFinder() {
 517                         @Override
 518                         public Optional<ModuleReference> find(String name) {
 519                             if (descriptor.name().equals(name))
 520                                 return Optional.of(mref);
 521                             else return Optional.empty();
 522                         }
 523 
 524                         @Override
 525                         public Set<ModuleReference> findAll() {
 526                             return Collections.singleton(mref);
 527                         }
 528                     });
 529 
 530                 return new Hasher(finder);
 531             } catch (IOException e) {


1063         @Override  public Class<Path> valueType() { return Path.class; }
1064 
1065         @Override  public String valuePattern() { return "path"; }
1066     }
1067 
1068     static class ModuleVersionConverter implements ValueConverter<Version> {
1069         @Override
1070         public Version convert(String value) {
1071             try {
1072                 return Version.parse(value);
1073             } catch (IllegalArgumentException x) {
1074                 throw new CommandException("err.invalid.version", x.getMessage());
1075             }
1076         }
1077 
1078         @Override public Class<Version> valueType() { return Version.class; }
1079 
1080         @Override public String valuePattern() { return "module-version"; }
1081     }
1082 






















1083     static class PatternConverter implements ValueConverter<Pattern> {
1084         @Override
1085         public Pattern convert(String value) {
1086             try {
1087                 if (value.startsWith("regex:")) {
1088                     value = value.substring("regex:".length()).trim();
1089                 }
1090 
1091                 return Pattern.compile(value);
1092             } catch (PatternSyntaxException e) {
1093                 throw new CommandException("err.bad.pattern", value);
1094             }
1095         }
1096 
1097         @Override public Class<Pattern> valueType() { return Pattern.class; }
1098 
1099         @Override public String valuePattern() { return "regex-pattern"; }
1100     }
1101 
1102     static class PathMatcherConverter implements ValueConverter<PathMatcher> {


1112         @Override public Class<PathMatcher> valueType() { return PathMatcher.class; }
1113 
1114         @Override public String valuePattern() { return "pattern-list"; }
1115     }
1116 
1117     /* Support for @<file> in jmod help */
1118     private static final String CMD_FILENAME = "@<filename>";
1119 
1120     /**
1121      * This formatter is adding the @filename option and does the required
1122      * formatting.
1123      */
1124     private static final class JmodHelpFormatter extends BuiltinHelpFormatter {
1125 
1126         private JmodHelpFormatter() { super(80, 2); }
1127 
1128         @Override
1129         public String format(Map<String, ? extends OptionDescriptor> options) {
1130             Map<String, OptionDescriptor> all = new HashMap<>();
1131             all.putAll(options);





1132             all.put(CMD_FILENAME, new OptionDescriptor() {
1133                 @Override
1134                 public Collection<String> options() {
1135                     List<String> ret = new ArrayList<>();
1136                     ret.add(CMD_FILENAME);
1137                     return ret;
1138                 }
1139                 @Override
1140                 public String description() { return getMessage("main.opt.cmdfile"); }
1141                 @Override
1142                 public List<?> defaultValues() { return Collections.emptyList(); }
1143                 @Override
1144                 public boolean isRequired() { return false; }
1145                 @Override
1146                 public boolean acceptsArguments() { return false; }
1147                 @Override
1148                 public boolean requiresArgument() { return false; }
1149                 @Override
1150                 public String argumentDescription() { return null; }
1151                 @Override


1253         OptionSpec<Version> moduleVersion
1254                 = parser.accepts("module-version", getMessage("main.opt.module-version"))
1255                         .withRequiredArg()
1256                         .withValuesConvertedBy(new ModuleVersionConverter());
1257 
1258         OptionSpec<String> osName
1259                 = parser.accepts("os-name", getMessage("main.opt.os-name"))
1260                         .withRequiredArg()
1261                         .describedAs(getMessage("main.opt.os-name.arg"));
1262 
1263         OptionSpec<String> osArch
1264                 = parser.accepts("os-arch", getMessage("main.opt.os-arch"))
1265                         .withRequiredArg()
1266                         .describedAs(getMessage("main.opt.os-arch.arg"));
1267 
1268         OptionSpec<String> osVersion
1269                 = parser.accepts("os-version", getMessage("main.opt.os-version"))
1270                         .withRequiredArg()
1271                         .describedAs(getMessage("main.opt.os-version.arg"));
1272 








1273         OptionSpec<Void> version
1274                 = parser.accepts("version", getMessage("main.opt.version"));
1275 
1276         NonOptionArgumentSpec<String> nonOptions
1277                 = parser.nonOptions();
1278 
1279         try {
1280             OptionSet opts = parser.parse(args);
1281 
1282             if (opts.has(help) || opts.has(version)) {
1283                 options = new Options();
1284                 options.help = opts.has(help);
1285                 options.version = opts.has(version);
1286                 return;  // informational message will be shown
1287             }
1288 
1289             List<String> words = opts.valuesOf(nonOptions);
1290             if (words.isEmpty())
1291                 throw new CommandException("err.missing.mode").showUsage(true);
1292             String verb = words.get(0);


1298             }
1299 
1300             if (opts.has(classPath))
1301                 options.classpath = opts.valuesOf(classPath);
1302             if (opts.has(cmds))
1303                 options.cmds = opts.valuesOf(cmds);
1304             if (opts.has(config))
1305                 options.configs = opts.valuesOf(config);
1306             if (opts.has(dryrun))
1307                 options.dryrun = true;
1308             if (opts.has(excludes))
1309                 options.excludes = opts.valuesOf(excludes);
1310             if (opts.has(libs))
1311                 options.libs = opts.valuesOf(libs);
1312             if (opts.has(headerFiles))
1313                 options.headerFiles = opts.valuesOf(headerFiles);
1314             if (opts.has(manPages))
1315                 options.manPages = opts.valuesOf(manPages);
1316             if (opts.has(modulePath)) {
1317                 Path[] dirs = opts.valuesOf(modulePath).toArray(new Path[0]);
1318                 options.moduleFinder = JLMA.newModulePath(Runtime.version(), true, dirs);
1319             }
1320             if (opts.has(moduleVersion))
1321                 options.moduleVersion = opts.valueOf(moduleVersion);
1322             if (opts.has(mainClass))
1323                 options.mainClass = opts.valueOf(mainClass);
1324             if (opts.has(osName))
1325                 options.osName = opts.valueOf(osName);
1326             if (opts.has(osArch))
1327                 options.osArch = opts.valueOf(osArch);
1328             if (opts.has(osVersion))
1329                 options.osVersion = opts.valueOf(osVersion);







1330             if (opts.has(hashModules)) {
1331                 options.modulesToHash = opts.valueOf(hashModules);
1332                 // if storing hashes then the module path is required
1333                 if (options.moduleFinder == null)
1334                     throw new CommandException("err.modulepath.must.be.specified")
1335                             .showUsage(true);
1336             }
1337 
1338             if (options.mode.equals(Mode.HASH)) {
1339                 if (options.moduleFinder == null || options.modulesToHash == null)
1340                     throw new CommandException("err.modulepath.must.be.specified")
1341                             .showUsage(true);
1342             } else {
1343                 if (words.size() <= 1)
1344                     throw new CommandException("err.jmod.must.be.specified").showUsage(true);
1345                 Path path = Paths.get(words.get(1));
1346 
1347                 if (options.mode.equals(Mode.CREATE) && Files.exists(path))
1348                     throw new CommandException("err.file.already.exists", path);
1349                 else if ((options.mode.equals(Mode.LIST) ||




  83 import java.util.jar.JarOutputStream;
  84 import java.util.stream.Collectors;
  85 import java.util.regex.Pattern;
  86 import java.util.regex.PatternSyntaxException;
  87 import java.util.stream.Stream;
  88 import java.util.zip.ZipEntry;
  89 import java.util.zip.ZipException;
  90 import java.util.zip.ZipFile;
  91 
  92 import jdk.internal.jmod.JmodFile;
  93 import jdk.internal.jmod.JmodFile.Section;
  94 import jdk.internal.joptsimple.BuiltinHelpFormatter;
  95 import jdk.internal.joptsimple.NonOptionArgumentSpec;
  96 import jdk.internal.joptsimple.OptionDescriptor;
  97 import jdk.internal.joptsimple.OptionException;
  98 import jdk.internal.joptsimple.OptionParser;
  99 import jdk.internal.joptsimple.OptionSet;
 100 import jdk.internal.joptsimple.OptionSpec;
 101 import jdk.internal.joptsimple.ValueConverter;
 102 import jdk.internal.loader.ResourceHelper;


 103 import jdk.internal.module.ModuleHashes;
 104 import jdk.internal.module.ModuleInfo;
 105 import jdk.internal.module.ModuleInfoExtender;
 106 import jdk.internal.module.ModulePath;
 107 import jdk.internal.module.ModuleResolution;
 108 import jdk.tools.jlink.internal.Utils;
 109 
 110 import static java.util.stream.Collectors.joining;
 111 
 112 /**
 113  * Implementation for the jmod tool.
 114  */
 115 public class JmodTask {
 116 
 117     static class CommandException extends RuntimeException {
 118         private static final long serialVersionUID = 0L;
 119         boolean showUsage;
 120 
 121         CommandException(String key, Object... args) {
 122             super(getMessageOrKey(key, args));
 123         }
 124 
 125         CommandException showUsage(boolean b) {
 126             showUsage = b;
 127             return this;


 160     };
 161 
 162     static class Options {
 163         Mode mode;
 164         Path jmodFile;
 165         boolean help;
 166         boolean version;
 167         List<Path> classpath;
 168         List<Path> cmds;
 169         List<Path> configs;
 170         List<Path> libs;
 171         List<Path> headerFiles;
 172         List<Path> manPages;
 173         ModuleFinder moduleFinder;
 174         Version moduleVersion;
 175         String mainClass;
 176         String osName;
 177         String osArch;
 178         String osVersion;
 179         Pattern modulesToHash;
 180         ModuleResolution moduleResolution;
 181         boolean dryrun;
 182         List<PathMatcher> excludes;
 183     }
 184 
 185     public int run(String[] args) {
 186 
 187         try {
 188             handleOptions(args);
 189             if (options == null) {
 190                 showUsageSummary();
 191                 return EXIT_CMDERR;
 192             }
 193             if (options.help) {
 194                 showHelp();
 195                 return EXIT_OK;
 196             }
 197             if (options.version) {
 198                 showVersion();
 199                 return EXIT_OK;
 200             }


 240             } catch (IOException x) {
 241                 throw new IOException("error opening jmod file", x);
 242             }
 243 
 244             // Trivially print the archive entries for now, pending a more complete implementation
 245             zip.stream().forEach(e -> out.println(e.getName()));
 246             return true;
 247         } finally {
 248             if (zip != null)
 249                 zip.close();
 250         }
 251     }
 252 
 253     private boolean hashModules() {
 254         return new Hasher(options.moduleFinder).run();
 255     }
 256 
 257     private boolean describe() throws IOException {
 258         try (JmodFile jf = new JmodFile(options.jmodFile)) {
 259             try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
 260                 ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
 261                 printModuleDescriptor(attrs.descriptor(), attrs.recordedHashes());
 262                 return true;
 263             } catch (IOException e) {
 264                 throw new CommandException("err.module.descriptor.not.found");
 265             }
 266         }
 267     }
 268 
 269     static <T> String toString(Collection<T> c) {
 270         if (c.isEmpty()) { return ""; }
 271         return c.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
 272                   .collect(joining(" "));
 273     }
 274 
 275     private void printModuleDescriptor(ModuleDescriptor md, ModuleHashes hashes)


 276         throws IOException
 277     {
 278         StringBuilder sb = new StringBuilder();
 279         sb.append("\n").append(md.toNameAndVersion());
 280 
 281         md.requires().stream()
 282             .sorted(Comparator.comparing(Requires::name))
 283             .forEach(r -> {
 284                 sb.append("\n  requires ");
 285                 if (!r.modifiers().isEmpty())
 286                     sb.append(toString(r.modifiers())).append(" ");
 287                 sb.append(r.name());
 288             });
 289 
 290         md.uses().stream().sorted()
 291             .forEach(s -> sb.append("\n  uses ").append(s));
 292 
 293         md.exports().stream()
 294             .sorted(Comparator.comparing(Exports::source))
 295             .forEach(p -> sb.append("\n  exports ").append(p));


 301         Set<String> concealed = new HashSet<>(md.packages());
 302         md.exports().stream().map(Exports::source).forEach(concealed::remove);
 303         md.opens().stream().map(Opens::source).forEach(concealed::remove);
 304         concealed.stream().sorted()
 305                  .forEach(p -> sb.append("\n  contains ").append(p));
 306 
 307         md.provides().stream()
 308             .sorted(Comparator.comparing(Provides::service))
 309             .forEach(p -> sb.append("\n  provides ").append(p.service())
 310                             .append(" with ")
 311                             .append(toString(p.providers())));
 312 
 313         md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
 314 
 315         md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
 316 
 317         md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
 318 
 319         md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 320 
 321         if (hashes != null) {
 322             hashes.names().stream().sorted().forEach(
 323                     mod -> sb.append("\n  hashes ").append(mod).append(" ")
 324                              .append(hashes.algorithm()).append(" ")
 325                              .append(toHex(hashes.hashFor(mod))));
 326         }
 327 
 328         out.println(sb.toString());
 329     }
 330 
 331     private String toHex(byte[] ba) {
 332         StringBuilder sb = new StringBuilder(ba.length);
 333         for (byte b: ba) {
 334             sb.append(String.format("%02x", b & 0xff));
 335         }
 336         return sb.toString();
 337     }
 338 
 339     private boolean create() throws IOException {
 340         JmodFileWriter jmod = new JmodFileWriter();
 341 
 342         // create jmod with temporary name to avoid it being examined
 343         // when scanning the module path
 344         Path target = options.jmodFile;
 345         Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
 346         try {
 347             try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) {
 348                 jmod.write(jos);
 349             }
 350             Files.move(tempTarget, target);
 351         } catch (Exception e) {
 352             if (Files.exists(tempTarget)) {
 353                 try {
 354                     Files.delete(tempTarget);
 355                 } catch (IOException ioe) {
 356                     e.addSuppressed(ioe);
 357                 }
 358             }
 359             throw e;
 360         }
 361         return true;
 362     }
 363 
 364     private class JmodFileWriter {
 365         final List<Path> cmds = options.cmds;
 366         final List<Path> libs = options.libs;
 367         final List<Path> configs = options.configs;
 368         final List<Path> classpath = options.classpath;
 369         final List<Path> headerFiles = options.headerFiles;
 370         final List<Path> manPages = options.manPages;
 371 
 372         final Version moduleVersion = options.moduleVersion;
 373         final String mainClass = options.mainClass;
 374         final String osName = options.osName;
 375         final String osArch = options.osArch;
 376         final String osVersion = options.osVersion;
 377         final List<PathMatcher> excludes = options.excludes;
 378         final Hasher hasher = hasher();
 379         final ModuleResolution moduleResolution = options.moduleResolution;
 380 
 381         JmodFileWriter() { }
 382 
 383         /**
 384          * Writes the jmod to the given output stream.
 385          */
 386         void write(JmodOutputStream out) throws IOException {
 387             // module-info.class
 388             writeModuleInfo(out, findPackages(classpath));
 389 
 390             // classes
 391             processClasses(out, classpath);
 392 
 393             processSection(out, Section.NATIVE_CMDS, cmds);
 394             processSection(out, Section.NATIVE_LIBS, libs);
 395             processSection(out, Section.CONFIG, configs);
 396             processSection(out, Section.HEADER_FILES, headerFiles);
 397             processSection(out, Section.MAN_PAGES, manPages);
 398 
 399         }


 468                 if (mainClass != null)
 469                     extender.mainClass(mainClass);
 470 
 471                 // --os-name, --os-arch, --os-version
 472                 if (osName != null || osArch != null || osVersion != null)
 473                     extender.targetPlatform(osName, osArch, osVersion);
 474 
 475                 // --module-version
 476                 if (moduleVersion != null)
 477                     extender.version(moduleVersion);
 478 
 479                 if (hasher != null) {
 480                     ModuleHashes moduleHashes = hasher.computeHashes(descriptor.name());
 481                     if (moduleHashes != null) {
 482                         extender.hashes(moduleHashes);
 483                     } else {
 484                         warning("warn.no.module.hashes", descriptor.name());
 485                     }
 486                 }
 487 
 488                 if (moduleResolution != null && moduleResolution.value() != 0) {
 489                     extender.moduleResolution(moduleResolution);
 490                 }
 491 
 492                 // write the (possibly extended or modified) module-info.class
 493                 out.writeEntry(extender.toByteArray(), Section.CLASSES, MODULE_INFO);
 494             }
 495         }
 496 
 497         /*
 498          * Hasher resolves a module graph using the --hash-modules PATTERN
 499          * as the roots.
 500          *
 501          * The jmod file is being created and does not exist in the
 502          * given modulepath.
 503          */
 504         private Hasher hasher() {
 505             if (options.modulesToHash == null)
 506                 return null;
 507 
 508             try {
 509                 Supplier<InputStream> miSupplier = newModuleInfoSupplier();
 510                 if (miSupplier == null) {
 511                     throw new IOException(MODULE_INFO + " not found");
 512                 }
 513 
 514                 ModuleDescriptor descriptor;
 515                 try (InputStream in = miSupplier.get()) {
 516                     descriptor = ModuleDescriptor.read(in);
 517                 }
 518 
 519                 URI uri = options.jmodFile.toUri();
 520                 ModuleReference mref = new ModuleReference(descriptor, uri) {
 521                     @Override
 522                     public ModuleReader open() {
 523                         throw new UnsupportedOperationException();
 524                     }
 525                 };
 526 
 527                 // compose a module finder with the module path and also
 528                 // a module finder that can find the jmod file being created
 529                 ModuleFinder finder = ModuleFinder.compose(options.moduleFinder,
 530                     new ModuleFinder() {
 531                         @Override
 532                         public Optional<ModuleReference> find(String name) {
 533                             if (descriptor.name().equals(name))
 534                                 return Optional.of(mref);
 535                             else return Optional.empty();
 536                         }
 537 
 538                         @Override
 539                         public Set<ModuleReference> findAll() {
 540                             return Collections.singleton(mref);
 541                         }
 542                     });
 543 
 544                 return new Hasher(finder);
 545             } catch (IOException e) {


1077         @Override  public Class<Path> valueType() { return Path.class; }
1078 
1079         @Override  public String valuePattern() { return "path"; }
1080     }
1081 
1082     static class ModuleVersionConverter implements ValueConverter<Version> {
1083         @Override
1084         public Version convert(String value) {
1085             try {
1086                 return Version.parse(value);
1087             } catch (IllegalArgumentException x) {
1088                 throw new CommandException("err.invalid.version", x.getMessage());
1089             }
1090         }
1091 
1092         @Override public Class<Version> valueType() { return Version.class; }
1093 
1094         @Override public String valuePattern() { return "module-version"; }
1095     }
1096 
1097     static class WarnIfResolvedReasonConverter
1098         implements ValueConverter<ModuleResolution>
1099     {
1100         @Override
1101         public ModuleResolution convert(String value) {
1102             if (value.equals("deprecated"))
1103                 return (new ModuleResolution(0)).withDeprecated();
1104             else if (value.equals("deprecated-for-removal"))
1105                 return (new ModuleResolution(0)).withDeprecatedForRemoval();
1106             else if (value.equals("incubating"))
1107                 return (new ModuleResolution(0)).withIncubating();
1108             else
1109                 throw new CommandException("err.bad.WarnIfResolvedReason", value);
1110         }
1111 
1112         @Override public Class<ModuleResolution> valueType() {
1113             return ModuleResolution.class;
1114         }
1115 
1116         @Override public String valuePattern() { return "reason"; }
1117     }
1118 
1119     static class PatternConverter implements ValueConverter<Pattern> {
1120         @Override
1121         public Pattern convert(String value) {
1122             try {
1123                 if (value.startsWith("regex:")) {
1124                     value = value.substring("regex:".length()).trim();
1125                 }
1126 
1127                 return Pattern.compile(value);
1128             } catch (PatternSyntaxException e) {
1129                 throw new CommandException("err.bad.pattern", value);
1130             }
1131         }
1132 
1133         @Override public Class<Pattern> valueType() { return Pattern.class; }
1134 
1135         @Override public String valuePattern() { return "regex-pattern"; }
1136     }
1137 
1138     static class PathMatcherConverter implements ValueConverter<PathMatcher> {


1148         @Override public Class<PathMatcher> valueType() { return PathMatcher.class; }
1149 
1150         @Override public String valuePattern() { return "pattern-list"; }
1151     }
1152 
1153     /* Support for @<file> in jmod help */
1154     private static final String CMD_FILENAME = "@<filename>";
1155 
1156     /**
1157      * This formatter is adding the @filename option and does the required
1158      * formatting.
1159      */
1160     private static final class JmodHelpFormatter extends BuiltinHelpFormatter {
1161 
1162         private JmodHelpFormatter() { super(80, 2); }
1163 
1164         @Override
1165         public String format(Map<String, ? extends OptionDescriptor> options) {
1166             Map<String, OptionDescriptor> all = new HashMap<>();
1167             all.putAll(options);
1168 
1169             // hidden options
1170             all.remove("do-not-resolve-by-default");
1171             all.remove("warn-if-resolved");
1172 
1173             all.put(CMD_FILENAME, new OptionDescriptor() {
1174                 @Override
1175                 public Collection<String> options() {
1176                     List<String> ret = new ArrayList<>();
1177                     ret.add(CMD_FILENAME);
1178                     return ret;
1179                 }
1180                 @Override
1181                 public String description() { return getMessage("main.opt.cmdfile"); }
1182                 @Override
1183                 public List<?> defaultValues() { return Collections.emptyList(); }
1184                 @Override
1185                 public boolean isRequired() { return false; }
1186                 @Override
1187                 public boolean acceptsArguments() { return false; }
1188                 @Override
1189                 public boolean requiresArgument() { return false; }
1190                 @Override
1191                 public String argumentDescription() { return null; }
1192                 @Override


1294         OptionSpec<Version> moduleVersion
1295                 = parser.accepts("module-version", getMessage("main.opt.module-version"))
1296                         .withRequiredArg()
1297                         .withValuesConvertedBy(new ModuleVersionConverter());
1298 
1299         OptionSpec<String> osName
1300                 = parser.accepts("os-name", getMessage("main.opt.os-name"))
1301                         .withRequiredArg()
1302                         .describedAs(getMessage("main.opt.os-name.arg"));
1303 
1304         OptionSpec<String> osArch
1305                 = parser.accepts("os-arch", getMessage("main.opt.os-arch"))
1306                         .withRequiredArg()
1307                         .describedAs(getMessage("main.opt.os-arch.arg"));
1308 
1309         OptionSpec<String> osVersion
1310                 = parser.accepts("os-version", getMessage("main.opt.os-version"))
1311                         .withRequiredArg()
1312                         .describedAs(getMessage("main.opt.os-version.arg"));
1313 
1314         OptionSpec<Void> doNotResolveByDefault
1315                 = parser.accepts("do-not-resolve-by-default");
1316 
1317         OptionSpec<ModuleResolution> warnIfResolved
1318                 = parser.accepts("warn-if-resolved")
1319                         .withRequiredArg()
1320                         .withValuesConvertedBy(new WarnIfResolvedReasonConverter());
1321 
1322         OptionSpec<Void> version
1323                 = parser.accepts("version", getMessage("main.opt.version"));
1324 
1325         NonOptionArgumentSpec<String> nonOptions
1326                 = parser.nonOptions();
1327 
1328         try {
1329             OptionSet opts = parser.parse(args);
1330 
1331             if (opts.has(help) || opts.has(version)) {
1332                 options = new Options();
1333                 options.help = opts.has(help);
1334                 options.version = opts.has(version);
1335                 return;  // informational message will be shown
1336             }
1337 
1338             List<String> words = opts.valuesOf(nonOptions);
1339             if (words.isEmpty())
1340                 throw new CommandException("err.missing.mode").showUsage(true);
1341             String verb = words.get(0);


1347             }
1348 
1349             if (opts.has(classPath))
1350                 options.classpath = opts.valuesOf(classPath);
1351             if (opts.has(cmds))
1352                 options.cmds = opts.valuesOf(cmds);
1353             if (opts.has(config))
1354                 options.configs = opts.valuesOf(config);
1355             if (opts.has(dryrun))
1356                 options.dryrun = true;
1357             if (opts.has(excludes))
1358                 options.excludes = opts.valuesOf(excludes);
1359             if (opts.has(libs))
1360                 options.libs = opts.valuesOf(libs);
1361             if (opts.has(headerFiles))
1362                 options.headerFiles = opts.valuesOf(headerFiles);
1363             if (opts.has(manPages))
1364                 options.manPages = opts.valuesOf(manPages);
1365             if (opts.has(modulePath)) {
1366                 Path[] dirs = opts.valuesOf(modulePath).toArray(new Path[0]);
1367                 options.moduleFinder = new ModulePath(Runtime.version(), true, dirs);
1368             }
1369             if (opts.has(moduleVersion))
1370                 options.moduleVersion = opts.valueOf(moduleVersion);
1371             if (opts.has(mainClass))
1372                 options.mainClass = opts.valueOf(mainClass);
1373             if (opts.has(osName))
1374                 options.osName = opts.valueOf(osName);
1375             if (opts.has(osArch))
1376                 options.osArch = opts.valueOf(osArch);
1377             if (opts.has(osVersion))
1378                 options.osVersion = opts.valueOf(osVersion);
1379             if (opts.has(warnIfResolved))
1380                 options.moduleResolution = opts.valueOf(warnIfResolved);
1381             if (opts.has(doNotResolveByDefault)) {
1382                 if (options.moduleResolution == null)
1383                     options.moduleResolution = new ModuleResolution(0);
1384                 options.moduleResolution = options.moduleResolution.withDoNotResolveByDefault();
1385             }
1386             if (opts.has(hashModules)) {
1387                 options.modulesToHash = opts.valueOf(hashModules);
1388                 // if storing hashes then the module path is required
1389                 if (options.moduleFinder == null)
1390                     throw new CommandException("err.modulepath.must.be.specified")
1391                             .showUsage(true);
1392             }
1393 
1394             if (options.mode.equals(Mode.HASH)) {
1395                 if (options.moduleFinder == null || options.modulesToHash == null)
1396                     throw new CommandException("err.modulepath.must.be.specified")
1397                             .showUsage(true);
1398             } else {
1399                 if (words.size() <= 1)
1400                     throw new CommandException("err.jmod.must.be.specified").showUsage(true);
1401                 Path path = Paths.get(words.get(1));
1402 
1403                 if (options.mode.equals(Mode.CREATE) && Files.exists(path))
1404                     throw new CommandException("err.file.already.exists", path);
1405                 else if ((options.mode.equals(Mode.LIST) ||


< prev index next >