2
0
Fork 0
mirror of https://github.com/ethauvin/bld.git synced 2025-04-24 07:47:11 -07:00

First commit of standalone repo

This commit is contained in:
Geert Bevin 2023-05-09 21:20:16 -04:00
commit 696b23b57a
241 changed files with 28028 additions and 0 deletions

57
.gitignore vendored Normal file
View file

@ -0,0 +1,57 @@
*.log
embedded_dbs
.gradle
.DS_Store
build
lib/bld/**
lib/compile/**
lib/runtime/**
lib/standalone/**
lib/test/**
!bld-wrapper.jar
!bld-wrapper.properties
# IDEA ignores
# User-specific
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Editor-based Rest Client
.idea/httpRequests

8
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

14
.idea/bld.iml generated Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/build/bld" />
<output-test url="file://$MODULE_DIR$/build/bld" />
<exclude-output />
<content url="file://$MODULE_DIR$/src/bld">
<sourceFolder url="file://$MODULE_DIR$/src/bld/java" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="bld" level="project" />
</component>
</module>

7
.idea/codeStyles/Project.xml generated Normal file
View file

@ -0,0 +1,7 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<ScalaCodeStyleSettings>
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
</ScalaCodeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View file

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

32
.idea/framework.iml generated Normal file
View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/build/main" />
<output-test url="file://$MODULE_DIR$/build/test" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/core/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/core/src/test/java" isTestSource="true" />
<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" />
<orderEntry type="module-library" scope="RUNTIME">
<library>
<CLASSES>
<root url="file://$MODULE_DIR$/src/main/resources/templates" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<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>

17
.idea/libraries/bld.xml generated Normal file
View file

@ -0,0 +1,17 @@
<component name="libraryTable">
<library name="bld">
<CLASSES>
<root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.rife2/dist/rife2-1.6.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.rife2/dist/rife2-1.6.3-sources.jar!/" />
</SOURCES>
<excluded>
<root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" />
</excluded>
<jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" type="SOURCES" />
</library>
</component>

13
.idea/libraries/compile.xml generated Normal file
View file

@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="compile">
<CLASSES>
<root url="file://$PROJECT_DIR$/lib/compile" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/compile" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" type="SOURCES" />
</library>
</component>

14
.idea/libraries/runtime.xml generated Normal file
View file

@ -0,0 +1,14 @@
<component name="libraryTable">
<library name="runtime">
<CLASSES>
<root url="file://$PROJECT_DIR$/lib/runtime" />
<root url="file://$PROJECT_DIR$/src/main/resources" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/runtime" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" type="SOURCES" />
</library>
</component>

15
.idea/libraries/test.xml generated Normal file
View file

@ -0,0 +1,15 @@
<component name="libraryTable">
<library name="test">
<CLASSES>
<root url="file://$PROJECT_DIR$/lib/test" />
<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" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" type="SOURCES" />
</library>
</component>

9
.idea/misc.xml generated Normal file
View file

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

9
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/bld.iml" filepath="$PROJECT_DIR$/.idea/bld.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/framework.iml" filepath="$PROJECT_DIR$/.idea/framework.iml" />
</modules>
</component>
</project>

13
.idea/runConfigurations/Run Tests.xml generated Normal file
View file

@ -0,0 +1,13 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run Tests" type="JUnit" factoryName="JUnit">
<module name="framework" />
<option name="PACKAGE_NAME" value="rife" />
<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>

7
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/core" vcs="Git" />
</component>
</project>

202
LICENSE.txt Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

2
bld Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/env sh
java -jar "$(dirname "$0")/lib/bld/bld-wrapper.jar" "$0" --build rife.BldBuild "$@"

4
bld.bat Normal file
View file

@ -0,0 +1,4 @@
@echo off
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
java -jar "%DIRNAME%/lib/bld/bld-wrapper.jar" "%0" --build rife.BldBuild %*

BIN
images/bld_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

13
images/bld_logo.svg Normal file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 179 108" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-210.511,-96.3382)">
<g transform="matrix(1,0,0,1,-23.3386,-649.816)">
<g transform="matrix(0.221288,0,0,0.24,73.9536,390.254)">
<path d="M722.568,1482.92L722.568,1921.1L808.968,1921.1L808.968,1888.7C822.168,1907.9 846.168,1930.1 893.568,1930.1C933.168,1930.1 961.968,1917.5 985.368,1893.5C1012.97,1865.9 1027.37,1827.5 1027.37,1786.1C1027.37,1741.7 1011.17,1705.1 985.368,1680.5C961.968,1658.3 928.968,1644.5 892.368,1644.5C862.968,1644.5 830.568,1654.1 808.968,1683.5L808.968,1482.92L722.568,1482.92ZM871.368,1718.9C888.768,1718.9 903.768,1723.7 917.568,1736.9C930.168,1748.9 938.568,1766.3 938.568,1787.9C938.568,1807.7 930.168,1825.1 917.568,1837.1C904.368,1849.7 887.568,1855.7 872.568,1855.7C856.368,1855.7 837.168,1849.1 823.368,1835.9C813.168,1826.3 803.568,1810.1 803.568,1787.9C803.568,1765.1 812.568,1749.5 822.768,1738.7C836.568,1724.3 852.768,1718.9 871.368,1718.9Z" style="fill:rgb(35,146,255);fill-rule:nonzero;"/>
<rect x="1083.77" y="1482.92" width="86.4" height="438.182" style="fill:rgb(250,144,82);fill-rule:nonzero;"/>
<path d="M1531.37,1482.92L1444.97,1482.92L1444.97,1683.5C1423.37,1654.1 1390.97,1644.5 1361.57,1644.5C1324.97,1644.5 1291.97,1658.3 1268.57,1680.5C1242.77,1705.1 1226.57,1741.7 1226.57,1786.1C1226.57,1827.5 1240.97,1865.9 1268.57,1893.5C1291.97,1917.5 1320.77,1930.1 1360.37,1930.1C1407.77,1930.1 1431.77,1907.9 1444.97,1888.7L1444.97,1921.1L1531.37,1921.1L1531.37,1482.92ZM1382.57,1718.9C1401.17,1718.9 1417.37,1724.3 1431.17,1738.7C1441.37,1749.5 1450.37,1765.1 1450.37,1787.9C1450.37,1810.1 1440.77,1826.3 1430.57,1835.9C1416.77,1849.1 1397.57,1855.7 1381.37,1855.7C1366.37,1855.7 1349.57,1849.7 1336.37,1837.1C1323.77,1825.1 1315.37,1807.7 1315.37,1787.9C1315.37,1766.3 1323.77,1748.9 1336.37,1736.9C1350.17,1723.7 1365.17,1718.9 1382.57,1718.9Z" style="fill:rgb(35,146,255);fill-rule:nonzero;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
lib/bld/bld-wrapper.jar Normal file

Binary file not shown.

View file

@ -0,0 +1,8 @@
bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true
bld.extension-antlr=com.uwyn.rife2:bld-antlr4:1.1.0
bld.extension-archive=com.uwyn.rife2:bld-archive:0.3.0
bld.extension-tests=com.uwyn.rife2:bld-tests-badge:1.3.0
bld.repositories=MAVEN_CENTRAL,RIFE2_RELEASES
rife2.downloadLocation=
rife2.version=1.6.3

View file

@ -0,0 +1,254 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife;
import rife.bld.BuildCommand;
import rife.bld.Project;
import rife.bld.dependencies.VersionNumber;
import rife.bld.extension.Antlr4Operation;
import rife.bld.extension.TestsBadgeOperation;
import rife.bld.extension.ZipOperation;
import rife.bld.operations.*;
import rife.bld.publish.*;
import rife.bld.wrapper.Wrapper;
import rife.tools.DirBuilder;
import rife.tools.FileUtils;
import rife.tools.StringUtils;
import java.io.File;
import java.nio.file.Files;
import java.util.List;
import java.util.jar.Attributes;
import java.util.regex.Pattern;
import static rife.bld.dependencies.Repository.*;
import static rife.bld.dependencies.Scope.*;
import static rife.bld.operations.JavadocOptions.DocLinkOption.NO_MISSING;
import static rife.bld.operations.TemplateType.*;
import static rife.tools.FileUtils.path;
public class BldBuild extends Project {
public BldBuild()
throws Exception {
pkg = "rife";
name = "bld";
mainClass = "rife.bld.Cli";
version = version(FileUtils.readString(new File(srcMainResourcesDirectory(), "BLD_VERSION")));
javaRelease = 17;
downloadSources = true;
autoDownloadPurge = true;
repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES);
scope(test)
.include(dependency("org.slf4j", "slf4j-simple", version(2,0,7)))
.include(dependency("net.imagej", "ij", version("1.54d")))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5,9,3)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1,9,3)))
.include(dependency("com.h2database", "h2", version(2,1,214)))
.include(dependency("net.sourceforge.htmlunit", "htmlunit", version(2,70,0)))
.include(dependency("org.postgresql", "postgresql", version(42,6,0)))
.include(dependency("com.mysql", "mysql-connector-j", version(8,0,33)))
.include(dependency("org.mariadb.jdbc", "mariadb-java-client", version(3,1,4)))
.include(dependency("org.hsqldb", "hsqldb", version(2,7,1)))
.include(dependency("org.apache.derby", "derby", version("10.16.1.1")))
.include(dependency("org.apache.derby", "derbytools", version("10.16.1.1")))
.include(dependency("com.oracle.database.jdbc", "ojdbc11", version("23.2.0.0")))
.include(dependency("org.json", "json", version(20230227)));
cleanOperation()
.directories(
new File(workDirectory(), "embedded_dbs"),
new File(workDirectory(), "logs"));
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_directory, "antlr")))
.outputDirectory(new File(buildDirectory(), "generated/rife/template/antlr"))
.visitor()
.longMessages();
precompileOperation()
.sourceDirectories(core_src_main_resources_templates_directory)
.templateTypes(HTML, XML, SQL, TXT, JSON);
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_directory)
.excluded(Pattern.compile("^\\Q" + core_src_main_resources_templates_directory.getAbsolutePath() + "\\E.*"))
.manifestAttribute(Attributes.Name.MAIN_CLASS, mainClass());
zipBldOperation
.destinationDirectory(buildDistDirectory())
.destinationFileName("rife2-" + version() + "-bld.zip");
testsBadgeOperation
.classpath(core_src_main_resources_directory.getAbsolutePath())
.classpath(core_src_test_resources_directory.getAbsolutePath());
propagateJavaProperties(testsBadgeOperation.javaOptions(),
"test.postgres",
"test.mysql",
"test.mariadb",
"test.oracle",
"test.oracle-free",
"test.derby",
"test.hsqldb",
"test.h2");
javadocOperation()
.excluded(
"rife/antlr/",
"rife/asm/",
"rife/.*/databasedrivers/",
"rife/.*/imagestoredrivers/",
"rife/.*/rawstoredrivers/",
"rife/.*/textstoredrivers/",
"rife/database/capabilities/"
)
.javadocOptions()
.docTitle("<a href=\"https://rife2.com/bld\">bld</a> " + version())
.docLint(NO_MISSING)
.keywords()
.splitIndex()
.tag("apiNote", "a", "API Note:")
.link("https://jakarta.ee/specifications/servlet/5.0/apidocs/")
.link("https://jsoup.org/apidocs/")
.overview(new File(srcMainJavaDirectory(), "overview.html"));
publishOperation()
.repository(version.isSnapshot() ? repository("rife2-snapshots") : repository("rife2-releases"))
.repository(version.isSnapshot() ? repository("sonatype-snapshots") : repository("sonatype-releases"))
.info(new PublishInfo()
.groupId("com.uwyn.rife2")
.artifactId("bld")
.name("bld")
.description("Pure java build tool for developers who don't like dealing with build tools.")
.url("https://github.com/rife2/bld")
.developer(new PublishDeveloper()
.id("gbevin")
.name("Geert Bevin")
.email("gbevin@uwyn.com")
.url("https://github.com/gbevin"))
.license(new PublishLicense()
.name("The Apache License, Version 2.0")
.url("https://www.apache.org/licenses/LICENSE-2.0.txt"))
.scm(new PublishScm()
.connection("scm:git:https://github.com/rife2/bld.git")
.developerConnection("scm:git:git@github.com:rife2/bld.git")
.url("https://github.com/rife2/bld"))
.signKey(property("sign.key"))
.signPassphrase(property("sign.passphrase")))
.artifacts(
new PublishArtifact(zipBldOperation.destinationFile(), "bld", "zip"));
}
void propagateJavaProperties(JavaOptions options, String... names) {
for (var name : names) {
if (properties().contains(name)) {
options.property(name, properties().getValueString(name));
}
}
}
final Antlr4Operation antlr4Operation = new Antlr4Operation() {
@Override
public void execute()
throws Exception {
super.execute();
// replace the package name so that it becomes part of RIFE2
FileUtils.transformFiles(outputDirectory(), FileUtils.JAVA_FILE_PATTERN, null, s ->
StringUtils.replace(s, "org.antlr.v4.runtime", "rife.antlr.v4.runtime"));
}
};
@BuildCommand(summary = "Generates the grammar Java sources")
public void generateGrammar()
throws Exception {
antlr4Operation.executeOnce();
}
public void compile()
throws Exception {
generateGrammar();
super.compile();
}
final ZipOperation zipBldOperation = new ZipOperation();
@BuildCommand(value = "zip-bld", summary = "Creates the bld zip archive")
public void zipBld()
throws Exception {
jar();
var tmp = Files.createTempDirectory("bld").toFile();
try {
new Wrapper().createWrapperFiles(path(tmp, "lib").toFile(), VersionNumber.UNKNOWN.toString());
new DirBuilder(tmp, t -> {
t.dir("bld", b -> {
b.dir("bin", i -> {
i.file("bld", f -> {
f.copy(path(srcMainDirectory(), "bld", "bld"));
f.perms(0755);
});
i.file("bld.bat", f -> {
f.copy(path(srcMainDirectory(), "bld", "bld.bat"));
f.perms(0755);
});
});
b.dir("lib", l -> {
l.file("bld-wrapper.jar", f -> f.move(path(tmp, "lib", "bld-wrapper.jar")));
});
});
t.dir("lib", l -> l.delete());
});
zipBldOperation
.sourceDirectories(tmp)
.execute();
} finally {
FileUtils.deleteDirectory(tmp);
}
}
private final TestsBadgeOperation testsBadgeOperation = new TestsBadgeOperation();
public void test()
throws Exception {
testsBadgeOperation.executeOnce(() -> testsBadgeOperation
.url(property("testsBadgeUrl"))
.apiKey(property("testsBadgeApiKey"))
.fromProject(this));
}
@BuildCommand(summary = "Creates all the distribution artifacts")
public void all()
throws Exception {
jar();
jarSources();
jarJavadoc();
zipBld();
}
public void publish()
throws Exception {
all();
super.publish();
}
public static void main(String[] args)
throws Exception {
new BldBuild().start(args);
}
}

2
src/main/bld/bld Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/env sh
java -jar "$(dirname "$0")/../lib/bld-wrapper.jar" "$0" "$@"

4
src/main/bld/bld.bat Normal file
View file

@ -0,0 +1,4 @@
@echo off
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
java -jar "%DIRNAME%/../lib/bld-wrapper.jar" "%0" %*

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,43 @@
/*
* 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.resources.ResourceFinderClasspath;
import rife.resources.exceptions.ResourceFinderErrorException;
/**
* Singleton class that provides access to the current RIFE2 version as a string.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.0
*/
public class BldVersion {
private String version_;
BldVersion() {
ResourceFinderClasspath resource_finder = ResourceFinderClasspath.instance();
try {
version_ = resource_finder.getContent("BLD_VERSION");
} catch (ResourceFinderErrorException e) {
version_ = null;
}
if (version_ != null) {
version_ = version_.trim();
}
if (null == version_) {
version_ = "unknown version";
}
}
private String getVersionString() {
return version_;
}
public static String getVersion() {
return BldVersionSingleton.INSTANCE.getVersionString();
}
}

View file

@ -0,0 +1,14 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld;
/**
* Helper class to avoid Double Check Locking
* and still have a thread-safe singleton pattern
*/
class BldVersionSingleton {
static final BldVersion INSTANCE = new BldVersion();
}

View file

@ -0,0 +1,52 @@
/*
* 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 java.lang.annotation.*;
/**
* Declares a {@link BuildExecutor} method to be used as a build command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface BuildCommand {
/**
* When provided, specifies a name for the build command that can be
* different from the method name.
*
* @return a string representing the build command name
* @since 1.5
*/
String value() default "";
/**
* When provided, specifies a short description about the command.
*
* @return the short summary, defaults to {@code ""}
* @since 1.5.12
*/
String summary() default "";
/**
* When provided, specifies the full help description of a command.
*
* @return the full help description, defaults to {@code ""}
* @since 1.5.12
*/
String description() default "";
/**
* When provided, specifies a class that provides help about the
* build command.
*
* @return a class providing help information
* @since 1.5
*/
Class<? extends CommandHelp> help() default CommandHelp.class;
}

View file

