Compare commits

..

No commits in common. "main" and "1.7.0" have entirely different histories.
main ... 1.7.0

211 changed files with 3818 additions and 20396 deletions

View file

@ -1,12 +0,0 @@
{
"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,11 +2,8 @@ name: bld-ci
on: [push, pull_request, workflow_dispatch]
env:
REPORTS_DIR: "build/test-results/test/"
jobs:
build-linux:
build-bld-project:
runs-on: ubuntu-latest
services:
@ -90,113 +87,24 @@ jobs:
strategy:
matrix:
java-version: [ 17, 20, 21, 22, 23, 24, 25 ]
java-version: [ 17, 19 ]
steps:
- name: Checkout source repository
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
clean: true
submodules: 'true'
fetch-depth: 0
- name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
distribution: 'corretto'
distribution: 'temurin'
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
./bld download compile test
-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
-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,30 +30,29 @@ jobs:
steps:
- name: Checkout source repository
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
clean: true
submodules: 'true'
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
distribution: 'corretto'
distribution: 'zulu'
java-version: 17
- name: Build Javadocs
run: ./bld clean download clean compile javadoc
run: ./bld download clean compile javadoc
- name: Setup Pages
uses: actions/configure-pages@v5
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@v1
with:
# Upload generated Javadocs repository
path: 'build/javadoc/'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v1

View file

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

View file

@ -1,8 +0,0 @@
<?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

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

View file

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

View file

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

View file

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

View file

@ -1,30 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<option name="skipTestSources" value="false" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="19" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build" />
</component>
</project>

View file

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

View file

@ -1,20 +0,0 @@
<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>

View file

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

View file

@ -1,20 +0,0 @@
# 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,9 +1,8 @@
[![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)
[![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)
[![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)
[![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)
[![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/)
[![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)
@ -34,8 +33,7 @@ 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
ends up looking very concise, is easily readable and understood by any IDE.
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.
Nothing else is needed to be able to run it, test it and distribute it:
@ -48,29 +46,34 @@ import java.util.List;
import static rife.bld.dependencies.Repository.*;
import static rife.bld.dependencies.Scope.*;
public class MyAppBuild extends Project {
public MyAppBuild() {
public class MyappBuild extends Project {
public MyappBuild() {
pkg = "com.example";
name = "my-app";
mainClass = "com.example.MyApp";
name = "Myapp";
mainClass = "com.example.MyappMain";
version = version(0,1,0);
downloadSources = true;
repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES);
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)));
.include(dependency("org.junit.jupiter",
"junit-jupiter",
version(5,9,2)))
.include(dependency("org.junit.platform",
"junit-platform-console-standalone",
version(1,9,2)));
}
public static void main(String[] args) {
new MyAppBuild().start(args);
new MyappBuild().start(args);
}
}
```
> **NOTE:** `bld` supports different ways to describe dependencies,
> `dependency("org.junit.jupiter", "junit-jupiter", version(5,11,4))` can for instance also
> be written as `dependency("org.junit.jupiter:junit-jupiter:5.11.4")`. Which format you use,
> `dependency("com.uwyn.rife2", "rife2", version(1,6,3))` can for instance also
> be written as `dependency("com.uwyn.rife2:rife2:1.6.3")`. Which format you use,
> is a matter of personal taste.
# Where does `bld` fit?
@ -91,47 +94,15 @@ significantly reduces the cognitive load, and taking actions immediately
without having to mentally construct a described plan, makes it easier to
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
`bld` lets your build logic get out of the way so that you can focus on writing
applications.
Get started immediately by [installing](https://github.com/rife2/bld/wiki/Installation) `bld`
through Homebrew, SDKMAN!, JBang, zip archive, or run it directly from its jar file.
If you merely want to create a new project, `bld` can also be used by executing this one-liner:
```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).
to post on the [forums](https://github.com/rife2/bld/discussions), to join
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) 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.
**Read more in the [full documentation](https://github.com/rife2/bld/wiki)
and [bld Javadocs](https://rife2.github.io/bld/).**

2
core

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

Binary file not shown.

View file

@ -1,12 +1,9 @@
bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true
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.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.sourceDirectories=core/src/bld/java
bld.version=2.3.0
bld.version=1.7.0

View file

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

View file

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

View file

@ -1,58 +0,0 @@
/**
* 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

@ -1,24 +0,0 @@
<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,17 +5,20 @@
package rife.bld;
import rife.bld.dependencies.*;
import rife.bld.dependencies.Module;
import rife.bld.help.*;
import rife.bld.operations.*;
import rife.tools.FileUtils;
import rife.tools.StringUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.regex.Pattern;
import static rife.bld.dependencies.Scope.runtime;
import static rife.bld.dependencies.VersionNumber.SNAPSHOT_QUALIFIER;
import static rife.tools.FileUtils.JAR_FILE_PATTERN;
/**
@ -55,19 +58,12 @@ public class BaseProject extends BuildExecutor {
*/
protected VersionNumber version = null;
/**
* The project's main class to execute.
* The project's main class.
*
* @see #mainClass()
* @since 1.5
*/
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.
@ -253,27 +249,6 @@ public class BaseProject extends BuildExecutor {
* @since 1.5
*/
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.
*
@ -281,13 +256,6 @@ public class BaseProject extends BuildExecutor {
* @since 1.5
*/
protected File libRuntimeDirectory = null;
/**
* The modules runtime scope lib directory.
*
* @see #libRuntimeModulesDirectory()
* @since 2.1
*/
protected File libRuntimeModulesDirectory = null;
/**
* The standalone scope lib directory.
*
@ -296,26 +264,12 @@ public class BaseProject extends BuildExecutor {
*/
protected File libStandaloneDirectory = null;
/**
* The modules standalone scope lib directory.
*
* @see #libStandaloneModulesDirectory()
* @since 2.1
*/
protected File libStandaloneModulesDirectory = null;
/**
* The test scope lib directory.
* The standalone scope lib directory.
*
* @see #libTestDirectory()
* @since 1.5
*/
protected File libTestDirectory = null;
/**
* The modules test scope lib directory.
*
* @see #libTestModulesDirectory()
* @since 2.1
*/
protected File libTestModulesDirectory = null;
/**
* The build directory.
*
@ -726,44 +680,8 @@ public class BaseProject extends BuildExecutor {
* {@link VersionNumber#UNKNOWN} if the description couldn't be parsed
* @since 1.5
*/
public Version version(String 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);
public VersionNumber version(String description) {
return VersionNumber.parse(description);
}
/**
@ -841,7 +759,7 @@ public class BaseProject extends BuildExecutor {
* @return a newly created {@code Dependency} instance
* @since 1.5
*/
public Dependency dependency(String groupId, String artifactId, Version version) {
public Dependency dependency(String groupId, String artifactId, VersionNumber version) {
return new Dependency(groupId, artifactId, version);
}
@ -855,7 +773,7 @@ public class BaseProject extends BuildExecutor {
* @return a newly created {@code Dependency} instance
* @since 1.5
*/
public Dependency dependency(String groupId, String artifactId, Version version, String classifier) {
public Dependency dependency(String groupId, String artifactId, VersionNumber version, String classifier) {
return new Dependency(groupId, artifactId, version, classifier);
}
@ -870,7 +788,7 @@ public class BaseProject extends BuildExecutor {
* @return a newly created {@code Dependency} instance
* @since 1.5
*/
public Dependency dependency(String groupId, String artifactId, Version version, String classifier, String type) {
public Dependency dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type) {
return new Dependency(groupId, artifactId, version, classifier, type);
}
@ -903,101 +821,6 @@ public class BaseProject extends BuildExecutor {
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
*/
@ -1150,36 +973,6 @@ public class BaseProject extends BuildExecutor {
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.
* Defaults to {@code "runtime"} relative to {@link #libDirectory()}.
@ -1190,16 +983,6 @@ public class BaseProject extends BuildExecutor {
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.
* Defaults to {@code null}.
@ -1207,17 +990,7 @@ public class BaseProject extends BuildExecutor {
* @since 1.5
*/
public File libStandaloneDirectory() {
return libStandaloneDirectory;
}
/**
* Returns the project standalone scope lib directory.
* Defaults to {@code null}.
*
* @since 2.1
*/
public File libStandaloneModulesDirectory() {
return libStandaloneModulesDirectory;
return null;
}
/**
@ -1230,16 +1003,6 @@ public class BaseProject extends BuildExecutor {
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.
* Defaults to {@code "build"} relative to {@link #workDirectory()}.
@ -1330,19 +1093,11 @@ public class BaseProject extends BuildExecutor {
libDirectory().mkdirs();
libBldDirectory().mkdirs();
libCompileDirectory().mkdirs();
libCompileModulesDirectory().mkdirs();
libProvidedDirectory().mkdirs();
libProvidedModulesDirectory().mkdirs();
libRuntimeDirectory().mkdirs();
libRuntimeModulesDirectory().mkdirs();
if (libStandaloneDirectory() != null) {
libStandaloneDirectory().mkdirs();
}
if (libStandaloneModulesDirectory() != null) {
libStandaloneModulesDirectory().mkdirs();
}
libTestDirectory().mkdirs();
libTestModulesDirectory().mkdirs();
}
/**
@ -1376,17 +1131,6 @@ public class BaseProject extends BuildExecutor {
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.
*
@ -1399,17 +1143,6 @@ public class BaseProject extends BuildExecutor {
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.
*
@ -1423,32 +1156,15 @@ public class BaseProject extends BuildExecutor {
}
/**
* 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.
* Returns the project's main class.
*
* @since 1.5
*/
public String mainClass() {
return mainClass;
if (mainClass == null) {
throw new IllegalStateException("The mainClass variable has to be set.");
}
/**
* Returns the project's module to execute.
*
* @since 2.1
*/
public String module() {
return module;
return mainClass;
}
/**
@ -1566,14 +1282,7 @@ public class BaseProject extends BuildExecutor {
* @since 1.5
*/
public String uberJarMainClass() {
if (uberJarMainClass != null) {
return uberJarMainClass;
}
if (mainClass() != null) {
return mainClass();
}
throw new IllegalStateException("The mainClass variable has to be set.");
return Objects.requireNonNullElseGet(uberJarMainClass, this::mainClass);
}
/**
@ -1653,66 +1362,10 @@ public class BaseProject extends BuildExecutor {
// build the compilation classpath
var classpath = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
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);
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.
* <p>
@ -1732,25 +1385,6 @@ public class BaseProject extends BuildExecutor {
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.
* <p>
@ -1775,30 +1409,6 @@ public class BaseProject extends BuildExecutor {
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.
* <p>
@ -1818,51 +1428,20 @@ public class BaseProject extends BuildExecutor {
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) {
if (dependencies.get(scope) == null) {
return;
}
for (var dependency : dependencies.get(scope).localDependencies()) {
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);
var local_file = new File(workDirectory(), dependency.path());
if (local_file.exists()) {
if (local_file.isDirectory()) {
var local_jar_files = FileUtils.getFileList(local_file.getAbsoluteFile(), INCLUDED_JARS, EXCLUDED_JARS);
jars.addAll(new ArrayList<>(local_jar_files.stream().map(file -> new File(local_file, file)).toList()));
classpath.addAll(new ArrayList<>(local_jar_files.stream().map(file -> new File(local_file, file)).toList()));
} else {
jars.add(local_file);
classpath.add(local_file);
}
}
}
}
@ -1870,29 +1449,18 @@ public class BaseProject extends BuildExecutor {
/**
* Returns all the classpath entries for compiling the main sources.
* <p>
* By default, this converts the files from {@link #compileClasspathJars()} and {@link #providedClasspathJars()} to absolute paths.
* By default, this converts the files from {@link #compileClasspathJars()} to absolute paths.
*
* @since 1.5
*/
public List<String> compileMainClasspath() {
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());
return FileUtils.combineToAbsolutePaths(compileClasspathJars());
}
/**
* Returns all the classpath entries for compiling the test sources.
* <p>
* By default, this converts the files from {@link #compileClasspathJars()}, {@link #providedClasspathJars()} and
* By default, this converts the files from {@link #compileClasspathJars()} and
* {@link #testClasspathJars()} to absolute paths, as well as the {@link #buildMainDirectory()}
*
* @since 1.5
@ -1900,22 +1468,10 @@ public class BaseProject extends BuildExecutor {
public List<String> compileTestClasspath() {
var paths = new ArrayList<String>();
paths.add(buildMainDirectory().getAbsolutePath());
paths.addAll(FileUtils.combineToAbsolutePaths(compileClasspathJars(), providedClasspathJars(), testClasspathJars()));
paths.addAll(FileUtils.combineToAbsolutePaths(compileClasspathJars(), testClasspathJars()));
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.
* <p>
@ -1933,22 +1489,10 @@ public class BaseProject extends BuildExecutor {
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.
* <p>
* By default, this converts the files from {@link #compileClasspathJars()}, {@link #providedClasspathJars()},
* By default, this converts the files from {@link #compileClasspathJars()},
* {@link #runtimeClasspathJars()} and {@link #testClasspathJars()}
* to absolute paths, as well as the {@link #srcMainResourcesDirectory()},
* {@link #buildMainDirectory()} and {@link #buildTestDirectory()}
@ -1961,23 +1505,10 @@ public class BaseProject extends BuildExecutor {
paths.add(srcTestResourcesDirectory().getAbsolutePath());
paths.add(buildMainDirectory().getAbsolutePath());
paths.add(buildTestDirectory().getAbsolutePath());
paths.addAll(FileUtils.combineToAbsolutePaths(compileClasspathJars(), providedClasspathJars(), runtimeClasspathJars(), standaloneClasspathJars(), testClasspathJars()));
paths.addAll(FileUtils.combineToAbsolutePaths(compileClasspathJars(), runtimeClasspathJars(), standaloneClasspathJars(), testClasspathJars()));
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
* {@code autoDownloadPurge} flag is set and changes have been detected.
@ -1991,28 +1522,84 @@ public class BaseProject extends BuildExecutor {
purge();
}
private static final String BLD_BUILD_HASH = "bld-build.hash";
private void performAutoDownloadPurge() {
var resolution = new VersionResolution(properties());
var cache = new BldCache(libBldDirectory(), resolution);
cache.cacheDependenciesHash(repositories(), dependencies());
cache.cacheDependenciesDownloads(downloadSources(), downloadJavadoc());
if (cache.isDependenciesCacheValid()) {
// verify and update the fingerprint hash file,
// don't download and purge if the hash is identical
var hash_file = new File(libBldDirectory(), BLD_BUILD_HASH);
var hash = createHash();
if (validateHash(hash_file, hash)) {
return;
}
try {
executeAutoDownloadPurge();
cache.writeCache();
writeHash(hash_file, hash);
} catch (Exception 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
public int execute(String[] arguments) {
if (!offline() &&
autoDownloadPurge()) {
if (autoDownloadPurge()) {
performAutoDownloadPurge();
}

View file

@ -1,561 +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;
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,15 +25,6 @@ public @interface BuildCommand {
*/
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.
*

View file

@ -11,7 +11,9 @@ import rife.bld.operations.exceptions.ExitStatusException;
import rife.ioc.HierarchicalProperties;
import rife.tools.ExceptionUtils;
import java.io.*;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;
@ -31,7 +33,6 @@ public class BuildExecutor {
public static final String BLD_PROPERTIES = "bld.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_HELP2 = "-h";
private static final String ARG_HELP3 = "-?";
@ -40,9 +41,7 @@ public class BuildExecutor {
private final HierarchicalProperties properties_;
private List<String> arguments_ = Collections.emptyList();
private boolean offline_ = false;
private Map<String, CommandDefinition> buildCommands_ = null;
private Map<String, String> buildAliases_ = null;
private final AtomicReference<String> currentCommandName_ = new AtomicReference<>();
private final AtomicReference<CommandDefinition> currentCommandDefinition_ = new AtomicReference<>();
private int exitStatus_ = 0;
@ -125,18 +124,7 @@ public class BuildExecutor {
}
/**
* 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.
* Returns the properties uses by this conversation.
*
* @return the instance of {@code HierarchicalProperties} that is used
* by this build executor
@ -226,16 +214,13 @@ public class BuildExecutor {
var show_help = false;
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) {
new HelpOperation(this, Collections.emptyList()).execute();
return exitStatus_;
}
else if (arguments_.isEmpty()) {
showBldHelp();
return exitStatus_;
}
while (!arguments_.isEmpty()) {
var command = arguments_.remove(0);
@ -245,39 +230,36 @@ public class BuildExecutor {
break;
}
} catch (Throwable e) {
exitStatus(ExitStatusException.EXIT_FAILURE);
outputCommandExecutionException(e);
break;
}
}
exitStatus(1);
return exitStatus_;
}
private void outputCommandExecutionException(Throwable e) {
System.err.println();
if (showStacktrace) {
System.err.println(ExceptionUtils.getExceptionStackTrace(e));
} else {
boolean first_exception = true;
boolean first = true;
var e2 = e;
while (e2 != null) {
if (e2.getMessage() != null) {
if (!first_exception) {
if (!first) {
System.err.print("> ");
}
System.err.println(e2.getMessage());
first_exception = false;
first = false;
}
e2 = e2.getCause();
}
if (first_exception) {
if (first) {
System.err.println(ExceptionUtils.getExceptionStackTrace(e));
}
}
}
}
return exitStatus_;
}
/**
* Starts the execution of the build. This method will call
@ -288,11 +270,6 @@ public class BuildExecutor {
* @since 1.5.1
*/
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));
}
@ -317,7 +294,6 @@ public class BuildExecutor {
public Map<String, CommandDefinition> buildCommands() {
if (buildCommands_ == null) {
var build_commands = new TreeMap<String, CommandDefinition>();
var build_aliases = new HashMap<String, String>();
Class<?> klass = getClass();
@ -335,11 +311,6 @@ public class BuildExecutor {
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)) {
var build_help = annotation.help();
CommandHelp command_help = null;
@ -372,27 +343,11 @@ public class BuildExecutor {
}
buildCommands_ = build_commands;
buildAliases_ = build_aliases;
}
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 final String summary_;
private final String description_;
@ -428,15 +383,6 @@ public class BuildExecutor {
var matched_command = 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
// the ones that are known
if (definition == null) {
@ -453,7 +399,7 @@ public class BuildExecutor {
fuzzy_regexp.append(ch);
fuzzy_regexp.append("\\E.*");
}
fuzzy_regexp.append('$');
fuzzy_regexp.append("$");
var fuzzy_pattern = Pattern.compile(fuzzy_regexp.toString());
matches.addAll(buildCommands().keySet().stream()
.filter(c -> fuzzy_pattern.matcher(c.toLowerCase()).matches())
@ -470,9 +416,9 @@ public class BuildExecutor {
// execute the command if we found one
if (definition != null) {
try {
currentCommandName_.set(matched_command);
currentCommandDefinition_.set(definition);
try {
definition.execute();
} catch (ExitStatusException e) {
exitStatus(e.getExitStatus());
@ -482,25 +428,14 @@ public class BuildExecutor {
currentCommandName_.set(null);
}
} else {
var message = "Unknown command '" + command + "'";
showBldHelp();
System.err.println("ERROR: " + message);
exitStatus(ExitStatusException.EXIT_FAILURE);
new HelpOperation(this, arguments()).executePrintOverviewHelp();
System.err.println();
System.err.println("ERROR: unknown command '" + command + "'");
return false;
}
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.
*

View file

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

View file

@ -108,11 +108,6 @@ public class WebProject extends Project {
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.
* Defaults to {@code "webapp"} relative to {@link #srcMainDirectory()}.

View file

@ -13,6 +13,7 @@ import java.util.List;
import static rife.bld.dependencies.Repository.MAVEN_CENTRAL;
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.
@ -21,16 +22,16 @@ import static rife.bld.dependencies.Repository.SONATYPE_SNAPSHOTS;
* @since 1.5.20
*/
public class BaseProjectBlueprint extends Project {
public BaseProjectBlueprint(File work, String packageName, String projectName, String baseName) {
this(work, packageName, projectName, baseName, new VersionNumber(0,0,1));
public BaseProjectBlueprint(File work, String packageName, String projectName) {
this(work, packageName, projectName, new VersionNumber(0,0,1));
}
public BaseProjectBlueprint(File work, String packageName, String projectName, String baseName, VersionNumber versionNumber) {
public BaseProjectBlueprint(File work, String packageName, String projectName, VersionNumber versionNumber) {
workDirectory = work;
pkg = packageName;
name = projectName;
mainClass = packageName + "." + baseName;
mainClass = packageName + "." + StringUtils.capitalize(projectName) + "Main";
version = versionNumber;
downloadSources = true;

View file

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

View file

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

View file

@ -4,87 +4,54 @@
*/
package rife.bld.dependencies;
import java.util.HashSet;
import java.util.Objects;
import java.util.regex.Pattern;
/**
* Contains the information required to describe a dependency in the build system.
* Contains the information required to describe an url 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)
* @since 1.5
*/
public class Dependency {
public record Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type, ExclusionSet exclusions, Dependency parent) {
public static final String CLASSIFIER_SOURCES = "sources";
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) {
this(groupId, artifactId, null, null, null);
}
public Dependency(String groupId, String artifactId, Version version) {
public Dependency(String groupId, String artifactId, VersionNumber version) {
this(groupId, artifactId, version, null, null);
}
public Dependency(String groupId, String artifactId, Version version, String classifier) {
public Dependency(String groupId, String artifactId, VersionNumber version, String classifier) {
this(groupId, artifactId, version, classifier, null);
}
public Dependency(String groupId, String artifactId, Version version, String classifier, String type) {
public Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type) {
this(groupId, artifactId, version, classifier, type, null);
}
public Dependency(String groupId, String artifactId, Version version, String classifier, String type, ExclusionSet exclusions) {
this(groupId, artifactId, version, classifier, type, exclusions, null);
public Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type, ExclusionSet exclusions) {
this(groupId, artifactId, version, classifier, type, null, null);
}
public Dependency(String groupId, String artifactId, Version version, String classifier, String type, ExclusionSet exclusions, Dependency parent) {
if (type == null) {
type = TYPE_JAR;
}
if (parent != null && parent.isModularJar() && TYPE_JAR.equals(type)) {
type = TYPE_MODULAR_JAR;
}
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<>();
public Dependency(String groupId, String artifactId, VersionNumber version, String classifier, String type, ExclusionSet exclusions, Dependency parent) {
this.groupId = groupId;
this.artifactId = artifactId;
this.version = (version == null ? VersionNumber.UNKNOWN : version);
this.classifier = (classifier == null ? "" : classifier);
this.type = (type == null ? "jar" : type);
this.exclusions = (exclusions == null ? new ExclusionSet() : exclusions);
this.parent = parent;
}
private static final Pattern DEPENDENCY_PATTERN = Pattern.compile("^(?<groupId>[^:@]+):(?<artifactId>[^:@]+)(?::(?<version>[^:@]+)(?::(?<classifier>[^:@]+))?)?(?:@(?<type>[^:@]+))?$");
@ -113,7 +80,7 @@ public class Dependency {
var groupId = matcher.group("groupId");
var artifactId = matcher.group("artifactId");
var version = Version.parse(matcher.group("version"));
var version = VersionNumber.parse(matcher.group("version"));
var classifier = matcher.group("classifier");
var type = matcher.group("type");
@ -128,7 +95,7 @@ public class Dependency {
* @since 1.5
*/
public Dependency baseDependency() {
return new Dependency(groupId_, artifactId_, VersionNumber.UNKNOWN, classifier_, type_);
return new Dependency(groupId, artifactId, VersionNumber.UNKNOWN, classifier, type);
}
/**
@ -140,7 +107,7 @@ public class Dependency {
* @since 1.5
*/
public Dependency exclude(String groupId, String artifactId) {
exclusions_.add(new DependencyExclusion(groupId, artifactId));
exclusions.add(new DependencyExclusion(groupId, artifactId));
return this;
}
@ -152,29 +119,7 @@ public class Dependency {
* @since 1.5.6
*/
public Dependency withClassifier(String classifier) {
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;
return new Dependency(groupId, artifactId, version, classifier, type);
}
/**
@ -185,150 +130,40 @@ public class Dependency {
*/
public String toFileName() {
var result = new StringBuilder(artifactId());
result.append('-').append(version());
result.append("-").append(version());
if (!classifier().isEmpty()) {
result.append('-').append(classifier());
result.append("-").append(classifier());
}
result.append('.').append(type());
result.append(".").append(type());
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() {
var result = new StringBuilder(groupId_).append(':').append(artifactId_);
if (!version_.equals(VersionNumber.UNKNOWN)) {
result.append(':').append(version_);
var result = new StringBuilder(groupId).append(":").append(artifactId);
if (!version.equals(VersionNumber.UNKNOWN)) {
result.append(":").append(version);
}
if (!classifier_.isEmpty()) {
result.append(':').append(classifier_);
if (!classifier.isEmpty()) {
result.append(":").append(classifier);
}
if (!type_.isEmpty() && !TYPE_JAR.equals(type_)) {
result.append('@').append(type_);
if (!type.isEmpty() && !type.equals("jar")) {
result.append("@").append(type);
}
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) {
if (this == o) return true;
if (!(o instanceof Dependency that)) return false;
return groupId_.equals(that.groupId_) &&
artifactId_.equals(that.artifactId_) &&
classifier_.equals(that.classifier_) &&
normalizedJarType(type_).equals(normalizedJarType(that.type_));
if (o == null || getClass() != o.getClass()) return false;
var that = (Dependency) o;
return groupId.equals(that.groupId) &&
artifactId.equals(that.artifactId) &&
classifier.equals(that.classifier) &&
type.equals(that.type);
}
public int hashCode() {
return Objects.hash(groupId_, artifactId_, classifier_, normalizedJarType(type_));
return Objects.hash(groupId, artifactId, classifier, type);
}
}

View file

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

View file

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

View file

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

View file

@ -23,7 +23,6 @@ import java.util.*;
public class DependencySet extends AbstractSet<Dependency> implements Set<Dependency> {
private final Map<Dependency, Dependency> dependencies_ = new LinkedHashMap<>();
private final Set<LocalDependency> localDependencies_ = new LinkedHashSet<>();
private final Set<LocalModule> localModules_ = new LinkedHashSet<>();
/**
* Creates an empty dependency set.
@ -80,94 +79,48 @@ public class DependencySet extends AbstractSet<Dependency> implements Set<Depend
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.
* <p>
* 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 repositories the repositories to use for the transfer
* @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
* @throws DependencyTransferException when an error occurred during the transfer
* @since 2.1
* @since 1.5.10
*/
public List<RepositoryArtifact> transferIntoDirectory(VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories, File directory, File modulesDirectory) {
return transferIntoDirectory(resolution, retriever, repositories, directory, modulesDirectory, (String[]) null);
public List<RepositoryArtifact> transferIntoDirectory(ArtifactRetriever retriever, List<Repository> repositories, File directory) {
return transferIntoDirectory(retriever, repositories, directory, (String[]) null);
}
/**
* Transfers the artifacts for the dependencies into the provided directories,
* Transfers the artifacts for the dependencies into the provided directory,
* including other classifiers.
* <p>
* 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 repositories the repositories to use for the download
* @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
* @return the list of artifacts that were transferred successfully
* @throws DependencyTransferException when an error occurred during the transfer
* @since 2.1
* @since 1.5.10
*/
public List<RepositoryArtifact> transferIntoDirectory(VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories, File directory, File modulesDirectory, String... classifiers) {
public List<RepositoryArtifact> transferIntoDirectory(ArtifactRetriever retriever, List<Repository> repositories, File directory, String... classifiers) {
var result = new ArrayList<RepositoryArtifact>();
for (var dependency : this) {
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);
var artifact = new DependencyResolver(retriever, repositories, dependency).transferIntoDirectory(directory);
if (artifact != null) {
result.add(artifact);
}
if (classifiers != null) {
for (var classifier : classifiers) {
if (classifier != null && !dependency.excludedClassifiers().contains(classifier)) {
var classifier_artifact = new DependencyResolver(resolution, retriever, repositories, dependency.withClassifier(classifier)).transferIntoDirectory(transfer_directory);
if (classifier != null) {
var classifier_artifact = new DependencyResolver(retriever, repositories, dependency.withClassifier(classifier)).transferIntoDirectory(directory);
if (classifier_artifact != null) {
result.add(classifier_artifact);
}
@ -197,18 +150,17 @@ public class DependencySet extends AbstractSet<Dependency> implements Set<Depend
* Generates the string description of the transitive hierarchical tree of
* 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 repositories the repositories to look for dependencies in
* @param scopes the scopes to return the transitive dependencies for
* @return the generated tree description string; or an empty string if
* there were no dependencies to describe
* @since 2.0
* @since 1.5.21
*/
public String generateTransitiveDependencyTree(VersionResolution resolution, ArtifactRetriever retriever, List<Repository> repositories, Scope... scopes) {
public String generateTransitiveDependencyTree(ArtifactRetriever retriever, List<Repository> repositories, Scope... scopes) {
var compile_dependencies = new DependencySet();
for (var dependency : this) {
compile_dependencies.addAll(new DependencyResolver(resolution, retriever, repositories, dependency).getAllDependencies(scopes));
compile_dependencies.addAll(new DependencyResolver(retriever, repositories, dependency).getAllDependencies(scopes));
}
return compile_dependencies.generateDependencyTree();
}

View file

@ -1,17 +0,0 @@
/*
* 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 {
/**
* Returns latest version in the metadata.
* Returns latest version number in the metadata.
*
* @return the latest version
* @return the latest version number
* @since 1.5.8
*/
Version getLatest();
VersionNumber getLatest();
/**
* Returns release version in the metadata.
* Returns release version number in the metadata.
*
* @return the release version
* @return the release version number
* @since 1.5.8
*/
Version getRelease();
VersionNumber getRelease();
/**
* Returns snapshot version in the metadata.
* Returns snapshot version number in the metadata.
*
* @return the snapshot version
* @return the snapshot version number
* @since 1.5.8
*/
Version getSnapshot();
VersionNumber getSnapshot();
/**
* Returns snapshot timestamp in the metadata.
@ -56,8 +56,8 @@ public interface MavenMetadata {
/**
* Returns all the release or snapshot versions in the metadata.
*
* @return the version list
* @return the version number list
* @since 1.5.8
*/
List<Version> getVersions();
List<VersionNumber> getVersions();
}

View file

@ -1,67 +0,0 @@
/*
* 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(
groupId(),
artifactId(),
Version.parse(version()),
VersionNumber.parse(version()),
classifier(),
type(),
exclusions(),

View file

@ -7,10 +7,8 @@ package rife.bld.dependencies;
import rife.ioc.HierarchicalProperties;
import rife.tools.StringEncryptor;
import java.io.File;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Pattern;
/**
* Contains the information required to locate a Maven-compatible repository.
@ -23,18 +21,11 @@ import java.util.regex.Pattern;
*/
public record Repository(String location, String username, String password) {
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 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_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_LEGACY = new Repository("https://oss.sonatype.org/content/repositories/snapshots/");
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 APACHE = new Repository("https://repo.maven.apache.org/maven2/");
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/");
@ -89,20 +80,14 @@ public record Repository(String location, String username, String password) {
}
return switch (locationOrName) {
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_SNAPSHOTS" -> Repository.RIFE2_SNAPSHOTS;
case "SECURECHAIN_REBUILT" -> SECURECHAIN_REBUILT;
case "SECURECHAIN_VETTED" -> SECURECHAIN_VETTED;
case "MAVEN_CENTRAL" -> Repository.MAVEN_CENTRAL;
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;
case "APACHE" -> Repository.APACHE;
case "RIFE2_RELEASES" -> Repository.RIFE2_RELEASES;
case "RIFE2_SNAPSHOTS" -> Repository.RIFE2_SNAPSHOTS;
default -> new Repository(locationOrName);
};
}
@ -117,12 +102,6 @@ public record Repository(String location, String username, String password) {
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.
*
@ -131,7 +110,7 @@ public record Repository(String location, String username, String password) {
* @since 1.5.10
*/
public boolean isLocal() {
return location().startsWith("/") || location().startsWith("file:") || isWindowsLocation();
return location().startsWith("/") || location().startsWith("file:");
}
/**
@ -167,12 +146,9 @@ public record Repository(String location, String username, String password) {
* @since 1.5.10
*/
public String getArtifactLocation(String groupId, String artifactId) {
var separator = "/";
var group_path = groupId.replace(".", "/");
var result = new StringBuilder();
if (isLocal()) {
if (isWindowsLocation()) {
separator = File.separator;
}
if (location().startsWith("file://")) {
result.append(location().substring("file://".length()));
} else {
@ -181,11 +157,10 @@ public record Repository(String location, String username, String password) {
} else {
result.append(location());
}
if (!location().endsWith(separator)) {
result.append(separator);
if (!location().endsWith("/")) {
result.append("/");
}
var group_path = groupId.replace(".", separator);
return result.append(group_path).append(separator).append(artifactId).append(separator).toString();
return result.append(group_path).append("/").append(artifactId).append("/").toString();
}
/**
@ -205,11 +180,11 @@ public record Repository(String location, String username, String password) {
public String toString() {
var result = new StringBuilder(location);
if (username() != null) {
result.append(':');
result.append(":");
try {
result.append(StringEncryptor.MD5HLO.performEncryption(username(), null));
if (password() != null) {
result.append(':');
result.append(":");
result.append(StringEncryptor.MD5HLO.performEncryption(password(), null));
}
} catch (NoSuchAlgorithmException e) {

View file

@ -1,79 +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.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

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

View file

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

View file

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

View file

@ -24,22 +24,6 @@ public class DependencyTransferException extends DependencyException {
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() {
return dependency_;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,44 +0,0 @@
/*
* 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

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

View file

@ -10,7 +10,8 @@ import rife.bld.operations.exceptions.OperationOptionException;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.*;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
/**
@ -23,13 +24,10 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
public static final String DEFAULT_JAVA_TOOL = "java";
protected File workDirectory_ = new File(System.getProperty("user.dir"));
protected final Map<String, String> environment_ = new HashMap<>();
protected String javaTool_ = DEFAULT_JAVA_TOOL;
protected final JavaOptions javaOptions_ = new JavaOptions();
protected final List<String> classpath_ = new ArrayList<>();
protected final List<String> modulePath_ = new ArrayList<>();
protected String mainClass_;
protected String module_;
protected Function<String, Boolean> outputProcessor_;
protected Function<String, Boolean> errorProcessor_;
protected Process process_;
@ -87,12 +85,6 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
var builder = new ProcessBuilder(executeConstructProcessCommandList());
builder.directory(workDirectory());
if (!environment_.isEmpty()) {
builder.environment().putAll(environment_);
}
builder.redirectInput(ProcessBuilder.Redirect.INHERIT);
final var output_processor = outputProcessor();
if (output_processor == null) {
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
@ -167,31 +159,6 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
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.
* <p>
@ -230,18 +197,6 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
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.
* <p>
@ -256,71 +211,6 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
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.
*
@ -333,18 +223,6 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
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.
* <p>
@ -383,18 +261,6 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
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.
*
@ -429,18 +295,6 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
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.
*
@ -451,16 +305,6 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
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.
*

View file

@ -1,283 +0,0 @@
/*
* 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,6 +5,7 @@
package rife.bld.operations;
import rife.bld.BaseProject;
import rife.bld.Project;
import rife.tools.FileUtils;
import rife.tools.exceptions.FileUtilsErrorException;

View file

@ -5,7 +5,7 @@
package rife.bld.operations;
import rife.bld.BaseProject;
import rife.bld.instrument.ModuleMainClassAdapter;
import rife.bld.Project;
import rife.bld.operations.exceptions.ExitStatusException;
import rife.tools.FileUtils;
@ -23,26 +23,16 @@ import java.util.List;
* @since 1.5
*/
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 buildTestDirectory_;
private final List<String> compileMainClasspath_ = 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> testSourceFiles_ = new ArrayList<>();
private final List<File> mainSourceDirectories_ = new ArrayList<>();
private final List<File> testSourceDirectories_ = new ArrayList<>();
private final JavacOptions compileOptions_ = new JavacOptions();
private final List<Diagnostic<? extends JavaFileObject>> diagnostics_ = new ArrayList<>();
private String moduleMainClass_;
/**
* Performs the compile operation.
@ -87,19 +77,11 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
for (var directory : mainSourceDirectories()) {
sources.addAll(FileUtils.getJavaFileList(directory));
}
if (sources.isEmpty()) {
if (!silent()) {
System.err.println("No main source files found.");
}
} else {
executeBuildSources(
compileMainClasspath(),
compileMainModulePath(),
sources,
buildMainDirectory());
}
}
/**
* Part of the {@link #execute} operation, builds the test sources.
@ -112,30 +94,21 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
for (var directory : testSourceDirectories()) {
sources.addAll(FileUtils.getJavaFileList(directory));
}
if (sources.isEmpty()) {
if (!silent()) {
System.err.println("No test source files found.");
}
} else {
executeBuildSources(
compileTestClasspath(),
compileTestModulePath(),
sources,
buildTestDirectory());
}
}
/**
* Part of the {@link #execute} operation, build sources to a destination.
*
* @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 destination the destination directory
* @since 2.1
* @since 1.5
*/
protected void executeBuildSources(List<String> classpath, List<String> modulePath, List<File> sources, File destination)
protected void executeBuildSources(List<String> classpath, List<File> sources, File destination)
throws IOException {
if (sources.isEmpty() || destination == null) {
return;
@ -145,51 +118,15 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
try (var file_manager = compiler.getStandardFileManager(null, null, null)) {
var compilation_units = file_manager.getJavaFileObjectsFromFiles(sources);
var diagnostics = new DiagnosticCollector<JavaFileObject>();
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));
}
var options = new ArrayList<>(List.of("-d", destination.getAbsolutePath(), "-cp", FileUtils.joinPaths(classpath)));
options.addAll(compileOptions());
var compilation_task = compiler.getTask(null, file_manager, diagnostics, options, null, compilation_units);
if (!compilation_task.call()) {
diagnostics_.addAll(diagnostics.getDiagnostics());
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.
@ -225,11 +162,8 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
.buildTestDirectory(project.buildTestDirectory())
.compileMainClasspath(project.compileMainClasspath())
.compileTestClasspath(project.compileTestClasspath())
.compileMainModulePath(project.compileMainModulePath())
.compileTestModulePath(project.compileTestModulePath())
.mainSourceFiles(project.mainSourceFiles())
.testSourceFiles(project.testSourceFiles())
.moduleMainClass(project.mainClass());
.testSourceFiles(project.testSourceFiles());
if (project.javaRelease() != null && !compileOptions().containsRelease()) {
compileOptions().release(project.javaRelease());
}
@ -312,58 +246,6 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
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.
*
@ -482,18 +364,6 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
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.
*
@ -538,30 +408,6 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
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.
* <p>
@ -631,15 +477,4 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
public List<Diagnostic<? extends JavaFileObject>> 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

@ -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.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() {
return new BaseProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName(), baseName());
return new BaseProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName());
}
}

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

View file

@ -7,7 +7,6 @@ package rife.bld.operations;
import rife.bld.operations.exceptions.OperationOptionException;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
@ -17,12 +16,6 @@ import java.util.List;
* @since 1.7
*/
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.
*
@ -34,40 +27,31 @@ public class CreateOperation {
String type = null;
String package_name = null;
String project_name = null;
String base_name = null;
if (!arguments.isEmpty()) {
if (arguments.size() > 0) {
type = arguments.remove(0);
}
var create_operation_args = new ArrayList<String>();
if (!arguments.isEmpty()) {
if (arguments.size() > 0) {
package_name = arguments.remove(0);
create_operation_args.add(package_name);
}
if (!arguments.isEmpty()) {
if (arguments.size() > 0) {
project_name = arguments.remove(0);
create_operation_args.add(project_name);
}
if (!arguments.isEmpty()) {
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 || package_name == null || project_name == null) && System.console() == null) {
throw new OperationOptionException("ERROR: Expecting the type, package and project names as the arguments.");
}
if (type == null || type.isBlank()) {
if (type == null || type.isEmpty()) {
System.out.println("Please enter a number for the project type:");
System.out.printf(" 1: %s (Java baseline project)%n", BASE);
System.out.printf(" 2: %s (Java application project)%n", APP);
System.out.printf(" 3: %s (Java library project)%n", LIB);
System.out.printf(" 4: %s (RIFE2 web application)%n", RIFE2);
System.out.println(" 1: base");
System.out.println(" 2: blank");
System.out.println(" 3: lib");
System.out.println(" 4: rife2");
var number = System.console().readLine();
switch (Integer.parseInt(number)) {
case 1 -> type = BASE;
case 2 -> type = APP;
case 3 -> type = LIB;
case 4 -> type = RIFE2;
case 1 -> type = "base";
case 2 -> type = "blank";
case 3 -> type = "lib";
case 4 -> type = "rife2";
}
} else {
System.out.println("Using project type: " + type);
@ -78,15 +62,32 @@ public class CreateOperation {
AbstractCreateOperation<?, ?> create_operation = null;
switch (type) {
case BASE -> create_operation = new CreateBaseOperation();
case APP -> create_operation = new CreateAppOperation();
case LIB -> create_operation = new CreateLibOperation();
case RIFE2 -> create_operation = new CreateRife2Operation();
case "base" -> create_operation = new CreateBaseOperation();
case "blank" -> create_operation = new CreateBlankOperation();
case "lib" -> create_operation = new CreateLibOperation();
case "rife2" -> create_operation = new CreateRife2Operation();
}
if (create_operation == null) {
throw new OperationOptionException("ERROR: Unsupported project type.");
}
return create_operation.fromArguments(create_operation_args);
if (package_name == null || package_name.isEmpty()) {
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,7 +7,6 @@ package rife.bld.operations;
import rife.bld.blueprints.Rife2ProjectBlueprint;
import rife.template.TemplateFactory;
import rife.tools.FileUtils;
import rife.tools.StringUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File;
@ -28,14 +27,14 @@ public class CreateRife2Operation extends AbstractCreateOperation<CreateRife2Ope
}
protected Rife2ProjectBlueprint createProjectBlueprint() {
return new Rife2ProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName(), baseName());
return new Rife2ProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName());
}
@Override
protected void executeConfigure() {
super.executeConfigure();
projectMainName_ = baseName() + "Site";
projectMainName_ = projectClassName_ + "Site";
projectMainUberName_ = projectMainName_ + "Uber";
srcMainWebappCssDirectory_ = new File(project_.srcMainWebappDirectory(), "css");
srcMainWebappWebInfDirectory_ = new File(project_.srcMainWebappDirectory(), "WEB-INF");
@ -64,7 +63,7 @@ public class CreateRife2Operation extends AbstractCreateOperation<CreateRife2Ope
// project template
var template_template = TemplateFactory.HTML.get(templateBase_ + "project_template");
template_template.setValue("project", project_.name());
template_template.setValue("project", projectClassName_);
var project_template_file = new File(project_.srcMainResourcesTemplatesDirectory(), "hello.html");
FileUtils.writeString(template_template.getContent(), project_template_file);

View file

@ -5,19 +5,13 @@
package rife.bld.operations;
import rife.bld.BaseProject;
import rife.bld.BldCache;
import rife.bld.BldVersion;
import rife.bld.BuildExecutor;
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.List;
import static rife.bld.dependencies.Scope.*;
import static rife.bld.dependencies.Scope.compile;
import static rife.bld.dependencies.Scope.runtime;
/**
* Transitively generates a hierarchical tree of dependencies.
@ -26,17 +20,10 @@ import static rife.bld.dependencies.Scope.*;
* @since 1.5.21
*/
public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOperation> {
private boolean offline_ = false;
private HierarchicalProperties properties_ = null;
private HierarchicalProperties extensionProperties_ = null;
private ArtifactRetriever retriever_ = null;
private final List<Repository> repositories_ = new ArrayList<>();
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 File libBldDir_ = null;
/**
* Performs the dependency tree operation.
@ -44,132 +31,16 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
* @since 1.5.21
*/
public void execute() {
if (offline_) {
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
var compile_tree = executeGenerateCompileDependencies();
var runtime_tree = executeGenerateRuntimeDependencies();
dependencyTree_.setLength(0);
dependencyTree_.append(extensions_tree);
dependencyTree_.append(System.lineSeparator());
dependencyTree_.append(compile_tree);
dependencyTree_.append(System.lineSeparator());
dependencyTree_.append(provided_tree);
dependencyTree_.append(System.lineSeparator());
dependencyTree_.append(runtime_tree);
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(provided_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;
}
/**
@ -178,52 +49,26 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
* @since 1.5.21
*/
protected String executeGenerateCompileDependencies() {
var compile_tree = dependencies().scope(compile).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile);
var compile_tree = dependencies().scope(compile).generateTransitiveDependencyTree(artifactRetriever(), repositories(), compile);
if (compile_tree.isEmpty()) {
compile_tree = "no dependencies" + System.lineSeparator();
}
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.
*
* @since 1.5.21
*/
protected String executeGenerateRuntimeDependencies() {
var runtime_tree = dependencies().scope(runtime).generateTransitiveDependencyTree(new VersionResolution(properties()), artifactRetriever(), repositories(), compile, runtime);
var runtime_tree = dependencies().scope(runtime).generateTransitiveDependencyTree(artifactRetriever(), repositories(), compile, runtime);
if (runtime_tree.isEmpty()) {
runtime_tree = "no dependencies" + System.lineSeparator();
}
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}.
@ -232,59 +77,11 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
* @since 1.5.21
*/
public DependencyTreeOperation fromProject(BaseProject project) {
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())
return artifactRetriever(project.artifactRetriever())
.repositories(project.repositories())
.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.
*
@ -323,44 +120,6 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
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.
*
@ -373,30 +132,6 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
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.
* <p>
@ -421,30 +156,6 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
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.
*
@ -467,30 +178,4 @@ public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOpe
public String dependencyTree() {
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,7 +6,6 @@ package rife.bld.operations;
import rife.bld.BaseProject;
import rife.bld.dependencies.*;
import rife.ioc.HierarchicalProperties;
import java.io.File;
import java.util.*;
@ -25,21 +24,13 @@ import static rife.bld.dependencies.Dependency.CLASSIFIER_SOURCES;
* @since 1.5
*/
public class DownloadOperation extends AbstractOperation<DownloadOperation> {
private boolean offline_ = false;
private HierarchicalProperties properties_ = null;
private ArtifactRetriever retriever_ = null;
private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes();
private File libCompileDirectory_;
private File libCompileModulesDirectory_;
private File libProvidedDirectory_;
private File libProvidedModulesDirectory_;
private File libRuntimeDirectory_;
private File libRuntimeModulesDirectory_;
private File libStandaloneDirectory_;
private File libStandaloneModulesDirectory_;
private File libTestDirectory_;
private File libTestModulesDirectory_;
private boolean downloadSources_ = false;
private boolean downloadJavadoc_ = false;
@ -49,13 +40,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5
*/
public void execute() {
if (offline_) {
System.out.println("Offline mode: download is disabled");
return;
}
executeDownloadCompileDependencies();
executeDownloadProvidedDependencies();
executeDownloadRuntimeDependencies();
executeDownloadStandaloneDependencies();
executeDownloadTestDependencies();
@ -70,16 +55,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5
*/
protected void executeDownloadCompileDependencies() {
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()));
executeDownloadDependencies(libCompileDirectory(), dependencies().resolveCompileDependencies(artifactRetriever(), repositories()));
}
/**
@ -88,7 +64,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5
*/
protected void executeDownloadRuntimeDependencies() {
executeDownloadDependencies(libRuntimeDirectory(), libRuntimeModulesDirectory(), dependencies().resolveRuntimeDependencies(properties(), artifactRetriever(), repositories()));
executeDownloadDependencies(libRuntimeDirectory(), dependencies().resolveRuntimeDependencies(artifactRetriever(), repositories()));
}
/**
@ -97,7 +73,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5
*/
protected void executeDownloadStandaloneDependencies() {
executeDownloadDependencies(libStandaloneDirectory(), libStandaloneModulesDirectory(), dependencies().resolveStandaloneDependencies(properties(), artifactRetriever(), repositories()));
executeDownloadDependencies(libStandaloneDirectory(), dependencies().resolveStandaloneDependencies(artifactRetriever(), repositories()));
}
/**
@ -106,18 +82,23 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5
*/
protected void executeDownloadTestDependencies() {
executeDownloadDependencies(libTestDirectory(), libTestModulesDirectory(), dependencies().resolveTestDependencies(properties(), artifactRetriever(), repositories()));
executeDownloadDependencies(libTestDirectory(), dependencies().resolveTestDependencies(artifactRetriever(), repositories()));
}
/**
* 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 modulesDirectory the directory in which the modules should be downloaded
* @param dependencies the dependencies to download
* @since 2.1
* @since 1.6
*/
protected void executeDownloadDependencies(File destinationDirectory, File modulesDirectory, DependencySet dependencies) {
protected void executeDownloadDependencies(File destinationDirectory, DependencySet dependencies) {
if (destinationDirectory == null) {
return;
}
destinationDirectory.mkdirs();
var additional_classifiers = new String[0];
if (downloadSources_ || downloadJavadoc_) {
@ -128,60 +109,27 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
additional_classifiers = classifiers.toArray(new String[0]);
}
dependencies.transferIntoDirectory(new VersionResolution(properties()), artifactRetriever(), repositories(), destinationDirectory, modulesDirectory, additional_classifiers);
dependencies.transferIntoDirectory(artifactRetriever(), repositories(), destinationDirectory, additional_classifiers);
}
/**
* Configures a compile operation from a {@link BaseProject}.
*
* @param project the project to configure the compile operation from
* @return this operation instance
* @since 1.5
*/
public DownloadOperation fromProject(BaseProject project) {
return offline(project.offline())
.properties(project.properties())
.artifactRetriever(project.artifactRetriever())
return artifactRetriever(project.artifactRetriever())
.repositories(project.repositories())
.dependencies(project.dependencies())
.libCompileDirectory(project.libCompileDirectory())
.libCompileModulesDirectory(project.libCompileModulesDirectory())
.libProvidedDirectory(project.libProvidedDirectory())
.libProvidedModulesDirectory(project.libProvidedModulesDirectory())
.libRuntimeDirectory(project.libRuntimeDirectory())
.libRuntimeModulesDirectory(project.libRuntimeModulesDirectory())
.libStandaloneDirectory(project.libStandaloneDirectory())
.libStandaloneModulesDirectory(project.libStandaloneModulesDirectory())
.libTestDirectory(project.libTestDirectory())
.libTestModulesDirectory(project.libTestModulesDirectory())
.downloadSources(project.downloadSources())
.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.
*
@ -232,42 +180,6 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
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.
*
@ -280,18 +192,6 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
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.
*
@ -304,18 +204,6 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
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.
*
@ -328,18 +216,6 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
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.
*
@ -378,18 +254,6 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
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.
* <p>
@ -424,36 +288,6 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
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.
*
@ -464,16 +298,6 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
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.
*
@ -484,16 +308,6 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
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.
*
@ -504,16 +318,6 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
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.
*
@ -548,17 +352,4 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
}
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,8 +6,6 @@ package rife.bld.operations;
import rife.bld.BldVersion;
import rife.bld.BuildExecutor;
import rife.template.TemplateFactory;
import rife.tools.ExceptionUtils;
import java.util.List;
@ -20,11 +18,8 @@ import static java.util.Comparator.comparingInt;
* @since 1.5
*/
public class HelpOperation {
private static final String JSON_ARGUMENT = "--json";
private final BuildExecutor executor_;
private final List<String> arguments_;
private boolean outputJson_ = false;
/**
* Creates a new help operation.
@ -46,116 +41,51 @@ public class HelpOperation {
public void execute() {
var topic = "";
if (!arguments_.isEmpty()) {
if (arguments_.get(0).equals(JSON_ARGUMENT)) {
arguments_.remove(0);
outputJson_ = true;
}
else {
topic = arguments_.remove(0);
}
}
if (!arguments_.isEmpty() && arguments_.get(0).equals(JSON_ARGUMENT)) {
arguments_.remove(0);
outputJson_ = true;
}
if (!outputJson_) {
executePrintWelcome();
}
System.err.println("Welcome to bld " + BldVersion.getVersion() + ".");
System.err.println();
var print_full_help = true;
Exception exception = null;
boolean print_full_help = true;
try {
var commands = executor_.buildCommands();
if (commands.containsKey(topic)) {
var command = commands.get(topic);
var help = command.getHelp().getDescription(topic);
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);
}
print_full_help = false;
}
}
} catch (Exception e) {
exception = e;
e.printStackTrace();
}
if (print_full_help) {
executePrintOverviewHelp(exception);
executePrintOverviewHelp();
}
}
private void executePrintOverviewHelp(Exception exception) {
if (outputJson_) {
var t = TemplateFactory.JSON.get("bld.help_commands");
if (exception != null) {
t.setValueEncoded("error-message", ExceptionUtils.getExceptionStackTrace(exception));
}
/**
* Part of the {@link #execute} operation, prints the help overview
* with summaries of all build commands.
*
* @since 1.5
*/
public void executePrintOverviewHelp() {
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("""
The bld CLI provides its features through a series of commands that
perform specific tasks. The help command provides more information about
the other commands.
Usage: help [command] [""" + JSON_ARGUMENT + "]");
Usage : help [command]
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:
The following commands are supported.
""");
var commands = executor_.buildCommands();
var command_length = commands.keySet().stream().max(comparingInt(String::length)).get().length() + 2;
for (var command : commands.entrySet()) {
System.err.print(" ");
@ -164,35 +94,12 @@ public class HelpOperation {
System.err.print(build_help.getSummary());
System.err.println();
}
}
/**
* Part of the {@link #execute} operation, prints the supported help arguments.
*
* @since 2.0
*/
public void executePrintHelpArguments() {
System.err.println("""
The following help arguments are supported:
--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
-?, -h, --help Shows this help message
-D<name>=<value> Set a JVM system property
-s, --stacktrace Print out the stacktrace for exceptions
""");
}
}

View file

@ -5,11 +5,6 @@
package rife.bld.operations;
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.
@ -29,39 +24,6 @@ public class JUnitOperation extends TestOperation<JUnitOperation, 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
public JUnitOperation fromProject(BaseProject project) {
super.fromProject(project);
@ -72,7 +34,7 @@ public class JUnitOperation extends TestOperation<JUnitOperation, JUnitOptions>
}
// add the default JUnit options if none were specified
if (testToolOptions().isEmpty() && DEFAULT_TEST_TOOL_JUNIT5.equals(mainClass())) {
if (testToolOptions().isEmpty() && mainClass().equals(DEFAULT_TEST_TOOL_JUNIT5)) {
testToolOptions().defaultOptions();
}
@ -83,9 +45,9 @@ public class JUnitOperation extends TestOperation<JUnitOperation, JUnitOptions>
var argument = arguments.get(0);
if (argument.startsWith("-")) {
arguments.remove(0);
if ("--junit-help".equals(argument)) {
if (argument.equals("--junit-help")) {
testToolOptions().add("--help");
} else if ("--junit-clear".equals(argument)) {
} else if (argument.equals("--junit-clear")) {
testToolOptions().clear();
} else {
testToolOptions().add(argument);

View file

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

View file

@ -4,12 +4,11 @@
*/
package rife.bld.operations;
import rife.tools.FileUtils;
import rife.tools.StringUtils;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -40,8 +39,8 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options
* @since 1.5.18
*/
public JavaOptions modulePath(File... paths) {
return modulePath(List.of(paths));
public JavaOptions modulePath(File... modules) {
return modulePath(Arrays.asList(modules));
}
/**
@ -50,49 +49,9 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options
* @since 1.5.18
*/
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) {
public JavaOptions modulePath(List<File> modules) {
add("--module-path");
add(FileUtils.joinPaths(paths));
add(StringUtils.join(modules, ":"));
return this;
}
@ -103,8 +62,8 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options
* @since 1.5.18
*/
public JavaOptions upgradeModulePath(File... paths) {
return upgradeModulePath(List.of(paths));
public JavaOptions upgradeModulePath(File... modulePath) {
return upgradeModulePath(Arrays.asList(modulePath));
}
/**
@ -114,53 +73,9 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options
* @since 1.5.18
*/
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) {
public JavaOptions upgradeModulePath(List<File> modulePath) {
add("--upgrade-module-path");
add(FileUtils.joinPaths(paths));
add(StringUtils.join(modulePath, ":"));
return this;
}
@ -173,7 +88,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18
*/
public JavaOptions addModules(String... modules) {
return addModules(List.of(modules));
return addModules(Arrays.asList(modules));
}
/**
@ -197,8 +112,8 @@ public class JavaOptions extends ArrayList<String> {
* @return this list of options
* @since 1.5.18
*/
public JavaOptions enableNativeAccess(String... modules) {
return enableNativeAccess(List.of(modules));
public JavaOptions enableNativeAccess(List... modules) {
return enableNativeAccess(Arrays.asList(modules));
}
/**
@ -300,7 +215,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18
*/
public JavaOptions agentLib(String libName) {
return agentLib(libName, (String)null);
return agentLib(libName, null);
}
/**
@ -310,28 +225,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18
*/
public JavaOptions agentLib(String libName, String 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, ",")));
add("-agentlib:" + libName + (options == null ? "" : ":" + options));
return this;
}
@ -342,7 +236,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18
*/
public JavaOptions agentPath(File pathName) {
return agentPath(pathName.getAbsolutePath(), (String)null);
return agentPath(pathName, null);
}
/**
@ -352,108 +246,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18
*/
public JavaOptions agentPath(File pathName, String 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, ",")));
add("-agentpath:" + pathName + (options == null ? "" : ":" + options));
return this;
}
@ -464,7 +257,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18
*/
public JavaOptions javaAgent(File jarPath) {
return javaAgent(jarPath.getAbsolutePath(), (String)null);
return javaAgent(jarPath, null);
}
/**
@ -474,108 +267,7 @@ public class JavaOptions extends ArrayList<String> {
* @since 1.5.18
*/
public JavaOptions javaAgent(File jarPath, String 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, ",")));
add("-javaagent:" + jarPath + (options == null ? "" : ":" + options));
return this;
}

File diff suppressed because it is too large Load diff

View file

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

View file

@ -9,10 +9,10 @@ import rife.tools.FileUtils;
import rife.tools.StringUtils;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* Options for the standard javadoc tool.
@ -100,7 +100,7 @@ public class JavadocOptions extends ArrayList<String> {
*/
public JavadocOptions doclet(String className) {
add("-doclet");
add(className);
add("className");
return this;
}
@ -112,7 +112,7 @@ public class JavadocOptions extends ArrayList<String> {
*/
public JavadocOptions docletPath(String path) {
add("-docletpath");
add(path);
add("path");
return this;
}
@ -135,7 +135,7 @@ public class JavadocOptions extends ArrayList<String> {
*/
public JavadocOptions encoding(String name) {
add("-encoding");
add(name);
add("name");
return this;
}
@ -178,48 +178,8 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.5.18
*/
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(String.join(",", dirs));
add(dirs.stream().map(File::getAbsolutePath).collect(Collectors.joining(",")));
return this;
}
@ -253,7 +213,7 @@ public class JavadocOptions extends ArrayList<String> {
*/
public JavadocOptions locale(String name) {
add("-locale");
add(name);
add("name");
return this;
}
@ -296,48 +256,8 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.6.3
*/
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(FileUtils.joinPaths(paths));
add(FileUtils.joinPaths(paths.stream().map(File::getAbsolutePath).toList()));
return this;
}
@ -348,28 +268,8 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.6.3
*/
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(path);
add(path.getAbsolutePath());
return this;
}
@ -525,29 +425,9 @@ public class JavadocOptions extends ArrayList<String> {
* @return this list of options
* @since 1.5.12
*/
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) {
public JavadocOptions addScript(File file) {
add("--add-script");
add(path);
add(file.getAbsolutePath());
return this;
}
@ -557,29 +437,9 @@ public class JavadocOptions extends ArrayList<String> {
* @return this list of options
* @since 1.5.12
*/
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) {
public JavadocOptions addStylesheet(File file) {
add("--add-stylesheet");
add(path);
add(file.getAbsolutePath());
return this;
}
@ -718,29 +578,9 @@ public class JavadocOptions extends ArrayList<String> {
* @return this list of options
* @since 1.5.12
*/
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) {
public JavadocOptions stylesheet(File file) {
add("--main-stylesheet");
add(path);
add(file.getAbsolutePath());
return this;
}
@ -895,29 +735,9 @@ public class JavadocOptions extends ArrayList<String> {
* @return this list of options
* @since 1.5.18
*/
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) {
public JavadocOptions overview(File htmlFile) {
add("-overview");
add(path);
add(htmlFile.getAbsolutePath());
return this;
}
@ -973,28 +793,8 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.5.12
*/
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(path);
add(path.getAbsolutePath());
return this;
}
@ -1052,28 +852,8 @@ public class JavadocOptions extends ArrayList<String> {
* @since 1.5.12
*/
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(path);
add(path.getAbsolutePath());
return this;
}

View file

@ -1,77 +0,0 @@
/*
* 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

@ -1,408 +0,0 @@
/*
* 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

@ -1,156 +0,0 @@
/*
* 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

@ -1,473 +0,0 @@
/*
* 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

@ -1,124 +0,0 @@
/*
* 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,11 +9,9 @@ import rife.bld.BldVersion;
import rife.bld.dependencies.*;
import rife.bld.dependencies.exceptions.DependencyException;
import rife.bld.operations.exceptions.OperationOptionException;
import rife.bld.operations.exceptions.RestApiException;
import rife.bld.operations.exceptions.SignException;
import rife.bld.operations.exceptions.UploadException;
import rife.bld.publish.*;
import rife.ioc.HierarchicalProperties;
import rife.tools.FileUtils;
import rife.tools.exceptions.FileUtilsErrorException;
@ -28,9 +26,7 @@ import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
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.tools.HttpUtils.*;
import static rife.tools.StringUtils.encodeHexLower;
@ -42,11 +38,6 @@ import static rife.tools.StringUtils.encodeHexLower;
* @since 1.5.7
*/
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 final HttpClient client_ = HttpClient.newHttpClient();
@ -54,7 +45,6 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes();
private PublishInfo info_ = new PublishInfo();
private PublishProperties publishProperties_ = new PublishProperties();
private final List<PublishArtifact> artifacts_ = new ArrayList<>();
/**
@ -63,11 +53,6 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @since 1.5.7
*/
public void execute() {
if (offline_) {
System.out.println("Offline mode: publish is disabled");
return;
}
if (repositories().isEmpty()) {
throw new OperationOptionException("ERROR: the publication repositories should be specified");
}
@ -92,11 +77,6 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
executePublishArtifacts(repository, actual_version);
executePublishPom(repository, actual_version);
executePublishMetadata(repository, moment);
if (!info().version().isSnapshot() &&
repository.location().contains(Repository.OSSRH_STAGING_API_DOMAIN)) {
executeCloseOSSRHStagingRepository(repository);
}
}
if (!silent()) {
System.out.println("Publishing finished successfully.");
@ -124,13 +104,13 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
*
* @param repository the repository to publish to
* @param moment the timestamp at which the operation started executing
* @return the adapted version with the snapshot timestamp and build number
* @return the adapted version number with the snapshot timestamp and build number
* @since 1.5.10
*/
protected Version executePublishSnapshotMetadata(Repository repository, ZonedDateTime moment) {
protected VersionNumber executePublishSnapshotMetadata(Repository repository, ZonedDateTime moment) {
var metadata = new MetadataBuilder();
Version actual_version;
VersionNumber actual_version;
if (repository.isLocal()) {
actual_version = info().version();
metadata.snapshotLocal();
@ -140,21 +120,16 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
// determine which build number to use
var snapshot_build_number = 1;
try {
var resolution = new VersionResolution(properties());
var resolver = new DependencyResolver(resolution, artifactRetriever(), List.of(repository), new Dependency(info().groupId(), info().artifactId(), info().version()));
var resolver = new DependencyResolver(artifactRetriever(), List.of(repository), new Dependency(info().groupId(), info().artifactId(), info().version()));
var snapshot_meta = resolver.getSnapshotMavenMetadata();
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;
snapshot_build_number = snapshot_meta.getSnapshotBuildNumber() + 1;
} catch (DependencyException e) {
// start the build number from the beginning
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.");
}
// adapt the actual version used by the artifacts
// adapt the actual version that's use by the artifacts
var snapshot_qualifier = snapshot_timestamp + "-" + snapshot_build_number;
actual_version = info().version().withQualifier(snapshot_qualifier);
@ -175,7 +150,7 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
.info(info())
.updated(moment)
.build(),
info().version() + "/" + repository.getMetadataName(), false);
info().version() + "/" + repository.getMetadataName(), true);
return actual_version;
}
@ -187,18 +162,18 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @param actualVersion the version that was potentially adapted if this is a snapshot
* @since 1.5.10
*/
protected void executePublishArtifacts(Repository repository, Version actualVersion) {
protected void executePublishArtifacts(Repository repository, VersionNumber actualVersion) {
// upload 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()) {
artifact_name.append('-').append(artifact.classifier());
artifact_name.append("-").append(artifact.classifier());
}
var type = artifact.type();
if (TYPE_JAR.equals(type) || TYPE_MODULAR_JAR.equals(type) || TYPE_CLASSPATH_JAR.equals(type)) {
type = TYPE_JAR;
if (type == null) {
type = "jar";
}
artifact_name.append('.').append(type);
artifact_name.append(".").append(type);
executePublishFileArtifact(repository, artifact.file(), info().version() + "/" + artifact_name);
}
@ -211,11 +186,11 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @param actualVersion the version that was potentially adapted if this is a snapshot
* @since 1.5.10
*/
protected void executePublishPom(Repository repository, Version actualVersion) {
protected void executePublishPom(Repository repository, VersionNumber actualVersion) {
// generate and upload pom
executePublishStringArtifact(
repository,
new PomBuilder().properties(publishProperties()).info(info()).dependencies(dependencies()).build(),
new PomBuilder().info(info()).dependencies(dependencies()).build(),
info().version() + "/" + info().artifactId() + "-" + actualVersion + ".pom", true);
}
@ -227,9 +202,8 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @since 1.5.8
*/
protected void executePublishMetadata(Repository repository, ZonedDateTime moment) {
var current_versions = new ArrayList<Version>();
var resolution = new VersionResolution(properties());
var resolver = new DependencyResolver(resolution, artifactRetriever(), List.of(repository), new Dependency(info().groupId(), info().artifactId(), info().version()));
var current_versions = new ArrayList<VersionNumber>();
var resolver = new DependencyResolver(artifactRetriever(), List.of(repository), new Dependency(info().groupId(), info().artifactId(), info().version()));
try {
current_versions.addAll(resolver.getMavenMetadata().getVersions());
} catch (DependencyException e) {
@ -484,8 +458,12 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
var builder = HttpRequest.newBuilder()
.PUT(body)
.uri(URI.create(url))
.header(HEADER_USER_AGENT, constructBldUserAgent());
applyAuthorization(repository, builder);
.header(HEADER_USER_AGENT, "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") + ")");
if (repository.username() != null && repository.password() != null) {
builder.header(HEADER_AUTHORIZATION, basicAuthorizationHeader(repository.username(), repository.password()));
}
var request = builder.build();
HttpResponse<String> response;
@ -511,105 +489,6 @@ 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}.
*
@ -617,19 +496,12 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
* @since 1.5.7
*/
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());
dependencies().include(project.dependencies());
artifacts(List.of(
new PublishArtifact(new File(project.buildDistDirectory(), project.jarFileName()), "", TYPE_JAR),
new PublishArtifact(new File(project.buildDistDirectory(), project.sourcesJarFileName()), CLASSIFIER_SOURCES, TYPE_JAR),
new PublishArtifact(new File(project.buildDistDirectory(), project.javadocJarFileName()), CLASSIFIER_JAVADOC, TYPE_JAR)));
new PublishArtifact(new File(project.buildDistDirectory(), project.jarFileName()), "", "jar"),
new PublishArtifact(new File(project.buildDistDirectory(), project.sourcesJarFileName()), "sources", "jar"),
new PublishArtifact(new File(project.buildDistDirectory(), project.javadocJarFileName()), "javadoc", "jar")));
if (info().groupId() == null) {
info().groupId(project.pkg());
}
@ -645,30 +517,6 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
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.
* <p>
@ -745,18 +593,6 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
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.
*
@ -807,18 +643,6 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
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.
* <p>
@ -843,18 +667,6 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
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.
* <p>
@ -891,17 +703,4 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
}
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,7 +6,6 @@ package rife.bld.operations;
import rife.bld.BaseProject;
import rife.bld.dependencies.*;
import rife.ioc.HierarchicalProperties;
import java.io.File;
import java.util.*;
@ -25,21 +24,13 @@ import static rife.bld.dependencies.Dependency.CLASSIFIER_SOURCES;
* @since 1.5
*/
public class PurgeOperation extends AbstractOperation<PurgeOperation> {
private boolean offline_ = false;
private HierarchicalProperties properties_ = null;
private ArtifactRetriever retriever_ = null;
private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes();
private File libCompileDirectory_;
private File libCompileModulesDirectory_;
private File libProvidedDirectory_;
private File libProvidedModulesDirectory_;
private File libRuntimeDirectory_;
private File libRuntimeModulesDirectory_;
private File libStandaloneDirectory_;
private File libStandaloneModulesDirectory_;
private File libTestDirectory_;
private File libTestModulesDirectory_;
private boolean preserveSources_ = false;
private boolean preserveJavadoc_ = false;
@ -49,13 +40,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
public void execute() {
if (offline_) {
System.out.println("Offline mode: purge is disabled");
return;
}
executePurgeCompileDependencies();
executePurgeProvidedDependencies();
executePurgeRuntimeDependencies();
executePurgeStandaloneDependencies();
executePurgeTestDependencies();
@ -70,16 +55,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
protected void executePurgeCompileDependencies() {
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()));
executePurgeDependencies(libCompileDirectory(), dependencies().resolveCompileDependencies(artifactRetriever(), repositories()));
}
/**
@ -88,7 +64,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
protected void executePurgeRuntimeDependencies() {
executePurgeDependencies(libRuntimeDirectory(), libRuntimeModulesDirectory(), dependencies().resolveRuntimeDependencies(properties(), artifactRetriever(), repositories()));
executePurgeDependencies(libRuntimeDirectory(), dependencies().resolveRuntimeDependencies(artifactRetriever(), repositories()));
}
/**
@ -97,7 +73,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
protected void executePurgeStandaloneDependencies() {
executePurgeDependencies(libStandaloneDirectory(), libStandaloneModulesDirectory(), dependencies().resolveStandaloneDependencies(properties(), artifactRetriever(), repositories()));
executePurgeDependencies(libStandaloneDirectory(), dependencies().resolveStandaloneDependencies(artifactRetriever(), repositories()));
}
/**
@ -106,66 +82,46 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
protected void executePurgeTestDependencies() {
executePurgeDependencies(libTestDirectory(), libTestModulesDirectory(), dependencies().resolveTestDependencies(properties(), artifactRetriever(), repositories()));
executePurgeDependencies(libTestDirectory(), dependencies().resolveTestDependencies(artifactRetriever(), repositories()));
}
/**
* Part of the {@link #execute} operation, purge the artifacts for a particular dependency scope.
*
* @param classpathDirectory the directory from which the artifacts should be purged
* @param modulesDirectory the directory from which the modules should be purged
* @param destinationDirectory the directory from which the artifacts should be purged
* @param dependencies the dependencies to purge
* @since 2.1
* @since 1.6
*/
protected void executePurgeDependencies(File classpathDirectory, File modulesDirectory, DependencySet dependencies) {
if (classpathDirectory == null && modulesDirectory == null) {
protected void executePurgeDependencies(File destinationDirectory, DependencySet dependencies) {
if (destinationDirectory == null) {
return;
}
var classpath_names = new HashSet<String>();
var modules_names = new HashSet<String>();
var filenames = new HashSet<String>();
for (var dependency : dependencies) {
var filenames = classpath_names;
if (dependency.isModularJar()) {
filenames = modules_names;
}
addTransferLocations(filenames, dependency);
if (preserveSources_ && !dependency.excludedClassifiers().contains(CLASSIFIER_SOURCES)) {
if (preserveSources_) {
addTransferLocations(filenames, dependency.withClassifier(CLASSIFIER_SOURCES));
}
if (preserveJavadoc_ && !dependency.excludedClassifiers().contains(CLASSIFIER_JAVADOC)) {
if (preserveJavadoc_) {
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;
var classpath_files = directory.listFiles();
if (classpath_files != null) {
for (var file : classpath_files) {
if (!preservedFileNames.contains(file.getName()) && !file.equals(preserveDirectory)) {
for (var file : destinationDirectory.listFiles()) {
if (!filenames.contains(file.getName())) {
if (!printed_header) {
printed_header = true;
System.out.println("Deleting from " + directory.getName() + ":");
System.out.println("Deleting from " + destinationDirectory.getName() + ":");
}
System.out.println(" " + file.getName());
file.delete();
}
}
}
}
private void addTransferLocations(HashSet<String> filenames, Dependency dependency) {
var resolution = new VersionResolution(properties());
for (var location : new DependencyResolver(resolution, artifactRetriever(), repositories(), dependency).getTransferLocations()) {
for (var location : new DependencyResolver(artifactRetriever(), repositories(), dependency).getTransferLocations()) {
filenames.add(location.substring(location.lastIndexOf("/") + 1));
}
}
@ -177,49 +133,17 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
public PurgeOperation fromProject(BaseProject project) {
return offline(project.offline())
.properties(project.properties())
.artifactRetriever(project.artifactRetriever())
return artifactRetriever(project.artifactRetriever())
.repositories(project.repositories())
.dependencies(project.dependencies())
.libCompileDirectory(project.libCompileDirectory())
.libCompileModulesDirectory(project.libCompileModulesDirectory())
.libProvidedDirectory(project.libProvidedDirectory())
.libProvidedModulesDirectory(project.libProvidedModulesDirectory())
.libRuntimeDirectory(project.libRuntimeDirectory())
.libRuntimeModulesDirectory(project.libRuntimeModulesDirectory())
.libStandaloneDirectory(project.libStandaloneDirectory())
.libStandaloneModulesDirectory(project.libStandaloneModulesDirectory())
.libTestDirectory(project.libTestDirectory())
.libTestModulesDirectory(project.libTestModulesDirectory())
.preserveSources(project.downloadSources())
.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.
*
@ -296,42 +220,6 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
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.
*
@ -344,18 +232,6 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
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.
*
@ -368,18 +244,6 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
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.
*
@ -392,18 +256,6 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
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.
*
@ -416,18 +268,6 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
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.
* <p>
@ -462,36 +302,6 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
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.
*
@ -502,16 +312,6 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
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.
*
@ -522,16 +322,6 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
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.
*
@ -542,16 +332,6 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
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.
*
@ -586,17 +366,4 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
}
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,7 +8,6 @@ import rife.bld.BaseProject;
import rife.tools.FileUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -18,7 +17,6 @@ import java.util.List;
* @since 1.5
*/
public class RunOperation extends AbstractProcessOperation<RunOperation> {
public static final String ARGS_OPTION = "--args=";
protected final List<String> runOptions_ = new ArrayList<>();
/**
@ -31,30 +29,12 @@ public class RunOperation extends AbstractProcessOperation<RunOperation> {
var args = new ArrayList<String>();
args.add(javaTool());
args.addAll(javaOptions());
if (!classpath().isEmpty()) {
args.add("-cp");
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());
}
else if (!silent()) {
System.err.println("No main class or module specified.");
}
args.addAll(runOptions());
return args;
}
@ -68,26 +48,10 @@ public class RunOperation extends AbstractProcessOperation<RunOperation> {
var operation = workDirectory(project.workDirectory())
.javaTool(project.javaTool())
.classpath(project.runClasspath())
.modulePath(project.runModulePath())
.mainClass(project.mainClass())
.module(project.module());
.mainClass(project.mainClass());
if (project.usesRife2Agent()) {
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;
}

View file

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

View file

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

View file

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

@ -1,30 +0,0 @@
/**
* 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

@ -1,40 +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.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,6 +4,8 @@
*/
package rife.bld.operations.exceptions;
import rife.tools.HttpUtils;
import java.io.File;
import java.io.Serial;

View file

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

View file

@ -7,15 +7,10 @@ package rife.bld.publish;
import rife.bld.dependencies.*;
import rife.template.Template;
import rife.template.TemplateFactory;
import rife.tools.FileUtils;
import rife.tools.StringUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File;
import java.util.Objects;
import static rife.bld.dependencies.Dependency.TYPE_JAR;
/**
* Provides the functionalities to build a Maven POM xml file.
*
@ -24,7 +19,6 @@ import static rife.bld.dependencies.Dependency.TYPE_JAR;
*/
public class PomBuilder {
private PublishInfo info_ = null;
private PublishProperties properties_ = new PublishProperties();
private DependencyScopes dependencies_ = new DependencyScopes();
/**
@ -49,28 +43,6 @@ public class PomBuilder {
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.
*
@ -140,38 +112,15 @@ 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()) {
addDependencies(t, Scope.compile);
addDependencies(t, Scope.runtime);
addDependencies(t, Scope.provided);
t.setBlock("dependencies-tag");
}
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) {
var scoped_dependencies = dependencies().scope(scope);
if (!scoped_dependencies.isEmpty()) {
@ -188,7 +137,7 @@ public class PomBuilder {
t.blankValue("dependency-type");
t.blankValue("dependency-type-tag");
if (!TYPE_JAR.equals(dependency.type())) {
if (!dependency.type().equals("jar")) {
t.setValueEncoded("dependency-type", dependency.type());
t.setBlock("dependency-type-tag");
}

View file

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

View file

@ -4,7 +4,6 @@
*/
package rife.bld.publish;
import rife.bld.dependencies.Version;
import rife.bld.dependencies.VersionNumber;
import java.util.ArrayList;
@ -19,7 +18,7 @@ import java.util.List;
public class PublishInfo {
private String groupId_ = null;
private String artifactId_ = null;
private Version version_ = null;
private VersionNumber version_ = null;
private String name_ = null;
private String description_ = null;
private String url_ = null;
@ -82,7 +81,7 @@ public class PublishInfo {
* @return this {@code PublishInfo} instance
* @since 1.5.7
*/
public PublishInfo version(Version version) {
public PublishInfo version(VersionNumber version) {
version_ = version;
return this;
}
@ -93,7 +92,7 @@ public class PublishInfo {
* @return the project's version.
* @since 1.5.7
*/
public Version version() {
public VersionNumber version() {
return version_;
}
@ -164,7 +163,7 @@ public class PublishInfo {
}
/**
* Provides the custom path to the {@code gpg} executable used for signing.
* Provides the custompath to the {@code gpg} executable used for signing.
* <p>
* By default, {@code gpg} will be used.
*

View file

@ -1,80 +0,0 @@
/*
* 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,7 +18,6 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.jar.*;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import static rife.tools.FileUtils.JAR_FILE_PATTERN;
@ -33,53 +32,32 @@ import static rife.tools.FileUtils.JAVA_FILE_PATTERN;
* @since 1.5
*/
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 CENTRAL_SNAPSHOTS = "https://central.sonatype.com/repository/maven-snapshots/";
static final String SONATYPE_SNAPSHOTS = "https://s01.oss.sonatype.org/content/repositories/snapshots/";
static final String DOWNLOAD_LOCATION = MAVEN_CENTRAL + "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 DOWNLOAD_LOCATION_SNAPSHOT = SONATYPE_SNAPSHOTS + "com/uwyn/rife2/bld/${version}/";
static final String BLD_FILENAME = "bld-${version}.jar";
static final String BLD_SOURCES_FILENAME = "bld-${version}-sources.jar";
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 BLD_PROPERTY_VERSION = "bld.version";
static final String RIFE2_PROPERTY_DOWNLOAD_LOCATION = "rife2.downloadLocation";
static final String BLD_PROPERTY_DOWNLOAD_LOCATION = "bld.downloadLocation";
static final String PROPERTY_REPOSITORIES = "bld.repositories";
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_JAVADOC = "bld.downloadExtensionJavadoc";
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 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 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 LaunchMode launchMode_ = LaunchMode.Cli;
private boolean offline_ = false;
private final Properties jvmProperties_ = new Properties();
private final Properties wrapperProperties_ = new Properties();
private File wrapperPropertiesFile_ = null;
private final Set<String> repositories_ = new LinkedHashSet<>();
@ -120,10 +98,6 @@ public class Wrapper {
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_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.
@ -135,50 +109,15 @@ public class Wrapper {
*/
public void upgradeIdeaBldLibrary(File destinationDirectory, String version)
throws IOException {
var libraries_bld = new File(destinationDirectory, Path.of("libraries", "bld.xml").toString());
if (libraries_bld.exists()) {
var file = new File(destinationDirectory, Path.of("libraries", "bld.xml").toString());
if (file.exists()) {
try {
var content = FileUtils.readString(libraries_bld);
var content = FileUtils.readString(file);
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 = 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");
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);
FileUtils.writeString(content, file);
} catch (FileUtilsErrorException e) {
throw new IOException(e);
}
@ -199,8 +138,8 @@ public class Wrapper {
if (file.exists()) {
try {
var content = FileUtils.readString(file);
content = BLD_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + ".jar");
content = RIFE2_JAR_PATTERN.matcher(content).replaceAll("/.bld/dist/bld-" + version + ".jar");
content = BLD_JAR_PATTERN.matcher(content).replaceAll("bld-" + version + ".jar");
content = RIFE2_JAR_PATTERN.matcher(content).replaceAll("bld-" + version + ".jar");
FileUtils.writeString(content, file);
} catch (FileUtilsErrorException e) {
throw new IOException(e);
@ -225,11 +164,9 @@ public class Wrapper {
var properties_blueprint = """
bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true
bld.downloadLocation=
bld.extensions=
bld.javaOptions=
bld.javacOptions=
bld.repositories=MAVEN_CENTRAL,RIFE2_RELEASES
bld.repositories=MAVEN_CENTRAL,RIFE2
bld.downloadLocation=
bld.sourceDirectories=
bld.version=${version}
"""
@ -253,7 +190,6 @@ public class Wrapper {
try (var jar = new JarOutputStream(new FileOutputStream(new File(destinationDirectory, WRAPPER_JAR)), manifest)) {
addClassToJar(jar, Wrapper.class);
addClassToJar(jar, Wrapper.LaunchMode.class);
addClassToJar(jar, WrapperClassLoader.class);
addClassToJar(jar, FileUtils.class);
addClassToJar(jar, FileUtilsErrorException.class);
@ -263,107 +199,6 @@ 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)
throws IOException {
addFileToJar(jar, klass.getName().replace('.', '/') + ".class");
@ -414,49 +249,28 @@ public class Wrapper {
private int installAndLaunch(List<String> arguments) {
if (!arguments.isEmpty()) {
File current_file;
File current_file = null;
try {
current_file = new File(arguments.remove(0)).getCanonicalFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
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 {
extractJvmProperties(arguments);
initWrapperProperties(getVersion());
var distribution = installDistribution();
File distribution;
try {
distribution = installDistribution();
} catch (IOException e) {
return -1;
}
return launchMain(distribution, arguments);
} catch (Exception 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() {
return Path.of(currentDir_.getAbsolutePath(), "build", "bld").toFile();
}
@ -481,6 +295,50 @@ public class Wrapper {
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()
throws IOException {
return wrapperProperties_.getProperty(BLD_PROPERTY_VERSION, getVersion());
@ -506,7 +364,7 @@ public class Wrapper {
var location = getWrapperDownloadLocation(version);
var result = new StringBuilder(location);
if (!location.endsWith("/")) {
result.append('/');
result.append("/");
}
result.append(fileName);
return result.toString();
@ -543,63 +401,32 @@ public class Wrapper {
var download_version = 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) {
var meta_data = "";
try {
meta_data = readString(version, new URL(downloadUrl(version, "maven-metadata.xml")));
} 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 meta_data = readString(version, new URL(downloadUrl(version, "maven-metadata.xml")));
var matcher = META_DATA_SNAPSHOT_VERSION.matcher(meta_data);
if (matcher.find()) {
download_version = matcher.group(1);
}
}
var distribution_file = new File(DISTRIBUTIONS_DIR, bldFileName(version));
var distribution_sources_file = new File(DISTRIBUTIONS_DIR, bldSourcesFileName(version));
if (!offline_) {
// if this is a snapshot and the distribution file exists,
// ensure that it's the latest by comparing hashes
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"));
try {
var digest = MessageDigest.getInstance("MD5");
digest.update(FileUtils.readBytes(distribution_file));
if (!download_md5.equals(encodeHexLower(digest.digest()))) {
delete_distribution_files = true;
distribution_file.delete();
distribution_sources_file.delete();
}
} catch (NoSuchAlgorithmException ignore) {
}
}
if (delete_distribution_files) {
distribution_file.delete();
if (distribution_sources_file.exists()) {
distribution_sources_file.delete();
}
}
}
// download distribution jars if necessary
if (!distribution_file.exists()) {
downloadDistribution(distribution_file, downloadUrl(version, bldFileName(download_version)));
@ -611,7 +438,6 @@ public class Wrapper {
// this is not critical, ignore
}
}
}
// find the wrapper classloader in the hierarchy and add the bld jar to it
classloader_ = new WrapperClassLoader();
@ -649,17 +475,15 @@ public class Wrapper {
private void resolveExtensions() {
if (null == classloader_ ||
null == wrapperPropertiesFile_ ||
offline_) {
null == wrapperPropertiesFile_) {
return;
}
try {
var resolver_class = classloader_.loadClass("rife.bld.wrapper.WrapperExtensionResolver");
var constructor = resolver_class.getConstructor(File.class, File.class, Properties.class, Properties.class, Collection.class, Collection.class, boolean.class, boolean.class);
var constructor = resolver_class.getConstructor(File.class, File.class, File.class, Collection.class, Collection.class, boolean.class, boolean.class);
var update_method = resolver_class.getMethod("updateExtensions");
var resolver = constructor.newInstance(currentDir_, libBldDirectory(),
jvmProperties_, wrapperProperties_,
var resolver = constructor.newInstance(currentDir_, new File(wrapperPropertiesFile_.getAbsolutePath() + ".hash"), libBldDirectory(),
repositories_, extensions_,
downloadExtensionSources_, downloadExtensionJavadoc_);
update_method.invoke(resolver);
@ -672,7 +496,7 @@ public class Wrapper {
private int launchMain(File jarFile, List<String> arguments)
throws IOException, InterruptedException, FileUtilsErrorException {
if (launchMode_ == LaunchMode.Cli) {
if (arguments.isEmpty() || !arguments.get(0).equals("--build")) {
return launchMainCli(jarFile, arguments);
}
return launchMainBuild(jarFile, arguments);
@ -681,8 +505,8 @@ public class Wrapper {
private int launchMainCli(File jarFile, List<String> arguments)
throws IOException, InterruptedException {
var args = new ArrayList<String>();
args.add(findJavaExecutable());
includeJvmProperties(arguments, args);
args.add("java");
includeJvmParameters(arguments, args);
args.add("-cp");
args.add(jarFile.getAbsolutePath());
@ -690,7 +514,6 @@ public class Wrapper {
args.add("-jar");
args.add(jarFile.getAbsolutePath());
args.addAll(bldJavaOptions());
args.addAll(arguments);
var process_builder = new ProcessBuilder(args);
@ -703,6 +526,8 @@ public class Wrapper {
throws IOException, InterruptedException {
resolveExtensions();
arguments.remove(0);
var build_bld_dir = buildBldDirectory();
if (build_bld_dir.exists()) {
FileUtils.deleteDirectory(buildBldDirectory());
@ -720,7 +545,6 @@ public class Wrapper {
var compilation_units = file_manager.getJavaFileObjectsFromFiles(bldSourceFiles());
var diagnostics = new DiagnosticCollector<JavaFileObject>();
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);
if (!compilation_task.call()) {
if (!diagnostics.getDiagnostics().isEmpty()) {
@ -734,15 +558,11 @@ public class Wrapper {
}
var java_args = new ArrayList<String>();
java_args.add(findJavaExecutable());
includeJvmProperties(arguments, java_args);
java_args.add("java");
includeJvmParameters(arguments, java_args);
java_args.add("-cp");
java_args.add(classpath);
java_args.addAll(bldJavaOptions());
java_args.addAll(arguments);
var process_builder = new ProcessBuilder(java_args);
process_builder.directory(currentDir_);
process_builder.inheritIO();
@ -751,20 +571,11 @@ public class Wrapper {
return process.waitFor();
}
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) {
private static void includeJvmParameters(List<String> arguments, List<String> javaArgs) {
var i = arguments.iterator();
while (i.hasNext()) {
var arg = i.next();
if (JVM_PROPERTY_PATTERN.matcher(arg).matches()) {
if (arg.matches("-D(.+?)=(.*)")) {
javaArgs.add(arg);
i.remove();
}
@ -774,7 +585,7 @@ public class Wrapper {
private List<File> bldClasspathJars() {
// detect the jar files in the compile lib directory
var dir_abs = libBldDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, CLASSPATH_INCLUDED_JARS, CLASSPATH_EXCLUDED_JARS);
var jar_files = FileUtils.getFileList(dir_abs, JAR_FILE_PATTERN, Pattern.compile(WRAPPER_JAR));
// build the compilation classpath
return new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
@ -804,28 +615,6 @@ public class Wrapper {
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)
throws IOException {
var connection = url.openConnection();

View file

@ -4,12 +4,16 @@
*/
package rife.bld.wrapper;
import rife.bld.BldCache;
import rife.bld.BuildExecutor;
import rife.bld.dependencies.*;
import rife.ioc.HierarchicalProperties;
import rife.tools.FileUtils;
import rife.tools.StringUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import static rife.bld.dependencies.Dependency.CLASSIFIER_JAVADOC;
@ -24,8 +28,9 @@ import static rife.bld.dependencies.Dependency.CLASSIFIER_SOURCES;
* @since 1.5.8
*/
public class WrapperExtensionResolver {
private final VersionResolution resolution_;
private final ArtifactRetriever retriever_;
private final ArtifactRetriever retriever_ = ArtifactRetriever.cachingInstance();
private final File hashFile_;
private final String fingerPrintHash_;
private final File destinationDirectory_;
private final List<Repository> repositories_ = new ArrayList<>();
private final DependencySet dependencies_ = new DependencySet();
@ -35,41 +40,39 @@ public class WrapperExtensionResolver {
private boolean headerPrinted_ = false;
public WrapperExtensionResolver(File currentDir, File destinationDirectory,
Properties jvmProperties, Properties wrapperProperties,
public WrapperExtensionResolver(File currentDir, File hashFile, File destinationDirectory,
Collection<String> repositories, Collection<String> extensions,
boolean downloadSources, boolean downloadJavadoc) {
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);
hashFile_ = hashFile;
destinationDirectory_ = destinationDirectory;
for (var repository : repositories) {
repositories_.add(Repository.resolveRepository(properties, repository));
}
dependencies_.addAll(extensions.stream().map(d -> resolution_.overrideDependency(Dependency.parse(d))).toList());
dependencies_.addAll(extensions.stream().map(Dependency::parse).toList());
downloadSources_ = downloadSources;
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() {
// verify and update the fingerprint hash file,
// don't update the extensions if the hash is identical
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()) {
if (validateHash()) {
return;
}
@ -79,20 +82,74 @@ public class WrapperExtensionResolver {
// purge the files that are not part of the latest extensions anymore
purgeExtensionDependencies(filenames);
cache.cacheExtensionsLocalArtifacts(localArtifacts_);
cache.writeCache();
writeHash();
if (headerPrinted_) {
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() {
var filenames = new HashSet<String>();
var dependencies = new DependencySet();
for (var d : dependencies_) {
if (d != null) {
dependencies.addAll(new DependencyResolver(resolution_, retriever_, repositories_, d).getAllDependencies(Scope.compile, Scope.runtime));
dependencies.addAll(new DependencyResolver(retriever_, repositories_, d).getAllDependencies(Scope.compile, Scope.runtime));
}
}
if (!dependencies.isEmpty()) {
@ -109,7 +166,7 @@ public class WrapperExtensionResolver {
additional_classifiers = classifiers.toArray(new String[0]);
}
var artifacts = dependencies.transferIntoDirectory(resolution_, retriever_, repositories_, destinationDirectory_, destinationDirectory_, additional_classifiers);
var artifacts = dependencies.transferIntoDirectory(retriever_, repositories_, destinationDirectory_, additional_classifiers);
for (var artifact : artifacts) {
var location = artifact.location();
@ -126,7 +183,7 @@ public class WrapperExtensionResolver {
private void purgeExtensionDependencies(Set<String> filenames) {
for (var file : destinationDirectory_.listFiles()) {
if (file.getName().startsWith(Wrapper.WRAPPER_PREFIX) ||
file.getName().equals(Wrapper.BLD_CACHE)) {
file.getName().equals(Wrapper.BLD_BUILD_HASH)) {
continue;
}
if (!filenames.contains(file.getName())) {

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