Compare commits

...

343 commits
1.7.0 ... main

Author SHA1 Message Date
Geert Bevin 7b542ac5d0
Merge pull request #76 from ethauvin/main
Some checks failed
bld-ci / build-linux (17) (push) Has been cancelled
bld-ci / build-linux (20) (push) Has been cancelled
bld-ci / build-linux (21) (push) Has been cancelled
bld-ci / build-linux (22) (push) Has been cancelled
bld-ci / build-linux (23) (push) Has been cancelled
bld-ci / build-linux (24) (push) Has been cancelled
bld-ci / build-linux (25) (push) Has been cancelled
bld-ci / build-macos (17) (push) Has been cancelled
bld-ci / build-macos (20) (push) Has been cancelled
bld-ci / build-macos (21) (push) Has been cancelled
bld-ci / build-macos (22) (push) Has been cancelled
bld-ci / build-macos (23) (push) Has been cancelled
bld-ci / build-macos (24) (push) Has been cancelled
bld-ci / build-macos (25) (push) Has been cancelled
bld-ci / build-windows (17) (push) Has been cancelled
bld-ci / build-windows (20) (push) Has been cancelled
bld-ci / build-windows (21) (push) Has been cancelled
bld-ci / build-windows (22) (push) Has been cancelled
bld-ci / build-windows (23) (push) Has been cancelled
bld-ci / build-windows (24) (push) Has been cancelled
bld-ci / build-windows (25) (push) Has been cancelled
javadocs-pages / deploy (push) Has been cancelled
Add support for multiple input types in path-related javac options
2026-03-05 19:02:46 -05:00
Erik C. Thauvin aa10006ce2
Remove redundant null/empty checks 2026-01-25 18:28:39 -08:00
Erik C. Thauvin 4de8d3c629
Handle null values in path and comma-separated options via stream filters 2026-01-25 11:37:35 -08:00
Erik C. Thauvin 44144ce095
Add missing null/empty checks 2026-01-25 11:20:24 -08:00
Erik C. Thauvin 3160161299
Update copyright 2026-01-22 00:19:36 -08:00
Erik C. Thauvin b22257ed43
Refactor javac options to improve consistency and handle null/empty parameters 2026-01-22 00:16:50 -08:00
Erik C. Thauvin 25c77ed5df
Improve method consistency 2026-01-21 15:01:17 -08:00
Erik C. Thauvin 21ed5912f0
Add support for multiple input types (Collection, Varargs, File, Path) in JavacOptions path-related methods. 2026-01-21 11:37:20 -08:00
Erik C. Thauvin 737927da26
Refactor XLint options for better handling of null/empty lists.
Some checks failed
bld-ci / build-linux (17) (push) Has been cancelled
bld-ci / build-linux (20) (push) Has been cancelled
bld-ci / build-linux (21) (push) Has been cancelled
bld-ci / build-linux (22) (push) Has been cancelled
bld-ci / build-linux (23) (push) Has been cancelled
bld-ci / build-linux (24) (push) Has been cancelled
bld-ci / build-linux (25) (push) Has been cancelled
bld-ci / build-macos (17) (push) Has been cancelled
bld-ci / build-macos (20) (push) Has been cancelled
bld-ci / build-macos (21) (push) Has been cancelled
bld-ci / build-macos (22) (push) Has been cancelled
bld-ci / build-macos (23) (push) Has been cancelled
bld-ci / build-macos (24) (push) Has been cancelled
bld-ci / build-macos (25) (push) Has been cancelled
bld-ci / build-windows (17) (push) Has been cancelled
bld-ci / build-windows (20) (push) Has been cancelled
bld-ci / build-windows (21) (push) Has been cancelled
bld-ci / build-windows (22) (push) Has been cancelled
bld-ci / build-windows (23) (push) Has been cancelled
bld-ci / build-windows (24) (push) Has been cancelled
bld-ci / build-windows (25) (push) Has been cancelled
javadocs-pages / deploy (push) Has been cancelled
2026-01-11 11:33:00 -08:00
Erik C. Thauvin 6fd3948f04
Add JUnit reporter integration and update workflow steps 2026-01-11 11:17:15 -08:00
Erik C. Thauvin c537b584f2
Add unit tests for JavacOptions class 2026-01-11 11:17:15 -08:00
Erik C. Thauvin 7a419ed197
Add support for -Xlint options in JavacOptions 2026-01-11 11:17:15 -08:00
Erik C. Thauvin 9c5928f9b1
Cleanup Javadocs 2026-01-11 11:17:15 -08:00
Erik C. Thauvin 26ff495b79
Fix containsRelease method to check for --release instead of -release in JavacOptions 2026-01-11 11:17:15 -08:00
Erik C. Thauvin 585325dd46
Add support for --add-reads, --default-module-for-created-files and --patch-module in JavacOptions 2026-01-11 11:17:15 -08:00
Erik C. Thauvin 793fde47dc
Add support for --add-exports in JavacOptions 2026-01-11 11:17:15 -08:00
Erik C. Thauvin fea026a9c6
Add support for --source and --target in JavacOptions 2026-01-11 11:17:14 -08:00
Erik C. Thauvin c71a98c6ee
Allow for modulePath and classPath specification using a File array or collection 2026-01-11 11:17:14 -08:00
Erik C. Thauvin 8ad5414d67
Revise README to focus on contributing guidelines
Some checks failed
bld-ci / build-linux (17) (push) Has been cancelled
bld-ci / build-linux (20) (push) Has been cancelled
bld-ci / build-linux (21) (push) Has been cancelled
bld-ci / build-linux (22) (push) Has been cancelled
bld-ci / build-linux (23) (push) Has been cancelled
bld-ci / build-linux (24) (push) Has been cancelled
bld-ci / build-linux (25) (push) Has been cancelled
bld-ci / build-macos (17) (push) Has been cancelled
bld-ci / build-macos (20) (push) Has been cancelled
bld-ci / build-macos (21) (push) Has been cancelled
bld-ci / build-macos (22) (push) Has been cancelled
bld-ci / build-macos (23) (push) Has been cancelled
bld-ci / build-macos (24) (push) Has been cancelled
bld-ci / build-macos (25) (push) Has been cancelled
bld-ci / build-windows (17) (push) Has been cancelled
bld-ci / build-windows (20) (push) Has been cancelled
bld-ci / build-windows (21) (push) Has been cancelled
bld-ci / build-windows (22) (push) Has been cancelled
bld-ci / build-windows (23) (push) Has been cancelled
bld-ci / build-windows (24) (push) Has been cancelled
bld-ci / build-windows (25) (push) Has been cancelled
javadocs-pages / deploy (push) Has been cancelled
Updated the README to replace the 'Building bld' section with a link to the 'CONTRIBUTING.md' file.
2025-12-30 12:45:43 -08:00
Erik C. Thauvin 684c697896
Create CONTRIBUTING.md with contribution instructions
Added contributing guidelines for the project.
2025-12-30 12:39:52 -08:00
Geert Bevin affa9e1dac Updated RIFE2/core
Some checks failed
bld-ci / build-linux (17) (push) Has been cancelled
bld-ci / build-linux (20) (push) Has been cancelled
bld-ci / build-linux (21) (push) Has been cancelled
bld-ci / build-linux (22) (push) Has been cancelled
bld-ci / build-linux (23) (push) Has been cancelled
bld-ci / build-linux (24) (push) Has been cancelled
bld-ci / build-linux (25) (push) Has been cancelled
bld-ci / build-macos (17) (push) Has been cancelled
bld-ci / build-macos (20) (push) Has been cancelled
bld-ci / build-macos (21) (push) Has been cancelled
bld-ci / build-macos (22) (push) Has been cancelled
bld-ci / build-macos (23) (push) Has been cancelled
bld-ci / build-macos (24) (push) Has been cancelled
bld-ci / build-macos (25) (push) Has been cancelled
bld-ci / build-windows (17) (push) Has been cancelled
bld-ci / build-windows (20) (push) Has been cancelled
bld-ci / build-windows (21) (push) Has been cancelled
bld-ci / build-windows (22) (push) Has been cancelled
bld-ci / build-windows (23) (push) Has been cancelled
bld-ci / build-windows (24) (push) Has been cancelled
bld-ci / build-windows (25) (push) Has been cancelled
javadocs-pages / deploy (push) Has been cancelled
2025-11-17 21:52:04 -05:00
Geert Bevin 1c70337afb Added Java 23 and 24 to CI tests 2025-11-17 21:45:32 -05:00
Geert Bevin 25bf0d3595 Added Java 25 to CI tests 2025-11-17 21:28:50 -05:00
Geert Bevin 0ec366e90b Updated RIFE2/core to version 1.9.3 2025-11-17 21:26:52 -05:00
Geert Bevin 8559696a6a Revert "Fixed missing main-class when running a modular application."
Some checks failed
bld-ci / build-linux (17) (push) Has been cancelled
bld-ci / build-linux (20) (push) Has been cancelled
bld-ci / build-linux (21) (push) Has been cancelled
bld-ci / build-linux (22) (push) Has been cancelled
bld-ci / build-macos (17) (push) Has been cancelled
bld-ci / build-macos (20) (push) Has been cancelled
bld-ci / build-macos (21) (push) Has been cancelled
bld-ci / build-macos (22) (push) Has been cancelled
bld-ci / build-windows (17) (push) Has been cancelled
bld-ci / build-windows (20) (push) Has been cancelled
bld-ci / build-windows (21) (push) Has been cancelled
bld-ci / build-windows (22) (push) Has been cancelled
javadocs-pages / deploy (push) Has been cancelled
This reverts commit 82705b952b.
2025-11-16 20:07:04 -05:00
Geert Bevin 6f54789dd9
Merge pull request #65 from Xasmedy/main
Some checks are pending
bld-ci / build-linux (17) (push) Waiting to run
bld-ci / build-linux (20) (push) Waiting to run
bld-ci / build-linux (21) (push) Waiting to run
bld-ci / build-linux (22) (push) Waiting to run
bld-ci / build-macos (17) (push) Waiting to run
bld-ci / build-macos (20) (push) Waiting to run
bld-ci / build-macos (21) (push) Waiting to run
bld-ci / build-macos (22) (push) Waiting to run
bld-ci / build-windows (17) (push) Waiting to run
bld-ci / build-windows (20) (push) Waiting to run
bld-ci / build-windows (21) (push) Waiting to run
bld-ci / build-windows (22) (push) Waiting to run
javadocs-pages / deploy (push) Waiting to run
Fixed missing main-class when running a modular application.
2025-11-16 11:17:30 -05:00
Geert Bevin 82fe6a3aa4
Merge pull request #71 from ethauvin/main
Log missing files when compiling or running
2025-11-16 11:16:54 -05:00
Geert Bevin 52e8a6ce6a Test fixes 2025-11-16 11:16:05 -05:00
Erik C. Thauvin f33108a3f0
Log missing main class or module when running. Closes #69 2025-11-14 20:52:59 -08:00
Erik C. Thauvin f4db05581b
Log missing source files when compiling. Closes #66 2025-11-14 20:49:00 -08:00
Erik C. Thauvin ba1dad4eb3
2.3.1-SNAPSHOT 2025-11-14 20:48:53 -08:00
xasmedy 82705b952b Fixed missing main-class when running a modular application.
The `RunOperation` is using the java `-m` flag to run the modular application, but it did not provide the required main-class as of documentation `-m <module>[/<mainclass>] [args...]`.
2025-11-13 00:13:20 +01:00
Geert Bevin 5efbc8c064 Updated readme
Some checks failed
bld-ci / build-linux (17) (push) Has been cancelled
bld-ci / build-linux (20) (push) Has been cancelled
bld-ci / build-linux (21) (push) Has been cancelled
bld-ci / build-linux (22) (push) Has been cancelled
bld-ci / build-macos (17) (push) Has been cancelled
bld-ci / build-macos (20) (push) Has been cancelled
bld-ci / build-macos (21) (push) Has been cancelled
bld-ci / build-macos (22) (push) Has been cancelled
bld-ci / build-windows (17) (push) Has been cancelled
bld-ci / build-windows (20) (push) Has been cancelled
bld-ci / build-windows (21) (push) Has been cancelled
bld-ci / build-windows (22) (push) Has been cancelled
javadocs-pages / deploy (push) Has been cancelled
2025-07-06 21:42:38 -04:00
Geert Bevin 22752668b7 Updated version to 2.3.0.
Some checks are pending
bld-ci / build-linux (17) (push) Waiting to run
bld-ci / build-linux (20) (push) Waiting to run
bld-ci / build-linux (21) (push) Waiting to run
bld-ci / build-linux (22) (push) Waiting to run
bld-ci / build-macos (17) (push) Waiting to run
bld-ci / build-macos (20) (push) Waiting to run
bld-ci / build-macos (21) (push) Waiting to run
bld-ci / build-macos (22) (push) Waiting to run
bld-ci / build-windows (17) (push) Waiting to run
bld-ci / build-windows (20) (push) Waiting to run
bld-ci / build-windows (21) (push) Waiting to run
bld-ci / build-windows (22) (push) Waiting to run
javadocs-pages / deploy (push) Waiting to run
Upgraded to bld 2.3.0.
Updated RIFE2/core.
2025-07-05 23:18:31 -04:00
Geert Bevin 9bea6d47c7 Updated version to 2.3.0-SNAPSHOT 2025-07-05 22:20:00 -04:00
Geert Bevin b0596911ed Updated readme with snapshot shield
Some checks failed
bld-ci / build-linux (17) (push) Has been cancelled
bld-ci / build-linux (20) (push) Has been cancelled
bld-ci / build-linux (21) (push) Has been cancelled
bld-ci / build-linux (22) (push) Has been cancelled
bld-ci / build-macos (17) (push) Has been cancelled
bld-ci / build-macos (20) (push) Has been cancelled
bld-ci / build-macos (21) (push) Has been cancelled
bld-ci / build-macos (22) (push) Has been cancelled
bld-ci / build-windows (17) (push) Has been cancelled
bld-ci / build-windows (20) (push) Has been cancelled
bld-ci / build-windows (21) (push) Has been cancelled
bld-ci / build-windows (22) (push) Has been cancelled
javadocs-pages / deploy (push) Has been cancelled
2025-07-04 19:20:34 -04:00
Geert Bevin e9906c0df7 Display error message when staging repository fails to be closed. 2025-07-04 18:13:08 -04:00
Geert Bevin d3d7614e7c Added support for automatically closing staging repositories with the new central staging API. 2025-07-04 14:31:30 -04:00
Geert Bevin 91a621dfea Added new sonatype central publishing repositories that replace the OOSRH repositories, called CENTRAL_RELEASED and CENTRAL_SNAPSHOTS.
Some checks are pending
bld-ci / build-linux (17) (push) Waiting to run
bld-ci / build-linux (20) (push) Waiting to run
bld-ci / build-linux (21) (push) Waiting to run
bld-ci / build-linux (22) (push) Waiting to run
bld-ci / build-macos (17) (push) Waiting to run
bld-ci / build-macos (20) (push) Waiting to run
bld-ci / build-macos (21) (push) Waiting to run
bld-ci / build-macos (22) (push) Waiting to run
bld-ci / build-windows (17) (push) Waiting to run
bld-ci / build-windows (20) (push) Waiting to run
bld-ci / build-windows (21) (push) Waiting to run
bld-ci / build-windows (22) (push) Waiting to run
javadocs-pages / deploy (push) Waiting to run
Updated bld to use the new snapshot repository instead.
Worked around new sonatype publishing repositories not allowing signed Maven metadata files.
2025-07-03 13:08:26 -04:00
Geert Bevin 5af8ca7b2e WIP additional debugging information when publishing upload fails
Some checks are pending
bld-ci / build-linux (17) (push) Waiting to run
bld-ci / build-linux (20) (push) Waiting to run
bld-ci / build-linux (21) (push) Waiting to run
bld-ci / build-linux (22) (push) Waiting to run
bld-ci / build-macos (17) (push) Waiting to run
bld-ci / build-macos (20) (push) Waiting to run
bld-ci / build-macos (21) (push) Waiting to run
bld-ci / build-macos (22) (push) Waiting to run
bld-ci / build-windows (17) (push) Waiting to run
bld-ci / build-windows (20) (push) Waiting to run
bld-ci / build-windows (21) (push) Waiting to run
bld-ci / build-windows (22) (push) Waiting to run
javadocs-pages / deploy (push) Waiting to run
2025-07-02 22:41:24 -04:00
Geert Bevin d6d3c0fc1d Updated version to 2.2.2-SNAPSHOT
Some checks failed
bld-ci / build-linux (17) (push) Has been cancelled
bld-ci / build-linux (20) (push) Has been cancelled
bld-ci / build-linux (21) (push) Has been cancelled
bld-ci / build-linux (22) (push) Has been cancelled
bld-ci / build-macos (17) (push) Has been cancelled
bld-ci / build-macos (20) (push) Has been cancelled
bld-ci / build-macos (21) (push) Has been cancelled
bld-ci / build-macos (22) (push) Has been cancelled
bld-ci / build-windows (17) (push) Has been cancelled
bld-ci / build-windows (20) (push) Has been cancelled
bld-ci / build-windows (21) (push) Has been cancelled
bld-ci / build-windows (22) (push) Has been cancelled
javadocs-pages / deploy (push) Has been cancelled
2025-02-24 21:02:58 -05:00
Geert Bevin 9158e7296f Upgraded GitHub actions 2025-02-24 20:39:56 -05:00
Geert Bevin b1b5c89c78 Updated version to 2.2.1 2025-02-24 20:29:27 -05:00
Geert Bevin 4b6cac6ace Improvement to environment API for process operation. 2025-01-22 19:14:13 -05:00
Geert Bevin 9362a60c52 More tests 2025-01-22 18:51:05 -05:00
Geert Bevin ca7fa0c4b8 Fixed #58 : Add an option to set environment variables before spawining a process 2025-01-22 18:30:07 -05:00
Geert Bevin f9f20e62ef Fixed #57 : Add an option to check if project required settins have been set 2025-01-21 21:19:45 -05:00
Geert Bevin 4b762796e0 Updated version to 2.2.1-SNAPSHOT 2025-01-21 21:08:31 -05:00
Geert Bevin 03a15433ff Updated version to 2.2.0.
Updated versions for RIFE2 project creation.
Updated RIFE2/core.
2025-01-11 12:08:10 -05:00
Geert Bevin 625055bbb6 RIFE2 project creation fix 2025-01-11 10:07:19 -05:00
Geert Bevin 72d214b3b6 Dependency update 2025-01-11 10:06:52 -05:00
Geert Bevin f753f87a79 Updated RIFE2/core 2025-01-10 18:53:25 -05:00
Geert Bevin fec4f68027 Added support for Maven project.parent properties 2025-01-10 18:45:02 -05:00
Geert Bevin 92c8cd3033 Updated RIFE2/core 2024-12-27 12:54:13 -05:00
Geert Bevin da0b92fb8e Updated RIFE2/core 2024-12-27 12:29:01 -05:00
Geert Bevin 2dd53ace3d More improvements to create operation 2024-12-27 10:33:38 -05:00
Geert Bevin 3d86aa8c8d Unify command line use of create operations 2024-12-26 20:06:59 -05:00
Geert Bevin 32052deaa3 Interrupt creation operation when a blank package or project name is provided 2024-12-26 18:47:14 -05:00
Geert Bevin b27cc78fb7 Don't add Lib suffix for lib project creation 2024-12-26 18:42:01 -05:00
Geert Bevin a7efd01697 Updated RIFE2/core 2024-12-26 17:13:43 -05:00
Geert Bevin 92fc85bd9c Updated blueprint dependencies 2024-12-26 17:09:33 -05:00
Geert Bevin 34667b5402 Improvements to create operations 2024-12-26 16:51:46 -05:00
Geert Bevin 66f7d180b9 Implements #52 : command line enhancements for project creation 2024-11-16 18:23:10 -05:00
Geert Bevin 6c2a9acf1c
Merge pull request #56 from ethauvin/main
Added javac options to specify the directory used to place generated source files.
2024-10-14 16:01:04 -04:00
Geert Bevin c6c9d32c35 Added support for automatically consolidating compile options that are named differently but serve the same purpose 2024-10-14 09:07:24 -04:00
Geert Bevin 3e9b252c51 Updated RIFE2/core 2024-10-10 10:11:04 -04:00
Erik C. Thauvin 3f60ed78ef
Removed extra empty line 2024-10-04 10:34:55 -07:00
Erik C. Thauvin 762e099988
Added javac options to specify the directory used to place generated source files. 2024-10-02 00:16:05 -07:00
Erik C. Thauvin 9941fc0d10
Merge pull request #55 from ethauvin/main
Added support for explicitly requesting annotation processing
2024-10-01 16:05:25 -07:00
Erik C. Thauvin f51add49f0
Added support for explicitly requesting annotation processing, as needed by Java 23 (and backported to 17 and 11) 2024-10-01 15:51:37 -07:00
Geert Bevin 3dce798d52 Updated version to 2.1.1-SNAPSHOT 2024-09-07 10:22:13 -04:00
Erik C. Thauvin d5e65ec9e8
Updated bld badge version to 2.1.0 2024-08-29 23:08:39 -07:00
Geert Bevin 4083f95bc8 Upgraded to bld-2.1.0.
Updated version to 2.1.0.
2024-08-29 19:19:13 -04:00
Geert Bevin 622ca99c7b Updated RIFE2/core submodule 2024-08-29 08:02:36 -04:00
Geert Bevin a8f43864bf Upgraded wrapper to latest version 2024-08-29 08:01:28 -04:00
Geert Bevin df173c4cfc Added ability to individually exclude sources and javadocs downloads for dependencies 2024-08-29 07:59:33 -04:00
Geert Bevin a07db3f94e
Merge pull request #50 from ethauvin/main
More cleanups to jlink, jmod & jpackage operations, options and tests
2024-08-29 07:33:28 -04:00
Erik C. Thauvin 5da9e4b3a5
More cleanups to jlink, jmod & jpackage operations, options and tests 2024-08-28 21:53:42 -07:00
Geert Bevin c7ca0e263d Updated to latest bld snapshot 2024-08-27 21:51:59 -04:00
Geert Bevin 22952cf189 Added missing IDEA lib dir upgrade 2024-08-27 21:49:35 -04:00
Geert Bevin 4fe40dadd7 Use recursive jar directory in IDEA project libraries so that modules can be picked up.
Updated wrapper so that old IDEA projects get updated for recursive scanning.
2024-08-27 21:45:28 -04:00
Geert Bevin 47d463e6aa Updated project dependencies and blueprint dependencies 2024-08-27 12:47:59 -04:00
Geert Bevin 5ab77194e0 Updated wrapper to latest 2.1.0-SNAPSHOT 2024-08-27 08:23:58 -04:00
Erik C. Thauvin df680a4846
Merge pull request #49 from ethauvin/main
Moved command files specification to the tool provider abstract operation
2024-08-26 14:41:27 -07:00
Erik C. Thauvin 406b83bd82
Moved command files specification to the tool provider abstract operation 2024-08-26 14:25:15 -07:00
Geert Bevin b4801b5b07 Upgraded to latest bld wrapper 2024-08-26 14:22:46 -04:00
Geert Bevin 28e548954f Javadoc improvements 2024-08-26 14:19:43 -04:00
Geert Bevin f15a8d2df2 Minor Javadoc tweaks. 2024-08-26 10:13:56 -04:00
Geert Bevin d68905b944
Merge pull request #48 from ethauvin/main
More cleanups to jlink, jmod & jpackage operations and options
2024-08-26 10:09:29 -04:00
Erik C. Thauvin c15a8d3bcf
Minor plural cleanups 2024-08-26 02:31:15 -07:00
Erik C. Thauvin 9deb570bf4
More cleanups to jlink, jmod & jpackage operations and options 2024-08-26 01:40:17 -07:00
Geert Bevin b8a63dd79c Cleanups to JlinkOptions, JmodOptions and JpackageOptions 2024-08-25 22:55:40 -04:00
Geert Bevin 22add235e3
Merge pull request #47 from ethauvin/main
Added JlinkOptions, JmodOptions and JpackageOptions File argument alt…
2024-08-25 22:27:23 -04:00
Erik C. Thauvin 0b9581cf12
Made paths specifications absolute 2024-08-25 18:46:15 -07:00
Geert Bevin 2b827a9a6f Added run operation test 2024-08-25 20:11:48 -04:00
Geert Bevin fd1429f2d3 Added support for automatically setting a module main class if module-info.java is part of the compilation operation and a main class was provided by the project. 2024-08-25 19:52:26 -04:00
Erik C. Thauvin 5821022fee
Fixed Jpackage main module specification 2024-08-25 16:09:30 -07:00
Geert Bevin a4300b37d1
Added JlinkOptions, JmodOptions and JpackageOptions File argument alternatives with Path and String.
Moved launches configurations from JPackage options to operation.
2024-08-25 15:47:51 -07:00
Geert Bevin 9f9e8a95db Added JavacOptions, JavadocOptions and JavaOptions File argument alternatives with Path and String.
Relaxed the requirement to specify mainClass in a project and added support for module.
2024-08-25 14:07:36 -04:00
Geert Bevin 126daecd21 Updated javadoc versioning for 2.1.0 2024-08-23 15:37:46 -04:00
Geert Bevin c70b4f1c43
Merge pull request #45 from ethauvin/main
implementations of JpackageOperation, JmodOperation and JlinkOperation
2024-08-23 15:36:30 -04:00
Geert Bevin 673ebbdeb0 Updated to latest bld wrapper 2024-08-23 10:58:37 -04:00
Geert Bevin a7c29080f5 Fix to the bld wrapper to take java.home into account for the java executable, otherwise there can be a mismatch between the javac version and the java version 2024-08-23 10:47:40 -04:00
Geert Bevin a616a8a8f6 Upgraded bld to 2.1.0-SNAPSHOT 2024-08-22 19:23:18 -04:00
Geert Bevin 0797e39dd6 Added native support for Java modules 2024-08-22 19:04:56 -04:00
Erik C. Thauvin 3bd17e224b
Improved command line tokenizer 2024-08-09 14:16:10 -07:00
Geert Bevin 7cd547f8b6 Implemented Java module for bld.
Updated version to 2.1.0-SNAPSHOT.
Updated RIFE2/core.
2024-08-05 21:10:59 -04:00
Erik C. Thauvin c59d61f8c1
Added command file and test for Windows 2024-08-05 14:52:18 -07:00
Erik C. Thauvin 0382444c0c
Added more command files tests 2024-08-05 10:40:42 -07:00
Erik C. Thauvin d72e6ebc2e
Truncate jmod ISO date to seconds 2024-08-05 10:25:41 -07:00
Erik C. Thauvin d42d2d6fa0
Added a command line tokenizer 2024-08-04 21:06:34 -07:00
Erik C. Thauvin a06ce8eaaa
Renamed fileOptions to cmdFiles 2024-08-04 20:16:55 -07:00
Geert Bevin 7f8120e3e3 Revert "Updated version to 2.1.0-SNAPSHOT."
This reverts commit 67c727e062.
2024-08-04 19:49:29 -04:00
Geert Bevin 67c727e062 Updated version to 2.1.0-SNAPSHOT.
Added Java module info.
Renamed IDEA module to be in-line with the Java module.
2024-08-04 19:29:08 -04:00
Erik C. Thauvin 62a324068f
Cleanups 2024-08-04 09:06:41 -07:00
Erik C. Thauvin e32e17403f
Added support for Java 20-21 specific options 2024-08-04 00:39:12 -07:00
Erik C. Thauvin 750758993d
Tests cleanup 2024-08-03 10:15:21 -07:00
Erik C. Thauvin 1d615a501c
More operation options cleanups 2024-08-03 09:51:09 -07:00
Erik C. Thauvin 91640e68ce
Fixed copyright 2024-08-03 08:01:28 -07:00
Erik C. Thauvin d029bb9b87
Fixed version parsing in tests 2024-08-03 07:47:12 -07:00
Erik C. Thauvin 7a946b17d8
Capture and check stdout in tests 2024-08-03 07:37:11 -07:00
Erik C. Thauvin f6aa5258ef
Normalized tool arguments setup and processing 2024-08-03 07:36:35 -07:00
Erik C. Thauvin 94225dfb7a
Improved @filename support 2024-08-02 21:33:33 -07:00
Erik C. Thauvin 8118f42285
Use System.out and System.out instead of StringWriter 2024-08-02 21:30:08 -07:00
Erik C. Thauvin c38594a173
Foce added jlink build directory 2024-08-02 18:37:28 -07:00
Erik C. Thauvin 0204cdff19
Added functional tests for jlink and jmod 2024-08-02 18:27:03 -07:00
Erik C. Thauvin b94b23af56
Clear command line arguments on execution 2024-08-02 18:26:00 -07:00
Erik C. Thauvin e2cc7a6782
Improved @filename options parsing 2024-08-02 18:25:39 -07:00
Erik C. Thauvin 002844861b
Fixed handling of @filename in all tools 2024-08-02 14:23:30 -07:00
Erik C. Thauvin 0ad964ea4d
Cleaned up and improved tests 2024-08-02 02:54:46 -07:00
Erik C. Thauvin d69956cf91
Revert install limbd0 on Ubuntu 2024-08-01 14:19:59 -07:00
Erik C. Thauvin 0aa93b708a
Install limbd0 on Ubuntu with sudo 2024-08-01 14:02:24 -07:00
Erik C. Thauvin 7fcbccd565
Install limbd0 on Ubuntu 2024-08-01 13:42:55 -07:00
Erik C. Thauvin 683f5dfb3a
Fixed test imports 2024-08-01 12:14:09 -07:00
Erik C. Thauvin 547b20a242
Draft implementations of JpackageOperation, JmodOperation and JlinkOperation 2024-08-01 11:41:29 -07:00
Geert Bevin aeecd957c6 Cleanups 2024-07-30 09:48:29 -04:00
Geert Bevin a3a753f70a Cleanup 2024-07-30 08:51:17 -04:00
Geert Bevin cec3d4ebbf
Update README.md 2024-07-29 21:15:12 -04:00
Geert Bevin bd93c6659b Updated readme 2024-07-28 21:04:26 -04:00
Geert Bevin d96ce65cbb Fixed regression in 2.0.0 with global bld command when used without any arguments.
Upgraded to bld 2.0.1.
Updated version to 2.0.1.
2024-07-28 20:59:21 -04:00
Geert Bevin 97a153f955 Updated version to 2.0.0.
Upgraded to bld 2.0.0.
2024-07-28 19:59:35 -04:00
Geert Bevin 78368fdecc Test fixes 2024-07-27 22:54:42 -04:00
Geert Bevin 89820f5262 Updated dependencies in RIFE2 blueprint. 2024-07-27 22:45:33 -04:00
Geert Bevin e5337f6ed7 Updated RIFE2/core 2024-07-27 22:42:41 -04:00
Geert Bevin fbaaa4ae3e Updated wrapper 2024-07-27 22:35:52 -04:00
Geert Bevin ba7e314e6e Added publication to GitHub packages 2024-07-27 22:34:24 -04:00
Geert Bevin fa5929a778 Updated wrapper 2024-07-23 05:17:21 -04:00
Geert Bevin bd5d8ef355 Bld cache cleanup, refactorings and javadocs 2024-07-23 04:24:37 -04:00
Geert Bevin ad8a866dc3 Cleanups 2024-07-22 22:13:39 -04:00
Geert Bevin 586aec0eae
Merge pull request #43 from ethauvin/main 2024-07-21 10:44:40 -04:00
Erik C. Thauvin c7ebaa7d87
Removed trailing commas 2024-07-21 01:09:14 -07:00
Geert Bevin 0e4e171a81 Don't try to avoid other std output when help is generating JSON, the plugin will now parse the JSON out regardless 2024-07-20 15:06:29 -04:00
Geert Bevin 3ec2cc68ce More changes to cache format, now the dependency tree generation is cached 2024-07-20 11:30:35 -04:00
Geert Bevin d24e9d223c Updated RIFE2-core 2024-07-20 02:51:02 -04:00
Geert Bevin d605ac1242 Preserve the project's version as a semantic version number. Created two version of parsing version string, one falls back to generic version, the other returns VersionNumber.UNKNOWN when parsing fails like in previous bld versions. 2024-07-20 02:44:51 -04:00
Geert Bevin fa0ac43828 Updated wrapper 2024-07-19 23:36:58 -04:00
Geert Bevin 4913519eb4 Still handle version ranges as an unknown version 2024-07-19 23:35:29 -04:00
Geert Bevin 3ee8f81317 Made VersionGeneric constructor public 2024-07-19 23:22:09 -04:00
Geert Bevin 19991e84c4 Regression fix to version handling 2024-07-19 23:16:18 -04:00
Geert Bevin 0f65e1d232 Regression fix to version handling 2024-07-19 23:09:57 -04:00
Geert Bevin 98e9035c5e Added generic version implementation 2024-07-19 22:59:29 -04:00
Geert Bevin 15be3a2cd7 Allow offline and help json modes work together 2024-07-19 18:11:09 -04:00
Geert Bevin 42ced8e340 Updated wrapper 2024-07-19 13:32:34 -04:00
Geert Bevin fcd5d01e86 Fix to local extension dependency cache 2024-07-19 13:27:08 -04:00
Geert Bevin 522b8b95d7 Updated wrapper 2024-07-19 08:53:45 -04:00
Geert Bevin f86b7fb40c Bld cache fixes for windows 2024-07-19 08:45:07 -04:00
Geert Bevin 8c42052e2e Test code cleanup 2024-07-19 08:37:13 -04:00
Geert Bevin a33e373367 Don't hold on to the cache file 2024-07-19 07:51:10 -04:00
Geert Bevin e731b00287
Merge pull request #42 from ethauvin/main
Cleaned up help messages
2024-07-19 07:48:17 -04:00
Erik C. Thauvin fb4ce1197a
Cleaned up help messages 2024-07-19 01:28:36 -07:00
Geert Bevin a3830dbdc0 Fix to cache so that it doesn't hold on to a parsed properties file 2024-07-19 00:02:32 -04:00
Geert Bevin bb4c980e66 Backing out messaging about each command that's starting 2024-07-18 22:20:16 -04:00
Geert Bevin 454c51db12 Updated wrapper 2024-07-18 22:15:53 -04:00
Geert Bevin 9614bd8014 Consolidate all hashing and caching into a single properties file instead of multiple files 2024-07-18 22:14:56 -04:00
Geert Bevin 604f5ba424 Tweaks to help output and bld output when no commands are provided 2024-07-17 22:56:07 -04:00
Geert Bevin b0a75b22b7 Tweaks to help overview documentation 2024-07-17 22:31:50 -04:00
Geert Bevin 0ed48f9eed Fix properties 2024-07-17 21:25:44 -04:00
Geert Bevin a02e78820e Improvement to offline operation, now pushed to the actual operations instead of the commands 2024-07-17 21:25:24 -04:00
Geert Bevin d904fd22b7 Better error reporting when internet is not accessible, added support for offline mode that will not access the internet for any reason. 2024-07-17 20:59:38 -04:00
Geert Bevin 8e02a3ac7e Removed generic json output support and only add it for the help operation 2024-07-14 15:22:45 -04:00
Geert Bevin 48c43a05ed Fixes for dependency override property behavior. 2024-07-13 20:44:45 -04:00
Geert Bevin bb6052250e Updated wrapper 2024-07-13 19:29:18 -04:00
Geert Bevin 23d9e26856 Fixed download location of bld's own wrapper 2024-07-13 19:26:27 -04:00
Geert Bevin 30f456e47a Added support for overriding dependency versions with properties throughout all of dependency resolution. 2024-07-13 19:25:44 -04:00
Geert Bevin fd38de9644 Updated wrapper for latest 2.0.0-SNAPSHOT 2024-07-13 08:00:32 -04:00
Geert Bevin 8928955fb1 Fixed one of the Dependency constructors not passing on exclusions 2024-07-13 08:00:16 -04:00
Geert Bevin a222bec47c Added support for displaying extensions dependencies in the dependency-tree command. 2024-07-12 22:33:39 -04:00
Geert Bevin feed8a8eb5 Updated to RIFE2/core 1.8.2 2024-07-12 10:17:14 -04:00
Geert Bevin ad15ff5095 Updated RIFE2 project creation to use RIFE2 v1.8.0 2024-07-12 10:16:23 -04:00
Geert Bevin 5ced931f7e Upgraded to latest bld wrapper 2024-07-10 18:50:10 -04:00
Geert Bevin 1d38c914e0 Fix for classpath generation of bld wrapper, making source sources and javadocs are not included. 2024-07-10 18:43:26 -04:00
Geert Bevin 8b75f74a1d Updated dependencies 2024-07-02 14:54:31 -04:00
Geert Bevin bc13bad49f Upgraded to latest bld wrapper 2024-06-26 08:03:49 -04:00
Geert Bevin b9ac76b5b5 Interrupt execution when exception triggers during command execution.
Minor refactoring.
2024-06-26 08:02:02 -04:00
Geert Bevin c912e4396e Improvements to json operation.
Upgraded bld to 2.0.0-SNAPSHOT.
2024-06-25 05:13:20 -04:00
Geert Bevin 793efb27ce Added support for generating bld output as JSON so that it can be consumed by other tools.
Added wrapper support for local Maven repository bld snapshots.
Updated version to 2.0.0-SNAPSHOT.
2024-06-24 20:28:54 -04:00
Geert Bevin 177a2e39af Back out the support for embedded launching 2024-06-23 20:46:26 -04:00
Geert Bevin 7f74bb015b Don't propagate the embedded argument to the Cli 2024-06-23 20:21:33 -04:00
Geert Bevin 9338768415 Allow bld to run in embedded mode 2024-06-23 20:11:06 -04:00
Geert Bevin 4f20fb2cc7 Support the provided scope by the PomBuilder class 2024-06-23 15:02:11 -04:00
Geert Bevin e65668a8be Test fixes 2024-06-23 13:19:34 -04:00
Geert Bevin ecb9289001 Added support for generating POM properties.
Projects with javaRelease specified automatically set the maven compiler properties in their POM at generation.
2024-06-23 13:07:03 -04:00
Geert Bevin a30b290c0d Fixed RIFE2 project bld tests with jetty 12.0.9 2024-05-30 17:57:57 -04:00
Geert Bevin abf84256a5 Revert RIFE2 blueprint Jetty version for now 2024-05-23 09:04:12 -04:00
Geert Bevin b25f332f3b Updated versions of rife2 blueprint 2024-05-23 08:05:08 -04:00
Geert Bevin e491f6d664 Updated to latest bld 1.9.2-SNAPSHOT 2024-05-23 07:56:03 -04:00
Geert Bevin aca7aa41a9 Added support for setting the bld build file java and javac options through bld-wrapper.properties. Fixes #33. 2024-05-23 07:53:16 -04:00
Geert Bevin 57c4b20de8 Improve artifact not found exception to explicitly mention that no repositories or no artifact locations are defined. 2024-05-22 12:25:02 -04:00
Geert Bevin f0129e7ba1 Updated version to 1.9.2-SNAPSHOT 2024-05-22 12:23:24 -04:00
Geert Bevin b5655ca346
Update devcontainer.json 2024-05-08 21:26:08 -04:00
Geert Bevin 921a1f11b5
Create devcontainer.json 2024-05-08 20:57:07 -04:00
Geert Bevin 60c332d750
Merge pull request #32 from sombriks/main
setting exit status for unknown command
2024-05-04 19:47:56 -04:00
Leonardo Silveira 4d841a7c72 setting exit status for unknown command 2024-05-04 18:44:18 -03:00
Geert Bevin accf27c4db Updated version to 1.9.1.
Updated to bld 1.9.1.
Updated to RIFE/core 1.8.1.
2024-05-01 16:48:02 -04:00
Geert Bevin 917d6bbe93 Fixed version number parsing to properly detect numerical qualifiers.
Fixes #30
Fixes #28
2024-05-01 15:12:38 -04:00
Geert Bevin 708304235b Updated for JDK 22 2024-03-22 14:44:49 -04:00
Geert Bevin 392ca23bd3 Fixed input stream not being inherited from current process for process operations. 2024-03-12 13:56:48 -04:00
Geert Bevin 31f9dc3373 Updated version to 1.9.1-SNAPSHOT.
Upgraded json dependency for tests.
2024-03-12 13:56:14 -04:00
Geert Bevin 1e04c3d530 Updated readme 2024-02-25 23:47:33 -05:00
Geert Bevin 52fc588795 Updated to bld 1.9.0 2024-02-25 22:52:13 -05:00
Geert Bevin e6feeff0da More vscode tweaks 2024-02-25 15:54:52 -05:00
Geert Bevin 30101af0ab Test fixes for changed dependency versions.
Tweaked vscode project structures.
Changed lib project to use JUnit and extend Project instead of BaseProject
2024-02-25 12:42:24 -05:00
Geert Bevin 183097c4f9 Updated some dependency versions to the latest 2024-02-25 11:39:53 -05:00
Geert Bevin 9d769a9d29 Fixed since specifier 2024-02-25 11:32:50 -05:00
Geert Bevin d8c0170dc0 Updated version to 1.9.0-SNAPSHOT.
Renamed blank project creation to app.
Revised project creation descriptions.
Added ability to have command aliases.
Preserve compatibility with create-blank command through an alias.
2024-02-25 11:27:01 -05:00
Geert Bevin 86d81c9c51 Dealing with X's 2024-02-25 08:43:23 -05:00
Geert Bevin aeb3369fe0 Allow file to be overwritten in the curl scripts 2024-02-25 08:24:12 -05:00
Geert Bevin 8b4055c1a3
Merge pull request #23 from ethauvin/main
Use the project type to determine the project example name
2024-02-25 07:55:24 -05:00
Geert Bevin 7e44493866 Added create.sh and upgrade.sh scripts that rely on curl 2024-02-25 07:51:45 -05:00
Erik C. Thauvin 2de4d7f4db Use the project type to determine the project example name 2024-02-25 04:47:41 -08:00
Erik C. Thauvin e7633b4723
Changed bash format to console 2024-01-31 18:45:24 -08:00
Geert Bevin 9fc422da21 RIFE2 blueprint dependency updates 2024-01-31 21:18:20 -05:00
Geert Bevin 81ce5cefed Updated readme 2024-01-31 20:53:43 -05:00
Erik C. Thauvin dfeb6d634b
Updated bld badge to 1.8.0 2024-01-30 21:25:17 -08:00
Geert Bevin 7d54edc4d9 Updated git ignore in project templates to account for lib/provided 2024-01-30 22:01:03 -05:00
Geert Bevin 72344ede79 Updated version to 1.8.1-SNAPSHOT 2024-01-30 22:00:48 -05:00
Geert Bevin 5e681a4400 Updated version to 1.8.0 2024-01-30 21:19:37 -05:00
Geert Bevin c9bcbc0bb7 Updated to latest dependencies in blueprints, updated to latest RIFE2/core 2024-01-30 19:37:25 -05:00
Geert Bevin f6d2265623 Minor readme tweaks 2024-01-30 17:01:43 -05:00
Geert Bevin 12458bc149 Updated readme 2024-01-30 16:45:35 -05:00
Geert Bevin 72fe2d5a5d Updated readme 2024-01-30 16:38:00 -05:00
Geert Bevin 317e77bfd1 Comment tweaks 2024-01-07 00:06:20 -05:00
Geert Bevin af6525acfa Provided scope dependencies are now stored in a separate directory and are only added to compile and test classpaths, but are not included for any runtime or distribution contexts. 2024-01-06 23:28:30 -05:00
Geert Bevin 6ffd6260b1 Include extension jars into the sources for the bld library in the IDEA templates 2023-11-11 16:42:42 -05:00
Erik C. Thauvin 0e6f988181
Merge pull request #16 from ethauvin/main
Added TuxCare SecureChain Java repositories
2023-11-01 16:38:40 -07:00
Erik C. Thauvin a66285ce95 Added TuxCare SecureChain Java repositories 2023-11-01 15:50:20 -07:00
Geert Bevin b1f28c62ec Updated readme 2023-10-21 08:27:27 -04:00
Geert Bevin 7406d7a0af Updated version to 1.7.6-SNAPSHOT.
Minor tweak to help formatting.
2023-10-21 08:24:47 -04:00
Geert Bevin 942cd28468 Updated to bld 1.7.5.
Updated to latest RIFE2/core with updated dependencies.
Updated version to 1.7.5.
Updated RIFE2 project blueprint to use v1.7.3 and related dependencies.
2023-10-20 17:24:28 -04:00
Geert Bevin 84a2bb337d Updated with support for latest JUnit in a backwards compatible way.
Updated some other blueprint dependencies.
2023-10-20 14:48:38 -04:00
Geert Bevin 6230db68af Added tests for Xml2MetaData snapshot 2023-10-19 18:50:14 -04:00
Geert Bevin 85f2c8fd7b Updated version to 1.7.5-SNAPSHOT.
WIP fix for new Gradle maven-metadata.xml layout.
2023-10-19 09:55:40 -04:00
Geert Bevin 1a243efb66 Updated version to 1.7.4 2023-10-10 16:14:56 -04:00
Geert Bevin e6be211d73 Add snapshot shorthand for version numbers in project 2023-10-10 11:56:39 -04:00
Geert Bevin 76186c78db Set RIFE2 version to 1.7.2 2023-10-10 11:56:11 -04:00
Geert Bevin f53c73c9d5 Revert "Fixed excessive String concatenations in loop"
This reverts commit 7009e54c71.
2023-10-10 11:55:38 -04:00
Geert Bevin 400bb13532 Updated README 2023-10-04 08:17:29 -04:00
Geert Bevin 95858f0c29
Update README.md 2023-10-03 23:31:44 -04:00
Geert Bevin 0beedb6918 Updated version to 1.7.4-SNAPSHOT 2023-10-03 23:29:54 -04:00
Geert Bevin f2b1d4228f Updated for bld 1.7.3. 2023-10-03 23:02:32 -04:00
Geert Bevin de4c4743b5 Updated RIFE2 version for blueprint, in anticipation of upcoming RIFE2 version 2023-10-03 19:31:46 -04:00
Geert Bevin f65ce504e3
Merge pull request #12 from rife2/ethauvin-patch-1
Added MAVEN_CENTRAL import. Closes #8
2023-10-03 19:18:56 -04:00
Geert Bevin e1489b9847 Updated version to 1.7.3 2023-10-03 19:16:14 -04:00
Erik C. Thauvin bb6726ec1f
Added MAVEN_CENTRAL import. Closes #8 2023-10-03 16:15:33 -07:00
Geert Bevin 96efbd260c Updated RIFE2-core 2023-10-03 19:15:16 -04:00
Geert Bevin 5519ff3f1c vscode related fixes 2023-10-03 13:36:44 -04:00
Geert Bevin 7face792f2 More Windows tweaks 2023-10-01 14:42:04 -04:00
Geert Bevin 35887e7d06 Disable reposilite publish tests on Windows for now 2023-10-01 14:18:05 -04:00
Geert Bevin 844b2b390d Try running on Windows in CI 2023-10-01 14:04:56 -04:00
Geert Bevin 4e64675bdb
Merge pull request #11 from ethauvin/main
Moderate Code Cleanup
2023-10-01 13:55:12 -04:00
Geert Bevin 7ceb6e3c27
Merge branch 'main' into main 2023-10-01 13:55:03 -04:00
Erik C. Thauvin f00418b4c2 Revert unwanted previous commit 2023-10-01 10:51:25 -07:00
Erik C. Thauvin 4ac6490dec Removed unused imports 2023-10-01 10:30:50 -07:00
Geert Bevin e7c7144c84 Renamed Github workflows 2023-10-01 12:48:32 -04:00
Geert Bevin cac57b3e4b Windows related tweaks and fixes 2023-10-01 12:43:04 -04:00
Geert Bevin 0b9f29a175 Merge remote-tracking branch 'origin/main' 2023-10-01 09:43:24 -04:00
Geert Bevin 2a5437de0c Updated for latest RIFE2 core.
Some build changes.
Run Github workflow on macOS.
2023-10-01 09:43:15 -04:00
Geert Bevin 7c2d0221b8 Fixed for some operation options typos 2023-10-01 09:29:15 -04:00
Geert Bevin a6aadf8e60 More test timing changes 2023-09-30 20:16:10 -04:00
Geert Bevin 5fb6fa16b7 Some test timing tweaks to try to work around CI failures. 2023-09-30 19:20:02 -04:00
Geert Bevin 0994f184f2 Backing out previous change since it only works on JDK 19 2023-09-30 19:17:11 -04:00
Geert Bevin 3eb5795cf2 Make sure previous executors are closed cleanly 2023-09-30 19:07:53 -04:00
Geert Bevin 77ceceb122 Updated Github workflow 2023-09-30 19:04:20 -04:00
Geert Bevin 3452a404fc Updated Github workflow 2023-09-30 18:51:20 -04:00
Geert Bevin c4b5748239 Updated Github workflow 2023-09-30 18:50:09 -04:00
Geert Bevin d52551f3b7 Test tweak to include check result for recently failing test 2023-09-30 18:26:20 -04:00
Erik C. Thauvin ec01a626ae Revert some changes per Geert comments 2023-09-30 10:22:09 -07:00
Erik C. Thauvin 87735bb88e Reverted sign exception modifications 2023-09-29 10:27:09 -07:00
Erik C. Thauvin 1ab53f5bad Cleaned up sign exception 2023-09-29 05:43:42 -07:00
Erik C. Thauvin 76cba6ed7a Added GOOGLE and SONATYPE_RELEASE_LEGACY to resolveRepository method. 2023-09-29 05:30:33 -07:00
Erik C. Thauvin 261b5d456a Added SONAYTPE_RELEASES_LEGACY repository 2023-09-29 04:14:54 -07:00
Erik C. Thauvin f6cb944565 Replaced more append("x") with append('x') where applicable 2023-09-15 06:58:34 -07:00
Erik C. Thauvin 7009e54c71 Fixed excessive String concatenations in loop 2023-09-15 06:51:04 -07:00
Erik C. Thauvin 89eb658d73 Fix chained appends 2023-09-15 06:26:33 -07:00
Erik C. Thauvin 60deb1906a Replaced all append("x") with append('x') 2023-09-15 06:24:12 -07:00
Erik C. Thauvin 102d3d3586 Preserved stacktrace 2023-09-15 05:44:19 -07:00
Erik C. Thauvin 762a63b12f Flipped String equals to avoid potential null pointer exception 2023-09-15 05:19:51 -07:00
Erik C. Thauvin e69f4fe554 Migrated syntax to Java 8+ 2023-09-15 05:02:50 -07:00
Erik C. Thauvin 6d082c1bac Removed unused imports 2023-09-15 04:56:38 -07:00
Geert Bevin 8c21c2f909
Merge pull request #10 from ethauvin/main
Added version ASCII art
2023-09-14 07:04:26 -04:00
Erik C. Thauvin a5c89dfd2d Reverted IDEA files 2023-09-13 11:06:15 -07:00
Erik C. Thauvin dfc402a9ee Added version ASCII art 2023-09-13 10:04:39 -07:00
Geert Bevin 743efa69e6 Updated RIFE2 core module 2023-09-05 06:06:02 +01:00
Geert Bevin 88aa78f3b5 Include provided and test scopes in Dependency Tree operation. 2023-08-27 19:41:22 -04:00
Geert Bevin 80a89b7343 Updated IDEA templates for latest format of misc.xml, excluding the XML declaration. 2023-08-26 11:25:04 -04:00
Geert Bevin 6b0455e9c5 Instead of excluding the templates folder from IDEA resources, setting a relative resource path to make IDEA put them in a classpath location that will not conflict with the source files in the project. 2023-08-26 10:47:50 -04:00
Geert Bevin d35166d53d Exclude signature files when generating uber jar. 2023-08-24 22:04:32 -04:00
Erik C. Thauvin f71f92bfa9
Merge pull request #7 from ethauvin/main
Switched to JDK 20 for testing
2023-08-22 14:09:50 -07:00
Erik C. Thauvin 278e1ff8dd Updated core 2023-08-22 13:18:16 -07:00
Erik C. Thauvin 6830c8c44c Switched to JDK 20 from 19 for testing 2023-08-22 11:45:25 -07:00
Erik C. Thauvin b7963ba6ca Minor cleanup 2023-08-22 11:45:25 -07:00
Erik C. Thauvin c75626efa4
Merge pull request #6 from ethauvin/main
Added GOOGLE repository
2023-08-22 11:41:57 -07:00
Erik C. Thauvin 29b4e267f8 Fixed missing GOOGLE trailing slash 2023-08-22 11:29:23 -07:00
Erik C. Thauvin 4058482cf7 Added GOOGLE repository 2023-08-22 11:24:35 -07:00
Erik C. Thauvin 8014d5d58e
Updated bld badge to 1.7.2 2023-08-21 07:42:06 -07:00
Geert Bevin 6e77f5a2f3 Updated README 2023-08-20 12:58:52 -04:00
Geert Bevin 6ad3f992ac Updated version to 1.7.3-SNAPSHOT 2023-08-20 00:11:24 -04:00
Geert Bevin d00471dd02 Updated version to 1.7.2 2023-08-19 23:53:19 -04:00
Geert Bevin 8d707a75ae
Merge pull request #5 from ethauvin/main
Fixed RunOption args parsing
2023-08-19 23:03:15 -04:00
Erik C. Thauvin c635b25b6f Fixed RunOption args parsing 2023-08-19 18:38:44 -07:00
Geert Bevin ba28294730
Update README.md 2023-08-17 18:04:03 -04:00
Geert Bevin 57fbaefda7 Updated version to 1.7.1 2023-08-17 11:28:56 -04:00
Geert Bevin bbdf89845a
Added bld badge 2023-08-16 20:58:57 -04:00
Geert Bevin 5f619ce188
Merge pull request #4 from ethauvin/main
Added support for run arguments
2023-08-16 20:54:15 -04:00
Erik C. Thauvin 912ba87c12 Removed IDEA inspection profile 2023-08-16 15:10:28 -07:00
Erik C. Thauvin 82ead98c5d Minor cleanup 2023-08-16 13:47:37 -07:00
Erik C. Thauvin c933f16e0f Make PomBuilder.generateInto(File) static 2023-08-16 12:10:49 -07:00
Erik C. Thauvin 49243568c6 Added method to generate a POM into a given file 2023-08-16 05:17:45 -07:00
Geert Bevin 5de491e5c6 Updated base project template to include repositories and sources download. 2023-08-14 14:17:23 -04:00
Erik C. Thauvin 17548f787c Fixed Run help summary 2023-08-13 18:17:56 -07:00
Erik C. Thauvin b81743896a Fixed RunOption help description 2023-08-13 18:09:22 -07:00
Erik C. Thauvin 262b500bc1 Minore cleanup 2023-08-13 17:52:29 -07:00
Erik C. Thauvin ecb72b6a7d Added ARGS_OPTION constant 2023-08-13 17:45:20 -07:00
Erik C. Thauvin c0418bb60a Fixed dangling System.out.println 2023-08-13 17:15:08 -07:00
Erik C. Thauvin 061a194322 Added support for run arguments 2023-08-13 16:55:56 -07:00
Geert Bevin cdaea733b2 Added more methods to the JavaOptions API.
Some cleanups.
2023-08-11 00:29:15 -04:00
Geert Bevin d95a26e8d6 Test fixes 2023-08-11 00:26:01 -04:00
Geert Bevin 950b47a383 Fix to java agent options API 2023-08-10 23:43:38 -04:00
Geert Bevin 39f1456d12 Wrapper fix to the default bld properties repositories 2023-08-10 23:43:09 -04:00
Geert Bevin 2ed5b4b388 Updated Discord link 2023-05-12 21:32:00 -04:00
Geert Bevin 502dd2231c Updated RIFE2 blueprint dependency version to 1.7.0 2023-05-12 17:03:58 -04:00
Geert Bevin c1531b58e4 Updated version to 1.7.1-SNAPSHOT 2023-05-12 17:03:32 -04:00
Geert Bevin 978e50e827 Minor readme tweak 2023-05-12 16:53:45 -04:00
211 changed files with 20398 additions and 3820 deletions

View file

@ -0,0 +1,12 @@
{
"name": "Java",
"image": "mcr.microsoft.com/devcontainers/java:1-21",
"features": {
"ghcr.io/devcontainers/features/java:1": {
"version": "none",
"installMaven": "false",
"installGradle": "false"
}
}
}

View file

@ -2,8 +2,11 @@ name: bld-ci
on: [push, pull_request, workflow_dispatch] on: [push, pull_request, workflow_dispatch]
env:
REPORTS_DIR: "build/test-results/test/"
jobs: jobs:
build-bld-project: build-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
services: services:
@ -87,24 +90,113 @@ jobs:
strategy: strategy:
matrix: matrix:
java-version: [ 17, 19 ] java-version: [ 17, 20, 21, 22, 23, 24, 25 ]
steps: steps:
- name: Checkout source repository - name: Checkout source repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
clean: true
submodules: 'true' submodules: 'true'
fetch-depth: 0 fetch-depth: 0
- name: Set up JDK ${{ matrix.java-version }} - name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'corretto'
java-version: ${{ matrix.java-version }} java-version: ${{ matrix.java-version }}
check-latest: true
- name: Download dependencies
run: ./bld clean download
- name: Compile source
run: ./bld compile
- name: Run tests - name: Run tests
id: tests
run: >- run: >-
./bld download compile test ./bld test
-Dtest.postgres=true -Dtest.mysql=true -Dtest.mariadb=true -Dtest.oracle=true -Dtest.oracle-free=true -Dtest.postgres=true -Dtest.mysql=true -Dtest.mariadb=true -Dtest.oracle=true -Dtest.oracle-free=true
-DtestsBadgeUrl=https://rife2.com/tests-badge/update/com.uwyn.rife2/bld -DtestsBadgeUrl=https://rife2.com/tests-badge/update/com.uwyn.rife2/bld
-DtestsBadgeApiKey=${{ secrets.TESTS_BADGE_API_KEY }} -DtestsBadgeApiKey=${{ secrets.TESTS_BADGE_API_KEY }}
--reports-dir=${{ env.REPORTS_DIR }}
- name: Run reporter
if: always() && steps.tests.outcome == 'failure'
run: ./bld reporter --all
build-macos:
runs-on: macos-latest
strategy:
matrix:
java-version: [ 17, 20, 21, 22, 23, 24, 25 ]
steps:
- name: Checkout source repository
uses: actions/checkout@v4
with:
clean: true
submodules: 'true'
fetch-depth: 0
- name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: ${{ matrix.java-version }}
check-latest: true
- name: Download dependencies
run: ./bld clean download
- name: Compile source
run: ./bld compile
- name: Run tests
id: tests
run: ./bld test --reports-dir=${{ env.REPORTS_DIR }}
- name: Run reporter
if: always() && steps.tests.outcome == 'failure'
run: ./bld reporter --all
build-windows:
runs-on: windows-latest
strategy:
matrix:
java-version: [ 17, 20, 21, 22, 23, 24, 25 ]
steps:
- name: Configure git line endings
run: git config --global core.autocrlf input
- name: Checkout source repository
uses: actions/checkout@v4
with:
clean: true
submodules: 'true'
fetch-depth: 0
- name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: ${{ matrix.java-version }}
check-latest: true
- name: Download dependencies
run: .\bld.bat clean download
- name: Compile source
run: .\bld.bat compile
- name: Run tests
id: tests
run: .\bld.bat test --reports-dir=${{ env.REPORTS_DIR }}
- name: Run reporter
if: always() && steps.tests.outcome == 'failure'
run: .\bld.bat reporter --all

View file

@ -30,29 +30,30 @@ jobs:
steps: steps:
- name: Checkout source repository - name: Checkout source repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
clean: true
submodules: 'true' submodules: 'true'
fetch-depth: 0 fetch-depth: 0
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'zulu' distribution: 'corretto'
java-version: 17 java-version: 17
- name: Build Javadocs - name: Build Javadocs
run: ./bld download clean compile javadoc run: ./bld clean download clean compile javadoc
- name: Setup Pages - name: Setup Pages
uses: actions/configure-pages@v3 uses: actions/configure-pages@v5
- name: Upload artifact - name: Upload artifact
uses: actions/upload-pages-artifact@v1 uses: actions/upload-pages-artifact@v3
with: with:
# Upload generated Javadocs repository # Upload generated Javadocs repository
path: 'build/javadoc/' path: 'build/javadoc/'
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
id: deployment id: deployment
uses: actions/deploy-pages@v1 uses: actions/deploy-pages@v4

View file

@ -10,8 +10,8 @@
<sourceFolder url="file://$MODULE_DIR$/build/generated" isTestSource="false" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/build/generated" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/core/src/main/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/core/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/core/src/test/java" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/core/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/core/src/main/resources/templates" /> <sourceFolder url="file://$MODULE_DIR$/core/src/main/resources" type="java-resource" relativeOutputPath="resources" />
<excludeFolder url="file://$MODULE_DIR$/src/main/resources/templates" /> <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" relativeOutputPath="resources" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
@ -27,6 +27,5 @@
<orderEntry type="library" name="compile" level="project" /> <orderEntry type="library" name="compile" level="project" />
<orderEntry type="library" scope="RUNTIME" name="runtime" level="project" /> <orderEntry type="library" scope="RUNTIME" name="runtime" level="project" />
<orderEntry type="library" scope="TEST" name="test" level="project" /> <orderEntry type="library" scope="TEST" name="test" level="project" />
<orderEntry type="module" module-name="bld" />
</component> </component>
</module> </module>

8
.idea/bld.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BldConfiguration">
<events>
<executeOn event="beforeCompilation" command="generate-grammar" />
</events>
</component>
</project>

View file

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="OctalLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View file

@ -2,11 +2,12 @@
<library name="bld"> <library name="bld">
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$/lib/bld" /> <root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-1.7.0.jar!/" /> <root url="jar://$USER_HOME$/.bld/dist/bld-2.3.0.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="jar://$USER_HOME$/.bld/dist/bld-1.7.0-sources.jar!/" /> <root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.3.0-sources.jar!/" />
</SOURCES> </SOURCES>
<excluded> <excluded>
<root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" />

View file

@ -2,12 +2,16 @@
<library name="compile"> <library name="compile">
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$/lib/compile" /> <root url="file://$PROJECT_DIR$/lib/compile" />
<root url="file://$PROJECT_DIR$/lib/provided" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/compile" /> <root url="file://$PROJECT_DIR$/lib/compile" />
<root url="file://$PROJECT_DIR$/lib/provided" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" /> <jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/provided" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/provided" recursive="true" type="SOURCES" />
</library> </library>
</component> </component>

View file

@ -3,12 +3,13 @@
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$/lib/runtime" /> <root url="file://$PROJECT_DIR$/lib/runtime" />
<root url="file://$PROJECT_DIR$/src/main/resources" /> <root url="file://$PROJECT_DIR$/src/main/resources" />
<root url="file://$PROJECT_DIR$/core/src/main/resources" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/runtime" /> <root url="file://$PROJECT_DIR$/lib/runtime" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" /> <jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" type="SOURCES" />
</library> </library>
</component> </component>

View file

@ -2,14 +2,18 @@
<library name="test"> <library name="test">
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$/lib/test" /> <root url="file://$PROJECT_DIR$/lib/test" />
<root url="file://$PROJECT_DIR$/lib/provided" />
<root url="file://$PROJECT_DIR$/src/test/resources" /> <root url="file://$PROJECT_DIR$/src/test/resources" />
<root url="file://$PROJECT_DIR$/core/src/test/resources" /> <root url="file://$PROJECT_DIR$/core/src/test/resources" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/test" /> <root url="file://$PROJECT_DIR$/lib/test" />
<root url="file://$PROJECT_DIR$/lib/provided" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" /> <jarDirectory url="file://$PROJECT_DIR$/lib/provided" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/provided" recursive="true" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" type="SOURCES" />
</library> </library>
</component> </component>

View file

@ -1,9 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0">
<entry_point TYPE="field" FQNAME="rife.bld.operations.JpackageOptions.PackageType APP_IMAGE" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JpackageOptions.PackageType DMG" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JpackageOptions.PackageType MSI" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JpackageOptions.PackageType PKG" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JpackageOptions.PackageType RPM" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JlinkOptions.CompressionLevel CONSTANT_STRING_SHARING" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JlinkOptions.CompressionLevel NO_COMPRESSION" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JlinkOptions.Endian LITTLE" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JmodOperation.OperationMode EXTRACT" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JmodOperation.OperationMode HASH" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JmodOptions.ResolvedReason DEPRECATED_FOR_REMOVAL" />
<entry_point TYPE="field" FQNAME="rife.bld.operations.JmodOptions.ResolvedReason INCUBATING" />
</entry_points>
<pattern value="rife.bld.operations.JpackageOptions.PackageType" />
<pattern value="rife.bld.operations.JlinkOptions.CompressionLevel" />
<pattern value="rife.bld.operations.JlinkOptions.Endian" />
<pattern value="rife.bld.operations.JmodOperation.OperationMode" />
<pattern value="rife.bld.operations.JmodOptions.ResolvedReason" />
</component>
<component name="PDMPlugin"> <component name="PDMPlugin">
<option name="skipTestSources" value="false" /> <option name="skipTestSources" value="false" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="19" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build" /> <output url="file://$PROJECT_DIR$/build" />
</component> </component>
</project> </project>

View file

@ -1,6 +1,7 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run Tests" type="JUnit" factoryName="JUnit"> <configuration default="false" name="Run all tests" type="JUnit" factoryName="JUnit">
<module name="app" /> <module name="app" />
<useClassPathOnly />
<option name="PACKAGE_NAME" value="rife" /> <option name="PACKAGE_NAME" value="rife" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />

View file

@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run bld tests" type="JUnit" factoryName="JUnit">
<module name="app" />
<useClassPathOnly />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="rife.bld.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="PACKAGE_NAME" value="rife.bld" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
<dir value="$PROJECT_DIR$/src/test/java" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

6
.idea/scala_compiler.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ScalaCompilerConfiguration">
<option name="separateProdTestSources" value="false" />
</component>
</project>

20
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,20 @@
# Contributing
If you want to contribute to `bld` or customize it, all you have to do is clone the GitHub
repository and update the [RIFE2/core](https://github.com/rife2/rife2-core) submodule:
```console
git clone git@github.com:rife2/bld.git
cd bld
git submodule init
git submodule update
```
Then use `bld` to build itself:
```console
./bld compile
```
The project has an IntelliJ IDEA project structure. You can just open it after all
the dependencies were downloaded and peruse the code.

View file

@ -1,8 +1,9 @@
[![License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Java](https://img.shields.io/badge/java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) [![Java](https://img.shields.io/badge/java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
[![bld](https://img.shields.io/badge/2.3.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld)
[![Release](https://img.shields.io/github/release/rife2/bld.svg)](https://github.com/rife2/bld/releases/latest) [![Release](https://img.shields.io/github/release/rife2/bld.svg)](https://github.com/rife2/bld/releases/latest)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.uwyn.rife2/bld/badge.svg?color=blue)](https://maven-badges.herokuapp.com/maven-central/com.uwyn.rife2/bld) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.uwyn.rife2/bld/badge.svg?color=blue)](https://maven-badges.herokuapp.com/maven-central/com.uwyn.rife2/bld)
[![Nexus Snapshot](https://img.shields.io/nexus/s/com.uwyn.rife2/bld?server=https%3A%2F%2Fs01.oss.sonatype.org%2F)](https://s01.oss.sonatype.org/content/repositories/snapshots/com/uwyn/rife2/bld/) [![GitHub Snapshot](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Fcentral.sonatype.com%2Frepository%2Fmaven-snapshots%2Fcom%2Fuwyn%2Frife2%2Fbld%2Fmaven-metadata.xml)](https://github.com/rife2/bld/packages/2214741/versions)
[![gradle-ci](https://github.com/rife2/bld/actions/workflows/bld.yml/badge.svg)](https://github.com/rife2/bld/actions/workflows/bld.yml) [![gradle-ci](https://github.com/rife2/bld/actions/workflows/bld.yml/badge.svg)](https://github.com/rife2/bld/actions/workflows/bld.yml)
[![Tests](https://rife2.com/tests-badge/badge/com.uwyn.rife2/bld)](https://github.com/rife2/rife2/actions/workflows/bld.yml) [![Tests](https://rife2.com/tests-badge/badge/com.uwyn.rife2/bld)](https://github.com/rife2/rife2/actions/workflows/bld.yml)
@ -33,7 +34,8 @@ bld relies on Java 17 and leverages many of the features that this version of
Java provides. Thanks to the modern language constructs, your Java build logic Java provides. Thanks to the modern language constructs, your Java build logic
ends up looking very concise, is easily readable and understood by any IDE. ends up looking very concise, is easily readable and understood by any IDE.
You automatically get support for auto-completion and javadoc documentation, You automatically get support for auto-completion and javadoc documentation,
and you can split your build logic into multiple files and classes when you outgrow a single file. and you can split your build logic into multiple files and classes when you
outgrow a single file.
Here is a complete bld file for a Java application using JUnit 5 for its tests. Here is a complete bld file for a Java application using JUnit 5 for its tests.
Nothing else is needed to be able to run it, test it and distribute it: Nothing else is needed to be able to run it, test it and distribute it:
@ -46,34 +48,29 @@ import java.util.List;
import static rife.bld.dependencies.Repository.*; import static rife.bld.dependencies.Repository.*;
import static rife.bld.dependencies.Scope.*; import static rife.bld.dependencies.Scope.*;
public class MyappBuild extends Project { public class MyAppBuild extends Project {
public MyappBuild() { public MyAppBuild() {
pkg = "com.example"; pkg = "com.example";
name = "Myapp"; name = "my-app";
mainClass = "com.example.MyappMain"; mainClass = "com.example.MyApp";
version = version(0,1,0); version = version(0,1,0);
downloadSources = true; downloadSources = true;
repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES); repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES);
scope(test) scope(test)
.include(dependency("org.junit.jupiter", .include(dependency("org.junit.jupiter", "junit-jupiter", version(5,11,4)))
"junit-jupiter", .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1,11,4)));
version(5,9,2)))
.include(dependency("org.junit.platform",
"junit-platform-console-standalone",
version(1,9,2)));
} }
public static void main(String[] args) { public static void main(String[] args) {
new MyappBuild().start(args); new MyAppBuild().start(args);
} }
} }
``` ```
> **NOTE:** `bld` supports different ways to describe dependencies, > **NOTE:** `bld` supports different ways to describe dependencies,
> `dependency("com.uwyn.rife2", "rife2", version(1,6,3))` can for instance also > `dependency("org.junit.jupiter", "junit-jupiter", version(5,11,4))` can for instance also
> be written as `dependency("com.uwyn.rife2:rife2:1.6.3")`. Which format you use, > be written as `dependency("org.junit.jupiter:junit-jupiter:5.11.4")`. Which format you use,
> is a matter of personal taste. > is a matter of personal taste.
# Where does `bld` fit? # Where does `bld` fit?
@ -94,15 +91,47 @@ significantly reduces the cognitive load, and taking actions immediately
without having to mentally construct a described plan, makes it easier to without having to mentally construct a described plan, makes it easier to
reason about your build. reason about your build.
# IDE support
<img src="https://rife2.com/images/bld-idea.png" style="width: 100%">
Since version 2.0, bld comes with its own [IntelliJ IDEA plugin](https://github.com/rife2/bld-idea):
* detect `bld` projects and find their main Java class
* quick access to open and edit the main Java class and wrapper properties of `bld` projects
* list all the commands in `bld` projects in a side panel
* execute one or multiple commands in the order they were selected
* reload the commands in the `bld` project
* terminate currently running `bld` commands
* `bld` console panel for command output with source code hyperlinking
* display the `bld` dependency tree
* toggle to run `bld` in offline or online mode
* auto-save all open files before executing a `bld` command
* convenient `bld` one-click cache invalidation
* set `bld` commands to run before or after IDEA compilation
* create custom `bld` command run configuration with options, JVM arguments, and before launch tasks
* assign keyboard shortcuts to `bld` commands
# Find out more # Find out more
`bld` lets your build logic get out of the way so that you can focus on writing `bld` lets your build logic get out of the way so that you can focus on writing
applications. applications.
If you have any questions, suggestions, ideas or just want to chat, feel free Get started immediately by [installing](https://github.com/rife2/bld/wiki/Installation) `bld`
to post on the [forums](https://github.com/rife2/bld/discussions), to join through Homebrew, SDKMAN!, JBang, zip archive, or run it directly from its jar file.
me on [Discord](https://discord.gg/DZRYPtkb6J) or to connect with me on
[Mastodon](https://uwyn.net/@gbevin).
**Read more in the [full documentation](https://github.com/rife2/bld/wiki) If you merely want to create a new project, `bld` can also be used by executing this one-liner:
and [bld Javadocs](https://rife2.github.io/bld/).**
```console
bash -c "$(curl -fsSL https://rife2.com/bld/create.sh)"
```
If you have any questions, suggestions, ideas or just want to chat, feel free
to post on the [forums](https://forum.uwyn.com) or to join us on [Discord](https://discord.gg/zDG6anEXQX).
Read more in the [full documentation](https://github.com/rife2/bld/wiki) and [bld Javadocs](https://rife2.github.io/bld/).
# Contributing
See [CONTIBUTING.md](https://github.com/rife2/bld?tab=contributing-ov-file#readme) for information about
contributing to this project.

2
core

@ -1 +1 @@
Subproject commit 31b722572483047afe80cb05bc0eef6d571a18a4 Subproject commit fa567721c00d99626ed439db4f0340eadff0ec03

Binary file not shown.

View file

@ -1,9 +1,12 @@
bld.downloadExtensionJavadoc=false bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true bld.downloadExtensionSources=true
bld.extension-antlr=com.uwyn.rife2:bld-antlr4:1.2.0
bld.extension-archive=com.uwyn.rife2:bld-archive:0.4.0
bld.extension-tests=com.uwyn.rife2:bld-tests-badge:1.4.0
bld.repositories=MAVEN_CENTRAL,RIFE2_RELEASES
bld.downloadLocation= bld.downloadLocation=
bld.extension-antlr=com.uwyn.rife2:bld-antlr4:1.4.3
bld.extension-archive=com.uwyn.rife2:bld-archive:0.6.3
bld.extension-reporter=com.uwyn.rife2:bld-junit-reporter:0.9.2
bld.extension-tests=com.uwyn.rife2:bld-tests-badge:1.6.3
bld.javaOptions=
bld.javacOptions=
bld.repositories=MAVEN_CENTRAL,RIFE2_RELEASES
bld.sourceDirectories=core/src/bld/java bld.sourceDirectories=core/src/bld/java
bld.version=1.7.0 bld.version=2.3.0

1
local.properties Normal file
View file

@ -0,0 +1 @@
bld.repo.github=https://maven.pkg.github.com/rife2/bld

View file

@ -6,6 +6,8 @@ package rife;
import rife.bld.BuildCommand; import rife.bld.BuildCommand;
import rife.bld.Cli; import rife.bld.Cli;
import rife.bld.dependencies.VersionNumber;
import rife.bld.extension.JUnitReporterOperation;
import rife.bld.extension.ZipOperation; import rife.bld.extension.ZipOperation;
import rife.bld.operations.*; import rife.bld.operations.*;
import rife.bld.publish.*; import rife.bld.publish.*;
@ -28,39 +30,42 @@ public class BldBuild extends AbstractRife2Build {
throws Exception { throws Exception {
name = "bld"; name = "bld";
mainClass = "rife.bld.Cli"; mainClass = "rife.bld.Cli";
version = version(FileUtils.readString(new File(srcMainResourcesDirectory(), "BLD_VERSION"))); version = VersionNumber.parse(FileUtils.readString(new File(srcMainResourcesDirectory(), "BLD_VERSION")));
repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES); repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES);
scope(test) scope(test)
.include(dependency("org.json", "json", version(20230227))); .include(dependency("org.json", "json", version(20250517)));
var core_directory = new File(workDirectory(), "core"); var core_dir = new File(workDirectory(), "core");
var core_src_directory = new File(core_directory, "src"); var core_src_dir = new File(core_dir, "src");
var core_src_main_directory = new File(core_src_directory, "main"); var core_src_main_dir = new File(core_src_dir, "main");
var core_src_main_java_directory = new File(core_src_main_directory, "java");
var core_src_main_resources_directory = new File(core_src_main_directory, "resources");
var core_src_test_directory = new File(core_src_directory, "test");
var core_src_test_java_directory = new File(core_src_test_directory, "java");
var core_src_test_resources_directory = new File(core_src_test_directory, "resources");
var core_src_main_resources_templates_directory = new File(core_src_main_resources_directory, "templates");
antlr4Operation antlr4Operation
.sourceDirectories(List.of(new File(core_src_main_directory, "antlr"))) .sourceDirectories(List.of(new File(core_src_main_dir, "antlr")));
.outputDirectory(new File(buildDirectory(), "generated/rife/template/antlr"));
precompileOperation() var core_src_test_dir = new File(core_src_dir, "test");
.sourceDirectories(core_src_main_resources_templates_directory) var core_src_test_java_dir = new File(core_src_test_dir, "java");
.templateTypes(HTML, XML, SQL, TXT, JSON); var core_src_main_java_dir = new File(core_src_main_dir, "java");
compileOperation() compileOperation()
.mainSourceDirectories(antlr4Operation.outputDirectory(), core_src_main_java_directory) .mainSourceDirectories(antlr4Operation.outputDirectory(), core_src_main_java_dir)
.testSourceDirectories(core_src_test_java_directory) .testSourceDirectories(core_src_test_java_dir)
.compileOptions() .compileOptions()
.debuggingInfo(JavacOptions.DebuggingInfo.ALL); .debuggingInfo(JavacOptions.DebuggingInfo.ALL)
.addAll(List.of("-encoding", "UTF-8"));
var core_src_main_resources_dir = new File(core_src_main_dir, "resources");
var core_src_main_resources_templates_dir = new File(core_src_main_resources_dir, "templates");
precompileOperation()
.sourceDirectories(core_src_main_resources_templates_dir)
.templateTypes(HTML, XML, SQL, TXT, JSON);
var core_src_test_resources_dir = new File(core_src_test_dir, "resources");
jarOperation() jarOperation()
.sourceDirectories(core_src_main_resources_directory) .sourceDirectories(core_src_main_resources_dir)
.excluded(Pattern.compile("^\\Q" + core_src_main_resources_templates_directory.getAbsolutePath() + "\\E.*")) .excluded(Pattern.compile("^\\Q" + core_src_main_resources_templates_dir.getAbsolutePath() + "\\E.*"))
.manifestAttribute(Attributes.Name.MAIN_CLASS, mainClass()); .manifestAttribute(Attributes.Name.MAIN_CLASS, mainClass());
zipBldOperation zipBldOperation
@ -68,18 +73,22 @@ public class BldBuild extends AbstractRife2Build {
.destinationFileName("bld-" + version() + ".zip"); .destinationFileName("bld-" + version() + ".zip");
testsBadgeOperation testsBadgeOperation
.classpath(core_src_main_resources_directory.getAbsolutePath()) .classpath(core_src_main_resources_dir.getAbsolutePath())
.classpath(core_src_test_resources_directory.getAbsolutePath()); .classpath(core_src_test_resources_dir.getAbsolutePath());
javadocOperation() javadocOperation()
.sourceFiles(FileUtils.getJavaFileList(core_src_main_java_directory)) .sourceFiles(FileUtils.getJavaFileList(core_src_main_java_dir))
.javadocOptions() .javadocOptions()
.docTitle("<a href=\"https://rife2.com/bld\">bld</a> " + version()) .docTitle("<a href=\"https://rife2.com/bld\">bld</a> " + version())
.overview(new File(srcMainJavaDirectory(), "overview.html")); .overview(new File(srcMainJavaDirectory(), "overview.html"))
.addAll(List.of("--allow-script-in-comments",
"-group", "bld", "rife.bld*",
"-group", "RIFE2/core", "rife:rife.cmf*:rife.config*:rife.database*:rife.datastructures*:rife.engine*:rife.forms*:rife.instrument*:rife.ioc*:rife.resources*:rife.selector*:rife.template*:rife.tools*:rife.validation*:rife.xml*"));
publishOperation() publishOperation()
.repository(version.isSnapshot() ? repository("rife2-snapshots") : repository("rife2-releases")) .repository(version.isSnapshot() ? repository("rife2-snapshots") : repository("rife2-releases"))
.repository(version.isSnapshot() ? repository("sonatype-snapshots") : repository("sonatype-releases")) .repository(version.isSnapshot() ? repository("central-snapshots") : repository("central-releases"))
.repository(repository("github"))
.info(new PublishInfo() .info(new PublishInfo()
.groupId("com.uwyn.rife2") .groupId("com.uwyn.rife2")
.artifactId("bld") .artifactId("bld")
@ -104,7 +113,6 @@ public class BldBuild extends AbstractRife2Build {
new PublishArtifact(zipBldOperation.destinationFile(), "", "zip")); new PublishArtifact(zipBldOperation.destinationFile(), "", "zip"));
} }
final ZipOperation zipBldOperation = new ZipOperation(); final ZipOperation zipBldOperation = new ZipOperation();
@BuildCommand(value = "zip-bld", summary = "Creates the bld zip archive") @BuildCommand(value = "zip-bld", summary = "Creates the bld zip archive")
public void zipBld() public void zipBld()
@ -132,11 +140,9 @@ public class BldBuild extends AbstractRife2Build {
f.perms(0755); f.perms(0755);
}); });
}); });
b.dir("lib", l -> { b.dir("lib", l -> l.file("bld-wrapper.jar", f -> f.move(path(tmp, "lib", "bld", "bld-wrapper.jar"))));
l.file("bld-wrapper.jar", f -> f.move(path(tmp, "lib", "bld", "bld-wrapper.jar")));
}); });
}); t.dir("lib", DirBuilder::delete);
t.dir("lib", l -> l.delete());
}); });
zipBldOperation zipBldOperation
@ -156,6 +162,14 @@ public class BldBuild extends AbstractRife2Build {
zipBld(); zipBld();
} }
@BuildCommand(summary = "Runs the JUnit reporter")
public void reporter() throws Exception {
new JUnitReporterOperation()
.fromProject(this)
.failOnSummary(true)
.execute();
}
public void publish() public void publish()
throws Exception { throws Exception {
all(); all();

View file

@ -0,0 +1,58 @@
/**
* bld is a new build system that allows you to write your build logic in pure Java.
* <p>
* More information can be found on the <a href="https://rife2.com/bld"><code>bld</code> website</a>.
* <p>
* Note that bld builds on top of the foundation that RIFE2 provides and includes the features
* of <a href="https://github.com/rife2/rife2-core">RIFE2/core</a>.
*
* @since 2.1.0
*/
module rife.bld {
requires java.compiler;
requires java.desktop;
requires java.logging;
requires java.net.http;
requires java.prefs;
requires static java.sql;
requires java.xml;
exports rife.bld;
exports rife.bld.blueprints;
exports rife.bld.dependencies;
exports rife.bld.dependencies.exceptions;
exports rife.bld.help;
exports rife.bld.instrument;
exports rife.bld.operations;
exports rife.bld.operations.exceptions;
exports rife.bld.publish;
exports rife;
exports rife.cmf;
exports rife.cmf.transform;
exports rife.config;
exports rife.config.exceptions;
exports rife.database;
exports rife.database.exceptions;
exports rife.database.queries;
exports rife.database.querymanagers.generic;
exports rife.database.querymanagers.generic.exceptions;
exports rife.database.types;
exports rife.datastructures;
exports rife.engine;
exports rife.forms;
exports rife.ioc;
exports rife.ioc.exceptions;
exports rife.resources;
exports rife.resources.exceptions;
exports rife.selector;
exports rife.template;
exports rife.template.exceptions;
exports rife.tools;
exports rife.tools.exceptions;
exports rife.validation;
exports rife.validation.annotations;
exports rife.validation.exceptions;
exports rife.xml;
exports rife.xml.exceptions;
}

View file

@ -0,0 +1,24 @@
<html>
<body>
<p><code>bld</code> is a new build system that allows you to write your build logic in pure Java.</p>
<p><code>bld</code>'s website is <a href="https://rife2.com/bld">https://rife2.com/bld</a>.</p>
<p>The GitHub project is at <a href="https://github.com/rife2/bld">https://github.com/rife2/bld</a></p>
<p>The documentation is available at <a href="https://github.com/rife2/bld/wiki">https://github.com/rife2/bld/wiki</a></p>
<p>Note that bld builds on top of the foundation that RIFE2 provides and includes the features of
<a href="https://github.com/rife2/rife2-core">RIFE2/core</a>.</p>
<script type="text/javascript">
window.onload = function () {
show('all-packages-table', 'all-packages-table-tab1', 2);
};
</script>
<style>
#all-packages-table-tab0 {
display: none;
}
</style>
</body>
</html>

View file

@ -5,20 +5,17 @@
package rife.bld; package rife.bld;
import rife.bld.dependencies.*; import rife.bld.dependencies.*;
import rife.bld.dependencies.Module;
import rife.bld.help.*; import rife.bld.help.*;
import rife.bld.operations.*; import rife.bld.operations.*;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import rife.tools.StringUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File; import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*; import java.util.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static rife.bld.dependencies.Scope.runtime; import static rife.bld.dependencies.Scope.runtime;
import static rife.bld.dependencies.VersionNumber.SNAPSHOT_QUALIFIER;
import static rife.tools.FileUtils.JAR_FILE_PATTERN; import static rife.tools.FileUtils.JAR_FILE_PATTERN;
/** /**
@ -58,12 +55,19 @@ public class BaseProject extends BuildExecutor {
*/ */
protected VersionNumber version = null; protected VersionNumber version = null;
/** /**
* The project's main class. * The project's main class to execute.
* *
* @see #mainClass() * @see #mainClass()
* @since 1.5 * @since 1.5
*/ */
protected String mainClass = null; protected String mainClass = null;
/**
* The project's module to execute.
*
* @see #module()
* @since 2.1
*/
protected String module = null;
/** /**
* The project's repositories for dependency resolution. * The project's repositories for dependency resolution.
@ -249,6 +253,27 @@ public class BaseProject extends BuildExecutor {
* @since 1.5 * @since 1.5
*/ */
protected File libCompileDirectory = null; protected File libCompileDirectory = null;
/**
* The modules compile scope lib directory.
*
* @see #libCompileModulesDirectory()
* @since 2.1
*/
protected File libCompileModulesDirectory = null;
/**
* The provided scope lib directory.
*
* @see #libProvidedDirectory()
* @since 1.8
*/
protected File libProvidedDirectory = null;
/**
* The modules provided scope lib directory.
*
* @see #libProvidedModulesDirectory()
* @since 2.1
*/
protected File libProvidedModulesDirectory = null;
/** /**
* The runtime scope lib directory. * The runtime scope lib directory.
* *
@ -256,6 +281,13 @@ public class BaseProject extends BuildExecutor {
* @since 1.5 * @since 1.5
*/ */
protected File libRuntimeDirectory = null; protected File libRuntimeDirectory = null;
/**
* The modules runtime scope lib directory.
*
* @see #libRuntimeModulesDirectory()
* @since 2.1
*/
protected File libRuntimeModulesDirectory = null;
/** /**
* The standalone scope lib directory. * The standalone scope lib directory.
* *
@ -264,12 +296,26 @@ public class BaseProject extends BuildExecutor {
*/ */
protected File libStandaloneDirectory = null; protected File libStandaloneDirectory = null;
/** /**
* The standalone scope lib directory. * The modules standalone scope lib directory.
*
* @see #libStandaloneModulesDirectory()
* @since 2.1
*/
protected File libStandaloneModulesDirectory = null;
/**
* The test scope lib directory.
* *
* @see #libTestDirectory() * @see #libTestDirectory()
* @since 1.5 * @since 1.5
*/ */
protected File libTestDirectory = null; protected File libTestDirectory = null;
/**
* The modules test scope lib directory.
*
* @see #libTestModulesDirectory()
* @since 2.1
*/
protected File libTestModulesDirectory = null;
/** /**
* The build directory. * The build directory.
* *
@ -680,8 +726,44 @@ public class BaseProject extends BuildExecutor {
* {@link VersionNumber#UNKNOWN} if the description couldn't be parsed * {@link VersionNumber#UNKNOWN} if the description couldn't be parsed
* @since 1.5 * @since 1.5
*/ */
public VersionNumber version(String description) { public Version version(String description) {
return VersionNumber.parse(description); return Version.parse(description);
}
/**
* Creates a new snapshot version instance.
*
* @param major the major component of the snapshot version number
* @return a newly created snapshot {@code VersionNumber} instance
* @since 1.7.4
*/
public VersionNumber snapshot(int major) {
return new VersionNumber(major, null, null, SNAPSHOT_QUALIFIER);
}
/**
* Creates a new snapshot version instance.
*
* @param major the major component of the snapshot version number
* @param minor the minor component of the snapshot version number
* @return a newly created snapshot {@code VersionNumber} instance
* @since 1.7.4
*/
public VersionNumber snapshot(int major, int minor) {
return new VersionNumber(major, minor, null, SNAPSHOT_QUALIFIER);
}
/**
* Creates a new snapshot version instance.
*
* @param major the major component of the snapshot version number
* @param minor the minor component of the snapshot version number
* @param revision the revision component of the snapshot version number
* @return a newly created snapshot {@code VersionNumber} instance
* @since 1.7.4
*/
public VersionNumber snapshot(int major, int minor, int revision) {
return new VersionNumber(major, minor, revision, SNAPSHOT_QUALIFIER);
} }
/** /**
@ -759,7 +841,7 @@ public class BaseProject extends BuildExecutor {
* @return a newly created {@code Dependency} instance * @return a newly created {@code Dependency} instance
* @since 1.5 * @since 1.5
*/ */
public Dependency dependency(String groupId, String artifactId, VersionNumber version) { public Dependency dependency(String groupId, String artifactId, Version version) {
return new Dependency(groupId, artifactId, version); return new Dependency(groupId, artifactId, version);
} }
@ -773,7 +855,7 @@ public class BaseProject extends BuildExecutor {
* @return a newly created {@code Dependency} instance * @return a newly created {@code Dependency} instance
* @since 1.5 * @since 1.5
*/ */
public Dependency dependency(String groupId, String artifactId, VersionNumber version, String classifier) { public Dependency dependency(String groupId, String artifactId, Version version, String classifier) {
return new Dependency(groupId, artifactId, version, classifier); return new Dependency(groupId, artifactId, version, classifier);
} }
@ -788,7 +870,7 @@ public class BaseProject extends BuildExecutor {
* @return a newly created {@code Dependency} instance * @return a newly created {@code Dependency} instance
* @since 1.5 * @since 1.5
*/ */
public Dependency dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type) { public Dependency dependency(String groupId, String artifactId, Version version, String classifier, String type) {
return new Dependency(groupId, artifactId, version, classifier, type); return new Dependency(groupId, artifactId, version, classifier, type);
} }
@ -821,6 +903,101 @@ public class BaseProject extends BuildExecutor {
return new LocalDependency(path); return new LocalDependency(path);
} }
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId) {
return new Module(groupId, artifactId);
}
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @param version the module version
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId, String version) {
return new Module(groupId, artifactId, version(version));
}
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @param version the module version
* @param classifier the module classifier
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId, String version, String classifier) {
return new Module(groupId, artifactId, version(version), classifier);
}
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @param version the module version
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId, Version version) {
return new Module(groupId, artifactId, version);
}
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @param version the module version
* @param classifier the module classifier
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId, Version version, String classifier) {
return new Module(groupId, artifactId, version, classifier);
}
/**
* Creates a new module instance from a string representation.
* The format is {@code groupId:artifactId:version:classifier}.
* The {@code version} and {@code classifier} are optional.
* <p>
* If the string can't be successfully parsed, {@code null} will be returned.
*
* @param description the module string to parse
* @return a parsed instance of {@code Module}; or
* {@code null} when the string couldn't be parsed
* @since 2.1
*/
public Module module(String description) {
return Module.parse(description);
}
/**
* Creates a local module instance.
* <p>
* If the local module points to a directory, it will be scanned for jar files.
*
* @param path the file system path of the local module
* @since 2.1
*/
public LocalModule localModule(String path) {
return new LocalModule(path);
}
/* /*
* Project directories * Project directories
*/ */
@ -973,6 +1150,36 @@ public class BaseProject extends BuildExecutor {
return Objects.requireNonNullElseGet(libCompileDirectory, () -> new File(libDirectory(), "compile")); return Objects.requireNonNullElseGet(libCompileDirectory, () -> new File(libDirectory(), "compile"));
} }
/**
* Returns the project modules compile scope lib directory.
* Defaults to {@code "modules"} relative to {@link #libCompileDirectory()}.
*
* @since 2.1
*/
public File libCompileModulesDirectory() {
return Objects.requireNonNullElseGet(libCompileModulesDirectory, () -> new File(libCompileDirectory(), "modules"));
}
/**
* Returns the project provided scope lib directory.
* Defaults to {@code "provided"} relative to {@link #libDirectory()}.
*
* @since 1.8
*/
public File libProvidedDirectory() {
return Objects.requireNonNullElseGet(libProvidedDirectory, () -> new File(libDirectory(), "provided"));
}
/**
* Returns the project modules provided scope lib directory.
* Defaults to {@code "modules"} relative to {@link #libProvidedDirectory()}.
*
* @since 2.1
*/
public File libProvidedModulesDirectory() {
return Objects.requireNonNullElseGet(libProvidedModulesDirectory, () -> new File(libProvidedDirectory(), "modules"));
}
/** /**
* Returns the project runtime scope lib directory. * Returns the project runtime scope lib directory.
* Defaults to {@code "runtime"} relative to {@link #libDirectory()}. * Defaults to {@code "runtime"} relative to {@link #libDirectory()}.
@ -983,6 +1190,16 @@ public class BaseProject extends BuildExecutor {
return Objects.requireNonNullElseGet(libRuntimeDirectory, () -> new File(libDirectory(), "runtime")); return Objects.requireNonNullElseGet(libRuntimeDirectory, () -> new File(libDirectory(), "runtime"));
} }
/**
* Returns the project modules runtime scope lib directory.
* Defaults to {@code "modules"} relative to {@link #libRuntimeDirectory()}.
*
* @since 1.5
*/
public File libRuntimeModulesDirectory() {
return Objects.requireNonNullElseGet(libRuntimeModulesDirectory, () -> new File(libRuntimeDirectory(), "modules"));
}
/** /**
* Returns the project standalone scope lib directory. * Returns the project standalone scope lib directory.
* Defaults to {@code null}. * Defaults to {@code null}.
@ -990,7 +1207,17 @@ public class BaseProject extends BuildExecutor {
* @since 1.5 * @since 1.5
*/ */
public File libStandaloneDirectory() { public File libStandaloneDirectory() {
return null; return libStandaloneDirectory;
}
/**
* Returns the project standalone scope lib directory.
* Defaults to {@code null}.
*
* @since 2.1
*/
public File libStandaloneModulesDirectory() {
return libStandaloneModulesDirectory;
} }
/** /**
@ -1003,6 +1230,16 @@ public class BaseProject extends BuildExecutor {
return Objects.requireNonNullElseGet(libTestDirectory, () -> new File(libDirectory(), "test")); return Objects.requireNonNullElseGet(libTestDirectory, () -> new File(libDirectory(), "test"));
} }
/**
* Returns the project modules test scope lib directory.
* Defaults to {@code "modules"} relative to {@link #libTestDirectory()}.
*
* @since 2.1
*/
public File libTestModulesDirectory() {
return Objects.requireNonNullElseGet(libTestModulesDirectory, () -> new File(libTestDirectory(), "modules"));
}
/** /**
* Returns the project build directory. * Returns the project build directory.
* Defaults to {@code "build"} relative to {@link #workDirectory()}. * Defaults to {@code "build"} relative to {@link #workDirectory()}.
@ -1093,11 +1330,19 @@ public class BaseProject extends BuildExecutor {
libDirectory().mkdirs(); libDirectory().mkdirs();
libBldDirectory().mkdirs(); libBldDirectory().mkdirs();
libCompileDirectory().mkdirs(); libCompileDirectory().mkdirs();
libCompileModulesDirectory().mkdirs();
libProvidedDirectory().mkdirs();
libProvidedModulesDirectory().mkdirs();
libRuntimeDirectory().mkdirs(); libRuntimeDirectory().mkdirs();
libRuntimeModulesDirectory().mkdirs();
if (libStandaloneDirectory() != null) { if (libStandaloneDirectory() != null) {
libStandaloneDirectory().mkdirs(); libStandaloneDirectory().mkdirs();
} }
if (libStandaloneModulesDirectory() != null) {
libStandaloneModulesDirectory().mkdirs();
}
libTestDirectory().mkdirs(); libTestDirectory().mkdirs();
libTestModulesDirectory().mkdirs();
} }
/** /**
@ -1131,6 +1376,17 @@ public class BaseProject extends BuildExecutor {
return pkg; return pkg;
} }
/**
* Returns whether this project's package was set.
*
* @return {@code true} if the package was set; or
* {@code false} otherwise
* @since 2.2.1
*/
public boolean hasPkg() {
return pkg != null;
}
/** /**
* Returns the project's name. * Returns the project's name.
* *
@ -1143,6 +1399,17 @@ public class BaseProject extends BuildExecutor {
return name; return name;
} }
/**
* Returns whether this project's name was set.
*
* @return {@code true} if the name was set; or
* {@code false} otherwise
* @since 2.2.1
*/
public boolean hasName() {
return name != null;
}
/** /**
* Returns the project's version. * Returns the project's version.
* *
@ -1156,17 +1423,34 @@ public class BaseProject extends BuildExecutor {
} }
/** /**
* Returns the project's main class. * Returns whether this project's version was set.
*
* @return {@code true} if the version was set; or
* {@code false} otherwise
* @since 2.2.1
*/
public boolean hasVersion() {
return version != null;
}
/**
* Returns the project's main class to execute.
* *
* @since 1.5 * @since 1.5
*/ */
public String mainClass() { public String mainClass() {
if (mainClass == null) {
throw new IllegalStateException("The mainClass variable has to be set.");
}
return mainClass; return mainClass;
} }
/**
* Returns the project's module to execute.
*
* @since 2.1
*/
public String module() {
return module;
}
/** /**
* Returns the list of repositories for this project. * Returns the list of repositories for this project.
* <p> * <p>
@ -1282,7 +1566,14 @@ public class BaseProject extends BuildExecutor {
* @since 1.5 * @since 1.5
*/ */
public String uberJarMainClass() { public String uberJarMainClass() {
return Objects.requireNonNullElseGet(uberJarMainClass, this::mainClass); if (uberJarMainClass != null) {
return uberJarMainClass;
}
if (mainClass() != null) {
return mainClass();
}
throw new IllegalStateException("The mainClass variable has to be set.");
} }
/** /**
@ -1362,10 +1653,66 @@ public class BaseProject extends BuildExecutor {
// build the compilation classpath // build the compilation classpath
var classpath = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList()); var classpath = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalDependencies(classpath, Scope.compile); addLocalDependencies(classpath, Scope.compile);
return classpath;
}
/**
* Returns all the jar files that are in the compile scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libCompileModulesDirectory()}
* and adds all the jar files from the compile scope local modules.
*
* @since 2.1
*/
public List<File> compileModulePathJars() {
// detect the jar files in the modules compile lib directory
var dir_abs = libCompileModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
// build the compilation module path
var module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalModules(module_path, Scope.compile);
return module_path;
}
/**
* Returns all the jar files that are in the provided scope classpath.
* <p>
* By default, this collects all the jar files in the {@link #libProvidedDirectory()}
* and adds all the jar files from the provided scope local dependencies.
*
* @since 1.8
*/
public List<File> providedClasspathJars() {
// detect the jar files in the provided lib directory
var dir_abs = libProvidedDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
// build the provided classpath
var classpath = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalDependencies(classpath, Scope.provided); addLocalDependencies(classpath, Scope.provided);
return classpath; return classpath;
} }
/**
* Returns all the jar files that are in the provided scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libProvidedModulesDirectory()}
* and adds all the jar files from the provided scope local modules.
*
* @since 2.1
*/
public List<File> providedModulePathJars() {
// detect the jar files in the modules provided lib directory
var dir_abs = libProvidedModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
// build the provided module path
var module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalModules(module_path, Scope.provided);
return module_path;
}
/** /**
* Returns all the jar files that are in the runtime scope classpath. * Returns all the jar files that are in the runtime scope classpath.
* <p> * <p>
@ -1385,6 +1732,25 @@ public class BaseProject extends BuildExecutor {
return classpath; return classpath;
} }
/**
* Returns all the jar files that are in the runtime scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libRuntimeModulesDirectory()}
* and adds all the jar files from the runtime scope local modules.
*
* @since 2.1
*/
public List<File> runtimeModulePathJars() {
// detect the jar files in the modules runtime lib directory
var dir_abs = libRuntimeModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
// build the runtime module path
var module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalModules(module_path, Scope.runtime);
return module_path;
}
/** /**
* Returns all the jar files that are in the standalone scope classpath. * Returns all the jar files that are in the standalone scope classpath.
* <p> * <p>
@ -1409,6 +1775,30 @@ public class BaseProject extends BuildExecutor {
return classpath; return classpath;
} }
/**
* Returns all the jar files that are in the standalone scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libStandaloneModulesDirectory()}
* and adds all the jar files from the standalone scope local modules.
*
* @since 2.1
*/
public List<File> standaloneModulePathJars() {
// build the standalone classpath
List<File> module_path;
if (libStandaloneModulesDirectory() == null) {
module_path = new ArrayList<>();
} else {
// detect the jar files in the modules standalone lib directory
var dir_abs = libStandaloneModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
}
addLocalModules(module_path, Scope.standalone);
return module_path;
}
/** /**
* Returns all the jar files that are in the test scope classpath. * Returns all the jar files that are in the test scope classpath.
* <p> * <p>
@ -1428,20 +1818,51 @@ public class BaseProject extends BuildExecutor {
return classpath; return classpath;
} }
/**
* Returns all the jar files that are in the test scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libTestModulesDirectory()}
* and adds all the jar files from the test scope local modules.
*
* @since 2.1
*/
public List<File> testModulePathJars() {
// detect the jar files in the test lib directory
var dir_abs = libTestModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
// build the test module path
var module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalModules(module_path, Scope.test);
return module_path;
}
private void addLocalDependencies(List<File> classpath, Scope scope) { private void addLocalDependencies(List<File> classpath, Scope scope) {
if (dependencies.get(scope) == null) { if (dependencies.get(scope) == null) {
return; return;
} }
for (var dependency : dependencies.get(scope).localDependencies()) { for (var dependency : dependencies.get(scope).localDependencies()) {
var local_file = new File(workDirectory(), dependency.path()); addLocalJars(classpath, dependency.path());
}
}
private void addLocalModules(List<File> classpath, Scope scope) {
if (dependencies.get(scope) == null) {
return;
}
for (var module : dependencies.get(scope).localModules()) {
addLocalJars(classpath, module.path());
}
}
private void addLocalJars(List<File> jars, String path) {
var local_file = new File(workDirectory(), path);
if (local_file.exists()) { if (local_file.exists()) {
if (local_file.isDirectory()) { if (local_file.isDirectory()) {
var local_jar_files = FileUtils.getFileList(local_file.getAbsoluteFile(), INCLUDED_JARS, EXCLUDED_JARS); var local_jar_files = FileUtils.getFileList(local_file.getAbsoluteFile(), INCLUDED_JARS, EXCLUDED_JARS);
classpath.addAll(new ArrayList<>(local_jar_files.stream().map(file -> new File(local_file, file)).toList())); jars.addAll(new ArrayList<>(local_jar_files.stream().map(file -> new File(local_file, file)).toList()));
} else { } else {
classpath.add(local_file); jars.add(local_file);
}
} }
} }
} }
@ -1449,18 +1870,29 @@ public class BaseProject extends BuildExecutor {
/** /**
* Returns all the classpath entries for compiling the main sources. * Returns all the classpath entries for compiling the main sources.
* <p> * <p>
* By default, this converts the files from {@link #compileClasspathJars()} to absolute paths. * By default, this converts the files from {@link #compileClasspathJars()} and {@link #providedClasspathJars()} to absolute paths.
* *
* @since 1.5 * @since 1.5
*/ */
public List<String> compileMainClasspath() { public List<String> compileMainClasspath() {
return FileUtils.combineToAbsolutePaths(compileClasspathJars()); return FileUtils.combineToAbsolutePaths(compileClasspathJars(), providedClasspathJars());
}
/**
* Returns all the module path entries for compiling the main sources.
* <p>
* By default, this converts the files from {@link #compileModulePathJars()} and {@link #providedModulePathJars()} to absolute paths.
*
* @since 2.1
*/
public List<String> compileMainModulePath() {
return FileUtils.combineToAbsolutePaths(compileModulePathJars(), providedModulePathJars());
} }
/** /**
* Returns all the classpath entries for compiling the test sources. * Returns all the classpath entries for compiling the test sources.
* <p> * <p>
* By default, this converts the files from {@link #compileClasspathJars()} and * By default, this converts the files from {@link #compileClasspathJars()}, {@link #providedClasspathJars()} and
* {@link #testClasspathJars()} to absolute paths, as well as the {@link #buildMainDirectory()} * {@link #testClasspathJars()} to absolute paths, as well as the {@link #buildMainDirectory()}
* *
* @since 1.5 * @since 1.5
@ -1468,10 +1900,22 @@ public class BaseProject extends BuildExecutor {
public List<String> compileTestClasspath() { public List<String> compileTestClasspath() {
var paths = new ArrayList<String>(); var paths = new ArrayList<String>();
paths.add(buildMainDirectory().getAbsolutePath()); paths.add(buildMainDirectory().getAbsolutePath());
paths.addAll(FileUtils.combineToAbsolutePaths(compileClasspathJars(), testClasspathJars())); paths.addAll(FileUtils.combineToAbsolutePaths(compileClasspathJars(), providedClasspathJars(), testClasspathJars()));
return paths; return paths;
} }
/**
* Returns all the module path entries for compiling the test sources.
* <p>
* By default, this converts the files from {@link #compileModulePathJars()}, {@link #providedModulePathJars()} and
* {@link #testModulePathJars()} to absolute paths.
*
* @since 2.1
*/
public List<String> compileTestModulePath() {
return FileUtils.combineToAbsolutePaths(compileModulePathJars(), providedModulePathJars(), testModulePathJars());
}
/** /**
* Returns all the classpath entries for running the application. * Returns all the classpath entries for running the application.
* <p> * <p>
@ -1489,10 +1933,22 @@ public class BaseProject extends BuildExecutor {
return paths; return paths;
} }
/**
* Returns all the module path entries for running the application.
* <p>
* By default, this converts the files from {@link #compileModulePathJars()},
* {@link #runtimeModulePathJars()} and {@link #standaloneModulePathJars()} to absolute paths.
*
* @since 2.1
*/
public List<String> runModulePath() {
return FileUtils.combineToAbsolutePaths(compileModulePathJars(), runtimeModulePathJars(), standaloneModulePathJars());
}
/** /**
* Returns all the classpath entries for testing the application. * Returns all the classpath entries for testing the application.
* <p> * <p>
* By default, this converts the files from {@link #compileClasspathJars()}, * By default, this converts the files from {@link #compileClasspathJars()}, {@link #providedClasspathJars()},
* {@link #runtimeClasspathJars()} and {@link #testClasspathJars()} * {@link #runtimeClasspathJars()} and {@link #testClasspathJars()}
* to absolute paths, as well as the {@link #srcMainResourcesDirectory()}, * to absolute paths, as well as the {@link #srcMainResourcesDirectory()},
* {@link #buildMainDirectory()} and {@link #buildTestDirectory()} * {@link #buildMainDirectory()} and {@link #buildTestDirectory()}
@ -1505,10 +1961,23 @@ public class BaseProject extends BuildExecutor {
paths.add(srcTestResourcesDirectory().getAbsolutePath()); paths.add(srcTestResourcesDirectory().getAbsolutePath());
paths.add(buildMainDirectory().getAbsolutePath()); paths.add(buildMainDirectory().getAbsolutePath());
paths.add(buildTestDirectory().getAbsolutePath()); paths.add(buildTestDirectory().getAbsolutePath());
paths.addAll(FileUtils.combineToAbsolutePaths(compileClasspathJars(), runtimeClasspathJars(), standaloneClasspathJars(), testClasspathJars())); paths.addAll(FileUtils.combineToAbsolutePaths(compileClasspathJars(), providedClasspathJars(), runtimeClasspathJars(), standaloneClasspathJars(), testClasspathJars()));
return paths; return paths;
} }
/**
* Returns all the module path entries for testing the application.
* <p>
* By default, this converts the files from {@link #compileModulePathJars()}, {@link #providedModulePathJars()},
* {@link #runtimeModulePathJars()} and {@link #testModulePathJars()}
* to absolute paths.
*
* @since 2.1
*/
public List<String> testModulePath() {
return FileUtils.combineToAbsolutePaths(compileModulePathJars(), providedModulePathJars(), runtimeModulePathJars(), standaloneModulePathJars(), testModulePathJars());
}
/** /**
* Executes download and purge commands automatically when the * Executes download and purge commands automatically when the
* {@code autoDownloadPurge} flag is set and changes have been detected. * {@code autoDownloadPurge} flag is set and changes have been detected.
@ -1522,84 +1991,28 @@ public class BaseProject extends BuildExecutor {
purge(); purge();
} }
private static final String BLD_BUILD_HASH = "bld-build.hash";
private void performAutoDownloadPurge() { private void performAutoDownloadPurge() {
// verify and update the fingerprint hash file, var resolution = new VersionResolution(properties());
// don't download and purge if the hash is identical var cache = new BldCache(libBldDirectory(), resolution);
var hash_file = new File(libBldDirectory(), BLD_BUILD_HASH); cache.cacheDependenciesHash(repositories(), dependencies());
var hash = createHash(); cache.cacheDependenciesDownloads(downloadSources(), downloadJavadoc());
if (validateHash(hash_file, hash)) { if (cache.isDependenciesCacheValid()) {
return; return;
} }
try { try {
executeAutoDownloadPurge(); executeAutoDownloadPurge();
writeHash(hash_file, hash); cache.writeCache();
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private String createHash() {
var finger_print = new StringBuilder();
for (var repository : repositories()) {
finger_print.append(repository.toString());
finger_print.append("\n");
}
for (var entry : dependencies().entrySet()) {
finger_print.append(entry.getKey());
finger_print.append("\n");
if (entry.getValue() != null) {
for (var dependency : entry.getValue()) {
finger_print.append(dependency.toString());
finger_print.append("\n");
}
}
}
finger_print.append(downloadSources());
finger_print.append("\n");
finger_print.append(downloadJavadoc());
finger_print.append("\n");
try {
var digest = MessageDigest.getInstance("SHA-1");
digest.update(finger_print.toString().getBytes(StandardCharsets.UTF_8));
return StringUtils.encodeHexLower(digest.digest());
} catch (NoSuchAlgorithmException e) {
// should not happen
throw new RuntimeException(e);
}
}
private boolean validateHash(File hashFile, String hash) {
try {
if (hashFile.exists()) {
var current_hash = FileUtils.readString(hashFile);
if (current_hash.equals(hash)) {
return true;
}
hashFile.delete();
}
return false;
} catch (FileUtilsErrorException e) {
throw new RuntimeException(e);
}
}
private void writeHash(File hashFile, String hash) {
try {
hashFile.getParentFile().mkdirs();
FileUtils.writeString(hash, hashFile);
} catch (FileUtilsErrorException e) {
throw new RuntimeException(e);
}
}
@Override @Override
public int execute(String[] arguments) { public int execute(String[] arguments) {
if (autoDownloadPurge()) { if (!offline() &&
autoDownloadPurge()) {
performAutoDownloadPurge(); performAutoDownloadPurge();
} }

View file

@ -0,0 +1,561 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld;
import rife.bld.dependencies.DependencyScopes;
import rife.bld.dependencies.Repository;
import rife.bld.dependencies.VersionResolution;
import rife.bld.wrapper.Wrapper;
import rife.tools.StringUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
/**
* Provides functionalities related to dependency hashing and caching.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 2.0
*/
public class BldCache {
/**
* Represents the name of a cache file used by bld.
* @since 2.0
*/
public static final String BLD_CACHE = "bld.cache";
private static final String PROPERTY_SUFFIX_HASH = ".hash";
private static final String PROPERTY_SUFFIX_LOCAL = ".local";
private static final String PROPERTY_SUFFIX_DOWNLOAD_SOURCES = ".download.sources";
private static final String PROPERTY_SUFFIX_DOWNLOAD_JAVADOC = ".download.javadoc";
private static final String PROPERTY_SUFFIX_DEPENDENCY_TREE = ".dependency.tree";
private static final String WRAPPER_PROPERTIES_HASH = Wrapper.WRAPPER_PROPERTIES + PROPERTY_SUFFIX_HASH;
private static final String BLD_BUILD_HASH = "bld-build" + PROPERTY_SUFFIX_HASH;
private static final String PROPERTY_EXTENSIONS_PREFIX = "bld.extensions";
private static final String PROPERTY_EXTENSIONS_HASH = PROPERTY_EXTENSIONS_PREFIX + PROPERTY_SUFFIX_HASH;
private static final String PROPERTY_EXTENSIONS_LOCAL = PROPERTY_EXTENSIONS_PREFIX + PROPERTY_SUFFIX_LOCAL;
private static final String PROPERTY_EXTENSIONS_DOWNLOAD_SOURCES = PROPERTY_EXTENSIONS_PREFIX + PROPERTY_SUFFIX_DOWNLOAD_SOURCES;
private static final String PROPERTY_EXTENSIONS_DOWNLOAD_JAVADOC = PROPERTY_EXTENSIONS_PREFIX + PROPERTY_SUFFIX_DOWNLOAD_JAVADOC;
private static final String PROPERTY_EXTENSIONS_DEPENDENCY_TREE = PROPERTY_EXTENSIONS_PREFIX + PROPERTY_SUFFIX_DEPENDENCY_TREE;
private static final String PROPERTY_DEPENDENCIES_PREFIX = "bld.dependencies";
private static final String PROPERTY_DEPENDENCIES_HASH = PROPERTY_DEPENDENCIES_PREFIX + PROPERTY_SUFFIX_HASH;
private static final String PROPERTY_DEPENDENCIES_DOWNLOAD_SOURCES = PROPERTY_DEPENDENCIES_PREFIX + PROPERTY_SUFFIX_DOWNLOAD_SOURCES;
private static final String PROPERTY_DEPENDENCIES_DOWNLOAD_JAVADOC = PROPERTY_DEPENDENCIES_PREFIX + PROPERTY_SUFFIX_DOWNLOAD_JAVADOC;
private static final String PROPERTY_DEPENDENCIES_COMPILE_DEPENDENCY_TREE = PROPERTY_DEPENDENCIES_PREFIX + ".compile" + PROPERTY_SUFFIX_DEPENDENCY_TREE;
private static final String PROPERTY_DEPENDENCIES_PROVIDED_DEPENDENCY_TREE = PROPERTY_DEPENDENCIES_PREFIX + ".provided" + PROPERTY_SUFFIX_DEPENDENCY_TREE;
private static final String PROPERTY_DEPENDENCIES_RUNTIME_DEPENDENCY_TREE = PROPERTY_DEPENDENCIES_PREFIX + ".runtime" + PROPERTY_SUFFIX_DEPENDENCY_TREE;
private static final String PROPERTY_DEPENDENCIES_TEST_DEPENDENCY_TREE = PROPERTY_DEPENDENCIES_PREFIX + ".test" + PROPERTY_SUFFIX_DEPENDENCY_TREE;
private final File cacheDir_;
private final VersionResolution resolution_;
private String extensionsHash_;
private Boolean extensionsDownloadSources_;
private Boolean extensionsDownloadJavadocs_;
private List<File> extensionsLocalArtifacts_;
private String extensionsDependencyTree_;
private String dependenciesHash_;
private Boolean dependenciesDownloadSources_;
private Boolean dependenciesDownloadJavadocs_;
private String dependenciesCompileDependencyTree_;
private String dependenciesProvidedDependencyTree_;
private String dependenciesRuntimeDependencyTree_;
private String dependenciesTestDependencyTree_;
/**
* Creates a new {@code BldCache} instance.
*
* @param cacheDir the directory where the bld cache file is stored
* @param resolution the version resolution that should be used when needed during the cache operations
* @since 2.0
*/
public BldCache(File cacheDir, VersionResolution resolution) {
cacheDir_ = cacheDir;
resolution_ = resolution;
new File(cacheDir, WRAPPER_PROPERTIES_HASH).delete();
new File(cacheDir, BLD_BUILD_HASH).delete();
}
/**
* Calculates the hash that corresponds to the provided repositories and extensions.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param repositories the repositories to include into the hash
* @param extensions the extensions to include into the hash
* @since 2.0
* @see #isExtensionsHashValid()
* @see #isExtensionsCacheValid()
* @see #writeCache()
*/
public void cacheExtensionsHash(Collection<String> repositories, Collection<String> extensions) {
try {
var overrides_fp = String.join("\n", resolution_.versionOverrides().entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).toList());
var repositories_fp = String.join("\n", repositories);
var extensions_fp = String.join("\n", extensions);
var fingerprint = overrides_fp + "\n" + repositories_fp + "\n" + extensions_fp + "\n";
var digest = MessageDigest.getInstance("SHA-1");
digest.update(fingerprint.getBytes(StandardCharsets.UTF_8));
extensionsHash_ = StringUtils.encodeHexLower(digest.digest());
} catch (NoSuchAlgorithmException e) {
// should not happen
throw new RuntimeException(e);
}
}
/**
* Determined whether the extensions hash stored in this {@code BldCache} instance is the same as the one stored
* in the cache on disk.
*
* @return {@code true} is the extensions hash is the same; or {@code false} otherwise
* @since 2.0
* @see #cacheExtensionsHash
* @see #isExtensionsCacheValid
*/
public boolean isExtensionsHashValid() {
return validateExtensionsHash(extensionsHash_);
}
/**
* Sets which other artifacts should be downloaded besides main jars for the extensions.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param downloadSources whether the extensions sources should be downloaded or not
* @param downloadJavadoc whether the extensions javadocs should be downloaded or not
* @since 2.0
* @see #isExtensionsCacheValid()
* @see #writeCache()
*/
public void cacheExtensionsDownloads(boolean downloadSources, boolean downloadJavadoc) {
extensionsDownloadSources_ = downloadSources;
extensionsDownloadJavadocs_ = downloadJavadoc;
}
/**
* Sets which local artifacts were used by the transfer of the extensions into the project.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param extensionsLocalArtifacts the list of extension files that were pulled from local storage
* @since 2.0
* @see #isExtensionsCacheValid()
* @see #writeCache()
*/
public void cacheExtensionsLocalArtifacts(List<File> extensionsLocalArtifacts) {
extensionsLocalArtifacts_ = extensionsLocalArtifacts;
}
/**
* Sets the textual presentation of the extensions dependency tree.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param dependencyTree the textual presentation of the extensions dependency tree
* @since 2.0
* @see #getCachedExtensionsDependencyTree
* @see #writeCache()
*/
public void cacheExtensionsDependencyTree(String dependencyTree) {
extensionsDependencyTree_ = dependencyTree;
}
/**
* Retrieves the textual presentation of the extensions dependency tree from the cache state on disk.
*
* @return the cached textual presentation of the extensions dependency tree; or {@code null} of this dependency
* tree wasn't found in the stored cache
* @since 2.0
* @see #cacheExtensionsDependencyTree
*/
public String getCachedExtensionsDependencyTree() {
return hashProperties().getProperty(PROPERTY_EXTENSIONS_DEPENDENCY_TREE);
}
/**
* Determines whether the extensions state stored in this {@code BldCache} instance is the same as the state of the cache on disk.
*
* @return {@code true} if state is identical; or {@code false} otherwise
* @since 2.0
* @see #cacheExtensionsHash
* @see #cacheExtensionsDownloads
* @see #cacheExtensionsLocalArtifacts
*/
public boolean isExtensionsCacheValid() {
var properties = hashProperties();
if (properties.isEmpty()) {
return false;
}
if (extensionsDownloadSources_ != Boolean.parseBoolean(properties.getProperty(PROPERTY_EXTENSIONS_DOWNLOAD_SOURCES))) {
return false;
}
if (extensionsDownloadJavadocs_ != Boolean.parseBoolean(properties.getProperty(PROPERTY_EXTENSIONS_DOWNLOAD_JAVADOC))) {
return false;
}
return validateExtensionsHash(extensionsHash_);
}
private boolean validateExtensionsHash(String hash) {
var properties = hashProperties();
if (properties.isEmpty()) {
return false;
}
if (!hash.equals(properties.getProperty(PROPERTY_EXTENSIONS_HASH))) {
return false;
}
var local_files = properties.getProperty(PROPERTY_EXTENSIONS_LOCAL);
if (local_files != null && !local_files.isEmpty()) {
var lines = StringUtils.split(local_files, "\n");
if (!lines.isEmpty()) {
// other lines are last modified timestamps of local files
// that were dependency artifacts
while (!lines.isEmpty()) {
var line = lines.get(0);
var parts = line.split(":", 2);
// verify that the local file has the same modified timestamp still
if (parts.length == 2) {
var file = new File(parts[1]);
if (!file.exists() || !file.canRead() || file.lastModified() != Long.parseLong(parts[0])) {
break;
}
} else {
break;
}
lines.remove(0);
}
// there were no invalid lines, so the hash file contents are valid
return lines.isEmpty();
}
}
return true;
}
/**
* Calculates the hash that corresponds to the provided repositories and dependencies.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param repositories the repositories to include into the hash
* @param dependencies the dependencies to include into the hash
* @since 2.0
* @see #isDependenciesHashValid()
* @see #isDependenciesCacheValid()
* @see #writeCache()
*/
public void cacheDependenciesHash(List<Repository> repositories, DependencyScopes dependencies) {
var finger_print = new StringBuilder();
finger_print.append(String.join("\n", resolution_.versionOverrides().entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).toList()));
for (var repository : repositories) {
finger_print.append(repository.toString());
finger_print.append('\n');
}
for (var entry : dependencies.entrySet()) {
finger_print.append(entry.getKey());
finger_print.append('\n');
if (entry.getValue() != null) {
for (var dependency : entry.getValue()) {
finger_print.append(dependency.toString());
finger_print.append('\n');
}
}
}
try {
var digest = MessageDigest.getInstance("SHA-1");
digest.update(finger_print.toString().getBytes(StandardCharsets.UTF_8));
dependenciesHash_ = StringUtils.encodeHexLower(digest.digest());
} catch (NoSuchAlgorithmException e) {
// should not happen
throw new RuntimeException(e);
}
}
/**
* Determined whether the dependencies hash stored in this {@code BldCache} instance is the same as the one stored
* in the cache on disk.
*
* @return {@code true} is the dependencies hash is the same; or {@code false} otherwise
* @since 2.0
* @see #cacheDependenciesHash
* @see #isDependenciesCacheValid
*/
public boolean isDependenciesHashValid() {
return validateDependenciesHash(dependenciesHash_);
}
/**
* Sets which other artifacts should be downloaded besides main jars for the dependencies.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param downloadSources whether the dependencies sources should be downloaded or not
* @param downloadJavadoc whether the dependencies javadocs should be downloaded or not
* @since 2.0
* @see #isDependenciesCacheValid()
* @see #writeCache()
*/
public void cacheDependenciesDownloads(boolean downloadSources, boolean downloadJavadoc) {
dependenciesDownloadSources_ = downloadSources;
dependenciesDownloadJavadocs_ = downloadJavadoc;
}
/**
* Sets the textual presentation of the compile scope dependency tree.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param compileTree the textual presentation of the compile scope dependency tree
* @since 2.0
* @see #getCachedDependenciesCompileDependencyTree
* @see #writeCache()
*/
public void cacheDependenciesCompileDependencyTree(String compileTree) {
dependenciesCompileDependencyTree_ = compileTree;
}
/**
* Retrieves the textual presentation of the compile scope dependency tree from the cache state on disk.
*
* @return the cached textual presentation of the compile scope dependency tree; or {@code null} of this dependency
* tree wasn't found in the stored cache
* @since 2.0
* @see #cacheDependenciesCompileDependencyTree
*/
public String getCachedDependenciesCompileDependencyTree() {
return hashProperties().getProperty(PROPERTY_DEPENDENCIES_COMPILE_DEPENDENCY_TREE);
}
/**
* Sets the textual presentation of the provided scope dependency tree.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param providedTree the textual presentation of the provided scope dependency tree
* @since 2.0
* @see #getCachedDependenciesProvidedDependencyTree
* @see #writeCache()
*/
public void cacheDependenciesProvidedDependencyTree(String providedTree) {
dependenciesProvidedDependencyTree_ = providedTree;
}
/**
* Retrieves the textual presentation of the provided scope dependency tree from the cache state on disk.
*
* @return the cached textual presentation of the provided scope dependency tree; or {@code null} of this dependency
* tree wasn't found in the stored cache
* @since 2.0
* @see #cacheDependenciesProvidedDependencyTree
*/
public String getCachedDependenciesProvidedDependencyTree() {
return hashProperties().getProperty(PROPERTY_DEPENDENCIES_PROVIDED_DEPENDENCY_TREE);
}
/**
* Sets the textual presentation of the runtime scope dependency tree.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param runtimeTree the textual presentation of the runtime scope dependency tree
* @since 2.0
* @see #getCachedDependenciesRuntimeDependencyTree
* @see #writeCache()
*/
public void cacheDependenciesRuntimeDependencyTree(String runtimeTree) {
dependenciesRuntimeDependencyTree_ = runtimeTree;
}
/**
* Retrieves the textual presentation of the runtime scope dependency tree from the cache state on disk.
*
* @return the cached textual presentation of the runtime scope dependency tree; or {@code null} of this dependency
* tree wasn't found in the stored cache
* @since 2.0
* @see #cacheDependenciesRuntimeDependencyTree
*/
public String getCachedDependenciesRuntimeDependencyTree() {
return hashProperties().getProperty(PROPERTY_DEPENDENCIES_RUNTIME_DEPENDENCY_TREE);
}
/**
* Sets the textual presentation of the test scope dependency tree.
* <p>
* This will be stored with this instance of {@code BldCache}, using {@link #writeCache()} is required to store it to disk.
*
* @param testTree the textual presentation of the test scope dependency tree
* @since 2.0
* @see #getCachedDependenciesTestDependencyTree
* @see #writeCache()
*/
public void cacheDependenciesTestDependencyTree(String testTree) {
dependenciesTestDependencyTree_ = testTree;
}
/**
* Retrieves the textual presentation of the test scope dependency tree from the cache state on disk.
*
* @return the cached textual presentation of the test scope dependency tree; or {@code null} of this dependency
* tree wasn't found in the stored cache
* @since 2.0
* @see #cacheDependenciesTestDependencyTree
*/
public String getCachedDependenciesTestDependencyTree() {
return hashProperties().getProperty(PROPERTY_DEPENDENCIES_TEST_DEPENDENCY_TREE);
}
/**
* Determines whether the dependencies state stored in this {@code BldCache} instance is the same as the state of the cache on disk.
*
* @return {@code true} if state is identical; or {@code false} otherwise
* @since 2.0
* @see #cacheDependenciesHash
* @see #cacheDependenciesDownloads
*/
public boolean isDependenciesCacheValid() {
var properties = hashProperties();
if (properties.isEmpty()) {
return false;
}
if (dependenciesDownloadSources_ != Boolean.parseBoolean(properties.getProperty(PROPERTY_DEPENDENCIES_DOWNLOAD_SOURCES))) {
return false;
}
if (dependenciesDownloadJavadocs_ != Boolean.parseBoolean(properties.getProperty(PROPERTY_DEPENDENCIES_DOWNLOAD_JAVADOC))) {
return false;
}
return validateDependenciesHash(dependenciesHash_);
}
private boolean validateDependenciesHash(String hash) {
var properties = hashProperties();
if (properties.isEmpty()) {
return false;
}
return hash.equals(properties.getProperty(PROPERTY_DEPENDENCIES_HASH));
}
private File getCacheFile() {
return new File(cacheDir_, BLD_CACHE);
}
private Properties hashProperties() {
var properties = new Properties();
if (getCacheFile().exists()) {
try {
try (var reader = new BufferedReader(new FileReader(getCacheFile()))) {
properties.load(reader);
}
} catch (IOException e) {
// no-op, we'll store a new properties file when we're writing the cache
}
}
return properties;
}
/**
* Writes the state of this {@code BldCache} instance to disk.
*
* @since 2.0
*/
public void writeCache() {
var properties = hashProperties();
try {
if (extensionsHash_ != null) {
if (!extensionsHash_.equals(properties.get(PROPERTY_EXTENSIONS_HASH))) {
properties.put(PROPERTY_EXTENSIONS_HASH, extensionsHash_);
properties.remove(PROPERTY_EXTENSIONS_DEPENDENCY_TREE);
}
if (extensionsDependencyTree_ != null) {
properties.put(PROPERTY_EXTENSIONS_DEPENDENCY_TREE, extensionsDependencyTree_);
}
}
if (extensionsDownloadSources_ != null) {
properties.put(PROPERTY_EXTENSIONS_DOWNLOAD_SOURCES, String.valueOf(extensionsDownloadSources_));
}
if (extensionsDownloadJavadocs_ != null) {
properties.put(PROPERTY_EXTENSIONS_DOWNLOAD_JAVADOC, String.valueOf(extensionsDownloadJavadocs_));
}
if (extensionsLocalArtifacts_ != null) {
var extensions_local = new StringBuilder();
for (var file : extensionsLocalArtifacts_) {
if (file.exists() && file.canRead()) {
if (!extensions_local.isEmpty()) {
extensions_local.append("\n");
}
extensions_local.append(file.lastModified()).append(':').append(file.getAbsolutePath());
}
}
properties.put(PROPERTY_EXTENSIONS_LOCAL, extensions_local.toString());
}
if (dependenciesHash_ != null) {
if (!dependenciesHash_.equals(properties.get(PROPERTY_DEPENDENCIES_HASH))) {
properties.put(PROPERTY_DEPENDENCIES_HASH, dependenciesHash_);
properties.remove(PROPERTY_DEPENDENCIES_COMPILE_DEPENDENCY_TREE);
properties.remove(PROPERTY_DEPENDENCIES_PROVIDED_DEPENDENCY_TREE);
properties.remove(PROPERTY_DEPENDENCIES_RUNTIME_DEPENDENCY_TREE);
properties.remove(PROPERTY_DEPENDENCIES_TEST_DEPENDENCY_TREE);
}
if (dependenciesCompileDependencyTree_ != null) {
properties.put(PROPERTY_DEPENDENCIES_COMPILE_DEPENDENCY_TREE, dependenciesCompileDependencyTree_);
}
if (dependenciesProvidedDependencyTree_ != null) {
properties.put(PROPERTY_DEPENDENCIES_PROVIDED_DEPENDENCY_TREE, dependenciesProvidedDependencyTree_);
}
if (dependenciesRuntimeDependencyTree_ != null) {
properties.put(PROPERTY_DEPENDENCIES_RUNTIME_DEPENDENCY_TREE, dependenciesRuntimeDependencyTree_);
}
if (dependenciesTestDependencyTree_ != null) {
properties.put(PROPERTY_DEPENDENCIES_TEST_DEPENDENCY_TREE, dependenciesTestDependencyTree_);
}
}
if (dependenciesDownloadSources_ != null) {
properties.put(PROPERTY_DEPENDENCIES_DOWNLOAD_SOURCES, String.valueOf(dependenciesDownloadSources_));
}
if (dependenciesDownloadJavadocs_ != null) {
properties.put(PROPERTY_DEPENDENCIES_DOWNLOAD_JAVADOC, String.valueOf(dependenciesDownloadJavadocs_));
}
cacheDir_.mkdirs();
try (var writer = new BufferedWriter(new FileWriter(getCacheFile()))) {
properties.store(writer, null);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -25,6 +25,15 @@ public @interface BuildCommand {
*/ */
String value() default ""; String value() default "";
/**
* When provided, specifies an alias for the build command that can be
* different from the method name.
*
* @return a string representing an alias for the build command
* @since 1.9
*/
String alias() default "";
/** /**
* When provided, specifies a short description about the command. * When provided, specifies a short description about the command.
* *

View file

@ -11,9 +11,7 @@ import rife.bld.operations.exceptions.ExitStatusException;
import rife.ioc.HierarchicalProperties; import rife.ioc.HierarchicalProperties;
import rife.tools.ExceptionUtils; import rife.tools.ExceptionUtils;
import java.io.File; import java.io.*;
import java.io.FileReader;
import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -33,6 +31,7 @@ public class BuildExecutor {
public static final String BLD_PROPERTIES = "bld.properties"; public static final String BLD_PROPERTIES = "bld.properties";
public static final String LOCAL_PROPERTIES = "local.properties"; public static final String LOCAL_PROPERTIES = "local.properties";
private static final String ARG_OFFLINE = "--offline";
private static final String ARG_HELP1 = "--help"; private static final String ARG_HELP1 = "--help";
private static final String ARG_HELP2 = "-h"; private static final String ARG_HELP2 = "-h";
private static final String ARG_HELP3 = "-?"; private static final String ARG_HELP3 = "-?";
@ -41,7 +40,9 @@ public class BuildExecutor {
private final HierarchicalProperties properties_; private final HierarchicalProperties properties_;
private List<String> arguments_ = Collections.emptyList(); private List<String> arguments_ = Collections.emptyList();
private boolean offline_ = false;
private Map<String, CommandDefinition> buildCommands_ = null; private Map<String, CommandDefinition> buildCommands_ = null;
private Map<String, String> buildAliases_ = null;
private final AtomicReference<String> currentCommandName_ = new AtomicReference<>(); private final AtomicReference<String> currentCommandName_ = new AtomicReference<>();
private final AtomicReference<CommandDefinition> currentCommandDefinition_ = new AtomicReference<>(); private final AtomicReference<CommandDefinition> currentCommandDefinition_ = new AtomicReference<>();
private int exitStatus_ = 0; private int exitStatus_ = 0;
@ -124,7 +125,18 @@ public class BuildExecutor {
} }
/** /**
* Returns the properties uses by this conversation. * Returns whether the bld execution is intended to be offline.
*
* @return {@code true} if the execution is intended to be offline;
* or {@code false} otherwise
* @since 2.0
*/
public boolean offline() {
return offline_;
}
/**
* Returns the properties uses for bld execution.
* *
* @return the instance of {@code HierarchicalProperties} that is used * @return the instance of {@code HierarchicalProperties} that is used
* by this build executor * by this build executor
@ -214,13 +226,16 @@ public class BuildExecutor {
var show_help = false; var show_help = false;
show_help |= arguments_.removeAll(List.of(ARG_HELP1, ARG_HELP2, ARG_HELP3)); show_help |= arguments_.removeAll(List.of(ARG_HELP1, ARG_HELP2, ARG_HELP3));
showStacktrace |= arguments_.removeAll(List.of(ARG_STACKTRACE1, ARG_STACKTRACE2)); showStacktrace = arguments_.removeAll(List.of(ARG_STACKTRACE1, ARG_STACKTRACE2));
show_help |= arguments_.isEmpty();
if (show_help) { if (show_help) {
new HelpOperation(this, Collections.emptyList()).execute(); new HelpOperation(this, Collections.emptyList()).execute();
return exitStatus_; return exitStatus_;
} }
else if (arguments_.isEmpty()) {
showBldHelp();
return exitStatus_;
}
while (!arguments_.isEmpty()) { while (!arguments_.isEmpty()) {
var command = arguments_.remove(0); var command = arguments_.remove(0);
@ -230,36 +245,39 @@ public class BuildExecutor {
break; break;
} }
} catch (Throwable e) { } catch (Throwable e) {
exitStatus(1); exitStatus(ExitStatusException.EXIT_FAILURE);
outputCommandExecutionException(e);
break;
}
}
return exitStatus_;
}
private void outputCommandExecutionException(Throwable e) {
System.err.println(); System.err.println();
if (showStacktrace) { if (showStacktrace) {
System.err.println(ExceptionUtils.getExceptionStackTrace(e)); System.err.println(ExceptionUtils.getExceptionStackTrace(e));
} else { } else {
boolean first = true; boolean first_exception = true;
var e2 = e; var e2 = e;
while (e2 != null) { while (e2 != null) {
if (e2.getMessage() != null) { if (e2.getMessage() != null) {
if (!first) { if (!first_exception) {
System.err.print("> "); System.err.print("> ");
} }
System.err.println(e2.getMessage()); System.err.println(e2.getMessage());
first = false; first_exception = false;
} }
e2 = e2.getCause(); e2 = e2.getCause();
} }
if (first) { if (first_exception) {
System.err.println(ExceptionUtils.getExceptionStackTrace(e)); System.err.println(ExceptionUtils.getExceptionStackTrace(e));
} }
} }
} }
}
return exitStatus_;
}
/** /**
* Starts the execution of the build. This method will call * Starts the execution of the build. This method will call
@ -270,6 +288,11 @@ public class BuildExecutor {
* @since 1.5.1 * @since 1.5.1
*/ */
public void start(String[] arguments) { public void start(String[] arguments) {
if (arguments.length > 0 && arguments[0].equals(ARG_OFFLINE)) {
offline_ = true;
arguments = Arrays.copyOfRange(arguments, 1, arguments.length);
}
System.exit(execute(arguments)); System.exit(execute(arguments));
} }
@ -294,6 +317,7 @@ public class BuildExecutor {
public Map<String, CommandDefinition> buildCommands() { public Map<String, CommandDefinition> buildCommands() {
if (buildCommands_ == null) { if (buildCommands_ == null) {
var build_commands = new TreeMap<String, CommandDefinition>(); var build_commands = new TreeMap<String, CommandDefinition>();
var build_aliases = new HashMap<String, String>();
Class<?> klass = getClass(); Class<?> klass = getClass();
@ -311,6 +335,11 @@ public class BuildExecutor {
name = annotation_name; name = annotation_name;
} }
var annotation_alias = annotation.alias();
if (annotation_alias != null && !annotation_alias.isEmpty()) {
build_aliases.put(annotation_alias, name);
}
if (!build_commands.containsKey(name)) { if (!build_commands.containsKey(name)) {
var build_help = annotation.help(); var build_help = annotation.help();
CommandHelp command_help = null; CommandHelp command_help = null;
@ -343,11 +372,27 @@ public class BuildExecutor {
} }
buildCommands_ = build_commands; buildCommands_ = build_commands;
buildAliases_ = build_aliases;
} }
return buildCommands_; return buildCommands_;
} }
/**
* Retrieves the command aliases that can be executed by this {@code BuildExecutor}.
*
* @return a map containing the alias and the associated name of the build command
* @see BuildCommand
* @since 1.9
*/
public Map<String, String> buildAliases() {
if (buildAliases_ == null) {
buildCommands();
}
return buildAliases_;
}
private static class AnnotatedCommandHelp implements CommandHelp { private static class AnnotatedCommandHelp implements CommandHelp {
private final String summary_; private final String summary_;
private final String description_; private final String description_;
@ -383,6 +428,15 @@ public class BuildExecutor {
var matched_command = command; var matched_command = command;
var definition = buildCommands().get(command); var definition = buildCommands().get(command);
// try to find an alias
if (definition == null) {
var aliased_command = buildAliases().get(command);
if (aliased_command != null) {
matched_command = aliased_command;
definition = buildCommands().get(aliased_command);
}
}
// try to find a match for the provided command amongst // try to find a match for the provided command amongst
// the ones that are known // the ones that are known
if (definition == null) { if (definition == null) {
@ -399,7 +453,7 @@ public class BuildExecutor {
fuzzy_regexp.append(ch); fuzzy_regexp.append(ch);
fuzzy_regexp.append("\\E.*"); fuzzy_regexp.append("\\E.*");
} }
fuzzy_regexp.append("$"); fuzzy_regexp.append('$');
var fuzzy_pattern = Pattern.compile(fuzzy_regexp.toString()); var fuzzy_pattern = Pattern.compile(fuzzy_regexp.toString());
matches.addAll(buildCommands().keySet().stream() matches.addAll(buildCommands().keySet().stream()
.filter(c -> fuzzy_pattern.matcher(c.toLowerCase()).matches()) .filter(c -> fuzzy_pattern.matcher(c.toLowerCase()).matches())
@ -416,9 +470,9 @@ public class BuildExecutor {
// execute the command if we found one // execute the command if we found one
if (definition != null) { if (definition != null) {
try {
currentCommandName_.set(matched_command); currentCommandName_.set(matched_command);
currentCommandDefinition_.set(definition); currentCommandDefinition_.set(definition);
try {
definition.execute(); definition.execute();
} catch (ExitStatusException e) { } catch (ExitStatusException e) {
exitStatus(e.getExitStatus()); exitStatus(e.getExitStatus());
@ -428,14 +482,25 @@ public class BuildExecutor {
currentCommandName_.set(null); currentCommandName_.set(null);
} }
} else { } else {
new HelpOperation(this, arguments()).executePrintOverviewHelp(); var message = "Unknown command '" + command + "'";
System.err.println(); showBldHelp();
System.err.println("ERROR: unknown command '" + command + "'"); System.err.println("ERROR: " + message);
exitStatus(ExitStatusException.EXIT_FAILURE);
return false; return false;
} }
return true; return true;
} }
private void showBldHelp() {
var help = new HelpOperation(this, arguments());
help.executePrintWelcome();
System.err.println("""
The bld CLI provides its features through a series of commands that
perform specific tasks.""");
help.executePrintCommands();
help.executePrintBldArguments();
}
/** /**
* Retrieves the name of the currently executing command. * Retrieves the name of the currently executing command.
* *

View file

@ -17,7 +17,7 @@ import rife.bld.operations.*;
public class Cli extends BuildExecutor { public class Cli extends BuildExecutor {
private final CreateOperation createOperation_ = new CreateOperation(); private final CreateOperation createOperation_ = new CreateOperation();
private final CreateBaseOperation createBaseOperation_ = new CreateBaseOperation(); private final CreateBaseOperation createBaseOperation_ = new CreateBaseOperation();
private final CreateBlankOperation createBlankOperation_ = new CreateBlankOperation(); private final CreateAppOperation createAppOperation_ = new CreateAppOperation();
private final CreateLibOperation createLibOperation_ = new CreateLibOperation(); private final CreateLibOperation createLibOperation_ = new CreateLibOperation();
private final CreateRife2Operation createRife2Operation_ = new CreateRife2Operation(); private final CreateRife2Operation createRife2Operation_ = new CreateRife2Operation();
private final UpgradeOperation upgradeOperation_ = new UpgradeOperation(); private final UpgradeOperation upgradeOperation_ = new UpgradeOperation();
@ -36,15 +36,15 @@ public class Cli extends BuildExecutor {
} }
/** /**
* The standard {@code create-blank} command. * The standard {@code create-app} command.
* *
* @throws Exception when an error occurred during the creation process * @throws Exception when an error occurred during the creation process
* @since 1.5 * @since 1.9
*/ */
@BuildCommand(value = "create-blank", help = CreateBlankHelp.class) @BuildCommand(value = "create-app", alias = "create-blank", help = CreateAppHelp.class)
public void createBlank() public void createApp()
throws Exception { throws Exception {
createBlankOperation_.executeOnce(() -> createBlankOperation_.fromArguments(arguments())); createAppOperation_.executeOnce(() -> createAppOperation_.fromArguments(arguments()));
} }
/** /**

View file

@ -108,6 +108,11 @@ public class WebProject extends Project {
return Objects.requireNonNullElseGet(libStandaloneDirectory, () -> new File(libDirectory(), "standalone")); return Objects.requireNonNullElseGet(libStandaloneDirectory, () -> new File(libDirectory(), "standalone"));
} }
@Override
public File libStandaloneModulesDirectory() {
return Objects.requireNonNullElseGet(libStandaloneModulesDirectory, () -> new File(libStandaloneDirectory(), "modules"));
}
/** /**
* Returns the project main webapp directory. * Returns the project main webapp directory.
* Defaults to {@code "webapp"} relative to {@link #srcMainDirectory()}. * Defaults to {@code "webapp"} relative to {@link #srcMainDirectory()}.

View file

@ -16,28 +16,28 @@ import static rife.bld.dependencies.Repository.SONATYPE_SNAPSHOTS;
import static rife.bld.dependencies.Scope.test; import static rife.bld.dependencies.Scope.test;
/** /**
* Provides the dependency information required to create a new blank project. * Provides the dependency information required to create a new app project.
* *
* @author Geert Bevin (gbevin[remove] at uwyn dot com) * @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5 * @since 1.9
*/ */
public class BlankProjectBlueprint extends Project { public class AppProjectBlueprint extends Project {
public BlankProjectBlueprint(File work, String packageName, String projectName) { public AppProjectBlueprint(File work, String packageName, String projectName, String baseName) {
this(work, packageName, projectName, new VersionNumber(0,0,1)); this(work, packageName, projectName, baseName, new VersionNumber(0,0,1));
} }
public BlankProjectBlueprint(File work, String packageName, String projectName, VersionNumber versionNumber) { public AppProjectBlueprint(File work, String packageName, String projectName, String baseName, VersionNumber versionNumber) {
workDirectory = work; workDirectory = work;
pkg = packageName; pkg = packageName;
name = projectName; name = projectName;
mainClass = packageName + "." + StringUtils.capitalize(projectName) + "Main"; mainClass = packageName + "." + baseName;
version = versionNumber; version = versionNumber;
downloadSources = true; downloadSources = true;
repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS); repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS);
scope(test) scope(test)
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5,9,3))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5,11,4)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1,9,3))); .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1,11,4)));
} }
} }

View file

@ -13,7 +13,6 @@ import java.util.List;
import static rife.bld.dependencies.Repository.MAVEN_CENTRAL; import static rife.bld.dependencies.Repository.MAVEN_CENTRAL;
import static rife.bld.dependencies.Repository.SONATYPE_SNAPSHOTS; import static rife.bld.dependencies.Repository.SONATYPE_SNAPSHOTS;
import static rife.bld.dependencies.Scope.test;
/** /**
* Provides the dependency information required to create a new base project. * Provides the dependency information required to create a new base project.
@ -22,16 +21,16 @@ import static rife.bld.dependencies.Scope.test;
* @since 1.5.20 * @since 1.5.20
*/ */
public class BaseProjectBlueprint extends Project { public class BaseProjectBlueprint extends Project {
public BaseProjectBlueprint(File work, String packageName, String projectName) { public BaseProjectBlueprint(File work, String packageName, String projectName, String baseName) {
this(work, packageName, projectName, new VersionNumber(0,0,1)); this(work, packageName, projectName, baseName, new VersionNumber(0,0,1));
} }
public BaseProjectBlueprint(File work, String packageName, String projectName, VersionNumber versionNumber) { public BaseProjectBlueprint(File work, String packageName, String projectName, String baseName, VersionNumber versionNumber) {
workDirectory = work; workDirectory = work;
pkg = packageName; pkg = packageName;
name = projectName; name = projectName;
mainClass = packageName + "." + StringUtils.capitalize(projectName) + "Main"; mainClass = packageName + "." + baseName;
version = versionNumber; version = versionNumber;
downloadSources = true; downloadSources = true;

View file

@ -13,6 +13,7 @@ import java.util.List;
import static rife.bld.dependencies.Repository.MAVEN_CENTRAL; import static rife.bld.dependencies.Repository.MAVEN_CENTRAL;
import static rife.bld.dependencies.Repository.SONATYPE_SNAPSHOTS; import static rife.bld.dependencies.Repository.SONATYPE_SNAPSHOTS;
import static rife.bld.dependencies.Scope.test;
/** /**
* Provides the dependency information required to create a new lib project. * Provides the dependency information required to create a new lib project.
@ -21,19 +22,22 @@ import static rife.bld.dependencies.Repository.SONATYPE_SNAPSHOTS;
* @since 1.6 * @since 1.6
*/ */
public class LibProjectBlueprint extends Project { public class LibProjectBlueprint extends Project {
public LibProjectBlueprint(File work, String packageName, String projectName) { public LibProjectBlueprint(File work, String packageName, String projectName, String baseName) {
this(work, packageName, projectName, new VersionNumber(0,0,1)); this(work, packageName, projectName, baseName, new VersionNumber(0,0,1));
} }
public LibProjectBlueprint(File work, String packageName, String projectName, VersionNumber versionNumber) { public LibProjectBlueprint(File work, String packageName, String projectName, String baseName, VersionNumber versionNumber) {
workDirectory = work; workDirectory = work;
pkg = packageName; pkg = packageName;
name = projectName; name = projectName;
mainClass = packageName + "." + StringUtils.capitalize(projectName) + "Lib"; mainClass = packageName + "." + baseName;
version = versionNumber; version = versionNumber;
downloadSources = true; downloadSources = true;
repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS); repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS);
scope(test)
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5,11,4)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1,11,4)));
} }
} }

View file

@ -23,30 +23,31 @@ import static rife.bld.dependencies.Scope.*;
* @since 1.5 * @since 1.5
*/ */
public class Rife2ProjectBlueprint extends WebProject { public class Rife2ProjectBlueprint extends WebProject {
public Rife2ProjectBlueprint(File work, String packageName, String projectName) { public Rife2ProjectBlueprint(File work, String packageName, String projectName, String baseName) {
this(work, packageName, projectName, new VersionNumber(0,0,1)); this(work, packageName, projectName, baseName, new VersionNumber(0,0,1));
} }
public Rife2ProjectBlueprint(File work, String packageName, String projectName, VersionNumber versionNumber) { public Rife2ProjectBlueprint(File work, String packageName, String projectName, String baseName, VersionNumber versionNumber) {
workDirectory = work; workDirectory = work;
pkg = packageName; pkg = packageName;
name = projectName; name = projectName;
mainClass = packageName + "." + StringUtils.capitalize(projectName) + "Site"; mainClass = packageName + "." + baseName + "Site";
uberJarMainClass = mainClass + "Uber";
version = versionNumber; version = versionNumber;
downloadSources = true; downloadSources = true;
repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS); repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS);
scope(compile) scope(compile)
.include(dependency("com.uwyn.rife2", "rife2", version(1,6,3))); .include(dependency("com.uwyn.rife2", "rife2", version(1,9,1)));
scope(test) scope(test)
.include(dependency("org.jsoup", "jsoup", version(1,16,1))) .include(dependency("org.jsoup", "jsoup", version(1,18,3)))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5,9,3))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5,11,4)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1,9,3))); .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1,11,4)));
scope(standalone) scope(standalone)
.include(dependency("org.eclipse.jetty", "jetty-server", version(11,0,15))) .include(dependency("org.eclipse.jetty.ee10", "jetty-ee10", version(12,0,16)))
.include(dependency("org.eclipse.jetty", "jetty-servlet", version(11,0,15))) .include(dependency("org.eclipse.jetty.ee10", "jetty-ee10-servlet", version(12,0,16)))
.include(dependency("org.slf4j", "slf4j-simple", version(2,0,7))); .include(dependency("org.slf4j", "slf4j-simple", version(2,0,16)));
precompileOperation().templateTypes(TemplateType.HTML); precompileOperation().templateTypes(TemplateType.HTML);
} }

View file

@ -4,54 +4,87 @@
*/ */
package rife.bld.dependencies; package rife.bld.dependencies;
import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
* Contains the information required to describe an url dependency in the build system. * Contains the information required to describe a dependency in the build system.
* *
* @param groupId the dependency group identifier
* @param artifactId the dependency url identifier
* @param version the dependency version
* @param classifier the dependency classier
* @param type the dependency type
* @param exclusions the dependency exclusions for transitive resolution
* @param parent the parent dependency that created this dependency (only for information purposes)
* @author Geert Bevin (gbevin[remove] at uwyn dot com) * @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5 * @since 1.5
*/ */
public record Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type, ExclusionSet exclusions, Dependency parent) { public class Dependency {
public static final String CLASSIFIER_SOURCES = "sources"; public static final String CLASSIFIER_SOURCES = "sources";
public static final String CLASSIFIER_JAVADOC = "javadoc"; public static final String CLASSIFIER_JAVADOC = "javadoc";
/**
* The dependency type name for a JAR file that can be placed either on the class-path or on the module-path.
*
* @since 2.1
*/
public static final String TYPE_JAR = "jar";
/**
* The dependency type name for a JAR file to unconditionally place on the class-path.
*
* @since 2.1
*/
public static final String TYPE_CLASSPATH_JAR = "classpath-jar";
/**
* The dependency type name for a JAR file to unconditionally place on the module-path.
*
* @since 2.1
*/
// see https://github.com/apache/maven/blob/maven-4.0.0-beta-3/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
public static final String TYPE_MODULAR_JAR = "modular-jar";
private final String groupId_;
private final String artifactId_;
private final Version version_;
private final String classifier_;
private final String type_;
private final ExclusionSet exclusions_;
private final Dependency parent_;
private final HashSet<String> excludedClassifiers_;
public Dependency(String groupId, String artifactId) { public Dependency(String groupId, String artifactId) {
this(groupId, artifactId, null, null, null); this(groupId, artifactId, null, null, null);
} }
public Dependency(String groupId, String artifactId, VersionNumber version) { public Dependency(String groupId, String artifactId, Version version) {
this(groupId, artifactId, version, null, null); this(groupId, artifactId, version, null, null);
} }
public Dependency(String groupId, String artifactId, VersionNumber version, String classifier) { public Dependency(String groupId, String artifactId, Version version, String classifier) {
this(groupId, artifactId, version, classifier, null); this(groupId, artifactId, version, classifier, null);
} }
public Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type) { public Dependency(String groupId, String artifactId, Version version, String classifier, String type) {
this(groupId, artifactId, version, classifier, type, null); this(groupId, artifactId, version, classifier, type, null);
} }
public Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type, ExclusionSet exclusions) { public Dependency(String groupId, String artifactId, Version version, String classifier, String type, ExclusionSet exclusions) {
this(groupId, artifactId, version, classifier, type, null, null); this(groupId, artifactId, version, classifier, type, exclusions, null);
} }
public Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type, ExclusionSet exclusions, Dependency parent) { public Dependency(String groupId, String artifactId, Version version, String classifier, String type, ExclusionSet exclusions, Dependency parent) {
this.groupId = groupId; if (type == null) {
this.artifactId = artifactId; type = TYPE_JAR;
this.version = (version == null ? VersionNumber.UNKNOWN : version); }
this.classifier = (classifier == null ? "" : classifier); if (parent != null && parent.isModularJar() && TYPE_JAR.equals(type)) {
this.type = (type == null ? "jar" : type); type = TYPE_MODULAR_JAR;
this.exclusions = (exclusions == null ? new ExclusionSet() : exclusions); }
this.parent = parent;
this.groupId_ = groupId;
this.artifactId_ = artifactId;
this.version_ = (version == null ? VersionNumber.UNKNOWN : version);
this.classifier_ = (classifier == null ? "" : classifier);
this.type_ = type;
this.exclusions_ = (exclusions == null ? new ExclusionSet() : exclusions);
this.parent_ = parent;
this.excludedClassifiers_ = new HashSet<>();
} }
private static final Pattern DEPENDENCY_PATTERN = Pattern.compile("^(?<groupId>[^:@]+):(?<artifactId>[^:@]+)(?::(?<version>[^:@]+)(?::(?<classifier>[^:@]+))?)?(?:@(?<type>[^:@]+))?$"); private static final Pattern DEPENDENCY_PATTERN = Pattern.compile("^(?<groupId>[^:@]+):(?<artifactId>[^:@]+)(?::(?<version>[^:@]+)(?::(?<classifier>[^:@]+))?)?(?:@(?<type>[^:@]+))?$");
@ -80,7 +113,7 @@ public record Dependency(String groupId, String artifactId, VersionNumber versio
var groupId = matcher.group("groupId"); var groupId = matcher.group("groupId");
var artifactId = matcher.group("artifactId"); var artifactId = matcher.group("artifactId");
var version = VersionNumber.parse(matcher.group("version")); var version = Version.parse(matcher.group("version"));
var classifier = matcher.group("classifier"); var classifier = matcher.group("classifier");
var type = matcher.group("type"); var type = matcher.group("type");
@ -95,7 +128,7 @@ public record Dependency(String groupId, String artifactId, VersionNumber versio
* @since 1.5 * @since 1.5
*/ */
public Dependency baseDependency() { public Dependency baseDependency() {
return new Dependency(groupId, artifactId, VersionNumber.UNKNOWN, classifier, type); return new Dependency(groupId_, artifactId_, VersionNumber.UNKNOWN, classifier_, type_);
} }
/** /**
@ -107,7 +140,7 @@ public record Dependency(String groupId, String artifactId, VersionNumber versio
* @since 1.5 * @since 1.5
*/ */
public Dependency exclude(String groupId, String artifactId) { public Dependency exclude(String groupId, String artifactId) {
exclusions.add(new DependencyExclusion(groupId, artifactId)); exclusions_.add(new DependencyExclusion(groupId, artifactId));
return this; return this;
} }
@ -119,7 +152,29 @@ public record Dependency(String groupId, String artifactId, VersionNumber versio
* @since 1.5.6 * @since 1.5.6
*/ */
public Dependency withClassifier(String classifier) { public Dependency withClassifier(String classifier) {
return new Dependency(groupId, artifactId, version, classifier, type); return new Dependency(groupId_, artifactId_, version_, classifier, type_);
}
/**
* Exclude the sources artifact from download operations.
*
* @return this dependency instance
* @since 2.1
*/
public Dependency excludeSources() {
excludedClassifiers_.add(CLASSIFIER_SOURCES);
return this;
}
/**
* Exclude the javadoc artifact from download operations.
*
* @return this dependency instance
* @since 2.1
*/
public Dependency excludeJavadoc() {
excludedClassifiers_.add(CLASSIFIER_JAVADOC);
return this;
} }
/** /**
@ -130,40 +185,150 @@ public record Dependency(String groupId, String artifactId, VersionNumber versio
*/ */
public String toFileName() { public String toFileName() {
var result = new StringBuilder(artifactId()); var result = new StringBuilder(artifactId());
result.append("-").append(version()); result.append('-').append(version());
if (!classifier().isEmpty()) { if (!classifier().isEmpty()) {
result.append("-").append(classifier()); result.append('-').append(classifier());
} }
result.append(".").append(type()); result.append('.').append(type());
return result.toString(); return result.toString();
} }
/**
* Returns a string representation of the dependency in the format "groupId:artifactId".
*
* @return the string representation of the dependency
* @since 2.0
*/
public String toArtifactString() {
return groupId_ + ':' + artifactId_;
}
public String toString() { public String toString() {
var result = new StringBuilder(groupId).append(":").append(artifactId); var result = new StringBuilder(groupId_).append(':').append(artifactId_);
if (!version.equals(VersionNumber.UNKNOWN)) { if (!version_.equals(VersionNumber.UNKNOWN)) {
result.append(":").append(version); result.append(':').append(version_);
} }
if (!classifier.isEmpty()) { if (!classifier_.isEmpty()) {
result.append(":").append(classifier); result.append(':').append(classifier_);
} }
if (!type.isEmpty() && !type.equals("jar")) { if (!type_.isEmpty() && !TYPE_JAR.equals(type_)) {
result.append("@").append(type); result.append('@').append(type_);
} }
return result.toString(); return result.toString();
} }
/**
* Returns this dependency's {@code groupId}.
*
* @return the {@code groupId} of this dependency
* @since 1.5
*/
public String groupId() {
return groupId_;
}
/**
* Returns this dependency's {@code artifactId}.
*
* @return the {@code artifactId} of this dependency
* @since 1.5
*/
public String artifactId() {
return artifactId_;
}
/**
* Returns this dependency's {@code version}.
*
* @return the {@code version} of this dependency
* @since 1.5
*/
public Version version() {
return version_;
}
/**
* Returns this dependency's {@code classifier}.
*
* @return the {@code classifier} of this dependency
* @since 1.5
*/
public String classifier() {
return classifier_;
}
/**
* Returns this dependency's {@code type}.
*
* @return the {@code type} of this dependency
* @since 1.5
*/
public String type() {
return type_;
}
/**
* Returns this dependency's {@code exclusions} for transitive resolution.
*
* @return the {@code exclusions} of this dependency
* @since 1.5
*/
public ExclusionSet exclusions() {
return exclusions_;
}
public HashSet<String> excludedClassifiers() {
return excludedClassifiers_;
}
/**
* Returns this dependency's {@code parent} dependency that created this
* dependency (only for information purposes).
*
* @return the {@code parent} of this dependency
* @since 1.5
*/
public Dependency parent() {
return parent_;
}
/**
* Indicates whether this dependency specifically is a classpath jar or not.
*
* @return {@code true} when this dependency specifically is a classpath jar; or {@code false} otherwise
* @since 2.1
*/
public boolean isClasspathJar() {
return Module.TYPE_CLASSPATH_JAR.equals(type_);
}
/**
* Indicates whether this dependency is a modular jar or not.
*
* @return {@code true} when this dependency is a modular jar; or {@code false} otherwise
* @since 2.1
*/
public boolean isModularJar() {
return Module.TYPE_MODULAR_JAR.equals(type_);
}
private static String normalizedJarType(String type) {
if (TYPE_JAR.equals(type) || TYPE_MODULAR_JAR.equals(type) || TYPE_CLASSPATH_JAR.equals(type)) {
return TYPE_JAR;
}
return type;
}
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (!(o instanceof Dependency that)) return false;
var that = (Dependency) o; return groupId_.equals(that.groupId_) &&
return groupId.equals(that.groupId) && artifactId_.equals(that.artifactId_) &&
artifactId.equals(that.artifactId) && classifier_.equals(that.classifier_) &&
classifier.equals(that.classifier) && normalizedJarType(type_).equals(normalizedJarType(that.type_));
type.equals(that.type);
} }
public int hashCode() { public int hashCode() {
return Objects.hash(groupId, artifactId, classifier, type); return Objects.hash(groupId_, artifactId_, classifier_, normalizedJarType(type_));
} }
} }

View file

@ -25,10 +25,10 @@ public record DependencyExclusion(String groupId, String artifactId) {
} }
boolean matches(PomDependency dependency) { boolean matches(PomDependency dependency) {
return (groupId().equals("*") && artifactId().equals("*")) || return ("*".equals(groupId()) && "*".equals(artifactId())) ||
(groupId().equals("*") && artifactId().equals(dependency.artifactId())) || ("*".equals(groupId()) && artifactId().equals(dependency.artifactId())) ||
(groupId().equals(dependency.groupId()) && artifactId().equals("*")) || (groupId().equals(dependency.groupId()) && "*".equals(artifactId())) ||
(groupId().equals(dependency.groupId()) && artifactId().equals(dependency.artifactId())); (groupId().equals(dependency.groupId()) && dependency.artifactId().equals(artifactId()));
} }
} }

View file

@ -11,6 +11,8 @@ import java.io.*;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static rife.bld.dependencies.Dependency.*;
/** /**
* Resolves a dependency within a list of Maven-compatible repositories. * Resolves a dependency within a list of Maven-compatible repositories.
* *
@ -18,6 +20,7 @@ import java.util.stream.Collectors;
* @since 1.5 * @since 1.5
*/ */
public class DependencyResolver { public class DependencyResolver {
private final VersionResolution resolution_;
private final ArtifactRetriever retriever_; private final ArtifactRetriever retriever_;
private final List<Repository> repositories_; private final List<Repository> repositories_;
private final Dependency dependency_; private final Dependency dependency_;
@ -30,12 +33,14 @@ public class DependencyResolver {
* <p> * <p>
* The repositories will be checked in the order they're listed. * The repositories will be checked in the order they're listed.
* *
* @param resolution the version resolution state that can be cached
* @param retriever the retriever to use to get artifacts * @param retriever the retriever to use to get artifacts
* @param repositories the repositories to use for the resolution * @param repositories the repositories to use for the resolution
* @param dependency the dependency to resolve * @param dependency the dependency to resolve
* @since 1.5.18 * @since 2.0
*/ */
public DependencyResolver(ArtifactRetriever retriever, List<Repository> repositories, Dependency dependency) { public DependencyResolver(VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories, Dependency dependency) {
resolution_ = resolution;
retriever_ = retriever; retriever_ = retriever;
if (repositories == null) { if (repositories == null) {
repositories = Collections.emptyList(); repositories = Collections.emptyList();
@ -64,7 +69,6 @@ public class DependencyResolver {
} }
} }
/** /**
* Resolves the dependency version in the provided repositories. * Resolves the dependency version in the provided repositories.
* <p> * <p>
@ -76,8 +80,8 @@ public class DependencyResolver {
* @return the resolved version * @return the resolved version
* @since 1.5 * @since 1.5
*/ */
public VersionNumber resolveVersion() { public Version resolveVersion() {
var version = dependency_.version(); var version = resolution_.overrideVersion(dependency_);
if (version.equals(VersionNumber.UNKNOWN)) { if (version.equals(VersionNumber.UNKNOWN)) {
return latestVersion(); return latestVersion();
} }
@ -98,7 +102,7 @@ public class DependencyResolver {
var pom_dependencies = getMavenPom(dependency_).getDependencies(scopes); var pom_dependencies = getMavenPom(dependency_).getDependencies(scopes);
var result = new DependencySet(); var result = new DependencySet();
for (var dependency : pom_dependencies) { for (var dependency : pom_dependencies) {
result.add(dependency.convertToDependency()); result.add(resolution_.overrideDependency(dependency.convertToDependency()));
} }
return result; return result;
} }
@ -118,11 +122,12 @@ public class DependencyResolver {
*/ */
public DependencySet getAllDependencies(Scope... scopes) { public DependencySet getAllDependencies(Scope... scopes) {
var result = new DependencySet(); var result = new DependencySet();
result.add(dependency_); var overridden = resolution_.overrideDependency(dependency_);
result.add(overridden);
var dependency_queue = new ArrayList<PomDependency>(); var dependency_queue = new ArrayList<PomDependency>();
var parent = dependency_; var parent = overridden;
var next_dependencies = getMavenPom(parent).getDependencies(scopes); var next_dependencies = getMavenPom(parent).getDependencies(scopes);
while (parent != null && next_dependencies != null) { while (parent != null && next_dependencies != null) {
@ -142,7 +147,7 @@ public class DependencyResolver {
// part of the results yet // part of the results yet
while (!dependency_queue.isEmpty()) { while (!dependency_queue.isEmpty()) {
var candidate = dependency_queue.remove(0); var candidate = dependency_queue.remove(0);
var dependency = candidate.convertToDependency(); var dependency = resolution_.overrideDependency(candidate.convertToDependency());
if (!result.contains(dependency)) { if (!result.contains(dependency)) {
result.add(dependency); result.add(dependency);
@ -150,7 +155,7 @@ public class DependencyResolver {
// dependencies so that they can be added to the queue after // dependencies so that they can be added to the queue after
// filtering // filtering
parent = dependency; parent = dependency;
next_dependencies = new DependencyResolver(retriever_, repositories_, dependency).getMavenPom(parent).getDependencies(scopes); next_dependencies = new DependencyResolver(resolution_, retriever_, repositories_, dependency).getMavenPom(parent).getDependencies(scopes);
break; break;
} }
} }
@ -188,7 +193,7 @@ public class DependencyResolver {
* couldn't be found in the provided repositories * couldn't be found in the provided repositories
* @since 1.5 * @since 1.5
*/ */
public List<VersionNumber> listVersions() { public List<Version> listVersions() {
return getMavenMetadata().getVersions(); return getMavenMetadata().getVersions();
} }
@ -199,7 +204,7 @@ public class DependencyResolver {
* if the dependency couldn't be found in the provided repositories * if the dependency couldn't be found in the provided repositories
* @since 1.5 * @since 1.5
*/ */
public VersionNumber latestVersion() { public Version latestVersion() {
return getMavenMetadata().getLatest(); return getMavenMetadata().getLatest();
} }
@ -210,7 +215,7 @@ public class DependencyResolver {
* if the dependency couldn't be found in the provided repositories * if the dependency couldn't be found in the provided repositories
* @since 1.5 * @since 1.5
*/ */
public VersionNumber releaseVersion() { public Version releaseVersion() {
return getMavenMetadata().getRelease(); return getMavenMetadata().getRelease();
} }
@ -258,6 +263,16 @@ public class DependencyResolver {
return dependency_; return dependency_;
} }
/**
* Returns the version resolution state that can be cached.
*
* @return the version resolution state
* @since 2.0
*/
public VersionResolution resolution() {
return resolution_;
}
/** /**
* Retrieves all the potential locations for the dependency * Retrieves all the potential locations for the dependency
* within the provided repositories. * within the provided repositories.
@ -305,7 +320,7 @@ public class DependencyResolver {
private List<RepositoryArtifact> getTransferArtifacts() { private List<RepositoryArtifact> getTransferArtifacts() {
final var version = resolveVersion(); final var version = resolveVersion();
final VersionNumber pom_version; final Version pom_version;
if (version.isSnapshot()) { if (version.isSnapshot()) {
var metadata = getSnapshotMavenMetadata(); var metadata = getSnapshotMavenMetadata();
pom_version = metadata.getSnapshot(); pom_version = metadata.getSnapshot();
@ -315,15 +330,15 @@ public class DependencyResolver {
return getArtifactLocations().stream().map(a -> { return getArtifactLocations().stream().map(a -> {
var result = new StringBuilder(); var result = new StringBuilder();
result.append(version).append("/").append(dependency_.artifactId()).append("-").append(pom_version); result.append(version).append('/').append(dependency_.artifactId()).append('-').append(pom_version);
if (!dependency_.classifier().isEmpty()) { if (!dependency_.classifier().isEmpty()) {
result.append("-").append(dependency_.classifier()); result.append('-').append(dependency_.classifier());
} }
var type = dependency_.type(); var type = dependency_.type();
if (type == null) { if (type == null || TYPE_JAR.equals(type) || TYPE_MODULAR_JAR.equals(type) || TYPE_CLASSPATH_JAR.equals(type)) {
type = "jar"; type = "jar";
} }
result.append(".").append(type); result.append('.').append(type);
return a.appendPath(result.toString()); return a.appendPath(result.toString());
}).toList(); }).toList();
@ -365,7 +380,16 @@ public class DependencyResolver {
} }
if (metadata == null) { if (metadata == null) {
throw new ArtifactNotFoundException(dependency_, artifacts.stream().map(RepositoryArtifact::location).collect(Collectors.joining(", "))); var location = artifacts.stream().map(RepositoryArtifact::location).collect(Collectors.joining(", "));
if (location.isEmpty()) {
if (repositories_.isEmpty()) {
location = "[no repositories defined]";
}
else {
location = "[no metadata locations defined]";
}
}
throw new ArtifactNotFoundException(dependency_, location);
} }
var xml = new Xml2MavenMetadata(); var xml = new Xml2MavenMetadata();
@ -378,7 +402,7 @@ public class DependencyResolver {
private List<RepositoryArtifact> getPomLocations() { private List<RepositoryArtifact> getPomLocations() {
final var version = resolveVersion(); final var version = resolveVersion();
final VersionNumber pom_version; final Version pom_version;
if (version.isSnapshot()) { if (version.isSnapshot()) {
var metadata = getSnapshotMavenMetadata(); var metadata = getSnapshotMavenMetadata();
pom_version = metadata.getSnapshot(); pom_version = metadata.getSnapshot();
@ -414,10 +438,24 @@ public class DependencyResolver {
} }
if (pom == null) { if (pom == null) {
throw new ArtifactNotFoundException(dependency_, artifacts.stream().map(RepositoryArtifact::location).collect(Collectors.joining(", "))); var location = artifacts.stream().map(RepositoryArtifact::location).collect(Collectors.joining(", "));
if (location.isEmpty()) {
if (repositories_.isEmpty()) {
location = "[no repositories defined]";
}
else {
location = "[no pom locations defined]";
}
}
throw new ArtifactNotFoundException(dependency_, location);
} }
var xml = new Xml2MavenPom(parent, retriever_, repositories_); var xml = new Xml2MavenPom(parent, resolution_, retriever_, repositories_);
// first pass only extracts the properties from the pom
if (!xml.processXml(pom)) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors());
}
// second pass parses all the rest so that the properties are available anywhere
if (!xml.processXml(pom)) { if (!xml.processXml(pom)) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors()); throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors());
} }

View file

@ -4,6 +4,8 @@
*/ */
package rife.bld.dependencies; package rife.bld.dependencies;
import rife.ioc.HierarchicalProperties;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -66,43 +68,62 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
/** /**
* Returns the transitive set of dependencies that would be used for the compile scope in a project. * Returns the transitive set of dependencies that would be used for the compile scope in a project.
* *
* @param properties the properties to use to get artifacts
* @param retriever the retriever to use to get artifacts * @param retriever the retriever to use to get artifacts
* @param repositories the repositories to use for the resolution * @param repositories the repositories to use for the resolution
* @return the compile scope dependency set * @return the compile scope dependency set
* @since 1.6 * @since 2.0
*/ */
public DependencySet resolveCompileDependencies(ArtifactRetriever retriever, List<Repository> repositories) { public DependencySet resolveCompileDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
return resolveScopedDependencies(retriever, repositories, return resolveScopedDependencies(properties, retriever, repositories,
new Scope[]{Scope.provided, Scope.compile},
new Scope[]{Scope.compile}, new Scope[]{Scope.compile},
new Scope[]{Scope.compile},
null);
}
/**
* Returns the transitive set of dependencies that would be used for the provided scope in a project.
*
* @param properties the properties to use to get artifacts
* @param retriever the retriever to use to get artifacts
* @param repositories the repositories to use for the resolution
* @return the provided scope dependency set
* @since 2.0
*/
public DependencySet resolveProvidedDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
return resolveScopedDependencies(properties, retriever, repositories,
new Scope[]{Scope.provided},
new Scope[]{Scope.compile, Scope.runtime},
null); null);
} }
/** /**
* Returns the transitive set of dependencies that would be used for the runtime scope in a project. * Returns the transitive set of dependencies that would be used for the runtime scope in a project.
* *
* @param properties the properties to use to get artifacts
* @param retriever the retriever to use to get artifacts * @param retriever the retriever to use to get artifacts
* @param repositories the repositories to use for the resolution * @param repositories the repositories to use for the resolution
* @return the runtime scope dependency set * @return the runtime scope dependency set
* @since 1.6 * @since 2.0
*/ */
public DependencySet resolveRuntimeDependencies(ArtifactRetriever retriever, List<Repository> repositories) { public DependencySet resolveRuntimeDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
return resolveScopedDependencies(retriever, repositories, return resolveScopedDependencies(properties, retriever, repositories,
new Scope[]{Scope.provided, Scope.compile, Scope.runtime},
new Scope[]{Scope.compile, Scope.runtime}, new Scope[]{Scope.compile, Scope.runtime},
resolveCompileDependencies(retriever, repositories)); new Scope[]{Scope.compile, Scope.runtime},
resolveCompileDependencies(properties, retriever, repositories));
} }
/** /**
* Returns the transitive set of dependencies that would be used for the standalone scope in a project. * Returns the transitive set of dependencies that would be used for the standalone scope in a project.
* *
* @param properties the properties to use to get artifacts
* @param retriever the retriever to use to get artifacts * @param retriever the retriever to use to get artifacts
* @param repositories the repositories to use for the resolution * @param repositories the repositories to use for the resolution
* @return the standalone scope dependency set * @return the standalone scope dependency set
* @since 1.6 * @since 2.0
*/ */
public DependencySet resolveStandaloneDependencies(ArtifactRetriever retriever, List<Repository> repositories) { public DependencySet resolveStandaloneDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
return resolveScopedDependencies(retriever, repositories, return resolveScopedDependencies(properties, retriever, repositories,
new Scope[]{Scope.standalone}, new Scope[]{Scope.standalone},
new Scope[]{Scope.compile, Scope.runtime}, new Scope[]{Scope.compile, Scope.runtime},
null); null);
@ -111,25 +132,27 @@ public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
/** /**
* Returns the transitive set of dependencies that would be used for the test scope in a project. * Returns the transitive set of dependencies that would be used for the test scope in a project.
* *
* @param properties the properties to use to get artifacts
* @param retriever the retriever to use to get artifacts * @param retriever the retriever to use to get artifacts
* @param repositories the repositories to use for the resolution * @param repositories the repositories to use for the resolution
* @return the test scope dependency set * @return the test scope dependency set
* @since 1.6 * @since 2.0
*/ */
public DependencySet resolveTestDependencies(ArtifactRetriever retriever, List<Repository> repositories) { public DependencySet resolveTestDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories) {
return resolveScopedDependencies(retriever, repositories, return resolveScopedDependencies(properties, retriever, repositories,
new Scope[]{Scope.test}, new Scope[]{Scope.test},
new Scope[]{Scope.compile, Scope.runtime}, new Scope[]{Scope.compile, Scope.runtime},
null); null);
} }
private DependencySet resolveScopedDependencies(ArtifactRetriever retriever, List<Repository> repositories, Scope[] resolvedScopes, Scope[] transitiveScopes, DependencySet excluded) { private DependencySet resolveScopedDependencies(HierarchicalProperties properties, ArtifactRetriever retriever, List<Repository> repositories, Scope[] resolvedScopes, Scope[] transitiveScopes, DependencySet excluded) {
var resolution = new VersionResolution(properties);
var dependencies = new DependencySet(); var dependencies = new DependencySet();
for (var scope : resolvedScopes) { for (var scope : resolvedScopes) {
var scoped_dependencies = get(scope); var scoped_dependencies = get(scope);
if (scoped_dependencies != null) { if (scoped_dependencies != null) {
for (var dependency : scoped_dependencies) { for (var dependency : scoped_dependencies) {
dependencies.addAll(new DependencyResolver(retriever, repositories, dependency).getAllDependencies(transitiveScopes)); dependencies.addAll(new DependencyResolver(resolution, retriever, repositories, dependency).getAllDependencies(transitiveScopes));
} }
} }
} }

View file

@ -23,6 +23,7 @@ import java.util.*;
public class DependencySet extends AbstractSet<Dependency> implements Set<Dependency> { public class DependencySet extends AbstractSet<Dependency> implements Set<Dependency> {
private final Map<Dependency, Dependency> dependencies_ = new LinkedHashMap<>(); private final Map<Dependency, Dependency> dependencies_ = new LinkedHashMap<>();
private final Set<LocalDependency> localDependencies_ = new LinkedHashSet<>(); private final Set<LocalDependency> localDependencies_ = new LinkedHashSet<>();
private final Set<LocalModule> localModules_ = new LinkedHashSet<>();
/** /**
* Creates an empty dependency set. * Creates an empty dependency set.
@ -79,48 +80,94 @@ public class DependencySet extends AbstractSet<Dependency> implements Set<Depend
return localDependencies_; return localDependencies_;
} }
/**
* Includes a local module into the dependency set.
* <p>
* Local modules aren't resolved and point to a location on
* the file system.
*
* @param module the module to include
* @return this dependency set instance
* @since 2.1
*/
public DependencySet include(LocalModule module) {
localModules_.add(module);
return this;
}
/**
* Retrieves the local modules.
*
* @return the set of local modules
* @since 2.1
*/
public Set<LocalModule> localModules() {
return localModules_;
}
/** /**
* Transfers the artifacts for the dependencies into the provided directory. * Transfers the artifacts for the dependencies into the provided directory.
* <p> * <p>
* The destination directory must exist and be writable. * The destination directory must exist and be writable.
* *
* @param resolution the version resolution state that can be cached
* @param retriever the retriever to use to get artifacts * @param retriever the retriever to use to get artifacts
* @param repositories the repositories to use for the transfer * @param repositories the repositories to use for the transfer
* @param directory the directory to transfer the artifacts into * @param directory the directory to transfer the artifacts into
* @param modulesDirectory the directory to download the modules into
* @return the list of artifacts that were transferred successfully * @return the list of artifacts that were transferred successfully
* @throws DependencyTransferException when an error occurred during the transfer * @throws DependencyTransferException when an error occurred during the transfer
* @since 1.5.10 * @since 2.1
*/ */
public List<RepositoryArtifact> transferIntoDirectory(ArtifactRetriever retriever, List<Repository> repositories, File directory) { public List<RepositoryArtifact> transferIntoDirectory(VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories, File directory, File modulesDirectory) {
return transferIntoDirectory(retriever, repositories, directory, (String[]) null); return transferIntoDirectory(resolution, retriever, repositories, directory, modulesDirectory, (String[]) null);
} }
/** /**
* Transfers the artifacts for the dependencies into the provided directory, * Transfers the artifacts for the dependencies into the provided directories,
* including other classifiers. * including other classifiers.
* <p> * <p>
* The destination directory must exist and be writable. * The destination directory must exist and be writable.
* *
* @param resolution the version resolution state that can be cached
* @param retriever the retriever to use to get artifacts * @param retriever the retriever to use to get artifacts
* @param repositories the repositories to use for the download * @param repositories the repositories to use for the download
* @param directory the directory to download the artifacts into * @param directory the directory to download the artifacts into
* @param modulesDirectory the directory to download the modules into
* @param classifiers the additional classifiers to transfer * @param classifiers the additional classifiers to transfer
* @return the list of artifacts that were transferred successfully * @return the list of artifacts that were transferred successfully
* @throws DependencyTransferException when an error occurred during the transfer * @throws DependencyTransferException when an error occurred during the transfer
* @since 1.5.10 * @since 2.1
*/ */
public List<RepositoryArtifact> transferIntoDirectory(ArtifactRetriever retriever, List<Repository> repositories, File directory, String... classifiers) { public List<RepositoryArtifact> transferIntoDirectory(VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories, File directory, File modulesDirectory, String... classifiers) {
var result = new ArrayList<RepositoryArtifact>(); var result = new ArrayList<RepositoryArtifact>();
for (var dependency : this) { for (var dependency : this) {
var artifact = new DependencyResolver(retriever, repositories, dependency).transferIntoDirectory(directory); var transfer_directory = directory;
if (dependency.isModularJar()) {
if (modulesDirectory == null) {
throw new DependencyTransferException(dependency, "modules directory is not provided");
}
transfer_directory = modulesDirectory;
}
else if (directory == null) {
throw new DependencyTransferException(dependency, "artifacts directory is not provided");
}
if (!transfer_directory.exists()) {
if (!transfer_directory.mkdirs()) {
throw new DependencyTransferException(dependency, transfer_directory, "couldn't create directory");
}
}
var artifact = new DependencyResolver(resolution, retriever, repositories, dependency).transferIntoDirectory(transfer_directory);
if (artifact != null) { if (artifact != null) {
result.add(artifact); result.add(artifact);
} }
if (classifiers != null) { if (classifiers != null) {
for (var classifier : classifiers) { for (var classifier : classifiers) {
if (classifier != null) { if (classifier != null && !dependency.excludedClassifiers().contains(classifier)) {
var classifier_artifact = new DependencyResolver(retriever, repositories, dependency.withClassifier(classifier)).transferIntoDirectory(directory); var classifier_artifact = new DependencyResolver(resolution, retriever, repositories, dependency.withClassifier(classifier)).transferIntoDirectory(transfer_directory);
if (classifier_artifact != null) { if (classifier_artifact != null) {
result.add(classifier_artifact); result.add(classifier_artifact);
} }
@ -150,17 +197,18 @@ public class DependencySet extends AbstractSet<Dependency> implements Set<Depend
* Generates the string description of the transitive hierarchical tree of * Generates the string description of the transitive hierarchical tree of
* dependencies for a particular scope. * dependencies for a particular scope.
* *
* @param resolution the version resolution state that can be cached
* @param retriever the retriever to use to get artifacts * @param retriever the retriever to use to get artifacts
* @param repositories the repositories to look for dependencies in * @param repositories the repositories to look for dependencies in
* @param scopes the scopes to return the transitive dependencies for * @param scopes the scopes to return the transitive dependencies for
* @return the generated tree description string; or an empty string if * @return the generated tree description string; or an empty string if
* there were no dependencies to describe * there were no dependencies to describe
* @since 1.5.21 * @since 2.0
*/ */
public String generateTransitiveDependencyTree(ArtifactRetriever retriever, List<Repository> repositories, Scope... scopes) { public String generateTransitiveDependencyTree(VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories, Scope... scopes) {
var compile_dependencies = new DependencySet(); var compile_dependencies = new DependencySet();
for (var dependency : this) { for (var dependency : this) {
compile_dependencies.addAll(new DependencyResolver(retriever, repositories, dependency).getAllDependencies(scopes)); compile_dependencies.addAll(new DependencyResolver(resolution, retriever, repositories, dependency).getAllDependencies(scopes));
} }
return compile_dependencies.generateDependencyTree(); return compile_dependencies.generateDependencyTree();
} }

View file

@ -0,0 +1,17 @@
/*
* Copyright 2001-2024 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.dependencies;
/**
* Contains the information required to describe a local module for the build system.
* <p>
* If the local module points to a directory, it will be scanned for jar files.
*
* @param path the file system path of the local module
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 2.1
*/
public record LocalModule(String path) {
}

View file

@ -14,28 +14,28 @@ import java.util.List;
*/ */
public interface MavenMetadata { public interface MavenMetadata {
/** /**
* Returns latest version number in the metadata. * Returns latest version in the metadata.
* *
* @return the latest version number * @return the latest version
* @since 1.5.8 * @since 1.5.8
*/ */
VersionNumber getLatest(); Version getLatest();
/** /**
* Returns release version number in the metadata. * Returns release version in the metadata.
* *
* @return the release version number * @return the release version
* @since 1.5.8 * @since 1.5.8
*/ */
VersionNumber getRelease(); Version getRelease();
/** /**
* Returns snapshot version number in the metadata. * Returns snapshot version in the metadata.
* *
* @return the snapshot version number * @return the snapshot version
* @since 1.5.8 * @since 1.5.8
*/ */
VersionNumber getSnapshot(); Version getSnapshot();
/** /**
* Returns snapshot timestamp in the metadata. * Returns snapshot timestamp in the metadata.
@ -56,8 +56,8 @@ public interface MavenMetadata {
/** /**
* Returns all the release or snapshot versions in the metadata. * Returns all the release or snapshot versions in the metadata.
* *
* @return the version number list * @return the version list
* @since 1.5.8 * @since 1.5.8
*/ */
List<VersionNumber> getVersions(); List<Version> getVersions();
} }

View file

@ -0,0 +1,67 @@
/*
* Copyright 2001-2024 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.dependencies;
import java.util.regex.Pattern;
/**
* Contains the information required to describe a Java module dependency in the build system.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 2.1
*/
public class Module extends Dependency {
public Module(String groupId, String artifactId) {
this(groupId, artifactId, null, null, null, null);
}
public Module(String groupId, String artifactId, Version version) {
this(groupId, artifactId, version, null, null, null);
}
public Module(String groupId, String artifactId, Version version, String classifier) {
this(groupId, artifactId, version, classifier, null, null);
}
public Module(String groupId, String artifactId, Version version, String classifier, ExclusionSet exclusions) {
this(groupId, artifactId, version, classifier, exclusions, null);
}
public Module(String groupId, String artifactId, Version version, String classifier, ExclusionSet exclusions, Dependency parent) {
super(groupId, artifactId, version, classifier, TYPE_MODULAR_JAR, exclusions, parent);
}
private static final Pattern MODULE_PATTERN = Pattern.compile("^(?<groupId>[^:@]+):(?<artifactId>[^:@]+)(?::(?<version>[^:@]+)(?::(?<classifier>[^:@]+))?)?(?:@modular-jar)?$");
/**
* Parses a module from a string representation.
* The format is {@code groupId:artifactId:version:classifier}.
* The {@code version} and {@code classifier} are optional.
* <p>
* If the string can't be successfully parsed, {@code null} will be returned.
*
* @param module the module string to parse
* @return a parsed instance of {@code Module}; or
* {@code null} when the string couldn't be parsed
* @since 2.1
*/
public static Module parse(String module) {
if (module == null || module.isEmpty()) {
return null;
}
var matcher = MODULE_PATTERN.matcher(module);
if (!matcher.matches()) {
return null;
}
var groupId = matcher.group("groupId");
var artifactId = matcher.group("artifactId");
var version = Version.parse(matcher.group("version"));
var classifier = matcher.group("classifier");
return new Module(groupId, artifactId, version, classifier);
}
}

View file

@ -34,7 +34,7 @@ public record PomDependency(String groupId, String artifactId, String version, S
return new Dependency( return new Dependency(
groupId(), groupId(),
artifactId(), artifactId(),
VersionNumber.parse(version()), Version.parse(version()),
classifier(), classifier(),
type(), type(),
exclusions(), exclusions(),

View file

@ -7,8 +7,10 @@ package rife.bld.dependencies;
import rife.ioc.HierarchicalProperties; import rife.ioc.HierarchicalProperties;
import rife.tools.StringEncryptor; import rife.tools.StringEncryptor;
import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.regex.Pattern;
/** /**
* Contains the information required to locate a Maven-compatible repository. * Contains the information required to locate a Maven-compatible repository.
@ -21,11 +23,18 @@ import java.security.NoSuchAlgorithmException;
*/ */
public record Repository(String location, String username, String password) { public record Repository(String location, String username, String password) {
public static Repository MAVEN_LOCAL = null; public static Repository MAVEN_LOCAL = null;
public static final Repository APACHE = new Repository("https://repo.maven.apache.org/maven2/");
public static final Repository GOOGLE = new Repository("https://maven.google.com/");
public static final Repository MAVEN_CENTRAL = new Repository("https://repo1.maven.org/maven2/"); public static final Repository MAVEN_CENTRAL = new Repository("https://repo1.maven.org/maven2/");
public static final Repository SECURECHAIN_REBUILT = new Repository("https://nexus-repo.corp.cloudlinux.com/repository/tuxcare_rebuilt");
public static final Repository SECURECHAIN_VETTED = new Repository("https://nexus-repo.corp.cloudlinux.com/repository/tuxcare_vetted");
public static final Repository SONATYPE_RELEASES = new Repository("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"); public static final Repository SONATYPE_RELEASES = new Repository("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/");
public static final Repository SONATYPE_RELEASES_LEGACY = new Repository("https://oss.sonatype.org/service/local/staging/deploy/maven2/");
public static final Repository SONATYPE_SNAPSHOTS = new Repository("https://s01.oss.sonatype.org/content/repositories/snapshots/"); public static final Repository SONATYPE_SNAPSHOTS = new Repository("https://s01.oss.sonatype.org/content/repositories/snapshots/");
public static final Repository SONATYPE_SNAPSHOTS_LEGACY = new Repository("https://oss.sonatype.org/content/repositories/snapshots/"); public static final Repository SONATYPE_SNAPSHOTS_LEGACY = new Repository("https://oss.sonatype.org/content/repositories/snapshots/");
public static final Repository APACHE = new Repository("https://repo.maven.apache.org/maven2/"); public static final String OSSRH_STAGING_API_DOMAIN = "ossrh-staging-api.central.sonatype.com";
public static final Repository CENTRAL_RELEASES = new Repository("https://" + OSSRH_STAGING_API_DOMAIN + "/service/local/staging/deploy/maven2/");
public static final Repository CENTRAL_SNAPSHOTS = new Repository("https://central.sonatype.com/repository/maven-snapshots/");
public static final Repository RIFE2_RELEASES = new Repository("https://repo.rife2.com/releases/"); public static final Repository RIFE2_RELEASES = new Repository("https://repo.rife2.com/releases/");
public static final Repository RIFE2_SNAPSHOTS = new Repository("https://repo.rife2.com/snapshots/"); public static final Repository RIFE2_SNAPSHOTS = new Repository("https://repo.rife2.com/snapshots/");
@ -80,14 +89,20 @@ public record Repository(String location, String username, String password) {
} }
return switch (locationOrName) { return switch (locationOrName) {
case "MAVEN_LOCAL" -> Repository.MAVEN_LOCAL;
case "MAVEN_CENTRAL" -> Repository.MAVEN_CENTRAL;
case "SONATYPE_RELEASES" -> Repository.SONATYPE_RELEASES;
case "SONATYPE_SNAPSHOTS" -> Repository.SONATYPE_SNAPSHOTS;
case "SONATYPE_SNAPSHOTS_LEGACY" -> Repository.SONATYPE_SNAPSHOTS_LEGACY;
case "APACHE" -> Repository.APACHE; case "APACHE" -> Repository.APACHE;
case "GOOGLE" -> Repository.GOOGLE;
case "MAVEN_CENTRAL" -> Repository.MAVEN_CENTRAL;
case "MAVEN_LOCAL" -> Repository.MAVEN_LOCAL;
case "RIFE2_RELEASES" -> Repository.RIFE2_RELEASES; case "RIFE2_RELEASES" -> Repository.RIFE2_RELEASES;
case "RIFE2_SNAPSHOTS" -> Repository.RIFE2_SNAPSHOTS; case "RIFE2_SNAPSHOTS" -> Repository.RIFE2_SNAPSHOTS;
case "SECURECHAIN_REBUILT" -> SECURECHAIN_REBUILT;
case "SECURECHAIN_VETTED" -> SECURECHAIN_VETTED;
case "SONATYPE_RELEASES" -> Repository.SONATYPE_RELEASES;
case "SONATYPE_RELEASES_LEGACY" -> Repository.SONATYPE_RELEASES_LEGACY;
case "SONATYPE_SNAPSHOTS" -> Repository.SONATYPE_SNAPSHOTS;
case "SONATYPE_SNAPSHOTS_LEGACY" -> Repository.SONATYPE_SNAPSHOTS_LEGACY;
case "CENTRAL_RELEASES" -> Repository.CENTRAL_RELEASES;
case "CENTRAL_SNAPSHOTS" -> Repository.CENTRAL_SNAPSHOTS;
default -> new Repository(locationOrName); default -> new Repository(locationOrName);
}; };
} }
@ -102,6 +117,12 @@ public record Repository(String location, String username, String password) {
this(location, null, null); this(location, null, null);
} }
private final static Pattern WINDOWS_ABSOLUTE_PATH = Pattern.compile("^\\p{L}:\\\\");
private boolean isWindowsLocation() {
return WINDOWS_ABSOLUTE_PATH.matcher(location()).find();
}
/** /**
* Indicates whether this repository is local. * Indicates whether this repository is local.
* *
@ -110,7 +131,7 @@ public record Repository(String location, String username, String password) {
* @since 1.5.10 * @since 1.5.10
*/ */
public boolean isLocal() { public boolean isLocal() {
return location().startsWith("/") || location().startsWith("file:"); return location().startsWith("/") || location().startsWith("file:") || isWindowsLocation();
} }
/** /**
@ -146,9 +167,12 @@ public record Repository(String location, String username, String password) {
* @since 1.5.10 * @since 1.5.10
*/ */
public String getArtifactLocation(String groupId, String artifactId) { public String getArtifactLocation(String groupId, String artifactId) {
var group_path = groupId.replace(".", "/"); var separator = "/";
var result = new StringBuilder(); var result = new StringBuilder();
if (isLocal()) { if (isLocal()) {
if (isWindowsLocation()) {
separator = File.separator;
}
if (location().startsWith("file://")) { if (location().startsWith("file://")) {
result.append(location().substring("file://".length())); result.append(location().substring("file://".length()));
} else { } else {
@ -157,10 +181,11 @@ public record Repository(String location, String username, String password) {
} else { } else {
result.append(location()); result.append(location());
} }
if (!location().endsWith("/")) { if (!location().endsWith(separator)) {
result.append("/"); result.append(separator);
} }
return result.append(group_path).append("/").append(artifactId).append("/").toString(); var group_path = groupId.replace(".", separator);
return result.append(group_path).append(separator).append(artifactId).append(separator).toString();
} }
/** /**
@ -180,11 +205,11 @@ public record Repository(String location, String username, String password) {
public String toString() { public String toString() {
var result = new StringBuilder(location); var result = new StringBuilder(location);
if (username() != null) { if (username() != null) {
result.append(":"); result.append(':');
try { try {
result.append(StringEncryptor.MD5HLO.performEncryption(username(), null)); result.append(StringEncryptor.MD5HLO.performEncryption(username(), null));
if (password() != null) { if (password() != null) {
result.append(":"); result.append(':');
result.append(StringEncryptor.MD5HLO.performEncryption(password(), null)); result.append(StringEncryptor.MD5HLO.performEncryption(password(), null));
} }
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {

View file

@ -0,0 +1,79 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.dependencies;
import static rife.bld.dependencies.VersionNumber.parseOrNull;
/**
* Represents the basic functionality of a dependency version.
*
* @since 2.0
*/
public interface Version extends Comparable<Version> {
/**
* Parses a version from a string representation.
* <p>
* If the string can't be successfully parsed as a semantic {@link VersionNumber},
* it will be parsed as a {@link VersionGeneric}.
*
* @param version the version string to parse
* @return the parsed version instance
* @since 2.0
*/
static Version parse(String version) {
if (version == null || version.isEmpty()) {
return VersionNumber.UNKNOWN;
}
var result = parseOrNull(version);
if (result != null) {
return result;
}
// bld doesn't support version ranges at this time
if (version.startsWith("[") || version.startsWith("(")) {
return VersionNumber.UNKNOWN;
}
return new VersionGeneric(version);
}
/**
* Retrieves the qualifier of the version.
*
* @return this version's qualifier
* @since 2.0
*/
String qualifier();
/**
* Retrieves the version number with a different qualifier.
*
* @return this version number with a different qualifier
* @since 2.0
*/
Version withQualifier(String qualifier);
/**
* Indicates whether this is a snapshot version.
*
* @return {@code true} if this is a snapshot version; or
* {@code false} otherwise
* @since 2.0
*/
boolean isSnapshot();
@Override
int compareTo(Version other);
@Override
String toString();
@Override
boolean equals(Object other);
@Override
int hashCode();
}

View file

@ -0,0 +1,373 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.dependencies;
import java.math.BigInteger;
import java.util.*;
import static java.util.Objects.requireNonNull;
/**
* Generic version implementation based on the Maven implementation.
*
* @since 2.0
*/
// https://github.com/apache/maven-resolver/blob/98126539f3c66fc4ab50b178c2eb4b8fd169fd72/maven-resolver-util/src/main/java/org/eclipse/aether/util/version/GenericVersion.java
public class VersionGeneric implements Version {
private final String version_;
private final List<Item> items_;
private final int hash_;
@Override
public String qualifier() {
return "";
}
@Override
public Version withQualifier(String qualifier) {
return new VersionGeneric(version_);
}
@Override
public boolean isSnapshot() {
return false;
}
/**
* Creates a generic version from the specified string.
*
* @param version The version string, must not be {@code null}.
* @since 2.0
*/
public VersionGeneric(String version) {
version_ = requireNonNull(version, "version cannot be null");
items_ = parse(version);
hash_ = items_.hashCode();
}
/**
* Visible for testing.
*/
List<Item> asItems() {
return items_;
}
private static List<Item> parse(String version) {
var items = new ArrayList<Item>();
for (var tokenizer = new Tokenizer(version); tokenizer.next(); ) {
var item = tokenizer.toItem();
items.add(item);
}
trimPadding(items);
return Collections.unmodifiableList(items);
}
/**
* Visible for testing.
*/
static void trimPadding(List<Item> items) {
Boolean number = null;
var end = items.size() - 1;
for (var i = end; i > 0; i--) {
var item = items.get(i);
if (!Boolean.valueOf(item.isNumber()).equals(number)) {
end = i;
number = item.isNumber();
}
if (end == i
&& (i == items.size() - 1 || items.get(i - 1).isNumber() == item.isNumber())
&& item.compareTo(null) == 0) {
items.remove(i);
end--;
}
}
}
@Override
public int compareTo(Version other) {
VersionGeneric generic;
if (other instanceof VersionGeneric) {
generic = (VersionGeneric)other;
}
else {
generic = new VersionGeneric(other.toString());
}
final var these = items_;
final var those = generic.items_;
var number = true;
for (var index = 0; ; index++) {
if (index >= these.size() && index >= those.size()) {
return 0;
} else if (index >= these.size()) {
return -comparePadding(those, index, null);
} else if (index >= those.size()) {
return comparePadding(these, index, null);
}
var thisItem = these.get(index);
var thatItem = those.get(index);
if (thisItem.isNumber() != thatItem.isNumber()) {
if (index == 0) {
return thisItem.compareTo(thatItem);
}
if (number == thisItem.isNumber()) {
return comparePadding(these, index, number);
} else {
return -comparePadding(those, index, number);
}
} else {
var rel = thisItem.compareTo(thatItem);
if (rel != 0) {
return rel;
}
number = thisItem.isNumber();
}
}
}
private static int comparePadding(List<Item> items, int index, Boolean number) {
var rel = 0;
for (var i = index; i < items.size(); i++) {
var item = items.get(i);
if (number != null && number != item.isNumber()) {
// do not stop here, but continue, skipping non-number members
continue;
}
rel = item.compareTo(null);
if (rel != 0) {
break;
}
}
return rel;
}
@Override
public boolean equals(Object obj) {
return (obj instanceof VersionGeneric) && compareTo((VersionGeneric) obj) == 0;
}
@Override
public int hashCode() {
return hash_;
}
@Override
public String toString() {
return version_;
}
static final class Tokenizer {
private static final Integer QUALIFIER_ALPHA = -5;
private static final Integer QUALIFIER_BETA = -4;
private static final Integer QUALIFIER_MILESTONE = -3;
private static final Map<String, Integer> QUALIFIERS;
static {
QUALIFIERS = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
QUALIFIERS.put("alpha", QUALIFIER_ALPHA);
QUALIFIERS.put("beta", QUALIFIER_BETA);
QUALIFIERS.put("milestone", QUALIFIER_MILESTONE);
QUALIFIERS.put("cr", -2);
QUALIFIERS.put("rc", -2);
QUALIFIERS.put("snapshot", -1);
QUALIFIERS.put("ga", 0);
QUALIFIERS.put("final", 0);
QUALIFIERS.put("release", 0);
QUALIFIERS.put("", 0);
QUALIFIERS.put("sp", 1);
}
private final String version_;
private final int versionLength_;
private int index_;
private String token_;
private boolean number_;
private boolean terminatedByNumber_;
Tokenizer(String version) {
version_ = (!version.isEmpty()) ? version : "0";
versionLength_ = this.version_.length();
}
public boolean next() {
if (index_ >= versionLength_) {
return false;
}
var state = -2;
var start = index_;
var end = versionLength_;
terminatedByNumber_ = false;
for (; index_ < versionLength_; index_++) {
var c = version_.charAt(index_);
if (c == '.' || c == '-' || c == '_') {
end = index_;
index_++;
break;
} else {
var digit = Character.digit(c, 10);
if (digit >= 0) {
if (state == -1) {
end = index_;
terminatedByNumber_ = true;
break;
}
if (state == 0) {
// normalize numbers and strip leading zeros (prereq for Integer/BigInteger handling)
start++;
}
state = (state > 0 || digit > 0) ? 1 : 0;
} else {
if (state >= 0) {
end = index_;
break;
}
state = -1;
}
}
}
if (end - start > 0) {
token_ = version_.substring(start, end);
number_ = state >= 0;
} else {
token_ = "0";
number_ = true;
}
return true;
}
@Override
public String toString() {
return String.valueOf(token_);
}
public Item toItem() {
if (number_) {
try {
if (token_.length() < 10) {
return new Item(Item.KIND_INT, Integer.parseInt(token_));
} else {
return new Item(Item.KIND_BIGINT, new BigInteger(token_));
}
} catch (NumberFormatException e) {
throw new IllegalStateException(e);
}
} else {
if (index_ >= version_.length()) {
if ("min".equalsIgnoreCase(token_)) {
return Item.MIN;
} else if ("max".equalsIgnoreCase(token_)) {
return Item.MAX;
}
}
if (terminatedByNumber_ && token_.length() == 1) {
switch (token_.charAt(0)) {
case 'a':
case 'A':
return new Item(Item.KIND_QUALIFIER, QUALIFIER_ALPHA);
case 'b':
case 'B':
return new Item(Item.KIND_QUALIFIER, QUALIFIER_BETA);
case 'm':
case 'M':
return new Item(Item.KIND_QUALIFIER, QUALIFIER_MILESTONE);
default:
}
}
var qualifier = QUALIFIERS.get(token_);
if (qualifier != null) {
return new Item(Item.KIND_QUALIFIER, qualifier);
} else {
return new Item(Item.KIND_STRING, token_.toLowerCase(Locale.ENGLISH));
}
}
}
}
static final class Item {
static final int KIND_MAX = 8;
static final int KIND_BIGINT = 5;
static final int KIND_INT = 4;
static final int KIND_STRING = 3;
static final int KIND_QUALIFIER = 2;
static final int KIND_MIN = 0;
static final Item MAX = new Item(KIND_MAX, "max");
static final Item MIN = new Item(KIND_MIN, "min");
private final int kind_;
private final Object value_;
Item(int kind, Object value) {
kind_ = kind;
value_ = value;
}
public boolean isNumber() {
return (kind_ & KIND_QUALIFIER) == 0; // i.e. kind != string/qualifier
}
public int compareTo(Item that) {
int rel;
if (that == null) {
// null in this context denotes the pad item (0 or "ga")
rel = switch (kind_) {
case KIND_MIN -> -1;
case KIND_MAX, KIND_BIGINT, KIND_STRING -> 1;
case KIND_INT, KIND_QUALIFIER -> (Integer) value_;
default -> throw new IllegalStateException("unknown version item kind " + kind_);
};
} else {
rel = kind_ - that.kind_;
if (rel == 0) {
switch (kind_) {
case KIND_MAX:
case KIND_MIN:
break;
case KIND_BIGINT:
rel = ((BigInteger) value_).compareTo((BigInteger) that.value_);
break;
case KIND_INT:
case KIND_QUALIFIER:
rel = ((Integer) value_).compareTo((Integer) that.value_);
break;
case KIND_STRING:
rel = ((String) value_).compareToIgnoreCase((String) that.value_);
break;
default:
throw new IllegalStateException("unknown version item kind " + kind_);
}
}
}
return rel;
}
@Override
public boolean equals(Object obj) {
return (obj instanceof Item) && compareTo((Item) obj) == 0;
}
@Override
public int hashCode() {
return value_.hashCode() + kind_ * 31;
}
@Override
public String toString() {
return String.valueOf(value_);
}
}
}

View file

@ -22,7 +22,7 @@ import java.util.regex.Pattern;
* @author Geert Bevin (gbevin[remove] at uwyn dot com) * @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5 * @since 1.5
*/ */
public record VersionNumber(Integer major, Integer minor, Integer revision, String qualifier, String separator) implements Comparable<VersionNumber> { public record VersionNumber(Integer major, Integer minor, Integer revision, String qualifier, String separator) implements Version {
public static final String SNAPSHOT_QUALIFIER = "SNAPSHOT"; public static final String SNAPSHOT_QUALIFIER = "SNAPSHOT";
/** /**
@ -32,12 +32,13 @@ public record VersionNumber(Integer major, Integer minor, Integer revision, Stri
*/ */
public static final VersionNumber UNKNOWN = new VersionNumber(0, 0, 0, ""); public static final VersionNumber UNKNOWN = new VersionNumber(0, 0, 0, "");
private static final Pattern VERSION_PATTERN = Pattern.compile("^(?<major>\\d+)(?:\\.(?<minor>\\d+)(?:\\.(?<revision>\\d+))?)?(?:(?<separator>[.\\-])(?<qualifier>.*[^.\\-]))??$"); private static final Pattern VERSION_PATTERN = Pattern.compile("^(?<major>0|[1-9]\\d*)(?:\\.(?<minor>0|[1-9]\\d*)(?:\\.(?<revision>0|[1-9]\\d*))?)?(?:(?<separator>[.\\-])(?<qualifier>.*[^.\\-]))??$");
/** /**
* Parses a version number from a string representation. * Parses a version number from a string representation.
* <p> * <p>
* If the string can't be successfully parsed, {@link VersionNumber#UNKNOWN} will be returned. * If the string can't be successfully parsed as a semantic version,
* {@link VersionNumber#UNKNOWN} will be returned.
* *
* @param version the version string to parse * @param version the version string to parse
* @return a parsed instance of {@code VersionNumber}; or * @return a parsed instance of {@code VersionNumber}; or
@ -49,9 +50,22 @@ public record VersionNumber(Integer major, Integer minor, Integer revision, Stri
return UNKNOWN; return UNKNOWN;
} }
var result = parseOrNull(version);
if (result == null) {
result = UNKNOWN;
}
return result;
}
static VersionNumber parseOrNull(String version) {
if (version == null) {
return null;
}
var matcher = VERSION_PATTERN.matcher(version); var matcher = VERSION_PATTERN.matcher(version);
if (!matcher.matches()) { if (!matcher.matches()) {
return UNKNOWN; return null;
} }
var major = matcher.group("major"); var major = matcher.group("major");
@ -142,13 +156,8 @@ public record VersionNumber(Integer major, Integer minor, Integer revision, Stri
return new VersionNumber(major, minor, revision, null); return new VersionNumber(major, minor, revision, null);
} }
/** @Override
* Retrieves the version number with a different qualifier. public Version withQualifier(String qualifier) {
*
* @return this version number with a different qualifier
* @since 1.5.8
*/
public VersionNumber withQualifier(String qualifier) {
return new VersionNumber(major, minor, revision, qualifier); return new VersionNumber(major, minor, revision, qualifier);
} }
@ -182,48 +191,46 @@ public record VersionNumber(Integer major, Integer minor, Integer revision, Stri
return revision == null ? 0 : revision; return revision == null ? 0 : revision;
} }
/**
* Indicates whether this is a snapshot version.
*
* @return {@code true} if this is a snapshot version; or
* {@code false} otherwise
* @since 1.5.8
*/
public boolean isSnapshot() { public boolean isSnapshot() {
return qualifier().toUpperCase().contains(SNAPSHOT_QUALIFIER); return qualifier().toUpperCase().contains(SNAPSHOT_QUALIFIER);
} }
public int compareTo(VersionNumber other) { @Override
if (majorInt() != other.majorInt()) { public int compareTo(Version other) {
return majorInt() - other.majorInt(); if (other instanceof VersionNumber otherNumber) {
if (majorInt() != otherNumber.majorInt()) {
return majorInt() - otherNumber.majorInt();
} }
if (minorInt() != other.minorInt()) { if (minorInt() != otherNumber.minorInt()) {
return minorInt() - other.minorInt(); return minorInt() - otherNumber.minorInt();
} }
if (revisionInt() != other.revisionInt()) { if (revisionInt() != otherNumber.revisionInt()) {
return revisionInt() - other.revisionInt(); return revisionInt() - otherNumber.revisionInt();
} }
if (qualifier.equals(other.qualifier)) { if (qualifier.equals(otherNumber.qualifier)) {
return 0; return 0;
} else if (qualifier.isEmpty()) { } else if (qualifier.isEmpty()) {
return 1; return 1;
} else if (other.qualifier.isEmpty()) { } else if (otherNumber.qualifier.isEmpty()) {
return -1; return -1;
} }
return qualifier.toLowerCase().compareTo(other.qualifier.toLowerCase()); return qualifier.toLowerCase().compareTo(otherNumber.qualifier.toLowerCase());
}
return toString().compareTo(other.toString());
} }
public String toString() { public String toString() {
var version = new StringBuilder(); var version = new StringBuilder();
version.append(majorInt()); version.append(majorInt());
if (minor != null || revision != null) { if (minor != null || revision != null) {
version.append("."); version.append('.');
version.append(minorInt()); version.append(minorInt());
} }
if (revision != null) { if (revision != null) {
version.append("."); version.append('.');
version.append(revisionInt()); version.append(revisionInt());
} }
if (qualifier != null && !qualifier.isEmpty()) { if (qualifier != null && !qualifier.isEmpty()) {
@ -235,7 +242,7 @@ public record VersionNumber(Integer major, Integer minor, Integer revision, Stri
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return other instanceof VersionNumber && compareTo((VersionNumber) other) == 0; return other instanceof Version && compareTo((Version) other) == 0;
} }
@Override @Override

View file

@ -0,0 +1,125 @@
/*
* Copyright 2001-2024 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.dependencies;
import rife.ioc.HierarchicalProperties;
import java.util.HashMap;
import java.util.Map;
/**
* This class is responsible for managing version overrides for dependencies.
* <p>
* It allows users to specify a property keys with the prefix "{@code bld.override}" where the values will be parsed as
* a comma-separated list of dependencies with the versions that should override any other versions that are encountered.
* <p>
* For instance:
* <pre>
* bld.override=com.uwyn.rife2:bld-tests-badge:1.4.7,com.h2database:h2:2.2.222
* </pre>
* <p>
* Multiple override properties can be used by simply adding differentiators behind the "{@code bld.override}" keys.
* <p>
* For instance:
* <pre>
* bld.override-tests=com.uwyn.rife2:bld-tests-badge:1.4.7
* bld.override-h2=com.h2database:h2:2.2.222
* </pre>
* @since 2.0
*/
public class VersionResolution {
/**
* The prefix for property keys used to override versions of dependencies.
* @since 2.0
*/
public static final String PROPERTY_OVERRIDE_PREFIX = "bld.override";
private final Map<String, Version> versionOverrides_ = new HashMap<>();
/**
* Returns a dummy {@code VersionResolution} instance that doesn't override anything.
*
* @return the dummy instance
* @since 2.0
*/
static VersionResolution dummy() {
return new VersionResolution(null);
}
/**
* Creates a new instance of the {@code VersionResolution} class from hierarchical properties that
* are passed in.
* <p>
* The actual version overrides are determined at instantiation time and any future changes to the
* properties will not influence version resolution.
*
* @param properties the hierarchical properties that will be used to determine the version overrides
* @since 2.0
*/
public VersionResolution(HierarchicalProperties properties) {
if (properties != null) {
for (var name : properties.getNames()) {
if (name.startsWith(PROPERTY_OVERRIDE_PREFIX)) {
for (var override : properties.get(name).toString().split(",")) {
override = override.trim();
if (!override.isBlank()) {
var dependency = Dependency.parse(override);
if (dependency != null) {
versionOverrides_.put(dependency.toArtifactString(), dependency.version());
}
}
}
}
}
}
}
/**
* Overrides the version of a given dependency with the corresponding overridden version.
*
* @param original the dependency for which the version needs to be overridden
* @return the overridden version if it is available; or the original version otherwise
* @since 2.0
*/
public Version overrideVersion(Dependency original) {
var overridden = versionOverrides_.get(original.toArtifactString());
if (overridden == null) {
return original.version();
}
return overridden;
}
/**
* Overrides the version of a given dependency with the corresponding overridden version and
* creates a new dependency object with the overridden version, if needed.
*
* @param original the dependency for which the version needs to be overridden
* @return the dependency with the overridden version if it's available; or the original dependency otherwise
* @since 2.0
*/
public Dependency overrideDependency(Dependency original) {
var overridden = versionOverrides_.get(original.toArtifactString());
if (overridden == null) {
return original;
}
return new Dependency(original.groupId(),
original.artifactId(),
overridden,
original.classifier(),
original.type(),
original.exclusions(),
original.parent());
}
/**
* Returns the map of version overrides, where the key is the name of the dependency and the value is the overridden version.
*
* @return the map of version overrides
* @since 2.0
*/
public Map<String, Version> versionOverrides() {
return versionOverrides_;
}
}

View file

@ -18,13 +18,14 @@ import java.util.regex.Pattern;
* @since 1.5.8 * @since 1.5.8
*/ */
public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata { public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata {
private VersionNumber latest_ = VersionNumber.UNKNOWN; private Version latest_ = VersionNumber.UNKNOWN;
private VersionNumber release_ = VersionNumber.UNKNOWN; private Version release_ = VersionNumber.UNKNOWN;
private final List<VersionNumber> versions_; private final List<Version> versions_;
private VersionNumber snapshot_ = VersionNumber.UNKNOWN; private Version snapshot_ = VersionNumber.UNKNOWN;
private StringBuilder characterData_ = null; private StringBuilder characterData_ = null;
private boolean isSnapshot_ = false;
private String snapshotTimestamp_ = null; private String snapshotTimestamp_ = null;
private Integer snapshotBuildNumber_ = null; private Integer snapshotBuildNumber_ = null;
@ -32,15 +33,15 @@ public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata {
versions_ = new ArrayList<>(); versions_ = new ArrayList<>();
} }
public VersionNumber getLatest() { public Version getLatest() {
return latest_; return latest_;
} }
public VersionNumber getRelease() { public Version getRelease() {
return release_; return release_;
} }
public VersionNumber getSnapshot() { public Version getSnapshot() {
return snapshot_; return snapshot_;
} }
@ -52,7 +53,7 @@ public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata {
return snapshotBuildNumber_; return snapshotBuildNumber_;
} }
public List<VersionNumber> getVersions() { public List<Version> getVersions() {
return versions_; return versions_;
} }
@ -62,21 +63,12 @@ public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata {
public void endElement(String uri, String localName, String qName) { public void endElement(String uri, String localName, String qName) {
switch (qName) { switch (qName) {
case "latest" -> latest_ = VersionNumber.parse(characterData_.toString()); case "latest" -> latest_ = Version.parse(characterData_.toString());
case "release" -> release_ = VersionNumber.parse(characterData_.toString()); case "release" -> release_ = Version.parse(characterData_.toString());
case "version" -> versions_.add(VersionNumber.parse(characterData_.toString())); case "version" -> versions_.add(Version.parse(characterData_.toString()));
case "timestamp" -> snapshotTimestamp_ = characterData_.toString(); case "timestamp" -> snapshotTimestamp_ = characterData_.toString();
case "buildNumber" -> snapshotBuildNumber_ = Integer.parseInt(characterData_.toString()); case "buildNumber" -> snapshotBuildNumber_ = Integer.parseInt(characterData_.toString());
case "snapshot" -> { case "snapshot" -> isSnapshot_ = true;
if (!versions_.isEmpty()) {
var version = versions_.get(0);
var qualifier = VersionNumber.SNAPSHOT_QUALIFIER;
if (snapshotTimestamp_ != null && snapshotBuildNumber_ != null) {
qualifier = snapshotTimestamp_ + "-" + snapshotBuildNumber_;
}
snapshot_ = new VersionNumber(version.major(), version.minor(), version.revision(), qualifier);
}
}
} }
characterData_ = null; characterData_ = null;
@ -88,9 +80,19 @@ public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata {
public void endDocument() public void endDocument()
throws SAXException { throws SAXException {
if (isSnapshot_) {
if (!versions_.isEmpty()) {
var version = versions_.get(0);
var qualifier = VersionNumber.SNAPSHOT_QUALIFIER;
if (snapshotTimestamp_ != null && snapshotBuildNumber_ != null) {
qualifier = snapshotTimestamp_ + "-" + snapshotBuildNumber_;
}
snapshot_ = version.withQualifier(qualifier);
}
}
// determine latest stable version by removing pre-release qualifiers // determine latest stable version by removing pre-release qualifiers
var filtered_versions = new TreeSet<VersionNumber>(); var filtered_versions = new TreeSet<>(versions_.stream()
filtered_versions.addAll(versions_.stream()
.filter(v -> { .filter(v -> {
if (v.qualifier() == null) return true; if (v.qualifier() == null) return true;
var q = v.qualifier().toLowerCase(); var q = v.qualifier().toLowerCase();

View file

@ -10,6 +10,8 @@ import rife.xml.Xml2Data;
import java.util.*; import java.util.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static rife.bld.dependencies.Dependency.TYPE_JAR;
/** /**
* Parses an XML document to retrieve POM information, this is an internal class. * Parses an XML document to retrieve POM information, this is an internal class.
* *
@ -18,16 +20,18 @@ import java.util.regex.Pattern;
*/ */
class Xml2MavenPom extends Xml2Data { class Xml2MavenPom extends Xml2Data {
private final Dependency parent_; private final Dependency parent_;
private final VersionResolution resolution_;
private final ArtifactRetriever retriever_; private final ArtifactRetriever retriever_;
private final List<Repository> repositories_; private final List<Repository> repositories_;
private Map<Scope, Set<PomDependency>> resolvedDependencies_ = null; private Map<Scope, Set<PomDependency>> resolvedDependencies_ = null;
private final Map<PomDependency, PomDependency> dependencyManagement_ = new LinkedHashMap<>(); private final Map<PomDependency, PomDependency> dependencyManagement_ = new LinkedHashMap<>();
private final Set<PomDependency> dependencies_ = new LinkedHashSet<>(); private final Set<PomDependency> dependencies_ = new LinkedHashSet<>();
private final Map<String, String> properties_ = new HashMap<>(); private final Map<String, String> mavenProperties_ = new HashMap<>();
private final Stack<String> elementStack_ = new Stack<>(); private final Stack<String> elementStack_ = new Stack<>();
private ExclusionSet exclusions_ = null; private ExclusionSet exclusions_ = null;
private boolean initialParse_ = true;
private boolean collectProperties_ = false; private boolean collectProperties_ = false;
private boolean collectDependencyManagement_ = false; private boolean collectDependencyManagement_ = false;
private boolean collectDependencies_ = false; private boolean collectDependencies_ = false;
@ -45,8 +49,9 @@ class Xml2MavenPom extends Xml2Data {
private String lastExclusionGroupId_ = null; private String lastExclusionGroupId_ = null;
private String lastExclusionArtifactId_ = null; private String lastExclusionArtifactId_ = null;
Xml2MavenPom(Dependency parent, ArtifactRetriever retriever, List<Repository> repositories) { Xml2MavenPom(Dependency parent, VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories) {
parent_ = parent; parent_ = parent;
resolution_ = resolution;
retriever_ = retriever; retriever_ = retriever;
repositories_ = repositories; repositories_ = repositories;
} }
@ -85,22 +90,22 @@ class Xml2MavenPom extends Xml2Data {
if (dep_scope == null) { if (dep_scope == null) {
dep_scope = "compile"; dep_scope = "compile";
} }
optional = resolveProperties(optional); optional = resolveMavenProperties(optional);
if ("true".equals(optional)) { if ("true".equals(optional)) {
continue; continue;
} }
var resolved_dependency = new PomDependency( var resolved_dependency = new PomDependency(
resolveProperties(dependency.groupId()), resolveMavenProperties(dependency.groupId()),
resolveProperties(dependency.artifactId()), resolveMavenProperties(dependency.artifactId()),
resolveProperties(version), resolveMavenProperties(version),
resolveProperties(dependency.classifier()), resolveMavenProperties(dependency.classifier()),
resolveProperties(dependency.type()), resolveMavenProperties(dependency.type()),
dep_scope, dep_scope,
"false", "false",
exclusions, exclusions,
dependency.parent()); dependency.parent());
if (resolved_dependency.type() == null || resolved_dependency.type().equals("jar")) { if (resolved_dependency.type() == null || TYPE_JAR.equals(resolved_dependency.type())) {
var scope = Scope.valueOf(resolved_dependency.scope()); var scope = Scope.valueOf(resolved_dependency.scope());
if (scopes_list.contains(scope)) { if (scopes_list.contains(scope)) {
var resolved_dependency_set = resolved_dependencies.computeIfAbsent(scope, k -> new LinkedHashSet<>()); var resolved_dependency_set = resolved_dependencies.computeIfAbsent(scope, k -> new LinkedHashSet<>());
@ -126,13 +131,13 @@ class Xml2MavenPom extends Xml2Data {
PomDependency resolveDependency(PomDependency dependency) { PomDependency resolveDependency(PomDependency dependency) {
return new PomDependency( return new PomDependency(
resolveProperties(dependency.groupId()), resolveMavenProperties(dependency.groupId()),
resolveProperties(dependency.artifactId()), resolveMavenProperties(dependency.artifactId()),
resolveProperties(dependency.version()), resolveMavenProperties(dependency.version()),
resolveProperties(dependency.classifier()), resolveMavenProperties(dependency.classifier()),
resolveProperties(dependency.type()), resolveMavenProperties(dependency.type()),
dependency.scope(), dependency.scope(),
resolveProperties(dependency.optional()), resolveMavenProperties(dependency.optional()),
dependency.exclusions(), dependency.exclusions(),
dependency.parent()); dependency.parent());
} }
@ -140,13 +145,16 @@ class Xml2MavenPom extends Xml2Data {
public void startElement(String uri, String localName, String qName, Attributes attributes) { public void startElement(String uri, String localName, String qName, Attributes attributes) {
characterData_ = new StringBuilder(); characterData_ = new StringBuilder();
switch (qName) { if (initialParse_) {
case "parent" -> resetState(); if (qName.equals("properties")) {
case "properties" -> {
if (isChildOfProject()) { if (isChildOfProject()) {
collectProperties_ = true; collectProperties_ = true;
} }
} }
}
else {
switch (qName) {
case "parent" -> resetState();
case "dependencyManagement" -> { case "dependencyManagement" -> {
if (isChildOfProject()) { if (isChildOfProject()) {
collectDependencyManagement_ = true; collectDependencyManagement_ = true;
@ -168,6 +176,7 @@ class Xml2MavenPom extends Xml2Data {
if (collectDependencies_) resetState(); if (collectDependencies_) resetState();
} }
} }
}
elementStack_.push(qName); elementStack_.push(qName);
} }
@ -175,14 +184,26 @@ class Xml2MavenPom extends Xml2Data {
public void endElement(String uri, String localName, String qName) { public void endElement(String uri, String localName, String qName) {
elementStack_.pop(); elementStack_.pop();
if (initialParse_) {
switch (qName) {
case "properties" -> collectProperties_ = false;
case "project" -> initialParse_ = false;
default -> {
if (collectProperties_) {
mavenProperties_.put(qName, getCharacterData());
}
}
}
}
else {
switch (qName) { switch (qName) {
case "parent" -> { case "parent" -> {
if (isChildOfProject()) { if (isChildOfProject()) {
var parent_dependency = new Dependency(resolveProperties(lastGroupId_), resolveProperties(lastArtifactId_), VersionNumber.parse(resolveProperties(lastVersion_))); var parent_dependency = new Dependency(resolveMavenProperties(lastGroupId_), resolveMavenProperties(lastArtifactId_), Version.parse(resolveMavenProperties(lastVersion_)));
var parent = new DependencyResolver(retriever_, repositories_, parent_dependency).getMavenPom(parent_); var parent = new DependencyResolver(resolution_, retriever_, repositories_, parent_dependency).getMavenPom(parent_);
parent.properties_.keySet().removeAll(properties_.keySet()); parent.mavenProperties_.keySet().removeAll(mavenProperties_.keySet());
properties_.putAll(parent.properties_); mavenProperties_.putAll(parent.mavenProperties_);
parent.dependencyManagement_.keySet().removeAll(dependencyManagement_.keySet()); parent.dependencyManagement_.keySet().removeAll(dependencyManagement_.keySet());
dependencyManagement_.putAll(parent.dependencyManagement_); dependencyManagement_.putAll(parent.dependencyManagement_);
@ -193,7 +214,6 @@ class Xml2MavenPom extends Xml2Data {
resetState(); resetState();
} }
} }
case "properties" -> collectProperties_ = false;
case "dependencyManagement" -> collectDependencyManagement_ = false; case "dependencyManagement" -> collectDependencyManagement_ = false;
case "dependencies" -> collectDependencies_ = false; case "dependencies" -> collectDependencies_ = false;
case "exclusions" -> collectExclusions_ = false; case "exclusions" -> collectExclusions_ = false;
@ -206,8 +226,8 @@ class Xml2MavenPom extends Xml2Data {
var dependency = new PomDependency(lastGroupId_, lastArtifactId_, lastVersion_, lastClassifier_, lastType_, lastScope_, lastOptional_, exclusions_, parent_); var dependency = new PomDependency(lastGroupId_, lastArtifactId_, lastVersion_, lastClassifier_, lastType_, lastScope_, lastOptional_, exclusions_, parent_);
if (collectDependencyManagement_) { if (collectDependencyManagement_) {
if (dependency.isPomImport()) { if (dependency.isPomImport()) {
var import_dependency = new Dependency(resolveProperties(lastGroupId_), resolveProperties(lastArtifactId_), VersionNumber.parse(resolveProperties(lastVersion_))); var import_dependency = new Dependency(resolveMavenProperties(lastGroupId_), resolveMavenProperties(lastArtifactId_), Version.parse(resolveMavenProperties(lastVersion_)));
var imported_pom = new DependencyResolver(retriever_, repositories_, import_dependency).getMavenPom(parent_); var imported_pom = new DependencyResolver(resolution_, retriever_, repositories_, import_dependency).getMavenPom(parent_);
imported_pom.dependencyManagement_.keySet().removeAll(dependencyManagement_.keySet()); imported_pom.dependencyManagement_.keySet().removeAll(dependencyManagement_.keySet());
var resolved_dependencies = new LinkedHashSet<PomDependency>(); var resolved_dependencies = new LinkedHashSet<PomDependency>();
for (var managed_dependency : imported_pom.dependencyManagement_.keySet()) { for (var managed_dependency : imported_pom.dependencyManagement_.keySet()) {
@ -230,6 +250,9 @@ class Xml2MavenPom extends Xml2Data {
if (isChildOfProject()) { if (isChildOfProject()) {
addProjectProperty(qName); addProjectProperty(qName);
} else if (isChildOfParent() || isChildOfDependency()) { } else if (isChildOfParent() || isChildOfDependency()) {
if (isChildOfProjectParent()) {
addProjectParentProperty(qName);
}
lastGroupId_ = getCharacterData(); lastGroupId_ = getCharacterData();
} else if (collectExclusions_ && isChildOfExclusion()) { } else if (collectExclusions_ && isChildOfExclusion()) {
lastExclusionGroupId_ = getCharacterData(); lastExclusionGroupId_ = getCharacterData();
@ -239,6 +262,9 @@ class Xml2MavenPom extends Xml2Data {
if (isChildOfProject()) { if (isChildOfProject()) {
addProjectProperty(qName); addProjectProperty(qName);
} else if (isChildOfParent() || isChildOfDependency()) { } else if (isChildOfParent() || isChildOfDependency()) {
if (isChildOfProjectParent()) {
addProjectParentProperty(qName);
}
lastArtifactId_ = getCharacterData(); lastArtifactId_ = getCharacterData();
} else if (collectExclusions_ && isChildOfExclusion()) { } else if (collectExclusions_ && isChildOfExclusion()) {
lastExclusionArtifactId_ = getCharacterData(); lastExclusionArtifactId_ = getCharacterData();
@ -249,6 +275,9 @@ class Xml2MavenPom extends Xml2Data {
addProjectProperty(qName); addProjectProperty(qName);
} else if (isChildOfParent() || isChildOfDependency()) { } else if (isChildOfParent() || isChildOfDependency()) {
lastVersion_ = getCharacterData(); lastVersion_ = getCharacterData();
if (isChildOfProjectParent()) {
addProjectParentProperty(qName);
}
} }
} }
case "type" -> { case "type" -> {
@ -276,10 +305,6 @@ class Xml2MavenPom extends Xml2Data {
addProjectProperty(qName); addProjectProperty(qName);
} }
} }
default -> {
if (collectProperties_) {
properties_.put(qName, getCharacterData());
}
} }
} }
@ -287,23 +312,34 @@ class Xml2MavenPom extends Xml2Data {
} }
private boolean isChildOfProject() { private boolean isChildOfProject() {
return elementStack_.peek().equals("project"); return "project".equals(elementStack_.peek());
}
private boolean isChildOfProjectParent() {
if (elementStack_.size() < 2) {
return false;
}
return "parent".equals(elementStack_.peek()) && "project".equals(elementStack_.elementAt(elementStack_.size() - 2));
} }
private boolean isChildOfParent() { private boolean isChildOfParent() {
return elementStack_.peek().equals("parent"); return "parent".equals(elementStack_.peek());
} }
private boolean isChildOfDependency() { private boolean isChildOfDependency() {
return elementStack_.peek().equals("dependency"); return "dependency".equals(elementStack_.peek());
} }
private boolean isChildOfExclusion() { private boolean isChildOfExclusion() {
return elementStack_.peek().equals("exclusion"); return "exclusion".equals(elementStack_.peek());
} }
private void addProjectProperty(String name) { private void addProjectProperty(String name) {
properties_.put("project." + name, getCharacterData()); mavenProperties_.put("project." + name, getCharacterData());
}
private void addProjectParentProperty(String name) {
mavenProperties_.put("project.parent." + name, getCharacterData());
} }
private String getCharacterData() { private String getCharacterData() {
@ -320,7 +356,7 @@ class Xml2MavenPom extends Xml2Data {
private static final Pattern MAVEN_PROPERTY = Pattern.compile("\\$\\{([^<>{}]+)}"); private static final Pattern MAVEN_PROPERTY = Pattern.compile("\\$\\{([^<>{}]+)}");
private String resolveProperties(String data) { private String resolveMavenProperties(String data) {
if (data == null) { if (data == null) {
return null; return null;
} }
@ -335,9 +371,9 @@ class Xml2MavenPom extends Xml2Data {
while (matcher.find()) { while (matcher.find()) {
if (matcher.groupCount() == 1) { if (matcher.groupCount() == 1) {
var property = matcher.group(1); var property = matcher.group(1);
if (properties_.containsKey(property)) { if (mavenProperties_.containsKey(property)) {
processed_data.append(data, last_end, matcher.start()); processed_data.append(data, last_end, matcher.start());
processed_data.append(properties_.get(property)); processed_data.append(mavenProperties_.get(property));
last_end = matcher.end(); last_end = matcher.end();
replaced = true; replaced = true;

View file

@ -24,6 +24,22 @@ public class DependencyTransferException extends DependencyException {
destination_ = destination; destination_ = destination;
} }
public DependencyTransferException(Dependency dependency, File destination, String message) {
super("Unable to transfer dependency '" + dependency + "' into '" + destination + "': " + message);
dependency_ = dependency;
location_ = null;
destination_ = destination;
}
public DependencyTransferException(Dependency dependency, String message) {
super("Unable to transfer dependency '" + dependency + "': " + message);
dependency_ = dependency;
location_ = null;
destination_ = null;
}
public Dependency getDependency() { public Dependency getDependency() {
return dependency_; return dependency_;
} }

View file

@ -8,22 +8,23 @@ import rife.bld.CommandHelp;
import rife.tools.StringUtils; import rife.tools.StringUtils;
/** /**
* Provides help for the create-blank command. * Provides help for the create-app command.
* *
* @author Geert Bevin (gbevin[remove] at uwyn dot com) * @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5 * @since 1.9
*/ */
public class CreateBlankHelp implements CommandHelp { public class CreateAppHelp implements CommandHelp {
public String getSummary() { public String getSummary() {
return "Creates a new blank Java project with standard commands"; return "Creates a new Java application project";
} }
public String getDescription(String topic) { public String getDescription(String topic) {
return StringUtils.replace(""" return StringUtils.replace("""
Creates a new blank Java project with standard commands. Creates a new Java application project.
Usage : ${topic} <package> <name> Usage : ${topic} <package> <name> <base>
package The package of the project to create package The package of the project to create
name The name of the project to create""", "${topic}", topic); name The name of the project to create
base The base name for generated project classes""", "${topic}", topic);
} }
} }

View file

@ -8,22 +8,23 @@ import rife.bld.CommandHelp;
import rife.tools.StringUtils; import rife.tools.StringUtils;
/** /**
* Provides help for the create-blank command. * Provides help for the create-base command.
* *
* @author Geert Bevin (gbevin[remove] at uwyn dot com) * @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.20 * @since 1.5.20
*/ */
public class CreateBaseHelp implements CommandHelp { public class CreateBaseHelp implements CommandHelp {
public String getSummary() { public String getSummary() {
return "Creates a new baseline Java project with minimal commands"; return "Creates a new Java baseline project";
} }
public String getDescription(String topic) { public String getDescription(String topic) {
return StringUtils.replace(""" return StringUtils.replace("""
Creates a new baseline Java project with minimal commands. Creates a new Java baseline project.
Usage : ${topic} <package> <name> Usage : ${topic} <package> <name> <base>
package The package of the project to create package The package of the project to create
name The name of the project to create""", "${topic}", topic); name The name of the project to create
base The base name for generated project classes""", "${topic}", topic);
} }
} }

View file

@ -15,16 +15,17 @@ import rife.tools.StringUtils;
*/ */
public class CreateHelp implements CommandHelp { public class CreateHelp implements CommandHelp {
public String getSummary() { public String getSummary() {
return "Creates a new project"; return "Creates a new project from multiple choice";
} }
public String getDescription(String topic) { public String getDescription(String topic) {
return StringUtils.replace(""" return StringUtils.replace("""
Creates a new project. Creates a new project from multiple choice.
Usage : ${topic} <type> <package> <name> Usage : ${topic} <type> <package> <name> <base>
type The type of project to create (base, blank, lib, rife2) type The type of project to create (app, base, lib, rife2)
package The package of the project to create package The package of the project to create
name The name of the project to create""", "${topic}", topic); name The name of the project to create
base The base name for generated project classes""", "${topic}", topic);
} }
} }

View file

@ -15,15 +15,16 @@ import rife.tools.StringUtils;
*/ */
public class CreateLibHelp implements CommandHelp { public class CreateLibHelp implements CommandHelp {
public String getSummary() { public String getSummary() {
return "Creates a new Java library with minimal commands"; return "Creates a new Java library project";
} }
public String getDescription(String topic) { public String getDescription(String topic) {
return StringUtils.replace(""" return StringUtils.replace("""
Creates a new library Java project with minimal commands. Creates a new Java library project.
Usage : ${topic} <package> <name> Usage : ${topic} <package> <name> <base>
package The package of the project to create package The package of the project to create
name The name of the project to create""", "${topic}", topic); name The name of the project to create
base The base name for generated project classes""", "${topic}", topic);
} }
} }

View file

@ -15,15 +15,16 @@ import rife.tools.StringUtils;
*/ */
public class CreateRife2Help implements CommandHelp { public class CreateRife2Help implements CommandHelp {
public String getSummary() { public String getSummary() {
return "Creates a new RIFE2 project"; return "Creates a new RIFE2 web application project";
} }
public String getDescription(String topic) { public String getDescription(String topic) {
return StringUtils.replace(""" return StringUtils.replace("""
Creates a new RIFE2 project. Creates a new RIFE2 web application project.
Usage : ${topic} <package> <name> Usage : ${topic} <package> <name> <base>
package The package of the project to create package The package of the project to create
name The name of the project to create""", "${topic}", topic); name The name of the project to create
base The base name for generated project classes""", "${topic}", topic);
} }
} }

View file

@ -5,7 +5,7 @@
package rife.bld.help; package rife.bld.help;
import rife.bld.CommandHelp; import rife.bld.CommandHelp;
import rife.tools.StringUtils; import rife.bld.operations.RunOperation;
/** /**
* Provides help for the run command. * Provides help for the run command.
@ -15,13 +15,13 @@ import rife.tools.StringUtils;
*/ */
public class RunHelp implements CommandHelp { public class RunHelp implements CommandHelp {
public String getSummary() { public String getSummary() {
return "Runs the project"; return "Runs the project (take option)";
} }
public String getDescription(String topic) { public String getDescription(String topic) {
return StringUtils.replace(""" return String.format("""
Runs the project. Runs the project.
Usage : ${topic}""", "${topic}", topic); Usage : %s [%sARG...]""", topic, RunOperation.ARGS_OPTION);
} }
} }

View file

@ -0,0 +1,44 @@
/*
* Copyright 2001-2024 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.instrument;
import rife.asm.*;
/**
* This utility class will modify a Java module {@code module-info.class} to add
* a module main class to its attributes.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 2.1
*/
public class ModuleMainClassAdapter extends ClassVisitor implements Opcodes {
private final String mainClass_;
/**
* Performs the actual modification of the module info class's bytecode.
*
* @param origBytes the bytes of the module class that should be modified
* @param mainClass the main class of the module
* @return the modified bytes
* @since 2.1
*/
public static byte[] addModuleMainClassToBytes(byte[] origBytes, String mainClass) {
var cw = new ClassWriter(0);
new ClassReader(origBytes).accept(new ModuleMainClassAdapter(mainClass, cw), 0);
return cw.toByteArray();
}
private ModuleMainClassAdapter(String mainClass, ClassVisitor writer) {
super(ASM9, writer);
mainClass_ = mainClass.replace('.', '/');
}
@Override
public ModuleVisitor visitModule(String name, int access, String version) {
var module_visitor = super.visitModule(name, access, version);
module_visitor.visitMainClass(mainClass_);
return module_visitor;
}
}

View file

@ -0,0 +1,10 @@
/*
* Copyright 2001-2024 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
/**
* Provides functionalities for bytecode instrumentation.
* @since 2.1
*/
package rife.bld.instrument;

View file

@ -6,6 +6,7 @@ package rife.bld.operations;
import rife.bld.BldVersion; import rife.bld.BldVersion;
import rife.bld.Project; import rife.bld.Project;
import rife.bld.dependencies.VersionNumber;
import rife.bld.operations.exceptions.OperationOptionException; import rife.bld.operations.exceptions.OperationOptionException;
import rife.bld.wrapper.Wrapper; import rife.bld.wrapper.Wrapper;
import rife.template.TemplateFactory; import rife.template.TemplateFactory;
@ -25,16 +26,17 @@ import java.util.List;
* @since 1.5 * @since 1.5
*/ */
public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<T, P>, P extends Project> extends AbstractOperation<AbstractCreateOperation<T, P>> { public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<T, P>, P extends Project> extends AbstractOperation<AbstractCreateOperation<T, P>> {
private String packageName_;
private String projectName_;
private String baseName_;
final String templateBase_; final String templateBase_;
File workDirectory_ = new File(System.getProperty("user.dir")); File workDirectory_ = new File(System.getProperty("user.dir"));
String packageName_;
String projectName_;
boolean downloadDependencies_; boolean downloadDependencies_;
P project_; P project_;
String projectClassName_;
String projectBuildName_; String projectBuildName_;
String projectMainName_; String projectMainName_;
String projectMainUberName_; String projectMainUberName_;
@ -96,11 +98,11 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
project_ = createProjectBlueprint(); project_ = createProjectBlueprint();
// standard names // standard names
projectClassName_ = StringUtils.capitalize(project_.name()); var base_name = baseName();
projectBuildName_ = projectBuildClassName(projectClassName_); projectBuildName_ = projectBuildClassName(base_name);
projectMainName_ = projectMainClassName(projectClassName_); projectMainName_ = projectMainClassName(base_name);
projectMainUberName_ = projectMainUberClassName(projectClassName_); projectMainUberName_ = projectMainUberClassName(base_name);
projectTestName_ = projectTestClassName(projectClassName_); projectTestName_ = projectTestClassName(base_name);
// create the main project structure // create the main project structure
ideaDirectory_ = new File(project_.workDirectory(), ".idea"); ideaDirectory_ = new File(project_.workDirectory(), ".idea");
@ -131,7 +133,7 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
* @since 1.6 * @since 1.6
*/ */
protected String projectMainClassName(String projectClassName) { protected String projectMainClassName(String projectClassName) {
return projectClassName + "Main"; return projectClassName;
} }
/** /**
@ -141,7 +143,7 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
* @since 1.6 * @since 1.6
*/ */
protected String projectMainUberClassName(String projectClassName) { protected String projectMainUberClassName(String projectClassName) {
return projectClassName + "Main"; return projectClassName;
} }
/** /**
@ -198,7 +200,7 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
test_template.setValue("projectTest", projectTestName_); test_template.setValue("projectTest", projectTestName_);
test_template.setValue("projectMain", projectMainName_); test_template.setValue("projectMain", projectMainName_);
if (test_template.hasValueId("project")) { if (test_template.hasValueId("project")) {
test_template.setValue("project", projectClassName_); test_template.setValue("project", project_.name());
} }
var project_test_file = new File(testPackageDirectory_, projectTestName_ + ".java"); var project_test_file = new File(testPackageDirectory_, projectTestName_ + ".java");
FileUtils.writeString(test_template.getContent(), project_test_file); FileUtils.writeString(test_template.getContent(), project_test_file);
@ -206,8 +208,12 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
// project build // project build
var build_template = TemplateFactory.TXT.get(templateBase_ + "project_build"); var build_template = TemplateFactory.TXT.get(templateBase_ + "project_build");
build_template.setValue("projectBuild", projectBuildName_); build_template.setValue("projectBuild", projectBuildName_);
if (build_template.hasValueId("package")) {
build_template.setValue("package", project_.pkg()); build_template.setValue("package", project_.pkg());
build_template.setValue("project", projectClassName_); }
if (build_template.hasValueId("project")) {
build_template.setValue("project", project_.name());
}
if (build_template.hasValueId("projectMain")) { if (build_template.hasValueId("projectMain")) {
build_template.setValue("projectMain", projectMainName_); build_template.setValue("projectMain", projectMainName_);
} }
@ -224,10 +230,16 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
build_template.setValue("groupId", dependency.groupId()); build_template.setValue("groupId", dependency.groupId());
build_template.setValue("artifactId", dependency.artifactId()); build_template.setValue("artifactId", dependency.artifactId());
var version = dependency.version(); var version = dependency.version();
var version_string = version.major() + "," + version.minor() + "," + version.revision(); var version_string = "";
if (version instanceof VersionNumber versionNumber) {
version_string = versionNumber.major() + "," + versionNumber.minor() + "," + versionNumber.revision();
if (!version.qualifier().isEmpty()) { if (!version.qualifier().isEmpty()) {
version_string += ",\"" + version.qualifier() + "\""; version_string += ",\"" + version.qualifier() + "\"";
} }
}
else {
version_string = "\"" + version.toString() + "\"";
}
build_template.setValue("version", version_string); build_template.setValue("version", version_string);
build_template.appendBlock("dependencies", "dependency"); build_template.appendBlock("dependencies", "dependency");
} }
@ -364,32 +376,62 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
public T fromArguments(List<String> arguments) { public T fromArguments(List<String> arguments) {
String package_name = null; String package_name = null;
String project_name = null; String project_name = null;
if (arguments.size() > 0) { String base_name = null;
if (!arguments.isEmpty()) {
package_name = arguments.remove(0); package_name = arguments.remove(0);
} }
if (arguments.size() > 0) { if (!arguments.isEmpty()) {
project_name = arguments.remove(0); project_name = arguments.remove(0);
} }
if ((package_name == null || project_name == null) && System.console() == null) { if (!arguments.isEmpty()) {
throw new OperationOptionException("ERROR: Expecting the package and project names as the arguments."); base_name = arguments.remove(0);
}
if ((package_name == null || project_name == null || base_name == null) && System.console() == null) {
throw new OperationOptionException("ERROR: Expecting the package, project and base names as the arguments.");
} }
if (package_name == null || package_name.isEmpty()) { if (package_name == null || package_name.isBlank()) {
System.out.println("Please enter a package name (for instance: com.example):"); System.out.println("Please enter a package name (for instance: com.example):");
package_name = System.console().readLine(); package_name = System.console().readLine();
if (package_name == null || package_name.isBlank()) {
throw new OperationOptionException("ERROR: package name is required.");
}
} else { } else {
System.out.println("Using package name: " + package_name); System.out.println("Using package name: " + package_name);
} }
if (project_name == null || project_name.isEmpty()) { if (!ValidityChecks.checkJavaPackage(package_name)) {
System.out.println("Please enter a project name (for instance: myapp):"); throw new OperationOptionException("ERROR: package name is invalid.");
}
if (project_name == null || project_name.isBlank()) {
System.out.println("Please enter a project name (for instance: my-app):");
project_name = System.console().readLine(); project_name = System.console().readLine();
if (project_name == null || project_name.isBlank()) {
throw new OperationOptionException("ERROR: project name is required.");
}
} else { } else {
System.out.println("Using project name: " + project_name); System.out.println("Using project name: " + project_name);
} }
if (base_name == null || base_name.isBlank()) {
var default_base_name = generateBaseName(project_name);
System.out.println("Please enter the base name for generated project classes (default: " + default_base_name + "):");
base_name = System.console().readLine();
if (base_name == null || base_name.isBlank()) {
base_name = default_base_name;
System.out.println("Using base name: " + base_name);
}
} else {
System.out.println("Using base name: " + base_name);
}
if (!ValidityChecks.checkJavaIdentifier(base_name)) {
throw new OperationOptionException("ERROR: base name is invalid.");
}
return workDirectory(new File(System.getProperty("user.dir"))) return workDirectory(new File(System.getProperty("user.dir")))
.packageName(package_name) .packageName(package_name)
.projectName(project_name) .projectName(project_name)
.baseName(base_name)
.downloadDependencies(true); .downloadDependencies(true);
} }
@ -434,7 +476,6 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
throw new OperationOptionException("ERROR: The package name is invalid."); throw new OperationOptionException("ERROR: The package name is invalid.");
} }
packageName_ = name;
return (T) this; return (T) this;
} }
@ -451,10 +492,26 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
throw new OperationOptionException("ERROR: The project name should not be blank."); throw new OperationOptionException("ERROR: The project name should not be blank.");
} }
if (!ValidityChecks.checkJavaIdentifier(projectName_)) { return (T) this;
throw new OperationOptionException("ERROR: The project name is invalid.");
} }
projectName_ = name;
/**
* Provides the base name for the project classes to generate.
*
* @param name the base name
* @return this operation instance
* @since 2.2
*/
public T baseName(String name) {
baseName_ = StringUtils.trim(name);
if (baseName_.isEmpty()) {
throw new OperationOptionException("ERROR: The base name should not be blank.");
}
if (!ValidityChecks.checkJavaIdentifier(baseName_)) {
throw new OperationOptionException("ERROR: The base name is invalid.");
}
return (T) this; return (T) this;
} }
@ -502,6 +559,30 @@ public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<
return projectName_; return projectName_;
} }
static String generateBaseName(String projectName) {
if (projectName != null) {
return StringUtils.filterAsIdentifier(projectName.trim(), true);
}
return null;
}
/**
* Retrieves the base name for the project classes to generate.
* <p>
* If no base name was provided, one will be generated from the project name.
*
* @return the base name
* @since 2.2
*/
public String baseName() {
if (baseName_ == null || baseName_.isEmpty()) {
return generateBaseName(projectName());
}
return baseName_;
}
/** /**
* Retrieves whether dependencies will be downloaded at project creation. * Retrieves whether dependencies will be downloaded at project creation.
* *

View file

@ -10,8 +10,7 @@ import rife.bld.operations.exceptions.OperationOptionException;
import rife.tools.exceptions.FileUtilsErrorException; import rife.tools.exceptions.FileUtilsErrorException;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.function.Function; import java.util.function.Function;
/** /**
@ -24,10 +23,13 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
public static final String DEFAULT_JAVA_TOOL = "java"; public static final String DEFAULT_JAVA_TOOL = "java";
protected File workDirectory_ = new File(System.getProperty("user.dir")); protected File workDirectory_ = new File(System.getProperty("user.dir"));
protected final Map<String, String> environment_ = new HashMap<>();
protected String javaTool_ = DEFAULT_JAVA_TOOL; protected String javaTool_ = DEFAULT_JAVA_TOOL;
protected final JavaOptions javaOptions_ = new JavaOptions(); protected final JavaOptions javaOptions_ = new JavaOptions();
protected final List<String> classpath_ = new ArrayList<>(); protected final List<String> classpath_ = new ArrayList<>();
protected final List<String> modulePath_ = new ArrayList<>();
protected String mainClass_; protected String mainClass_;
protected String module_;
protected Function<String, Boolean> outputProcessor_; protected Function<String, Boolean> outputProcessor_;
protected Function<String, Boolean> errorProcessor_; protected Function<String, Boolean> errorProcessor_;
protected Process process_; protected Process process_;
@ -85,6 +87,12 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
var builder = new ProcessBuilder(executeConstructProcessCommandList()); var builder = new ProcessBuilder(executeConstructProcessCommandList());
builder.directory(workDirectory()); builder.directory(workDirectory());
if (!environment_.isEmpty()) {
builder.environment().putAll(environment_);
}
builder.redirectInput(ProcessBuilder.Redirect.INHERIT);
final var output_processor = outputProcessor(); final var output_processor = outputProcessor();
if (output_processor == null) { if (output_processor == null) {
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT); builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
@ -159,6 +167,31 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
return (T) this; return (T) this;
} }
/**
* Provides an environment variable to use for the operation.
*
* @param name the name of the environment variable
* @param value the value of the environment variable
* @return this operation instance
* @since 2.2.1
*/
public T environment(String name, String value) {
environment_.put(name, value);
return (T) this;
}
/**
* Provides environment variable entries to use for the operation.
*
* @param environment environment entries for the operation
* @return this operation instance
* @since 2.2.1
*/
public T environment(Map<String, String> environment) {
environment_.putAll(environment);
return (T) this;
}
/** /**
* Provides the name of the tool to use for {@code java} execution. * Provides the name of the tool to use for {@code java} execution.
* <p> * <p>
@ -197,6 +230,18 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
return (T) this; return (T) this;
} }
/**
* Provides classpath entries to use for the operation.
*
* @param classpath classpath entries for the operation
* @return this operation instance
* @since 2.3.1
*
*/
public T classpath(File... classpath) {
return classpath(List.of(classpath));
}
/** /**
* Provides a list of classpath entries to use for the operation. * Provides a list of classpath entries to use for the operation.
* <p> * <p>
@ -211,6 +256,71 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
return (T) this; return (T) this;
} }
/**
* Provides a list of classpath entries to use for the operation.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param classpath a list of classpath entries for the operation
* @return this operation instance
* @since 2.3.1
*/
public T classpath(Collection<File> classpath) {
classpath_.addAll(classpath.stream().map(File::getAbsolutePath).toList());
return (T) this;
}
/**
* Provides module path entries to use for the operation.
*
* @param modulePath module path entries for the operation
* @return this operation instance
* @since 2.1
*/
public T modulePath(String... modulePath) {
modulePath_.addAll(List.of(modulePath));
return (T) this;
}
/**
* Provides module path entries to use for the operation.
*
* @param modulePath module path entries for the operation
* @return this operation instance
* @since 2.3.1
*/
public T modulePath(File... modulePath) {
return modulePath(List.of(modulePath));
}
/**
* Provides a list of module path entries to use for the operation.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param modulePath a list of module path entries for the operation
* @return this operation instance
* @since 2.1
*/
public T modulePath(List<String> modulePath) {
modulePath_.addAll(modulePath);
return (T) this;
}
/**
* Provides a list of module path entries to use for the operation.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param modulePath a list of module path entries for the operation
* @return this operation instance
* @since 2.3.1
*/
public T modulePath(Collection<File> modulePath) {
modulePath_.addAll(modulePath.stream().map(File::getAbsolutePath).toList());
return (T) this;
}
/** /**
* Provides the main class to launch with the java tool. * Provides the main class to launch with the java tool.
* *
@ -223,6 +333,18 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
return (T) this; return (T) this;
} }
/**
* Provides the module to launch with the java tool.
*
* @param name the module to launch
* @return this operation instance
* @since 2.1
*/
public T module(String name) {
module_ = name;
return (T) this;
}
/** /**
* Provides the processor that will be used to handle the process output. * Provides the processor that will be used to handle the process output.
* <p> * <p>
@ -261,6 +383,18 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
return workDirectory_; return workDirectory_;
} }
/**
* Retrieves the environment to use for the operation.
* <p>
* This is a modifiable map that can be retrieved and changed.
*
* @return the operation's environment
* @since 2.2.1
*/
public Map<String, String> environment() {
return environment_;
}
/** /**
* retrieves the name of the tool to use for {@code java} execution. * retrieves the name of the tool to use for {@code java} execution.
* *
@ -295,6 +429,18 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
return classpath_; return classpath_;
} }
/**
* Retrieves the module path to use for the operation.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the operation's module path
* @since 2.1
*/
public List<String> modulePath() {
return modulePath_;
}
/** /**
* Retrieves the main class to launch with the java tool. * Retrieves the main class to launch with the java tool.
* *
@ -305,6 +451,16 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
return mainClass_; return mainClass_;
} }
/**
* Retrieves the module to launch with the java tool.
*
* @return the module to launch
* @since 2.1
*/
public String module() {
return module_;
}
/** /**
* Retrieves the processor that is used to handle the process output. * Retrieves the processor that is used to handle the process output.
* *

View file

@ -0,0 +1,283 @@
/*
* Copyright 2024 Erik C. Thauvin (https://erik.thauvin.net/)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import rife.bld.operations.exceptions.ExitStatusException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.spi.ToolProvider;
/**
* Provides common features for tool providers.
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 2.1.0
*/
public abstract class AbstractToolProviderOperation<T extends AbstractToolProviderOperation<T>>
extends AbstractOperation<AbstractToolProviderOperation<T>> {
private final List<String> cmdFiles_ = new ArrayList<>();
private final List<String> toolArgs_ = new ArrayList<>();
private final String toolName_;
/**
* Provides the name of the tool.
*
* @param toolName the tool name
*/
public AbstractToolProviderOperation(String toolName) {
toolName_ = toolName;
}
/**
* Read options and/or mode from file(s).
*
* @param files one or more files
* @return this operation instance
*/
public T cmdFiles(String... files) {
return cmdFilesStrings(List.of(files));
}
/**
* Read options and/or mode from file(s).
*
* @param files one or more files
* @return this operation instance
*/
@SuppressWarnings({"unchecked"})
public T cmdFiles(List<File> files) {
cmdFiles_.addAll(files.stream().map(File::getAbsolutePath).toList());
return (T) this;
}
/**
* Read options and/or mode from file(s).
*
* @param files one or more files
* @return this operation instance
*/
public T cmdFiles(File... files) {
return cmdFiles(List.of(files));
}
/**
* Read options and/or mode from file(s).
*
* @param files one or more files
* @return this operation instance
*/
public T cmdFiles(Path... files) {
return cmdFilesPaths(List.of(files));
}
/**
* Retrieves the list of files containing options or mode.
*
* @return the list of files
*/
public List<String> cmdFiles() {
return cmdFiles_;
}
/**
* Read options and/or mode from file(s).
*
* @param files one or more files
* @return this operation instance
*/
public T cmdFilesPaths(List<Path> files) {
return cmdFilesStrings(files.stream().map(Path::toFile).map(File::getAbsolutePath).toList());
}
/**
* Read options and/or mode from file(s).
*
* @param files one or more files
* @return this operation instance
*/
@SuppressWarnings({"unchecked"})
public T cmdFilesStrings(List<String> files) {
cmdFiles_.addAll(files);
return (T) this;
}
/**
* Runs an instance of the tool.
* <p>
* On success, command line arguments are automatically cleared.
*
* @throws Exception if an error occurred
*/
@Override
public void execute() throws Exception {
if (toolArgs_.isEmpty()) {
System.err.println("No " + toolName_ + " command line arguments specified.");
throw new ExitStatusException(ExitStatusException.EXIT_FAILURE);
}
var tool = ToolProvider.findFirst(toolName_).orElseThrow(() ->
new IllegalStateException("No " + toolName_ + " tool found."));
var status = tool.run(System.out, System.err, toolArgs_.toArray(new String[0]));
if (status != 0) {
System.out.println(tool.name() + ' ' + String.join(" ", toolArgs_));
}
ExitStatusException.throwOnFailure(status);
toolArgs_.clear();
}
/**
* Adds arguments to pass to the tool.
*
* @param args tbe list of arguments
* @return this operation
*/
@SuppressWarnings({"unchecked"})
public T toolArgs(List<String> args) {
toolArgs_.addAll(args);
return (T) this;
}
/**
* Adds arguments to pass to the tool.
*
* @param args one or more arguments
* @return this operation
*/
public T toolArgs(String... args) {
return toolArgs(List.of(args));
}
/**
* Returns the tool's arguments.
*
* @return the arguments
*/
public List<String> toolArgs() {
return toolArgs_;
}
/**
* Parses arguments to pass to the tool from the {@link #cmdFiles() command files}.
*
* @throws FileNotFoundException if a file cannot be found
*/
protected void toolArgsFromFiles() throws IOException {
for (var file : cmdFiles_) {
try (var reader = Files.newBufferedReader(Paths.get(file), Charset.defaultCharset())) {
var tokenizer = new CommandLineTokenizer(reader);
String token;
while ((token = tokenizer.nextToken()) != null) {
toolArgs_.add(token);
}
}
}
}
/**
* Adds arguments to pass to the tool.
*
* @param args the argument-value pairs to add
* @return this operation
*/
@SuppressWarnings({"unchecked", "UnusedReturnValue"})
protected T toolArgs(Map<String, String> args) {
args.forEach((k, v) -> {
toolArgs_.add(k);
if (v != null && !v.isEmpty()) {
toolArgs_.add(v);
}
});
return (T) this;
}
/**
* Tokenize command line arguments.
*
* <ul>
* <li>Arguments containing spaces should be quoted</li>
* <li>Escape sequences and comments are supported</li>
* </ul>
*/
public static class CommandLineTokenizer {
private final StringBuilder buf_ = new StringBuilder();
private final Reader input_;
private int ch_;
public CommandLineTokenizer(Reader input) throws IOException {
input_ = input;
ch_ = input.read();
}
public String nextToken() throws IOException {
trimWhitespaceOrComments();
if (ch_ == -1) {
return null;
}
buf_.setLength(0); // reset buffer
char quote = 0;
while (ch_ != -1) {
if (ch_ == '\'' || ch_ == '"') { // quotes
if (quote == 0) { // begin quote
quote = (char) ch_;
} else if (quote == ch_) { // end quote
quote = 0;
} else {
buf_.append((char) ch_);
}
} else if (ch_ == '\\') { // escaped
ch_ = input_.read();
buf_.append(handleEscapeSequence());
} else if (quote == 0 && Character.isWhitespace(ch_)) { // whitespaces
break;
} else {
buf_.append((char) ch_);
}
ch_ = input_.read();
}
return buf_.toString();
}
private char handleEscapeSequence() {
return switch (ch_) {
case -1 -> '\\';
case 'n' -> '\n';
case 'r' -> '\r';
case 't' -> '\t';
case 'f' -> '\f';
default -> (char) ch_;
};
}
private void trimWhitespaceOrComments() throws IOException {
while (ch_ != -1) {
if (Character.isWhitespace(ch_)) { // Skip whitespaces
ch_ = input_.read();
} else if (ch_ == '#') {
// Skip the entire comment until a new line or end of input
do {
ch_ = input_.read();
} while (ch_ != -1 && ch_ != '\n' && ch_ != '\r');
} else {
break;
}
}
}
}
}

View file

@ -5,7 +5,6 @@
package rife.bld.operations; package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.Project;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import rife.tools.exceptions.FileUtilsErrorException; import rife.tools.exceptions.FileUtilsErrorException;

View file

@ -5,7 +5,7 @@
package rife.bld.operations; package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.Project; import rife.bld.instrument.ModuleMainClassAdapter;
import rife.bld.operations.exceptions.ExitStatusException; import rife.bld.operations.exceptions.ExitStatusException;
import rife.tools.FileUtils; import rife.tools.FileUtils;
@ -23,16 +23,26 @@ import java.util.List;
* @since 1.5 * @since 1.5
*/ */
public class CompileOperation extends AbstractOperation<CompileOperation> { public class CompileOperation extends AbstractOperation<CompileOperation> {
static final String COMPILE_OPTION_D = "-d";
static final String COMPILE_OPTION_CP = "-cp";
static final String COMPILE_OPTION_CLASS_PATH = "--class-path";
static final String COMPILE_OPTION_CLASSPATH = "--classpath";
static final String COMPILE_OPTION_P = "-p";
static final String COMPILE_OPTION_MODULE_PATH = "--module-path";
private File buildMainDirectory_; private File buildMainDirectory_;
private File buildTestDirectory_; private File buildTestDirectory_;
private final List<String> compileMainClasspath_ = new ArrayList<>(); private final List<String> compileMainClasspath_ = new ArrayList<>();
private final List<String> compileTestClasspath_ = new ArrayList<>(); private final List<String> compileTestClasspath_ = new ArrayList<>();
private final List<String> compileMainModulePath_ = new ArrayList<>();
private final List<String> compileTestModulePath_ = new ArrayList<>();
private final List<File> mainSourceFiles_ = new ArrayList<>(); private final List<File> mainSourceFiles_ = new ArrayList<>();
private final List<File> testSourceFiles_ = new ArrayList<>(); private final List<File> testSourceFiles_ = new ArrayList<>();
private final List<File> mainSourceDirectories_ = new ArrayList<>(); private final List<File> mainSourceDirectories_ = new ArrayList<>();
private final List<File> testSourceDirectories_ = new ArrayList<>(); private final List<File> testSourceDirectories_ = new ArrayList<>();
private final JavacOptions compileOptions_ = new JavacOptions(); private final JavacOptions compileOptions_ = new JavacOptions();
private final List<Diagnostic<? extends JavaFileObject>> diagnostics_ = new ArrayList<>(); private final List<Diagnostic<? extends JavaFileObject>> diagnostics_ = new ArrayList<>();
private String moduleMainClass_;
/** /**
* Performs the compile operation. * Performs the compile operation.
@ -77,11 +87,19 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
for (var directory : mainSourceDirectories()) { for (var directory : mainSourceDirectories()) {
sources.addAll(FileUtils.getJavaFileList(directory)); sources.addAll(FileUtils.getJavaFileList(directory));
} }
if (sources.isEmpty()) {
if (!silent()) {
System.err.println("No main source files found.");
}
} else {
executeBuildSources( executeBuildSources(
compileMainClasspath(), compileMainClasspath(),
compileMainModulePath(),
sources, sources,
buildMainDirectory()); buildMainDirectory());
} }
}
/** /**
* Part of the {@link #execute} operation, builds the test sources. * Part of the {@link #execute} operation, builds the test sources.
@ -94,21 +112,30 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
for (var directory : testSourceDirectories()) { for (var directory : testSourceDirectories()) {
sources.addAll(FileUtils.getJavaFileList(directory)); sources.addAll(FileUtils.getJavaFileList(directory));
} }
if (sources.isEmpty()) {
if (!silent()) {
System.err.println("No test source files found.");
}
} else {
executeBuildSources( executeBuildSources(
compileTestClasspath(), compileTestClasspath(),
compileTestModulePath(),
sources, sources,
buildTestDirectory()); buildTestDirectory());
} }
}
/** /**
* Part of the {@link #execute} operation, build sources to a destination. * Part of the {@link #execute} operation, build sources to a destination.
* *
* @param classpath the classpath list used for the compilation * @param classpath the classpath list used for the compilation
* @param modulePath the module path list used for the compilation
* @param sources the source files to compile * @param sources the source files to compile
* @param destination the destination directory * @param destination the destination directory
* @since 1.5 * @since 2.1
*/ */
protected void executeBuildSources(List<String> classpath, List<File> sources, File destination) protected void executeBuildSources(List<String> classpath, List<String> modulePath, List<File> sources, File destination)
throws IOException { throws IOException {
if (sources.isEmpty() || destination == null) { if (sources.isEmpty() || destination == null) {
return; return;
@ -118,15 +145,51 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
try (var file_manager = compiler.getStandardFileManager(null, null, null)) { try (var file_manager = compiler.getStandardFileManager(null, null, null)) {
var compilation_units = file_manager.getJavaFileObjectsFromFiles(sources); var compilation_units = file_manager.getJavaFileObjectsFromFiles(sources);
var diagnostics = new DiagnosticCollector<JavaFileObject>(); var diagnostics = new DiagnosticCollector<JavaFileObject>();
var options = new ArrayList<>(List.of("-d", destination.getAbsolutePath(), "-cp", FileUtils.joinPaths(classpath))); var options = new ArrayList<>(List.of(COMPILE_OPTION_D, destination.getAbsolutePath()));
if (!classpath.isEmpty()) {
var class_path = FileUtils.joinPaths(classpath);
class_path = removeAndAppendCompileOptionPath(class_path, COMPILE_OPTION_CP);
class_path = removeAndAppendCompileOptionPath(class_path, COMPILE_OPTION_CLASS_PATH);
class_path = removeAndAppendCompileOptionPath(class_path, COMPILE_OPTION_CLASSPATH);
options.addAll(List.of(COMPILE_OPTION_CP, class_path));
}
if (!modulePath.isEmpty()) {
var module_path = FileUtils.joinPaths(modulePath);
module_path = removeAndAppendCompileOptionPath(module_path, COMPILE_OPTION_P);
module_path = removeAndAppendCompileOptionPath(module_path, COMPILE_OPTION_MODULE_PATH);
options.addAll(List.of(COMPILE_OPTION_P, module_path));
}
options.addAll(compileOptions()); options.addAll(compileOptions());
var compilation_task = compiler.getTask(null, file_manager, diagnostics, options, null, compilation_units); var compilation_task = compiler.getTask(null, file_manager, diagnostics, options, null, compilation_units);
if (!compilation_task.call()) { if (!compilation_task.call()) {
diagnostics_.addAll(diagnostics.getDiagnostics()); diagnostics_.addAll(diagnostics.getDiagnostics());
executeProcessDiagnostics(diagnostics); executeProcessDiagnostics(diagnostics);
} }
var module_info_class = new File(destination, "module-info.class");
if (module_info_class.exists() && moduleMainClass() != null) {
var orig_bytes = FileUtils.readBytes(module_info_class);
var transformed_bytes = ModuleMainClassAdapter.addModuleMainClassToBytes(orig_bytes, moduleMainClass());
FileUtils.writeBytes(transformed_bytes, module_info_class);
} }
} }
}
private String removeAndAppendCompileOptionPath(String basePath, String option) {
var index = compileOptions_.indexOf(option);
if (index != -1 && index + 1 < compileOptions_.size() - 1) {
compileOptions_.remove(index);
return basePath + File.pathSeparator + compileOptions_.remove(index);
}
return basePath;
}
/** /**
* Part of the {@link #execute} operation, processes the compilation diagnostics. * Part of the {@link #execute} operation, processes the compilation diagnostics.
@ -162,8 +225,11 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
.buildTestDirectory(project.buildTestDirectory()) .buildTestDirectory(project.buildTestDirectory())
.compileMainClasspath(project.compileMainClasspath()) .compileMainClasspath(project.compileMainClasspath())
.compileTestClasspath(project.compileTestClasspath()) .compileTestClasspath(project.compileTestClasspath())
.compileMainModulePath(project.compileMainModulePath())
.compileTestModulePath(project.compileTestModulePath())
.mainSourceFiles(project.mainSourceFiles()) .mainSourceFiles(project.mainSourceFiles())
.testSourceFiles(project.testSourceFiles()); .testSourceFiles(project.testSourceFiles())
.moduleMainClass(project.mainClass());
if (project.javaRelease() != null && !compileOptions().containsRelease()) { if (project.javaRelease() != null && !compileOptions().containsRelease()) {
compileOptions().release(project.javaRelease()); compileOptions().release(project.javaRelease());
} }
@ -246,6 +312,58 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
return this; return this;
} }
/**
* Provides entries for the main compilation module path.
*
* @param modulePath module path entries
* @return this operation instance
* @since 2.1
*/
public CompileOperation compileMainModulePath(String... modulePath) {
compileMainModulePath_.addAll(Arrays.asList(modulePath));
return this;
}
/**
* Provides a list of entries for the main compilation module path.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param modulePath a list of module path entries
* @return this operation instance
* @since 2.1
*/
public CompileOperation compileMainModulePath(List<String> modulePath) {
compileMainModulePath_.addAll(modulePath);
return this;
}
/**
* Provides entries for the test compilation module path.
*
* @param modulePath module path entries
* @return this operation instance
* @since 2.1
*/
public CompileOperation compileTestModulePath(String... modulePath) {
compileTestModulePath_.addAll(Arrays.asList(modulePath));
return this;
}
/**
* Provides a list of entries for the test compilation module path.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param modulePath a list of module path entries
* @return this operation instance
* @since 2.1
*/
public CompileOperation compileTestModulePath(List<String> modulePath) {
compileTestModulePath_.addAll(modulePath);
return this;
}
/** /**
* Provides main files that should be compiled. * Provides main files that should be compiled.
* *
@ -364,6 +482,18 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
return this; return this;
} }
/**
* Provides the main class to use if this compilation includes @{code module-info.java}.
*
* @param name the main class of the module
* @return this operation instance
* @since 2.1
*/
public CompileOperation moduleMainClass(String name) {
moduleMainClass_ = name;
return this;
}
/** /**
* Retrieves the main build destination directory. * Retrieves the main build destination directory.
* *
@ -408,6 +538,30 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
return compileTestClasspath_; return compileTestClasspath_;
} }
/**
* Retrieves the list of entries for the main compilation module path.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the main compilation module path list
* @since 2.1
*/
public List<String> compileMainModulePath() {
return compileMainModulePath_;
}
/**
* Retrieves the list of entries for the test compilation module path.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the test compilation module path list
* @since 2.1
*/
public List<String> compileTestModulePath() {
return compileTestModulePath_;
}
/** /**
* Retrieves the list of main files that should be compiled. * Retrieves the list of main files that should be compiled.
* <p> * <p>
@ -477,4 +631,15 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
public List<Diagnostic<? extends JavaFileObject>> diagnostics() { public List<Diagnostic<? extends JavaFileObject>> diagnostics() {
return diagnostics_; return diagnostics_;
} }
/**
* Retrieves the main class to use if this compilation includes @{code module-info.java}.
*
* @return the main class to use for the module
* @since 2.1
*/
public String moduleMainClass() {
return moduleMainClass_;
}
} }

View file

@ -0,0 +1,26 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import rife.bld.Project;
import rife.bld.blueprints.AppProjectBlueprint;
import java.io.File;
/**
* Creates a new app project structure.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.9
*/
public class CreateAppOperation extends AbstractCreateOperation<CreateAppOperation, Project> {
public CreateAppOperation() {
super("bld.app.");
}
protected Project createProjectBlueprint() {
return new AppProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName(), baseName());
}
}

View file

@ -21,6 +21,6 @@ public class CreateBaseOperation extends AbstractCreateOperation<CreateBaseOpera
} }
protected Project createProjectBlueprint() { protected Project createProjectBlueprint() {
return new BaseProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName()); return new BaseProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName(), baseName());
} }
} }

View file

@ -1,26 +0,0 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import rife.bld.Project;
import rife.bld.blueprints.BlankProjectBlueprint;
import java.io.File;
/**
* Creates a new blank project structure.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class CreateBlankOperation extends AbstractCreateOperation<CreateBlankOperation, Project> {
public CreateBlankOperation() {
super("bld.blank.");
}
protected Project createProjectBlueprint() {
return new BlankProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName());
}
}

View file

@ -5,7 +5,6 @@
package rife.bld.operations; package rife.bld.operations;
import rife.bld.Project; import rife.bld.Project;
import rife.bld.blueprints.BaseProjectBlueprint;
import rife.bld.blueprints.LibProjectBlueprint; import rife.bld.blueprints.LibProjectBlueprint;
import java.io.File; import java.io.File;
@ -22,11 +21,7 @@ public class CreateLibOperation extends AbstractCreateOperation<CreateLibOperati
} }
protected Project createProjectBlueprint() { protected Project createProjectBlueprint() {
return new LibProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName()); return new LibProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName(), baseName());
}
protected String projectMainClassName(String projectClassName) {
return projectClassName + "Lib";
} }
protected boolean createIdeaRunMain() { protected boolean createIdeaRunMain() {

View file

@ -7,6 +7,7 @@ package rife.bld.operations;
import rife.bld.operations.exceptions.OperationOptionException; import rife.bld.operations.exceptions.OperationOptionException;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -16,6 +17,12 @@ import java.util.List;
* @since 1.7 * @since 1.7
*/ */
public class CreateOperation { public class CreateOperation {
private static final String BASE = "base";
private static final String APP = "app";
private static final String LIB = "lib";
private static final String RIFE2 = "rife2";
/** /**
* Configures a creation operation from command-line arguments. * Configures a creation operation from command-line arguments.
* *
@ -27,31 +34,40 @@ public class CreateOperation {
String type = null; String type = null;
String package_name = null; String package_name = null;
String project_name = null; String project_name = null;
if (arguments.size() > 0) { String base_name = null;
if (!arguments.isEmpty()) {
type = arguments.remove(0); type = arguments.remove(0);
} }
if (arguments.size() > 0) {
var create_operation_args = new ArrayList<String>();
if (!arguments.isEmpty()) {
package_name = arguments.remove(0); package_name = arguments.remove(0);
create_operation_args.add(package_name);
} }
if (arguments.size() > 0) { if (!arguments.isEmpty()) {
project_name = arguments.remove(0); project_name = arguments.remove(0);
create_operation_args.add(project_name);
} }
if ((type == null || package_name == null || project_name == null) && System.console() == null) { if (!arguments.isEmpty()) {
throw new OperationOptionException("ERROR: Expecting the type, package and project names as the arguments."); base_name = arguments.remove(0);
create_operation_args.add(base_name);
}
if ((package_name == null || project_name == null || base_name == null) && System.console() == null) {
throw new OperationOptionException("ERROR: Expecting the package, project and base names as the arguments.");
} }
if (type == null || type.isEmpty()) { if (type == null || type.isBlank()) {
System.out.println("Please enter a number for the project type:"); System.out.println("Please enter a number for the project type:");
System.out.println(" 1: base"); System.out.printf(" 1: %s (Java baseline project)%n", BASE);
System.out.println(" 2: blank"); System.out.printf(" 2: %s (Java application project)%n", APP);
System.out.println(" 3: lib"); System.out.printf(" 3: %s (Java library project)%n", LIB);
System.out.println(" 4: rife2"); System.out.printf(" 4: %s (RIFE2 web application)%n", RIFE2);
var number = System.console().readLine(); var number = System.console().readLine();
switch (Integer.parseInt(number)) { switch (Integer.parseInt(number)) {
case 1 -> type = "base"; case 1 -> type = BASE;
case 2 -> type = "blank"; case 2 -> type = APP;
case 3 -> type = "lib"; case 3 -> type = LIB;
case 4 -> type = "rife2"; case 4 -> type = RIFE2;
} }
} else { } else {
System.out.println("Using project type: " + type); System.out.println("Using project type: " + type);
@ -62,32 +78,15 @@ public class CreateOperation {
AbstractCreateOperation<?, ?> create_operation = null; AbstractCreateOperation<?, ?> create_operation = null;
switch (type) { switch (type) {
case "base" -> create_operation = new CreateBaseOperation(); case BASE -> create_operation = new CreateBaseOperation();
case "blank" -> create_operation = new CreateBlankOperation(); case APP -> create_operation = new CreateAppOperation();
case "lib" -> create_operation = new CreateLibOperation(); case LIB -> create_operation = new CreateLibOperation();
case "rife2" -> create_operation = new CreateRife2Operation(); case RIFE2 -> create_operation = new CreateRife2Operation();
} }
if (create_operation == null) { if (create_operation == null) {
throw new OperationOptionException("ERROR: Unsupported project type."); throw new OperationOptionException("ERROR: Unsupported project type.");
} }
if (package_name == null || package_name.isEmpty()) { return create_operation.fromArguments(create_operation_args);
System.out.println("Please enter a package name (for instance: com.example):");
package_name = System.console().readLine();
} else {
System.out.println("Using package name: " + package_name);
}
if (project_name == null || project_name.isEmpty()) {
System.out.println("Please enter a project name (for instance: myapp):");
project_name = System.console().readLine();
} else {
System.out.println("Using project name: " + project_name);
}
return create_operation.workDirectory(new File(System.getProperty("user.dir")))
.packageName(package_name)
.projectName(project_name)
.downloadDependencies(true);
} }
} }

View file

@ -7,6 +7,7 @@ package rife.bld.operations;
import rife.bld.blueprints.Rife2ProjectBlueprint; import rife.bld.blueprints.Rife2ProjectBlueprint;
import rife.template.TemplateFactory; import rife.template.TemplateFactory;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import rife.tools.StringUtils;
import rife.tools.exceptions.FileUtilsErrorException; import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File; import java.io.File;
@ -27,14 +28,14 @@ public class CreateRife2Operation extends AbstractCreateOperation<CreateRife2Ope
} }
protected Rife2ProjectBlueprint createProjectBlueprint() { protected Rife2ProjectBlueprint createProjectBlueprint() {
return new Rife2ProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName()); return new Rife2ProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName(), baseName());
} }
@Override @Override
protected void executeConfigure() { protected void executeConfigure() {
super.executeConfigure(); super.executeConfigure();
projectMainName_ = projectClassName_ + "Site"; projectMainName_ = baseName() + "Site";
projectMainUberName_ = projectMainName_ + "Uber"; projectMainUberName_ = projectMainName_ + "Uber";
srcMainWebappCssDirectory_ = new File(project_.srcMainWebappDirectory(), "css"); srcMainWebappCssDirectory_ = new File(project_.srcMainWebappDirectory(), "css");
srcMainWebappWebInfDirectory_ = new File(project_.srcMainWebappDirectory(), "WEB-INF"); srcMainWebappWebInfDirectory_ = new File(project_.srcMainWebappDirectory(), "WEB-INF");
@ -63,7 +64,7 @@ public class CreateRife2Operation extends AbstractCreateOperation<CreateRife2Ope
// project template // project template
var template_template = TemplateFactory.HTML.get(templateBase_ + "project_template"); var template_template = TemplateFactory.HTML.get(templateBase_ + "project_template");
template_template.setValue("project", projectClassName_); template_template.setValue("project", project_.name());
var project_template_file = new File(project_.srcMainResourcesTemplatesDirectory(), "hello.html"); var project_template_file = new File(project_.srcMainResourcesTemplatesDirectory(), "hello.html");
FileUtils.writeString(template_template.getContent(), project_template_file); FileUtils.writeString(template_template.getContent(), project_template_file);

View file

@ -5,13 +5,19 @@
package rife.bld.operations; package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.BldCache;
import rife.bld.BldVersion;
import rife.bld.BuildExecutor;
import rife.bld.dependencies.*; import rife.bld.dependencies.*;
import rife.bld.wrapper.Wrapper;
import rife.ioc.HierarchicalProperties;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static rife.bld.dependencies.Scope.compile; import static rife.bld.dependencies.Scope.*;
import static rife.bld.dependencies.Scope.runtime;
/** /**
* Transitively generates a hierarchical tree of dependencies. * Transitively generates a hierarchical tree of dependencies.
@ -20,10 +26,17 @@ import static rife.bld.dependencies.Scope.runtime;
* @since 1.5.21 * @since 1.5.21
*/ */
public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOperation> { public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOperation> {
private boolean offline_ = false;
private HierarchicalProperties properties_ = null;
private HierarchicalProperties extensionProperties_ = null;
private ArtifactRetriever retriever_ = null; private ArtifactRetriever retriever_ = null;
private final List<Repository> repositories_ = new ArrayList<>(); private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes(); private final DependencyScopes dependencies_ = new DependencyScopes();
private final List<Repository> extensionRepositories_ = new ArrayList<>();
private final DependencyScopes extensionDependencies_ = new DependencyScopes();
private final StringBuilder dependencyTree_ = new StringBuilder(); private final StringBuilder dependencyTree_ = new StringBuilder();
private File libBldDir_ = null;
/** /**
* Performs the dependency tree operation. * Performs the dependency tree operation.
@ -31,16 +44,132 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
* @since 1.5.21 * @since 1.5.21
*/ */
public void execute() { public void execute() {
var compile_tree = executeGenerateCompileDependencies(); if (offline_) {
var runtime_tree = executeGenerateRuntimeDependencies(); System.out.println("Offline mode: dependency-tree is disabled");
return;
}
// calculate the dependency tree of the extensions, using the cache if possible
String extensions_tree = null;
BldCache extensions_cache = null;
if (libBldDir_ != null) {
extensions_cache = new BldCache(libBldDir_, new VersionResolution(extensionProperties()));
extensions_cache.cacheExtensionsHash(
extensionRepositories().stream().map(Repository::toString).toList(),
extensionDependencies().scope(compile).stream().map(Dependency::toString).toList());
if (extensions_cache.isExtensionsHashValid()) {
var cached_tree = extensions_cache.getCachedExtensionsDependencyTree();
if (cached_tree != null) {
extensions_tree = cached_tree;
}
}
}
if (extensions_tree == null) {
extensions_tree = executeGenerateExtensionsDependencies();
if (extensions_cache != null) {
extensions_cache.cacheExtensionsDependencyTree(extensions_tree);
extensions_cache.writeCache();
}
}
// calculate the dependency tree of the dependencies, using the cache if possible
String compile_tree = null;
String provided_tree = null;
String runtime_tree = null;
String test_tree = null;
BldCache dependencies_cache = null;
if (libBldDir_ != null) {
dependencies_cache = new BldCache(libBldDir_, new VersionResolution(properties()));
dependencies_cache.cacheDependenciesHash(repositories(), dependencies());
if (dependencies_cache.isDependenciesHashValid()) {
var cached_compile_tree = dependencies_cache.getCachedDependenciesCompileDependencyTree();
if (cached_compile_tree != null) {
compile_tree = cached_compile_tree;
}
var cached_provided_tree = dependencies_cache.getCachedDependenciesProvidedDependencyTree();
if (cached_provided_tree != null) {
provided_tree = cached_provided_tree;
}
var cached_runtime_tree = dependencies_cache.getCachedDependenciesRuntimeDependencyTree();
if (cached_runtime_tree != null) {
runtime_tree = cached_runtime_tree;
}
var cached_test_tree = dependencies_cache.getCachedDependenciesTestDependencyTree();
if (cached_test_tree != null) {
test_tree = cached_test_tree;
}
}
}
var write_dependencies_cache = false;
if (compile_tree == null) {
compile_tree = executeGenerateCompileDependencies();
if (dependencies_cache != null) {
dependencies_cache.cacheDependenciesCompileDependencyTree(compile_tree);
write_dependencies_cache = true;
}
}
if (provided_tree == null) {
provided_tree = executeGenerateProvidedDependencies();
if (dependencies_cache != null) {
dependencies_cache.cacheDependenciesProvidedDependencyTree(provided_tree);
write_dependencies_cache = true;
}
}
if (runtime_tree == null) {
runtime_tree = executeGenerateRuntimeDependencies();
if (dependencies_cache != null) {
dependencies_cache.cacheDependenciesRuntimeDependencyTree(runtime_tree);
write_dependencies_cache = true;
}
}
if (test_tree == null) {
test_tree = executeGenerateTestDependencies();
if (dependencies_cache != null) {
dependencies_cache.cacheDependenciesTestDependencyTree(test_tree);
write_dependencies_cache = true;
}
}
if (write_dependencies_cache) {
dependencies_cache.writeCache();
}
// output the dependency trees
dependencyTree_.setLength(0); dependencyTree_.setLength(0);
dependencyTree_.append(extensions_tree);
dependencyTree_.append(System.lineSeparator());
dependencyTree_.append(compile_tree); dependencyTree_.append(compile_tree);
dependencyTree_.append(System.lineSeparator()); dependencyTree_.append(System.lineSeparator());
dependencyTree_.append(provided_tree);
dependencyTree_.append(System.lineSeparator());
dependencyTree_.append(runtime_tree); dependencyTree_.append(runtime_tree);
dependencyTree_.append(System.lineSeparator()); dependencyTree_.append(System.lineSeparator());
dependencyTree_.append(test_tree);
dependencyTree_.append(System.lineSeparator());
System.out.println(extensions_tree);
System.out.println(compile_tree); System.out.println(compile_tree);
System.out.println(provided_tree);
System.out.println(runtime_tree); System.out.println(runtime_tree);
System.out.println(test_tree);
}
/**
* Part of the {@link #execute} operation, generates the tree for the extensions.
*
* @since 2.0
*/
protected String executeGenerateExtensionsDependencies() {
var extensions_tree = extensionDependencies().scope(compile).generateTransitiveDependencyTree(new VersionResolution(extensionProperties()), artifactRetriever(), extensionRepositories(), compile, runtime);
if (extensions_tree.isEmpty()) {
extensions_tree = "no dependencies" + System.lineSeparator();
}
return "extensions:" + System.lineSeparator() + extensions_tree;
} }
/** /**
@ -49,26 +178,52 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
* @since 1.5.21 * @since 1.5.21
*/ */
protected String executeGenerateCompileDependencies() { protected String executeGenerateCompileDependencies() {
var compile_tree = dependencies().scope(compile).generateTransitiveDependencyTree(artifactRetriever(), repositories(), compile); var compile_tree = dependencies().scope(compile).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile);
if (compile_tree.isEmpty()) { if (compile_tree.isEmpty()) {
compile_tree = "no dependencies" + System.lineSeparator(); compile_tree = "no dependencies" + System.lineSeparator();
} }
return "compile:" + System.lineSeparator() + compile_tree; return "compile:" + System.lineSeparator() + compile_tree;
} }
/**
* Part of the {@link #execute} operation, generates the tree for the provided scope.
*
* @since 1.7.3
*/
protected String executeGenerateProvidedDependencies() {
var provided_tree = dependencies().scope(provided).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile, runtime);
if (provided_tree.isEmpty()) {
provided_tree = "no dependencies" + System.lineSeparator();
}
return "provided:" + System.lineSeparator() + provided_tree;
}
/** /**
* Part of the {@link #execute} operation, generates the tree for the runtime scope. * Part of the {@link #execute} operation, generates the tree for the runtime scope.
* *
* @since 1.5.21 * @since 1.5.21
*/ */
protected String executeGenerateRuntimeDependencies() { protected String executeGenerateRuntimeDependencies() {
var runtime_tree = dependencies().scope(runtime).generateTransitiveDependencyTree(artifactRetriever(), repositories(), compile, runtime); var runtime_tree = dependencies().scope(runtime).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile, runtime);
if (runtime_tree.isEmpty()) { if (runtime_tree.isEmpty()) {
runtime_tree = "no dependencies" + System.lineSeparator(); runtime_tree = "no dependencies" + System.lineSeparator();
} }
return "runtime:" + System.lineSeparator() + runtime_tree; return "runtime:" + System.lineSeparator() + runtime_tree;
} }
/**
* Part of the {@link #execute} operation, generates the tree for the test scope.
*
* @since 1.7.3
*/
protected String executeGenerateTestDependencies() {
var test_tree = dependencies().scope(test).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile, runtime);
if (test_tree.isEmpty()) {
test_tree = "no dependencies" + System.lineSeparator();
}
return "test:" + System.lineSeparator() + test_tree;
}
/** /**
* Configures a dependency tree operation from a {@link BaseProject}. * Configures a dependency tree operation from a {@link BaseProject}.
@ -77,11 +232,59 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
* @since 1.5.21 * @since 1.5.21
*/ */
public DependencyTreeOperation fromProject(BaseProject project) { public DependencyTreeOperation fromProject(BaseProject project) {
return artifactRetriever(project.artifactRetriever()) libBldDir_ = project.libBldDirectory();
// add the repositories and dependencies from the extensions
var wrapper = new Wrapper();
wrapper.currentDir(project.workDirectory());
try {
wrapper.initWrapperProperties(BldVersion.getVersion());
var extension_properties = BuildExecutor.setupProperties(project.workDirectory());
extension_properties = new HierarchicalProperties().parent(extension_properties);
extension_properties.putAll(wrapper.wrapperProperties());
extensionProperties(extension_properties);
for (var repository : wrapper.repositories()) {
extensionRepositories().add(Repository.resolveRepository(extensionProperties(), repository));
}
extensionDependencies().scope(compile).addAll(wrapper.extensions().stream().map(Dependency::parse).toList());
} catch (IOException e) {
throw new RuntimeException(e);
}
// add the repositories and the dependencies from the project
return offline(project.offline())
.properties(project.properties())
.artifactRetriever(project.artifactRetriever())
.repositories(project.repositories()) .repositories(project.repositories())
.dependencies(project.dependencies()); .dependencies(project.dependencies());
} }
/**
* Indicates whether the operation has to run offline.
*
* @param flag {@code true} if the operation runs offline; or
* {@code false} otherwise
* @return this operation instance
* @since 2.0
*/
public DependencyTreeOperation offline(boolean flag) {
offline_ = flag;
return this;
}
/**
* Returns whether the operation has to run offline.
*
* @return {@code true} if the operation runs offline; or
* {@code false} otherwise
* @since 2.0
*/
public boolean offline() {
return offline_;
}
/** /**
* Provides repositories to resolve the dependencies against. * Provides repositories to resolve the dependencies against.
* *
@ -120,6 +323,44 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
return this; return this;
} }
/**
* Provides extension repositories to resolve the extension dependencies against.
*
* @param repositories extension repositories against which extension dependencies will be resolved
* @return this operation instance
* @since 2.0
*/
public DependencyTreeOperation extensionRepositories(Repository... repositories) {
extensionRepositories_.addAll(List.of(repositories));
return this;
}
/**
* Provides a list of extension repositories to resolve the extension dependencies against.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param repositories a list of extension repositories against which extension dependencies will be resolved
* @return this operation instance
* @since 2.0
*/
public DependencyTreeOperation extensionRepositories(List<Repository> repositories) {
extensionRepositories_.addAll(repositories);
return this;
}
/**
* Provides scoped extension dependencies to generate a tree for.
*
* @param dependencies the extension dependencies that will be resolved for tree generation
* @return this operation instance
* @since 2.0
*/
public DependencyTreeOperation extensionDependencies(DependencyScopes dependencies) {
extensionDependencies_.include(dependencies);
return this;
}
/** /**
* Provides the artifact retriever to use. * Provides the artifact retriever to use.
* *
@ -132,6 +373,30 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
return this; return this;
} }
/**
* Provides the hierarchical properties to use.
*
* @param properties the hierarchical properties
* @return this operation instance
* @since 2.0
*/
public DependencyTreeOperation properties(HierarchicalProperties properties) {
properties_ = properties;
return this;
}
/**
* Provides the extension hierarchical properties to use.
*
* @param properties the extension hierarchical properties
* @return this operation instance
* @since 2.0
*/
public DependencyTreeOperation extensionProperties(HierarchicalProperties properties) {
extensionProperties_ = properties;
return this;
}
/** /**
* Retrieves the repositories in which the dependencies will be resolved. * Retrieves the repositories in which the dependencies will be resolved.
* <p> * <p>
@ -156,6 +421,30 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
return dependencies_; return dependencies_;
} }
/**
* Retrieves the extension repositories in which the dependencies will be resolved.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the extension repositories used for dependency resolution
* @since 2.0
*/
public List<Repository> extensionRepositories() {
return extensionRepositories_;
}
/**
* Retrieves the scoped extension dependencies that will be used for tree generation.
* <p>
* This is a modifiable structure that can be retrieved and changed.
*
* @return the scoped extension dependencies
* @since 2.0
*/
public DependencyScopes extensionDependencies() {
return extensionDependencies_;
}
/** /**
* Returns the artifact retriever that is used. * Returns the artifact retriever that is used.
* *
@ -178,4 +467,30 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
public String dependencyTree() { public String dependencyTree() {
return dependencyTree_.toString(); return dependencyTree_.toString();
} }
/**
* Returns the hierarchical properties that are used.
*
* @return the hierarchical properties
* @since 2.0
*/
public HierarchicalProperties properties() {
if (properties_ == null) {
properties_ = new HierarchicalProperties();
}
return properties_;
}
/**
* Returns the extension hierarchical properties that are used.
*
* @return the extension hierarchical properties
* @since 2.0
*/
public HierarchicalProperties extensionProperties() {
if (extensionProperties_ == null) {
extensionProperties_ = new HierarchicalProperties();
}
return extensionProperties_;
}
} }

View file

@ -6,6 +6,7 @@ package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.dependencies.*; import rife.bld.dependencies.*;
import rife.ioc.HierarchicalProperties;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
@ -24,13 +25,21 @@ import static rife.bld.dependencies.Dependency.CLASSIFIER_SOURCES;
* @since 1.5 * @since 1.5
*/ */
public class DownloadOperation extends AbstractOperation<DownloadOperation> { public class DownloadOperation extends AbstractOperation<DownloadOperation> {
private boolean offline_ = false;
private HierarchicalProperties properties_ = null;
private ArtifactRetriever retriever_ = null; private ArtifactRetriever retriever_ = null;
private final List<Repository> repositories_ = new ArrayList<>(); private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes(); private final DependencyScopes dependencies_ = new DependencyScopes();
private File libCompileDirectory_; private File libCompileDirectory_;
private File libCompileModulesDirectory_;
private File libProvidedDirectory_;
private File libProvidedModulesDirectory_;
private File libRuntimeDirectory_; private File libRuntimeDirectory_;
private File libRuntimeModulesDirectory_;
private File libStandaloneDirectory_; private File libStandaloneDirectory_;
private File libStandaloneModulesDirectory_;
private File libTestDirectory_; private File libTestDirectory_;
private File libTestModulesDirectory_;
private boolean downloadSources_ = false; private boolean downloadSources_ = false;
private boolean downloadJavadoc_ = false; private boolean downloadJavadoc_ = false;
@ -40,7 +49,13 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5 * @since 1.5
*/ */
public void execute() { public void execute() {
if (offline_) {
System.out.println("Offline mode: download is disabled");
return;
}
executeDownloadCompileDependencies(); executeDownloadCompileDependencies();
executeDownloadProvidedDependencies();
executeDownloadRuntimeDependencies(); executeDownloadRuntimeDependencies();
executeDownloadStandaloneDependencies(); executeDownloadStandaloneDependencies();
executeDownloadTestDependencies(); executeDownloadTestDependencies();
@ -55,7 +70,16 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5 * @since 1.5
*/ */
protected void executeDownloadCompileDependencies() { protected void executeDownloadCompileDependencies() {
executeDownloadDependencies(libCompileDirectory(), dependencies().resolveCompileDependencies(artifactRetriever(), repositories())); executeDownloadDependencies(libCompileDirectory(), libCompileModulesDirectory(), dependencies().resolveCompileDependencies(properties(), artifactRetriever(), repositories()));
}
/**
* Part of the {@link #execute} operation, download the {@code provided} scope artifacts.
*
* @since 1.8
*/
protected void executeDownloadProvidedDependencies() {
executeDownloadDependencies(libProvidedDirectory(), libProvidedModulesDirectory(), dependencies().resolveProvidedDependencies(properties(), artifactRetriever(), repositories()));
} }
/** /**
@ -64,7 +88,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5 * @since 1.5
*/ */
protected void executeDownloadRuntimeDependencies() { protected void executeDownloadRuntimeDependencies() {
executeDownloadDependencies(libRuntimeDirectory(), dependencies().resolveRuntimeDependencies(artifactRetriever(), repositories())); executeDownloadDependencies(libRuntimeDirectory(), libRuntimeModulesDirectory(), dependencies().resolveRuntimeDependencies(properties(), artifactRetriever(), repositories()));
} }
/** /**
@ -73,7 +97,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5 * @since 1.5
*/ */
protected void executeDownloadStandaloneDependencies() { protected void executeDownloadStandaloneDependencies() {
executeDownloadDependencies(libStandaloneDirectory(), dependencies().resolveStandaloneDependencies(artifactRetriever(), repositories())); executeDownloadDependencies(libStandaloneDirectory(), libStandaloneModulesDirectory(), dependencies().resolveStandaloneDependencies(properties(), artifactRetriever(), repositories()));
} }
/** /**
@ -82,23 +106,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5 * @since 1.5
*/ */
protected void executeDownloadTestDependencies() { protected void executeDownloadTestDependencies() {
executeDownloadDependencies(libTestDirectory(), dependencies().resolveTestDependencies(artifactRetriever(), repositories())); executeDownloadDependencies(libTestDirectory(), libTestModulesDirectory(), dependencies().resolveTestDependencies(properties(), artifactRetriever(), repositories()));
} }
/** /**
* Part of the {@link #execute} operation, download the artifacts for a particular dependency scope. * Part of the {@link #execute} operation, download the artifacts for a particular dependency scope.
* *
* @param destinationDirectory the directory in which the artifacts should be downloaded * @param destinationDirectory the directory in which the artifacts should be downloaded
* @param modulesDirectory the directory in which the modules should be downloaded
* @param dependencies the dependencies to download * @param dependencies the dependencies to download
* @since 1.6 * @since 2.1
*/ */
protected void executeDownloadDependencies(File destinationDirectory, DependencySet dependencies) { protected void executeDownloadDependencies(File destinationDirectory, File modulesDirectory, DependencySet dependencies) {
if (destinationDirectory == null) {
return;
}
destinationDirectory.mkdirs();
var additional_classifiers = new String[0]; var additional_classifiers = new String[0];
if (downloadSources_ || downloadJavadoc_) { if (downloadSources_ || downloadJavadoc_) {
@ -109,27 +128,60 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
additional_classifiers = classifiers.toArray(new String[0]); additional_classifiers = classifiers.toArray(new String[0]);
} }
dependencies.transferIntoDirectory(artifactRetriever(), repositories(), destinationDirectory, additional_classifiers); dependencies.transferIntoDirectory(new VersionResolution(properties()), artifactRetriever(), repositories(), destinationDirectory, modulesDirectory, additional_classifiers);
} }
/** /**
* Configures a compile operation from a {@link BaseProject}. * Configures a compile operation from a {@link BaseProject}.
* *
* @param project the project to configure the compile operation from * @param project the project to configure the compile operation from
* @return this operation instance
* @since 1.5 * @since 1.5
*/ */
public DownloadOperation fromProject(BaseProject project) { public DownloadOperation fromProject(BaseProject project) {
return artifactRetriever(project.artifactRetriever()) return offline(project.offline())
.properties(project.properties())
.artifactRetriever(project.artifactRetriever())
.repositories(project.repositories()) .repositories(project.repositories())
.dependencies(project.dependencies()) .dependencies(project.dependencies())
.libCompileDirectory(project.libCompileDirectory()) .libCompileDirectory(project.libCompileDirectory())
.libCompileModulesDirectory(project.libCompileModulesDirectory())
.libProvidedDirectory(project.libProvidedDirectory())
.libProvidedModulesDirectory(project.libProvidedModulesDirectory())
.libRuntimeDirectory(project.libRuntimeDirectory()) .libRuntimeDirectory(project.libRuntimeDirectory())
.libRuntimeModulesDirectory(project.libRuntimeModulesDirectory())
.libStandaloneDirectory(project.libStandaloneDirectory()) .libStandaloneDirectory(project.libStandaloneDirectory())
.libStandaloneModulesDirectory(project.libStandaloneModulesDirectory())
.libTestDirectory(project.libTestDirectory()) .libTestDirectory(project.libTestDirectory())
.libTestModulesDirectory(project.libTestModulesDirectory())
.downloadSources(project.downloadSources()) .downloadSources(project.downloadSources())
.downloadJavadoc(project.downloadJavadoc()); .downloadJavadoc(project.downloadJavadoc());
} }
/**
* Indicates whether the operation has to run offline.
*
* @param flag {@code true} if the operation runs offline; or
* {@code false} otherwise
* @return this operation instance
* @since 2.0
*/
public DownloadOperation offline(boolean flag) {
offline_ = flag;
return this;
}
/**
* Returns whether the operation has to run offline.
*
* @return {@code true} if the operation runs offline; or
* {@code false} otherwise
* @since 2.0
*/
public boolean offline() {
return offline_;
}
/** /**
* Provides repositories to resolve the dependencies against. * Provides repositories to resolve the dependencies against.
* *
@ -180,6 +232,42 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this; return this;
} }
/**
* Provides the {@code compile} scope modules download directory.
*
* @param directory the directory to download the {@code compile} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libCompileModulesDirectory(File directory) {
libCompileModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code provided} scope download directory.
*
* @param directory the directory to download the {@code provided} scope artifacts into
* @return this operation instance
* @since 1.8
*/
public DownloadOperation libProvidedDirectory(File directory) {
libProvidedDirectory_ = directory;
return this;
}
/**
* Provides the {@code provided} scope modules download directory.
*
* @param directory the directory to download the {@code provided} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libProvidedModulesDirectory(File directory) {
libProvidedModulesDirectory_ = directory;
return this;
}
/** /**
* Provides the {@code runtime} scope download directory. * Provides the {@code runtime} scope download directory.
* *
@ -192,6 +280,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this; return this;
} }
/**
* Provides the {@code runtime} scope modules download directory.
*
* @param directory the directory to download the {@code runtime} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libRuntimeModulesDirectory(File directory) {
libRuntimeModulesDirectory_ = directory;
return this;
}
/** /**
* Provides the {@code standalone} scope download directory. * Provides the {@code standalone} scope download directory.
* *
@ -204,6 +304,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this; return this;
} }
/**
* Provides the {@code standalone} scope modules download directory.
*
* @param directory the directory to download the {@code standalone} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libStandaloneModulesDirectory(File directory) {
libStandaloneModulesDirectory_ = directory;
return this;
}
/** /**
* Provides the {@code test} scope download directory. * Provides the {@code test} scope download directory.
* *
@ -216,6 +328,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this; return this;
} }
/**
* Provides the {@code test} scope modules download directory.
*
* @param directory the directory to download the {@code test} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libTestModulesDirectory(File directory) {
libTestModulesDirectory_ = directory;
return this;
}
/** /**
* Indicates whether the sources classifier should also be downloaded. * Indicates whether the sources classifier should also be downloaded.
* *
@ -254,6 +378,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this; return this;
} }
/**
* Provides the hierarchical properties to use.
*
* @param properties the hierarchical properties
* @return this operation instance
* @since 2.0
*/
public DownloadOperation properties(HierarchicalProperties properties) {
properties_ = properties;
return this;
}
/** /**
* Retrieves the repositories in which the dependencies will be resolved. * Retrieves the repositories in which the dependencies will be resolved.
* <p> * <p>
@ -288,6 +424,36 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return libCompileDirectory_; return libCompileDirectory_;
} }
/**
* Retrieves the {@code compile} scope modules download directory.
*
* @return the {@code compile} scope modules download directory
* @since 2.1
*/
public File libCompileModulesDirectory() {
return libCompileModulesDirectory_;
}
/**
* Retrieves the {@code provided} scope download directory.
*
* @return the {@code provided} scope download directory
* @since 1.8
*/
public File libProvidedDirectory() {
return libProvidedDirectory_;
}
/**
* Retrieves the {@code provided} scope modules download directory.
*
* @return the {@code provided} scope modules download directory
* @since 2.1
*/
public File libProvidedModulesDirectory() {
return libProvidedModulesDirectory_;
}
/** /**
* Retrieves the {@code runtime} scope download directory. * Retrieves the {@code runtime} scope download directory.
* *
@ -298,6 +464,16 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return libRuntimeDirectory_; return libRuntimeDirectory_;
} }
/**
* Retrieves the {@code runtime} scope modules download directory.
*
* @return the {@code runtime} scope modules download directory
* @since 2.1
*/
public File libRuntimeModulesDirectory() {
return libRuntimeModulesDirectory_;
}
/** /**
* Retrieves the {@code standalone} scope download directory. * Retrieves the {@code standalone} scope download directory.
* *
@ -308,6 +484,16 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return libStandaloneDirectory_; return libStandaloneDirectory_;
} }
/**
* Retrieves the {@code standalone} scope modules download directory.
*
* @return the {@code standalone} scope modules download directory
* @since 2.1
*/
public File libStandaloneModulesDirectory() {
return libStandaloneModulesDirectory_;
}
/** /**
* Retrieves the {@code test} scope download directory. * Retrieves the {@code test} scope download directory.
* *
@ -318,6 +504,16 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return libTestDirectory_; return libTestDirectory_;
} }
/**
* Retrieves the {@code test} scope modules download directory.
*
* @return the {@code test} scope modules download directory
* @since 2.1
*/
public File libTestModulesDirectory() {
return libTestModulesDirectory_;
}
/** /**
* Retrieves whether the sources classifier should also be downloaded. * Retrieves whether the sources classifier should also be downloaded.
* *
@ -352,4 +548,17 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
} }
return retriever_; return retriever_;
} }
/**
* Returns the hierarchical properties that are used.
*
* @return the hierarchical properties
* @since 2.0
*/
public HierarchicalProperties properties() {
if (properties_ == null) {
properties_ = new HierarchicalProperties();
}
return properties_;
}
} }

View file

@ -6,6 +6,8 @@ package rife.bld.operations;
import rife.bld.BldVersion; import rife.bld.BldVersion;
import rife.bld.BuildExecutor; import rife.bld.BuildExecutor;
import rife.template.TemplateFactory;
import rife.tools.ExceptionUtils;
import java.util.List; import java.util.List;
@ -18,8 +20,11 @@ import static java.util.Comparator.comparingInt;
* @since 1.5 * @since 1.5
*/ */
public class HelpOperation { public class HelpOperation {
private static final String JSON_ARGUMENT = "--json";
private final BuildExecutor executor_; private final BuildExecutor executor_;
private final List<String> arguments_; private final List<String> arguments_;
private boolean outputJson_ = false;
/** /**
* Creates a new help operation. * Creates a new help operation.
@ -41,51 +46,116 @@ public class HelpOperation {
public void execute() { public void execute() {
var topic = ""; var topic = "";
if (!arguments_.isEmpty()) { if (!arguments_.isEmpty()) {
if (arguments_.get(0).equals(JSON_ARGUMENT)) {
arguments_.remove(0);
outputJson_ = true;
}
else {
topic = arguments_.remove(0); topic = arguments_.remove(0);
} }
}
if (!arguments_.isEmpty() && arguments_.get(0).equals(JSON_ARGUMENT)) {
arguments_.remove(0);
outputJson_ = true;
}
System.err.println("Welcome to bld " + BldVersion.getVersion() + "."); if (!outputJson_) {
System.err.println(); executePrintWelcome();
}
boolean print_full_help = true; var print_full_help = true;
Exception exception = null;
try { try {
var commands = executor_.buildCommands(); var commands = executor_.buildCommands();
if (commands.containsKey(topic)) { if (commands.containsKey(topic)) {
var command = commands.get(topic); var command = commands.get(topic);
var help = command.getHelp().getDescription(topic); var help = command.getHelp().getDescription(topic);
if (!help.isEmpty()) { if (!help.isEmpty()) {
if (outputJson_) {
var t = TemplateFactory.JSON.get("bld.help_description");
t.setValueEncoded("command", topic);
t.setValueEncoded("description", help);
System.out.print(t.getContent());
}
else {
System.err.println(help); System.err.println(help);
}
print_full_help = false; print_full_help = false;
} }
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); exception = e;
} }
if (print_full_help) { if (print_full_help) {
executePrintOverviewHelp(); executePrintOverviewHelp(exception);
} }
} }
/** private void executePrintOverviewHelp(Exception exception) {
* Part of the {@link #execute} operation, prints the help overview if (outputJson_) {
* with summaries of all build commands. var t = TemplateFactory.JSON.get("bld.help_commands");
*
* @since 1.5 if (exception != null) {
*/ t.setValueEncoded("error-message", ExceptionUtils.getExceptionStackTrace(exception));
public void executePrintOverviewHelp() { }
var commands = executor_.buildCommands(); var commands = executor_.buildCommands();
for (var command : commands.entrySet()) {
if (t.isValueSet("commands")) {
t.setValue("separator", ", ");
}
else {
t.blankValue("separator");
}
t.setValueEncoded("command", command.getKey());
var build_help = command.getValue().getHelp();
t.setValueEncoded("summary", build_help.getSummary());
t.appendBlock("commands", "command");
}
System.out.print(t.getContent());
}
else {
if (exception != null) {
exception.printStackTrace();
}
System.err.println(""" System.err.println("""
The bld CLI provides its features through a series of commands that The bld CLI provides its features through a series of commands that
perform specific tasks. The help command provides more information about perform specific tasks. The help command provides more information about
the other commands. the other commands.
Usage : help [command] Usage: help [command] [""" + JSON_ARGUMENT + "]");
The following commands are supported. executePrintCommands();
executePrintHelpArguments();
executePrintBldArguments();
}
}
/**
* Part of the {@link #execute} operation, prints the welcome message.
*
* @since 2.0
*/
public void executePrintWelcome() {
System.err.println("Welcome to bld " + BldVersion.getVersion() + ".");
System.err.println();
}
/**
* Part of the {@link #execute} operation, prints the summaries of all supported build commands.
*
* @since 2.0
*/
public void executePrintCommands() {
System.err.println("""
The following commands are supported:
"""); """);
var commands = executor_.buildCommands();
var command_length = commands.keySet().stream().max(comparingInt(String::length)).get().length() + 2; var command_length = commands.keySet().stream().max(comparingInt(String::length)).get().length() + 2;
for (var command : commands.entrySet()) { for (var command : commands.entrySet()) {
System.err.print(" "); System.err.print(" ");
@ -94,12 +164,35 @@ public class HelpOperation {
System.err.print(build_help.getSummary()); System.err.print(build_help.getSummary());
System.err.println(); System.err.println();
} }
}
/**
* Part of the {@link #execute} operation, prints the supported help arguments.
*
* @since 2.0
*/
public void executePrintHelpArguments() {
System.err.println(""" System.err.println("""
-?, -h, --help Shows this help message The following help arguments are supported:
-D<name>=<value> Set a JVM system property
-s, --stacktrace Print out the stacktrace for exceptions --json Outputs help in JSON format""");
}
/**
* Part of the {@link #execute} operation, prints the supported bld arguments.
*
* @since 2.0
*/
public void executePrintBldArguments() {
System.err.println("""
The following bld arguments are supported:
--offline Works without Internet (only as first argument)
-?, -h, --help Shows the help
-D<name>=<value> Sets a JVM system property
-s, --stacktrace Prints out the stacktrace for exceptions
"""); """);
} }
} }

View file

@ -5,6 +5,11 @@
package rife.bld.operations; package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.tools.FileUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/** /**
* Tests a Java application with JUnit. * Tests a Java application with JUnit.
@ -24,6 +29,39 @@ public class JUnitOperation extends TestOperation<JUnitOperation, JUnitOptions>
return new JUnitOptions(); return new JUnitOptions();
} }
@Override
protected List<String> executeConstructProcessCommandList() {
if (mainClass() == null) {
throw new IllegalArgumentException("ERROR: Missing main class for test execution.");
}
var args = new ArrayList<String>();
args.add(javaTool());
args.addAll(javaOptions());
args.add("-cp");
var classpath = FileUtils.joinPaths(classpath());
args.add(classpath);
args.add(mainClass());
// the JUnit console launcher syntax changed in v1.10.x,
// this logic defaults to the new syntax but if it finds an older
// JUnit jar in the classpath, uses the old syntax
var junit_version_1_10_and_later = true;
var junit_version_pattern = Pattern.compile("junit-platform-console-standalone-(\\d+)\\.(\\d+)\\.");
var junit_version_matcher = junit_version_pattern.matcher(classpath);
if (junit_version_matcher.find() &&
(Integer.parseInt(junit_version_matcher.group(1)) < 1 ||
(Integer.parseInt(junit_version_matcher.group(1)) == 1 &&
Integer.parseInt(junit_version_matcher.group(2)) < 10))) {
junit_version_1_10_and_later = false;
}
if (junit_version_1_10_and_later) {
args.add("execute");
}
args.addAll(testToolOptions());
return args;
}
@Override @Override
public JUnitOperation fromProject(BaseProject project) { public JUnitOperation fromProject(BaseProject project) {
super.fromProject(project); super.fromProject(project);
@ -34,7 +72,7 @@ public class JUnitOperation extends TestOperation<JUnitOperation, JUnitOptions>
} }
// add the default JUnit options if none were specified // add the default JUnit options if none were specified
if (testToolOptions().isEmpty() && mainClass().equals(DEFAULT_TEST_TOOL_JUNIT5)) { if (testToolOptions().isEmpty() && DEFAULT_TEST_TOOL_JUNIT5.equals(mainClass())) {
testToolOptions().defaultOptions(); testToolOptions().defaultOptions();
} }
@ -45,9 +83,9 @@ public class JUnitOperation extends TestOperation<JUnitOperation, JUnitOptions>
var argument = arguments.get(0); var argument = arguments.get(0);
if (argument.startsWith("-")) { if (argument.startsWith("-")) {
arguments.remove(0); arguments.remove(0);
if (argument.equals("--junit-help")) { if ("--junit-help".equals(argument)) {
testToolOptions().add("--help"); testToolOptions().add("--help");
} else if (argument.equals("--junit-clear")) { } else if ("--junit-clear".equals(argument)) {
testToolOptions().clear(); testToolOptions().clear();
} else { } else {
testToolOptions().add(argument); testToolOptions().add(argument);

View file

@ -6,7 +6,6 @@ package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.NamedFile; import rife.bld.NamedFile;
import rife.bld.Project;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import rife.tools.StringUtils; import rife.tools.StringUtils;
@ -95,6 +94,7 @@ public class JarOperation extends AbstractOperation<JarOperation> {
// don't use putAll since Attributes does an instanceof check // don't use putAll since Attributes does an instanceof check
// on the map being passed in, causing it to fail if it's not // on the map being passed in, causing it to fail if it's not
// and instance of Attributes // and instance of Attributes
//noinspection UseBulkOperation
attributes.put(entry.getKey(), entry.getValue()); attributes.put(entry.getKey(), entry.getValue());
// ^^^ READ above, don't use putAll // ^^^ READ above, don't use putAll
} }

View file

@ -4,11 +4,12 @@
*/ */
package rife.bld.operations; package rife.bld.operations;
import rife.tools.FileUtils;
import rife.tools.StringUtils; import rife.tools.StringUtils;
import java.io.File; import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@ -39,8 +40,8 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options * @return this list of options
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions modulePath(File... modules) { public JavaOptions modulePath(File... paths) {
return modulePath(Arrays.asList(modules)); return modulePath(List.of(paths));
} }
/** /**
@ -49,9 +50,49 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options * @return this list of options
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions modulePath(List<File> modules) { public JavaOptions modulePath(List<File> paths) {
return modulePathStrings(paths.stream().map(File::getAbsolutePath).toList());
}
/**
* A list of directories, each directory is a directory of modules.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions modulePath(Path... paths) {
return modulePathPaths(List.of(paths));
}
/**
* A list of directories, each directory is a directory of modules.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions modulePathPaths(List<Path> paths) {
return modulePath(paths.stream().map(Path::toFile).toList());
}
/**
* A list of directories, each directory is a directory of modules.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions modulePath(String... paths) {
return modulePathStrings(List.of(paths));
}
/**
* A list of directories, each directory is a directory of modules.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions modulePathStrings(List<String> paths) {
add("--module-path"); add("--module-path");
add(StringUtils.join(modules, ":")); add(FileUtils.joinPaths(paths));
return this; return this;
} }
@ -62,8 +103,8 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options * @return this list of options
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions upgradeModulePath(File... modulePath) { public JavaOptions upgradeModulePath(File... paths) {
return upgradeModulePath(Arrays.asList(modulePath)); return upgradeModulePath(List.of(paths));
} }
/** /**
@ -73,9 +114,53 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options * @return this list of options
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions upgradeModulePath(List<File> modulePath) { public JavaOptions upgradeModulePath(List<File> paths) {
return upgradeModulePathStrings(paths.stream().map(File::getAbsolutePath).toList());
}
/**
* List of directories, each directory is a directory of modules
* that replace upgradeable modules in the runtime image
*
* @return this list of options
* @since 2.1
*/
public JavaOptions upgradeModulePath(Path... paths) {
return upgradeModulePathPaths(List.of(paths));
}
/**
* List of directories, each directory is a directory of modules
* that replace upgradeable modules in the runtime image
*
* @return this list of options
* @since 2.1
*/
public JavaOptions upgradeModulePathPaths(List<Path> paths) {
return upgradeModulePath(paths.stream().map(Path::toFile).toList());
}
/**
* List of directories, each directory is a directory of modules
* that replace upgradeable modules in the runtime image
*
* @return this list of options
* @since 2.1
*/
public JavaOptions upgradeModulePath(String... paths) {
return upgradeModulePathStrings(List.of(paths));
}
/**
* List of directories, each directory is a directory of modules
* that replace upgradeable modules in the runtime image
*
* @return this list of options
* @since 2.1
*/
public JavaOptions upgradeModulePathStrings(List<String> paths) {
add("--upgrade-module-path"); add("--upgrade-module-path");
add(StringUtils.join(modulePath, ":")); add(FileUtils.joinPaths(paths));
return this; return this;
} }
@ -88,7 +173,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions addModules(String... modules) { public JavaOptions addModules(String... modules) {
return addModules(Arrays.asList(modules)); return addModules(List.of(modules));
} }
/** /**
@ -112,8 +197,8 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options * @return this list of options
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions enableNativeAccess(List... modules) { public JavaOptions enableNativeAccess(String... modules) {
return enableNativeAccess(Arrays.asList(modules)); return enableNativeAccess(List.of(modules));
} }
/** /**
@ -215,7 +300,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions agentLib(String libName) { public JavaOptions agentLib(String libName) {
return agentLib(libName, null); return agentLib(libName, (String)null);
} }
/** /**
@ -225,7 +310,28 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions agentLib(String libName, String options) { public JavaOptions agentLib(String libName, String options) {
add("-agentlib:" + libName + (options == null ? "" : ":" + options)); add("-agentlib:" + libName + (options == null ? "" : "=" + options));
return this;
}
/**
* Load native agent library.
*
* @return this list of options
* @since 1.7.1
*/
public JavaOptions agentLib(String libName, String... options) {
return agentLib(libName, List.of(options));
}
/**
* Load native agent library.
*
* @return this list of options
* @since 1.7.1
*/
public JavaOptions agentLib(String libName, List<String> options) {
add("-agentlib:" + libName + (options == null || options.isEmpty() ? "" : "=" + StringUtils.join(options, ",")));
return this; return this;
} }
@ -236,7 +342,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions agentPath(File pathName) { public JavaOptions agentPath(File pathName) {
return agentPath(pathName, null); return agentPath(pathName.getAbsolutePath(), (String)null);
} }
/** /**
@ -246,7 +352,108 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions agentPath(File pathName, String options) { public JavaOptions agentPath(File pathName, String options) {
add("-agentpath:" + pathName + (options == null ? "" : ":" + options)); return agentPath(pathName.getAbsolutePath(), options);
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 1.7.1
*/
public JavaOptions agentPath(File pathName, String... options) {
return agentPath(pathName.getAbsolutePath(), List.of(options));
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 1.7.1
*/
public JavaOptions agentPath(File pathName, List<String> options) {
return agentPath(pathName.getAbsolutePath(), options);
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions agentPath(Path pathName) {
return agentPath(pathName.toFile(), (String)null);
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions agentPath(Path pathName, String options) {
return agentPath(pathName.toFile(), options);
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions agentPath(Path pathName, String... options) {
return agentPath(pathName.toFile(), List.of(options));
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions agentPath(Path pathName, List<String> options) {
return agentPath(pathName.toFile(), options);
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions agentPath(String pathName) {
return agentPath(pathName, (String)null);
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions agentPath(String pathName, String options) {
add("-agentpath:" + pathName + (options == null ? "" : "=" + options));
return this;
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions agentPath(String pathName, String... options) {
return agentPath(pathName, List.of(options));
}
/**
* Load native agent library by full pathname.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions agentPath(String pathName, List<String> options) {
add("-agentpath:" + pathName + (options == null || options.isEmpty() ? "" : "=" + StringUtils.join(options, ",")));
return this; return this;
} }
@ -257,7 +464,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions javaAgent(File jarPath) { public JavaOptions javaAgent(File jarPath) {
return javaAgent(jarPath, null); return javaAgent(jarPath.getAbsolutePath(), (String)null);
} }
/** /**
@ -267,7 +474,108 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18 * @since 1.5.18
*/ */
public JavaOptions javaAgent(File jarPath, String options) { public JavaOptions javaAgent(File jarPath, String options) {
add("-javaagent:" + jarPath + (options == null ? "" : ":" + options)); return javaAgent(jarPath.getAbsolutePath(), options);
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 1.7.1
*/
public JavaOptions javaAgent(File jarPath, String... options) {
return javaAgent(jarPath.getAbsolutePath(), List.of(options));
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 1.7.1
*/
public JavaOptions javaAgent(File jarPath, List<String> options) {
return javaAgent(jarPath.getAbsolutePath(), options);
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions javaAgent(Path jarPath) {
return javaAgent(jarPath.toFile(), (String)null);
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions javaAgent(Path jarPath, String options) {
return javaAgent(jarPath.toFile(), options);
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions javaAgent(Path jarPath, String... options) {
return javaAgent(jarPath.toFile(), List.of(options));
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions javaAgent(Path jarPath, List<String> options) {
return javaAgent(jarPath.toFile(), options);
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions javaAgent(String jarPath) {
return javaAgent(jarPath, (String)null);
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions javaAgent(String jarPath, String options) {
add("-javaagent:" + jarPath + (options == null ? "" : "=" + options));
return this;
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions javaAgent(String jarPath, String... options) {
return javaAgent(jarPath, List.of(options));
}
/**
* Load Java programming language agent.
*
* @return this list of options
* @since 2.1
*/
public JavaOptions javaAgent(String jarPath, List<String> options) {
add("-javaagent:" + jarPath + (options == null || options.isEmpty() ? "" : "=" + StringUtils.join(options, ",")));
return this; return this;
} }

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,6 @@
package rife.bld.operations; package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.Project;
import rife.bld.operations.exceptions.ExitStatusException; import rife.bld.operations.exceptions.ExitStatusException;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import rife.tools.StringUtils; import rife.tools.StringUtils;
@ -27,6 +26,7 @@ import java.util.regex.Pattern;
public class JavadocOperation extends AbstractOperation<JavadocOperation> { public class JavadocOperation extends AbstractOperation<JavadocOperation> {
private File buildDirectory_; private File buildDirectory_;
private final List<String> classpath_ = new ArrayList<>(); private final List<String> classpath_ = new ArrayList<>();
private final List<String> modulePath_ = new ArrayList<>();
private final List<File> sourceFiles_ = new ArrayList<>(); private final List<File> sourceFiles_ = new ArrayList<>();
private final List<File> sourceDirectories_ = new ArrayList<>(); private final List<File> sourceDirectories_ = new ArrayList<>();
private final JavadocOptions javadocOptions_ = new JavadocOptions(); private final JavadocOptions javadocOptions_ = new JavadocOptions();
@ -75,6 +75,7 @@ public class JavadocOperation extends AbstractOperation<JavadocOperation> {
} }
executeBuildSources( executeBuildSources(
classpath(), classpath(),
modulePath(),
sources, sources,
buildDirectory()); buildDirectory());
} }
@ -82,12 +83,13 @@ public class JavadocOperation extends AbstractOperation<JavadocOperation> {
/** /**
* Part of the {@link #execute} operation, build sources to a destination. * Part of the {@link #execute} operation, build sources to a destination.
* *
* @param classpath the classpath list used for the compilation * @param classpath the classpath list used for the javadoc generation
* @param modulePath the module path list used for the javadoc generation
* @param sources the source files to compile * @param sources the source files to compile
* @param destination the destination directory * @param destination the destination directory
* @since 1.5.10 * @since 2.1
*/ */
protected void executeBuildSources(List<String> classpath, List<File> sources, File destination) protected void executeBuildSources(List<String> classpath, List<String> modulePath, List<File> sources, File destination)
throws IOException { throws IOException {
if (sources.isEmpty() || destination == null) { if (sources.isEmpty() || destination == null) {
return; return;
@ -104,7 +106,13 @@ public class JavadocOperation extends AbstractOperation<JavadocOperation> {
try (var file_manager = documentation.getStandardFileManager(null, null, null)) { try (var file_manager = documentation.getStandardFileManager(null, null, null)) {
var compilation_units = file_manager.getJavaFileObjectsFromFiles(filtered_sources); var compilation_units = file_manager.getJavaFileObjectsFromFiles(filtered_sources);
var diagnostics = new DiagnosticCollector<JavaFileObject>(); var diagnostics = new DiagnosticCollector<JavaFileObject>();
var options = new ArrayList<>(List.of("-d", destination.getAbsolutePath(), "-cp", FileUtils.joinPaths(classpath))); var options = new ArrayList<>(List.of("-d", destination.getAbsolutePath()));
if (!classpath.isEmpty()) {
options.addAll(List.of("-cp", FileUtils.joinPaths(classpath)));
}
if (!modulePath.isEmpty()) {
options.addAll(List.of("-p", FileUtils.joinPaths(modulePath)));
}
options.addAll(javadocOptions()); options.addAll(javadocOptions());
var documentation_task = documentation.getTask(null, file_manager, diagnostics, null, options, compilation_units); var documentation_task = documentation.getTask(null, file_manager, diagnostics, null, options, compilation_units);
if (!documentation_task.call()) { if (!documentation_task.call()) {
@ -147,6 +155,7 @@ public class JavadocOperation extends AbstractOperation<JavadocOperation> {
var operation = buildDirectory(project.buildJavadocDirectory()) var operation = buildDirectory(project.buildJavadocDirectory())
.classpath(project.compileMainClasspath()) .classpath(project.compileMainClasspath())
.classpath(project.buildMainDirectory().getAbsolutePath()) .classpath(project.buildMainDirectory().getAbsolutePath())
.modulePath(project.compileMainModulePath())
.sourceFiles(project.mainSourceFiles()); .sourceFiles(project.mainSourceFiles());
if (project.javaRelease() != null && !javadocOptions().containsRelease()) { if (project.javaRelease() != null && !javadocOptions().containsRelease()) {
javadocOptions().release(project.javaRelease()); javadocOptions().release(project.javaRelease());
@ -192,6 +201,32 @@ public class JavadocOperation extends AbstractOperation<JavadocOperation> {
return this; return this;
} }
/**
* Provides entries for the javadoc module path.
*
* @param modulePath module path entries
* @return this operation instance
* @since 2.1
*/
public JavadocOperation modulePath(String... modulePath) {
modulePath_.addAll(Arrays.asList(modulePath));
return this;
}
/**
* Provides a list of entries for the javadoc moduel path.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param modulePath a list of module path entries
* @return this operation instance
* @since 2.1
*/
public JavadocOperation modulePath(List<String> modulePath) {
modulePath_.addAll(modulePath);
return this;
}
/** /**
* Provides files for which documentation should be generated. * Provides files for which documentation should be generated.
* *
@ -362,6 +397,18 @@ public class JavadocOperation extends AbstractOperation<JavadocOperation> {
return classpath_; return classpath_;
} }
/**
* Retrieves the list of entries for the javadoc module path.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the javadoc module path list
* @since 2.1
*/
public List<String> modulePath() {
return modulePath_;
}
/** /**
* Retrieves the list of files for which documentation should be generation. * Retrieves the list of files for which documentation should be generation.
* <p> * <p>

View file

@ -9,10 +9,10 @@ import rife.tools.FileUtils;
import rife.tools.StringUtils; import rife.tools.StringUtils;
import java.io.File; import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* Options for the standard javadoc tool. * Options for the standard javadoc tool.
@ -100,7 +100,7 @@ public class JavadocOptions extends ArrayList<String> {
*/ */
public JavadocOptions doclet(String className) { public JavadocOptions doclet(String className) {
add("-doclet"); add("-doclet");
add("className"); add(className);
return this; return this;
} }
@ -112,7 +112,7 @@ public class JavadocOptions extends ArrayList<String> {
*/ */
public JavadocOptions docletPath(String path) { public JavadocOptions docletPath(String path) {
add("-docletpath"); add("-docletpath");
add("path"); add(path);
return this; return this;
} }
@ -135,7 +135,7 @@ public class JavadocOptions extends ArrayList<String> {
*/ */
public JavadocOptions encoding(String name) { public JavadocOptions encoding(String name) {
add("-encoding"); add("-encoding");
add("name"); add(name);
return this; return this;
} }
@ -178,8 +178,48 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.5.18 * @since 1.5.18
*/ */
public JavadocOptions extDirs(List<File> dirs) { public JavadocOptions extDirs(List<File> dirs) {
return extDirsStrings(dirs.stream().map(File::getAbsolutePath).toList());
}
/**
* Override location of installed extensions
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions extDirs(Path... dirs) {
return extDirsPaths(Arrays.asList(dirs));
}
/**
* Override location of installed extensions
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions extDirsPaths(List<Path> dirs) {
return extDirs(dirs.stream().map(Path::toFile).toList());
}
/**
* Override location of installed extensions
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions extDirs(String... dirs) {
return extDirsStrings(Arrays.asList(dirs));
}
/**
* Override location of installed extensions
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions extDirsStrings(List<String> dirs) {
add("-extdirs"); add("-extdirs");
add(dirs.stream().map(File::getAbsolutePath).collect(Collectors.joining(","))); add(String.join(",", dirs));
return this; return this;
} }
@ -213,7 +253,7 @@ public class JavadocOptions extends ArrayList<String> {
*/ */
public JavadocOptions locale(String name) { public JavadocOptions locale(String name) {
add("-locale"); add("-locale");
add("name"); add(name);
return this; return this;
} }
@ -256,8 +296,48 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.6.3 * @since 1.6.3
*/ */
public JavadocOptions modulePath(List<File> paths) { public JavadocOptions modulePath(List<File> paths) {
return modulePathStrings(paths.stream().map(File::getAbsolutePath).toList());
}
/**
* Specify where to find application modules
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions modulePath(Path... paths) {
return modulePathPaths(Arrays.asList(paths));
}
/**
* Specify where to find application modules
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions modulePathPaths(List<Path> paths) {
return modulePath(paths.stream().map(Path::toFile).toList());
}
/**
* Specify where to find application modules
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions modulePath(String... paths) {
return modulePathStrings(Arrays.asList(paths));
}
/**
* Specify where to find application modules
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions modulePathStrings(List<String> paths) {
add("--module-path"); add("--module-path");
add(FileUtils.joinPaths(paths.stream().map(File::getAbsolutePath).toList())); add(FileUtils.joinPaths(paths));
return this; return this;
} }
@ -268,8 +348,28 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.6.3 * @since 1.6.3
*/ */
public JavadocOptions moduleSourcePath(File path) { public JavadocOptions moduleSourcePath(File path) {
return moduleSourcePath(path.getAbsolutePath());
}
/**
* Specify where to find input source files for multiple modules
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions moduleSourcePath(Path path) {
return moduleSourcePath(path.toFile());
}
/**
* Specify where to find input source files for multiple modules
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions moduleSourcePath(String path) {
add("--module-source-path"); add("--module-source-path");
add(path.getAbsolutePath()); add(path);
return this; return this;
} }
@ -425,9 +525,29 @@ public class JavadocOptions extends ArrayList<String> {
* @return this list of options * @return this list of options
* @since 1.5.12 * @since 1.5.12
*/ */
public JavadocOptions addScript(File file) { public JavadocOptions addScript(File path) {
return addScript(path.getAbsolutePath());
}
/**
* Add a script file to the generated documentation
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions addScript(Path path) {
return addScript(path.toFile());
}
/**
* Add a script file to the generated documentation
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions addScript(String path) {
add("--add-script"); add("--add-script");
add(file.getAbsolutePath()); add(path);
return this; return this;
} }
@ -437,9 +557,29 @@ public class JavadocOptions extends ArrayList<String> {
* @return this list of options * @return this list of options
* @since 1.5.12 * @since 1.5.12
*/ */
public JavadocOptions addStylesheet(File file) { public JavadocOptions addStylesheet(File path) {
return addStylesheet(path.getAbsolutePath());
}
/**
* Add a stylesheet file to the generated documentation
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions addStylesheet(Path path) {
return addStylesheet(path.toFile());
}
/**
* Add a stylesheet file to the generated documentation
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions addStylesheet(String path) {
add("--add-stylesheet"); add("--add-stylesheet");
add(file.getAbsolutePath()); add(path);
return this; return this;
} }
@ -578,9 +718,29 @@ public class JavadocOptions extends ArrayList<String> {
* @return this list of options * @return this list of options
* @since 1.5.12 * @since 1.5.12
*/ */
public JavadocOptions stylesheet(File file) { public JavadocOptions stylesheet(File path) {
return stylesheet(path.getAbsolutePath());
}
/**
* File to change style of the generated documentation
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions stylesheet(Path path) {
return stylesheet(path.toFile());
}
/**
* File to change style of the generated documentation
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions stylesheet(String path) {
add("--main-stylesheet"); add("--main-stylesheet");
add(file.getAbsolutePath()); add(path);
return this; return this;
} }
@ -735,9 +895,29 @@ public class JavadocOptions extends ArrayList<String> {
* @return this list of options * @return this list of options
* @since 1.5.18 * @since 1.5.18
*/ */
public JavadocOptions overview(File htmlFile) { public JavadocOptions overview(File path) {
return overview(path.getAbsolutePath());
}
/**
* Read overview documentation from HTML file
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions overview(Path path) {
return overview(path.toFile());
}
/**
* Read overview documentation from HTML file
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions overview(String path) {
add("-overview"); add("-overview");
add(htmlFile.getAbsolutePath()); add(path);
return this; return this;
} }
@ -793,8 +973,28 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.5.12 * @since 1.5.12
*/ */
public JavadocOptions snippetPath(File path) { public JavadocOptions snippetPath(File path) {
return snippetPath(path.getAbsolutePath());
}
/**
* The path for external snippets
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions snippetPath(Path path) {
return snippetPath(path.toFile());
}
/**
* The path for external snippets
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions snippetPath(String path) {
add("--snippet-path"); add("--snippet-path");
add(path.getAbsolutePath()); add(path);
return this; return this;
} }
@ -852,8 +1052,28 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.5.12 * @since 1.5.12
*/ */
public JavadocOptions tagletPath(File path) { public JavadocOptions tagletPath(File path) {
return tagletPath(path.getAbsolutePath());
}
/**
* The path to Taglets
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions tagletPath(Path path) {
return tagletPath(path.toFile());
}
/**
* The path to Taglets
*
* @return this list of options
* @since 2.1
*/
public JavadocOptions tagletPath(String path) {
add("-tagletpath"); add("-tagletpath");
add(path.getAbsolutePath()); add(path);
return this; return this;
} }

View file

@ -0,0 +1,77 @@
/*
* Copyright 2024 Erik C. Thauvin (https://erik.thauvin.net/)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Create run-time images using the jlink tool.
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 2.1.0
*/
public class JlinkOperation extends AbstractToolProviderOperation<JlinkOperation> {
private final List<String> disabledPlugins_ = new ArrayList<>();
private final JlinkOptions jlinkOptions_ = new JlinkOptions();
public JlinkOperation() {
super("jlink");
}
/**
* Disable the plugin(s) mentioned.
*
* @param plugins the plugin name(s)
* @return this map of options
*/
public JlinkOperation disablePlugin(List<String> plugins) {
disabledPlugins_.addAll(plugins);
return this;
}
/**
* Disable the plugin(s) mentioned.
*
* @param plugins the plugin name(s)
* @return this map of options
*/
public JlinkOperation disablePlugin(String... plugins) {
return disablePlugin(List.of(plugins));
}
@Override
public void execute() throws Exception {
toolArgsFromFiles();
disabledPlugins_.forEach(plugin -> toolArgs("--disable-plugin", plugin));
toolArgs(jlinkOptions_);
super.execute();
}
/**
* Provides a list of options to provide to the jlink tool.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param options the argument-value pairs
* @return this operation instance
*/
public JlinkOperation jlinkOptions(Map<String, String> options) {
jlinkOptions_.putAll(options);
return this;
}
/**
* Retrieves the list of options for the jlink tool.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the map of jlink options
*/
public JlinkOptions jlinkOptions() {
return jlinkOptions_;
}
}

View file

@ -0,0 +1,408 @@
/*
* Copyright 2024 Erik C. Thauvin (https://erik.thauvin.net/)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Options for jlink tool.
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 2.1.0
*/
public class JlinkOptions extends LinkedHashMap<String, String> {
/**
* All Modules Path.
*/
@SuppressWarnings("unused")
public final static String ALL_MODULE_PATH = "ALL-MODULE-PATH";
/**
* Root modules to resolve in addition to the initial modules.
* <p>
* Module can also be {@link #ALL_MODULE_PATH}
*
* @param modules one or more modules
* @return this map of options
*/
public JlinkOptions addModules(List<String> modules) {
put("--add-modules", String.join(",", modules));
return this;
}
/**
* Root modules to resolve in addition to the initial modules.
* <p>
* Module can also be {@link #ALL_MODULE_PATH}
*
* @param modules one or more modules
* @return this map of options
*/
public JlinkOptions addModules(String... modules) {
return addModules(List.of(modules));
}
/**
* Link in service provider modules and their dependencies.
*
* @param bindServices {@code true} to bind services, {@code false} otherwise
* @return this map of options
*/
public JlinkOptions bindServices(boolean bindServices) {
if (bindServices) {
put("--bind-services");
} else {
remove("--bind-services");
}
return this;
}
/**
* Compression to use in compressing resources.
* <p>
* <b>Requires Java 21 or higher</b>. Use {@link #compress(CompressionLevel)} for lower versions.
* <p>
* Where {@link ZipCompression#ZIP_0 ZIP_0} provides no compression and {@link ZipCompression#ZIP_9 ZIP_9} provides
* the best compression.
* <p>Default is {@link ZipCompression#ZIP_6 ZIP_6}
*
* @param compression the {@link ZipCompression compression} level
* @return this map of options
* @see #compress(ZipCompression)
*/
public JlinkOptions compress(ZipCompression compression) {
put("--compress", compression.level);
return this;
}
/**
* Enable compression of resources.
* <p>
* Use {@link #compress(ZipCompression)} on Java 21 or higher.
*
* @param compression the {@link CompressionLevel compression} level
* @return this map of options
* @see #compress(CompressionLevel)
*/
public JlinkOptions compress(CompressionLevel compression) {
put("--compress", compression.level);
return this;
}
/**
* Byte order of generated jimage.
* <p>
* Default: native
*
* @param endian the byte order
* @return this map of options
*/
public JlinkOptions endian(Endian endian) {
put("--endian", endian.byteOrder);
return this;
}
/**
* Suppress a fatal error when signed modular JARs are linked in the image.
*
* @param ignoreSigningInformation {@code true} to ignore signing information, {@code false} otherwise
* @return this map of options
*/
public JlinkOptions ignoreSigningInformation(boolean ignoreSigningInformation) {
if (ignoreSigningInformation) {
put("--ignore-signing-information");
} else {
remove("--ignore-signing-information");
}
return this;
}
/**
* Add a launcher command of the given name for the module.
*
* @param name the name
* @param module the module
* @return this map of options
*/
@SuppressWarnings("UnusedReturnValue")
public JlinkOptions launcher(String name, String module) {
put("--launcher", name + "=" + module);
return this;
}
/**
* Add a launcher command of the given name for the module and the main class.
*
* @param name the name
* @param module the module
* @param mainClass the main class
* @return this map of options
*/
public JlinkOptions launcher(String name, String module, String mainClass) {
put("--launcher", name + "=" + module + "/" + mainClass);
return this;
}
/**
* Limit the universe of observable modules.
*
* @param modules one or more modules
* @return this map of options
*/
public JlinkOptions limitModule(List<String> modules) {
put("--limit-modules", String.join(",", modules));
return this;
}
/**
* Limit the universe of observable modules.
*
* @param modules one or more modules
* @return this map of options
*/
public JlinkOptions limitModule(String... modules) {
return limitModule(List.of(modules));
}
/**
* Module path.
* <p>
* If not specified, the JDKs jmods directory will be used, if it exists. If specified, but it does not contain the
* {@code java.base} module, the JDKs jmods directory will be added, if it exists.
*
* @param path the module path
* @return this map of options
*/
public JlinkOptions modulePath(String path) {
put("--module-path", path);
return this;
}
/**
* Module path.
* <p>
* If not specified, the JDKs jmods directory will be used, if it exists. If specified, but it does not contain the
* {@code java.base} module, the JDKs jmods directory will be added, if it exists.
*
* @param path the module path
* @return this map of options
*/
public JlinkOptions modulePath(File path) {
return modulePath(path.getAbsolutePath());
}
/**
* Module path.
* <p>
* If not specified, the JDKs jmods directory will be used, if it exists. If specified, but it does not contain the
* {@code java.base} module, the JDKs jmods directory will be added, if it exists.
*
* @param path the module path
* @return this map of options
*/
public JlinkOptions modulePath(Path path) {
return modulePath(path.toFile().getAbsolutePath());
}
/**
* Exclude include header files.
*
* @param noHeaderFiles {@code true} to exclude header files, {@code false} otherwise
* @return this map of options
*/
public JlinkOptions noHeaderFiles(boolean noHeaderFiles) {
if (noHeaderFiles) {
put("--no-header-files");
} else {
remove("--no-header-files");
}
return this;
}
/**
* Exclude man pages.
*
* @param noManPages {@code true} to exclude man pages, {@code false} otherwise
* @return this map of options
*/
public JlinkOptions noManPages(boolean noManPages) {
if (noManPages) {
put("--no-man-pages");
} else {
remove("--no-man-pages");
}
return this;
}
/**
* Location of output path.
*
* @param path the output path
* @return this map of options
*/
public JlinkOptions output(String path) {
put("--output", path);
return this;
}
/**
* Location of output path.
*
* @param path the output path
* @return this map of options
*/
public JlinkOptions output(File path) {
return output(path.getAbsolutePath());
}
/**
* Location of output path.
*
* @param path the output path
* @return this map of options
*/
public JlinkOptions output(Path path) {
return output(path.toFile().getAbsolutePath());
}
/**
* Associates {@code null} with the specified key in this map. If the map previously contained a mapping for the
* key, the old value is replaced.
*
* @param key key with which the specified value is to be associated
*/
public void put(String key) {
put(key, null);
}
/**
* Suggest providers that implement the given service types from the module path.
*
* @param filename the filename
* @return this map of options
*/
public JlinkOptions saveOpts(String filename) {
put("--save-opts", filename);
return this;
}
/**
* Strip debug information.
*
* @param stripDebug {@code true} to strip debug info, {@code false} otherwise
* @return this map of options
*/
public JlinkOptions stripDebug(boolean stripDebug) {
if (stripDebug) {
put("--strip-debug");
} else {
remove("--strip-debug");
}
return this;
}
/**
* Strip native commands.
*
* @param stripNativeCommands {@code true} to strip, {@code false} otherwise
* @return this map of options
*/
public JlinkOptions stripNativeCommands(boolean stripNativeCommands) {
if (stripNativeCommands) {
put("--strip-native-commands");
} else {
remove("--strip-native-commands");
}
return this;
}
/**
* Suggest providers that implement the given service types from the module path.
*
* @param names one or more provider names
* @return this map of options
*/
public JlinkOptions suggestProviders(List<String> names) {
put("--suggest-providers", String.join(",", names));
return this;
}
/**
* Suggest providers that implement the given service types from the module path.
*
* @param names one or more provider names
* @return this map of options
*/
public JlinkOptions suggestProviders(String... names) {
return suggestProviders(List.of(names));
}
public List<String> toList() {
var list = new ArrayList<String>();
forEach((k, v) -> {
list.add(k);
if (v != null && !v.isEmpty()) {
list.add(v);
}
});
return list;
}
/**
* Enable verbose tracing.
*
* @param verbose {@code true} to enable verbose tracing, {@code false} otherwise.
* @return this map of options
*/
public JlinkOptions verbose(boolean verbose) {
if (verbose) {
put("--verbose");
} else {
remove("--verbose");
}
return this;
}
/**
* The byte orders.
*/
public enum Endian {
BIG("big"), LITTLE("little");
public final String byteOrder;
Endian(String byteOrder) {
this.byteOrder = byteOrder;
}
}
/**
* Resources compression levels.
*/
public enum CompressionLevel {
/**
* Level 0: No compression
*/
NO_COMPRESSION("0"),
/**
* Level 1: Constant string sharing
*/
CONSTANT_STRING_SHARING("1"),
/**
* Level 2: ZIP
*/
ZIP("2");
public final String level;
CompressionLevel(String level) {
this.level = level;
}
}
}

View file

@ -0,0 +1,156 @@
/*
* Copyright 2024 Erik C. Thauvin (https://erik.thauvin.net/)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import java.io.File;
import java.nio.file.Path;
import java.util.Map;
/**
* Create JMOD files with the jmod tool.
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 2.1.0
*/
public class JmodOperation extends AbstractToolProviderOperation<JmodOperation> {
private final JmodOptions jmodOptions_ = new JmodOptions();
private String jmodFile_;
private OperationMode operationMode_;
public JmodOperation() {
super("jmod");
}
@Override
public void execute() throws Exception {
if (operationMode_ != null) {
toolArgs(operationMode_.mode);
}
toolArgsFromFiles();
toolArgs(jmodOptions_);
if (jmodFile_ != null) {
toolArgs(jmodFile_);
}
super.execute();
}
/**
* Retrieves the name of the JMOD file to create or from which to retrieve information.
*
* @return the JMOD file
*/
public String jmodFile() {
return jmodFile_;
}
/**
* Specifies name of the JMOD file to create or from which to retrieve information.
* <p>
* The JMOD file is <b>required</b>.
*
* @param file the JMOD file
* @return this operation instance
*/
public JmodOperation jmodFile(String file) {
jmodFile_ = file;
return this;
}
/**
* Specifies name of the JMOD file to create or from which to retrieve information.
* <p>
* The JMOD file is <b>required</b>.
*
* @param file the JMOD file
* @return this operation instance
*/
public JmodOperation jmodFile(File file) {
return jmodFile(file.getAbsolutePath());
}
/**
* Specifies name of the JMOD file to create or from which to retrieve information.
* <p>
* The JMOD file is <b>required</b>.
*
* @param file the JMOD file
* @return this operation instance
*/
public JmodOperation jmodFile(Path file) {
return jmodFile(file.toFile().getAbsolutePath());
}
/**
* Retrieves the list of options for the jmod tool.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the map of jmod options
*/
public JmodOptions jmodOptions() {
return jmodOptions_;
}
/**
* Provides a list of options to provide to the jmod tool.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param options the list of jmod options
* @return this operation instance
*/
public JmodOperation jmodOptions(Map<String, String> options) {
jmodOptions_.putAll(options);
return this;
}
/**
* Provides the {@link OperationMode operation mode}.
* <p>
* The operation mode is <b>required</b>.
*
* @param mode the mode
* @return this operation instance
*/
public JmodOperation operationMode(OperationMode mode) {
operationMode_ = mode;
return this;
}
/**
* The operation modes.
*/
public enum OperationMode {
/**
* Creates a new JMOD archive file.
*/
CREATE("create"),
/**
* Prints the module details.
*/
DESCRIBE("describe"),
/**
* Extracts all the files from the JMOD archive file.
*/
EXTRACT("extract"),
/**
* Determines leaf modules and records the hashes of the dependencies that directly and indirectly require them.
*/
HASH("hash"),
/**
* Prints the names of all the entries.
*/
LIST("list");
final String mode;
OperationMode(String mode) {
this.mode = mode;
}
}
}

View file

@ -0,0 +1,473 @@
/*
* Copyright 2024 Erik C. Thauvin (https://erik.thauvin.net/)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import java.io.File;
import java.nio.file.Path;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Options for jmod tool.
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 2.1.0
*/
public class JmodOptions extends LinkedHashMap<String, String> {
/**
* Application jar files|dir containing classes.
*
* @param classpath the classpath
* @return this map of options
*/
public JmodOptions classpath(String classpath) {
put("--class-path", classpath);
return this;
}
/**
* Location of native commands.
*
* @param path the location
* @return this map of options
*/
public JmodOptions cmds(String path) {
put("--cmds", path);
return this;
}
/**
* Location of native commands.
*
* @param path the location
* @return this map of options
*/
@SuppressWarnings("UnusedReturnValue")
public JmodOptions cmds(File path) {
return cmds(path.getAbsolutePath());
}
/**
* Location of native commands.
*
* @param path the location
* @return this map of options
*/
public JmodOptions cmds(Path path) {
return cmds(path.toFile().getAbsolutePath());
}
/**
* Compression to use when creating the JMOD archive.
* <p>
* <b>Requires Java 20 or higher</b>.
* <p>
* Where {@link ZipCompression#ZIP_0 ZIP_0} provides no compression and {@link ZipCompression#ZIP_9 ZIP_9} provides the
* best compression.
* <p>
* Default is {@link ZipCompression#ZIP_6 ZIP_6}
*
* @param compression the {@link ZipCompression compression} level
* @return this map of options
*/
@SuppressWarnings("UnusedReturnValue")
public JmodOptions compress(ZipCompression compression) {
put("--compress", compression.level);
return this;
}
/**
* Location of user-editable config files
*
* @param path the path to the config files
* @return this map of options
*/
public JmodOptions config(String path) {
put("--config", path);
return this;
}
/**
* Location of user-editable config files
*
* @param path the path to the config files
* @return this map of options
*/
public JmodOptions config(File path) {
return config(path.getAbsolutePath());
}
/**
* Location of user-editable config files
*
* @param path the path to the config files
* @return this map of options
*/
public JmodOptions config(Path path) {
return config(path.toFile().getAbsolutePath());
}
/**
* Date and time for the timestamps of entries.
*
* @param date the date
* @return this map of options
*/
public JmodOptions date(ZonedDateTime date) {
put("--date", date.truncatedTo(ChronoUnit.SECONDS).format(DateTimeFormatter.ISO_INSTANT));
return this;
}
/**
* Target directory for extract
*
* @param path the directory path
* @return this map of options
*/
public JmodOptions dir(String path) {
put("--dir", path);
return this;
}
/**
* Target directory for extract
*
* @param path the directory path
* @return this map of options
*/
public JmodOptions dir(File path) {
return dir(path.getAbsolutePath());
}
/**
* Target directory for extract
*
* @param path the directory path
* @return this map of options
*/
public JmodOptions dir(Path path) {
return dir(path.toFile().getAbsolutePath());
}
/**
* Exclude from the default root set of modules.
*
* @param doNotResolveByDefault {@code true} to not resolve, {@code false} otherwise
* @return this map of options
*/
public JmodOptions doNotResolveByDefault(boolean doNotResolveByDefault) {
if (doNotResolveByDefault) {
put("--do-not-resolve-by-default");
} else {
remove("--do-not-resolve-by-default");
}
return this;
}
/**
* Dry run of hash mode.
*
* @param dryRun {@code true} for dry run, {@code false} otherwise
* @return this list of operation
*/
public JmodOptions dryRun(boolean dryRun) {
if (dryRun) {
put("--dry-run");
} else {
remove("--dry-run");
}
return this;
}
/**
* Exclude files matching the supplied pattern list.
*
* @param patterns one or more patterns
* @return the map of options
*/
public JmodOptions exclude(List<FilePattern> patterns) {
var args = new ArrayList<String>();
for (var p : patterns) {
if (p.type == FilePatternType.GLOB) {
args.add("glob:" + p.pattern);
} else if (p.type == FilePatternType.REGEX) {
args.add("regex:" + p.pattern);
}
}
put("--exclude", String.join(",", args));
return this;
}
/**
* Exclude files matching the supplied pattern list.
*
* @param patterns one or more patterns
* @return the map of options
*/
public JmodOptions exclude(FilePattern... patterns) {
return exclude(List.of(patterns));
}
/**
* Compute and record hashes to tie a packaged module with modules matching the given regular expression pattern and
* depending upon it directly or indirectly. The hashes are recorded in the JMOD file being created, or a JMOD file
* or modular JAR on the module path specified the jmod hash command.
*
* @param regexPattern the regular expression pattern
* @return this map of options
*/
public JmodOptions hashModules(String regexPattern) {
put("--hash-modules", regexPattern);
return this;
}
/**
* Location of header files.
*
* @param path the location
* @return this map of options
*/
public JmodOptions headerFiles(String path) {
put("--header-files", path);
return this;
}
/**
* Location of header files.
*
* @param path the location
* @return this map of options
*/
@SuppressWarnings("UnusedReturnValue")
public JmodOptions headerFiles(File path) {
return headerFiles(path.getAbsolutePath());
}
/**
* Location of header files.
*
* @param path the location
* @return this map of options
*/
public JmodOptions headerFiles(Path path) {
return headerFiles(path.toFile().getAbsolutePath());
}
/**
* Location of legal notices.
*
* @param path the location
* @return this map of options
*/
public JmodOptions legalNotices(String path) {
put("--legal-notices", path);
return this;
}
/**
* Location of legal notices.
*
* @param path the location
* @return this map of options
*/
@SuppressWarnings("UnusedReturnValue")
public JmodOptions legalNotices(File path) {
return legalNotices(path.getAbsolutePath());
}
/**
* Location of legal notices.
*
* @param path the location
* @return this map of options
*/
public JmodOptions legalNotices(Path path) {
return legalNotices(path.toFile().getAbsolutePath());
}
/**
* Location of native libraries.
*
* @param path the location
* @return this map of options
*/
public JmodOptions libs(String path) {
put("--libs", path);
return this;
}
/**
* Location of native libraries.
*
* @param path the location
* @return this map of options
*/
@SuppressWarnings("UnusedReturnValue")
public JmodOptions libs(File path) {
return libs(path.getAbsolutePath());
}
/**
* Location of native libraries.
*
* @param path the location
* @return this map of options
*/
public JmodOptions libs(Path path) {
return libs(path.toFile().getAbsolutePath());
}
/**
* Main class.
*
* @param name the class name
* @return this list of operation
*/
public JmodOptions mainClass(String name) {
put("--main-class", name);
return this;
}
/**
* Location of man pages.
*
* @param path the location
* @return this map of options
*/
public JmodOptions manPages(String path) {
put("--man-pages", path);
return this;
}
/**
* Location of man pages.
*
* @param path the location
* @return this map of options
*/
@SuppressWarnings("UnusedReturnValue")
public JmodOptions manPages(File path) {
return manPages(path.getAbsolutePath());
}
/**
* Location of man pages.
*
* @param path the location
* @return this map of options
*/
public JmodOptions manPages(Path path) {
return manPages(path.toFile().getAbsolutePath());
}
/**
* Module path.
*
* @param path the module path
* @return this map of options
*/
public JmodOptions modulePath(String path) {
put("--module-path", path);
return this;
}
/**
* Module path.
*
* @param path the module path
* @return this map of options
*/
public JmodOptions modulePath(File path) {
return modulePath(path.getAbsolutePath());
}
/**
* Module path.
*
* @param path the module path
* @return this map of options
*/
public JmodOptions modulePath(Path path) {
return modulePath(path.toFile().getAbsolutePath());
}
/**
* Module version.
*
* @param version the module version.
* @return this map of options
*/
public JmodOptions moduleVersion(String version) {
put("--module-version", version);
return this;
}
/**
* Associates {@code null} with the specified key in this map. If the map previously contained a mapping for the
* key, the old value is replaced.
*
* @param key key with which the specified value is to be associated
*/
public void put(String key) {
put(key, null);
}
/**
* Target platform.
*
* @param platform the platform
* @return this list of operation
*/
public JmodOptions targetPlatform(String platform) {
put("--target-platform", platform);
return this;
}
/**
* Hint for a tool to issue a warning if the module is resolved.
*
* @param reason the reason
* @return this map of options
*/
public JmodOptions warnIfResolved(ResolvedReason reason) {
put("--warn-if-resolved", reason.reason);
return this;
}
/**
* The resolved reasons.
*/
public enum ResolvedReason {
DEPRECATED("deprecated"),
DEPRECATED_FOR_REMOVAL("deprecated-for-removal"),
INCUBATING("incubating");
final String reason;
ResolvedReason(String reason) {
this.reason = reason;
}
}
/**
* The file pattern types.
*/
public enum FilePatternType {
GLOB, REGEX
}
/**
* Defines a file pattern and pattern type.
*
* @param type the pattern type
* @param pattern the pattern
*/
public record FilePattern(FilePatternType type, String pattern) {
}
}

View file

@ -0,0 +1,124 @@
/*
* Copyright 2024 Erik C. Thauvin (https://erik.thauvin.net/)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Package self-contained Java applications with the jpackage tool.
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 2.1.0
*/
public class JpackageOperation extends AbstractToolProviderOperation<JpackageOperation> {
private final JpackageOptions jpackageOptions_ = new JpackageOptions();
private final List<Launcher> launchers_ = new ArrayList<>();
public JpackageOperation() {
super("jpackage");
}
/**
* List of application launchers.
* <p>
* The main application launcher will be built from the command line options.
* <p>
* Additional alternative launchers can be built using this option, and this option can be used to build multiple
* additional launchers.
*
* @param launchers one or more {@link Launcher launchers}
* @return this operation instance
*/
public JpackageOperation addLauncher(List<Launcher> launchers) {
launchers_.addAll(launchers);
return this;
}
/**
* List of application launchers.
* <p>
* The main application launcher will be built from the command line options.
* <p>
* Additional alternative launchers can be built using this option, and this option can be used to build multiple
* additional launchers.
*
* @param launchers one or more {@link Launcher launchers}
* @return this operation instance
*/
public JpackageOperation addLauncher(Launcher... launchers) {
return addLauncher(List.of(launchers));
}
@Override
public void execute() throws Exception {
toolArgs(cmdFiles().stream().map(opt -> '@' + opt).toList());
for (var l : launchers_) {
toolArgs("--add-launcher", l.name + '=' + l.path);
}
toolArgs(jpackageOptions_);
super.execute();
}
/**
* Retrieves the list of options for the jpackage tool.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the map of jpackage options
*/
public JpackageOptions jpackageOptions() {
return jpackageOptions_;
}
/**
* Provides a list of options to provide to the jpackage tool.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param options the map of jpackage options
* @return this operation instance
*/
public JpackageOperation jpackageOptions(Map<String, String> options) {
jpackageOptions_.putAll(options);
return this;
}
/**
* Retrieves the list of application launchers.
*
* @return the list of launchers
*/
public List<Launcher> launchers() {
return launchers_;
}
/**
* Name of launcher, and a path to a Properties file that contains a list of key, value pairs.
* <p>
* The keys {@code module}, {@code main-jar}, {@code main-class}, {@code description},
* {@code arguments}, {@code java-options}, {@code app-version}, {@code icon},
* {@code launcher-as-service}, {@code win-console}, {@code win-shortcut}, {@code win-menu},
* {@code linux-app-category}, and {@code linux-shortcut} can be used.
* <p>
* These options are added to, or used to overwrite, the original command line options to build an additional
* alternative launcher.
*
* @param name the name
* @param path absolute path or relative to the current directory
*/
public record Launcher(String name, String path) {
public Launcher(String name, File path) {
this(name, path.getAbsolutePath());
}
public Launcher(String name, Path path) {
this(name, path.toFile().getAbsolutePath());
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -9,9 +9,11 @@ import rife.bld.BldVersion;
import rife.bld.dependencies.*; import rife.bld.dependencies.*;
import rife.bld.dependencies.exceptions.DependencyException; import rife.bld.dependencies.exceptions.DependencyException;
import rife.bld.operations.exceptions.OperationOptionException; import rife.bld.operations.exceptions.OperationOptionException;
import rife.bld.operations.exceptions.RestApiException;
import rife.bld.operations.exceptions.SignException; import rife.bld.operations.exceptions.SignException;
import rife.bld.operations.exceptions.UploadException; import rife.bld.operations.exceptions.UploadException;
import rife.bld.publish.*; import rife.bld.publish.*;
import rife.ioc.HierarchicalProperties;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import rife.tools.exceptions.FileUtilsErrorException; import rife.tools.exceptions.FileUtilsErrorException;
@ -26,7 +28,9 @@ import java.time.ZoneId;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern;
import static rife.bld.dependencies.Dependency.*;
import static rife.bld.publish.MetadataBuilder.SNAPSHOT_TIMESTAMP_FORMATTER; import static rife.bld.publish.MetadataBuilder.SNAPSHOT_TIMESTAMP_FORMATTER;
import static rife.tools.HttpUtils.*; import static rife.tools.HttpUtils.*;
import static rife.tools.StringUtils.encodeHexLower; import static rife.tools.StringUtils.encodeHexLower;
@ -38,6 +42,11 @@ import static rife.tools.StringUtils.encodeHexLower;
* @since 1.5.7 * @since 1.5.7
*/ */
public class PublishOperation extends AbstractOperation<PublishOperation> { public class PublishOperation extends AbstractOperation<PublishOperation> {
private static final String OSSRH_STAGING_MANUAL_SEARCH = "https://" + Repository.OSSRH_STAGING_API_DOMAIN + "/manual/search/repositories";
private static final String OSSRH_STAGING_MANUAL_UPLOAD = "https://" + Repository.OSSRH_STAGING_API_DOMAIN + "/manual/upload/repository/";
private boolean offline_ = false;
private HierarchicalProperties properties_ = null;
private ArtifactRetriever retriever_ = null; private ArtifactRetriever retriever_ = null;
private final HttpClient client_ = HttpClient.newHttpClient(); private final HttpClient client_ = HttpClient.newHttpClient();
@ -45,6 +54,7 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
private final List<Repository> repositories_ = new ArrayList<>(); private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes(); private final DependencyScopes dependencies_ = new DependencyScopes();
private PublishInfo info_ = new PublishInfo(); private PublishInfo info_ = new PublishInfo();
private PublishProperties publishProperties_ = new PublishProperties();
private final List<PublishArtifact> artifacts_ = new ArrayList<>(); private final List<PublishArtifact> artifacts_ = new ArrayList<>();
/** /**
@ -53,6 +63,11 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @since 1.5.7 * @since 1.5.7
*/ */
public void execute() { public void execute() {
if (offline_) {
System.out.println("Offline mode: publish is disabled");
return;
}
if (repositories().isEmpty()) { if (repositories().isEmpty()) {
throw new OperationOptionException("ERROR: the publication repositories should be specified"); throw new OperationOptionException("ERROR: the publication repositories should be specified");
} }
@ -77,6 +92,11 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
executePublishArtifacts(repository, actual_version); executePublishArtifacts(repository, actual_version);
executePublishPom(repository, actual_version); executePublishPom(repository, actual_version);
executePublishMetadata(repository, moment); executePublishMetadata(repository, moment);
if (!info().version().isSnapshot() &&
repository.location().contains(Repository.OSSRH_STAGING_API_DOMAIN)) {
executeCloseOSSRHStagingRepository(repository);
}
} }
if (!silent()) { if (!silent()) {
System.out.println("Publishing finished successfully."); System.out.println("Publishing finished successfully.");
@ -104,13 +124,13 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* *
* @param repository the repository to publish to * @param repository the repository to publish to
* @param moment the timestamp at which the operation started executing * @param moment the timestamp at which the operation started executing
* @return the adapted version number with the snapshot timestamp and build number * @return the adapted version with the snapshot timestamp and build number
* @since 1.5.10 * @since 1.5.10
*/ */
protected VersionNumber executePublishSnapshotMetadata(Repository repository, ZonedDateTime moment) { protected Version executePublishSnapshotMetadata(Repository repository, ZonedDateTime moment) {
var metadata = new MetadataBuilder(); var metadata = new MetadataBuilder();
VersionNumber actual_version; Version actual_version;
if (repository.isLocal()) { if (repository.isLocal()) {
actual_version = info().version(); actual_version = info().version();
metadata.snapshotLocal(); metadata.snapshotLocal();
@ -120,16 +140,21 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
// determine which build number to use // determine which build number to use
var snapshot_build_number = 1; var snapshot_build_number = 1;
try { try {
var resolver = new DependencyResolver(artifactRetriever(), List.of(repository), new Dependency(info().groupId(), info().artifactId(), info().version())); var resolution = new VersionResolution(properties());
var resolver = new DependencyResolver(resolution, artifactRetriever(), List.of(repository), new Dependency(info().groupId(), info().artifactId(), info().version()));
var snapshot_meta = resolver.getSnapshotMavenMetadata(); var snapshot_meta = resolver.getSnapshotMavenMetadata();
snapshot_build_number = snapshot_meta.getSnapshotBuildNumber() + 1; var build_number_meta = snapshot_meta.getSnapshotBuildNumber();
if (build_number_meta == null) {
throw new DependencyException("Snapshot metadata build number doesn't exist.");
}
snapshot_build_number = build_number_meta + 1;
} catch (DependencyException e) { } catch (DependencyException e) {
// start the build number from the beginning // start the build number from the beginning
System.out.println("Unable to retrieve previous snapshot metadata, using first build number."); System.out.println("Unable to retrieve previous snapshot metadata, using first build number.");
System.out.println("This is expected for a first publication or for publication to a staging repository."); System.out.println("This is expected for a first publication or for publication to a staging repository.");
} }
// adapt the actual version that's use by the artifacts // adapt the actual version used by the artifacts
var snapshot_qualifier = snapshot_timestamp + "-" + snapshot_build_number; var snapshot_qualifier = snapshot_timestamp + "-" + snapshot_build_number;
actual_version = info().version().withQualifier(snapshot_qualifier); actual_version = info().version().withQualifier(snapshot_qualifier);
@ -150,7 +175,7 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
.info(info()) .info(info())
.updated(moment) .updated(moment)
.build(), .build(),
info().version() + "/" + repository.getMetadataName(), true); info().version() + "/" + repository.getMetadataName(), false);
return actual_version; return actual_version;
} }
@ -162,18 +187,18 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @param actualVersion the version that was potentially adapted if this is a snapshot * @param actualVersion the version that was potentially adapted if this is a snapshot
* @since 1.5.10 * @since 1.5.10
*/ */
protected void executePublishArtifacts(Repository repository, VersionNumber actualVersion) { protected void executePublishArtifacts(Repository repository, Version actualVersion) {
// upload artifacts // upload artifacts
for (var artifact : artifacts()) { for (var artifact : artifacts()) {
var artifact_name = new StringBuilder(info().artifactId()).append("-").append(actualVersion); var artifact_name = new StringBuilder(info().artifactId()).append('-').append(actualVersion);
if (!artifact.classifier().isEmpty()) { if (!artifact.classifier().isEmpty()) {
artifact_name.append("-").append(artifact.classifier()); artifact_name.append('-').append(artifact.classifier());
} }
var type = artifact.type(); var type = artifact.type();
if (type == null) { if (TYPE_JAR.equals(type) || TYPE_MODULAR_JAR.equals(type) || TYPE_CLASSPATH_JAR.equals(type)) {
type = "jar"; type = TYPE_JAR;
} }
artifact_name.append(".").append(type); artifact_name.append('.').append(type);
executePublishFileArtifact(repository, artifact.file(), info().version() + "/" + artifact_name); executePublishFileArtifact(repository, artifact.file(), info().version() + "/" + artifact_name);
} }
@ -186,11 +211,11 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @param actualVersion the version that was potentially adapted if this is a snapshot * @param actualVersion the version that was potentially adapted if this is a snapshot
* @since 1.5.10 * @since 1.5.10
*/ */
protected void executePublishPom(Repository repository, VersionNumber actualVersion) { protected void executePublishPom(Repository repository, Version actualVersion) {
// generate and upload pom // generate and upload pom
executePublishStringArtifact( executePublishStringArtifact(
repository, repository,
new PomBuilder().info(info()).dependencies(dependencies()).build(), new PomBuilder().properties(publishProperties()).info(info()).dependencies(dependencies()).build(),
info().version() + "/" + info().artifactId() + "-" + actualVersion + ".pom", true); info().version() + "/" + info().artifactId() + "-" + actualVersion + ".pom", true);
} }
@ -202,8 +227,9 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @since 1.5.8 * @since 1.5.8
*/ */
protected void executePublishMetadata(Repository repository, ZonedDateTime moment) { protected void executePublishMetadata(Repository repository, ZonedDateTime moment) {
var current_versions = new ArrayList<VersionNumber>(); var current_versions = new ArrayList<Version>();
var resolver = new DependencyResolver(artifactRetriever(), List.of(repository), new Dependency(info().groupId(), info().artifactId(), info().version())); var resolution = new VersionResolution(properties());
var resolver = new DependencyResolver(resolution, artifactRetriever(), List.of(repository), new Dependency(info().groupId(), info().artifactId(), info().version()));
try { try {
current_versions.addAll(resolver.getMavenMetadata().getVersions()); current_versions.addAll(resolver.getMavenMetadata().getVersions());
} catch (DependencyException e) { } catch (DependencyException e) {
@ -458,12 +484,8 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
var builder = HttpRequest.newBuilder() var builder = HttpRequest.newBuilder()
.PUT(body) .PUT(body)
.uri(URI.create(url)) .uri(URI.create(url))
.header(HEADER_USER_AGENT, "bld/" + BldVersion.getVersion() + .header(HEADER_USER_AGENT, constructBldUserAgent());
" (" + System.getProperty("os.name") + "; " + System.getProperty("os.version") + "; " + System.getProperty("os.arch") + ") " + applyAuthorization(repository, builder);
"(" + System.getProperty("java.vendor") + " " + System.getProperty("java.vm.name") + "; " + System.getProperty("java.version") + "; " + System.getProperty("java.vm.version") + ")");
if (repository.username() != null && repository.password() != null) {
builder.header(HEADER_AUTHORIZATION, basicAuthorizationHeader(repository.username(), repository.password()));
}
var request = builder.build(); var request = builder.build();
HttpResponse<String> response; HttpResponse<String> response;
@ -489,6 +511,105 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
} }
} }
private static String constructBldUserAgent() {
return "bld/" + BldVersion.getVersion() +
" (" + System.getProperty("os.name") + "; " + System.getProperty("os.version") + "; " + System.getProperty("os.arch") + ") " +
"(" + System.getProperty("java.vendor") + " " + System.getProperty("java.vm.name") + "; " + System.getProperty("java.version") + "; " + System.getProperty("java.vm.version") + ")";
}
private static void applyAuthorization(Repository repository, HttpRequest.Builder builder) {
if (repository.username() != null && repository.password() != null) {
builder.header(HEADER_AUTHORIZATION, basicAuthorizationHeader(repository.username(), repository.password()));
}
}
/**
* Part of the {@link #execute} operation, closes the OSSRH staging API repository.
*
* @param repository the repository to close a staging repository in
* @since 2.2.2
*/
protected void executeCloseOSSRHStagingRepository(Repository repository) {
var url_search = OSSRH_STAGING_MANUAL_SEARCH;
System.out.print("Finding open staging repositories at: " + url_search + " ... ");
System.out.flush();
try {
var builder_search = HttpRequest.newBuilder()
.GET()
.uri(URI.create(url_search))
.header(HEADER_USER_AGENT, constructBldUserAgent());
applyAuthorization(repository, builder_search);
var request_list = builder_search.build();
HttpResponse<String> response_search;
try {
response_search = client_.send(request_list, HttpResponse.BodyHandlers.ofString());
} catch (IOException e) {
System.out.print("I/O error");
throw new RestApiException(url_search, e);
} catch (InterruptedException e) {
System.out.print("interrupted");
throw new RestApiException(url_search, e);
}
if (response_search.statusCode() >= 200 &&
response_search.statusCode() < 300) {
System.out.println("done");
var pattern_key = Pattern.compile("\\{\\s*\"key\"\\s*:\\s*\"([^\"]+)\"\\s*,\\s*\"state\"\\s*:\\s*\"open\"");
var matcher_key = pattern_key.matcher(response_search.body());
if (matcher_key.find()) {
var key = matcher_key.group(1);
System.out.println("Found open staging repository with key: " + key);
var url_close = OSSRH_STAGING_MANUAL_UPLOAD + key;
System.out.print("Closing the staging repository at: " + url_close + " ... ");
System.out.flush();
var builder_close = HttpRequest.newBuilder()
.POST(BodyPublishers.ofString(""))
.uri(URI.create(url_close))
.header(HEADER_USER_AGENT, constructBldUserAgent());
applyAuthorization(repository, builder_close);
var request_close = builder_close.build();
HttpResponse<String> response_close;
try {
response_close = client_.send(request_close, HttpResponse.BodyHandlers.ofString());
} catch (IOException e) {
System.out.print("I/O error");
throw new RestApiException(url_close, e);
} catch (InterruptedException e) {
System.out.print("interrupted");
throw new RestApiException(url_close, e);
}
if (response_close.statusCode() >= 200 &&
response_close.statusCode() < 300) {
System.out.print("done");
} else {
System.out.println("failed");
var pattern_error = Pattern.compile("\\s*\"error\"\\s*:\\s*\"([^\"]*)\"");
var matcher_error = pattern_error.matcher(response_close.body());
if (matcher_error.find()) {
var error = matcher_error.group(1);
System.out.print(error.translateEscapes());
}
throw new RestApiException(url_close, response_close.statusCode());
}
}
else {
System.out.print("No open staging repository found.");
throw new RestApiException(url_search);
}
} else {
System.out.print("failed");
throw new RestApiException(url_search, response_search.statusCode());
}
} finally {
System.out.println();
}
}
/** /**
* Configures a publish operation from a {@link BaseProject}. * Configures a publish operation from a {@link BaseProject}.
* *
@ -496,12 +617,19 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @since 1.5.7 * @since 1.5.7
*/ */
public PublishOperation fromProject(BaseProject project) { public PublishOperation fromProject(BaseProject project) {
if (project.javaRelease() != null) {
publishProperties()
.mavenCompilerSource(project.javaRelease())
.mavenCompilerTarget(project.javaRelease());
}
offline(project.offline());
properties(project.properties());
artifactRetriever(project.artifactRetriever()); artifactRetriever(project.artifactRetriever());
dependencies().include(project.dependencies()); dependencies().include(project.dependencies());
artifacts(List.of( artifacts(List.of(
new PublishArtifact(new File(project.buildDistDirectory(), project.jarFileName()), "", "jar"), new PublishArtifact(new File(project.buildDistDirectory(), project.jarFileName()), "", TYPE_JAR),
new PublishArtifact(new File(project.buildDistDirectory(), project.sourcesJarFileName()), "sources", "jar"), new PublishArtifact(new File(project.buildDistDirectory(), project.sourcesJarFileName()), CLASSIFIER_SOURCES, TYPE_JAR),
new PublishArtifact(new File(project.buildDistDirectory(), project.javadocJarFileName()), "javadoc", "jar"))); new PublishArtifact(new File(project.buildDistDirectory(), project.javadocJarFileName()), CLASSIFIER_JAVADOC, TYPE_JAR)));
if (info().groupId() == null) { if (info().groupId() == null) {
info().groupId(project.pkg()); info().groupId(project.pkg());
} }
@ -517,6 +645,30 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
return this; return this;
} }
/**
* Indicates whether the operation has to run offline.
*
* @param flag {@code true} if the operation runs offline; or
* {@code false} otherwise
* @return this operation instance
* @since 2.0
*/
public PublishOperation offline(boolean flag) {
offline_ = flag;
return this;
}
/**
* Returns whether the operation has to run offline.
*
* @return {@code true} if the operation runs offline; or
* {@code false} otherwise
* @since 2.0
*/
public boolean offline() {
return offline_;
}
/** /**
* Provides the moment of publication. * Provides the moment of publication.
* <p> * <p>
@ -593,6 +745,18 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
return this; return this;
} }
/**
* Provides the publication properties.
*
* @param properties the publication properties
* @return this operation instance
* @since 2.0
*/
public PublishOperation publishProperties(PublishProperties properties) {
publishProperties_ = properties;
return this;
}
/** /**
* Provides the publication info structure. * Provides the publication info structure.
* *
@ -643,6 +807,18 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
return this; return this;
} }
/**
* Provides the hierarchical properties to use.
*
* @param properties the hierarchical properties
* @return this operation instance
* @since 2.0
*/
public PublishOperation properties(HierarchicalProperties properties) {
properties_ = properties;
return this;
}
/** /**
* Retrieves the repositories to which will be published. * Retrieves the repositories to which will be published.
* <p> * <p>
@ -667,6 +843,18 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
return dependencies_; return dependencies_;
} }
/**
* Retrieves the publication properties.
* <p>
* This is a modifiable structure that can be retrieved and changed.
*
* @return the publication properties
* @since 2.0
*/
public PublishProperties publishProperties() {
return publishProperties_;
}
/** /**
* Retrieves the publication info structure. * Retrieves the publication info structure.
* <p> * <p>
@ -703,4 +891,17 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
} }
return retriever_; return retriever_;
} }
/**
* Returns the hierarchical properties that are used.
*
* @return the hierarchical properties
* @since 2.0
*/
public HierarchicalProperties properties() {
if (properties_ == null) {
properties_ = new HierarchicalProperties();
}
return properties_;
}
} }

View file

@ -6,6 +6,7 @@ package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.dependencies.*; import rife.bld.dependencies.*;
import rife.ioc.HierarchicalProperties;
import java.io.File; import java.io.File;
import java.util.*; import java.util.*;
@ -24,13 +25,21 @@ import static rife.bld.dependencies.Dependency.CLASSIFIER_SOURCES;
* @since 1.5 * @since 1.5
*/ */
public class PurgeOperation extends AbstractOperation<PurgeOperation> { public class PurgeOperation extends AbstractOperation<PurgeOperation> {
private boolean offline_ = false;
private HierarchicalProperties properties_ = null;
private ArtifactRetriever retriever_ = null; private ArtifactRetriever retriever_ = null;
private final List<Repository> repositories_ = new ArrayList<>(); private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes(); private final DependencyScopes dependencies_ = new DependencyScopes();
private File libCompileDirectory_; private File libCompileDirectory_;
private File libCompileModulesDirectory_;
private File libProvidedDirectory_;
private File libProvidedModulesDirectory_;
private File libRuntimeDirectory_; private File libRuntimeDirectory_;
private File libRuntimeModulesDirectory_;
private File libStandaloneDirectory_; private File libStandaloneDirectory_;
private File libStandaloneModulesDirectory_;
private File libTestDirectory_; private File libTestDirectory_;
private File libTestModulesDirectory_;
private boolean preserveSources_ = false; private boolean preserveSources_ = false;
private boolean preserveJavadoc_ = false; private boolean preserveJavadoc_ = false;
@ -40,7 +49,13 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5 * @since 1.5
*/ */
public void execute() { public void execute() {
if (offline_) {
System.out.println("Offline mode: purge is disabled");
return;
}
executePurgeCompileDependencies(); executePurgeCompileDependencies();
executePurgeProvidedDependencies();
executePurgeRuntimeDependencies(); executePurgeRuntimeDependencies();
executePurgeStandaloneDependencies(); executePurgeStandaloneDependencies();
executePurgeTestDependencies(); executePurgeTestDependencies();
@ -55,7 +70,16 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5 * @since 1.5
*/ */
protected void executePurgeCompileDependencies() { protected void executePurgeCompileDependencies() {
executePurgeDependencies(libCompileDirectory(), dependencies().resolveCompileDependencies(artifactRetriever(), repositories())); executePurgeDependencies(libCompileDirectory(), libCompileModulesDirectory(), dependencies().resolveCompileDependencies(properties(), artifactRetriever(), repositories()));
}
/**
* Part of the {@link #execute} operation, purge the {@code provided} scope artifacts.
*
* @since 1.8
*/
protected void executePurgeProvidedDependencies() {
executePurgeDependencies(libProvidedDirectory(), libProvidedModulesDirectory(), dependencies().resolveProvidedDependencies(properties(), artifactRetriever(), repositories()));
} }
/** /**
@ -64,7 +88,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5 * @since 1.5
*/ */
protected void executePurgeRuntimeDependencies() { protected void executePurgeRuntimeDependencies() {
executePurgeDependencies(libRuntimeDirectory(), dependencies().resolveRuntimeDependencies(artifactRetriever(), repositories())); executePurgeDependencies(libRuntimeDirectory(), libRuntimeModulesDirectory(), dependencies().resolveRuntimeDependencies(properties(), artifactRetriever(), repositories()));
} }
/** /**
@ -73,7 +97,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5 * @since 1.5
*/ */
protected void executePurgeStandaloneDependencies() { protected void executePurgeStandaloneDependencies() {
executePurgeDependencies(libStandaloneDirectory(), dependencies().resolveStandaloneDependencies(artifactRetriever(), repositories())); executePurgeDependencies(libStandaloneDirectory(), libStandaloneModulesDirectory(), dependencies().resolveStandaloneDependencies(properties(), artifactRetriever(), repositories()));
} }
/** /**
@ -82,46 +106,66 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5 * @since 1.5
*/ */
protected void executePurgeTestDependencies() { protected void executePurgeTestDependencies() {
executePurgeDependencies(libTestDirectory(), dependencies().resolveTestDependencies(artifactRetriever(), repositories())); executePurgeDependencies(libTestDirectory(), libTestModulesDirectory(), dependencies().resolveTestDependencies(properties(), artifactRetriever(), repositories()));
} }
/** /**
* Part of the {@link #execute} operation, purge the artifacts for a particular dependency scope. * Part of the {@link #execute} operation, purge the artifacts for a particular dependency scope.
* *
* @param destinationDirectory the directory from which the artifacts should be purged * @param classpathDirectory the directory from which the artifacts should be purged
* @param modulesDirectory the directory from which the modules should be purged
* @param dependencies the dependencies to purge * @param dependencies the dependencies to purge
* @since 1.6 * @since 2.1
*/ */
protected void executePurgeDependencies(File destinationDirectory, DependencySet dependencies) { protected void executePurgeDependencies(File classpathDirectory, File modulesDirectory, DependencySet dependencies) {
if (destinationDirectory == null) { if (classpathDirectory == null && modulesDirectory == null) {
return; return;
} }
var filenames = new HashSet<String>();
var classpath_names = new HashSet<String>();
var modules_names = new HashSet<String>();
for (var dependency : dependencies) { for (var dependency : dependencies) {
var filenames = classpath_names;
if (dependency.isModularJar()) {
filenames = modules_names;
}
addTransferLocations(filenames, dependency); addTransferLocations(filenames, dependency);
if (preserveSources_) { if (preserveSources_ && !dependency.excludedClassifiers().contains(CLASSIFIER_SOURCES)) {
addTransferLocations(filenames, dependency.withClassifier(CLASSIFIER_SOURCES)); addTransferLocations(filenames, dependency.withClassifier(CLASSIFIER_SOURCES));
} }
if (preserveJavadoc_) { if (preserveJavadoc_ && !dependency.excludedClassifiers().contains(CLASSIFIER_JAVADOC)) {
addTransferLocations(filenames, dependency.withClassifier(CLASSIFIER_JAVADOC)); addTransferLocations(filenames, dependency.withClassifier(CLASSIFIER_JAVADOC));
} }
} }
purgeFromDirectory(classpathDirectory, modulesDirectory, classpath_names);
purgeFromDirectory(modulesDirectory, classpathDirectory, modules_names);
}
private static void purgeFromDirectory(File directory, File preserveDirectory, HashSet<String> preservedFileNames) {
if (directory == null) {
return;
}
boolean printed_header = false; boolean printed_header = false;
for (var file : destinationDirectory.listFiles()) { var classpath_files = directory.listFiles();
if (!filenames.contains(file.getName())) { if (classpath_files != null) {
for (var file : classpath_files) {
if (!preservedFileNames.contains(file.getName()) && !file.equals(preserveDirectory)) {
if (!printed_header) { if (!printed_header) {
printed_header = true; printed_header = true;
System.out.println("Deleting from " + destinationDirectory.getName() + ":"); System.out.println("Deleting from " + directory.getName() + ":");
} }
System.out.println(" " + file.getName()); System.out.println(" " + file.getName());
file.delete(); file.delete();
} }
} }
} }
}
private void addTransferLocations(HashSet<String> filenames, Dependency dependency) { private void addTransferLocations(HashSet<String> filenames, Dependency dependency) {
for (var location : new DependencyResolver(artifactRetriever(), repositories(), dependency).getTransferLocations()) { var resolution = new VersionResolution(properties());
for (var location : new DependencyResolver(resolution, artifactRetriever(), repositories(), dependency).getTransferLocations()) {
filenames.add(location.substring(location.lastIndexOf("/") + 1)); filenames.add(location.substring(location.lastIndexOf("/") + 1));
} }
} }
@ -133,17 +177,49 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5 * @since 1.5
*/ */
public PurgeOperation fromProject(BaseProject project) { public PurgeOperation fromProject(BaseProject project) {
return artifactRetriever(project.artifactRetriever()) return offline(project.offline())
.properties(project.properties())
.artifactRetriever(project.artifactRetriever())
.repositories(project.repositories()) .repositories(project.repositories())
.dependencies(project.dependencies()) .dependencies(project.dependencies())
.libCompileDirectory(project.libCompileDirectory()) .libCompileDirectory(project.libCompileDirectory())
.libCompileModulesDirectory(project.libCompileModulesDirectory())
.libProvidedDirectory(project.libProvidedDirectory())
.libProvidedModulesDirectory(project.libProvidedModulesDirectory())
.libRuntimeDirectory(project.libRuntimeDirectory()) .libRuntimeDirectory(project.libRuntimeDirectory())
.libRuntimeModulesDirectory(project.libRuntimeModulesDirectory())
.libStandaloneDirectory(project.libStandaloneDirectory()) .libStandaloneDirectory(project.libStandaloneDirectory())
.libStandaloneModulesDirectory(project.libStandaloneModulesDirectory())
.libTestDirectory(project.libTestDirectory()) .libTestDirectory(project.libTestDirectory())
.libTestModulesDirectory(project.libTestModulesDirectory())
.preserveSources(project.downloadSources()) .preserveSources(project.downloadSources())
.preserveJavadoc(project.downloadJavadoc()); .preserveJavadoc(project.downloadJavadoc());
} }
/**
* Indicates whether the operation has to run offline.
*
* @param flag {@code true} if the operation runs offline; or
* {@code false} otherwise
* @return this operation instance
* @since 2.0
*/
public PurgeOperation offline(boolean flag) {
offline_ = flag;
return this;
}
/**
* Returns whether the operation has to run offline.
*
* @return {@code true} if the operation runs offline; or
* {@code false} otherwise
* @since 2.0
*/
public boolean offline() {
return offline_;
}
/** /**
* Indicates whether the sources classifier files should be preserved. * Indicates whether the sources classifier files should be preserved.
* *
@ -220,6 +296,42 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this; return this;
} }
/**
* Provides the {@code compile} scope modules purge directory.
*
* @param directory the directory to purge the {@code compile} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libCompileModulesDirectory(File directory) {
libCompileModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code provided} scope purge directory.
*
* @param directory the directory to purge the {@code provided} scope artifacts from
* @return this operation instance
* @since 1.8
*/
public PurgeOperation libProvidedDirectory(File directory) {
libProvidedDirectory_ = directory;
return this;
}
/**
* Provides the {@code provided} scope modules purge directory.
*
* @param directory the directory to purge the {@code provided} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libProvidedModulesDirectory(File directory) {
libProvidedModulesDirectory_ = directory;
return this;
}
/** /**
* Provides the {@code runtime} scope purge directory. * Provides the {@code runtime} scope purge directory.
* *
@ -232,6 +344,18 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this; return this;
} }
/**
* Provides the {@code runtime} scope modules purge directory.
*
* @param directory the directory to purge the {@code runtime} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libRuntimeModulesDirectory(File directory) {
libRuntimeModulesDirectory_ = directory;
return this;
}
/** /**
* Provides the {@code standalone} scope purge directory. * Provides the {@code standalone} scope purge directory.
* *
@ -244,6 +368,18 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this; return this;
} }
/**
* Provides the {@code standalone} scope modules purge directory.
*
* @param directory the directory to purge the {@code standalone} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libStandaloneModulesDirectory(File directory) {
libStandaloneModulesDirectory_ = directory;
return this;
}
/** /**
* Provides the {@code test} scope purge directory. * Provides the {@code test} scope purge directory.
* *
@ -256,6 +392,18 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this; return this;
} }
/**
* Provides the {@code test} scope modules purge directory.
*
* @param directory the directory to purge the {@code test} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libTestModulesDirectory(File directory) {
libTestModulesDirectory_ = directory;
return this;
}
/** /**
* Provides the artifact retriever to use. * Provides the artifact retriever to use.
* *
@ -268,6 +416,18 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this; return this;
} }
/**
* Provides the hierarchical properties to use.
*
* @param properties the hierarchical properties
* @return this operation instance
* @since 2.0
*/
public PurgeOperation properties(HierarchicalProperties properties) {
properties_ = properties;
return this;
}
/** /**
* Retrieves the repositories in which the dependencies will be resolved. * Retrieves the repositories in which the dependencies will be resolved.
* <p> * <p>
@ -302,6 +462,36 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return libCompileDirectory_; return libCompileDirectory_;
} }
/**
* Retrieves the {@code compile} scope modules purge directory.
*
* @return the {@code compile} scope modules purge directory
* @since 2.1
*/
public File libCompileModulesDirectory() {
return libCompileModulesDirectory_;
}
/**
* Retrieves the {@code provided} scope purge directory.
*
* @return the {@code provided} scope purge directory
* @since 1.8
*/
public File libProvidedDirectory() {
return libProvidedDirectory_;
}
/**
* Retrieves the {@code provided} scope modules purge directory.
*
* @return the {@code provided} scope modules purge directory
* @since 2.1
*/
public File libProvidedModulesDirectory() {
return libProvidedModulesDirectory_;
}
/** /**
* Retrieves the {@code runtime} scope purge directory. * Retrieves the {@code runtime} scope purge directory.
* *
@ -312,6 +502,16 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return libRuntimeDirectory_; return libRuntimeDirectory_;
} }
/**
* Retrieves the {@code runtime} scope modules purge directory.
*
* @return the {@code runtime} scope modules purge directory
* @since 2.1
*/
public File libRuntimeModulesDirectory() {
return libRuntimeModulesDirectory_;
}
/** /**
* Retrieves the {@code standalone} scope purge directory. * Retrieves the {@code standalone} scope purge directory.
* *
@ -322,6 +522,16 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return libStandaloneDirectory_; return libStandaloneDirectory_;
} }
/**
* Retrieves the {@code standalone} scope modules purge directory.
*
* @return the {@code standalone} scope modules purge directory
* @since 2.1
*/
public File libStandaloneModulesDirectory() {
return libStandaloneModulesDirectory_;
}
/** /**
* Retrieves the {@code test} scope purge directory. * Retrieves the {@code test} scope purge directory.
* *
@ -332,6 +542,16 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return libTestDirectory_; return libTestDirectory_;
} }
/**
* Retrieves the {@code test} scope modules purge directory.
*
* @return the {@code test} scope modules purge directory
* @since 2.1
*/
public File libTestModulesDirectory() {
return libTestModulesDirectory_;
}
/** /**
* Retrieves whether the sources classifier files should be preserved. * Retrieves whether the sources classifier files should be preserved.
* *
@ -366,4 +586,17 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
} }
return retriever_; return retriever_;
} }
/**
* Returns the hierarchical properties that are used.
*
* @return the hierarchical properties
* @since 2.0
*/
public HierarchicalProperties properties() {
if (properties_ == null) {
properties_ = new HierarchicalProperties();
}
return properties_;
}
} }

View file

@ -8,6 +8,7 @@ import rife.bld.BaseProject;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@ -17,6 +18,7 @@ import java.util.List;
* @since 1.5 * @since 1.5
*/ */
public class RunOperation extends AbstractProcessOperation<RunOperation> { public class RunOperation extends AbstractProcessOperation<RunOperation> {
public static final String ARGS_OPTION = "--args=";
protected final List<String> runOptions_ = new ArrayList<>(); protected final List<String> runOptions_ = new ArrayList<>();
/** /**
@ -29,12 +31,30 @@ public class RunOperation extends AbstractProcessOperation<RunOperation> {
var args = new ArrayList<String>(); var args = new ArrayList<String>();
args.add(javaTool()); args.add(javaTool());
args.addAll(javaOptions()); args.addAll(javaOptions());
if (!classpath().isEmpty()) { if (!classpath().isEmpty()) {
args.add("-cp"); args.add("-cp");
args.add(FileUtils.joinPaths(classpath())); args.add(FileUtils.joinPaths(classpath()));
} }
if (!modulePath().isEmpty()) {
args.add("-p");
args.add(FileUtils.joinPaths(modulePath()));
}
if (module() != null && !module().isEmpty()) {
args.add("-m");
args.add(module());
}
else if (mainClass() != null && !mainClass().isEmpty()){
args.add(mainClass()); args.add(mainClass());
}
else if (!silent()) {
System.err.println("No main class or module specified.");
}
args.addAll(runOptions()); args.addAll(runOptions());
return args; return args;
} }
@ -48,10 +68,26 @@ public class RunOperation extends AbstractProcessOperation<RunOperation> {
var operation = workDirectory(project.workDirectory()) var operation = workDirectory(project.workDirectory())
.javaTool(project.javaTool()) .javaTool(project.javaTool())
.classpath(project.runClasspath()) .classpath(project.runClasspath())
.mainClass(project.mainClass()); .modulePath(project.runModulePath())
.mainClass(project.mainClass())
.module(project.module());
if (project.usesRife2Agent()) { if (project.usesRife2Agent()) {
operation.javaOptions().javaAgent(project.getRife2AgentFile()); operation.javaOptions().javaAgent(project.getRife2AgentFile());
} }
// parse the run arguments if any
var args = project.arguments();
if (!args.isEmpty()) {
var arg = args.get(0);
if (arg.startsWith(ARGS_OPTION)) {
args.remove(0);
var runArgs = arg.substring(ARGS_OPTION.length());
if (!runArgs.isBlank()) {
runOptions_.addAll(0, Arrays.asList(runArgs.split(" ")));
}
}
}
return operation; return operation;
} }

View file

@ -5,12 +5,10 @@
package rife.bld.operations; package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.Project;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* Tests a Java application. * Tests a Java application.
@ -53,8 +51,14 @@ public class TestOperation<T extends TestOperation<T, O>, O extends List<String>
var args = new ArrayList<String>(); var args = new ArrayList<String>();
args.add(javaTool()); args.add(javaTool());
args.addAll(javaOptions()); args.addAll(javaOptions());
if (!classpath().isEmpty()) {
args.add("-cp"); args.add("-cp");
args.add(FileUtils.joinPaths(classpath())); args.add(FileUtils.joinPaths(classpath()));
}
if (!modulePath().isEmpty()) {
args.add("-p");
args.add(FileUtils.joinPaths(modulePath()));
}
args.add(mainClass()); args.add(mainClass());
args.addAll(testToolOptions()); args.addAll(testToolOptions());
@ -70,7 +74,8 @@ public class TestOperation<T extends TestOperation<T, O>, O extends List<String>
public T fromProject(BaseProject project) { public T fromProject(BaseProject project) {
var operation = workDirectory(project.workDirectory()) var operation = workDirectory(project.workDirectory())
.javaTool(project.javaTool()) .javaTool(project.javaTool())
.classpath(project.testClasspath()); .classpath(project.testClasspath())
.modulePath(project.testModulePath());
if (project.usesRife2Agent()) { if (project.usesRife2Agent()) {
operation.javaOptions().javaAgent(project.getRife2AgentFile()); operation.javaOptions().javaAgent(project.getRife2AgentFile());
} }

View file

@ -6,7 +6,6 @@ package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.NamedFile; import rife.bld.NamedFile;
import rife.bld.Project;
import rife.tools.FileUtils; import rife.tools.FileUtils;
import rife.tools.exceptions.FileUtilsErrorException; import rife.tools.exceptions.FileUtilsErrorException;
@ -98,7 +97,9 @@ public class UberJarOperation extends AbstractOperation<UberJarOperation> {
.sourceDirectories(stagingDirectory) .sourceDirectories(stagingDirectory)
.destinationDirectory(destinationDirectory()) .destinationDirectory(destinationDirectory())
.destinationFileName(destinationFileName()) .destinationFileName(destinationFileName())
.excluded(List.of(Pattern.compile("(?:(?:^.*[/\\\\])|^)\\.DS_Store$"))) .excluded(List.of(
Pattern.compile("(?:(?:^.*[/\\\\])|^)\\.DS_Store$"),
Pattern.compile("(?:(?:^.*[/\\\\])|^).+\\.(DSA|RSA|SF)$")))
.silent(true) .silent(true)
.execute(); .execute();
} }

View file

@ -5,8 +5,8 @@
package rife.bld.operations; package rife.bld.operations;
import rife.bld.BaseProject; import rife.bld.BaseProject;
import rife.bld.Project;
import rife.bld.dependencies.*; import rife.bld.dependencies.*;
import rife.ioc.HierarchicalProperties;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -18,6 +18,7 @@ import java.util.List;
* @since 1.5 * @since 1.5
*/ */
public class UpdatesOperation extends AbstractOperation<UpdatesOperation> { public class UpdatesOperation extends AbstractOperation<UpdatesOperation> {
private HierarchicalProperties properties_ = null;
private ArtifactRetriever retriever_ = null; private ArtifactRetriever retriever_ = null;
private final List<Repository> repositories_ = new ArrayList<>(); private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes(); private final DependencyScopes dependencies_ = new DependencyScopes();
@ -29,11 +30,12 @@ public class UpdatesOperation extends AbstractOperation<UpdatesOperation> {
* @since 1.5 * @since 1.5
*/ */
public void execute() { public void execute() {
var resolution = new VersionResolution(properties());
var result = new DependencyScopes(); var result = new DependencyScopes();
for (var entry : dependencies_.entrySet()) { for (var entry : dependencies_.entrySet()) {
var scope = entry.getKey(); var scope = entry.getKey();
for (var dependency : entry.getValue()) { for (var dependency : entry.getValue()) {
var latest = new DependencyResolver(artifactRetriever(), repositories(), dependency).latestVersion(); var latest = new DependencyResolver(resolution, artifactRetriever(), repositories(), dependency).latestVersion();
if (latest.compareTo(dependency.version()) > 0) { if (latest.compareTo(dependency.version()) > 0) {
var latest_dependency = new Dependency(dependency.groupId(), dependency.artifactId(), latest, var latest_dependency = new Dependency(dependency.groupId(), dependency.artifactId(), latest,
dependency.classifier(), dependency.type()); dependency.classifier(), dependency.type());
@ -66,7 +68,8 @@ public class UpdatesOperation extends AbstractOperation<UpdatesOperation> {
* @since 1.5 * @since 1.5
*/ */
public UpdatesOperation fromProject(BaseProject project) { public UpdatesOperation fromProject(BaseProject project) {
return artifactRetriever(project.artifactRetriever()) return properties(project.properties())
.artifactRetriever(project.artifactRetriever())
.repositories(project.repositories()) .repositories(project.repositories())
.dependencies(project.dependencies()); .dependencies(project.dependencies());
} }
@ -121,6 +124,18 @@ public class UpdatesOperation extends AbstractOperation<UpdatesOperation> {
return this; return this;
} }
/**
* Provides the hierarchical properties to use.
*
* @param properties the hierarchical properties
* @return this operation instance
* @since 2.0
*/
public UpdatesOperation properties(HierarchicalProperties properties) {
properties_ = properties;
return this;
}
/** /**
* Retrieves the repositories in which the dependencies will be resolved. * Retrieves the repositories in which the dependencies will be resolved.
* <p> * <p>
@ -167,4 +182,17 @@ public class UpdatesOperation extends AbstractOperation<UpdatesOperation> {
} }
return retriever_; return retriever_;
} }
/**
* Returns the hierarchical properties that are used.
*
* @return the hierarchical properties
* @since 2.0
*/
public HierarchicalProperties properties() {
if (properties_ == null) {
properties_ = new HierarchicalProperties();
}
return properties_;
}
} }

View file

@ -0,0 +1,30 @@
/**
* Copyright 2024 Erik C. Thauvin (https://erik.thauvin.net/)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations;
/**
* The zip compression levels for jlink and jmod.
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @since 2.1.0
*/
public enum ZipCompression {
ZIP_0("zip-0"),
ZIP_1("zip-1"),
ZIP_2("zip-2"),
ZIP_3("zip-3"),
ZIP_4("zip-4"),
ZIP_5("zip-5"),
ZIP_6("zip-6"),
ZIP_7("zip-7"),
ZIP_8("zip-8"),
ZIP_9("zip-9");
public final String level;
ZipCompression(String level) {
this.level = level;
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.operations.exceptions;
import rife.tools.HttpUtils;
import java.io.Serial;
/**
* When thrown, indicates that something went wrong during the use of a rest API call.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 2.2.2
*/
public class RestApiException extends RuntimeException {
@Serial private static final long serialVersionUID = -6753423938407177328L;
private final String url_;
public RestApiException(String url, int status) {
super("An error occurred while using rest API at '" + url + "'\nHTTP status code " + status + " : " + HttpUtils.statusReason(status));
url_ = url;
}
public RestApiException(String url, Throwable cause) {
super("An error occurred while using rest API at '" + url + "'", cause);
url_ = url;
}
public RestApiException(String url) {
super("An error occurred while using rest API at '" + url + "'");
url_ = url;
}
public String getUrl() {
return url_;
}
}

View file

@ -4,8 +4,6 @@
*/ */
package rife.bld.operations.exceptions; package rife.bld.operations.exceptions;
import rife.tools.HttpUtils;
import java.io.File; import java.io.File;
import java.io.Serial; import java.io.Serial;

View file

@ -4,6 +4,7 @@
*/ */
package rife.bld.publish; package rife.bld.publish;
import rife.bld.dependencies.Version;
import rife.bld.dependencies.VersionNumber; import rife.bld.dependencies.VersionNumber;
import rife.template.TemplateFactory; import rife.template.TemplateFactory;
import rife.tools.StringUtils; import rife.tools.StringUtils;
@ -24,7 +25,7 @@ public class MetadataBuilder {
private PublishInfo info_ = null; private PublishInfo info_ = null;
private ZonedDateTime timestamp_ = null; private ZonedDateTime timestamp_ = null;
private final Set<VersionNumber> otherVersions_ = new HashSet<>(); private final Set<Version> otherVersions_ = new HashSet<>();
private ZonedDateTime snapshotTimestamp_ = null; private ZonedDateTime snapshotTimestamp_ = null;
private Integer snapshotBuildNumber_ = null; private Integer snapshotBuildNumber_ = null;
private boolean snapshotLocal_ = false; private boolean snapshotLocal_ = false;
@ -81,7 +82,7 @@ public class MetadataBuilder {
* @return this {@code MetadataBuilder} instance * @return this {@code MetadataBuilder} instance
* @since 1.5.8 * @since 1.5.8
*/ */
public MetadataBuilder otherVersions(Collection<VersionNumber> otherVersions) { public MetadataBuilder otherVersions(Collection<Version> otherVersions) {
otherVersions_.addAll(otherVersions); otherVersions_.addAll(otherVersions);
return this; return this;
} }
@ -94,7 +95,7 @@ public class MetadataBuilder {
* @return the other versions * @return the other versions
* @since 1.5.8 * @since 1.5.8
*/ */
public Set<VersionNumber> otherVersions() { public Set<Version> otherVersions() {
return otherVersions_; return otherVersions_;
} }

View file

@ -7,10 +7,15 @@ package rife.bld.publish;
import rife.bld.dependencies.*; import rife.bld.dependencies.*;
import rife.template.Template; import rife.template.Template;
import rife.template.TemplateFactory; import rife.template.TemplateFactory;
import rife.tools.FileUtils;
import rife.tools.StringUtils; import rife.tools.StringUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File;
import java.util.Objects; import java.util.Objects;
import static rife.bld.dependencies.Dependency.TYPE_JAR;
/** /**
* Provides the functionalities to build a Maven POM xml file. * Provides the functionalities to build a Maven POM xml file.
* *
@ -19,6 +24,7 @@ import java.util.Objects;
*/ */
public class PomBuilder { public class PomBuilder {
private PublishInfo info_ = null; private PublishInfo info_ = null;
private PublishProperties properties_ = new PublishProperties();
private DependencyScopes dependencies_ = new DependencyScopes(); private DependencyScopes dependencies_ = new DependencyScopes();
/** /**
@ -43,6 +49,28 @@ public class PomBuilder {
return info_; return info_;
} }
/**
* Provides the properties to build the POM with.
*
* @param properties the properties to use
* @return this {@code PomBuilder} instance
* @since 2.0
*/
public PomBuilder properties(PublishProperties properties) {
properties_ = properties;
return this;
}
/**
* Retrieves the properties to build the POM with.
*
* @return the properties to use
* @since 2.0
*/
public PublishProperties properties() {
return properties_;
}
/** /**
* Provides the dependencies to build the POM for. * Provides the dependencies to build the POM for.
* *
@ -112,15 +140,38 @@ public class PomBuilder {
} }
} }
if (properties() != null && !properties().isEmpty()) {
for (var entry : properties().entrySet()) {
if (entry.getKey() != null) {
t.setValueEncoded("property-key", entry.getKey());
t.setValueEncoded("property-value", Objects.requireNonNullElse(entry.getValue(), ""));
t.appendBlock("properties", "property");
}
}
t.setBlock("properties-tag");
}
if (dependencies() != null && !dependencies().isEmpty()) { if (dependencies() != null && !dependencies().isEmpty()) {
addDependencies(t, Scope.compile); addDependencies(t, Scope.compile);
addDependencies(t, Scope.runtime); addDependencies(t, Scope.runtime);
addDependencies(t, Scope.provided);
t.setBlock("dependencies-tag"); t.setBlock("dependencies-tag");
} }
return StringUtils.stripBlankLines(t.getContent()); return StringUtils.stripBlankLines(t.getContent());
} }
/**
* Generates a POM into the given file.
*
* @since 1.7.1
*/
public static void generateInto(PublishInfo info, DependencyScopes dependencies, File file)
throws FileUtilsErrorException {
var pomBuilder = new PomBuilder().info(info).dependencies(dependencies);
FileUtils.writeString(pomBuilder.build(), file);
}
private void addDependencies(Template t, Scope scope) { private void addDependencies(Template t, Scope scope) {
var scoped_dependencies = dependencies().scope(scope); var scoped_dependencies = dependencies().scope(scope);
if (!scoped_dependencies.isEmpty()) { if (!scoped_dependencies.isEmpty()) {
@ -137,7 +188,7 @@ public class PomBuilder {
t.blankValue("dependency-type"); t.blankValue("dependency-type");
t.blankValue("dependency-type-tag"); t.blankValue("dependency-type-tag");
if (!dependency.type().equals("jar")) { if (!TYPE_JAR.equals(dependency.type())) {
t.setValueEncoded("dependency-type", dependency.type()); t.setValueEncoded("dependency-type", dependency.type());
t.setBlock("dependency-type-tag"); t.setBlock("dependency-type-tag");
} }

View file

@ -6,6 +6,8 @@ package rife.bld.publish;
import java.io.File; import java.io.File;
import static rife.bld.dependencies.Dependency.TYPE_JAR;
/** /**
* Contains the information about an artifact that will be published. * Contains the information about an artifact that will be published.
* *
@ -19,6 +21,6 @@ public record PublishArtifact(File file, String classifier, String type) {
public PublishArtifact(File file, String classifier, String type) { public PublishArtifact(File file, String classifier, String type) {
this.file = file; this.file = file;
this.classifier = (classifier == null ? "" : classifier); this.classifier = (classifier == null ? "" : classifier);
this.type = (type == null ? "jar" : type); this.type = (type == null ? TYPE_JAR : type);
} }
} }

View file

@ -4,6 +4,7 @@
*/ */
package rife.bld.publish; package rife.bld.publish;
import rife.bld.dependencies.Version;
import rife.bld.dependencies.VersionNumber; import rife.bld.dependencies.VersionNumber;
import java.util.ArrayList; import java.util.ArrayList;
@ -18,7 +19,7 @@ import java.util.List;
public class PublishInfo { public class PublishInfo {
private String groupId_ = null; private String groupId_ = null;
private String artifactId_ = null; private String artifactId_ = null;
private VersionNumber version_ = null; private Version version_ = null;
private String name_ = null; private String name_ = null;
private String description_ = null; private String description_ = null;
private String url_ = null; private String url_ = null;
@ -81,7 +82,7 @@ public class PublishInfo {
* @return this {@code PublishInfo} instance * @return this {@code PublishInfo} instance
* @since 1.5.7 * @since 1.5.7
*/ */
public PublishInfo version(VersionNumber version) { public PublishInfo version(Version version) {
version_ = version; version_ = version;
return this; return this;
} }
@ -92,7 +93,7 @@ public class PublishInfo {
* @return the project's version. * @return the project's version.
* @since 1.5.7 * @since 1.5.7
*/ */
public VersionNumber version() { public Version version() {
return version_; return version_;
} }

View file

@ -0,0 +1,80 @@
/*
* Copyright 2001-2024 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.publish;
import java.util.*;
/**
* Provides the properties information for publication.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 2.0
*/
public class PublishProperties extends LinkedHashMap<String, String> {
private static final String MAVEN_COMPILER_SOURCE = "maven.compiler.source";
private static final String MAVEN_COMPILER_TARGET = "maven.compiler.target";
/**
* Sets the value of the 'maven.compiler.source' property.
*
* @param value the value to be set for the 'maven.compiler.source' property
* @return this {@code PomProperties} instance
* @since 2.0
*/
public PublishProperties mavenCompilerSource(Integer value) {
if (value == null) {
remove(MAVEN_COMPILER_SOURCE);
}
else {
put(MAVEN_COMPILER_SOURCE, String.valueOf(value));
}
return this;
}
/**
* Retrieves the value of the 'maven.compiler.source' property.
*
* @return the value of the 'maven.compiler.source' property
* @since 2.0
*/
public Integer mavenCompilerSource() {
var value = get(MAVEN_COMPILER_SOURCE);
if (value == null) {
return null;
}
return Integer.parseInt(value);
}
/**
* Sets the value of the 'maven.compiler.target' property.
*
* @param value the value to be set for the 'maven.compiler.target' property
* @return this {@code PomProperties} instance
* @since 2.0
*/
public PublishProperties mavenCompilerTarget(Integer value) {
if (value == null) {
remove(MAVEN_COMPILER_TARGET);
}
else {
put(MAVEN_COMPILER_TARGET, String.valueOf(value));
}
return this;
}
/**
* Retrieves the value of the 'maven.compiler.target' property.
*
* @return the value of the 'maven.compiler.target' property
* @since 2.0
*/
public Integer mavenCompilerTarget() {
var value = get(MAVEN_COMPILER_TARGET);
if (value == null) {
return null;
}
return Integer.parseInt(value);
}
}

View file

@ -18,6 +18,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.*; import java.util.*;
import java.util.jar.*; import java.util.jar.*;
import java.util.regex.MatchResult;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static rife.tools.FileUtils.JAR_FILE_PATTERN; import static rife.tools.FileUtils.JAR_FILE_PATTERN;
@ -32,32 +33,53 @@ import static rife.tools.FileUtils.JAVA_FILE_PATTERN;
* @since 1.5 * @since 1.5
*/ */
public class Wrapper { public class Wrapper {
private enum LaunchMode {
Cli,
Build
}
public static final String BUILD_ARGUMENT = "--build";
public static final String OFFLINE_ARGUMENT = "--offline";
public static final String WRAPPER_PREFIX = "bld-wrapper";
public static final String WRAPPER_PROPERTIES = WRAPPER_PREFIX + ".properties";
static final String MAVEN_CENTRAL = "https://repo1.maven.org/maven2/"; static final String MAVEN_CENTRAL = "https://repo1.maven.org/maven2/";
static final String SONATYPE_SNAPSHOTS = "https://s01.oss.sonatype.org/content/repositories/snapshots/"; static final String CENTRAL_SNAPSHOTS = "https://central.sonatype.com/repository/maven-snapshots/";
static final String DOWNLOAD_LOCATION = MAVEN_CENTRAL + "com/uwyn/rife2/bld/${version}/"; static final String DOWNLOAD_LOCATION = MAVEN_CENTRAL + "com/uwyn/rife2/bld/${version}/";
static final String DOWNLOAD_LOCATION_SNAPSHOT = SONATYPE_SNAPSHOTS + "com/uwyn/rife2/bld/${version}/"; static final String DOWNLOAD_LOCATION_SNAPSHOT = CENTRAL_SNAPSHOTS + "com/uwyn/rife2/bld/${version}/";
static final String BLD_CACHE = "bld.cache";
static final String BLD_FILENAME = "bld-${version}.jar"; static final String BLD_FILENAME = "bld-${version}.jar";
static final String BLD_SOURCES_FILENAME = "bld-${version}-sources.jar"; static final String BLD_SOURCES_FILENAME = "bld-${version}-sources.jar";
static final String BLD_VERSION = "BLD_VERSION"; static final String BLD_VERSION = "BLD_VERSION";
static final String BLD_BUILD_HASH = "bld-build.hash";
static final String WRAPPER_PREFIX = "bld-wrapper";
static final String WRAPPER_PROPERTIES = WRAPPER_PREFIX + ".properties";
static final String WRAPPER_JAR = WRAPPER_PREFIX + ".jar"; static final String WRAPPER_JAR = WRAPPER_PREFIX + ".jar";
static final String BLD_PROPERTY_VERSION = "bld.version"; static final String BLD_PROPERTY_VERSION = "bld.version";
static final String RIFE2_PROPERTY_DOWNLOAD_LOCATION = "rife2.downloadLocation"; static final String RIFE2_PROPERTY_DOWNLOAD_LOCATION = "rife2.downloadLocation";
static final String BLD_PROPERTY_DOWNLOAD_LOCATION = "bld.downloadLocation"; static final String BLD_PROPERTY_DOWNLOAD_LOCATION = "bld.downloadLocation";
static final String PROPERTY_REPOSITORIES = "bld.repositories"; static final String PROPERTY_REPOSITORIES = "bld.repositories";
static final String PROPERTY_EXTENSION_PREFIX = "bld.extension"; static final String PROPERTY_EXTENSION_PREFIX = "bld.extension";
static final String PROPERTY_EXTENSIONS = "bld.extensions";
static final String PROPERTY_DOWNLOAD_EXTENSION_SOURCES = "bld.downloadExtensionSources"; static final String PROPERTY_DOWNLOAD_EXTENSION_SOURCES = "bld.downloadExtensionSources";
static final String PROPERTY_DOWNLOAD_EXTENSION_JAVADOC = "bld.downloadExtensionJavadoc"; static final String PROPERTY_DOWNLOAD_EXTENSION_JAVADOC = "bld.downloadExtensionJavadoc";
static final String PROPERTY_SOURCE_DIRECTORIES = "bld.sourceDirectories"; static final String PROPERTY_SOURCE_DIRECTORIES = "bld.sourceDirectories";
static final String PROPERTY_JAVAC_OPTIONS = "bld.javacOptions";
static final String PROPERTY_JAVA_OPTIONS = "bld.javaOptions";
static final File BLD_USER_DIR = new File(System.getProperty("user.home"), ".bld"); static final File BLD_USER_DIR = new File(System.getProperty("user.home"), ".bld");
static final File DISTRIBUTIONS_DIR = new File(BLD_USER_DIR, "dist"); static final File DISTRIBUTIONS_DIR = new File(BLD_USER_DIR, "dist");
static final Pattern META_DATA_LOCAL_COPY = Pattern.compile("<localCopy>\\s*true\\s*</localCopy>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
static final Pattern META_DATA_SNAPSHOT_VERSION = Pattern.compile("<snapshotVersion>.*?<value>([^<]+)</value>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE); static final Pattern META_DATA_SNAPSHOT_VERSION = Pattern.compile("<snapshotVersion>.*?<value>([^<]+)</value>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
static final Pattern OPTIONS_PATTERN = Pattern.compile("\"[^\"]+\"|\\S+");
static final Pattern JVM_PROPERTY_PATTERN = Pattern.compile("-D(.+?)=(.*)");
private static final Pattern JAR_EXCLUDE_SOURCES_PATTERN = Pattern.compile("^.*-sources\\.jar$", Pattern.CASE_INSENSITIVE);
private static final Pattern JAR_EXCLUDE_JAVADOC_PATTERN = Pattern.compile("^.*-javadoc\\.jar$", Pattern.CASE_INSENSITIVE);
private static final Pattern[] CLASSPATH_INCLUDED_JARS = new Pattern[]{JAR_FILE_PATTERN};
private static final Pattern[] CLASSPATH_EXCLUDED_JARS = new Pattern[]{JAR_EXCLUDE_SOURCES_PATTERN, JAR_EXCLUDE_JAVADOC_PATTERN, Pattern.compile(WRAPPER_JAR)};
private File currentDir_ = new File(System.getProperty("user.dir")); private File currentDir_ = new File(System.getProperty("user.dir"));
private LaunchMode launchMode_ = LaunchMode.Cli;
private boolean offline_ = false;
private final Properties jvmProperties_ = new Properties();
private final Properties wrapperProperties_ = new Properties(); private final Properties wrapperProperties_ = new Properties();
private File wrapperPropertiesFile_ = null; private File wrapperPropertiesFile_ = null;
private final Set<String> repositories_ = new LinkedHashSet<>(); private final Set<String> repositories_ = new LinkedHashSet<>();
@ -98,6 +120,10 @@ public class Wrapper {
private static final Pattern BLD_JAR_PATTERN = Pattern.compile("/\\.bld/dist/bld-[^\"/!]+(?<!sources)\\.jar"); private static final Pattern BLD_JAR_PATTERN = Pattern.compile("/\\.bld/dist/bld-[^\"/!]+(?<!sources)\\.jar");
private static final Pattern BLD_SOURCES_JAR_PATTERN = Pattern.compile("/\\.bld/dist/bld-[^\"/!]+-sources\\.jar"); private static final Pattern BLD_SOURCES_JAR_PATTERN = Pattern.compile("/\\.bld/dist/bld-[^\"/!]+-sources\\.jar");
private static final Pattern BLD_PROPERTY_VERSION_PATTERN = Pattern.compile(".*bld\\.version.*"); private static final Pattern BLD_PROPERTY_VERSION_PATTERN = Pattern.compile(".*bld\\.version.*");
private static final Pattern JAR_DIRECTORY_LIB_COMPILE_RECURSIVE_PATTERN = Pattern.compile("<jarDirectory\\s+url=\"file://\\$PROJECT_DIR\\$/lib/compile\"\\s+recursive=\"false\"");
private static final Pattern JAR_DIRECTORY_LIB_PROVIDED_RECURSIVE_PATTERN = Pattern.compile("<jarDirectory\\s+url=\"file://\\$PROJECT_DIR\\$/lib/provided\"\\s+recursive=\"false\"");
private static final Pattern JAR_DIRECTORY_LIB_RUNTIME_RECURSIVE_PATTERN = Pattern.compile("<jarDirectory\\s+url=\"file://\\$PROJECT_DIR\\$/lib/runtime\"\\s+recursive=\"false\"");
private static final Pattern JAR_DIRECTORY_LIB_TEST_RECURSIVE_PATTERN = Pattern.compile("<jarDirectory\\s+url=\"file://\\$PROJECT_DIR\\$/lib/test\"\\s+recursive=\"false\"");
/** /**
* Upgraded the IDEA bld files that were generated with a previous version. * Upgraded the IDEA bld files that were generated with a previous version.
@ -109,15 +135,50 @@ public class Wrapper {
*/ */
public void upgradeIdeaBldLibrary(File destinationDirectory, String version) public void upgradeIdeaBldLibrary(File destinationDirectory, String version)
throws IOException { throws IOException {
var file = new File(destinationDirectory, Path.of("libraries", "bld.xml").toString()); var libraries_bld = new File(destinationDirectory, Path.of("libraries", "bld.xml").toString());
if (file.exists()) { if (libraries_bld.exists()) {
try { try {
var content = FileUtils.readString(file); var content = FileUtils.readString(libraries_bld);
content = BLD_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + ".jar"); content = BLD_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + ".jar");
content = BLD_SOURCES_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + "-sources.jar"); content = BLD_SOURCES_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + "-sources.jar");
content = RIFE2_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + ".jar"); content = RIFE2_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + ".jar");
content = RIFE2_SOURCES_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + "-sources.jar"); content = RIFE2_SOURCES_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + "-sources.jar");
FileUtils.writeString(content, file); FileUtils.writeString(content, libraries_bld);
} catch (FileUtilsErrorException e) {
throw new IOException(e);
}
}
var libraries_compile = new File(destinationDirectory, Path.of("libraries", "compile.xml").toString());
if (libraries_compile.exists()) {
try {
var content = FileUtils.readString(libraries_compile);
content = JAR_DIRECTORY_LIB_COMPILE_RECURSIVE_PATTERN.matcher(content).replaceAll("<jarDirectory url=\"file://\\$PROJECT_DIR\\$/lib/compile\" recursive=\"true\"");
content = JAR_DIRECTORY_LIB_PROVIDED_RECURSIVE_PATTERN.matcher(content).replaceAll("<jarDirectory url=\"file://\\$PROJECT_DIR\\$/lib/provided\" recursive=\"true\"");
FileUtils.writeString(content, libraries_compile);
} catch (FileUtilsErrorException e) {
throw new IOException(e);
}
}
var libraries_runtime = new File(destinationDirectory, Path.of("libraries", "runtime.xml").toString());
if (libraries_runtime.exists()) {
try {
var content = FileUtils.readString(libraries_runtime);
content = JAR_DIRECTORY_LIB_RUNTIME_RECURSIVE_PATTERN.matcher(content).replaceAll("<jarDirectory url=\"file://\\$PROJECT_DIR\\$/lib/runtime\" recursive=\"true\"");
FileUtils.writeString(content, libraries_runtime);
} catch (FileUtilsErrorException e) {
throw new IOException(e);
}
}
var libraries_test = new File(destinationDirectory, Path.of("libraries", "test.xml").toString());
if (libraries_test.exists()) {
try {
var content = FileUtils.readString(libraries_test);
content = JAR_DIRECTORY_LIB_PROVIDED_RECURSIVE_PATTERN.matcher(content).replaceAll("<jarDirectory url=\"file://\\$PROJECT_DIR\\$/lib/provided\" recursive=\"true\"");
content = JAR_DIRECTORY_LIB_TEST_RECURSIVE_PATTERN.matcher(content).replaceAll("<jarDirectory url=\"file://\\$PROJECT_DIR\\$/lib/test\" recursive=\"true\"");
FileUtils.writeString(content, libraries_test);
} catch (FileUtilsErrorException e) { } catch (FileUtilsErrorException e) {
throw new IOException(e); throw new IOException(e);
} }
@ -138,8 +199,8 @@ public class Wrapper {
if (file.exists()) { if (file.exists()) {
try { try {
var content = FileUtils.readString(file); var content = FileUtils.readString(file);
content = BLD_JAR_PATTERN.matcher(content).replaceAll("bld-" + version + ".jar"); content = BLD_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + ".jar");
content = RIFE2_JAR_PATTERN.matcher(content).replaceAll("bld-" + version + ".jar"); content = RIFE2_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + ".jar");
FileUtils.writeString(content, file); FileUtils.writeString(content, file);
} catch (FileUtilsErrorException e) { } catch (FileUtilsErrorException e) {
throw new IOException(e); throw new IOException(e);
@ -164,9 +225,11 @@ public class Wrapper {
var properties_blueprint = """ var properties_blueprint = """
bld.downloadExtensionJavadoc=false bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true bld.downloadExtensionSources=true
bld.extensions=
bld.repositories=MAVEN_CENTRAL,RIFE2
bld.downloadLocation= bld.downloadLocation=
bld.extensions=
bld.javaOptions=
bld.javacOptions=
bld.repositories=MAVEN_CENTRAL,RIFE2_RELEASES
bld.sourceDirectories= bld.sourceDirectories=
bld.version=${version} bld.version=${version}
""" """
@ -190,6 +253,7 @@ public class Wrapper {
try (var jar = new JarOutputStream(new FileOutputStream(new File(destinationDirectory, WRAPPER_JAR)), manifest)) { try (var jar = new JarOutputStream(new FileOutputStream(new File(destinationDirectory, WRAPPER_JAR)), manifest)) {
addClassToJar(jar, Wrapper.class); addClassToJar(jar, Wrapper.class);
addClassToJar(jar, Wrapper.LaunchMode.class);
addClassToJar(jar, WrapperClassLoader.class); addClassToJar(jar, WrapperClassLoader.class);
addClassToJar(jar, FileUtils.class); addClassToJar(jar, FileUtils.class);
addClassToJar(jar, FileUtilsErrorException.class); addClassToJar(jar, FileUtilsErrorException.class);
@ -199,6 +263,107 @@ public class Wrapper {
} }
} }
/**
* Sets the current directory for the wrapper.
*
* @param dir the directory to set as the current directory
* @since 2.0
*/
public void currentDir(File dir) {
currentDir_ = dir;
}
/**
* Initializes the properties set for the wrapper.
*
* @param version the bld version they should be using
* @throws IOException when an error occurred during the creation of the wrapper files
* @since 2.0
*/
public void initWrapperProperties(String version)
throws IOException {
// ensure required properties are available
wrapperProperties_.put(PROPERTY_REPOSITORIES, MAVEN_CENTRAL);
wrapperProperties_.put(BLD_PROPERTY_VERSION, version);
// retrieve properties from possible locations
var config = libBldDirectory(WRAPPER_PROPERTIES);
if (config.exists()) {
wrapperPropertiesFile_ = config;
wrapperProperties_.load(new FileReader(config));
} else {
config = libDirectory(WRAPPER_PROPERTIES);
if (config.exists()) {
wrapperPropertiesFile_ = config;
wrapperProperties_.load(new FileReader(config));
}
}
// extract repositories
if (wrapperProperties_.containsKey(PROPERTY_REPOSITORIES)) {
for (var repository : wrapperProperties_.getProperty(PROPERTY_REPOSITORIES).split(",")) {
repository = repository.trim();
if (!repository.isBlank()) {
repositories_.add(repository);
}
}
}
// extract wrapper extension specifications
for (var property : wrapperProperties_.entrySet()) {
if (property.getKey().toString().startsWith(PROPERTY_EXTENSION_PREFIX)) {
for (var extension : property.getValue().toString().split(",")) {
extension = extension.trim();
if (!extension.isBlank()) {
extensions_.add(extension);
}
}
}
}
// check whether extension sources or javadoc should be downloaded
downloadExtensionSources_ = Boolean.parseBoolean(wrapperProperties_.getProperty(PROPERTY_DOWNLOAD_EXTENSION_SOURCES, "false"));
downloadExtensionJavadoc_ = Boolean.parseBoolean(wrapperProperties_.getProperty(PROPERTY_DOWNLOAD_EXTENSION_JAVADOC, "false"));
}
/**
* Returns the set of extension repositories.
*
* @return the set of extension repositories
* @since 2.0
*/
public Set<String> repositories() {
return repositories_;
}
/**
* Returns the set of extensions.
*
* @return the set of extensions
* @since 2.0
*/
public Set<String> extensions() {
return extensions_;
}
/**
* Returns the wrapper properties.
*
* @return the wrapper properties
* @since 2.0
*/
public Properties wrapperProperties() {
return wrapperProperties_;
}
/**
* Returns the wrapper properties file.
*
* @return the wrapper properties file
* @since 2.0
*/
public File wrapperPropertiesFile() {
return wrapperPropertiesFile_;
}
private void addClassToJar(JarOutputStream jar, Class klass) private void addClassToJar(JarOutputStream jar, Class klass)
throws IOException { throws IOException {
addFileToJar(jar, klass.getName().replace('.', '/') + ".class"); addFileToJar(jar, klass.getName().replace('.', '/') + ".class");
@ -249,28 +414,49 @@ public class Wrapper {
private int installAndLaunch(List<String> arguments) { private int installAndLaunch(List<String> arguments) {
if (!arguments.isEmpty()) { if (!arguments.isEmpty()) {
File current_file = null; File current_file;
try { try {
current_file = new File(arguments.remove(0)).getCanonicalFile(); current_file = new File(arguments.remove(0)).getCanonicalFile();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
currentDir_ = new File(current_file.getParent()); currentDir_ = new File(current_file.getParent());
if (!arguments.isEmpty() &&
BUILD_ARGUMENT.equals(arguments.get(0))) {
launchMode_ = LaunchMode.Build;
arguments.remove(0);
} }
// first argument after the --build argument is the main build file
// arguments.get(0)
// check if the next argument enables offline mode
if (arguments.size() >= 2 &&
OFFLINE_ARGUMENT.equals(arguments.get(1))) {
offline_ = true;
}
}
try { try {
extractJvmProperties(arguments);
initWrapperProperties(getVersion()); initWrapperProperties(getVersion());
File distribution; var distribution = installDistribution();
try {
distribution = installDistribution();
} catch (IOException e) {
return -1;
}
return launchMain(distribution, arguments); return launchMain(distribution, arguments);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private void extractJvmProperties(List<String> arguments) {
for (var arg : arguments) {
var matcher = JVM_PROPERTY_PATTERN.matcher(arg);
if (matcher.matches()) {
jvmProperties_.put(matcher.group(1), matcher.group(2));
}
}
}
private File buildBldDirectory() { private File buildBldDirectory() {
return Path.of(currentDir_.getAbsolutePath(), "build", "bld").toFile(); return Path.of(currentDir_.getAbsolutePath(), "build", "bld").toFile();
} }
@ -295,50 +481,6 @@ public class Wrapper {
return Path.of(currentDir_.getAbsolutePath(), "lib", "bld", path).toFile(); return Path.of(currentDir_.getAbsolutePath(), "lib", "bld", path).toFile();
} }
private void initWrapperProperties(String version)
throws IOException {
// ensure required properties are available
wrapperProperties_.put(PROPERTY_REPOSITORIES, MAVEN_CENTRAL);
wrapperProperties_.put(BLD_PROPERTY_VERSION, version);
// retrieve properties from possible locations
var config = libBldDirectory(WRAPPER_PROPERTIES);
if (config.exists()) {
wrapperPropertiesFile_ = config;
wrapperProperties_.load(new FileReader(config));
} else {
config = libDirectory(WRAPPER_PROPERTIES);
if (config.exists()) {
wrapperPropertiesFile_ = config;
wrapperProperties_.load(new FileReader(config));
}
}
// extract repositories
if (wrapperProperties_.containsKey(PROPERTY_REPOSITORIES)) {
for (var repository : wrapperProperties_.getProperty(PROPERTY_REPOSITORIES).split(",")) {
repository = repository.trim();
if (!repository.isBlank()) {
repositories_.add(repository);
}
}
}
// extract wrapper extension specifications
for (var property : wrapperProperties_.entrySet()) {
if (property.getKey().toString().startsWith(PROPERTY_EXTENSION_PREFIX)) {
for (var extension : property.getValue().toString().split(",")) {
extension = extension.trim();
if (!extension.isBlank()) {
extensions_.add(extension);
}
}
}
}
// check whether extension sources or javadoc should be downloaded
downloadExtensionSources_ = Boolean.parseBoolean(wrapperProperties_.getProperty(PROPERTY_DOWNLOAD_EXTENSION_SOURCES, "false"));
downloadExtensionJavadoc_ = Boolean.parseBoolean(wrapperProperties_.getProperty(PROPERTY_DOWNLOAD_EXTENSION_JAVADOC, "false"));
}
private String getWrapperVersion() private String getWrapperVersion()
throws IOException { throws IOException {
return wrapperProperties_.getProperty(BLD_PROPERTY_VERSION, getVersion()); return wrapperProperties_.getProperty(BLD_PROPERTY_VERSION, getVersion());
@ -364,7 +506,7 @@ public class Wrapper {
var location = getWrapperDownloadLocation(version); var location = getWrapperDownloadLocation(version);
var result = new StringBuilder(location); var result = new StringBuilder(location);
if (!location.endsWith("/")) { if (!location.endsWith("/")) {
result.append("/"); result.append('/');
} }
result.append(fileName); result.append(fileName);
return result.toString(); return result.toString();
@ -401,32 +543,63 @@ public class Wrapper {
var download_version = version; var download_version = version;
var is_snapshot = isSnapshot(version); var is_snapshot = isSnapshot(version);
var is_local = false;
if (offline_) {
System.out.println("Offline mode: no artifacts will be checked nor downloaded");
System.out.flush();
}
else {
if (is_snapshot) { if (is_snapshot) {
var meta_data = readString(version, new URL(downloadUrl(version, "maven-metadata.xml"))); var meta_data = "";
var matcher = META_DATA_SNAPSHOT_VERSION.matcher(meta_data); try {
if (matcher.find()) { meta_data = readString(version, new URL(downloadUrl(version, "maven-metadata.xml")));
download_version = matcher.group(1); } catch (IOException e) {
try {
meta_data = readString(version, new URL(downloadUrl(version, "maven-metadata-local.xml")));
} catch (IOException e2) {
throw e;
}
}
var local_matcher = META_DATA_LOCAL_COPY.matcher(meta_data);
is_local = local_matcher.find();
if (!is_local) {
var version_matcher = META_DATA_SNAPSHOT_VERSION.matcher(meta_data);
if (version_matcher.find()) {
download_version = version_matcher.group(1);
}
}
} }
} }
var distribution_file = new File(DISTRIBUTIONS_DIR, bldFileName(version)); var distribution_file = new File(DISTRIBUTIONS_DIR, bldFileName(version));
var distribution_sources_file = new File(DISTRIBUTIONS_DIR, bldSourcesFileName(version)); var distribution_sources_file = new File(DISTRIBUTIONS_DIR, bldSourcesFileName(version));
if (!offline_) {
// if this is a snapshot and the distribution file exists, // if this is a snapshot and the distribution file exists,
// ensure that it's the latest by comparing hashes // ensure that it's the latest by comparing hashes
if (is_snapshot && distribution_file.exists()) { if (is_snapshot && distribution_file.exists()) {
boolean delete_distribution_files = is_local;
if (!delete_distribution_files) {
var download_md5 = readString(version, new URL(downloadUrl(version, bldFileName(download_version)) + ".md5")); var download_md5 = readString(version, new URL(downloadUrl(version, bldFileName(download_version)) + ".md5"));
try { try {
var digest = MessageDigest.getInstance("MD5"); var digest = MessageDigest.getInstance("MD5");
digest.update(FileUtils.readBytes(distribution_file)); digest.update(FileUtils.readBytes(distribution_file));
if (!download_md5.equals(encodeHexLower(digest.digest()))) { if (!download_md5.equals(encodeHexLower(digest.digest()))) {
distribution_file.delete(); delete_distribution_files = true;
distribution_sources_file.delete();
} }
} catch (NoSuchAlgorithmException ignore) { } catch (NoSuchAlgorithmException ignore) {
} }
} }
if (delete_distribution_files) {
distribution_file.delete();
if (distribution_sources_file.exists()) {
distribution_sources_file.delete();
}
}
}
// download distribution jars if necessary // download distribution jars if necessary
if (!distribution_file.exists()) { if (!distribution_file.exists()) {
downloadDistribution(distribution_file, downloadUrl(version, bldFileName(download_version))); downloadDistribution(distribution_file, downloadUrl(version, bldFileName(download_version)));
@ -438,6 +611,7 @@ public class Wrapper {
// this is not critical, ignore // this is not critical, ignore
} }
} }
}
// find the wrapper classloader in the hierarchy and add the bld jar to it // find the wrapper classloader in the hierarchy and add the bld jar to it
classloader_ = new WrapperClassLoader(); classloader_ = new WrapperClassLoader();
@ -475,15 +649,17 @@ public class Wrapper {
private void resolveExtensions() { private void resolveExtensions() {
if (null == classloader_ || if (null == classloader_ ||
null == wrapperPropertiesFile_) { null == wrapperPropertiesFile_ ||
offline_) {
return; return;
} }
try { try {
var resolver_class = classloader_.loadClass("rife.bld.wrapper.WrapperExtensionResolver"); var resolver_class = classloader_.loadClass("rife.bld.wrapper.WrapperExtensionResolver");
var constructor = resolver_class.getConstructor(File.class, File.class, File.class, Collection.class, Collection.class, boolean.class, boolean.class); var constructor = resolver_class.getConstructor(File.class, File.class, Properties.class, Properties.class, Collection.class, Collection.class, boolean.class, boolean.class);
var update_method = resolver_class.getMethod("updateExtensions"); var update_method = resolver_class.getMethod("updateExtensions");
var resolver = constructor.newInstance(currentDir_, new File(wrapperPropertiesFile_.getAbsolutePath() + ".hash"), libBldDirectory(), var resolver = constructor.newInstance(currentDir_, libBldDirectory(),
jvmProperties_, wrapperProperties_,
repositories_, extensions_, repositories_, extensions_,
downloadExtensionSources_, downloadExtensionJavadoc_); downloadExtensionSources_, downloadExtensionJavadoc_);
update_method.invoke(resolver); update_method.invoke(resolver);
@ -496,7 +672,7 @@ public class Wrapper {
private int launchMain(File jarFile, List<String> arguments) private int launchMain(File jarFile, List<String> arguments)
throws IOException, InterruptedException, FileUtilsErrorException { throws IOException, InterruptedException, FileUtilsErrorException {
if (arguments.isEmpty() || !arguments.get(0).equals("--build")) { if (launchMode_ == LaunchMode.Cli) {
return launchMainCli(jarFile, arguments); return launchMainCli(jarFile, arguments);
} }
return launchMainBuild(jarFile, arguments); return launchMainBuild(jarFile, arguments);
@ -505,8 +681,8 @@ public class Wrapper {
private int launchMainCli(File jarFile, List<String> arguments) private int launchMainCli(File jarFile, List<String> arguments)
throws IOException, InterruptedException { throws IOException, InterruptedException {
var args = new ArrayList<String>(); var args = new ArrayList<String>();
args.add("java"); args.add(findJavaExecutable());
includeJvmParameters(arguments, args); includeJvmProperties(arguments, args);
args.add("-cp"); args.add("-cp");
args.add(jarFile.getAbsolutePath()); args.add(jarFile.getAbsolutePath());
@ -514,6 +690,7 @@ public class Wrapper {
args.add("-jar"); args.add("-jar");
args.add(jarFile.getAbsolutePath()); args.add(jarFile.getAbsolutePath());
args.addAll(bldJavaOptions());
args.addAll(arguments); args.addAll(arguments);
var process_builder = new ProcessBuilder(args); var process_builder = new ProcessBuilder(args);
@ -526,8 +703,6 @@ public class Wrapper {
throws IOException, InterruptedException { throws IOException, InterruptedException {
resolveExtensions(); resolveExtensions();
arguments.remove(0);
var build_bld_dir = buildBldDirectory(); var build_bld_dir = buildBldDirectory();
if (build_bld_dir.exists()) { if (build_bld_dir.exists()) {
FileUtils.deleteDirectory(buildBldDirectory()); FileUtils.deleteDirectory(buildBldDirectory());
@ -545,6 +720,7 @@ public class Wrapper {
var compilation_units = file_manager.getJavaFileObjectsFromFiles(bldSourceFiles()); var compilation_units = file_manager.getJavaFileObjectsFromFiles(bldSourceFiles());
var diagnostics = new DiagnosticCollector<JavaFileObject>(); var diagnostics = new DiagnosticCollector<JavaFileObject>();
var options = new ArrayList<>(List.of("-d", buildBldDirectory().getAbsolutePath(), "-cp", classpath)); var options = new ArrayList<>(List.of("-d", buildBldDirectory().getAbsolutePath(), "-cp", classpath));
options.addAll(bldJavacOptions());
var compilation_task = compiler.getTask(null, file_manager, diagnostics, options, null, compilation_units); var compilation_task = compiler.getTask(null, file_manager, diagnostics, options, null, compilation_units);
if (!compilation_task.call()) { if (!compilation_task.call()) {
if (!diagnostics.getDiagnostics().isEmpty()) { if (!diagnostics.getDiagnostics().isEmpty()) {
@ -558,11 +734,15 @@ public class Wrapper {
} }
var java_args = new ArrayList<String>(); var java_args = new ArrayList<String>();
java_args.add("java"); java_args.add(findJavaExecutable());
includeJvmParameters(arguments, java_args); includeJvmProperties(arguments, java_args);
java_args.add("-cp"); java_args.add("-cp");
java_args.add(classpath); java_args.add(classpath);
java_args.addAll(bldJavaOptions());
java_args.addAll(arguments); java_args.addAll(arguments);
var process_builder = new ProcessBuilder(java_args); var process_builder = new ProcessBuilder(java_args);
process_builder.directory(currentDir_); process_builder.directory(currentDir_);
process_builder.inheritIO(); process_builder.inheritIO();
@ -571,11 +751,20 @@ public class Wrapper {
return process.waitFor(); return process.waitFor();
} }
private static void includeJvmParameters(List<String> arguments, List<String> javaArgs) { private static String findJavaExecutable() {
var executable = System.getProperty("os.name").toLowerCase().contains("win") ? "java.exe" : "java";
var java_home = System.getProperty("java.home");
if (null == java_home) {
return executable;
}
return java_home + File.separator + "bin" + File.separator + executable;
}
private static void includeJvmProperties(List<String> arguments, List<String> javaArgs) {
var i = arguments.iterator(); var i = arguments.iterator();
while (i.hasNext()) { while (i.hasNext()) {
var arg = i.next(); var arg = i.next();
if (arg.matches("-D(.+?)=(.*)")) { if (JVM_PROPERTY_PATTERN.matcher(arg).matches()) {
javaArgs.add(arg); javaArgs.add(arg);
i.remove(); i.remove();
} }
@ -585,7 +774,7 @@ public class Wrapper {
private List<File> bldClasspathJars() { private List<File> bldClasspathJars() {
// detect the jar files in the compile lib directory // detect the jar files in the compile lib directory
var dir_abs = libBldDirectory().getAbsoluteFile(); var dir_abs = libBldDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, JAR_FILE_PATTERN, Pattern.compile(WRAPPER_JAR)); var jar_files = FileUtils.getFileList(dir_abs, CLASSPATH_INCLUDED_JARS, CLASSPATH_EXCLUDED_JARS);
// build the compilation classpath // build the compilation classpath
return new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList()); return new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
@ -615,6 +804,28 @@ public class Wrapper {
return source_files; return source_files;
} }
public List<String> bldJavacOptions() {
if (!wrapperProperties_.containsKey(PROPERTY_JAVAC_OPTIONS)) {
return Collections.emptyList();
}
return OPTIONS_PATTERN.matcher(wrapperProperties_.get(PROPERTY_JAVAC_OPTIONS).toString())
.results()
.map(MatchResult::group)
.toList();
}
public List<String> bldJavaOptions() {
if (!wrapperProperties_.containsKey(PROPERTY_JAVA_OPTIONS)) {
return Collections.emptyList();
}
return OPTIONS_PATTERN.matcher(wrapperProperties_.get(PROPERTY_JAVA_OPTIONS).toString())
.results()
.map(MatchResult::group)
.toList();
}
private String readString(String version, URL url) private String readString(String version, URL url)
throws IOException { throws IOException {
var connection = url.openConnection(); var connection = url.openConnection();

View file

@ -4,16 +4,12 @@
*/ */
package rife.bld.wrapper; package rife.bld.wrapper;
import rife.bld.BldCache;
import rife.bld.BuildExecutor; import rife.bld.BuildExecutor;
import rife.bld.dependencies.*; import rife.bld.dependencies.*;
import rife.tools.FileUtils; import rife.ioc.HierarchicalProperties;
import rife.tools.StringUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File; import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*; import java.util.*;
import static rife.bld.dependencies.Dependency.CLASSIFIER_JAVADOC; import static rife.bld.dependencies.Dependency.CLASSIFIER_JAVADOC;
@ -28,9 +24,8 @@ import static rife.bld.dependencies.Dependency.CLASSIFIER_SOURCES;
* @since 1.5.8 * @since 1.5.8
*/ */
public class WrapperExtensionResolver { public class WrapperExtensionResolver {
private final ArtifactRetriever retriever_ = ArtifactRetriever.cachingInstance(); private final VersionResolution resolution_;
private final File hashFile_; private final ArtifactRetriever retriever_;
private final String fingerPrintHash_;
private final File destinationDirectory_; private final File destinationDirectory_;
private final List<Repository> repositories_ = new ArrayList<>(); private final List<Repository> repositories_ = new ArrayList<>();
private final DependencySet dependencies_ = new DependencySet(); private final DependencySet dependencies_ = new DependencySet();
@ -40,39 +35,41 @@ public class WrapperExtensionResolver {
private boolean headerPrinted_ = false; private boolean headerPrinted_ = false;
public WrapperExtensionResolver(File currentDir, File hashFile, File destinationDirectory, public WrapperExtensionResolver(File currentDir, File destinationDirectory,
Properties jvmProperties, Properties wrapperProperties,
Collection<String> repositories, Collection<String> extensions, Collection<String> repositories, Collection<String> extensions,
boolean downloadSources, boolean downloadJavadoc) { boolean downloadSources, boolean downloadJavadoc) {
var properties = BuildExecutor.setupProperties(currentDir); var properties = BuildExecutor.setupProperties(currentDir);
properties.getRoot().putAll(jvmProperties);
properties = new HierarchicalProperties().parent(properties);
properties.putAll(wrapperProperties);
resolution_ = new VersionResolution(properties);
retriever_ = ArtifactRetriever.cachingInstance();
Repository.resolveMavenLocal(properties); Repository.resolveMavenLocal(properties);
hashFile_ = hashFile;
destinationDirectory_ = destinationDirectory; destinationDirectory_ = destinationDirectory;
for (var repository : repositories) { for (var repository : repositories) {
repositories_.add(Repository.resolveRepository(properties, repository)); repositories_.add(Repository.resolveRepository(properties, repository));
} }
dependencies_.addAll(extensions.stream().map(Dependency::parse).toList());
dependencies_.addAll(extensions.stream().map(d -> resolution_.overrideDependency(Dependency.parse(d))).toList());
downloadSources_ = downloadSources; downloadSources_ = downloadSources;
downloadJavadoc_ = downloadJavadoc; downloadJavadoc_ = downloadJavadoc;
fingerPrintHash_ = createHash(repositories_.stream().map(Objects::toString).toList(), extensions, downloadSources, downloadJavadoc);
}
private String createHash(Collection<String> repositories, Collection<String> extensions, boolean downloadSources, boolean downloadJavadoc) {
try {
var fingerprint = String.join("\n", repositories) + "\n" + String.join("\n", extensions) + "\n" + downloadSources + "\n" + downloadJavadoc;
var digest = MessageDigest.getInstance("SHA-1");
digest.update(fingerprint.getBytes(StandardCharsets.UTF_8));
return StringUtils.encodeHexLower(digest.digest());
} catch (NoSuchAlgorithmException e) {
// should not happen
throw new RuntimeException(e);
}
} }
public void updateExtensions() { public void updateExtensions() {
// verify and update the fingerprint hash file, // verify and update the fingerprint hash file,
// don't update the extensions if the hash is identical // don't update the extensions if the hash is identical
if (validateHash()) { var cache = new BldCache(destinationDirectory_, resolution_);
cache.cacheExtensionsHash(
repositories_.stream().map(Objects::toString).toList(),
dependencies_.stream().map(Objects::toString).toList());
cache.cacheExtensionsDownloads(downloadSources_, downloadJavadoc_);
if (cache.isExtensionsCacheValid()) {
return; return;
} }
@ -82,74 +79,20 @@ public class WrapperExtensionResolver {
// purge the files that are not part of the latest extensions anymore // purge the files that are not part of the latest extensions anymore
purgeExtensionDependencies(filenames); purgeExtensionDependencies(filenames);
writeHash(); cache.cacheExtensionsLocalArtifacts(localArtifacts_);
cache.writeCache();
if (headerPrinted_) { if (headerPrinted_) {
System.out.println(); System.out.println();
} }
} }
private boolean validateHash() {
try {
if (hashFile_.exists()) {
var contents = FileUtils.readString(hashFile_);
var lines = StringUtils.split(contents, "\n");
if (!lines.isEmpty()) {
// first line is the fingerprint hash
if (lines.remove(0).equals(fingerPrintHash_)) {
// other lines are last modified timestamps of local files
// that were dependency artifacts
while (!lines.isEmpty()) {
var line = lines.get(0);
var parts = line.split(":", 2);
// verify that the local file has the same modified timestamp still
if (parts.length == 2) {
var file = new File(parts[1]);
if (!file.exists() || !file.canRead() || file.lastModified() != Long.parseLong(parts[0])) {
break;
}
} else {
break;
}
lines.remove(0);
}
// there were no invalid lines, so the hash file contents are valid
if (lines.isEmpty()) {
return true;
}
}
}
hashFile_.delete();
}
return false;
} catch (FileUtilsErrorException e) {
throw new RuntimeException(e);
}
}
private void writeHash() {
try {
var contents = new StringBuilder();
contents.append(fingerPrintHash_);
for (var file : localArtifacts_) {
if (file.exists() && file.canRead()) {
contents.append("\n").append(file.lastModified()).append(":").append(file.getAbsolutePath());
}
}
FileUtils.writeString(contents.toString(), hashFile_);
} catch (FileUtilsErrorException e) {
throw new RuntimeException(e);
}
}
private Set<String> transferExtensionDependencies() { private Set<String> transferExtensionDependencies() {
var filenames = new HashSet<String>(); var filenames = new HashSet<String>();
var dependencies = new DependencySet(); var dependencies = new DependencySet();
for (var d : dependencies_) { for (var d : dependencies_) {
if (d != null) { if (d != null) {
dependencies.addAll(new DependencyResolver(retriever_, repositories_, d).getAllDependencies(Scope.compile, Scope.runtime)); dependencies.addAll(new DependencyResolver(resolution_, retriever_, repositories_, d).getAllDependencies(Scope.compile, Scope.runtime));
} }
} }
if (!dependencies.isEmpty()) { if (!dependencies.isEmpty()) {
@ -166,7 +109,7 @@ public class WrapperExtensionResolver {
additional_classifiers = classifiers.toArray(new String[0]); additional_classifiers = classifiers.toArray(new String[0]);
} }
var artifacts = dependencies.transferIntoDirectory(retriever_, repositories_, destinationDirectory_, additional_classifiers); var artifacts = dependencies.transferIntoDirectory(resolution_, retriever_, repositories_, destinationDirectory_, destinationDirectory_, additional_classifiers);
for (var artifact : artifacts) { for (var artifact : artifacts) {
var location = artifact.location(); var location = artifact.location();
@ -183,7 +126,7 @@ public class WrapperExtensionResolver {
private void purgeExtensionDependencies(Set<String> filenames) { private void purgeExtensionDependencies(Set<String> filenames) {
for (var file : destinationDirectory_.listFiles()) { for (var file : destinationDirectory_.listFiles()) {
if (file.getName().startsWith(Wrapper.WRAPPER_PREFIX) || if (file.getName().startsWith(Wrapper.WRAPPER_PREFIX) ||
file.getName().equals(Wrapper.BLD_BUILD_HASH)) { file.getName().equals(Wrapper.BLD_CACHE)) {
continue; continue;
} }
if (!filenames.contains(file.getName())) { if (!filenames.contains(file.getName())) {

Some files were not shown because too many files have changed in this diff Show more