@ -0,0 +1,467 @@
/*
* 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.DependencyResolver;
import rife.bld.dependencies.Repository;
import rife.bld.help.HelpHelp;
import rife.bld.operations.HelpOperation;
import rife.bld.operations.exceptions.ExitStatusException;
import rife.ioc.HierarchicalProperties;
import rife.tools.ExceptionUtils;
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;
import java.util.regex.Pattern;
/**
* Base class that executes build commands from a list of arguments.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @see BuildCommand
* @see CommandDefinition
* @since 1.5
*/
public class BuildExecutor {
public static final File RIFE2_USER_DIR = new File(System.getProperty("user.home"), ".rife2");
public static final String BLD_PROPERTIES = "bld.properties";
public static final String LOCAL_PROPERTIES = "local.properties";
private static final String ARG_HELP1 = "--help";
private static final String ARG_HELP2 = "-h";
private static final String ARG_HELP3 = "-?";
private static final String ARG_STACKTRACE1 = "--stacktrace";
private static final String ARG_STACKTRACE2 = "-s";
private final HierarchicalProperties properties_;
private List<String> arguments_ = Collections.emptyList();
private Map<String, CommandDefinition> buildCommands_ = null;
private final AtomicReference<String> currentCommandName_ = new AtomicReference<>();
private final AtomicReference<CommandDefinition> currentCommandDefinition_ = new AtomicReference<>();
private int exitStatus_ = 0;
/**
* Show the full Java stacktrace when exceptions occur, as opposed
* to the chain of messages.
* <p>
* Defaults to {@code false}, can be set to {@code true} by setting
* through code or by adding {@code --stacktrace} as a CLI argument.
*
* @since 1.5.19
*/
protected boolean showStacktrace = false;
/**
* Creates a new build executor instance.
*
* @since 1.5
*/
public BuildExecutor() {
properties_ = setupProperties(workDirectory());
Repository.resolveMavenLocal(properties());
}
/**
* Creates a properties hierarchy for bld execution.
*
* @param workDirectory the directory where the project build files are location
* @return the properties hierarchy
* @since 1.5.12
*/
public static HierarchicalProperties setupProperties(File workDirectory) {
var system_properties = HierarchicalProperties.createSystemInstance();
var java_properties = system_properties;
system_properties = java_properties.getParent();
HierarchicalProperties bld_properties = null;
HierarchicalProperties local_properties = null;
var bld_properties_file = new File(RIFE2_USER_DIR, BLD_PROPERTIES);
if (bld_properties_file.exists() && bld_properties_file.isFile() && bld_properties_file.canRead()) {
try {
var bld = new Properties();
bld.load(new FileReader(bld_properties_file));
bld_properties = new HierarchicalProperties();
bld_properties.putAll(bld);
bld_properties.parent(system_properties);
} catch (IOException e) {
Logger.getLogger("rife.bld").warning("Unable to parse " + bld_properties_file + " as a properties file:\n" + e.getMessage());
}
}
var local_properties_file = new File(workDirectory, LOCAL_PROPERTIES);
if (local_properties_file.exists() && local_properties_file.isFile() && local_properties_file.canRead()) {
try {
var local = new Properties();
local.load(new FileReader(local_properties_file));
local_properties = new HierarchicalProperties();
local_properties.putAll(local);
local_properties.parent(Objects.requireNonNullElse(bld_properties, system_properties));
} catch (IOException e) {
Logger.getLogger("rife.bld").warning("Unable to parse " + local_properties_file + " as a properties file:\n" + e.getMessage());
}
}
java_properties.parent(
Objects.requireNonNullElse(local_properties,
Objects.requireNonNullElse(bld_properties, system_properties)));
final HierarchicalProperties properties = new HierarchicalProperties();
properties.parent(java_properties);
return properties;
}
/**
* Returns the properties uses by this conversation.
*
* @return the instance of {@code HierarchicalProperties} that is used
* by this build executor
* @since 1.5
*/
public HierarchicalProperties properties() {
return properties_;
}
/**
* Retrieve a property from the {@link #properties()}.
*
* @param name the name of the property
* @return the requested property; or {@code null} if it doesn't exist
* @since 1.5.15
*/
public String property(String name) {
return properties().getValueString(name);
}
/**
* Retrieve a property from the {@link #properties()} with a default value.
*
* @param name the name of the property
* @param defaultValue the value that should be used as a fallback
* @return the requested property; or the default value if it doesn't exist
* @since 1.5.15
*/
public String property(String name, String defaultValue) {
return properties().getValueString(name, defaultValue);
}
/**
* Checks for the existence of a property in {@link #properties()}.
*
* @param name the name of the property
* @return {@code true} if the property exists; or {@code false} otherwise
* @since 1.5.15
*/
public boolean hasProperty(String name) {
return properties().contains(name);
}
/**
* Returns the work directory of the project.
* Defaults to this process's user working directory, which when running
* through the bld wrapper corresponds to the top-level project directory.
*
* @since 1.5.12
*/
public File workDirectory() {
return new File(System.getProperty("user.dir"));
}
/**
* Set the exist status to use at the end of the execution.
*
* @param status sets the exit status
* @since 1.5.1
*/
public void exitStatus(int status) {
exitStatus_ = status;
}
/**
* Retrieves the exit status.
*
* @return the exit status
* @since 1.5.1
*/
public int exitStatus() {
return exitStatus_;
}
/**
* Execute the build commands from the provided arguments.
* <p>
* While the build is executing, the arguments can be retrieved
* using {@link #arguments()}.
*
* @param arguments the arguments to execute the build with
* @return the exist status
* @since 1.5.1
*/
public int execute(String[] arguments) {
arguments_ = new ArrayList<>(Arrays.asList(arguments));
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));
show_help |= arguments_.isEmpty();
if (show_help) {
new HelpOperation(this, Collections.emptyList()).execute();
return exitStatus_;
}
while (!arguments_.isEmpty()) {
var command = arguments_.remove(0);
try {
if (!executeCommand(command)) {
break;
}
} catch (Throwable e) {
exitStatus(1);
System.err.println();
if (showStacktrace) {
System.err.println(ExceptionUtils.getExceptionStackTrace(e));
} else {
boolean first = true;
var e2 = e;
while (e2 != null) {
if (e2.getMessage() != null) {
if (!first) {
System.err.print("> ");
}
System.err.println(e2.getMessage());
first = false;
}
e2 = e2.getCause();
}
if (first) {
System.err.println(ExceptionUtils.getExceptionStackTrace(e));
}
}
}
}
return exitStatus_;
}
/**
* Starts the execution of the build. This method will call
* System.exit() when done with the appropriate exit status.
*
* @param arguments the arguments to execute the build with
* @see #execute
* @since 1.5.1
*/
public void start(String[] arguments) {
System.exit(execute(arguments));
}
/**
* Retrieves the list of arguments that are being processed.
*
* @return the list of arguments
* @since 1.5
*/
public List<String> arguments() {
return arguments_;
}
/**
* Retrieves the commands that can be executed by this {@code BuildExecutor}.
*
* @return a map containing the name of the build command and the method that
* corresponds to execution
* @see BuildCommand
* @since 1.5
*/
public Map<String, CommandDefinition> buildCommands() {
if (buildCommands_ == null) {
var build_commands = new TreeMap<String, CommandDefinition>();
Class<?> klass = getClass();
try {
while (klass != null) {
for (var method : klass.getDeclaredMethods()) {
if (method.getParameters().length == 0 && method.isAnnotationPresent(BuildCommand.class)) {
method.setAccessible(true);
var name = method.getName();
var annotation = method.getAnnotation(BuildCommand.class);
var annotation_name = annotation.value();
if (annotation_name != null && !annotation_name.isEmpty()) {
name = annotation_name;
}
if (!build_commands.containsKey(name)) {
var build_help = annotation.help();
CommandHelp command_help = null;
if (build_help != null && build_help != CommandHelp.class) {
command_help = build_help.getDeclaredConstructor().newInstance();
}
var summary = annotation.summary();
var description = annotation.description();
if ((summary != null && !summary.isBlank()) ||
(description != null && !description.isBlank())) {
if (summary == null) summary = "";
if (description == null) description = "";
if (command_help != null) {
if (summary.isBlank()) summary = command_help.getSummary();
if (description.isBlank()) description = command_help.getDescription(name);
}
command_help = new AnnotatedCommandHelp(summary, description);
}
build_commands.put(name, new CommandAnnotated(this, method, command_help));
}
}
}
klass = klass.getSuperclass();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
buildCommands_ = build_commands;
}
return buildCommands_;
}
private static class AnnotatedCommandHelp implements CommandHelp {
private final String summary_;
private final String description_;
AnnotatedCommandHelp(String summary, String description) {
summary_ = summary;
description_ = description;
}
@Override
public String getSummary() {
return summary_;
}
@Override
public String getDescription(String topic) {
return description_;
}
}
/**
* Performs the execution of a single command.
*
* @param command the name of the command to execute
* @return {@code true} when the command was found and executed; or
* {@code false} if the command couldn't be found
* @throws Throwable when an exception occurred during the command execution
* @see BuildCommand
* @since 1.5
*/
public boolean executeCommand(String command)
throws Throwable {
var matched_command = command;
var definition = buildCommands().get(command);
// try to find a match for the provided command amongst
// the ones that are known
if (definition == null) {
// try to find starting matching options
var matches = new ArrayList<>(buildCommands().keySet().stream()
.filter(c -> c.toLowerCase().startsWith(command.toLowerCase()))
.toList());
if (matches.isEmpty()) {
// try to find fuzzy matching options
var fuzzy_regexp = new StringBuilder("^.*");
for (var ch : command.toCharArray()) {
fuzzy_regexp.append("\\Q");
fuzzy_regexp.append(ch);
fuzzy_regexp.append("\\E.*");
}
fuzzy_regexp.append("$");
var fuzzy_pattern = Pattern.compile(fuzzy_regexp.toString());
matches.addAll(buildCommands().keySet().stream()
.filter(c -> fuzzy_pattern.matcher(c.toLowerCase()).matches())
.toList());
}
// only proceed if exactly one match was found
if (matches.size() == 1) {
matched_command = matches.get(0);
System.out.println("Executing matched command: " + matched_command);
definition = buildCommands().get(matched_command);
}
}
// execute the command if we found one
if (definition != null) {
try {
currentCommandName_.set(matched_command);
currentCommandDefinition_.set(definition);
definition.execute();
} catch (ExitStatusException e) {
exitStatus(e.getExitStatus());
return e.getExitStatus() == ExitStatusException.EXIT_SUCCESS;
} finally {
currentCommandDefinition_.set(null);
currentCommandName_.set(null);
}
} else {
new HelpOperation(this, arguments()).executePrintOverviewHelp();
System.err.println();
System.err.println("ERROR: unknown command '" + command + "'");
return false;
}
return true;
}
/**
* Retrieves the name of the currently executing command.
*
* @return the name of the current command; or
* {@code null} if no command is currently executing
* @since 1.5.12
*/
public String getCurrentCommandName() {
return currentCommandName_.get();
}
/**
* Retrieves the definition of the currently executing command.
*
* @return the definition of the current command; or
* {@code null} if no command is currently executing
* @since 1.5.12
*/
public CommandDefinition getCurrentCommandDefinition() {
return currentCommandDefinition_.get();
}
/**
* The standard {@code help} command.
*
* @since 1.5
*/
@BuildCommand(help = HelpHelp.class)
public void help() {
new HelpOperation(this, arguments()).execute();
}
}

View file

@ -0,0 +1,100 @@
/*
* 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.help.*;
import rife.bld.operations.*;
/**
* Implements the RIFE2 CLI build executor that is available when running
* the RIFE2 jar as an executable jar.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class Cli extends BuildExecutor {
private final CreateBaseOperation createBaseOperation_ = new CreateBaseOperation();
private final CreateBlankOperation createBlankOperation_ = new CreateBlankOperation();
private final CreateLibOperation createLibOperation_ = new CreateLibOperation();
private final CreateRife2Operation createRife2Operation_ = new CreateRife2Operation();
private final UpgradeOperation upgradeOperation_ = new UpgradeOperation();
private final VersionOperation versionOperation_ = new VersionOperation();
/**
* The standard {@code create} command.
*
* @throws Exception when an error occurred during the creation process
* @since 1.5
*/
@BuildCommand(help = CreateRife2Help.class)
public void create()
throws Exception {
createRife2Operation_.executeOnce(() -> createRife2Operation_.fromArguments(arguments()));
}
/**
* The standard {@code create-blank} command.
*
* @throws Exception when an error occurred during the creation process
* @since 1.5
*/
@BuildCommand(value = "create-blank", help = CreateBlankHelp.class)
public void createBlank()
throws Exception {
createBlankOperation_.executeOnce(() -> createBlankOperation_.fromArguments(arguments()));
}
/**
* The standard {@code create-base} command.
*
* @throws Exception when an error occurred during the creation process
* @since 1.5.20
*/
@BuildCommand(value = "create-base", help = CreateBaseHelp.class)
public void createBase()
throws Exception {
createBaseOperation_.executeOnce(() -> createBaseOperation_.fromArguments(arguments()));
}
/**
* The standard {@code create-lib} command.
*
* @throws Exception when an error occurred during the creation process
* @since 1.6
*/
@BuildCommand(value = "create-lib", help = CreateLibHelp.class)
public void createLib()
throws Exception {
createLibOperation_.executeOnce(() -> createLibOperation_.fromArguments(arguments()));
}
/**
* The standard {@code upgrade} command.
*
* @throws Exception when an error occurred during the upgrade process
* @since 1.5
*/
@BuildCommand(help = UpgradeHelp.class)
public void upgrade()
throws Exception {
upgradeOperation_.executeOnce();
}
/**
* The standard {@code version} command.
*
* @since 1.5.2
*/
@BuildCommand(help = VersionHelp.class)
public void version()
throws Exception {
versionOperation_.executeOnce();
}
public static void main(String[] arguments)
throws Exception {
new Cli().start(arguments);
}
}

View file

@ -0,0 +1,36 @@
/*
* 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 java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class CommandAnnotated implements CommandDefinition {
private final BuildExecutor executor_;
private final Method method_;
private final CommandHelp help_;
CommandAnnotated(BuildExecutor executor, Method method, CommandHelp help) {
executor_ = executor;
method_ = method;
if (help == null) {
help = new CommandHelp() {};
}
help_ = help;
}
public void execute()
throws Throwable {
try {
method_.invoke(executor_);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
public CommandHelp getHelp() {
return help_;
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld;
/**
* Defines the logic for a build command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public interface CommandDefinition {
/**
* Called when a build command is executed.
*
* @throws Throwable when an error occurred during the execution of the build command
* @since 1.5
*/
void execute() throws Throwable;
/**
* Retrieves the help information of a build command.
* <p>
* Defaults to blank help sections.
*
* @return this build command's help information
* @since 1.5
*/
default CommandHelp getHelp() {
return new CommandHelp() {};
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld;
/**
* Interface that provides help texts to display about {@link BuildExecutor} commands.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public interface CommandHelp {
/**
* Returns a short description about the command.
*
* @return the short summary, defaults to {@code ""}
* @since 1.5
*/
default String getSummary() {
return "";
}
/**
* Returns the full help description of a command.
*
* @return the full help description, defaults to {@code ""}
* @since 1.5
*/
default String getDescription(String topic) {
return "";
}
}

View file

@ -0,0 +1,19 @@
/*
* 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 java.io.File;
/**
* Combines the information of a filesystem file with the name it's intended
* to have.
*
* @param name the intended name of the file
* @param file the location on the filesystem
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public record NamedFile(String name, File file) {
}

View file

@ -0,0 +1,195 @@
/*
* 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.help.*;
import rife.bld.operations.*;
import java.util.*;
import java.util.jar.Attributes;
/**
* Provides the configuration and commands of a Java project for the
* build system with all standard commands ready to go.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class Project extends BaseProject {
/*
* Standard build commands
*/
private final JavadocOperation javadocOperation_ = new JavadocOperation();
private final PrecompileOperation precompileOperation_ = new PrecompileOperation();
private final JarOperation jarOperation_ = new JarOperation();
private final JarOperation jarSourcesOperation_ = new JarOperation();
private final JarOperation jarJavadocOperation_ = new JarOperation();
private final JUnitOperation junitTestOperation_ = new JUnitOperation();
private final UberJarOperation uberJarOperation_ = new UberJarOperation();
@Override
public JUnitOperation testOperation() {
return junitTestOperation_;
}
/**
* Retrieves the project's default javadoc operation.
*
* @return the default javadoc operation instance
* @since 1.5.18
*/
public JavadocOperation javadocOperation() {
return javadocOperation_;
}
/**
* Retrieves the project's default precompile operation.
*
* @return the default precompile operation instance
* @since 1.5.18
*/
public PrecompileOperation precompileOperation() {
return precompileOperation_;
}
/**
* Retrieves the project's default jar operation.
*
* @return the default jar operation instance
* @since 1.5.18
*/
public JarOperation jarOperation() {
return jarOperation_;
}
/**
* Retrieves the project's default jar operation for sources.
*
* @return the default jar operation instance for sources
* @since 1.5.18
*/
public JarOperation jarSourcesOperation() {
return jarSourcesOperation_;
}
/**
* Retrieves the project's default jar operation for javadoc.
*
* @return the default jar operation instance for javadoc
* @since 1.5.18
*/
public JarOperation jarJavadocOperation() {
return jarJavadocOperation_;
}
/**
* Retrieves the project's default uberjar operation.
*
* @return the default uberjar operation instance
* @since 1.5.18
*/
public UberJarOperation uberJarOperation() {
return uberJarOperation_;
}
@BuildCommand(help = JUnitHelp.class)
@Override
public void test()
throws Exception {
super.test();
}
/**
* Standard build command, generates javadoc.
*
* @since 1.5.10
*/
@BuildCommand(help = JavadocHelp.class)
public void javadoc()
throws Exception {
javadocOperation().executeOnce(() -> javadocOperation().fromProject(this));
}
/**
* Standard build command, pre-compiles RIFE2 templates to class files.
*
* @since 1.5
*/
@BuildCommand(help = PrecompileHelp.class)
public void precompile()
throws Exception {
precompileOperation().executeOnce(() -> precompileOperation().fromProject(this));
}
/**
* Standard build command, creates a jar archive for the project.
*
* @since 1.5
*/
@BuildCommand(help = JarHelp.class)
public void jar()
throws Exception {
compile();
precompile();
jarOperation().executeOnce(() -> jarOperation().fromProject(this));
}
/**
* Standard build command, creates a sources jar archive for the project.
*
* @since 1.5.10
*/
@BuildCommand(value = "jar-sources", help = JarSourcesHelp.class)
public void jarSources()
throws Exception {
jarSourcesOperation().executeOnce(() -> jarSourcesOperation()
.manifestAttributes(Map.of(Attributes.Name.MANIFEST_VERSION, "1.0"))
.sourceDirectories(List.of(srcMainJavaDirectory()))
.destinationDirectory(buildDistDirectory())
.destinationFileName(sourcesJarFileName()));
}
/**
* Standard build command, creates a javadoc jar archive for the project.
*
* @since 1.5.10
*/
@BuildCommand(value = "jar-javadoc", help = JarJavadocHelp.class)
public void jarJavadoc()
throws Exception {
compile();
javadoc();
jarJavadocOperation().executeOnce(() -> jarJavadocOperation().manifestAttributes(Map.of(Attributes.Name.MANIFEST_VERSION, "1.0"))
.sourceDirectories(List.of(buildJavadocDirectory()))
.destinationDirectory(buildDistDirectory())
.destinationFileName(javadocJarFileName()));
}
/**
* Standard build command, creates an UberJar archive for the project.
*
* @since 1.5
*/
@BuildCommand(help = UberJarHelp.class)
public void uberjar()
throws Exception {
jar();
uberJarOperation().executeOnce(() -> uberJarOperation().fromProject(this));
}
/**
* Standard publish command, uploads artifacts to the publication repository.
*
* @since 1.5.7
*/
@BuildCommand(help = PublishHelp.class)
public void publish()
throws Exception {
jar();
jarSources();
jarJavadoc();
publishOperation().executeOnce(() -> publishOperation().fromProject(this));
}
}

