192 } |
210 } |
193 |
211 |
194 public JPackageCommand setFakeRuntime() { |
212 public JPackageCommand setFakeRuntime() { |
195 verifyMutable(); |
213 verifyMutable(); |
196 |
214 |
197 try { |
215 ThrowingConsumer<Path> createBulkFile = path -> { |
|
216 Files.createDirectories(path.getParent()); |
|
217 try (FileOutputStream out = new FileOutputStream(path.toFile())) { |
|
218 byte[] bytes = new byte[4 * 1024]; |
|
219 new SecureRandom().nextBytes(bytes); |
|
220 out.write(bytes); |
|
221 } |
|
222 }; |
|
223 |
|
224 addAction(cmd -> { |
198 Path fakeRuntimeDir = TKit.workDir().resolve("fake_runtime"); |
225 Path fakeRuntimeDir = TKit.workDir().resolve("fake_runtime"); |
|
226 |
|
227 TKit.trace(String.format("Init fake runtime in [%s] directory", |
|
228 fakeRuntimeDir)); |
|
229 |
199 Files.createDirectories(fakeRuntimeDir); |
230 Files.createDirectories(fakeRuntimeDir); |
200 |
231 |
201 if (TKit.isWindows() || TKit.isLinux()) { |
232 if (TKit.isWindows() || TKit.isLinux()) { |
202 // Needed to make WindowsAppBundler happy as it copies MSVC dlls |
233 // Needed to make WindowsAppBundler happy as it copies MSVC dlls |
203 // from `bin` directory. |
234 // from `bin` directory. |
204 // Need to make the code in rpm spec happy as it assumes there is |
235 // Need to make the code in rpm spec happy as it assumes there is |
205 // always something in application image. |
236 // always something in application image. |
206 fakeRuntimeDir.resolve("bin").toFile().mkdir(); |
237 fakeRuntimeDir.resolve("bin").toFile().mkdir(); |
207 } |
238 } |
208 |
239 |
209 Path bulk = fakeRuntimeDir.resolve(Path.of("bin", "bulk")); |
240 if (TKit.isOSX()) { |
|
241 // Make MacAppImageBuilder happy |
|
242 createBulkFile.accept(fakeRuntimeDir.resolve(Path.of( |
|
243 "Contents/Home/lib/jli/libjli.dylib"))); |
|
244 } |
210 |
245 |
211 // Mak sure fake runtime takes some disk space. |
246 // Mak sure fake runtime takes some disk space. |
212 // Package bundles with 0KB size are unexpected and considered |
247 // Package bundles with 0KB size are unexpected and considered |
213 // an error by PackageTest. |
248 // an error by PackageTest. |
214 Files.createDirectories(bulk.getParent()); |
249 createBulkFile.accept(fakeRuntimeDir.resolve(Path.of("bin", "bulk"))); |
215 try (FileOutputStream out = new FileOutputStream(bulk.toFile())) { |
250 |
216 byte[] bytes = new byte[4 * 1024]; |
251 cmd.addArguments("--runtime-image", fakeRuntimeDir); |
217 new SecureRandom().nextBytes(bytes); |
252 }); |
218 out.write(bytes); |
|
219 } |
|
220 |
|
221 addArguments("--runtime-image", fakeRuntimeDir); |
|
222 } catch (IOException ex) { |
|
223 throw new RuntimeException(ex); |
|
224 } |
|
225 |
253 |
226 return this; |
254 return this; |
227 } |
255 } |
228 |
256 |
229 JPackageCommand addAction(ThrowingConsumer<JPackageCommand> action) { |
257 JPackageCommand addAction(ThrowingConsumer<JPackageCommand> action) { |
230 verifyMutable(); |
258 verifyMutable(); |
231 actions.add(ThrowingConsumer.toConsumer(action)); |
259 actions.add(ThrowingConsumer.toConsumer(action)); |
232 return this; |
260 return this; |
233 } |
261 } |
234 |
262 |
|
263 /** |
|
264 * Shorthand for {@code helloAppImage(null)}. |
|
265 */ |
235 public static JPackageCommand helloAppImage() { |
266 public static JPackageCommand helloAppImage() { |
236 return helloAppImage(null); |
267 JavaAppDesc javaAppDesc = null; |
|
268 return helloAppImage(javaAppDesc); |
237 } |
269 } |
238 |
270 |
239 /** |
271 /** |
240 * Creates new JPackageCommand instance configured with the test Java app. |
272 * Creates new JPackageCommand instance configured with the test Java app. |
241 * For the explanation of `javaAppDesc` parameter, see documentation for |
273 * For the explanation of `javaAppDesc` parameter, see documentation for |
242 * HelloApp.addTo() method. |
274 * #JavaAppDesc.parse() method. |
243 * |
275 * |
244 * @param javaAppDesc Java application description |
276 * @param javaAppDesc Java application description |
245 * @return this |
277 * @return this |
246 */ |
278 */ |
247 public static JPackageCommand helloAppImage(String javaAppDesc) { |
279 public static JPackageCommand helloAppImage(String javaAppDesc) { |
|
280 final JavaAppDesc appDesc; |
|
281 if (javaAppDesc == null) { |
|
282 appDesc = null; |
|
283 } else { |
|
284 appDesc = JavaAppDesc.parse(javaAppDesc); |
|
285 } |
|
286 return helloAppImage(appDesc); |
|
287 } |
|
288 |
|
289 public static JPackageCommand helloAppImage(JavaAppDesc javaAppDesc) { |
248 JPackageCommand cmd = new JPackageCommand(); |
290 JPackageCommand cmd = new JPackageCommand(); |
249 cmd.setDefaultInputOutput().setDefaultAppName(); |
291 cmd.setDefaultInputOutput().setDefaultAppName(); |
250 PackageType.IMAGE.applyTo(cmd); |
292 PackageType.IMAGE.applyTo(cmd); |
251 HelloApp.addTo(cmd, javaAppDesc); |
293 new HelloApp(javaAppDesc).addTo(cmd); |
252 return cmd; |
294 return cmd; |
253 } |
295 } |
254 |
296 |
255 public JPackageCommand setPackageType(PackageType type) { |
297 public JPackageCommand setPackageType(PackageType type) { |
256 verifyMutable(); |
298 verifyMutable(); |
260 |
302 |
261 JPackageCommand setDefaultAppName() { |
303 JPackageCommand setDefaultAppName() { |
262 return addArguments("--name", TKit.getCurrentDefaultAppName()); |
304 return addArguments("--name", TKit.getCurrentDefaultAppName()); |
263 } |
305 } |
264 |
306 |
|
307 /** |
|
308 * Returns path to output bundle of configured jpackage command. |
|
309 * |
|
310 * If this is build image command, returns path to application image directory. |
|
311 */ |
265 public Path outputBundle() { |
312 public Path outputBundle() { |
266 final PackageType type = packageType(); |
313 final String bundleName; |
267 if (PackageType.IMAGE == type) { |
314 if (isImagePackageType()) { |
268 return null; |
315 String dirName = name(); |
269 } |
316 if (TKit.isOSX()) { |
270 |
317 dirName = dirName + ".app"; |
271 String bundleName = null; |
318 } |
272 if (PackageType.LINUX.contains(type)) { |
319 bundleName = dirName; |
|
320 } else if (TKit.isLinux()) { |
273 bundleName = LinuxHelper.getBundleName(this); |
321 bundleName = LinuxHelper.getBundleName(this); |
274 } else if (PackageType.WINDOWS.contains(type)) { |
322 } else if (TKit.isWindows()) { |
275 bundleName = WindowsHelper.getBundleName(this); |
323 bundleName = WindowsHelper.getBundleName(this); |
276 } else if (PackageType.MAC.contains(type)) { |
324 } else if (TKit.isOSX()) { |
277 bundleName = MacHelper.getBundleName(this); |
325 bundleName = MacHelper.getBundleName(this); |
|
326 } else { |
|
327 throw TKit.throwUnknownPlatformError(); |
278 } |
328 } |
279 |
329 |
280 return outputDir().resolve(bundleName); |
330 return outputDir().resolve(bundleName); |
281 } |
331 } |
282 |
332 |
283 /** |
333 /** |
284 * Returns path to directory where application will be installed. |
334 * Returns application layout. |
|
335 * |
|
336 * If this is build image command, returns application image layout of the |
|
337 * output bundle relative to output directory. Otherwise returns layout of |
|
338 * installed application relative to the root directory. |
|
339 * |
|
340 * If this command builds Java runtime, not an application, returns |
|
341 * corresponding layout. |
|
342 */ |
|
343 public ApplicationLayout appLayout() { |
|
344 final ApplicationLayout layout; |
|
345 if (isRuntime()) { |
|
346 layout = ApplicationLayout.javaRuntime(); |
|
347 } else { |
|
348 layout = ApplicationLayout.platformAppImage(); |
|
349 } |
|
350 |
|
351 if (isImagePackageType()) { |
|
352 return layout.resolveAt(outputBundle()); |
|
353 } |
|
354 |
|
355 return layout.resolveAt(appInstallationDirectory()); |
|
356 } |
|
357 |
|
358 /** |
|
359 * Returns path to directory where application will be installed or null if |
|
360 * this is build image command. |
285 * |
361 * |
286 * E.g. on Linux for app named Foo default the function will return |
362 * E.g. on Linux for app named Foo default the function will return |
287 * `/opt/foo` |
363 * `/opt/foo` |
288 */ |
364 */ |
289 public Path appInstallationDirectory() { |
365 public Path appInstallationDirectory() { |
290 final PackageType type = packageType(); |
366 if (isImagePackageType()) { |
291 if (PackageType.IMAGE == type) { |
|
292 return null; |
367 return null; |
293 } |
368 } |
294 |
369 |
295 if (PackageType.LINUX.contains(type)) { |
370 if (TKit.isLinux()) { |
296 if (isRuntime()) { |
371 if (isRuntime()) { |
297 // Not fancy, but OK. |
372 // Not fancy, but OK. |
298 return Path.of(getArgumentValue("--install-dir", () -> "/opt"), |
373 return Path.of(getArgumentValue("--install-dir", () -> "/opt"), |
299 LinuxHelper.getPackageName(this)); |
374 LinuxHelper.getPackageName(this)); |
300 } |
375 } |
301 |
376 |
302 // Launcher is in "bin" subfolder of the installation directory. |
377 // Launcher is in "bin" subfolder of the installation directory. |
303 return launcherInstallationPath().getParent().getParent(); |
378 return appLauncherPath().getParent().getParent(); |
304 } |
379 } |
305 |
380 |
306 if (PackageType.WINDOWS.contains(type)) { |
381 if (TKit.isWindows()) { |
307 return WindowsHelper.getInstallationDirectory(this); |
382 return WindowsHelper.getInstallationDirectory(this); |
308 } |
383 } |
309 |
384 |
310 if (PackageType.MAC.contains(type)) { |
385 if (TKit.isOSX()) { |
311 return MacHelper.getInstallationDirectory(this); |
386 return MacHelper.getInstallationDirectory(this); |
312 } |
387 } |
313 |
388 |
314 throw throwUnexpectedPackageTypeError(); |
389 throw TKit.throwUnknownPlatformError(); |
315 } |
390 } |
316 |
391 |
317 /** |
392 /** |
318 * Returns path where application's Java runtime will be installed. |
393 * Returns path to application's Java runtime. |
319 * If the command will package Java run-time only, still returns path to |
394 * If the command will package Java runtime only, returns correct path to |
320 * runtime subdirectory. |
395 * runtime directory. |
321 * |
396 * |
322 * E.g. on Linux for app named `Foo` the function will return |
397 * E.g.: |
323 * `/opt/foo/runtime` |
398 * [jpackage --name Foo --package-type rpm] -> `/opt/foo/lib/runtime` |
324 */ |
399 * [jpackage --name Foo --package-type app-image --dest bar] -> `bar/Foo/lib/runtime` |
325 public Path appRuntimeInstallationDirectory() { |
400 * [jpackage --name Foo --package-type rpm --runtime-image java] -> `/opt/foo` |
326 if (PackageType.IMAGE == packageType()) { |
401 */ |
327 return null; |
402 public Path appRuntimeDirectory() { |
328 } |
403 return appLayout().runtimeDirectory(); |
329 return appInstallationDirectory().resolve(appRuntimePath(packageType())); |
404 } |
330 } |
405 |
331 |
406 /** |
332 /** |
407 * Returns path for application launcher with the given name. |
333 * Returns path where application launcher will be installed. |
408 * |
334 * If the command will package Java run-time only, still returns path to |
409 * E.g.: [jpackage --name Foo --package-type rpm] -> `/opt/foo/bin/Foo` |
335 * application launcher. |
410 * [jpackage --name Foo --package-type app-image --dest bar] -> |
336 * |
411 * `bar/Foo/bin/Foo` |
337 * E.g. on Linux for app named Foo default the function will return |
412 * |
338 * `/opt/foo/bin/Foo` |
413 * @param launcherName name of launcher or {@code null} for the main |
339 */ |
414 * launcher |
340 public Path launcherInstallationPath() { |
415 * |
341 final PackageType type = packageType(); |
416 * @throws IllegalArgumentException if the command is configured for |
342 if (PackageType.IMAGE == type) { |
417 * packaging Java runtime |
343 return null; |
418 */ |
344 } |
419 public Path appLauncherPath(String launcherName) { |
345 |
420 verifyNotRuntime(); |
346 if (PackageType.LINUX.contains(type)) { |
421 if (launcherName == null) { |
347 return outputDir().resolve(LinuxHelper.getLauncherPath(this)); |
422 launcherName = name(); |
348 } |
423 } |
349 |
424 |
350 if (PackageType.WINDOWS.contains(type)) { |
425 if (TKit.isWindows()) { |
351 return appInstallationDirectory().resolve(name() + ".exe"); |
426 launcherName = launcherName + ".exe"; |
352 } |
427 } |
353 |
428 |
354 if (PackageType.MAC.contains(type)) { |
429 if (isImagePackageType()) { |
355 return appInstallationDirectory().resolve(Path.of("Contents", "MacOS", name())); |
430 return appLayout().launchersDirectory().resolve(launcherName); |
356 } |
431 } |
357 |
|
358 throw throwUnexpectedPackageTypeError(); |
|
359 } |
|
360 |
|
361 /** |
|
362 * Returns path to application image directory. |
|
363 * |
|
364 * E.g. if --dest is set to `foo` and --name is set to `bar` the function |
|
365 * will return `foo/bar` path on Linux and Windows and `foo/bar.app` on macOS. |
|
366 * |
|
367 * @throws IllegalArgumentException is command is doing platform packaging |
|
368 */ |
|
369 public Path appImage() { |
|
370 verifyIsOfType(PackageType.IMAGE); |
|
371 String dirName = name(); |
|
372 if (TKit.isOSX()) { |
|
373 dirName = dirName + ".app"; |
|
374 } |
|
375 return outputDir().resolve(dirName); |
|
376 } |
|
377 |
|
378 /** |
|
379 * Returns path to application launcher relative to image directory. |
|
380 * |
|
381 * E.g. if --name is set to `Foo` the function will return `bin/Foo` path on |
|
382 * Linux, and `Foo.exe` on Windows. |
|
383 * |
|
384 * @throws IllegalArgumentException is command is doing platform packaging |
|
385 */ |
|
386 public Path launcherPathInAppImage() { |
|
387 verifyIsOfType(PackageType.IMAGE); |
|
388 |
432 |
389 if (TKit.isLinux()) { |
433 if (TKit.isLinux()) { |
390 return Path.of("bin", name()); |
434 LinuxHelper.getLauncherPath(this).getParent().resolve(launcherName); |
391 } |
435 } |
392 |
436 |
393 if (TKit.isOSX()) { |
437 return appLayout().launchersDirectory().resolve(launcherName); |
394 return Path.of("Contents", "MacOS", name()); |
438 } |
395 } |
439 |
396 |
440 /** |
397 if (TKit.isWindows()) { |
441 * Shorthand for {@code appLauncherPath(null)}. |
398 return Path.of(name() + ".exe"); |
442 */ |
399 } |
443 public Path appLauncherPath() { |
400 |
444 return appLauncherPath(null); |
401 throw TKit.throwUnknownPlatformError(); |
445 } |
402 } |
446 |
403 |
447 private void verifyNotRuntime() { |
404 /** |
448 if (isRuntime()) { |
405 * Returns path to runtime directory relative to image directory. |
449 throw new IllegalArgumentException("Java runtime packaging"); |
406 * |
450 } |
407 * @throws IllegalArgumentException if command is configured for platform |
451 } |
408 * packaging |
452 |
409 */ |
453 /** |
410 public Path appRuntimeDirectoryInAppImage() { |
454 * Returns path to .cfg file of the given application launcher. |
411 verifyIsOfType(PackageType.IMAGE); |
455 * |
412 return appRuntimePath(packageType()); |
456 * E.g.: |
413 } |
457 * [jpackage --name Foo --package-type rpm] -> `/opt/foo/lib/app/Foo.cfg` |
414 |
458 * [jpackage --name Foo --package-type app-image --dest bar] -> `bar/Foo/lib/app/Foo.cfg` |
415 private static Path appRuntimePath(PackageType type) { |
459 * |
416 if (TKit.isLinux()) { |
460 * @param launcher name of launcher or {@code null} for the main launcher |
417 return Path.of("lib/runtime"); |
461 * |
418 } |
462 * @throws IllegalArgumentException if the command is configured for |
419 if (TKit.isOSX()) { |
463 * packaging Java runtime |
420 return Path.of("Contents/runtime"); |
464 */ |
421 } |
465 public Path appLauncherCfgPath(String launcherName) { |
422 |
466 verifyNotRuntime(); |
423 return Path.of("runtime"); |
467 if (launcherName == null) { |
424 } |
468 launcherName = name(); |
425 |
469 } |
426 public boolean isFakeRuntimeInAppImage(String msg) { |
470 return appLayout().appDirectory().resolve(launcherName + ".cfg"); |
427 return isFakeRuntime(appImage().resolve( |
471 } |
428 appRuntimeDirectoryInAppImage()), msg); |
472 |
429 } |
473 public boolean isFakeRuntime(String msg) { |
430 |
474 Path runtimeDir = appRuntimeDirectory(); |
431 public boolean isFakeRuntimeInstalled(String msg) { |
475 |
432 return isFakeRuntime(appRuntimeInstallationDirectory(), msg); |
|
433 } |
|
434 |
|
435 private static boolean isFakeRuntime(Path runtimeDir, String msg) { |
|
436 final Collection<Path> criticalRuntimeFiles; |
476 final Collection<Path> criticalRuntimeFiles; |
437 if (TKit.isWindows()) { |
477 if (TKit.isWindows()) { |
438 criticalRuntimeFiles = WindowsHelper.CRITICAL_RUNTIME_FILES; |
478 criticalRuntimeFiles = WindowsHelper.CRITICAL_RUNTIME_FILES; |
439 } else if (TKit.isLinux()) { |
479 } else if (TKit.isLinux()) { |
440 criticalRuntimeFiles = LinuxHelper.CRITICAL_RUNTIME_FILES; |
480 criticalRuntimeFiles = LinuxHelper.CRITICAL_RUNTIME_FILES; |
480 verifyMutable(); |
520 verifyMutable(); |
481 suppressOutput = !v; |
521 suppressOutput = !v; |
482 return this; |
522 return this; |
483 } |
523 } |
484 |
524 |
|
525 public JPackageCommand ignoreDefaultRuntime(boolean v) { |
|
526 verifyMutable(); |
|
527 ignoreDefaultRuntime = v; |
|
528 return this; |
|
529 } |
|
530 |
485 public boolean isWithToolProvider() { |
531 public boolean isWithToolProvider() { |
486 return Optional.ofNullable(withToolProvider).orElse( |
532 return Optional.ofNullable(withToolProvider).orElse( |
487 defaultWithToolProvider); |
533 defaultWithToolProvider); |
488 } |
534 } |
489 |
535 |
490 public void executePrerequisiteActions() { |
536 public JPackageCommand executePrerequisiteActions() { |
491 verifyMutable(); |
537 verifyMutable(); |
492 if (!actionsExecuted) { |
538 if (!actionsExecuted) { |
493 actionsExecuted = true; |
539 actionsExecuted = true; |
494 if (actions != null) { |
540 if (actions != null) { |
495 actions.stream().forEach(r -> r.accept(this)); |
541 actions.stream().forEach(r -> r.accept(this)); |
496 } |
542 } |
497 } |
543 } |
|
544 return this; |
|
545 } |
|
546 |
|
547 public Executor createExecutor() { |
|
548 verifyMutable(); |
|
549 Executor exec = new Executor() |
|
550 .saveOutput(saveConsoleOutput).dumpOutput(!suppressOutput) |
|
551 .addArguments(args); |
|
552 |
|
553 if (isWithToolProvider()) { |
|
554 exec.setToolProvider(JavaTool.JPACKAGE); |
|
555 } else { |
|
556 exec.setExecutable(JavaTool.JPACKAGE); |
|
557 } |
|
558 |
|
559 return exec; |
498 } |
560 } |
499 |
561 |
500 public Executor.Result execute() { |
562 public Executor.Result execute() { |
501 executePrerequisiteActions(); |
563 executePrerequisiteActions(); |
502 |
564 |
503 if (packageType() == PackageType.IMAGE) { |
565 if (isImagePackageType()) { |
504 TKit.deleteDirectoryContentsRecursive(outputDir()); |
566 TKit.deleteDirectoryContentsRecursive(outputDir()); |
505 } |
567 } |
506 |
568 |
507 Executor exec = new Executor() |
569 return new JPackageCommand(this) |
508 .saveOutput(saveConsoleOutput).dumpOutput(!suppressOutput) |
570 .adjustArgumentsBeforeExecution() |
509 .addArguments(new JPackageCommand().addArguments( |
571 .createExecutor() |
510 args).adjustArgumentsBeforeExecution().args); |
572 .execute(); |
511 |
|
512 if (isWithToolProvider()) { |
|
513 exec.setToolProvider(JavaTool.JPACKAGE.asToolProvider()); |
|
514 } else { |
|
515 exec.setExecutable(JavaTool.JPACKAGE); |
|
516 } |
|
517 return exec.execute(); |
|
518 } |
573 } |
519 |
574 |
520 public JPackageCommand executeAndAssertHelloAppImageCreated() { |
575 public JPackageCommand executeAndAssertHelloAppImageCreated() { |
521 executeAndAssertImageCreated(); |
576 executeAndAssertImageCreated(); |
522 HelloApp.executeLauncherAndVerifyOutput(this); |
577 HelloApp.executeLauncherAndVerifyOutput(this); |