23 * questions.
24 */
25 package jdk.tools.jlink.internal;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.PrintWriter;
30 import java.io.UncheckedIOException;
31 import java.lang.module.Configuration;
32 import java.lang.module.ModuleDescriptor;
33 import java.lang.module.ModuleFinder;
34 import java.lang.module.ModuleReference;
35 import java.lang.module.ResolutionException;
36 import java.lang.module.ResolvedModule;
37 import java.net.URI;
38 import java.nio.ByteOrder;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.nio.file.Paths;
42 import java.util.*;
43 import java.util.stream.Collectors;
44 import java.util.stream.Stream;
45
46 import jdk.tools.jlink.internal.TaskHelper.BadArgs;
47 import static jdk.tools.jlink.internal.TaskHelper.JLINK_BUNDLE;
48 import jdk.tools.jlink.internal.Jlink.JlinkConfiguration;
49 import jdk.tools.jlink.internal.Jlink.PluginsConfiguration;
50 import jdk.tools.jlink.internal.TaskHelper.Option;
51 import jdk.tools.jlink.internal.TaskHelper.OptionsHelper;
52 import jdk.tools.jlink.internal.ImagePluginStack.ImageProvider;
53 import jdk.tools.jlink.plugin.PluginException;
54 import jdk.tools.jlink.builder.DefaultImageBuilder;
55 import jdk.tools.jlink.plugin.Plugin;
56 import jdk.internal.misc.SharedSecrets;
57
58 /**
59 * Implementation for the jlink tool.
60 *
61 * ## Should use jdk.joptsimple some day.
62 */
63 public class JlinkTask {
64 static final boolean DEBUG = Boolean.getBoolean("jlink.debug");
65
66 // jlink API ignores by default. Remove when signing is implemented.
67 static final boolean IGNORE_SIGNING_DEFAULT = true;
68
69 private static final TaskHelper taskHelper
70 = new TaskHelper(JLINK_BUNDLE);
71
72 private static final Option<?>[] recognizedOptions = {
73 new Option<JlinkTask>(false, (task, opt, arg) -> {
74 task.options.help = true;
75 }, "--help", "-h"),
76 new Option<JlinkTask>(true, (task, opt, arg) -> {
243 plugins = plugins == null ? new PluginsConfiguration() : plugins;
244
245 if (config.getModulepaths().isEmpty()) {
246 throw new IllegalArgumentException("Empty module paths");
247 }
248
249 ModuleFinder finder = newModuleFinder(config.getModulepaths(),
250 config.getLimitmods(),
251 config.getModules());
252
253 if (config.getModules().isEmpty()) {
254 throw new IllegalArgumentException("No modules to add");
255 }
256
257 // First create the image provider
258 ImageProvider imageProvider =
259 createImageProvider(finder,
260 config.getModules(),
261 config.getByteOrder(),
262 null,
263 IGNORE_SIGNING_DEFAULT);
264
265 // Then create the Plugin Stack
266 ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins);
267
268 //Ask the stack to proceed;
269 stack.operate(imageProvider);
270 }
271
272 /*
273 * Jlink API entry point.
274 */
275 public static void postProcessImage(ExecutableImage image, List<Plugin> postProcessorPlugins)
276 throws Exception {
277 Objects.requireNonNull(image);
278 Objects.requireNonNull(postProcessorPlugins);
279 PluginsConfiguration config = new PluginsConfiguration(postProcessorPlugins);
280 ImagePluginStack stack = ImagePluginConfiguration.
281 parseConfiguration(config);
282
283 stack.operate((ImagePluginStack stack1) -> image);
311 finder.findAll()
312 .stream()
313 .map(ModuleReference::descriptor)
314 .map(ModuleDescriptor::name)
315 .forEach(mn -> roots.add(mn));
316 } else {
317 roots.add(mod);
318 }
319 }
320
321 ModuleFinder finder = newModuleFinder(options.modulePath,
322 options.limitMods,
323 roots);
324
325
326 // First create the image provider
327 ImageProvider imageProvider = createImageProvider(finder,
328 roots,
329 options.endian,
330 options.packagedModulesPath,
331 options.ignoreSigning);
332
333 // Then create the Plugin Stack
334 ImagePluginStack stack = ImagePluginConfiguration.
335 parseConfiguration(taskHelper.getPluginsConfig(options.output));
336
337 //Ask the stack to proceed
338 stack.operate(imageProvider);
339 }
340
341 /**
342 * Returns a module finder to find the observable modules specified in
343 * the --module-path and --limit-modules options
344 */
345 private ModuleFinder modulePathFinder() {
346 Path[] entries = options.modulePath.toArray(new Path[0]);
347 ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
348 .newModulePath(Runtime.version(), true, entries);
349
350 if (!options.limitMods.isEmpty()) {
351 finder = limitFinder(finder, options.limitMods, Collections.emptySet());
365 {
366 Path[] entries = paths.toArray(new Path[0]);
367 ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
368 .newModulePath(Runtime.version(), true, entries);
369
370 // if limitmods is specified then limit the universe
371 if (!limitMods.isEmpty()) {
372 finder = limitFinder(finder, limitMods, roots);
373 }
374 return finder;
375 }
376
377 private static Path toPathLocation(ResolvedModule m) {
378 Optional<URI> ouri = m.reference().location();
379 if (!ouri.isPresent())
380 throw new InternalError(m + " does not have a location");
381 URI uri = ouri.get();
382 return Paths.get(uri);
383 }
384
385 private static ImageProvider createImageProvider(ModuleFinder finder,
386 Set<String> roots,
387 ByteOrder order,
388 Path retainModulesPath,
389 boolean ignoreSigning)
390 throws IOException
391 {
392 if (roots.isEmpty()) {
393 throw new IllegalArgumentException("empty modules and limitmods");
394 }
395
396 Configuration cf = Configuration.empty()
397 .resolveRequires(finder,
398 ModuleFinder.of(),
399 roots);
400
401 Map<String, Path> mods = cf.modules().stream()
402 .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
403 return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
404 }
405
406 /*
407 * Returns a ModuleFinder that limits observability to the given root
408 * modules, their transitive dependences, plus a set of other modules.
409 */
410 private static ModuleFinder limitFinder(ModuleFinder finder,
411 Set<String> roots,
412 Set<String> otherMods) {
413
414 // resolve all root modules
415 Configuration cf = Configuration.empty()
416 .resolveRequires(finder,
417 ModuleFinder.of(),
418 roots);
419
|
23 * questions.
24 */
25 package jdk.tools.jlink.internal;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.PrintWriter;
30 import java.io.UncheckedIOException;
31 import java.lang.module.Configuration;
32 import java.lang.module.ModuleDescriptor;
33 import java.lang.module.ModuleFinder;
34 import java.lang.module.ModuleReference;
35 import java.lang.module.ResolutionException;
36 import java.lang.module.ResolvedModule;
37 import java.net.URI;
38 import java.nio.ByteOrder;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.nio.file.Paths;
42 import java.util.*;
43 import java.util.function.Predicate;
44 import java.util.stream.Collectors;
45 import java.util.stream.Stream;
46
47 import jdk.tools.jlink.internal.TaskHelper.BadArgs;
48 import static jdk.tools.jlink.internal.TaskHelper.JLINK_BUNDLE;
49 import jdk.tools.jlink.internal.Jlink.JlinkConfiguration;
50 import jdk.tools.jlink.internal.Jlink.PluginsConfiguration;
51 import jdk.tools.jlink.internal.TaskHelper.Option;
52 import jdk.tools.jlink.internal.TaskHelper.OptionsHelper;
53 import jdk.tools.jlink.internal.ImagePluginStack.ImageProvider;
54 import jdk.tools.jlink.plugin.PluginException;
55 import jdk.tools.jlink.builder.DefaultImageBuilder;
56 import jdk.tools.jlink.plugin.Plugin;
57 import jdk.internal.misc.SharedSecrets;
58 import jdk.internal.module.WarnIfResolvedReason;
59
60 /**
61 * Implementation for the jlink tool.
62 *
63 * ## Should use jdk.joptsimple some day.
64 */
65 public class JlinkTask {
66 static final boolean DEBUG = Boolean.getBoolean("jlink.debug");
67
68 // jlink API ignores by default. Remove when signing is implemented.
69 static final boolean IGNORE_SIGNING_DEFAULT = true;
70
71 private static final TaskHelper taskHelper
72 = new TaskHelper(JLINK_BUNDLE);
73
74 private static final Option<?>[] recognizedOptions = {
75 new Option<JlinkTask>(false, (task, opt, arg) -> {
76 task.options.help = true;
77 }, "--help", "-h"),
78 new Option<JlinkTask>(true, (task, opt, arg) -> {
245 plugins = plugins == null ? new PluginsConfiguration() : plugins;
246
247 if (config.getModulepaths().isEmpty()) {
248 throw new IllegalArgumentException("Empty module paths");
249 }
250
251 ModuleFinder finder = newModuleFinder(config.getModulepaths(),
252 config.getLimitmods(),
253 config.getModules());
254
255 if (config.getModules().isEmpty()) {
256 throw new IllegalArgumentException("No modules to add");
257 }
258
259 // First create the image provider
260 ImageProvider imageProvider =
261 createImageProvider(finder,
262 config.getModules(),
263 config.getByteOrder(),
264 null,
265 IGNORE_SIGNING_DEFAULT,
266 null);
267
268 // Then create the Plugin Stack
269 ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins);
270
271 //Ask the stack to proceed;
272 stack.operate(imageProvider);
273 }
274
275 /*
276 * Jlink API entry point.
277 */
278 public static void postProcessImage(ExecutableImage image, List<Plugin> postProcessorPlugins)
279 throws Exception {
280 Objects.requireNonNull(image);
281 Objects.requireNonNull(postProcessorPlugins);
282 PluginsConfiguration config = new PluginsConfiguration(postProcessorPlugins);
283 ImagePluginStack stack = ImagePluginConfiguration.
284 parseConfiguration(config);
285
286 stack.operate((ImagePluginStack stack1) -> image);
314 finder.findAll()
315 .stream()
316 .map(ModuleReference::descriptor)
317 .map(ModuleDescriptor::name)
318 .forEach(mn -> roots.add(mn));
319 } else {
320 roots.add(mod);
321 }
322 }
323
324 ModuleFinder finder = newModuleFinder(options.modulePath,
325 options.limitMods,
326 roots);
327
328
329 // First create the image provider
330 ImageProvider imageProvider = createImageProvider(finder,
331 roots,
332 options.endian,
333 options.packagedModulesPath,
334 options.ignoreSigning,
335 log);
336
337 // Then create the Plugin Stack
338 ImagePluginStack stack = ImagePluginConfiguration.
339 parseConfiguration(taskHelper.getPluginsConfig(options.output));
340
341 //Ask the stack to proceed
342 stack.operate(imageProvider);
343 }
344
345 /**
346 * Returns a module finder to find the observable modules specified in
347 * the --module-path and --limit-modules options
348 */
349 private ModuleFinder modulePathFinder() {
350 Path[] entries = options.modulePath.toArray(new Path[0]);
351 ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
352 .newModulePath(Runtime.version(), true, entries);
353
354 if (!options.limitMods.isEmpty()) {
355 finder = limitFinder(finder, options.limitMods, Collections.emptySet());
369 {
370 Path[] entries = paths.toArray(new Path[0]);
371 ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
372 .newModulePath(Runtime.version(), true, entries);
373
374 // if limitmods is specified then limit the universe
375 if (!limitMods.isEmpty()) {
376 finder = limitFinder(finder, limitMods, roots);
377 }
378 return finder;
379 }
380
381 private static Path toPathLocation(ResolvedModule m) {
382 Optional<URI> ouri = m.reference().location();
383 if (!ouri.isPresent())
384 throw new InternalError(m + " does not have a location");
385 URI uri = ouri.get();
386 return Paths.get(uri);
387 }
388
389 private static final Predicate<ModuleDescriptor> hasIncubatorWarning = md ->
390 SharedSecrets.getJavaLangModuleAccess().warnIfResolvedReason(md)
391 == WarnIfResolvedReason.INCUBATING;
392
393 private static ImageProvider createImageProvider(ModuleFinder finder,
394 Set<String> roots,
395 ByteOrder order,
396 Path retainModulesPath,
397 boolean ignoreSigning,
398 PrintWriter log)
399 throws IOException
400 {
401 if (roots.isEmpty()) {
402 throw new IllegalArgumentException("empty modules and limitmods");
403 }
404
405 Configuration cf = Configuration.empty()
406 .resolveRequires(finder,
407 ModuleFinder.of(),
408 roots);
409
410 // issue a warning for any incubating modules in the configuration
411 if (log != null) {
412 String incubatingModules = cf.modules()
413 .stream()
414 .map(ResolvedModule::reference)
415 .map(ModuleReference::descriptor)
416 .filter(hasIncubatorWarning)
417 .map(ModuleDescriptor::name)
418 .collect(Collectors.joining(", "));
419
420 if (!"".equals(incubatingModules))
421 log.println("WARNING: using incubating module(s): " + incubatingModules);
422 }
423
424 Map<String, Path> mods = cf.modules().stream()
425 .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
426 return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
427 }
428
429 /*
430 * Returns a ModuleFinder that limits observability to the given root
431 * modules, their transitive dependences, plus a set of other modules.
432 */
433 private static ModuleFinder limitFinder(ModuleFinder finder,
434 Set<String> roots,
435 Set<String> otherMods) {
436
437 // resolve all root modules
438 Configuration cf = Configuration.empty()
439 .resolveRequires(finder,
440 ModuleFinder.of(),
441 roots);
442
|