View file

@ -0,0 +1,134 @@
/*
* 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.help.*;
import rife.bld.operations.*;
import rife.bld.publish.PublishArtifact;
import java.io.File;
import java.util.List;
import java.util.Objects;
/**
* Provides the configuration and commands of a Java web project for the
* build system.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class WebProject extends Project {
/**
* The main war archive creation.
*
* @see #warFileName()
* @since 1.5.0
*/
protected String warFileName = null;
/**
* The main webapp directory.
*
* @see #srcMainWebappDirectory()
* @since 1.5
*/
protected File srcMainWebappDirectory = null;
/*
* Standard build commands
*/
private final WarOperation warOperation_ = new WarOperation();
/**
* Retrieves the project's default war operation.
*
* @return the default war operation instance
* @since 1.5.18
*/
protected WarOperation warOperation() {
return warOperation_;
}
/**
* Standard build command, creates an UberJar archive for the web project.
*
* @since 1.5
*/
@Override
public void uberjar()
throws Exception {
jar();
uberJarOperation().executeOnce(() -> {
uberJarOperation().fromProject(this);
uberJarOperation().sourceDirectories(List.of(new NamedFile("webapp", srcMainWebappDirectory())));
uberJarOperation().jarSourceFiles().addAll(standaloneClasspathJars());
});
}
/**
* Standard build command, creates a war archive for the web project.
*
* @since 1.5
*/
@BuildCommand(help = WarHelp.class)
public void war()
throws Exception {
jar();
warOperation().executeOnce(() -> warOperation().fromProject(this));
}
/**
* Standard publish-web command, uploads artifacts to the publication repository.
*
* @since 1.5.7
*/
@BuildCommand(help = PublishWebHelp.class)
public void publish()
throws Exception {
jar();
jarSources();
jarJavadoc();
uberjar();
war();
publishOperation().executeOnce(() -> {
publishOperation().fromProject(this);
publishOperation().artifacts().add(new PublishArtifact(new File(buildDistDirectory(), uberJarFileName()), "uber", "jar"));
publishOperation().artifacts().add(new PublishArtifact(new File(buildDistDirectory(), warFileName()), "", "war"));
});
}
/*
* Project directories
*/
@Override
public File libStandaloneDirectory() {
return Objects.requireNonNullElseGet(libStandaloneDirectory, () -> new File(libDirectory(), "standalone"));
}
/**
* Returns the project main webapp directory.
* Defaults to {@code "webapp"} relative to {@link #srcMainDirectory()}.
*
* @since 1.5
*/
public File srcMainWebappDirectory() {
return Objects.requireNonNullElseGet(srcMainWebappDirectory, () -> new File(srcMainDirectory(), "webapp"));
}
/*
* Project options
*/
/**
* Returns filename to use for the main war archive creation.
* By default, appends the version and the {@code war} extension to the {@link #archiveBaseName()}.
*
* @since 1.5.0
*/
public String warFileName() {
return Objects.requireNonNullElseGet(warFileName, () -> archiveBaseName() + "-" + version() + ".war");
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.blueprints;
import rife.bld.Project;
import rife.bld.dependencies.VersionNumber;
import rife.tools.StringUtils;
import java.io.File;
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.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.20
*/
public class BaseProjectBlueprint extends Project {
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, VersionNumber versionNumber) {
workDirectory = work;
pkg = packageName;
name = projectName;
mainClass = packageName + "." + StringUtils.capitalize(projectName) + "Main";
version = versionNumber;
downloadSources = true;
repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS);
}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.blueprints;
import rife.bld.Project;
import rife.bld.dependencies.VersionNumber;
import rife.tools.StringUtils;
import java.io.File;
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 blank project.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class BlankProjectBlueprint extends Project {
public BlankProjectBlueprint(File work, String packageName, String projectName) {
this(work, packageName, projectName, new VersionNumber(0,0,1));
}
public BlankProjectBlueprint(File work, String packageName, String projectName, VersionNumber versionNumber) {
workDirectory = work;
pkg = packageName;
name = projectName;
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,9,3)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1,9,3)));
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.blueprints;
import rife.bld.Project;
import rife.bld.dependencies.VersionNumber;
import rife.tools.StringUtils;
import java.io.File;
import java.util.List;
import static rife.bld.dependencies.Repository.MAVEN_CENTRAL;
import static rife.bld.dependencies.Repository.SONATYPE_SNAPSHOTS;
/**
* Provides the dependency information required to create a new lib project.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.6
*/
public class LibProjectBlueprint extends Project {
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, VersionNumber versionNumber) {
workDirectory = work;
pkg = packageName;
name = projectName;
mainClass = packageName + "." + StringUtils.capitalize(projectName) + "Lib";
version = versionNumber;
downloadSources = true;
repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS);
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.blueprints;
import rife.bld.WebProject;
import rife.bld.dependencies.VersionNumber;
import rife.bld.operations.TemplateType;
import rife.tools.StringUtils;
import java.io.File;
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.*;
/**
* Provides the dependency information required to create a new RIFE2 project.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class Rife2ProjectBlueprint extends WebProject {
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, VersionNumber versionNumber) {
workDirectory = work;
pkg = packageName;
name = projectName;
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,6,3)));
scope(test)
.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", "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

@ -0,0 +1,10 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
/**
* Provides blueprints for project creation.
* @since 1.5
*/
package rife.bld.blueprints;

View file

@ -0,0 +1,202 @@
/*
* 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 rife.tools.FileUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.security.MessageDigest;
import java.util.*;
import static rife.tools.HttpUtils.HEADER_AUTHORIZATION;
import static rife.tools.HttpUtils.basicAuthorizationHeader;
import static rife.tools.StringUtils.encodeHexLower;
/**
* Retrieves artifact data.
* <p>
* To instantiate, use either {@link #instance()} for direct retrieval of
* each request, or {@link #cachingInstance()} where previous retrievals
* of remote string content will be cached for faster future retrieval.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.18
*/
public abstract class ArtifactRetriever {
private final static ArtifactRetriever UNCACHED = new ArtifactRetriever() {
String getCached(RepositoryArtifact artifact) {
return null;
}
void cache(RepositoryArtifact artifact, String content) {
}
};
/**
* Gets an artifact retriever that does direct retrieval of each request.
*
* @return the direct retrieval instance
* @since 1.5.18
*/
public static ArtifactRetriever instance() {
return UNCACHED;
}
/**
* Creates a caching artifact retriever where previous retrievals
* of remote string content will be cached for faster future retrieval.
*
* @return a caching instance
* @since 1.5.18
*/
public static ArtifactRetriever cachingInstance() {
return new ArtifactRetriever() {
private final Map<RepositoryArtifact, String> artifactCache = new HashMap<>();
String getCached(RepositoryArtifact artifact) {
return artifactCache.get(artifact);
}
void cache(RepositoryArtifact artifact, String content) {
artifactCache.put(artifact, content);
}
};
}
private ArtifactRetriever() {
}
abstract String getCached(RepositoryArtifact artifact);
abstract void cache(RepositoryArtifact artifact, String content);
/**
* Reads the contents of an artifact as a string.
*
* @param artifact the artifact who's content to retrieve
* @return the string content of the artifact
* @throws FileUtilsErrorException when an error occurred when reading the contents
* @since 1.5.18
*/
public String readString(RepositoryArtifact artifact)
throws FileUtilsErrorException {
if (artifact.repository().isLocal()) {
return FileUtils.readString(new File(artifact.location()));
} else {
var cached = getCached(artifact);
if (cached != null) {
return cached;
}
try {
var connection = new URL(artifact.location()).openConnection();
connection.setUseCaches(false);
if (artifact.repository().username() != null && artifact.repository().password() != null) {
connection.setRequestProperty(
HEADER_AUTHORIZATION,
basicAuthorizationHeader(artifact.repository().username(), artifact.repository().password()));
}
try (var input_stream = connection.getInputStream()) {
var result = FileUtils.readString(input_stream);
cache(artifact, result);
return result;
}
} catch (IOException e) {
throw new FileUtilsErrorException("Error while reading URL '" + artifact.location() + ".", e);
}
}
}
/**
* Transfers artifact into the provided directory.
* <p>
* The destination directory must exist and be writable.
*
* @param artifact the artifact to transfer
* @param directory the directory to transfer the artifact into
* @return {@code true} when the artifact is present in the directory (it could already have been
* there and be validated as correct); or {@code false} when the artifact couldn't be transferred
* @throws IOException when an error occurred during the transfer
* @throws FileUtilsErrorException when an error occurred during the transfer
* @since 1.5.18
*/
public boolean transferIntoDirectory(RepositoryArtifact artifact, File directory)
throws IOException, FileUtilsErrorException {
if (directory == null) throw new IllegalArgumentException("directory can't be null");
if (!directory.exists()) throw new IllegalArgumentException("directory '" + directory + "' doesn't exit");
if (!directory.canWrite()) throw new IllegalArgumentException("directory '" + directory + "' can't be written to");
if (!directory.isDirectory()) throw new IllegalArgumentException("directory '" + directory + "' is not a directory");
var download_filename = artifact.location().substring(artifact.location().lastIndexOf("/") + 1);
var download_file = new File(directory, download_filename);
System.out.print("Downloading: " + artifact.location() + " ... ");
System.out.flush();
try {
if (artifact.repository().isLocal()) {
var source = new File(artifact.location());
if (source.exists()) {
FileUtils.copy(source, download_file);
System.out.print("done");
return true;
} else {
System.out.print("not found");
return false;
}
} else {
try {
if (download_file.exists() && download_file.canRead()) {
if (checkHash(artifact, download_file, ".sha256", "SHA-256") ||
checkHash(artifact, download_file, ".md5", "MD5")) {
System.out.print("exists");
return true;
}
}
var connection = new URL(artifact.location()).openConnection();
connection.setUseCaches(false);
if (artifact.repository().username() != null && artifact.repository().password() != null) {
connection.setRequestProperty(
HEADER_AUTHORIZATION,
basicAuthorizationHeader(artifact.repository().username(), artifact.repository().password()));
}
try (var input_stream = connection.getInputStream()) {
var readableByteChannel = Channels.newChannel(input_stream);
try (var fileOutputStream = new FileOutputStream(download_file)) {
var fileChannel = fileOutputStream.getChannel();
fileChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
System.out.print("done");
return true;
}
}
} catch (FileNotFoundException e) {
System.out.print("not found");
return false;
}
}
} finally {
System.out.println();
}
}
private boolean checkHash(RepositoryArtifact artifact, File downloadFile, String extension, String algorithm) {
try {
var hash_sum = readString(artifact.appendPath(extension));
var digest = MessageDigest.getInstance(algorithm);
digest.update(FileUtils.readBytes(downloadFile));
return hash_sum.equals(encodeHexLower(digest.digest()));
} catch (Exception e) {
// no-op, the hash file couldn't be found or calculated, so it couldn't be checked
}
return false;
}
}

View file

@ -0,0 +1,169 @@
/*
* 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.util.Objects;
import java.util.regex.Pattern;
/**
* 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 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";
public Dependency(String groupId, String artifactId) {
this(groupId, artifactId, null, null, null);
}
public Dependency(String groupId, String artifactId, VersionNumber version) {
this(groupId, artifactId, version, null, null);
}
public Dependency(String groupId, String artifactId, VersionNumber version, String classifier) {
this(groupId, artifactId, version, classifier, null);
}
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, VersionNumber version, String classifier, String type, ExclusionSet exclusions) {
this(groupId, artifactId, version, classifier, type, null, null);
}
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>[^:@]+))?$");
/**
* Parses a dependency from a string representation.
* The format is {@code groupId:artifactId:version:classifier@type}.
* The {@code version}, {@code classifier} and {@code type} are optional.
* <p>
* If the string can't be successfully parsed, {@code null} will be returned.
*
* @param dependency the dependency string to parse
* @return a parsed instance of {@code Dependency}; or
* {@code null} when the string couldn't be parsed
* @since 1.5.2
*/
public static Dependency parse(String dependency) {
if (dependency == null || dependency.isEmpty()) {
return null;
}
var matcher = DEPENDENCY_PATTERN.matcher(dependency);
if (!matcher.matches()) {
return null;
}
var groupId = matcher.group("groupId");
var artifactId = matcher.group("artifactId");
var version = VersionNumber.parse(matcher.group("version"));
var classifier = matcher.group("classifier");
var type = matcher.group("type");
return new Dependency(groupId, artifactId, version, classifier, type);
}
/**
* Returns the base dependency of this dependency, replacing the version number
* with an unknown version number.
*
* @return this dependency's base dependency
* @since 1.5
*/
public Dependency baseDependency() {
return new Dependency(groupId, artifactId, VersionNumber.UNKNOWN, classifier, type);
}
/**
* Adds an exclusion to this dependency.
*
* @param groupId the exclusion group identifier, use {@code "*"} to exclude all groupIds
* @param artifactId the exclusion url identifier, use {@code "*"} to exclude all artifactIds
* @return this dependency instance
* @since 1.5
*/
public Dependency exclude(String groupId, String artifactId) {
exclusions.add(new DependencyExclusion(groupId, artifactId));
return this;
}
/**
* Returns a new dependency with the same data, except for the provided classifier.
*
* @param classifier the classifier to use for the new dependency
* @return the new dependency with the changed classifier
* @since 1.5.6
*/
public Dependency withClassifier(String classifier) {
return new Dependency(groupId, artifactId, version, classifier, type);
}
/**
* Returns a filename that corresponds to the dependency information.
*
* @return a filename for the dependency
* @since 1.5.4
*/
public String toFileName() {
var result = new StringBuilder(artifactId());
result.append("-").append(version());
if (!classifier().isEmpty()) {
result.append("-").append(classifier());
}
result.append(".").append(type());
return result.toString();
}
public String toString() {
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 (!type.isEmpty() && !type.equals("jar")) {
result.append("@").append(type);
}
return result.toString();
}
public boolean equals(Object o) {
if (this == o) return true;
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, type);
}
}

View file

