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

Added native support for Java modules

This commit is contained in:
Geert Bevin 2024-08-22 19:04:56 -04:00
parent 7cd547f8b6
commit 0797e39dd6
43 changed files with 3196 additions and 444 deletions

View file

@ -5,6 +5,7 @@
package rife.bld;
import rife.bld.dependencies.*;
import rife.bld.dependencies.Module;
import rife.bld.help.*;
import rife.bld.operations.*;
import rife.tools.FileUtils;
@ -245,6 +246,13 @@ public class BaseProject extends BuildExecutor {
* @since 1.5
*/
protected File libCompileDirectory = null;
/**
* The modules compile scope lib directory.
*
* @see #libCompileModulesDirectory()
* @since 2.1
*/
protected File libCompileModulesDirectory = null;
/**
* The provided scope lib directory.
*
@ -252,6 +260,13 @@ public class BaseProject extends BuildExecutor {
* @since 1.8
*/
protected File libProvidedDirectory = null;
/**
* The modules provided scope lib directory.
*
* @see #libProvidedModulesDirectory()
* @since 2.1
*/
protected File libProvidedModulesDirectory = null;
/**
* The runtime scope lib directory.
*
@ -259,6 +274,13 @@ public class BaseProject extends BuildExecutor {
* @since 1.5
*/
protected File libRuntimeDirectory = null;
/**
* The modules runtime scope lib directory.
*
* @see #libRuntimeModulesDirectory()
* @since 2.1
*/
protected File libRuntimeModulesDirectory = null;
/**
* The standalone scope lib directory.
*
@ -267,12 +289,26 @@ public class BaseProject extends BuildExecutor {
*/
protected File libStandaloneDirectory = null;
/**
* The standalone scope lib directory.
* The modules standalone scope lib directory.
*
* @see #libStandaloneModulesDirectory()
* @since 2.1
*/
protected File libStandaloneModulesDirectory = null;
/**
* The test scope lib directory.
*
* @see #libTestDirectory()
* @since 1.5
*/
protected File libTestDirectory = null;
/**
* The modules test scope lib directory.
*
* @see #libTestModulesDirectory()
* @since 2.1
*/
protected File libTestModulesDirectory = null;
/**
* The build directory.
*
@ -860,6 +896,101 @@ public class BaseProject extends BuildExecutor {
return new LocalDependency(path);
}
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId) {
return new Module(groupId, artifactId);
}
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @param version the module version
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId, String version) {
return new Module(groupId, artifactId, version(version));
}
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @param version the module version
* @param classifier the module classifier
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId, String version, String classifier) {
return new Module(groupId, artifactId, version(version), classifier);
}
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @param version the module version
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId, Version version) {
return new Module(groupId, artifactId, version);
}
/**
* Creates a new module instance.
*
* @param groupId the module group identifier
* @param artifactId the module artifact identifier
* @param version the module version
* @param classifier the module classifier
* @return a newly created {@code Module} instance
* @since 2.1
*/
public Module module(String groupId, String artifactId, Version version, String classifier) {
return new Module(groupId, artifactId, version, classifier);
}
/**
* Creates a new module instance from a string representation.
* The format is {@code groupId:artifactId:version:classifier}.
* The {@code version} and {@code classifier} are optional.
* <p>
* If the string can't be successfully parsed, {@code null} will be returned.
*
* @param description the module string to parse
* @return a parsed instance of {@code Module}; or
* {@code null} when the string couldn't be parsed
* @since 2.1
*/
public Module module(String description) {
return Module.parse(description);
}
/**
* Creates a local module instance.
* <p>
* If the local module points to a directory, it will be scanned for jar files.
*
* @param path the file system path of the local module
* @since 2.1
*/
public LocalModule localModule(String path) {
return new LocalModule(path);
}
/*
* Project directories
*/
@ -1012,6 +1143,16 @@ public class BaseProject extends BuildExecutor {
return Objects.requireNonNullElseGet(libCompileDirectory, () -> new File(libDirectory(), "compile"));
}
/**
* Returns the project modules compile scope lib directory.
* Defaults to {@code "modules"} relative to {@link #libCompileDirectory()}.
*
* @since 2.1
*/
public File libCompileModulesDirectory() {
return Objects.requireNonNullElseGet(libCompileModulesDirectory, () -> new File(libCompileDirectory(), "modules"));
}
/**
* Returns the project provided scope lib directory.
* Defaults to {@code "provided"} relative to {@link #libDirectory()}.
@ -1022,6 +1163,16 @@ public class BaseProject extends BuildExecutor {
return Objects.requireNonNullElseGet(libProvidedDirectory, () -> new File(libDirectory(), "provided"));
}
/**
* Returns the project modules provided scope lib directory.
* Defaults to {@code "modules"} relative to {@link #libProvidedDirectory()}.
*
* @since 2.1
*/
public File libProvidedModulesDirectory() {
return Objects.requireNonNullElseGet(libProvidedModulesDirectory, () -> new File(libProvidedDirectory(), "modules"));
}
/**
* Returns the project runtime scope lib directory.
* Defaults to {@code "runtime"} relative to {@link #libDirectory()}.
@ -1032,6 +1183,16 @@ public class BaseProject extends BuildExecutor {
return Objects.requireNonNullElseGet(libRuntimeDirectory, () -> new File(libDirectory(), "runtime"));
}
/**
* Returns the project modules runtime scope lib directory.
* Defaults to {@code "modules"} relative to {@link #libRuntimeDirectory()}.
*
* @since 1.5
*/
public File libRuntimeModulesDirectory() {
return Objects.requireNonNullElseGet(libRuntimeModulesDirectory, () -> new File(libRuntimeDirectory(), "modules"));
}
/**
* Returns the project standalone scope lib directory.
* Defaults to {@code null}.
@ -1039,7 +1200,17 @@ public class BaseProject extends BuildExecutor {
* @since 1.5
*/
public File libStandaloneDirectory() {
return null;
return libStandaloneDirectory;
}
/**
* Returns the project standalone scope lib directory.
* Defaults to {@code null}.
*
* @since 2.1
*/
public File libStandaloneModulesDirectory() {
return libStandaloneModulesDirectory;
}
/**
@ -1052,6 +1223,16 @@ public class BaseProject extends BuildExecutor {
return Objects.requireNonNullElseGet(libTestDirectory, () -> new File(libDirectory(), "test"));
}
/**
* Returns the project modules test scope lib directory.
* Defaults to {@code "modules"} relative to {@link #libTestDirectory()}.
*
* @since 2.1
*/
public File libTestModulesDirectory() {
return Objects.requireNonNullElseGet(libTestModulesDirectory, () -> new File(libTestDirectory(), "modules"));
}
/**
* Returns the project build directory.
* Defaults to {@code "build"} relative to {@link #workDirectory()}.
@ -1142,12 +1323,19 @@ public class BaseProject extends BuildExecutor {
libDirectory().mkdirs();
libBldDirectory().mkdirs();
libCompileDirectory().mkdirs();
libCompileModulesDirectory().mkdirs();
libProvidedDirectory().mkdirs();
libProvidedModulesDirectory().mkdirs();
libRuntimeDirectory().mkdirs();
libRuntimeModulesDirectory().mkdirs();
if (libStandaloneDirectory() != null) {
libStandaloneDirectory().mkdirs();
}
if (libStandaloneModulesDirectory() != null) {
libStandaloneModulesDirectory().mkdirs();
}
libTestDirectory().mkdirs();
libTestModulesDirectory().mkdirs();
}
/**
@ -1415,6 +1603,25 @@ public class BaseProject extends BuildExecutor {
return classpath;
}
/**
* Returns all the jar files that are in the compile scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libCompileModulesDirectory()}
* and adds all the jar files from the compile scope local modules.
*
* @since 2.1
*/
public List<File> compileModulePathJars() {
// detect the jar files in the modules compile lib directory
var dir_abs = libCompileModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
// build the compilation module path
var module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalModules(module_path, Scope.compile);
return module_path;
}
/**
* Returns all the jar files that are in the provided scope classpath.
* <p>
@ -1434,6 +1641,25 @@ public class BaseProject extends BuildExecutor {
return classpath;
}
/**
* Returns all the jar files that are in the provided scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libProvidedModulesDirectory()}
* and adds all the jar files from the provided scope local modules.
*
* @since 2.1
*/
public List<File> providedModulePathJars() {
// detect the jar files in the modules provided lib directory
var dir_abs = libProvidedModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
// build the provided module path
var module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalModules(module_path, Scope.provided);
return module_path;
}
/**
* Returns all the jar files that are in the runtime scope classpath.
* <p>
@ -1453,6 +1679,25 @@ public class BaseProject extends BuildExecutor {
return classpath;
}
/**
* Returns all the jar files that are in the runtime scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libRuntimeModulesDirectory()}
* and adds all the jar files from the runtime scope local modules.
*
* @since 2.1
*/
public List<File> runtimeModulePathJars() {
// detect the jar files in the modules runtime lib directory
var dir_abs = libRuntimeModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
// build the runtime module path
var module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalModules(module_path, Scope.runtime);
return module_path;
}
/**
* Returns all the jar files that are in the standalone scope classpath.
* <p>
@ -1477,6 +1722,30 @@ public class BaseProject extends BuildExecutor {
return classpath;
}
/**
* Returns all the jar files that are in the standalone scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libStandaloneModulesDirectory()}
* and adds all the jar files from the standalone scope local modules.
*
* @since 2.1
*/
public List<File> standaloneModulePathJars() {
// build the standalone classpath
List<File> module_path;
if (libStandaloneModulesDirectory() == null) {
module_path = new ArrayList<>();
} else {
// detect the jar files in the modules standalone lib directory
var dir_abs = libStandaloneModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
}
addLocalModules(module_path, Scope.standalone);
return module_path;
}
/**
* Returns all the jar files that are in the test scope classpath.
* <p>
@ -1496,20 +1765,51 @@ public class BaseProject extends BuildExecutor {
return classpath;
}
/**
* Returns all the jar files that are in the test scope module path.
* <p>
* By default, this collects all the jar files in the {@link #libTestModulesDirectory()}
* and adds all the jar files from the test scope local modules.
*
* @since 2.1
*/
public List<File> testModulePathJars() {
// detect the jar files in the test lib directory
var dir_abs = libTestModulesDirectory().getAbsoluteFile();
var jar_files = FileUtils.getFileList(dir_abs, INCLUDED_JARS, EXCLUDED_JARS);
// build the test module path
var module_path = new ArrayList<>(jar_files.stream().map(file -> new File(dir_abs, file)).toList());
addLocalModules(module_path, Scope.test);
return module_path;
}
private void addLocalDependencies(List<File> classpath, Scope scope) {
if (dependencies.get(scope) == null) {
return;
}
for (var dependency : dependencies.get(scope).localDependencies()) {
var local_file = new File(workDirectory(), dependency.path());
if (local_file.exists()) {
if (local_file.isDirectory()) {
var local_jar_files = FileUtils.getFileList(local_file.getAbsoluteFile(), INCLUDED_JARS, EXCLUDED_JARS);
classpath.addAll(new ArrayList<>(local_jar_files.stream().map(file -> new File(local_file, file)).toList()));
} else {
classpath.add(local_file);
}
addLocalJars(classpath, dependency.path());
}
}
private void addLocalModules(List<File> classpath, Scope scope) {
if (dependencies.get(scope) == null) {
return;
}
for (var module : dependencies.get(scope).localModules()) {
addLocalJars(classpath, module.path());
}
}
private void addLocalJars(List<File> jars, String path) {
var local_file = new File(workDirectory(), path);
if (local_file.exists()) {
if (local_file.isDirectory()) {
var local_jar_files = FileUtils.getFileList(local_file.getAbsoluteFile(), INCLUDED_JARS, EXCLUDED_JARS);
jars.addAll(new ArrayList<>(local_jar_files.stream().map(file -> new File(local_file, file)).toList()));
} else {
jars.add(local_file);
}
}
}
@ -1517,7 +1817,7 @@ public class BaseProject extends BuildExecutor {
/**
* Returns all the classpath entries for compiling the main sources.
* <p>
* By default, this converts the files from {@link #compileClasspathJars()} to absolute paths.
* By default, this converts the files from {@link #compileClasspathJars()} and {@link #providedClasspathJars()} to absolute paths.
*
* @since 1.5
*/
@ -1525,10 +1825,21 @@ public class BaseProject extends BuildExecutor {
return FileUtils.combineToAbsolutePaths(compileClasspathJars(), providedClasspathJars());
}
/**
* Returns all the module path entries for compiling the main sources.
* <p>
* By default, this converts the files from {@link #compileModulePathJars()} and {@link #providedModulePathJars()} to absolute paths.
*
* @since 2.1
*/
public List<String> compileMainModulePath() {
return FileUtils.combineToAbsolutePaths(compileModulePathJars(), providedModulePathJars());
}
/**
* Returns all the classpath entries for compiling the test sources.
* <p>
* By default, this converts the files from {@link #compileClasspathJars()} and
* By default, this converts the files from {@link #compileClasspathJars()}, {@link #providedClasspathJars()} and
* {@link #testClasspathJars()} to absolute paths, as well as the {@link #buildMainDirectory()}
*
* @since 1.5
@ -1540,6 +1851,18 @@ public class BaseProject extends BuildExecutor {
return paths;
}
/**
* Returns all the module path entries for compiling the test sources.
* <p>
* By default, this converts the files from {@link #compileModulePathJars()}, {@link #providedModulePathJars()} and
* {@link #testModulePathJars()} to absolute paths.
*
* @since 2.1
*/
public List<String> compileTestModulePath() {
return FileUtils.combineToAbsolutePaths(compileModulePathJars(), providedModulePathJars(), testModulePathJars());
}
/**
* Returns all the classpath entries for running the application.
* <p>
@ -1557,10 +1880,22 @@ public class BaseProject extends BuildExecutor {
return paths;
}
/**
* Returns all the module path entries for running the application.
* <p>
* By default, this converts the files from {@link #compileModulePathJars()},
* {@link #runtimeModulePathJars()} and {@link #standaloneModulePathJars()} to absolute paths.
*
* @since 2.1
*/
public List<String> runModulePath() {
return FileUtils.combineToAbsolutePaths(compileModulePathJars(), runtimeModulePathJars(), standaloneModulePathJars());
}
/**
* Returns all the classpath entries for testing the application.
* <p>
* By default, this converts the files from {@link #compileClasspathJars()},
* By default, this converts the files from {@link #compileClasspathJars()}, {@link #providedClasspathJars()},
* {@link #runtimeClasspathJars()} and {@link #testClasspathJars()}
* to absolute paths, as well as the {@link #srcMainResourcesDirectory()},
* {@link #buildMainDirectory()} and {@link #buildTestDirectory()}
@ -1577,6 +1912,19 @@ public class BaseProject extends BuildExecutor {
return paths;
}
/**
* Returns all the module path entries for testing the application.
* <p>
* By default, this converts the files from {@link #compileModulePathJars()}, {@link #providedModulePathJars()},
* {@link #runtimeModulePathJars()} and {@link #testModulePathJars()}
* to absolute paths.
*
* @since 2.1
*/
public List<String> testModulePath() {
return FileUtils.combineToAbsolutePaths(compileModulePathJars(), providedModulePathJars(), runtimeModulePathJars(), standaloneModulePathJars(), testModulePathJars());
}
/**
* Executes download and purge commands automatically when the
* {@code autoDownloadPurge} flag is set and changes have been detected.

View file

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

View file

@ -8,22 +8,45 @@ import java.util.Objects;
import java.util.regex.Pattern;
/**
* Contains the information required to describe an url dependency in the build system.
* Contains the information required to describe a dependency in the build system.
*
* @param groupId the dependency group identifier
* @param artifactId the dependency url identifier
* @param version the dependency version
* @param classifier the dependency classier
* @param type the dependency type
* @param exclusions the dependency exclusions for transitive resolution
* @param parent the parent dependency that created this dependency (only for information purposes)
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 1.5
*/
public record Dependency(String groupId, String artifactId, Version version, String classifier, String type, ExclusionSet exclusions, Dependency parent) {
public class Dependency {
public static final String CLASSIFIER_SOURCES = "sources";
public static final String CLASSIFIER_JAVADOC = "javadoc";
/**
* The dependency type name for a JAR file that can be placed either on the class-path or on the module-path.
*
* @since 2.1
*/
public static final String TYPE_JAR = "jar";
/**
* The dependency type name for a JAR file to unconditionally place on the class-path.
*
* @since 2.1
*/
public static final String TYPE_CLASSPATH_JAR = "classpath-jar";
/**
* The dependency type name for a JAR file to unconditionally place on the module-path.
*
* @since 2.1
*/
// see https://github.com/apache/maven/blob/maven-4.0.0-beta-3/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
public static final String TYPE_MODULAR_JAR = "modular-jar";
private final String groupId_;
private final String artifactId_;
private final Version version_;
private final String classifier_;
private final String type_;
private final ExclusionSet exclusions_;
private final Dependency parent_;
public Dependency(String groupId, String artifactId) {
this(groupId, artifactId, null, null, null);
}
@ -45,13 +68,20 @@ public record Dependency(String groupId, String artifactId, Version version, Str
}
public Dependency(String groupId, String artifactId, Version 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;
if (type == null) {
type = TYPE_JAR;
}
if (parent != null && parent.isModularJar() && TYPE_JAR.equals(type)) {
type = TYPE_MODULAR_JAR;
}
this.groupId_ = groupId;
this.artifactId_ = artifactId;
this.version_ = (version == null ? VersionNumber.UNKNOWN : version);
this.classifier_ = (classifier == null ? "" : classifier);
this.type_ = type;
this.exclusions_ = (exclusions == null ? new ExclusionSet() : exclusions);
this.parent_ = parent;
}
private static final Pattern DEPENDENCY_PATTERN = Pattern.compile("^(?<groupId>[^:@]+):(?<artifactId>[^:@]+)(?::(?<version>[^:@]+)(?::(?<classifier>[^:@]+))?)?(?:@(?<type>[^:@]+))?$");
@ -95,7 +125,7 @@ public record Dependency(String groupId, String artifactId, Version version, Str
* @since 1.5
*/
public Dependency baseDependency() {
return new Dependency(groupId, artifactId, VersionNumber.UNKNOWN, classifier, type);
return new Dependency(groupId_, artifactId_, VersionNumber.UNKNOWN, classifier_, type_);
}
/**
@ -107,7 +137,7 @@ public record Dependency(String groupId, String artifactId, Version version, Str
* @since 1.5
*/
public Dependency exclude(String groupId, String artifactId) {
exclusions.add(new DependencyExclusion(groupId, artifactId));
exclusions_.add(new DependencyExclusion(groupId, artifactId));
return this;
}
@ -119,7 +149,7 @@ public record Dependency(String groupId, String artifactId, Version version, Str
* @since 1.5.6
*/
public Dependency withClassifier(String classifier) {
return new Dependency(groupId, artifactId, version, classifier, type);
return new Dependency(groupId_, artifactId_, version_, classifier, type_);
}
/**
@ -146,34 +176,130 @@ public record Dependency(String groupId, String artifactId, Version version, Str
* @since 2.0
*/
public String toArtifactString() {
return groupId + ':' + artifactId;
return groupId_ + ':' + artifactId_;
}
public String toString() {
var result = new StringBuilder(groupId).append(':').append(artifactId);
if (!version.equals(VersionNumber.UNKNOWN)) {
result.append(':').append(version);
var result = new StringBuilder(groupId_).append(':').append(artifactId_);
if (!version_.equals(VersionNumber.UNKNOWN)) {
result.append(':').append(version_);
}
if (!classifier.isEmpty()) {
result.append(':').append(classifier);
if (!classifier_.isEmpty()) {
result.append(':').append(classifier_);
}
if (!type.isEmpty() && !"jar".equals(type)) {
result.append('@').append(type);
if (!type_.isEmpty() && !TYPE_JAR.equals(type_)) {
result.append('@').append(type_);
}
return result.toString();
}
/**
* Returns this dependency's {@code groupId}.
*
* @return the {@code groupId} of this dependency
* @since 1.5
*/
public String groupId() {
return groupId_;
}
/**
* Returns this dependency's {@code artifactId}.
*
* @return the {@code artifactId} of this dependency
* @since 1.5
*/
public String artifactId() {
return artifactId_;
}
/**
* Returns this dependency's {@code version}.
*
* @return the {@code version} of this dependency
* @since 1.5
*/
public Version version() {
return version_;
}
/**
* Returns this dependency's {@code classifier}.
*
* @return the {@code classifier} of this dependency
* @since 1.5
*/
public String classifier() {
return classifier_;
}
/**
* Returns this dependency's {@code type}.
*
* @return the {@code type} of this dependency
* @since 1.5
*/
public String type() {
return type_;
}
/**
* Returns this dependency's {@code exclusions} for transitive resolution.
*
* @return the {@code exclusions} of this dependency
* @since 1.5
*/
public ExclusionSet exclusions() {
return exclusions_;
}
/**
* Returns this dependency's {@code parent} dependency that created this
* dependency (only for information purposes).
*
* @return the {@code parent} of this dependency
* @since 1.5
*/
public Dependency parent() {
return parent_;
}
/**
* Indicates whether this dependency specifically is a classpath jar or not.
*
* @return {@code true} when this dependency specifically is a classpath jar; or {@code false} otherwise
* @since 2.1
*/
public boolean isClasspathJar() {
return Module.TYPE_CLASSPATH_JAR.equals(type_);
}
/**
* Indicates whether this dependency is a modular jar or not.
*
* @return {@code true} when this dependency is a modular jar; or {@code false} otherwise
* @since 2.1
*/
public boolean isModularJar() {
return Module.TYPE_MODULAR_JAR.equals(type_);
}
private static String normalizedJarType(String type) {
if (TYPE_JAR.equals(type) || TYPE_MODULAR_JAR.equals(type) || TYPE_CLASSPATH_JAR.equals(type)) {
return TYPE_JAR;
}
return type;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == 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);
if (!(o instanceof Dependency that)) return false;
return groupId_.equals(that.groupId_) &&
artifactId_.equals(that.artifactId_) &&
classifier_.equals(that.classifier_) &&
normalizedJarType(type_).equals(normalizedJarType(that.type_));
}
public int hashCode() {
return Objects.hash(groupId, artifactId, classifier, type);
return Objects.hash(groupId_, artifactId_, classifier_, normalizedJarType(type_));
}
}

View file

@ -11,6 +11,8 @@ import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
import static rife.bld.dependencies.Dependency.*;
/**
* Resolves a dependency within a list of Maven-compatible repositories.
*
@ -333,7 +335,7 @@ public class DependencyResolver {
result.append('-').append(dependency_.classifier());
}
var type = dependency_.type();
if (type == null) {
if (type == null || TYPE_JAR.equals(type) || TYPE_MODULAR_JAR.equals(type) || TYPE_CLASSPATH_JAR.equals(type)) {
type = "jar";
}
result.append('.').append(type);

View file

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

View file

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

View file

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

View file

@ -10,6 +10,8 @@ import rife.xml.Xml2Data;
import java.util.*;
import java.util.regex.Pattern;
import static rife.bld.dependencies.Dependency.TYPE_JAR;
/**
* Parses an XML document to retrieve POM information, this is an internal class.
*
@ -103,7 +105,7 @@ class Xml2MavenPom extends Xml2Data {
"false",
exclusions,
dependency.parent());
if (resolved_dependency.type() == null || resolved_dependency.type().equals("jar")) {
if (resolved_dependency.type() == null || TYPE_JAR.equals(resolved_dependency.type())) {
var scope = Scope.valueOf(resolved_dependency.scope());
if (scopes_list.contains(scope)) {
var resolved_dependency_set = resolved_dependencies.computeIfAbsent(scope, k -> new LinkedHashSet<>());

View file

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

View file

@ -27,6 +27,7 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
protected String javaTool_ = DEFAULT_JAVA_TOOL;
protected final JavaOptions javaOptions_ = new JavaOptions();
protected final List<String> classpath_ = new ArrayList<>();
protected final List<String> modulePath_ = new ArrayList<>();
protected String mainClass_;
protected Function<String, Boolean> outputProcessor_;
protected Function<String, Boolean> errorProcessor_;
@ -213,6 +214,32 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
return (T) this;
}
/**
* Provides module path entries to use for the operation.
*
* @param modulePath module path entries for the operation
* @return this operation instance
* @since 2.1
*/
public T modulePath(String... modulePath) {
modulePath_.addAll(List.of(modulePath));
return (T) this;
}
/**
* Provides a list of module path entries to use for the operation.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param modulePath a list of module path entries for the operation
* @return this operation instance
* @since 2.1
*/
public T modulePath(List<String> modulePath) {
modulePath_.addAll(modulePath);
return (T) this;
}
/**
* Provides the main class to launch with the java tool.
*
@ -297,6 +324,18 @@ public abstract class AbstractProcessOperation<T extends AbstractProcessOperatio
return classpath_;
}
/**
* Retrieves the module path to use for the operation.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the operation's module path
* @since 2.1
*/
public List<String> modulePath() {
return modulePath_;
}
/**
* Retrieves the main class to launch with the java tool.
*

View file

@ -26,6 +26,8 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
private File buildTestDirectory_;
private final List<String> compileMainClasspath_ = new ArrayList<>();
private final List<String> compileTestClasspath_ = new ArrayList<>();
private final List<String> compileMainModulePath_ = new ArrayList<>();
private final List<String> compileTestModulePath_ = new ArrayList<>();
private final List<File> mainSourceFiles_ = new ArrayList<>();
private final List<File> testSourceFiles_ = new ArrayList<>();
private final List<File> mainSourceDirectories_ = new ArrayList<>();
@ -78,6 +80,7 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
}
executeBuildSources(
compileMainClasspath(),
compileMainModulePath(),
sources,
buildMainDirectory());
}
@ -95,6 +98,7 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
}
executeBuildSources(
compileTestClasspath(),
compileTestModulePath(),
sources,
buildTestDirectory());
}
@ -103,11 +107,12 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
* Part of the {@link #execute} operation, build sources to a destination.
*
* @param classpath the classpath list used for the compilation
* @param modulePath the module path list used for the compilation
* @param sources the source files to compile
* @param destination the destination directory
* @since 1.5
* @since 2.1
*/
protected void executeBuildSources(List<String> classpath, List<File> sources, File destination)
protected void executeBuildSources(List<String> classpath, List<String> modulePath, List<File> sources, File destination)
throws IOException {
if (sources.isEmpty() || destination == null) {
return;
@ -117,7 +122,13 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
try (var file_manager = compiler.getStandardFileManager(null, null, null)) {
var compilation_units = file_manager.getJavaFileObjectsFromFiles(sources);
var diagnostics = new DiagnosticCollector<JavaFileObject>();
var options = new ArrayList<>(List.of("-d", destination.getAbsolutePath(), "-cp", FileUtils.joinPaths(classpath)));
var options = new ArrayList<>(List.of("-d", destination.getAbsolutePath()));
if (!classpath.isEmpty()) {
options.addAll(List.of("-cp", FileUtils.joinPaths(classpath)));
}
if (!modulePath.isEmpty()) {
options.addAll(List.of("-p", FileUtils.joinPaths(modulePath)));
}
options.addAll(compileOptions());
var compilation_task = compiler.getTask(null, file_manager, diagnostics, options, null, compilation_units);
if (!compilation_task.call()) {
@ -161,6 +172,8 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
.buildTestDirectory(project.buildTestDirectory())
.compileMainClasspath(project.compileMainClasspath())
.compileTestClasspath(project.compileTestClasspath())
.compileMainModulePath(project.compileMainModulePath())
.compileTestModulePath(project.compileTestModulePath())
.mainSourceFiles(project.mainSourceFiles())
.testSourceFiles(project.testSourceFiles());
if (project.javaRelease() != null && !compileOptions().containsRelease()) {
@ -245,6 +258,58 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
return this;
}
/**
* Provides entries for the main compilation module path.
*
* @param modulePath module path entries
* @return this operation instance
* @since 2.1
*/
public CompileOperation compileMainModulePath(String... modulePath) {
compileMainModulePath_.addAll(Arrays.asList(modulePath));
return this;
}
/**
* Provides a list of entries for the main compilation module path.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param modulePath a list of module path entries
* @return this operation instance
* @since 2.1
*/
public CompileOperation compileMainModulePath(List<String> modulePath) {
compileMainModulePath_.addAll(modulePath);
return this;
}
/**
* Provides entries for the test compilation module path.
*
* @param modulePath module path entries
* @return this operation instance
* @since 2.1
*/
public CompileOperation compileTestModulePath(String... modulePath) {
compileTestModulePath_.addAll(Arrays.asList(modulePath));
return this;
}
/**
* Provides a list of entries for the test compilation module path.
* <p>
* A copy will be created to allow this list to be independently modifiable.
*
* @param modulePath a list of module path entries
* @return this operation instance
* @since 2.1
*/
public CompileOperation compileTestModulePath(List<String> modulePath) {
compileTestModulePath_.addAll(modulePath);
return this;
}
/**
* Provides main files that should be compiled.
*
@ -407,6 +472,30 @@ public class CompileOperation extends AbstractOperation<CompileOperation> {
return compileTestClasspath_;
}
/**
* Retrieves the list of entries for the main compilation module path.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the main compilation module path list
* @since 2.1
*/
public List<String> compileMainModulePath() {
return compileMainModulePath_;
}
/**
* Retrieves the list of entries for the test compilation module path.
* <p>
* This is a modifiable list that can be retrieved and changed.
*
* @return the test compilation module path list
* @since 2.1
*/
public List<String> compileTestModulePath() {
return compileTestModulePath_;
}
/**
* Retrieves the list of main files that should be compiled.
* <p>

View file

@ -31,10 +31,15 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes();
private File libCompileDirectory_;
private File libCompileModulesDirectory_;
private File libProvidedDirectory_;
private File libProvidedModulesDirectory_;
private File libRuntimeDirectory_;
private File libRuntimeModulesDirectory_;
private File libStandaloneDirectory_;
private File libStandaloneModulesDirectory_;
private File libTestDirectory_;
private File libTestModulesDirectory_;
private boolean downloadSources_ = false;
private boolean downloadJavadoc_ = false;
@ -65,7 +70,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5
*/
protected void executeDownloadCompileDependencies() {
executeDownloadDependencies(libCompileDirectory(), dependencies().resolveCompileDependencies(properties(), artifactRetriever(), repositories()));
executeDownloadDependencies(libCompileDirectory(), libCompileModulesDirectory(), dependencies().resolveCompileDependencies(properties(), artifactRetriever(), repositories()));
}
/**
@ -74,7 +79,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.8
*/
protected void executeDownloadProvidedDependencies() {
executeDownloadDependencies(libProvidedDirectory(), dependencies().resolveProvidedDependencies(properties(), artifactRetriever(), repositories()));
executeDownloadDependencies(libProvidedDirectory(), libProvidedModulesDirectory(), dependencies().resolveProvidedDependencies(properties(), artifactRetriever(), repositories()));
}
/**
@ -83,7 +88,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5
*/
protected void executeDownloadRuntimeDependencies() {
executeDownloadDependencies(libRuntimeDirectory(), dependencies().resolveRuntimeDependencies(properties(), artifactRetriever(), repositories()));
executeDownloadDependencies(libRuntimeDirectory(), libRuntimeModulesDirectory(), dependencies().resolveRuntimeDependencies(properties(), artifactRetriever(), repositories()));
}
/**
@ -92,7 +97,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5
*/
protected void executeDownloadStandaloneDependencies() {
executeDownloadDependencies(libStandaloneDirectory(), dependencies().resolveStandaloneDependencies(properties(), artifactRetriever(), repositories()));
executeDownloadDependencies(libStandaloneDirectory(), libStandaloneModulesDirectory(), dependencies().resolveStandaloneDependencies(properties(), artifactRetriever(), repositories()));
}
/**
@ -101,23 +106,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
* @since 1.5
*/
protected void executeDownloadTestDependencies() {
executeDownloadDependencies(libTestDirectory(), dependencies().resolveTestDependencies(properties(), artifactRetriever(), repositories()));
executeDownloadDependencies(libTestDirectory(), libTestModulesDirectory(), dependencies().resolveTestDependencies(properties(), artifactRetriever(), repositories()));
}
/**
* Part of the {@link #execute} operation, download the artifacts for a particular dependency scope.
*
* @param destinationDirectory the directory in which the artifacts should be downloaded
* @param modulesDirectory the directory in which the modules should be downloaded
* @param dependencies the dependencies to download
* @since 1.6
* @since 2.1
*/
protected void executeDownloadDependencies(File destinationDirectory, DependencySet dependencies) {
if (destinationDirectory == null) {
return;
}
destinationDirectory.mkdirs();
protected void executeDownloadDependencies(File destinationDirectory, File modulesDirectory, DependencySet dependencies) {
var additional_classifiers = new String[0];
if (downloadSources_ || downloadJavadoc_) {
@ -128,7 +128,7 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
additional_classifiers = classifiers.toArray(new String[0]);
}
dependencies.transferIntoDirectory(new VersionResolution(properties()), artifactRetriever(), repositories(), destinationDirectory, additional_classifiers);
dependencies.transferIntoDirectory(new VersionResolution(properties()), artifactRetriever(), repositories(), destinationDirectory, modulesDirectory, additional_classifiers);
}
/**
@ -145,10 +145,15 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
.repositories(project.repositories())
.dependencies(project.dependencies())
.libCompileDirectory(project.libCompileDirectory())
.libCompileModulesDirectory(project.libCompileModulesDirectory())
.libProvidedDirectory(project.libProvidedDirectory())
.libProvidedModulesDirectory(project.libProvidedModulesDirectory())
.libRuntimeDirectory(project.libRuntimeDirectory())
.libRuntimeModulesDirectory(project.libRuntimeModulesDirectory())
.libStandaloneDirectory(project.libStandaloneDirectory())
.libStandaloneModulesDirectory(project.libStandaloneModulesDirectory())
.libTestDirectory(project.libTestDirectory())
.libTestModulesDirectory(project.libTestModulesDirectory())
.downloadSources(project.downloadSources())
.downloadJavadoc(project.downloadJavadoc());
}
@ -227,6 +232,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this;
}
/**
* Provides the {@code compile} scope modules download directory.
*
* @param directory the directory to download the {@code compile} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libCompileModulesDirectory(File directory) {
libCompileModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code provided} scope download directory.
*
@ -239,6 +256,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this;
}
/**
* Provides the {@code provided} scope modules download directory.
*
* @param directory the directory to download the {@code provided} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libProvidedModulesDirectory(File directory) {
libProvidedModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code runtime} scope download directory.
*
@ -251,6 +280,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this;
}
/**
* Provides the {@code runtime} scope modules download directory.
*
* @param directory the directory to download the {@code runtime} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libRuntimeModulesDirectory(File directory) {
libRuntimeModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code standalone} scope download directory.
*
@ -263,6 +304,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this;
}
/**
* Provides the {@code standalone} scope modules download directory.
*
* @param directory the directory to download the {@code standalone} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libStandaloneModulesDirectory(File directory) {
libStandaloneModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code test} scope download directory.
*
@ -275,6 +328,18 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return this;
}
/**
* Provides the {@code test} scope modules download directory.
*
* @param directory the directory to download the {@code test} scope modules into
* @return this operation instance
* @since 2.1
*/
public DownloadOperation libTestModulesDirectory(File directory) {
libTestModulesDirectory_ = directory;
return this;
}
/**
* Indicates whether the sources classifier should also be downloaded.
*
@ -359,6 +424,16 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return libCompileDirectory_;
}
/**
* Retrieves the {@code compile} scope modules download directory.
*
* @return the {@code compile} scope modules download directory
* @since 2.1
*/
public File libCompileModulesDirectory() {
return libCompileModulesDirectory_;
}
/**
* Retrieves the {@code provided} scope download directory.
*
@ -369,6 +444,16 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return libProvidedDirectory_;
}
/**
* Retrieves the {@code provided} scope modules download directory.
*
* @return the {@code provided} scope modules download directory
* @since 2.1
*/
public File libProvidedModulesDirectory() {
return libProvidedModulesDirectory_;
}
/**
* Retrieves the {@code runtime} scope download directory.
*
@ -379,6 +464,16 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return libRuntimeDirectory_;
}
/**
* Retrieves the {@code runtime} scope modules download directory.
*
* @return the {@code runtime} scope modules download directory
* @since 2.1
*/
public File libRuntimeModulesDirectory() {
return libRuntimeModulesDirectory_;
}
/**
* Retrieves the {@code standalone} scope download directory.
*
@ -389,6 +484,16 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return libStandaloneDirectory_;
}
/**
* Retrieves the {@code standalone} scope modules download directory.
*
* @return the {@code standalone} scope modules download directory
* @since 2.1
*/
public File libStandaloneModulesDirectory() {
return libStandaloneModulesDirectory_;
}
/**
* Retrieves the {@code test} scope download directory.
*
@ -399,6 +504,16 @@ public class DownloadOperation extends AbstractOperation<DownloadOperation> {
return libTestDirectory_;
}
/**
* Retrieves the {@code test} scope modules download directory.
*
* @return the {@code test} scope modules download directory
* @since 2.1
*/
public File libTestModulesDirectory() {
return libTestModulesDirectory_;
}
/**
* Retrieves whether the sources classifier should also be downloaded.
*

View file

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

View file

@ -28,6 +28,7 @@ import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import static rife.bld.dependencies.Dependency.*;
import static rife.bld.publish.MetadataBuilder.SNAPSHOT_TIMESTAMP_FORMATTER;
import static rife.tools.HttpUtils.*;
import static rife.tools.StringUtils.encodeHexLower;
@ -180,8 +181,8 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
artifact_name.append('-').append(artifact.classifier());
}
var type = artifact.type();
if (type == null) {
type = "jar";
if (type == null || TYPE_JAR.equals(type) || TYPE_MODULAR_JAR.equals(type) || TYPE_CLASSPATH_JAR.equals(type)) {
type = TYPE_JAR;
}
artifact_name.append('.').append(type);
@ -517,9 +518,9 @@ public class PublishOperation extends AbstractOperation<PublishOperation> {
artifactRetriever(project.artifactRetriever());
dependencies().include(project.dependencies());
artifacts(List.of(
new PublishArtifact(new File(project.buildDistDirectory(), project.jarFileName()), "", "jar"),
new PublishArtifact(new File(project.buildDistDirectory(), project.sourcesJarFileName()), "sources", "jar"),
new PublishArtifact(new File(project.buildDistDirectory(), project.javadocJarFileName()), "javadoc", "jar")));
new PublishArtifact(new File(project.buildDistDirectory(), project.jarFileName()), "", TYPE_JAR),
new PublishArtifact(new File(project.buildDistDirectory(), project.sourcesJarFileName()), CLASSIFIER_SOURCES, TYPE_JAR),
new PublishArtifact(new File(project.buildDistDirectory(), project.javadocJarFileName()), CLASSIFIER_JAVADOC, TYPE_JAR)));
if (info().groupId() == null) {
info().groupId(project.pkg());
}

View file

@ -31,10 +31,15 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
private final List<Repository> repositories_ = new ArrayList<>();
private final DependencyScopes dependencies_ = new DependencyScopes();
private File libCompileDirectory_;
private File libCompileModulesDirectory_;
private File libProvidedDirectory_;
private File libProvidedModulesDirectory_;
private File libRuntimeDirectory_;
private File libRuntimeModulesDirectory_;
private File libStandaloneDirectory_;
private File libStandaloneModulesDirectory_;
private File libTestDirectory_;
private File libTestModulesDirectory_;
private boolean preserveSources_ = false;
private boolean preserveJavadoc_ = false;
@ -65,7 +70,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
protected void executePurgeCompileDependencies() {
executePurgeDependencies(libCompileDirectory(), dependencies().resolveCompileDependencies(properties(), artifactRetriever(), repositories()));
executePurgeDependencies(libCompileDirectory(), libCompileModulesDirectory(), dependencies().resolveCompileDependencies(properties(), artifactRetriever(), repositories()));
}
/**
@ -74,7 +79,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.8
*/
protected void executePurgeProvidedDependencies() {
executePurgeDependencies(libProvidedDirectory(), dependencies().resolveProvidedDependencies(properties(), artifactRetriever(), repositories()));
executePurgeDependencies(libProvidedDirectory(), libProvidedModulesDirectory(), dependencies().resolveProvidedDependencies(properties(), artifactRetriever(), repositories()));
}
/**
@ -83,7 +88,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
protected void executePurgeRuntimeDependencies() {
executePurgeDependencies(libRuntimeDirectory(), dependencies().resolveRuntimeDependencies(properties(), artifactRetriever(), repositories()));
executePurgeDependencies(libRuntimeDirectory(), libRuntimeModulesDirectory(), dependencies().resolveRuntimeDependencies(properties(), artifactRetriever(), repositories()));
}
/**
@ -92,7 +97,7 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
protected void executePurgeStandaloneDependencies() {
executePurgeDependencies(libStandaloneDirectory(), dependencies().resolveStandaloneDependencies(properties(), artifactRetriever(), repositories()));
executePurgeDependencies(libStandaloneDirectory(), libStandaloneModulesDirectory(), dependencies().resolveStandaloneDependencies(properties(), artifactRetriever(), repositories()));
}
/**
@ -101,22 +106,29 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
* @since 1.5
*/
protected void executePurgeTestDependencies() {
executePurgeDependencies(libTestDirectory(), dependencies().resolveTestDependencies(properties(), artifactRetriever(), repositories()));
executePurgeDependencies(libTestDirectory(), libTestModulesDirectory(), dependencies().resolveTestDependencies(properties(), artifactRetriever(), repositories()));
}
/**
* Part of the {@link #execute} operation, purge the artifacts for a particular dependency scope.
*
* @param destinationDirectory the directory from which the artifacts should be purged
* @param dependencies the dependencies to purge
* @since 1.6
* @param classpathDirectory the directory from which the artifacts should be purged
* @param modulesDirectory the directory from which the modules should be purged
* @param dependencies the dependencies to purge
* @since 2.1
*/
protected void executePurgeDependencies(File destinationDirectory, DependencySet dependencies) {
if (destinationDirectory == null) {
protected void executePurgeDependencies(File classpathDirectory, File modulesDirectory, DependencySet dependencies) {
if (classpathDirectory == null && modulesDirectory == null) {
return;
}
var filenames = new HashSet<String>();
var classpath_names = new HashSet<String>();
var modules_names = new HashSet<String>();
for (var dependency : dependencies) {
var filenames = classpath_names;
if (dependency.isModularJar()) {
filenames = modules_names;
}
addTransferLocations(filenames, dependency);
if (preserveSources_) {
addTransferLocations(filenames, dependency.withClassifier(CLASSIFIER_SOURCES));
@ -126,15 +138,27 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
}
}
purgeFromDirectory(classpathDirectory, modulesDirectory, classpath_names);
purgeFromDirectory(modulesDirectory, classpathDirectory, modules_names);
}
private static void purgeFromDirectory(File directory, File preserveDirectory, HashSet<String> preservedFileNames) {
if (directory == null) {
return;
}
boolean printed_header = false;
for (var file : destinationDirectory.listFiles()) {
if (!filenames.contains(file.getName())) {
if (!printed_header) {
printed_header = true;
System.out.println("Deleting from " + destinationDirectory.getName() + ":");
var classpath_files = directory.listFiles();
if (classpath_files != null) {
for (var file : classpath_files) {
if (!preservedFileNames.contains(file.getName()) && !file.equals(preserveDirectory)) {
if (!printed_header) {
printed_header = true;
System.out.println("Deleting from " + directory.getName() + ":");
}
System.out.println(" " + file.getName());
file.delete();
}
System.out.println(" " + file.getName());
file.delete();
}
}
}
@ -159,10 +183,15 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
.repositories(project.repositories())
.dependencies(project.dependencies())
.libCompileDirectory(project.libCompileDirectory())
.libCompileModulesDirectory(project.libCompileModulesDirectory())
.libProvidedDirectory(project.libProvidedDirectory())
.libProvidedModulesDirectory(project.libProvidedModulesDirectory())
.libRuntimeDirectory(project.libRuntimeDirectory())
.libRuntimeModulesDirectory(project.libRuntimeModulesDirectory())
.libStandaloneDirectory(project.libStandaloneDirectory())
.libStandaloneModulesDirectory(project.libStandaloneModulesDirectory())
.libTestDirectory(project.libTestDirectory())
.libTestModulesDirectory(project.libTestModulesDirectory())
.preserveSources(project.downloadSources())
.preserveJavadoc(project.downloadJavadoc());
}
@ -267,6 +296,18 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this;
}
/**
* Provides the {@code compile} scope modules purge directory.
*
* @param directory the directory to purge the {@code compile} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libCompileModulesDirectory(File directory) {
libCompileModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code provided} scope purge directory.
*
@ -279,6 +320,18 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this;
}
/**
* Provides the {@code provided} scope modules purge directory.
*
* @param directory the directory to purge the {@code provided} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libProvidedModulesDirectory(File directory) {
libProvidedModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code runtime} scope purge directory.
*
@ -291,6 +344,18 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this;
}
/**
* Provides the {@code runtime} scope modules purge directory.
*
* @param directory the directory to purge the {@code runtime} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libRuntimeModulesDirectory(File directory) {
libRuntimeModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code standalone} scope purge directory.
*
@ -303,6 +368,18 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this;
}
/**
* Provides the {@code standalone} scope modules purge directory.
*
* @param directory the directory to purge the {@code standalone} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libStandaloneModulesDirectory(File directory) {
libStandaloneModulesDirectory_ = directory;
return this;
}
/**
* Provides the {@code test} scope purge directory.
*
@ -315,6 +392,18 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return this;
}
/**
* Provides the {@code test} scope modules purge directory.
*
* @param directory the directory to purge the {@code test} scope modules from
* @return this operation instance
* @since 2.1
*/
public PurgeOperation libTestModulesDirectory(File directory) {
libTestModulesDirectory_ = directory;
return this;
}
/**
* Provides the artifact retriever to use.
*
@ -373,6 +462,16 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return libCompileDirectory_;
}
/**
* Retrieves the {@code compile} scope modules purge directory.
*
* @return the {@code compile} scope modules purge directory
* @since 2.1
*/
public File libCompileModulesDirectory() {
return libCompileModulesDirectory_;
}
/**
* Retrieves the {@code provided} scope purge directory.
*
@ -383,6 +482,16 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return libProvidedDirectory_;
}
/**
* Retrieves the {@code provided} scope modules purge directory.
*
* @return the {@code provided} scope modules purge directory
* @since 2.1
*/
public File libProvidedModulesDirectory() {
return libProvidedModulesDirectory_;
}
/**
* Retrieves the {@code runtime} scope purge directory.
*
@ -393,6 +502,16 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return libRuntimeDirectory_;
}
/**
* Retrieves the {@code runtime} scope modules purge directory.
*
* @return the {@code runtime} scope modules purge directory
* @since 2.1
*/
public File libRuntimeModulesDirectory() {
return libRuntimeModulesDirectory_;
}
/**
* Retrieves the {@code standalone} scope purge directory.
*
@ -403,6 +522,16 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return libStandaloneDirectory_;
}
/**
* Retrieves the {@code standalone} scope modules purge directory.
*
* @return the {@code standalone} scope modules purge directory
* @since 2.1
*/
public File libStandaloneModulesDirectory() {
return libStandaloneModulesDirectory_;
}
/**
* Retrieves the {@code test} scope purge directory.
*
@ -413,6 +542,16 @@ public class PurgeOperation extends AbstractOperation<PurgeOperation> {
return libTestDirectory_;
}
/**
* Retrieves the {@code test} scope modules purge directory.
*
* @return the {@code test} scope modules purge directory
* @since 2.1
*/
public File libTestModulesDirectory() {
return libTestModulesDirectory_;
}
/**
* Retrieves whether the sources classifier files should be preserved.
*

View file

@ -35,6 +35,10 @@ public class RunOperation extends AbstractProcessOperation<RunOperation> {
args.add("-cp");
args.add(FileUtils.joinPaths(classpath()));
}
if (!modulePath().isEmpty()) {
args.add("-p");
args.add(FileUtils.joinPaths(modulePath()));
}
args.add(mainClass());
args.addAll(runOptions());
return args;
@ -50,6 +54,7 @@ public class RunOperation extends AbstractProcessOperation<RunOperation> {
var operation = workDirectory(project.workDirectory())
.javaTool(project.javaTool())
.classpath(project.runClasspath())
.modulePath(project.runModulePath())
.mainClass(project.mainClass());
if (project.usesRife2Agent()) {
operation.javaOptions().javaAgent(project.getRife2AgentFile());

View file

@ -51,8 +51,14 @@ public class TestOperation<T extends TestOperation<T, O>, O extends List<String>
var args = new ArrayList<String>();
args.add(javaTool());
args.addAll(javaOptions());
args.add("-cp");
args.add(FileUtils.joinPaths(classpath()));
if (!classpath().isEmpty()) {
args.add("-cp");
args.add(FileUtils.joinPaths(classpath()));
}
if (!modulePath().isEmpty()) {
args.add("-p");
args.add(FileUtils.joinPaths(modulePath()));
}
args.add(mainClass());
args.addAll(testToolOptions());
@ -68,7 +74,8 @@ public class TestOperation<T extends TestOperation<T, O>, O extends List<String>
public T fromProject(BaseProject project) {
var operation = workDirectory(project.workDirectory())
.javaTool(project.javaTool())
.classpath(project.testClasspath());
.classpath(project.testClasspath())
.modulePath(project.testModulePath());
if (project.usesRife2Agent()) {
operation.javaOptions().javaAgent(project.getRife2AgentFile());
}

View file

@ -14,6 +14,8 @@ import rife.tools.exceptions.FileUtilsErrorException;
import java.io.File;
import java.util.Objects;
import static rife.bld.dependencies.Dependency.TYPE_JAR;
/**
* Provides the functionalities to build a Maven POM xml file.
*
@ -186,7 +188,7 @@ public class PomBuilder {
t.blankValue("dependency-type");
t.blankValue("dependency-type-tag");
if (!"jar".equals(dependency.type())) {
if (!TYPE_JAR.equals(dependency.type())) {
t.setValueEncoded("dependency-type", dependency.type());
t.setBlock("dependency-type-tag");
}

View file

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

View file

@ -109,7 +109,7 @@ public class WrapperExtensionResolver {
additional_classifiers = classifiers.toArray(new String[0]);
}
var artifacts = dependencies.transferIntoDirectory(resolution_, retriever_, repositories_, destinationDirectory_, additional_classifiers);
var artifacts = dependencies.transferIntoDirectory(resolution_, retriever_, repositories_, destinationDirectory_, destinationDirectory_, additional_classifiers);
for (var artifact : artifacts) {
var location = artifact.location();