@ -0,0 +1,34 @@
/*
* 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.util.Objects;
/**
* Contains the information to describe a dependency exclusion.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public record DependencyExclusion(String groupId, String artifactId) {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DependencyExclusion that = (DependencyExclusion) o;
return Objects.equals(groupId, that.groupId) && Objects.equals(artifactId, that.artifactId);
}
public int hashCode() {
return Objects.hash(groupId, artifactId);
}
boolean matches(PomDependency dependency) {
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

@ -0,0 +1,427 @@
/*
* 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 rife.bld.dependencies.exceptions.*;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
/**
* Resolves a dependency within a list of Maven-compatible repositories.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class DependencyResolver {
private final ArtifactRetriever retriever_;
private final List<Repository> repositories_;
private final Dependency dependency_;
private MavenMetadata metadata_ = null;
private MavenMetadata snapshotMetadata_ = null;
/**
* Creates a new resolver for a particular dependency.
* <p>
* The repositories will be checked in the order they're listed.
*
* @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 1.5.18
*/
public DependencyResolver(ArtifactRetriever retriever, List<Repository> repositories, Dependency dependency) {
retriever_ = retriever;
if (repositories == null) {
repositories = Collections.emptyList();
}
repositories_ = repositories;
dependency_ = dependency;
}
/**
* Checks whether the dependency exists in any of the provided repositories.
*
* @return {@code true} if the dependency exists; {@code false} otherwise
* @since 1.5
*/
public boolean exists() {
try {
if (getMavenMetadata() == null) {
return false;
}
if (!dependency_.version().equals(VersionNumber.UNKNOWN)) {
return getMavenMetadata().getVersions().contains(dependency_.version());
}
return true;
} catch (ArtifactNotFoundException | ArtifactRetrievalErrorException e) {
return false;
}
}
/**
* Resolves the dependency version in the provided repositories.
* <p>
* When the dependency was defined without a specific version number,
* the latest version number will be returned if the dependency exists.
* If the dependency couldn't be found and no specific version number
* was provided, {@linkplain VersionNumber#UNKNOWN} will be returned.
*
* @return the resolved version
* @since 1.5
*/
public VersionNumber resolveVersion() {
var version = dependency_.version();
if (version.equals(VersionNumber.UNKNOWN)) {
return latestVersion();
}
return version;
}
/**
* Retrieves the direct dependencies of the resolved dependency for the
* provided scopes.
*
* @param scopes the scopes to return the direct dependencies for
* @return the requested direct dependencies; or an empty {@linkplain DependencySet}
* if no direct dependencies could be found or the dependency doesn't exist in
* the provided repositories
* @since 1.5
*/
public DependencySet getDirectDependencies(Scope... scopes) {
var pom_dependencies = getMavenPom(dependency_).getDependencies(scopes);
var result = new DependencySet();
for (var dependency : pom_dependencies) {
result.add(dependency.convertToDependency());
}
return result;
}
/**
* Retrieves all the transitive dependencies of the resolved dependency for the
* provided scopes. This includes the dependency of this resolver also.
* <p>
* This can be a slow and expensive operation since querying continues through
* the complete POM hierarchy until all transitive dependencies have been found.
*
* @param scopes the scopes to return the transitive dependencies for
* @return the requested transitive dependencies; or an empty {@linkplain DependencySet}
* if no transitive dependencies could be found or the dependency doesn't exist in
* the provided repositories
* @since 1.5
*/
public DependencySet getAllDependencies(Scope... scopes) {
var result = new DependencySet();
result.add(dependency_);
var dependency_queue = new ArrayList<PomDependency>();
var parent = dependency_;
var next_dependencies = getMavenPom(parent).getDependencies(scopes);
while (parent != null && next_dependencies != null) {
// remove any next dependencies that are already queued
dependency_queue.forEach(next_dependencies::remove);
// remove any next dependencies that match the current exclusion context
final var exclusion_context = parent;
next_dependencies.removeIf(it -> matchesExclusions(exclusion_context, it));
// add all next dependencies to the queue
dependency_queue.addAll(next_dependencies);
// unless we find a next set of dependencies to add, stop resolving
parent = null;
next_dependencies = null;
// iterate through the dependency queue until we find one that isn't
// part of the results yet
while (!dependency_queue.isEmpty()) {
var candidate = dependency_queue.remove(0);
var dependency = candidate.convertToDependency();
if (!result.contains(dependency)) {
result.add(dependency);
// we found a dependency that was added to the result, get its
// dependencies so that they can be added to the queue after
// filtering
parent = dependency;
next_dependencies = new DependencyResolver(retriever_, repositories_, dependency).getMavenPom(parent).getDependencies(scopes);
break;
}
}
}
return result;
}
private boolean matchesExclusions(Dependency context, PomDependency checked) {
while (context != null) {
if (context.exclusions() != null) {
for (var exclusion : context.exclusions()) {
if (exclusion.matches(checked)) {
return true;
}
}
}
context = context.parent();
}
if (dependency_.exclusions() != null) {
for (var exclusion : dependency_.exclusions()) {
if (exclusion.matches(checked)) {
return true;
}
}
}
return false;
}
/**
* Retrieves all the versions of the resolved dependency.
*
* @return this dependency's version list; or an empty list if the dependency
* couldn't be found in the provided repositories
* @since 1.5
*/
public List<VersionNumber> listVersions() {
return getMavenMetadata().getVersions();
}
/**
* Retrieves the latest version of the resolved dependency.
*
* @return this dependency's latest version; or {@link VersionNumber#UNKNOWN}
* if the dependency couldn't be found in the provided repositories
* @since 1.5
*/
public VersionNumber latestVersion() {
return getMavenMetadata().getLatest();
}
/**
* Retrieves the release version of the resolved dependency.
*
* @return this dependency's release version; or {@link VersionNumber#UNKNOWN}
* if the dependency couldn't be found in the provided repositories
* @since 1.5
*/
public VersionNumber releaseVersion() {
return getMavenMetadata().getRelease();
}
/**
* Transfers the artifacts for the resolved dependency into the provided directory.
* <p>
* The destination directory must exist and be writable.
*
* @param directory the directory to transfer the dependency artifact into
* @return the artifact that was successfully transferred; or {@code null} if no artifact was transferred
* @throws DependencyTransferException when an error occurred during the transfer
* @since 1.5.10
*/
public RepositoryArtifact transferIntoDirectory(File directory)
throws DependencyTransferException {
for (var artifact : getTransferArtifacts()) {
try {
if (retriever_.transferIntoDirectory(artifact, directory)) {
return artifact;
}
} catch (IOException e) {
throw new DependencyTransferException(dependency_, artifact.location(), directory, e);
}
}
return null;
}
/**
* Retrieve the repositories that are used by this dependency resolver.
*
* @return the dependency resolver's repositories
* @since 1.5
*/
public List<Repository> repositories() {
return repositories_;
}
/**
* Retrieve the dependency that is resolved.
*
* @return the resolved dependency
* @since 1.5
*/
public Dependency dependency() {
return dependency_;
}
/**
* Retrieves all the potential locations for the dependency
* within the provided repositories.
*
* @return a list of potential transfer locations
* @since 1.5.10
*/
public List<String> getTransferLocations() {
return getTransferArtifacts().stream().map(RepositoryArtifact::location).toList();
}
/**
* Returns the main Maven metadata for this dependency
*
* @return this dependency's metadata
* @since 1.5.8
*/
public MavenMetadata getMavenMetadata() {
if (metadata_ == null) {
var locations = getMetadataLocations();
metadata_ = parseMavenMetadata(locations);
}
return metadata_;
}
/**
* THe Maven metadata with snapshot information when this is a snapshot version.
*
* @return Maven metadata if this is a snapshot dependency version; or
* {@code null} if this version is not a snapshot
* @since 1.5.8
*/
public MavenMetadata getSnapshotMavenMetadata() {
if (snapshotMetadata_ == null) {
final var version = resolveVersion();
if (version.isSnapshot()) {
var locations = getSnapshotMetadataLocations();
snapshotMetadata_ = parseMavenMetadata(locations);
}
}
return snapshotMetadata_;
}
private List<RepositoryArtifact> getTransferArtifacts() {
final var version = resolveVersion();
final VersionNumber pom_version;
if (version.isSnapshot()) {
var metadata = getSnapshotMavenMetadata();
pom_version = metadata.getSnapshot();
} else {
pom_version = version;
}
return getArtifactLocations().stream().map(a -> {
var result = new StringBuilder();
result.append(version).append("/").append(dependency_.artifactId()).append("-").append(pom_version);
if (!dependency_.classifier().isEmpty()) {
result.append("-").append(dependency_.classifier());
}
var type = dependency_.type();
if (type == null) {
type = "jar";
}
result.append(".").append(type);
return a.appendPath(result.toString());
}).toList();
}
private List<RepositoryArtifact> getArtifactLocations() {
return repositories_.stream().map(repository -> new RepositoryArtifact(repository, repository.getArtifactLocation(dependency_))).toList();
}
private List<RepositoryArtifact> getMetadataLocations() {
return getArtifactLocations().stream().map(a -> a.appendPath(a.repository().getMetadataName())).toList();
}
private List<RepositoryArtifact> getSnapshotMetadataLocations() {
var version = resolveVersion();
return getArtifactLocations().stream().map(a -> a.appendPath(version + "/" + a.repository().getMetadataName())).toList();
}
private MavenMetadata parseMavenMetadata(List<RepositoryArtifact> artifacts) {
RepositoryArtifact retrieved_artifact = null;
String metadata = null;
for (var artifact : artifacts) {
try {
var content = retriever_.readString(artifact);
if (content == null) {
throw new ArtifactNotFoundException(dependency_, artifact.location());
}
retrieved_artifact = artifact;
metadata = content;
break;
} catch (FileUtilsErrorException e) {
if (e.getCause() instanceof FileNotFoundException) {
continue;
}
throw new ArtifactRetrievalErrorException(dependency_, artifact.location(), e);
}
}
if (metadata == null) {
throw new ArtifactNotFoundException(dependency_, artifacts.stream().map(RepositoryArtifact::location).collect(Collectors.joining(", ")));
}
var xml = new Xml2MavenMetadata();
if (!xml.processXml(metadata)) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors());
}
return xml;
}
private List<RepositoryArtifact> getPomLocations() {
final var version = resolveVersion();
final VersionNumber pom_version;
if (version.isSnapshot()) {
var metadata = getSnapshotMavenMetadata();
pom_version = metadata.getSnapshot();
} else {
pom_version = version;
}
return getArtifactLocations().stream().map(a -> a.appendPath(version + "/" + dependency_.artifactId() + "-" + pom_version + ".pom")).toList();
}
Xml2MavenPom getMavenPom(Dependency parent) {
RepositoryArtifact retrieved_artifact = null;
String pom = null;
var artifacts = getPomLocations();
for (var artifact : artifacts) {
try {
var content = retriever_.readString(artifact);
if (content == null) {
throw new ArtifactNotFoundException(dependency_, artifact.location());
}
retrieved_artifact = artifact;
pom = content;
break;
} catch (FileUtilsErrorException e) {
if (e.getCause() instanceof FileNotFoundException) {
continue;
}
throw new ArtifactRetrievalErrorException(dependency_, artifact.location(), e);
}
}
if (pom == null) {
throw new ArtifactNotFoundException(dependency_, artifacts.stream().map(RepositoryArtifact::location).collect(Collectors.joining(", ")));
}
var xml = new Xml2MavenPom(parent, retriever_, repositories_);
if (!xml.processXml(pom)) {
throw new DependencyXmlParsingErrorException(dependency_, retrieved_artifact.location(), xml.getErrors());
}
return xml;
}
}

View file

@ -0,0 +1,141 @@
/*
* 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.util.LinkedHashMap;
import java.util.List;
/**
* Convenience class to map a {@link Scope} to its dependencies.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class DependencyScopes extends LinkedHashMap<Scope, DependencySet> {
/**
* Creates an empty dependency scope map.
*
* @since 1.5
*/
public DependencyScopes() {
}
/**
* Creates a dependency scope map from another one.
*
* @param other the other map to create this one from
* @since 1.5
*/
public DependencyScopes(DependencyScopes other) {
for (var entry : other.entrySet()) {
put(entry.getKey(), new DependencySet(entry.getValue()));
}
}
/**
* Includes all the dependencies from another dependency scope map.
*
* @param other the other map to include dependencies from
* @since 1.5
*/
public void include(DependencyScopes other) {
for (var entry : other.entrySet()) {
var dependencies = get(entry.getKey());
if (dependencies == null) {
dependencies = new DependencySet();
put(entry.getKey(), dependencies);
}
dependencies.addAll(entry.getValue());
}
}
/**
* Retrieves the {@link DependencySet} for a particular scope.
*
* @param scope the scope to retrieve the dependencies for
* @return the scope's {@code DependencySet};
* or an empty {@code DependencySet} if none have been defined for the provided scope.
* @since 1.5
*/
public DependencySet scope(Scope scope) {
return computeIfAbsent(scope, k -> new DependencySet());
}
/**
* Returns the transitive set of dependencies that would be used for the compile scope in a project.
*
* @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 1.6
*/
public DependencySet resolveCompileDependencies(ArtifactRetriever retriever, List<Repository> repositories) {
return resolveScopedDependencies(retriever, repositories,
new Scope[]{Scope.provided, Scope.compile},
new Scope[]{Scope.compile},
null);
}
/**
* Returns the transitive set of dependencies that would be used for the runtime scope in a project.
*
* @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 1.6
*/
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},
resolveCompileDependencies(retriever, repositories));
}
/**
* Returns the transitive set of dependencies that would be used for the standalone scope in a project.
*
* @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 1.6
*/
public DependencySet resolveStandaloneDependencies(ArtifactRetriever retriever, List<Repository> repositories) {
return resolveScopedDependencies(retriever, repositories,
new Scope[]{Scope.standalone},
new Scope[]{Scope.compile, Scope.runtime},
null);
}
/**
* Returns the transitive set of dependencies that would be used for the test scope in a project.
*
* @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 1.6
*/
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(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(retriever, repositories, dependency).getAllDependencies(transitiveScopes));
}
}
}
if (excluded != null) {
dependencies.removeAll(excluded);
}
return dependencies;
}
}

View file

@ -0,0 +1,266 @@
/*
* 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 rife.bld.dependencies.exceptions.DependencyTransferException;
import java.io.File;
import java.util.*;
/**
* Convenience class to handle a set of {@link Dependency} objects.
* <p>
* Only a single version of each dependency can exist in this set.
* When adding a new dependency, it will only be added if it didn't exist
* in the set yet, or if the new dependency has a higher version than
* the existing one.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class DependencySet extends AbstractSet<Dependency> implements Set<Dependency> {
private final Map<Dependency, Dependency> dependencies_ = new LinkedHashMap<>();
private final Set<LocalDependency> localDependencies_ = new LinkedHashSet<>();
/**
* Creates an empty dependency set.
*
* @since 1.5
*/
public DependencySet() {
}
/**
* Creates a dependency set from another one.
*
* @param other the other set to create this one from
* @since 1.5
*/
public DependencySet(DependencySet other) {
addAll(other);
}
/**
* Includes a dependency into the dependency set.
*
* @param dependency the dependency to include
* @return this dependency set instance
* @since 1.5
*/
public DependencySet include(Dependency dependency) {
add(dependency);
return this;
}
/**
* Includes a local dependency into the dependency set.
* <p>
* Local dependencies aren't resolved and point to a location on
* the file system.
*
* @param dependency the dependency to include
* @return this dependency set instance
* @since 1.5.2
*/
public DependencySet include(LocalDependency dependency) {
localDependencies_.add(dependency);
return this;
}
/**
* Retrieves the local dependencies.
*
* @return the set of local dependencies
* @since 1.5.2
*/
public Set<LocalDependency> localDependencies() {
return localDependencies_;
}
/**
* Transfers the artifacts for the dependencies into the provided directory.
* <p>
* The destination directory must exist and be writable.
*
* @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
* @return the list of artifacts that were transferred successfully
* @throws DependencyTransferException when an error occurred during the transfer
* @since 1.5.10
*/
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 directory,
* including other classifiers.
* <p>
* The destination directory must exist and be writable.
*
* @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 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 1.5.10
*/
public List<RepositoryArtifact> transferIntoDirectory(ArtifactRetriever retriever, List<Repository> repositories, File directory, String... classifiers) {
var result = new ArrayList<RepositoryArtifact>();
for (var dependency : this) {
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) {
var classifier_artifact = new DependencyResolver(retriever, repositories, dependency.withClassifier(classifier)).transferIntoDirectory(directory);
if (classifier_artifact != null) {
result.add(classifier_artifact);
}
}
}
}
}
return result;
}
/**
* Returns the dependency that was stored in the set.
* <p>
* The version can be different from the dependency passed in and this
* method can be used to look up the actual version of the dependency in the set.
*
* @param dependency the dependency to look for
* @return the dependency in the set; or
* {@code null} if no such dependency exists
* @since 1.5
*/
public Dependency get(Dependency dependency) {
return dependencies_.get(dependency);
}
/**
* Generates the string description of the transitive hierarchical tree of
* dependencies for a particular scope.
*
* @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 1.5.21
*/
public String generateTransitiveDependencyTree(ArtifactRetriever retriever, List<Repository> repositories, Scope... scopes) {
var compile_dependencies = new DependencySet();
for (var dependency : this) {
compile_dependencies.addAll(new DependencyResolver(retriever, repositories, dependency).getAllDependencies(scopes));
}
return compile_dependencies.generateDependencyTree();
}
/**
* Generates the string description of the hierarchical tree of
* dependencies in this {@code DependencySet}. This relies on the {@code Dependency}
* {@code parent} field to be set correctly to indicate their relationships.
*
* @return the generated tree description string; or an empty string if
* there were no dependencies to describe
* @since 1.5.21
*/
public String generateDependencyTree() {
var result = new StringBuilder();
var dependency_list = new ArrayList<>(this);
var dependency_stack = new Stack<DependencyTreeEntry>();
var roots = dependency_list.stream().filter(dependency -> dependency.parent() == null).toList();
dependency_list.removeIf(dependency -> dependency.parent() == null);
var roots_it = roots.iterator();
while (roots_it.hasNext()) {
var root = roots_it.next();
dependency_list.add(0, root);
stack:
do {
var list_it = dependency_list.iterator();
while (list_it.hasNext()) {
var list_dep = list_it.next();
if (list_dep.parent() == null) {
list_it.remove();
var entry = new DependencyTreeEntry(null, list_dep, !roots_it.hasNext());
result.append(entry).append(System.lineSeparator());
dependency_stack.add(entry);
} else {
var stack_entry = dependency_stack.peek();
if (list_dep.parent().equals(stack_entry.dependency())) {
list_it.remove();
boolean last = dependency_list.stream().noneMatch(d -> d.parent().equals(stack_entry.dependency()));
var entry = new DependencyTreeEntry(stack_entry, list_dep, last);
result.append(entry).append(System.lineSeparator());
dependency_stack.add(entry);
continue stack;
}
}
}
dependency_stack.pop();
} while (!dependency_stack.isEmpty());
}
return result.toString();
}
private record DependencyTreeEntry(DependencyTreeEntry parent, Dependency dependency, boolean last) {
public String toString() {
var result = new StringBuilder();
if (last) {
result.insert(0, "└─ ");
} else {
result.insert(0, "├─ ");
}
var p = parent();
while (p != null) {
if (p.last()) {
result.insert(0, " ");
} else {
result.insert(0, "");
}
p = p.parent();
}
return result.toString() + dependency;
}
}
public boolean add(Dependency dependency) {
var existing = dependencies_.get(dependency);
if (existing == null) {
dependencies_.put(dependency, dependency);
return true;
}
if (dependency.version().compareTo(existing.version()) > 0) {
dependencies_.remove(dependency);
dependencies_.put(dependency, dependency);
return true;
}
return false;
}
public Iterator<Dependency> iterator() {
return dependencies_.keySet().iterator();
}
public int size() {
return dependencies_.size();
}
}

View file

@ -0,0 +1,16 @@
/*
* 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.util.LinkedHashSet;
/**
* Convenience class to handle a set of {@link DependencyExclusion} objects.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class ExclusionSet extends LinkedHashSet<DependencyExclusion> {
}

View file

@ -0,0 +1,17 @@
/*
* 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;
/**
* Contains the information required to describe a local dependency for the build system.
* <p>
* If the local dependency points to a directory, it will be scanned for jar files.
*
* @param path the file system path of the local dependency
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.2
*/
public record LocalDependency(String path) {
}

View file

@ -0,0 +1,63 @@
/*
* 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.util.List;
/**
* Provides Maven metadata information
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.8
*/
public interface MavenMetadata {
/**
* Returns latest version number in the metadata.
*
* @return the latest version number
* @since 1.5.8
*/
VersionNumber getLatest();
/**
* Returns release version number in the metadata.
*
* @return the release version number
* @since 1.5.8
*/
VersionNumber getRelease();
/**
* Returns snapshot version number in the metadata.
*
* @return the snapshot version number
* @since 1.5.8
*/
VersionNumber getSnapshot();
/**
* Returns snapshot timestamp in the metadata.
*
* @return the snapshot timestamp
* @since 1.5.8
*/
String getSnapshotTimestamp();
/**
* Returns snapshot build number in the metadata.
*
* @return the snapshot build number
* @since 1.5.8
*/
Integer getSnapshotBuildNumber();
/**
* Returns all the release or snapshot versions in the metadata.
*
* @return the version number list
* @since 1.5.8
*/
List<VersionNumber> getVersions();
}

View file

@ -0,0 +1,47 @@
/*
* 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.util.*;
/**
* Contains the information required to describe a dependency with all
* the details stored in a Maven POM descriptor.
* <p>
* This is used by the {@linkplain DependencyResolver} while traversing
* the dependency graph, eventually resulting into fully resolved
* {@linkplain Dependency} instances.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public record PomDependency(String groupId, String artifactId, String version, String classifier, String type,
String scope, String optional, ExclusionSet exclusions, Dependency parent) {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PomDependency that = (PomDependency) o;
return Objects.equals(groupId, that.groupId) && Objects.equals(artifactId, that.artifactId) && Objects.equals(classifier, that.classifier) && Objects.equals(type, that.type);
}
boolean isPomImport() {
return "pom".equals(type()) && "import".equals(scope());
}
Dependency convertToDependency() {
return new Dependency(
groupId(),
artifactId(),
VersionNumber.parse(version()),
classifier(),
type(),
exclusions(),
parent());
}
public int hashCode() {
return Objects.hash(groupId, artifactId, classifier, type);
}
}

View file

@ -0,0 +1,197 @@
/*
* 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 rife.ioc.HierarchicalProperties;
import rife.tools.StringEncryptor;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
/**
* Contains the information required to locate a Maven-compatible repository.
*
* @param location the base location of the repository
* @param username the username to access the repository
* @param password the password to access the repository
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public record Repository(String location, String username, String password) {
public static Repository MAVEN_LOCAL = null;
public static final Repository MAVEN_CENTRAL = new Repository("https://repo1.maven.org/maven2/");
public static final Repository SONATYPE_RELEASES = new Repository("https://s01.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 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/");
private static final String MAVEN_LOCAL_REPO_PROPERTY = "maven.repo.local";
public static final String PROPERTY_BLD_REPO_PREFIX = "bld.repo.";
public static final String PROPERTY_BLD_REPO_USERNAME_SUFFIX = ".username";
public static final String PROPERTY_BLD_REPO_PASSWORD_SUFFIX = ".password";
/**
* This method will be called as soon as hierarchical properties
* are initialized in the build executor. It is not intended to be called
* manually.
*
* @param properties the hierarchical properties to use for resolving
* the maven local repository
* @since 1.5.12
*/
public static void resolveMavenLocal(HierarchicalProperties properties) {
var user_home = properties.getValueString("user.home");
if (user_home == null) {
user_home = System.getProperty("user.home");
}
var maven_local = properties.getValueString(
MAVEN_LOCAL_REPO_PROPERTY,
Path.of(user_home, ".m2", "repository").toString());
MAVEN_LOCAL = new Repository(maven_local);
}
/**
* Resolves the repository in the provided hierarchical properties.
* <p>
* For instance, using the name {@code myrepo} will look for the following properties:<br>
* {@code bld.repo.myrepo}<br>
* {@code bld.repo.myrepo.username} (optional)<br>
* {@code bld.repo.myrepo.password} (optional)
* <p>
* If the {@code bld.repo.myrepo} property isn't found, the {@code locationOrName}
* parameter will be used as a location instead.
*
* @param properties the hierarchical properties to look into
* @param locationOrName the text to resolve a repository name or to be used as a location
* @return the repository instance
* @since 1.5.12
*/
public static Repository resolveRepository(HierarchicalProperties properties, String locationOrName) {
if (properties != null && properties.contains(PROPERTY_BLD_REPO_PREFIX + locationOrName)) {
var location = properties.getValueString(PROPERTY_BLD_REPO_PREFIX + locationOrName);
var username = properties.getValueString(PROPERTY_BLD_REPO_PREFIX + locationOrName + PROPERTY_BLD_REPO_USERNAME_SUFFIX);
var password = properties.getValueString(PROPERTY_BLD_REPO_PREFIX + locationOrName + PROPERTY_BLD_REPO_PASSWORD_SUFFIX);
return new Repository(location, username, password);
}
return switch (locationOrName) {
case "MAVEN_LOCAL" -> Repository.MAVEN_LOCAL;
case "MAVEN_CENTRAL" -> Repository.MAVEN_CENTRAL;
case "SONATYPE_RELEASES" -> Repository.SONATYPE_RELEASES;
case "SONATYPE_SNAPSHOTS" -> Repository.SONATYPE_SNAPSHOTS;
case "SONATYPE_SNAPSHOTS_LEGACY" -> Repository.SONATYPE_SNAPSHOTS_LEGACY;
case "APACHE" -> Repository.APACHE;
case "RIFE2_RELEASES" -> Repository.RIFE2_RELEASES;
case "RIFE2_SNAPSHOTS" -> Repository.RIFE2_SNAPSHOTS;
default -> new Repository(locationOrName);
};
}
/**
* Creates a new repository with only a location.
*
* @param location the location to create the repository for
* @since 1.5
*/
public Repository(String location) {
this(location, null, null);
}
/**
* Indicates whether this repository is local.
*
* @return {@code true} when this repository is local; or
* {@code false} otherwise
* @since 1.5.10
*/
public boolean isLocal() {
return location().startsWith("/") || location().startsWith("file:");
}
/**
* Creates a new repository instance of the same location, but with
* different credentials.
*
* @param username the username to access the repository
* @param password the password to access the repository
* @return the new repository
* @since 1.5.10
*/
public Repository withCredentials(String username, String password) {
return new Repository(location(), username, password);
}
/**
* Constructs the location for a dependency if it would be located in this repository.
*
* @param dependency the dependency to create the location for
* @return the constructed location
* @since 1.5.10
*/
public String getArtifactLocation(Dependency dependency) {
return getArtifactLocation(dependency.groupId(), dependency.artifactId());
}
/**
* Constructs the location for a dependency if it would be located in this repository.
*
* @param groupId the groupId dependency to create the location for
* @param artifactId the artifactId dependency to create the location for
* @return the constructed location
* @since 1.5.10
*/
public String getArtifactLocation(String groupId, String artifactId) {
var group_path = groupId.replace(".", "/");
var result = new StringBuilder();
if (isLocal()) {
if (location().startsWith("file://")) {
result.append(location().substring("file://".length()));
} else {
result.append(location());
}
} else {
result.append(location());
}
if (!location().endsWith("/")) {
result.append("/");
}
return result.append(group_path).append("/").append(artifactId).append("/").toString();
}
/**
* Returns the appropriate metadata name.
*
* @return the metadata name for this repository.
* @since 1.5.10
*/
public String getMetadataName() {
if (isLocal()) {
return "maven-metadata-local.xml";
} else {
return "maven-metadata.xml";
}
}
public String toString() {
var result = new StringBuilder(location);
if (username() != null) {
result.append(":");
try {
result.append(StringEncryptor.MD5HLO.performEncryption(username(), null));
if (password() != null) {
result.append(":");
result.append(StringEncryptor.MD5HLO.performEncryption(password(), null));
}
} catch (NoSuchAlgorithmException e) {
// should never happen
throw new RuntimeException(e);
}
}
return result.toString();
}
}

View file

@ -0,0 +1,23 @@
/*
* 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;
/**
* Represents an artifact location in a repository.
*
* @param repository the repository of the artifact
* @param location the location of the artifact in the repository
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.6
*/
public record RepositoryArtifact(Repository repository, String location) {
public RepositoryArtifact appendPath(String path) {
return new RepositoryArtifact(repository, location + path);
}
public String toString() {
return repository + ":" + location;
}
}

View file

@ -0,0 +1,44 @@
/*
* 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;
/**
* Provides all the dependency scopes that are supported by
* the RIFE2 build system.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public enum Scope {
/**
* Used for compiling the main source code.
* @since 1.5
*/
compile,
/**
* Used when running the main source code.
* @since 1.5
*/
runtime,
/**
* Used when compiling and running the test source code.
* @since 1.5
*/
test,
/**
* Used when running the main source code without container.
* @since 1.5
*/
standalone,
/**
* Provided by a container when running the main source code.
* @since 1.5
*/
provided
}

View file

@ -0,0 +1,249 @@
/*
* 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.util.Objects;
import java.util.regex.Pattern;
/**
* Contains the information required to describe a dependency version number.
* <p>
* This operates according to the versioning scheme specified by Maven.
* <p>
* When the version number is undefined, {@link VersionNumber#UNKNOWN} should be used.
*
* @param major the major version component
* @param minor the minor version component
* @param revision the revision of the version
* @param qualifier a string qualifier for the version
* @param separator the separator used to separate the qualifier from the version number
* @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 Comparable<VersionNumber> {
public static final String SNAPSHOT_QUALIFIER = "SNAPSHOT";
/**
* Singleton to use when the version is not specified.
*
* @since 1.5
*/
public static final VersionNumber UNKNOWN = new VersionNumber(0, 0, 0, "");
private static final Pattern VERSION_PATTERN = Pattern.compile("^(?<major>\\d+)(?:\\.(?<minor>\\d+)(?:\\.(?<revision>\\d+))?)?(?:(?<separator>[.\\-])(?<qualifier>.*[^.\\-]))??$");
/**
* Parses a version number from a string representation.
* <p>
* 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
* {@link VersionNumber#UNKNOWN} when the string couldn't be parsed
* @since 1.5
*/
public static VersionNumber parse(String version) {
if (version == null || version.isEmpty()) {
return UNKNOWN;
}
var matcher = VERSION_PATTERN.matcher(version);
if (!matcher.matches()) {
return UNKNOWN;
}
var major = matcher.group("major");
var minor = matcher.group("minor");
var revision = matcher.group("revision");
var major_integer = (major != null ? Integer.parseInt(major) : null);
var minor_integer = (minor != null ? Integer.parseInt(minor) : null);
var revision_integer = (revision != null ? Integer.parseInt(revision) : null);
var qualifier = matcher.group("qualifier");
var separator = matcher.group("separator");
return new VersionNumber(major_integer, minor_integer, revision_integer, qualifier, separator);
}
/**
* Constructs a version number with only a major component.
*
* @param major the major version component
* @since 1.5
*/
public VersionNumber(Integer major) {
this(major, null, null, "");
}
/**
* Constructs a version number with a major and minor component.
*
* @param major the major version component
* @param minor the minor version component
* @since 1.5
*/
public VersionNumber(Integer major, Integer minor) {
this(major, minor, null, "");
}
/**
* Constructs a version number with major, minor and revision components.
*
* @param major the major version component
* @param minor the minor version component
* @param revision the version revision component
* @since 1.5
*/
public VersionNumber(Integer major, Integer minor, Integer revision) {
this(major, minor, revision, "");
}
/**
* Constructs a complete version number with qualifier, the separator will default to "{@code -}".
*
* @param major the major version component
* @param minor the minor version component
* @param revision the version revision component
* @param qualifier the version qualifier
* @since 1.5
*/
public VersionNumber(Integer major, Integer minor, Integer revision, String qualifier) {
this(major, minor, revision, qualifier, "-");
}
/**
* Constructs a complete version number with qualifier.
*
* @param major the major version component
* @param minor the minor version component
* @param revision the version revision component
* @param qualifier the version qualifier
* @param separator the separator for the version qualifier
* @since 1.5
*/
public VersionNumber(Integer major, Integer minor, Integer revision, String qualifier, String separator) {
this.major = major;
this.minor = minor;
this.revision = revision;
this.qualifier = (qualifier == null ? "" : qualifier);
this.separator = separator;
}
/**
* Retrieves the base version number without the qualifier.
*
* @return the base version number instance
* @since 1.5
*/
public VersionNumber getBaseVersion() {
return new VersionNumber(major, minor, revision, null);
}
/**
* 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);
}
/**
* Returns a primitive integer for the major version component.
*
* @return the major version component as an {@code int}
* @since 1.5
*/
public int majorInt() {
return major == null ? 0 : major;
}
/**
* Returns a primitive integer for the minor version component.
*
* @return the minor version component as an {@code int}
* @since 1.5
*/
public int minorInt() {
return minor == null ? 0 : minor;
}
/**
* Returns a primitive integer for the version revision component.
*
* @return the version revision component as an {@code int}
* @since 1.5
*/
public int revisionInt() {
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);
}
public int compareTo(VersionNumber other) {
if (majorInt() != other.majorInt()) {
return majorInt() - other.majorInt();
}
if (minorInt() != other.minorInt()) {
return minorInt() - other.minorInt();
}
if (revisionInt() != other.revisionInt()) {
return revisionInt() - other.revisionInt();
}
if (qualifier.equals(other.qualifier)) {
return 0;
} else if (qualifier.isEmpty()) {
return 1;
} else if (other.qualifier.isEmpty()) {
return -1;
}
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(minorInt());
}
if (revision != null) {
version.append(".");
version.append(revisionInt());
}
if (qualifier != null && !qualifier.isEmpty()) {
version.append(separator);
version.append(qualifier);
}
return version.toString();
}
@Override
public boolean equals(Object other) {
return other instanceof VersionNumber && compareTo((VersionNumber) other) == 0;
}
@Override
public int hashCode() {
int result = majorInt();
result = 31 * result + minorInt();
result = 31 * result + revisionInt();
result = 31 * result + Objects.hashCode(qualifier.toLowerCase());
return result;
}
}

View file

@ -0,0 +1,120 @@
/*
* 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 org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import rife.xml.Xml2Data;
import java.util.*;
import java.util.regex.Pattern;
/**
* Parses an XML document to generate {@link MavenMetadata}, this is an internal class.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.8
*/
public class Xml2MavenMetadata extends Xml2Data implements MavenMetadata {
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 String snapshotTimestamp_ = null;
private Integer snapshotBuildNumber_ = null;
public Xml2MavenMetadata() {
versions_ = new ArrayList<>();
}
public VersionNumber getLatest() {
return latest_;
}
public VersionNumber getRelease() {
return release_;
}
public VersionNumber getSnapshot() {
return snapshot_;
}
public String getSnapshotTimestamp() {
return snapshotTimestamp_;
}
public Integer getSnapshotBuildNumber() {
return snapshotBuildNumber_;
}
public List<VersionNumber> getVersions() {
return versions_;
}
public void startElement(String uri, String localName, String qName, Attributes attributes) {
characterData_ = new StringBuilder();
}
public void endElement(String uri, String localName, String qName) {
switch (qName) {
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" -> {
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;
}
private static final Pattern MILESTONE = Pattern.compile("^m\\d*$");
private static final Pattern BETA = Pattern.compile("^b\\d*$");
private static final Pattern ALPHA = Pattern.compile("^a\\d*$");
public void endDocument()
throws SAXException {
// determine latest stable version by removing pre-release qualifiers
var filtered_versions = new TreeSet<VersionNumber>();
filtered_versions.addAll(versions_.stream()
.filter(v -> {
if (v.qualifier() == null) return true;
var q = v.qualifier().toLowerCase();
return !q.startsWith("rc") &&
!q.startsWith("cr") &&
!q.contains("milestone") &&
!MILESTONE.matcher(q).matches() &&
!q.contains("beta") &&
!BETA.matcher(q).matches() &&
!q.contains("alpha") &&
!ALPHA.matcher(q).matches();
}).toList());
// only replace the stable version from the metadata when
// something remained from the filtering, then use the
// last version in the sorted set
if (!filtered_versions.isEmpty()) {
latest_ = filtered_versions.last();
}
}
public void characters(char[] ch, int start, int length) {
if (characterData_ != null) {
characterData_.append(String.copyValueOf(ch, start, length));
}
}
}

View file

@ -0,0 +1,375 @@
/*
* 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 org.xml.sax.Attributes;
import rife.xml.Xml2Data;
import java.util.*;
import java.util.regex.Pattern;
/**
* Parses an XML document to retrieve POM information, this is an internal class.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.18
*/
class Xml2MavenPom extends Xml2Data {
private final Dependency parent_;
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> properties_ = new HashMap<>();
private final Stack<String> elementStack_ = new Stack<>();
private ExclusionSet exclusions_ = null;
private boolean collectProperties_ = false;
private boolean collectDependencyManagement_ = false;
private boolean collectDependencies_ = false;
private boolean collectExclusions_ = false;
private StringBuilder characterData_ = null;
private String lastGroupId_ = null;
private String lastArtifactId_ = null;
private String lastVersion_ = null;
private String lastType_ = null;
private String lastClassifier_ = null;
private String lastScope_ = null;
private String lastOptional_ = null;
private String lastExclusionGroupId_ = null;
private String lastExclusionArtifactId_ = null;
Xml2MavenPom(Dependency parent, ArtifactRetriever retriever, List<Repository> repositories) {
parent_ = parent;
retriever_ = retriever;
repositories_ = repositories;
}
Set<PomDependency> getDependencies(Scope... scopes) {
if (scopes == null || scopes.length == 0) {
return Collections.emptySet();
}
var scopes_list = Arrays.asList(scopes);
if (resolvedDependencies_ == null) {
var resolved_dependencies = new HashMap<Scope, Set<PomDependency>>();
if (!dependencies_.isEmpty()) {
for (var dependency : dependencies_) {
var managed_dependency = dependencyManagement_.get(dependency);
var version = dependency.version();
var dep_scope = dependency.scope();
var optional = dependency.optional();
var exclusions = dependency.exclusions();
if (managed_dependency != null) {
if (version == null) {
version = managed_dependency.version();
}
if (dep_scope == null) {
dep_scope = managed_dependency.scope();
}
if (optional == null) {
optional = managed_dependency.optional();
}
if (exclusions == null) {
exclusions = managed_dependency.exclusions();
}
}
if (dep_scope == null) {
dep_scope = "compile";
}
optional = resolveProperties(optional);
if ("true".equals(optional)) {
continue;
}
var resolved_dependency = new PomDependency(
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 || 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<>());
resolved_dependency_set.add(resolved_dependency);
}
}
}
}
resolvedDependencies_ = resolved_dependencies;
}
var result = new LinkedHashSet<PomDependency>();
for (var scope : scopes) {
var deps = resolvedDependencies_.get(scope);
if (deps != null) {
result.addAll(deps);
}
}
return result;
}
PomDependency resolveDependency(PomDependency dependency) {
return new PomDependency(
resolveProperties(dependency.groupId()),
resolveProperties(dependency.artifactId()),
resolveProperties(dependency.version()),
resolveProperties(dependency.classifier()),
resolveProperties(dependency.type()),
dependency.scope(),
resolveProperties(dependency.optional()),
dependency.exclusions(),
dependency.parent());
}
public void startElement(String uri, String localName, String qName, Attributes attributes) {
characterData_ = new StringBuilder();
switch (qName) {
case "parent" -> resetState();
case "properties" -> {
if (isChildOfProject()) {
collectProperties_ = true;
}
}
case "dependencyManagement" -> {
if (isChildOfProject()) {
collectDependencyManagement_ = true;
}
}
case "dependencies" -> {
if (isChildOfProject()) {
resetState();
collectDependencies_ = true;
}
}
case "exclusions" -> {
if (collectDependencyManagement_ || collectDependencies_) {
collectExclusions_ = true;
exclusions_ = new ExclusionSet();
}
}
case "dependency" -> {
if (collectDependencies_) resetState();
}
}
elementStack_.push(qName);
}
public void endElement(String uri, String localName, String qName) {
elementStack_.pop();
switch (qName) {
case "parent" -> {
if (isChildOfProject()) {
var parent_dependency = new Dependency(resolveProperties(lastGroupId_), resolveProperties(lastArtifactId_), VersionNumber.parse(resolveProperties(lastVersion_)));
var parent = new DependencyResolver(retriever_, repositories_, parent_dependency).getMavenPom(parent_);
parent.properties_.keySet().removeAll(properties_.keySet());
properties_.putAll(parent.properties_);
parent.dependencyManagement_.keySet().removeAll(dependencyManagement_.keySet());
dependencyManagement_.putAll(parent.dependencyManagement_);
parent.dependencies_.removeAll(dependencies_);
dependencies_.addAll(parent.dependencies_);
resetState();
}
}
case "properties" -> collectProperties_ = false;
case "dependencyManagement" -> collectDependencyManagement_ = false;
case "dependencies" -> collectDependencies_ = false;
case "exclusions" -> collectExclusions_ = false;
case "exclusion" -> {
if (collectExclusions_) {
exclusions_.add(new DependencyExclusion(lastExclusionGroupId_, lastExclusionArtifactId_));
}
}
case "dependency" -> {
var dependency = new PomDependency(lastGroupId_, lastArtifactId_, lastVersion_, lastClassifier_, lastType_, lastScope_, lastOptional_, exclusions_, parent_);
if (collectDependencyManagement_) {
if (dependency.isPomImport()) {
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()) {
resolved_dependencies.add(imported_pom.resolveDependency(managed_dependency));
}
resolved_dependencies.removeAll(dependencyManagement_.keySet());
for (var resolved_dependency : resolved_dependencies) {
dependencyManagement_.put(resolved_dependency, resolved_dependency);
}
} else {
dependencyManagement_.put(dependency, dependency);
}
} else if (collectDependencies_) {
dependencies_.add(dependency);
}
resetState();
}
case "groupId" -> {
if (isChildOfProject()) {
addProjectProperty(qName);
} else if (isChildOfParent() || isChildOfDependency()) {
lastGroupId_ = getCharacterData();
} else if (collectExclusions_ && isChildOfExclusion()) {
lastExclusionGroupId_ = getCharacterData();
}
}
case "artifactId" -> {
if (isChildOfProject()) {
addProjectProperty(qName);
} else if (isChildOfParent() || isChildOfDependency()) {
lastArtifactId_ = getCharacterData();
} else if (collectExclusions_ && isChildOfExclusion()) {
lastExclusionArtifactId_ = getCharacterData();
}
}
case "version" -> {
if (isChildOfProject()) {
addProjectProperty(qName);
} else if (isChildOfParent() || isChildOfDependency()) {
lastVersion_ = getCharacterData();
}
}
case "type" -> {
if (isChildOfDependency()) {
lastType_ = getCharacterData();
}
}
case "classifier" -> {
if (isChildOfDependency()) {
lastClassifier_ = getCharacterData();
}
}
case "scope" -> {
if (isChildOfDependency()) {
lastScope_ = getCharacterData();
}
}
case "optional" -> {
if (isChildOfDependency()) {
lastOptional_ = getCharacterData();
}
}
case "packaging", "name", "description", "url", "inceptionYear" -> {
if (isChildOfProject()) {
addProjectProperty(qName);
}
}
default -> {
if (collectProperties_) {
properties_.put(qName, getCharacterData());
}
}
}
characterData_ = null;
}
private boolean isChildOfProject() {
return elementStack_.peek().equals("project");
}
private boolean isChildOfParent() {
return elementStack_.peek().equals("parent");
}
private boolean isChildOfDependency() {
return elementStack_.peek().equals("dependency");
}
private boolean isChildOfExclusion() {
return elementStack_.peek().equals("exclusion");
}
private void addProjectProperty(String name) {
properties_.put("project." + name, getCharacterData());
}
private String getCharacterData() {
if (characterData_ == null) {
return null;
}
var result = characterData_.toString().trim();
if (result.isEmpty()) {
return null;
}
return result;
}
private static final Pattern MAVEN_PROPERTY = Pattern.compile("\\$\\{([^<>{}]+)}");
private String resolveProperties(String data) {
if (data == null) {
return null;
}
boolean replaced;
do {
replaced = false;
var processed_data = new StringBuilder();
var matcher = MAVEN_PROPERTY.matcher(data);
var last_end = 0;
while (matcher.find()) {
if (matcher.groupCount() == 1) {
var property = matcher.group(1);
if (properties_.containsKey(property)) {
processed_data.append(data, last_end, matcher.start());
processed_data.append(properties_.get(property));
last_end = matcher.end();
replaced = true;
}
}
}
if (last_end < data.length()) {
processed_data.append(data.substring(last_end));
}
data = processed_data.toString();
} while (replaced);
return data;
}
private void resetState() {
lastGroupId_ = null;
lastArtifactId_ = null;
lastVersion_ = null;
lastType_ = null;
lastClassifier_ = null;
lastScope_ = null;
lastOptional_ = null;
lastExclusionArtifactId_ = null;
lastExclusionGroupId_ = null;
exclusions_ = null;
}
public void characters(char[] ch, int start, int length) {
if (characterData_ != null) {
characterData_.append(String.copyValueOf(ch, start, length));
}
}
}

View file

@ -0,0 +1,31 @@
/*
* 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.exceptions;
import rife.bld.dependencies.Dependency;
import java.io.Serial;
public class ArtifactNotFoundException extends DependencyException {
@Serial private static final long serialVersionUID = 3137804373567469249L;
private final Dependency dependency_;
private final String location_;
public ArtifactNotFoundException(Dependency dependency, String location) {
super("Couldn't find artifact for dependency '" + dependency + "' at " + location);
dependency_ = dependency;
location_ = location;
}
public Dependency getDependency() {
return dependency_;
}
public String getLocation() {
return location_;
}
}

View file

@ -0,0 +1,31 @@
/*
* 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.exceptions;
import rife.bld.dependencies.Dependency;
import java.io.Serial;
public class ArtifactRetrievalErrorException extends DependencyException {
@Serial private static final long serialVersionUID = 5570184718213503548L;
private final Dependency dependency_;
private final String location_;
public ArtifactRetrievalErrorException(Dependency dependency, String location, Throwable e) {
super("Unexpected error while retrieving artifact for dependency '" + dependency + "' from '" + location + "'", e);
dependency_ = dependency;
location_ = location;
}
public Dependency getDependency() {
return dependency_;
}
public String getLocation() {
return location_;
}
}

View file

@ -0,0 +1,23 @@
/*
* 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.exceptions;
import java.io.Serial;
public class DependencyException extends RuntimeException {
@Serial private static final long serialVersionUID = 7683888067001718316L;
public DependencyException(String message) {
super(message);
}
public DependencyException(String message, Throwable cause) {
super(message, cause);
}
public DependencyException(Throwable cause) {
super(cause);
}
}

View file

@ -0,0 +1,38 @@
/*
* 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.exceptions;
import rife.bld.dependencies.Dependency;
import java.io.File;
import java.io.Serial;
public class DependencyTransferException extends DependencyException {
@Serial private static final long serialVersionUID = 2128741620203670830L;
private final Dependency dependency_;
private final String location_;
private final File destination_;
public DependencyTransferException(Dependency dependency, String location, File destination, Throwable e) {
super("Unable to transfer dependency '" + dependency + "' from '" + location + "' into '" + destination + "'", e);
dependency_ = dependency;
location_ = location;
destination_ = destination;
}
public Dependency getDependency() {
return dependency_;
}
public String getLocation() {
return location_;
}
public File getDestination() {
return destination_;
}
}

View file

@ -0,0 +1,39 @@
/*
* 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.exceptions;
import rife.bld.dependencies.Dependency;
import rife.tools.StringUtils;
import java.io.Serial;
import java.util.Set;
public class DependencyXmlParsingErrorException extends DependencyException {
@Serial private static final long serialVersionUID = -1050469071912675264L;
private final Dependency dependency_;
private final String location_;
private final Set<String> errors_;
public DependencyXmlParsingErrorException(Dependency dependency, String location, Set<String> errors) {
super("Unable to parse artifact document for dependency '" + dependency + "' from '" + location + "' :\n" + StringUtils.join(errors, "\n"));
dependency_ = dependency;
location_ = location;
errors_ = errors;
}
public Dependency getDependency() {
return dependency_;
}
public String getLocation() {
return location_;
}
public Set<String> getErrors() {
return errors_;
}
}

View file

@ -0,0 +1,10 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
/**
* Provides exception classes build system dependency handling.
* @since 1.5
*/
package rife.bld.dependencies.exceptions;

View file

@ -0,0 +1,10 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
/**
* Provides functionalities to resolve and retrieve dependency artifacts.
* @since 1.5
*/
package rife.bld.dependencies;

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the clean command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class CleanHelp implements CommandHelp {
public String getSummary() {
return "Cleans the build files";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Cleans the build files.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the compile command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class CompileHelp implements CommandHelp {
public String getSummary() {
return "Compiles the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Compiles the project.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* 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 baseline Java project with minimal commands";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Creates a new baseline Java project with minimal commands.
Usage : ${topic} <package> <name>
package The package of the project to create
name The name of the project to create""", "${topic}", topic);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the create-blank command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class CreateBlankHelp implements CommandHelp {
public String getSummary() {
return "Creates a new blank Java project with standard commands";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Creates a new blank Java project with standard commands.
Usage : ${topic} <package> <name>
package The package of the project to create
name The name of the project to create""", "${topic}", topic);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the create-lib command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.6
*/
public class CreateLibHelp implements CommandHelp {
public String getSummary() {
return "Creates a new Java library with minimal commands";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Creates a new library Java project with minimal commands.
Usage : ${topic} <package> <name>
package The package of the project to create
name The name of the project to create""", "${topic}", topic);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the create command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class CreateRife2Help implements CommandHelp {
public String getSummary() {
return "Creates a new RIFE2 project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Creates a new RIFE2 project.
Usage : ${topic} <package> <name>
package The package of the project to create
name The name of the project to create""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the dependency tree command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.21
*/
public class DependencyTreeHelp implements CommandHelp {
public String getSummary() {
return "Outputs the dependency tree of the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Outputs the dependency tree of the project
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the download command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class DownloadHelp implements CommandHelp {
public String getSummary() {
return "Downloads all dependencies of the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Downloads all dependencies of the project
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,19 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
/**
* Provides help for the help command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class HelpHelp implements CommandHelp {
public String getSummary() {
return "Provides help about any of the other commands";
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the JUnit test command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.20
*/
public class JUnitHelp implements CommandHelp {
public String getSummary() {
return "Tests the project with JUnit (takes options)";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Tests the project with JUnit.
Additional JUnit console launcher options can be
provided after the command.
These commandline options are provided by this command:
--junit-help see the full list of JUnit launcher options
--junit-clear clear the JUnit launcher options the build uses
(needs to be provided before other options)
Usage : ${topic} [OPTIONS]""", "${topic}", topic);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the jar command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class JarHelp implements CommandHelp {
public String getSummary() {
return "Creates a jar archive for the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Creates a jar archive for the project.
The standard jar command will automatically also execute
the compile and precompile commands beforehand.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the jar-javadoc command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.10
*/
public class JarJavadocHelp implements CommandHelp {
public String getSummary() {
return "Creates a javadoc jar archive for the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Creates a javadoc jar archive for the project.
The standard jar-javadoc command will automatically also execute
the compile and javadoc commands beforehand.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the jar-sources command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.10
*/
public class JarSourcesHelp implements CommandHelp {
public String getSummary() {
return "Creates a sources jar archive for the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Creates a sources jar archive for the project.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the javadoc command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.10
*/
public class JavadocHelp implements CommandHelp {
public String getSummary() {
return "Generates javadoc for the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Generates javadoc for the project.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the precompile command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class PrecompileHelp implements CommandHelp {
public String getSummary() {
return "Pre-compiles RIFE2 templates to class files";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Pre-compiles RIFE2 templates to class files
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the publish command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.7
*/
public class PublishHelp implements CommandHelp {
public String getSummary() {
return "Publishes the artifacts of your project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Publishes the artifacts of the project to the publication
repository.
The standard publish command will automatically also execute
the jar, jar-sources and jar-javadoc commands beforehand.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the publish web command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.7
*/
public class PublishWebHelp implements CommandHelp {
public String getSummary() {
return "Publishes the artifacts of your web project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Publishes the artifacts of the web project to the publication
repository.
The standard web publish command will automatically also execute
the jar, jar-sources, jar-javadoc, uberjar and war commands
beforehand.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the purge command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class PurgeHelp implements CommandHelp {
public String getSummary() {
return "Purges all unused artifacts from the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Purges all the unused dependency artifacts from the project
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the run command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class RunHelp implements CommandHelp {
public String getSummary() {
return "Runs the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Runs the project.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the test command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class TestHelp implements CommandHelp {
public String getSummary() {
return "Tests the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Tests the project.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the uberjar command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class UberJarHelp implements CommandHelp {
public String getSummary() {
return "Creates an UberJar archive for the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Creates an UberJar archive for the project.
The standard uberjar command will automatically also execute
the jar command beforehand.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the updates command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class UpdatesHelp implements CommandHelp {
public String getSummary() {
return "Checks for updates of the project dependencies";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Checks which updates are available for the project dependencies.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the upgrade command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class UpgradeHelp implements CommandHelp {
public String getSummary() {
return "Upgrades the bld wrapper to the latest version";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Upgrades the bld wrapper to the latest version.
This command should be executed in the root directory of
your project.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the version command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.2
*/
public class VersionHelp implements CommandHelp {
public String getSummary() {
return "Outputs the version of the build system";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Outputs the version of the build system.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld.help;
import rife.bld.CommandHelp;
import rife.tools.StringUtils;
/**
* Provides help for the war command.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class WarHelp implements CommandHelp {
public String getSummary() {
return "Creates a war archive for the project";
}
public String getDescription(String topic) {
return StringUtils.replace("""
Creates a war archive for the project.
The standard war command will automatically also execute
the jar command beforehand.
Usage : ${topic}""", "${topic}", topic);
}
}

View file

@ -0,0 +1,10 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
/**
* Provides help texts for build commands.
* @since 1.5
*/
package rife.bld.help;

View file

@ -0,0 +1,526 @@
/*
* 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.BldVersion;
import rife.bld.Project;
import rife.bld.operations.exceptions.OperationOptionException;
import rife.bld.wrapper.Wrapper;
import rife.template.TemplateFactory;
import rife.tools.FileUtils;
import rife.tools.StringUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import rife.validation.ValidityChecks;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* Provides the baseline foundation for creating a project structure.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public abstract class AbstractCreateOperation<T extends AbstractCreateOperation<T, P>, P extends Project> extends AbstractOperation<AbstractCreateOperation<T, P>> {
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_;
String projectTestName_;
File bldPackageDirectory_;
File mainPackageDirectory_;
File testPackageDirectory_;
File ideaDirectory_;
File ideaLibrariesDirectory_;
File ideaRunConfigurationsDirectory_;
File vscodeDirectory_;
protected AbstractCreateOperation(String templateBase) {
templateBase_ = templateBase;
}
/**
* Performs the creation operation.
*
* @throws FileUtilsErrorException when an error occurred during the creation operation
* @throws IOException when an error occurred during the creation operation
* @since 1.5
*/
public void execute()
throws FileUtilsErrorException, IOException {
if (packageName() == null || projectName() == null) {
System.err.println("ERROR: Missing package or project name.");
return;
}
executeConfigure();
executeCreateProjectStructure();
executePopulateProjectStructure();
executePopulateIdeaProject();
executePopulateVscodeProject();
if (downloadDependencies()) {
executeDownloadDependencies();
}
if (!silent()) {
System.out.println("The project was successfully created at '" + project_.workDirectory() + "'.");
}
}
/**
* Create a blueprint of the project.
*
* @return a blueprint for project creation
* @since 1.5
*/
protected abstract P createProjectBlueprint();
/**
* Part of the {@link #execute} operation, configures the project.
*
* @since 1.5
*/
protected void executeConfigure() {
project_ = createProjectBlueprint();
// standard names
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");
ideaLibrariesDirectory_ = new File(ideaDirectory_, "libraries");
ideaRunConfigurationsDirectory_ = new File(ideaDirectory_, "runConfigurations");
vscodeDirectory_ = new File(project_.workDirectory(), ".vscode");
var package_dir = project_.pkg().replace('.', File.separatorChar);
bldPackageDirectory_ = new File(project_.srcBldJavaDirectory(), package_dir);
mainPackageDirectory_ = new File(project_.srcMainJavaDirectory(), package_dir);
testPackageDirectory_ = new File(project_.srcTestJavaDirectory(), package_dir);
}
/**
* Generates the build class name from the project class name
* @param projectClassName the project class name
* @return the generated build class name
* @since 1.6
*/
protected String projectBuildClassName(String projectClassName) {
return projectClassName + "Build";
}
/**
* Generates the main class name from the project class name
* @param projectClassName the project class name
* @return the generated main class name
* @since 1.6
*/
protected String projectMainClassName(String projectClassName) {
return projectClassName + "Main";
}
/**
* Generates the main uber class name from the project class name
* @param projectClassName the project class name
* @return the generated main uber class name
* @since 1.6
*/
protected String projectMainUberClassName(String projectClassName) {
return projectClassName + "Main";
}
/**
* Generates the test class name from the project class name
* @param projectClassName the project class name
* @return the generated test class name
* @since 1.6
*/
protected String projectTestClassName(String projectClassName) {
return projectClassName + "Test";
}
/**
* Part of the {@link #execute} operation, creates the project structure.
*
* @since 1.5
*/
protected void executeCreateProjectStructure() {
project_.createProjectStructure();
bldPackageDirectory_.mkdirs();
mainPackageDirectory_.mkdirs();
testPackageDirectory_.mkdirs();
ideaDirectory_.mkdirs();
ideaLibrariesDirectory_.mkdirs();
ideaRunConfigurationsDirectory_.mkdirs();
vscodeDirectory_.mkdirs();
}
/**
* Part of the {@link #execute} operation, populates the project structure.
*
* @since 1.5
*/
protected void executePopulateProjectStructure()
throws FileUtilsErrorException, IOException {
// project gitignore
FileUtils.writeString(
TemplateFactory.TXT.get(templateBase_ + "project_gitignore").getContent(),
new File(project_.workDirectory(), ".gitignore"));
// project main
var site_template = TemplateFactory.TXT.get(templateBase_ + "project_main");
site_template.setValue("package", project_.pkg());
site_template.setValue("projectMain", projectMainName_);
var project_main_file = new File(mainPackageDirectory_, projectMainName_ + ".java");
FileUtils.writeString(site_template.getContent(), project_main_file);
// project test
var test_template = TemplateFactory.TXT.get(templateBase_ + "project_test");
test_template.setValue("package", project_.pkg());
test_template.setValue("projectTest", projectTestName_);
test_template.setValue("projectMain", projectMainName_);
if (test_template.hasValueId("project")) {
test_template.setValue("project", projectClassName_);
}
var project_test_file = new File(testPackageDirectory_, projectTestName_ + ".java");
FileUtils.writeString(test_template.getContent(), project_test_file);
// project build
var build_template = TemplateFactory.TXT.get(templateBase_ + "project_build");
build_template.setValue("projectBuild", projectBuildName_);
build_template.setValue("package", project_.pkg());
build_template.setValue("project", projectClassName_);
if (build_template.hasValueId("projectMain")) {
build_template.setValue("projectMain", projectMainName_);
}
if (build_template.hasValueId("projectTest")) {
build_template.setValue("projectTest", projectTestName_);
}
if (build_template.hasValueId("projectMainUber")) {
build_template.setValue("projectMainUber", projectMainUberName_);
}
for (var entry : project_.dependencies().entrySet()) {
build_template.blankValue("dependencies");
for (var dependency : entry.getValue()) {
build_template.setValue("groupId", dependency.groupId());
build_template.setValue("artifactId", dependency.artifactId());
var version = dependency.version();
var version_string = version.major() + "," + version.minor() + "," + version.revision();
if (!version.qualifier().isEmpty()) {
version_string += ",\"" + version.qualifier() + "\"";
}
build_template.setValue("version", version_string);
build_template.appendBlock("dependencies", "dependency");
}
build_template.setValue("name", entry.getKey().name());
build_template.appendBlock("scopes", "scope");
}
var project_build_file = new File(bldPackageDirectory_, projectBuildName_ + ".java");
FileUtils.writeString(build_template.getContent(), project_build_file);
// build shell scripts
var build_sh_template = TemplateFactory.TXT.get("bld.bld");
build_sh_template.setValue("projectBuild", projectBuildName_);
build_sh_template.setValue("package", project_.pkg());
var build_sh_file = new File(project_.workDirectory(), "bld");
FileUtils.writeString(build_sh_template.getContent(), build_sh_file);
build_sh_file.setExecutable(true);
var build_bat_template = TemplateFactory.TXT.get("bld.bld_bat");
build_bat_template.setValue("projectBuild", projectBuildName_);
build_bat_template.setValue("package", project_.pkg());
var build_bat_file = new File(project_.workDirectory(), "bld.bat");
FileUtils.writeString(build_bat_template.getContent(), build_bat_file);
// create the wrapper files
new Wrapper().createWrapperFiles(project_.libBldDirectory(), BldVersion.getVersion());
}
/**
* Part of the {@link #execute} operation, populates the IDEA project structure.
*
* @since 1.5
*/
protected void executePopulateIdeaProject()
throws FileUtilsErrorException {
// IDEA project files
FileUtils.writeString(
TemplateFactory.XML.get(templateBase_ + "idea.app_iml").getContent(),
new File(ideaDirectory_, "app.iml"));
FileUtils.writeString(
TemplateFactory.XML.get(templateBase_ + "idea.bld_iml").getContent(),
new File(ideaDirectory_, "bld.iml"));
FileUtils.writeString(
TemplateFactory.XML.get(templateBase_ + "idea.misc").getContent(),
new File(ideaDirectory_, "misc.xml"));
FileUtils.writeString(
TemplateFactory.XML.get(templateBase_ + "idea.modules").getContent(),
new File(ideaDirectory_, "modules.xml"));
var bld_xml_template = TemplateFactory.XML.get(templateBase_ + "idea.libraries.bld");
bld_xml_template.setValue("version", BldVersion.getVersion());
var bld_xml_file = new File(ideaLibrariesDirectory_, "bld.xml");
FileUtils.writeString(bld_xml_template.getContent(), bld_xml_file);
FileUtils.writeString(
TemplateFactory.XML.get(templateBase_ + "idea.libraries.compile").getContent(),
new File(ideaLibrariesDirectory_, "compile.xml"));
FileUtils.writeString(
TemplateFactory.XML.get(templateBase_ + "idea.libraries.runtime").getContent(),
new File(ideaLibrariesDirectory_, "runtime.xml"));
FileUtils.writeString(
TemplateFactory.XML.get(templateBase_ + "idea.libraries.test").getContent(),
new File(ideaLibrariesDirectory_, "test.xml"));
// IDEA run site
if (createIdeaRunMain()) {
var run_site_template = TemplateFactory.XML.get(templateBase_ + "idea.runConfigurations.Run_Main");
run_site_template.setValue("package", project_.pkg());
run_site_template.setValue("projectMain", projectMainName_);
var run_site_file = new File(ideaRunConfigurationsDirectory_, "Run Main.xml");
FileUtils.writeString(run_site_template.getContent(), run_site_file);
}
// IDEA run tests
var run_tests_template = TemplateFactory.XML.get(templateBase_ + "idea.runConfigurations.Run_Tests");
run_tests_template.setValue("package", project_.pkg());
if (run_tests_template.hasValueId("projectTest")) {
run_tests_template.setValue("projectTest", projectTestName_);
}
var run_tests_file = new File(ideaRunConfigurationsDirectory_, "Run Tests.xml");
FileUtils.writeString(run_tests_template.getContent(), run_tests_file);
}
/**
* Indicates whether the IDEA main run target should be generated
* @return {@code true} of it should be generated; or {@code false} otherwise
* @since 1.6
*/
protected boolean createIdeaRunMain() {
return true;
}
/**
* Part of the {@link #execute} operation, populates the vscode project structure.
*
* @since 1.5.6
*/
protected void executePopulateVscodeProject()
throws FileUtilsErrorException {
var launch_template = TemplateFactory.JSON.get(templateBase_ + "vscode.launch");
launch_template.setValue("package", project_.pkg());
if (launch_template.hasValueId("projectMain")) {
launch_template.setValue("projectMain", projectMainName_);
}
if (launch_template.hasValueId("projectTest")) {
launch_template.setValue("projectTest", projectTestName_);
}
var launch_file = new File(vscodeDirectory_, "launch.json");
FileUtils.writeString(launch_template.getContent(), launch_file);
var settings_template = TemplateFactory.JSON.get(templateBase_ + "vscode.settings");
if (settings_template.hasValueId("version")) {
settings_template.setValue("version", BldVersion.getVersion());
}
var settings_file = new File(vscodeDirectory_, "settings.json");
FileUtils.writeString(settings_template.getContent(), settings_file);
}
/**
* Part of the {@link #execute} operation, downloads the dependencies, when enabled.
*
* @since 1.5
*/
protected void executeDownloadDependencies() {
new DownloadOperation().fromProject(project_).execute();
}
/**
* Configures a creation operation from command-line arguments.
*
* @param arguments the arguments that will be considered
* @return this operation instance
* @since 1.5
*/
public T fromArguments(List<String> arguments) {
String package_name = null;
String project_name = null;
if (arguments.size() > 0) {
package_name = arguments.remove(0);
}
if (arguments.size() > 0) {
project_name = arguments.remove(0);
}
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.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 workDirectory(new File(System.getProperty("user.dir")))
.packageName(package_name)
.projectName(project_name)
.downloadDependencies(true);
}
/**
* Provides the work directory in which the project will be created.
* <p>
* If no work directory is provided, the JVM working directory will be used.
*
* @param directory the directory to use as a work directory
* @return this operation instance
* @since 1.5
*/
public T workDirectory(File directory) {
if (!directory.exists()) {
throw new OperationOptionException("ERROR: The work directory '" + directory + "' doesn't exist.");
}
if (!directory.isDirectory()) {
throw new OperationOptionException("ERROR: '" + directory + "' is not a directory.");
}
if (!directory.canWrite()) {
throw new OperationOptionException("ERROR: The work directory '" + directory + "' is not writable.");
}
workDirectory_ = directory;
return (T) this;
}
/**
* Provides the package of the project that will be created.
*
* @param name the package name
* @return this operation instance
* @since 1.5
*/
public T packageName(String name) {
packageName_ = StringUtils.trim(name);
if (packageName_.isEmpty()) {
throw new OperationOptionException("ERROR: The package name should not be blank.");
}
if (!ValidityChecks.checkJavaPackage(packageName_)) {
throw new OperationOptionException("ERROR: The package name is invalid.");
}
packageName_ = name;
return (T) this;
}
/**
* Provides the name of the project that will be created.
*
* @param name the project name
* @return this operation instance
* @since 1.5
*/
public T projectName(String name) {
projectName_ = StringUtils.trim(name);
if (projectName_.isEmpty()) {
throw new OperationOptionException("ERROR: The project name should not be blank.");
}
if (!ValidityChecks.checkJavaIdentifier(projectName_)) {
throw new OperationOptionException("ERROR: The project name is invalid.");
}
projectName_ = name;
return (T) this;
}
/**
* Indicates whether the dependencies for the project should be downloaded
* upon creation, by default this is {@code false}.
*
* @param flag {@code true} if the dependencies should be downloaded; or
* {@code false} otherwise
* @return this operation instance
* @since 1.5
*/
public T downloadDependencies(boolean flag) {
downloadDependencies_ = flag;
return (T) this;
}
/**
* Retrieves the work directory that is used for the project creation.
*
* @return the work directory
* @since 1.5
*/
public File workDirectory() {
return workDirectory_;
}
/**
* Retrieves the package that is used for the project creation.
*
* @return the package name
* @since 1.5
*/
public String packageName() {
return packageName_;
}
/**
* Retrieves the name that is used for the project creation.
*
* @return the project name
* @since 1.5
*/
public String projectName() {
return projectName_;
}
/**
* Retrieves whether dependencies will be downloaded at project creation.
*
* @return {@code true} if dependencies will be downloaded; or
* {@code false} otherwise
* @since 1.5
*/
public boolean downloadDependencies() {
return downloadDependencies_;
}
/**
* Retrieves the project instance that was used as a blueprint for the
* project creation.
*
* @return the project creation blueprint instance
* @since 1.5
*/
public P project() {
return project_;
}
}

View file

@ -0,0 +1,86 @@
/*
* 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;
/**
* Provides common features across all operations
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.2
*/
public abstract class AbstractOperation<T extends AbstractOperation<T>> {
private boolean silent_ = false;
private boolean executed_ = false;
/**
* Changes whether the operation should be silent or not.
* <p>
* Defaults to not silent.
*
* @param silent {@code true} if the operation should be silent;
* {@code false} otherwise
* @return this operation instance
* @since 1.5.2
*/
public T silent(boolean silent) {
silent_ = silent;
return (T) this;
}
/**
* Indicates whether the operation should be silent or not.
*
* @return {@code true} if the operation should be silent;
* {@code false} otherwise
* @since 1.5.2
*/
public boolean silent() {
return silent_;
}
/**
* Ensures that this operation instance is executed once and only once.
*
* @throws Exception when an exception was thrown by the {@link #execute()} call
* @see #executeOnce(Runnable)
* @since 1.5.17
*/
public void executeOnce()
throws Exception {
executeOnce(null);
}
/**
* Ensures that this operation instance is executed once and only once.
* <p>
* A setup lambda can be provided that is called when the only execution takes place.
*
* @param setup the setup lambda that will be called with the only execution
* @throws Exception when an exception was thrown by the {@link #execute()} call
* @see #executeOnce()
* @since 1.5.17
*/
public void executeOnce(Runnable setup)
throws Exception {
if (executed_) {
return;
}
executed_ = true;
if (setup != null) {
setup.run();
}
execute();
}
/**
* Performs the operation execution that can be wrapped by the {@code #executeOnce} call.
*
* @throws Exception when an exception occurs during the execution
* @since 1.5.10
*/
public abstract void execute()
throws Exception;
}

View file

@ -0,0 +1,337 @@
/*
* 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.BaseProject;
import rife.bld.operations.exceptions.ExitStatusException;
import rife.bld.operations.exceptions.OperationOptionException;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
/**
* Abstract operation that starts a Java application as a separate process.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.18
*/
public abstract class AbstractProcessOperation<T extends AbstractProcessOperation<T>> extends AbstractOperation<T> {
public static final String DEFAULT_JAVA_TOOL = "java";
protected File workDirectory_ = new File(System.getProperty("user.dir"));
protected String javaTool_ = DEFAULT_JAVA_TOOL;
protected final JavaOptions javaOptions_ = new JavaOptions();
protected final List<String> classpath_ = new ArrayList<>();
protected String mainClass_;
protected Function<String, Boolean> outputProcessor_;
protected Function<String, Boolean> errorProcessor_;
protected Process process_;
protected boolean successful_;
protected Thread outputProcessorThread_;
protected Thread errorProcessorThread_;
/**
* Performs the operation.
*
* @throws InterruptedException when the operation was interrupted
* @throws IOException when an exception occurred during the execution of the process
* @throws FileUtilsErrorException when an exception occurred during the retrieval of the operation output
* @throws ExitStatusException when the exit status was changed during the operation
* @since 1.5
*/
public void execute()
throws IOException, FileUtilsErrorException, InterruptedException, ExitStatusException {
successful_ = true;
outputProcessorThread_ = null;
errorProcessorThread_ = null;
process_ = executeStartProcess();
int status = process_.waitFor();
if (outputProcessorThread_ != null) {
outputProcessorThread_.join();
}
if (errorProcessorThread_ != null) {
errorProcessorThread_.join();
}
if (!successful_) {
status = ExitStatusException.EXIT_FAILURE;
}
ExitStatusException.throwOnFailure(status);
}
/**
* Part of the {@link #execute} operation, constructs the command list
* to use for building the process.
*
* @since 1.5
*/
abstract protected List<String> executeConstructProcessCommandList();
/**
* Part of the {@link #execute} operation, starts the process.
*
* @since 1.5
*/
protected Process executeStartProcess()
throws IOException {
var builder = new ProcessBuilder(executeConstructProcessCommandList());
builder.directory(workDirectory());
final var output_processor = outputProcessor();
if (output_processor == null) {
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
} else {
builder.redirectOutput(ProcessBuilder.Redirect.PIPE);
}
final var error_processor = errorProcessor();
if (error_processor == null) {
builder.redirectError(ProcessBuilder.Redirect.INHERIT);
} else {
builder.redirectError(ProcessBuilder.Redirect.PIPE);
}
final var process = builder.start();
if (output_processor != null) {
outputProcessorThread_ = startProcessStreamProcessor(process.getInputStream(), output_processor);
}
if (error_processor != null) {
errorProcessorThread_ = startProcessStreamProcessor(process.getErrorStream(), error_processor);
}
return process;
}
private Thread startProcessStreamProcessor(InputStream stream, Function<String, Boolean> processor) {
var processor_thread = new Thread(() -> {
try {
String line;
var in = new BufferedReader(new InputStreamReader(stream));
while ((line = in.readLine()) != null) {
successful_ &= processor.apply(line);
}
} catch (Exception e) {
// ignore
}
});
processor_thread.start();
return processor_thread;
}
/**
* Configures the operation from a {@link BaseProject}.
*
* @param project the project to configure the operation from
* @since 1.5
*/
abstract public T fromProject(BaseProject project);
/**
* Provides the work directory in which the operation will be performed.
* <p>
* If no work directory is provided, the JVM working directory will be used.
*
* @param directory the directory to use as a work directory
* @return this operation instance
* @since 1.5
*/
public T workDirectory(File directory) {
if (!directory.exists()) {
throw new OperationOptionException("ERROR: The work directory '" + directory + "' doesn't exist.");
}
if (!directory.isDirectory()) {
throw new OperationOptionException("ERROR: '" + directory + "' is not a directory.");
}
if (!directory.canWrite()) {
throw new OperationOptionException("ERROR: The work directory '" + directory + "' is not writable.");
}
workDirectory_ = directory;
return (T) this;
}
/**
* Provides the name of the tool to use for {@code java} execution.
* <p>
* If no java tool is provided {@code java} will be used.
*
* @param tool the name of the java tool
* @return this operation instance
* @since 1.5
*/
public T javaTool(String tool) {
javaTool_ = tool;
return (T) this;
}
/**
* Provides the options to provide to the java tool.
*
* @param options the java tool's options
* @return this operation instance
* @since 1.5
*/
public T javaOptions(List<String> options) {
javaOptions_.addAll(options);
return (T) this;
}
/**
* Provides classpath entries to use for the operation.
*
* @param classpath classpath entries for the operation
* @return this operation instance
* @since 1.5.18
*/
public T classpath(String... classpath) {
classpath_.addAll(List.of(classpath));
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 1.5
*/
public T classpath(List<String> classpath) {
classpath_.addAll(classpath);
return (T) this;
}
/**
* Provides the main class to launch with the java tool.
*
* @param name the main class to launch
* @return this operation instance
* @since 1.5
*/
public T mainClass(String name) {
mainClass_ = name;
return (T) this;
}
/**
* Provides the processor that will be used to handle the process output.
* <p>
* It will be called for each line in the output.
*
* @param processor the output processor
* @return this operation instance
* @since 1.5.1
*/
public T outputProcessor(Function<String, Boolean> processor) {
outputProcessor_ = processor;
return (T) this;
}
/**
* Provides the processor that will be used to handle the process errors.
* <p>
* It will be called for each line in the error output.
*
* @param processor the error processor
* @return this operation instance
* @since 1.5.1
*/
public T errorProcessor(Function<String, Boolean> processor) {
errorProcessor_ = processor;
return (T) this;
}
/**
* Retrieves the work directory in which the operation will be performed.
*
* @return the directory to use as a work directory
* @since 1.5
*/
public File workDirectory() {
return workDirectory_;
}
/**
* retrieves the name of the tool to use for {@code java} execution.
*
* @return the name of the java tool
* @since 1.5
*/
public String javaTool() {
return javaTool_;
}
/**
* Retrieves the options to provide to the java tool.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the java tool's options
* @since 1.5
*/
public JavaOptions javaOptions() {
return javaOptions_;
}
/**
* Retrieves the classpath to use for the operation.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the operation's classpath
* @since 1.5
*/
public List<String> classpath() {
return classpath_;
}
/**
* Retrieves the main class to launch with the java tool.
*
* @return the main class to launch
* @since 1.5
*/
public String mainClass() {
return mainClass_;
}
/**
* Retrieves the processor that is used to handle the process output.
*
* @return the output processor
* @since 1.5.1
*/
public Function<String, Boolean> outputProcessor() {
return outputProcessor_;
}
/**
* Retrieves the processor that is used to handle the process errors.
*
* @return the error processor
* @since 1.5.1
*/
public Function<String, Boolean> errorProcessor() {
return errorProcessor_;
}
/**
* Retrieves the process that was used for the execution.
*
* @return the process that was executed
* @since 1.5
*/
public Process process() {
return process_;
}
}

View file

@ -0,0 +1,101 @@
/*
* 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.BaseProject;
import rife.bld.Project;
import rife.tools.FileUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Cleans by deleting a list of directories and all their contents.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class CleanOperation extends AbstractOperation<CleanOperation> {
private final List<File> directories_ = new ArrayList<>();
/**
* Performs the clean operation.
*
* @since 1.5
*/
public void execute() {
for (var directory : directories()) {
executeCleanDirectory(directory);
}
if (!silent()) {
System.out.println("Cleaning finished successfully.");
}
}
/**
* Part of the {@link #execute} operation, cleans an individual directory.
*
* @param directory the directory to clean.
* @since 1.5
*/
protected void executeCleanDirectory(File directory) {
try {
FileUtils.deleteDirectory(directory);
} catch (FileUtilsErrorException e) {
// no-op
}
}
/**
* Configures a clean operation from a {@link BaseProject}.
*
* @param project the project to configure the clean operation from
* @since 1.5
*/
public CleanOperation fromProject(BaseProject project) {
return directories(project.buildDirectory()
.listFiles(f -> !f.equals(project.buildBldDirectory())));
}
/**
* Provides directories to clean.
*
* @param directories directories to clean
* @return this operation instance
* @since 1.5.18
*/
public CleanOperation directories(File... directories) {
directories_.addAll(List.of(directories));
return this;
}
/**
* Provides a list of directories to clean.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param directories a list of directories to clean
* @return this operation instance
* @since 1.5
*/
public CleanOperation directories(List<File> directories) {
directories_.addAll(directories);
return this;
}
/**
* Retrieves the list of directories to clean.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the list of directories to clean.
* @since 1.5
*/
public List<File> directories() {
return directories_;
}
}

View file

@ -0,0 +1,480 @@
/*
* 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.BaseProject;
import rife.bld.Project;
import rife.bld.operations.exceptions.ExitStatusException;
import rife.tools.FileUtils;
import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Compiles main and test sources in the relevant build directories.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class CompileOperation extends AbstractOperation<CompileOperation> {
private File buildMainDirectory_;
private File buildTestDirectory_;
private final List<String> compileMainClasspath_ = new ArrayList<>();
private final List<String> compileTestClasspath_ = 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<>();
/**
* Performs the compile operation.
*
* @since 1.5
*/
public void execute()
throws IOException, ExitStatusException {
executeCreateBuildDirectories();
executeBuildMainSources();
executeBuildTestSources();
if (!diagnostics().isEmpty()) {
throw new ExitStatusException(ExitStatusException.EXIT_FAILURE);
}
if (!silent()) {
System.out.println("Compilation finished successfully.");
}
}
/**
* Part of the {@link #execute} operation, creates the build directories.
*
* @since 1.5
*/
protected void executeCreateBuildDirectories() {
if (buildMainDirectory() != null) {
buildMainDirectory().mkdirs();
}
if (buildTestDirectory() != null) {
buildTestDirectory().mkdirs();
}
}
/**
* Part of the {@link #execute} operation, builds the main sources.
*
* @since 1.5
*/
protected void executeBuildMainSources()
throws IOException {
var sources = new ArrayList<>(mainSourceFiles());
for (var directory : mainSourceDirectories()) {
sources.addAll(FileUtils.getJavaFileList(directory));
}
executeBuildSources(
compileMainClasspath(),
sources,
buildMainDirectory());
}
/**
* Part of the {@link #execute} operation, builds the test sources.
*
* @since 1.5
*/
protected void executeBuildTestSources()
throws IOException {
var sources = new ArrayList<>(testSourceFiles());
for (var directory : testSourceDirectories()) {
sources.addAll(FileUtils.getJavaFileList(directory));
}
executeBuildSources(
compileTestClasspath(),
sources,
buildTestDirectory());
}
/**
* Part of the {@link #execute} operation, build sources to a destination.
*
* @param classpath the classpath list used for the compilation
* @param sources the source files to compile
* @param destination the destination directory
* @since 1.5
*/
protected void executeBuildSources(List<String> classpath, List<File> sources, File destination)
throws IOException {
if (sources.isEmpty() || destination == null) {
return;
}
var compiler = ToolProvider.getSystemJavaCompiler();
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("-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);
}
}
}
/**
* Part of the {@link #execute} operation, processes the compilation diagnostics.
*
* @param diagnostics the diagnostics to process
* @since 1.5
*/
protected void executeProcessDiagnostics(DiagnosticCollector<JavaFileObject> diagnostics) {
for (var diagnostic : diagnostics.getDiagnostics()) {
System.err.print(executeFormatDiagnostic(diagnostic));
}
}
/**
* Part of the {@link #execute} operation, format a single diagnostic.
*
* @param diagnostic the diagnostic to format
* @return a string representation of the diagnostic
* @since 1.5
*/
protected String executeFormatDiagnostic(Diagnostic<? extends JavaFileObject> diagnostic) {
return diagnostic.toString() + System.lineSeparator();
}
/**
* Configures a compile operation from a {@link BaseProject}.
*
* @param project the project to configure the compile operation from
* @since 1.5
*/
public CompileOperation fromProject(BaseProject project) {
var operation = buildMainDirectory(project.buildMainDirectory())
.buildTestDirectory(project.buildTestDirectory())
.compileMainClasspath(project.compileMainClasspath())
.compileTestClasspath(project.compileTestClasspath())
.mainSourceFiles(project.mainSourceFiles())
.testSourceFiles(project.testSourceFiles());
if (project.javaRelease() != null && !compileOptions().containsRelease()) {
compileOptions().release(project.javaRelease());
}
return operation;
}
/**
* Provides the main build destination directory.
*
* @param directory the directory to use for the main build destination
* @return this operation instance
* @since 1.5
*/
public CompileOperation buildMainDirectory(File directory) {
buildMainDirectory_ = directory;
return this;
}
/**
* Provides the test build destination directory.
*
* @param directory the directory to use for the test build destination
* @return this operation instance
* @since 1.5
*/
public CompileOperation buildTestDirectory(File directory) {
buildTestDirectory_ = directory;
return this;
}
/**
* Provides entries for the main compilation classpath.
*
* @param classpath classpath entries
* @return this operation instance
* @since 1.5.18
*/
public CompileOperation compileMainClasspath(String... classpath) {
compileMainClasspath_.addAll(Arrays.asList(classpath));
return this;
}
/**
* Provides a list of entries for the main compilation classpath.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param classpath a list of classpath entries
* @return this operation instance
* @since 1.5
*/
public CompileOperation compileMainClasspath(List<String> classpath) {
compileMainClasspath_.addAll(classpath);
return this;
}
/**
* Provides entries for the test compilation classpath.
*
* @param classpath classpath entries
* @return this operation instance
* @since 1.5.18
*/
public CompileOperation compileTestClasspath(String... classpath) {
compileTestClasspath_.addAll(Arrays.asList(classpath));
return this;
}
/**
* Provides a list of entries for the test compilation classpath.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param classpath a list of classpath entries
* @return this operation instance
* @since 1.5
*/
public CompileOperation compileTestClasspath(List<String> classpath) {
compileTestClasspath_.addAll(classpath);
return this;
}
/**
* Provides main files that should be compiled.
*
* @param files main files
* @return this operation instance
* @since 1.5.18
*/
public CompileOperation mainSourceFiles(File... files) {
mainSourceFiles_.addAll(Arrays.asList(files));
return this;
}
/**
* Provides a list of main files that should be compiled.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param files a list of main files
* @return this operation instance
* @since 1.5
*/
public CompileOperation mainSourceFiles(List<File> files) {
mainSourceFiles_.addAll(files);
return this;
}
/**
* Provides test files that should be compiled.
*
* @param files test files
* @return this operation instance
* @since 1.5.18
*/
public CompileOperation testSourceFiles(File... files) {
testSourceFiles_.addAll(Arrays.asList(files));
return this;
}
/**
* Provides a list of test files that should be compiled.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param files a list of test files
* @return this operation instance
* @since 1.5
*/
public CompileOperation testSourceFiles(List<File> files) {
testSourceFiles_.addAll(files);
return this;
}
/**
* Provides main source directories that should be compiled.
*
* @param directories main source directories
* @return this operation instance
* @since 1.5.10
*/
public CompileOperation mainSourceDirectories(File... directories) {
mainSourceDirectories_.addAll(List.of(directories));
return this;
}
/**
* Provides a list of main source directories that should be compiled.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param directories a list of main source directories
* @return this operation instance
* @since 1.5.10
*/
public CompileOperation mainSourceDirectories(List<File> directories) {
mainSourceDirectories_.addAll(directories);
return this;
}
/**
* Provides test source directories that should be compiled.
*
* @param directories test source directories
* @return this operation instance
* @since 1.5.10
*/
public CompileOperation testSourceDirectories(File... directories) {
testSourceDirectories_.addAll(List.of(directories));
return this;
}
/**
* Provides a list of test source directories that should be compiled.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param directories a list of test source directories
* @return this operation instance
* @since 1.5.10
*/
public CompileOperation testSourceDirectories(List<File> directories) {
testSourceDirectories_.addAll(directories);
return this;
}
/**
* Provides a list of compilation options to provide to the compiler.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param options the list of compilation options
* @return this operation instance
* @since 1.5
*/
public CompileOperation compileOptions(List<String> options) {
compileOptions_.addAll(options);
return this;
}
/**
* Retrieves the main build destination directory.
*
* @return the main build destination
* @since 1.5
*/
public File buildMainDirectory() {
return buildMainDirectory_;
}
/**
* Retrieves the test build destination directory.
*
* @return the test build destination
* @since 1.5
*/
public File buildTestDirectory() {
return buildTestDirectory_;
}
/**
* Retrieves the list of entries for the main compilation classpath.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the main compilation classpath list
* @since 1.5
*/
public List<String> compileMainClasspath() {
return compileMainClasspath_;
}
/**
* Retrieves the list of entries for the test compilation classpath.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the test compilation classpath list
* @since 1.5
*/
public List<String> compileTestClasspath() {
return compileTestClasspath_;
}
/**
* Retrieves the list of main files that should be compiled.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the list of main files to compile
* @since 1.5
*/
public List<File> mainSourceFiles() {
return mainSourceFiles_;
}
/**
* Retrieves the list of test files that should be compiled.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the list of test files to compile
* @since 1.5
*/
public List<File> testSourceFiles() {
return testSourceFiles_;
}
/**
* Retrieves the list of main source directories that should be compiled.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the list of main source directories to compile
* @since 1.5.10
*/
public List<File> mainSourceDirectories() {
return mainSourceDirectories_;
}
/**
* Retrieves the list of test source directories that should be compiled.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the list of test source directories to compile
* @since 1.5.10
*/
public List<File> testSourceDirectories() {
return testSourceDirectories_;
}
/**
* Retrieves the list of compilation options for the compiler.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the list of compiler options
* @since 1.5
*/
public JavacOptions compileOptions() {
return compileOptions_;
}
/**
* Retrieves the list of diagnostics resulting from the compilation.
*
* @return the list of compilation diagnostics
* @since 1.5
*/
public List<Diagnostic<? extends JavaFileObject>> diagnostics() {
return diagnostics_;
}
}

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.BaseProjectBlueprint;
import java.io.File;
/**
* Creates a new base project structure.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.20
*/
public class CreateBaseOperation extends AbstractCreateOperation<CreateBaseOperation, Project> {
public CreateBaseOperation() {
super("bld.base.");
}
protected Project createProjectBlueprint() {
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

@ -0,0 +1,35 @@
/*
* 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.BaseProjectBlueprint;
import rife.bld.blueprints.LibProjectBlueprint;
import java.io.File;
/**
* Creates a new lib project structure.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.6
*/
public class CreateLibOperation extends AbstractCreateOperation<CreateLibOperation, Project> {
public CreateLibOperation() {
super("bld.lib.");
}
protected Project createProjectBlueprint() {
return new LibProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName());
}
protected String projectMainClassName(String projectClassName) {
return projectClassName + "Lib";
}
protected boolean createIdeaRunMain() {
return false;
}
}

View file

@ -0,0 +1,92 @@
/*
* 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.blueprints.Rife2ProjectBlueprint;
import rife.bld.dependencies.*;
import rife.template.TemplateFactory;
import rife.tools.FileUtils;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File;
import java.io.IOException;
/**
* Creates a new RIFE2 project structure.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public class CreateRife2Operation extends AbstractCreateOperation<CreateRife2Operation, Rife2ProjectBlueprint> {
File srcMainWebappCssDirectory_;
File srcMainWebappWebInfDirectory_;
public CreateRife2Operation() {
super("bld.rife2_hello.");
}
protected Rife2ProjectBlueprint createProjectBlueprint() {
return new Rife2ProjectBlueprint(new File(workDirectory(), projectName()), packageName(), projectName());
}
@Override
protected void executeConfigure() {
super.executeConfigure();
projectMainName_ = projectClassName_ + "Site";
projectMainUberName_ = projectMainName_ + "Uber";
srcMainWebappCssDirectory_ = new File(project_.srcMainWebappDirectory(), "css");
srcMainWebappWebInfDirectory_ = new File(project_.srcMainWebappDirectory(), "WEB-INF");
}
@Override
protected void executeCreateProjectStructure() {
super.executeCreateProjectStructure();
srcMainWebappCssDirectory_.mkdirs();
srcMainWebappWebInfDirectory_.mkdirs();
}
@Override
protected void executePopulateProjectStructure()
throws FileUtilsErrorException, IOException {
super.executePopulateProjectStructure();
// project site uber
var main_uber_template = TemplateFactory.TXT.get(templateBase_ + "project_main_uber");
main_uber_template.setValue("package", project_.pkg());
main_uber_template.setValue("projectMain", projectMainName_);
main_uber_template.setValue("projectMainUber", projectMainUberName_);
var project_main_uber_file = new File(mainPackageDirectory_, projectMainUberName_ + ".java");
FileUtils.writeString(main_uber_template.getContent(), project_main_uber_file);
// project template
var template_template = TemplateFactory.HTML.get(templateBase_ + "project_template");
template_template.setValue("project", projectClassName_);
var project_template_file = new File(project_.srcMainResourcesTemplatesDirectory(), "hello.html");
FileUtils.writeString(template_template.getContent(), project_template_file);
// project css
FileUtils.writeString(
TemplateFactory.TXT.get(templateBase_ + "project_style").getContent(),
new File(srcMainWebappCssDirectory_, "style.css"));
// project web.xml
var web_xml_template = TemplateFactory.XML.get(templateBase_ + "project_web");
web_xml_template.setValue("package", project_.pkg());
web_xml_template.setValue("projectMain", projectMainName_);
var project_web_xml_file = new File(srcMainWebappWebInfDirectory_, "web.xml");
FileUtils.writeString(web_xml_template.getContent(), project_web_xml_file);
}
@Override
protected void executePopulateIdeaProject()
throws FileUtilsErrorException {
super.executePopulateIdeaProject();
FileUtils.writeString(
TemplateFactory.XML.get(templateBase_ + "idea.libraries.standalone").getContent(),
new File(ideaLibrariesDirectory_, "standalone.xml"));
}
}

View file

@ -0,0 +1,181 @@
/*
* 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.BaseProject;
import rife.bld.dependencies.*;
import java.util.ArrayList;
import java.util.List;
import static rife.bld.dependencies.Scope.compile;
import static rife.bld.dependencies.Scope.runtime;
/**
* Transitively generates a hierarchical tree of dependencies.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5.21
*/
public class DependencyTreeOperation extends AbstractOperation<DependencyTreeOperation> {
private ArtifactRetriever retriever_ = null;
private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes();
private final StringBuilder dependencyTree_ = new StringBuilder();
/**
* Performs the dependency tree operation.
*
* @since 1.5.21
*/
public void execute() {
var compile_tree = executeGenerateCompileDependencies();
var runtime_tree = executeGenerateRuntimeDependencies();
dependencyTree_.setLength(0);
dependencyTree_.append(compile_tree);
dependencyTree_.append(System.lineSeparator());
dependencyTree_.append(runtime_tree);
dependencyTree_.append(System.lineSeparator());
System.out.println(compile_tree);
System.out.println(runtime_tree);
}
/**
* Part of the {@link #execute} operation, generates the tree for the compile scope.
*
* @since 1.5.21
*/
protected String executeGenerateCompileDependencies() {
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 runtime scope.
*
* @since 1.5.21
*/
protected String executeGenerateRuntimeDependencies() {
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;
}
/**
* Configures a dependency tree operation from a {@link BaseProject}.
*
* @param project the project to configure the operation from
* @since 1.5.21
*/
public DependencyTreeOperation fromProject(BaseProject project) {
return artifactRetriever(project.artifactRetriever())
.repositories(project.repositories())
.dependencies(project.dependencies());
}
/**
* Provides repositories to resolve the dependencies against.
*
* @param repositories repositories against which dependencies will be resolved
* @return this operation instance
* @since 1.5.21
*/
public DependencyTreeOperation repositories(Repository... repositories) {
repositories_.addAll(List.of(repositories));
return this;
}
/**
* Provides a list of repositories to resolve the dependencies against.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param repositories a list of repositories against which dependencies will be resolved
* @return this operation instance
* @since 1.5.21
*/
public DependencyTreeOperation repositories(List<Repository> repositories) {
repositories_.addAll(repositories);
return this;
}
/**
* Provides scoped dependencies to generate a tree for.
*
* @param dependencies the dependencies that will be resolved for tree generation
* @return this operation instance
* @since 1.5.21
*/
public DependencyTreeOperation dependencies(DependencyScopes dependencies) {
dependencies_.include(dependencies);
return this;
}
/**
* Provides the artifact retriever to use.
*
* @param retriever the artifact retriever
* @return this operation instance
* @since 1.5.21
*/
public DependencyTreeOperation artifactRetriever(ArtifactRetriever retriever) {
retriever_ = retriever;
return this;
}
/**
* Retrieves the repositories in which the dependencies will be resolved.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the repositories used for dependency resolution
* @since 1.5.21
*/
public List<Repository> repositories() {
return repositories_;
}
/**
* Retrieves the scoped dependencies that will be used for tree generation.
* <p>
* This is a modifiable structure that can be retrieved and changed.
*
* @return the scoped dependencies
* @since 1.5.21
*/
public DependencyScopes dependencies() {
return dependencies_;
}
/**
* Returns the artifact retriever that is used.
*
* @return the artifact retriever
* @since 1.5.21
*/
public ArtifactRetriever artifactRetriever() {
if (retriever_ == null) {
return ArtifactRetriever.instance();
}
return retriever_;
}
/**
* Returns the last generated dependency tree.
*
* @return the last generated dependency tree
* @since 1.5.21
*/
public String dependencyTree() {
return dependencyTree_.toString();
}
}

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