Switch to maven 4.0.0-alpha-2 (#718)

This commit is contained in:
Guillaume Nodet
2022-11-19 16:56:26 +01:00
committed by GitHub
parent 5a8f29cf6f
commit 895381b43f
16 changed files with 407 additions and 860 deletions

View File

@@ -24,8 +24,6 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@@ -37,7 +35,7 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.function.Consumer;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -45,6 +43,7 @@ import java.util.stream.Stream;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option; import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.maven.InternalErrorException; import org.apache.maven.InternalErrorException;
import org.apache.maven.Maven; import org.apache.maven.Maven;
import org.apache.maven.building.FileSource; import org.apache.maven.building.FileSource;
@@ -61,10 +60,7 @@ import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.exception.DefaultExceptionHandler; import org.apache.maven.exception.DefaultExceptionHandler;
import org.apache.maven.exception.ExceptionHandler; import org.apache.maven.exception.ExceptionHandler;
import org.apache.maven.exception.ExceptionSummary; import org.apache.maven.exception.ExceptionSummary;
import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.*;
import org.apache.maven.execution.MavenExecutionRequestPopulationException;
import org.apache.maven.execution.MavenExecutionRequestPopulator;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule; import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
import org.apache.maven.extension.internal.CoreExports; import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.extension.internal.CoreExtensionEntry; import org.apache.maven.extension.internal.CoreExtensionEntry;
@@ -101,9 +97,6 @@ import org.mvndaemon.mvnd.cache.invalidating.InvalidatingProjectArtifactsCache;
import org.mvndaemon.mvnd.cli.EnvHelper; import org.mvndaemon.mvnd.cli.EnvHelper;
import org.mvndaemon.mvnd.common.Environment; import org.mvndaemon.mvnd.common.Environment;
import org.mvndaemon.mvnd.common.Os; import org.mvndaemon.mvnd.common.Os;
import org.mvndaemon.mvnd.execution.BuildResumptionPersistenceException;
import org.mvndaemon.mvnd.execution.DefaultBuildResumptionAnalyzer;
import org.mvndaemon.mvnd.execution.DefaultBuildResumptionDataRepository;
import org.mvndaemon.mvnd.logging.internal.Slf4jLoggerManager; import org.mvndaemon.mvnd.logging.internal.Slf4jLoggerManager;
import org.mvndaemon.mvnd.logging.smart.BuildEventListener; import org.mvndaemon.mvnd.logging.smart.BuildEventListener;
import org.mvndaemon.mvnd.logging.smart.LoggingExecutionListener; import org.mvndaemon.mvnd.logging.smart.LoggingExecutionListener;
@@ -177,7 +170,9 @@ public class DaemonMavenCli {
private final LoggingExecutionListener executionListener; private final LoggingExecutionListener executionListener;
/** Non-volatile, assuming that it is accessed only from the main thread */ /**
* Non-volatile, assuming that it is accessed only from the main thread
*/
private BuildEventListener buildEventListener = BuildEventListener.dummy(); private BuildEventListener buildEventListener = BuildEventListener.dummy();
public DaemonMavenCli() throws Exception { public DaemonMavenCli() throws Exception {
@@ -354,12 +349,12 @@ public class DaemonMavenCli {
*/ */
void logging(CliRequest cliRequest) { void logging(CliRequest cliRequest) {
// LOG LEVEL // LOG LEVEL
cliRequest.debug = cliRequest.commandLine.hasOption(CLIManager.DEBUG); cliRequest.verbose = cliRequest.commandLine.hasOption(CLIManager.VERBOSE);
cliRequest.quiet = !cliRequest.debug && cliRequest.commandLine.hasOption(CLIManager.QUIET); cliRequest.quiet = !cliRequest.verbose && cliRequest.commandLine.hasOption(CLIManager.QUIET);
cliRequest.showErrors = cliRequest.debug || cliRequest.commandLine.hasOption(CLIManager.ERRORS); cliRequest.showErrors = cliRequest.verbose || cliRequest.commandLine.hasOption(CLIManager.ERRORS);
ch.qos.logback.classic.Level level; ch.qos.logback.classic.Level level;
if (cliRequest.debug) { if (cliRequest.verbose) {
level = ch.qos.logback.classic.Level.DEBUG; level = ch.qos.logback.classic.Level.DEBUG;
} else if (cliRequest.quiet) { } else if (cliRequest.quiet) {
level = ch.qos.logback.classic.Level.WARN; level = ch.qos.logback.classic.Level.WARN;
@@ -413,7 +408,7 @@ public class DaemonMavenCli {
} }
private void version(CliRequest cliRequest) throws ExitException { private void version(CliRequest cliRequest) throws ExitException {
if (cliRequest.debug || cliRequest.commandLine.hasOption(CLIManager.VERSION)) { if (cliRequest.verbose || cliRequest.commandLine.hasOption(CLIManager.VERSION)) {
buildEventListener.log(CLIReportingUtils.showVersion()); buildEventListener.log(CLIReportingUtils.showVersion());
if (cliRequest.commandLine.hasOption(CLIManager.VERSION)) { if (cliRequest.commandLine.hasOption(CLIManager.VERSION)) {
throw new ExitException(0); throw new ExitException(0);
@@ -576,7 +571,7 @@ public class DaemonMavenCli {
properties(cliRequest); properties(cliRequest);
configure(cliRequest, eventSpyDispatcher, configurationProcessors); configure(cliRequest, eventSpyDispatcher, configurationProcessors);
LoggingExecutionListener executionListener = container.lookup(LoggingExecutionListener.class); LoggingExecutionListener executionListener = container.lookup(LoggingExecutionListener.class);
populateRequest(cliRequest, cliRequest.request, slf4jLogger, eventSpyDispatcher, populateRequest(cliRequest, cliRequest.request, eventSpyDispatcher,
container.lookup(ModelProcessor.class), createTransferListener(cliRequest), buildEventListener, container.lookup(ModelProcessor.class), createTransferListener(cliRequest), buildEventListener,
executionListener); executionListener);
executionRequestPopulator.populateDefaults(cliRequest.request); executionRequestPopulator.populateDefaults(cliRequest.request);
@@ -729,18 +724,7 @@ public class DaemonMavenCli {
} }
} }
boolean canResume = new DefaultBuildResumptionAnalyzer().determineBuildResumptionData(result).map(resumption -> { if (result.canResume()) {
try {
Path directory = Paths.get(request.getBaseDirectory()).resolve("target");
new DefaultBuildResumptionDataRepository().persistResumptionData(directory, resumption);
return true;
} catch (BuildResumptionPersistenceException e) {
slf4jLogger.warn("Could not persist build resumption data", e);
}
return false;
}).orElse(false);
if (canResume) {
logBuildResumeHint("mvn <args> -r"); logBuildResumeHint("mvn <args> -r");
} else if (!failedProjects.isEmpty()) { } else if (!failedProjects.isEmpty()) {
List<MavenProject> sortedProjects = result.getTopologicallySortedProjects(); List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
@@ -763,8 +747,6 @@ public class DaemonMavenCli {
return 1; return 1;
} }
} else { } else {
Path directory = Paths.get(request.getBaseDirectory()).resolve("target");
new DefaultBuildResumptionDataRepository().removeResumptionData(directory);
return 0; return 0;
} }
} }
@@ -999,14 +981,13 @@ public class DaemonMavenCli {
} }
private void populateRequest(CliRequest cliRequest) { private void populateRequest(CliRequest cliRequest) {
populateRequest(cliRequest, cliRequest.request, slf4jLogger, eventSpyDispatcher, modelProcessor, populateRequest(cliRequest, cliRequest.request, eventSpyDispatcher, modelProcessor,
createTransferListener(cliRequest), buildEventListener, executionListener); createTransferListener(cliRequest), buildEventListener, executionListener);
} }
private static void populateRequest( private void populateRequest(
CliRequest cliRequest, CliRequest cliRequest,
MavenExecutionRequest request, MavenExecutionRequest request,
Logger slf4jLogger,
EventSpyDispatcher eventSpyDispatcher, EventSpyDispatcher eventSpyDispatcher,
ModelProcessor modelProcessor, ModelProcessor modelProcessor,
TransferListener transferListener, TransferListener transferListener,
@@ -1014,208 +995,50 @@ public class DaemonMavenCli {
LoggingExecutionListener executionListener) { LoggingExecutionListener executionListener) {
CommandLine commandLine = cliRequest.commandLine; CommandLine commandLine = cliRequest.commandLine;
String workingDirectory = cliRequest.workingDirectory; String workingDirectory = cliRequest.workingDirectory;
boolean showErrors = cliRequest.showErrors; boolean quiet = cliRequest.quiet;
boolean verbose = cliRequest.verbose;
String[] deprecatedOptions = { "up", "npu", "cpu", "npr" }; request.setShowErrors(cliRequest.showErrors); // default: false
for (String deprecatedOption : deprecatedOptions) {
if (commandLine.hasOption(deprecatedOption)) {
slf4jLogger.warn("Command line option -{} is deprecated and will be removed in future Maven versions.",
deprecatedOption);
}
}
// ----------------------------------------------------------------------
// Now that we have everything that we need we will fire up plexus and
// bring the maven component to life for use.
// ----------------------------------------------------------------------
if (commandLine.hasOption(CLIManager.BATCH_MODE)) {
request.setInteractiveMode(false);
}
boolean noSnapshotUpdates = false;
if (commandLine.hasOption(CLIManager.SUPRESS_SNAPSHOT_UPDATES)) {
noSnapshotUpdates = true;
}
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
List<String> goals = commandLine.getArgList();
boolean recursive = true;
// this is the default behavior.
String reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST;
if (commandLine.hasOption(CLIManager.NON_RECURSIVE)) {
recursive = false;
}
if (commandLine.hasOption(CLIManager.FAIL_FAST)) {
reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST;
} else if (commandLine.hasOption(CLIManager.FAIL_AT_END)) {
reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_AT_END;
} else if (commandLine.hasOption(CLIManager.FAIL_NEVER)) {
reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_NEVER;
}
if (commandLine.hasOption(CLIManager.OFFLINE)) {
request.setOffline(true);
}
boolean updateSnapshots = false;
if (commandLine.hasOption(CLIManager.UPDATE_SNAPSHOTS)) {
updateSnapshots = true;
}
String globalChecksumPolicy = null;
if (commandLine.hasOption(CLIManager.CHECKSUM_FAILURE_POLICY)) {
globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
} else if (commandLine.hasOption(CLIManager.CHECKSUM_WARNING_POLICY)) {
globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_WARN;
}
File baseDirectory = new File(workingDirectory, "").getAbsoluteFile(); File baseDirectory = new File(workingDirectory, "").getAbsoluteFile();
// ---------------------------------------------------------------------- disableOnPresentOption(commandLine, CLIManager.BATCH_MODE, request::setInteractiveMode);
// Profile Activation enableOnPresentOption(commandLine, CLIManager.SUPPRESS_SNAPSHOT_UPDATES, request::setNoSnapshotUpdates);
// ---------------------------------------------------------------------- request.setGoals(commandLine.getArgList());
request.setReactorFailureBehavior(determineReactorFailureBehaviour(commandLine));
List<String> activeProfiles = new ArrayList<>(); disableOnPresentOption(commandLine, CLIManager.NON_RECURSIVE, request::setRecursive);
enableOnPresentOption(commandLine, CLIManager.OFFLINE, request::setOffline);
List<String> inactiveProfiles = new ArrayList<>(); enableOnPresentOption(commandLine, CLIManager.UPDATE_SNAPSHOTS, request::setUpdateSnapshots);
request.setGlobalChecksumPolicy(determineGlobalCheckPolicy(commandLine));
if (commandLine.hasOption(CLIManager.ACTIVATE_PROFILES)) { request.setBaseDirectory(baseDirectory);
String[] profileOptionValues = commandLine.getOptionValues(CLIManager.ACTIVATE_PROFILES); request.setSystemProperties(cliRequest.systemProperties);
if (profileOptionValues != null) { request.setUserProperties(cliRequest.userProperties);
for (String profileOptionValue : profileOptionValues) { request.setMultiModuleProjectDirectory(cliRequest.multiModuleProjectDirectory);
StringTokenizer profileTokens = new StringTokenizer(profileOptionValue, ","); request.setPom(determinePom(modelProcessor, commandLine, workingDirectory, baseDirectory));
request.setTransferListener(transferListener);
while (profileTokens.hasMoreTokens()) { request.setExecutionListener(executionListener);
String profileAction = profileTokens.nextToken().trim();
if (profileAction.startsWith("-") || profileAction.startsWith("!")) {
inactiveProfiles.add(profileAction.substring(1));
} else if (profileAction.startsWith("+")) {
activeProfiles.add(profileAction.substring(1));
} else {
activeProfiles.add(profileAction);
}
}
}
}
}
ExecutionEventLogger executionEventLogger = new ExecutionEventLogger(); ExecutionEventLogger executionEventLogger = new ExecutionEventLogger();
executionListener.init( executionListener.init(
eventSpyDispatcher.chainListener(executionEventLogger), eventSpyDispatcher.chainListener(executionEventLogger),
buildEventListener); buildEventListener);
String alternatePomFile = null;
if (commandLine.hasOption(CLIManager.ALTERNATE_POM_FILE)) {
alternatePomFile = commandLine.getOptionValue(CLIManager.ALTERNATE_POM_FILE);
}
request.setBaseDirectory(baseDirectory)
.setGoals(goals)
.setSystemProperties(cliRequest.systemProperties)
.setUserProperties(cliRequest.userProperties)
.setReactorFailureBehavior(reactorFailureBehaviour) // default: fail fast
.setRecursive(recursive) // default: true
.setShowErrors(showErrors) // default: false
.addActiveProfiles(activeProfiles) // optional
.addInactiveProfiles(inactiveProfiles) // optional
.setExecutionListener(executionListener)
.setTransferListener(transferListener) // default: batch mode which goes along with interactive
.setUpdateSnapshots(updateSnapshots) // default: false
.setNoSnapshotUpdates(noSnapshotUpdates) // default: false
.setGlobalChecksumPolicy(globalChecksumPolicy) // default: warn
.setMultiModuleProjectDirectory(cliRequest.getMultiModuleProjectDirectory());
if (alternatePomFile != null) {
File pom = resolveFile(new File(alternatePomFile), workingDirectory);
if (pom.isDirectory()) {
pom = new File(pom, "pom.xml");
}
request.setPom(pom);
} else if (modelProcessor != null) {
File pom = modelProcessor.locatePom(baseDirectory);
if (pom.isFile()) {
request.setPom(pom);
}
}
if ((request.getPom() != null) && (request.getPom().getParentFile() != null)) { if ((request.getPom() != null) && (request.getPom().getParentFile() != null)) {
request.setBaseDirectory(request.getPom().getParentFile()); request.setBaseDirectory(request.getPom().getParentFile());
} }
if (commandLine.hasOption(RESUME)) {
new DefaultBuildResumptionDataRepository()
.applyResumptionData(request, Paths.get(request.getBaseDirectory()).resolve("target"));
}
if (commandLine.hasOption(CLIManager.RESUME_FROM)) {
request.setResumeFrom(commandLine.getOptionValue(CLIManager.RESUME_FROM)); request.setResumeFrom(commandLine.getOptionValue(CLIManager.RESUME_FROM));
} enableOnPresentOption(commandLine, CLIManager.RESUME, request::setResume);
request.setMakeBehavior(determineMakeBehavior(commandLine));
if (commandLine.hasOption(CLIManager.PROJECT_LIST)) {
String[] projectOptionValues = commandLine.getOptionValues(CLIManager.PROJECT_LIST);
List<String> inclProjects = new ArrayList<>();
List<String> exclProjects = new ArrayList<>();
if (projectOptionValues != null) {
for (String projectOptionValue : projectOptionValues) {
StringTokenizer projectTokens = new StringTokenizer(projectOptionValue, ",");
while (projectTokens.hasMoreTokens()) {
String projectAction = projectTokens.nextToken().trim();
if (projectAction.startsWith("-") || projectAction.startsWith("!")) {
exclProjects.add(projectAction.substring(1));
} else if (projectAction.startsWith("+")) {
inclProjects.add(projectAction.substring(1));
} else {
inclProjects.add(projectAction);
}
}
}
}
request.setSelectedProjects(inclProjects);
request.setExcludedProjects(exclProjects);
}
if (commandLine.hasOption(CLIManager.ALSO_MAKE) && !commandLine.hasOption(
CLIManager.ALSO_MAKE_DEPENDENTS)) {
request.setMakeBehavior(MavenExecutionRequest.REACTOR_MAKE_UPSTREAM);
} else if (!commandLine.hasOption(CLIManager.ALSO_MAKE) && commandLine.hasOption(
CLIManager.ALSO_MAKE_DEPENDENTS)) {
request.setMakeBehavior(MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM);
} else if (commandLine.hasOption(CLIManager.ALSO_MAKE) && commandLine.hasOption(
CLIManager.ALSO_MAKE_DEPENDENTS)) {
request.setMakeBehavior(MavenExecutionRequest.REACTOR_MAKE_BOTH);
}
String localRepoProperty = request.getUserProperties().getProperty(MavenCli.LOCAL_REPO_PROPERTY);
if (localRepoProperty == null) {
localRepoProperty = request.getSystemProperties().getProperty(MavenCli.LOCAL_REPO_PROPERTY);
}
if (localRepoProperty != null) {
request.setLocalRepositoryPath(localRepoProperty);
}
request.setCacheNotFound(true); request.setCacheNotFound(true);
request.setCacheTransferError(false); request.setCacheTransferError(false);
performProjectActivation(commandLine, request.getProjectActivation());
performProfileActivation(commandLine, request.getProfileActivation());
final String localRepositoryPath = determineLocalRepositoryPath(request);
if (localRepositoryPath != null) {
request.setLocalRepositoryPath(localRepositoryPath);
}
// //
// Builder, concurrency and parallelism // Builder, concurrency and parallelism
// //
@@ -1224,34 +1047,233 @@ public class DaemonMavenCli {
// parameters but this is sufficient for now. Ultimately we want components like Builders to provide a way to // parameters but this is sufficient for now. Ultimately we want components like Builders to provide a way to
// extend the command line to accept its own configuration parameters. // extend the command line to accept its own configuration parameters.
// //
final String threadConfiguration = commandLine.hasOption(CLIManager.THREADS) final String threadConfiguration = commandLine.getOptionValue(CLIManager.THREADS);
? commandLine.getOptionValue(CLIManager.THREADS)
: null;
if (threadConfiguration != null) { if (threadConfiguration != null) {
// int degreeOfConcurrency = calculateDegreeOfConcurrency(threadConfiguration);
// Default to the standard multithreaded builder if (degreeOfConcurrency > 1) {
//
request.setBuilderId("multithreaded"); request.setBuilderId("multithreaded");
request.setDegreeOfConcurrency(degreeOfConcurrency);
if (threadConfiguration.contains("C")) {
request.setDegreeOfConcurrency(calculateDegreeOfConcurrencyWithCoreMultiplier(threadConfiguration));
} else {
request.setDegreeOfConcurrency(Integer.parseInt(threadConfiguration));
} }
} }
// //
// Allow the builder to be overridden by the user if requested. The builders are now pluggable. // Allow the builder to be overridden by the user if requested. The builders are now pluggable.
// //
if (commandLine.hasOption(CLIManager.BUILDER)) { request.setBuilderId(commandLine.getOptionValue(CLIManager.BUILDER, request.getBuilderId()));
request.setBuilderId(commandLine.getOptionValue(CLIManager.BUILDER)); }
private String determineLocalRepositoryPath(final MavenExecutionRequest request) {
String userDefinedLocalRepo = request.getUserProperties().getProperty(MavenCli.LOCAL_REPO_PROPERTY);
if (userDefinedLocalRepo != null) {
return userDefinedLocalRepo;
}
return request.getSystemProperties().getProperty(MavenCli.LOCAL_REPO_PROPERTY);
}
private File determinePom(ModelProcessor modelProcessor, final CommandLine commandLine, final String workingDirectory,
final File baseDirectory) {
String alternatePomFile = null;
if (commandLine.hasOption(CLIManager.ALTERNATE_POM_FILE)) {
alternatePomFile = commandLine.getOptionValue(CLIManager.ALTERNATE_POM_FILE);
}
if (alternatePomFile != null) {
File pom = resolveFile(new File(alternatePomFile), workingDirectory);
if (pom.isDirectory()) {
pom = new File(pom, "pom.xml");
}
return pom;
} else if (modelProcessor != null) {
File pom = modelProcessor.locatePom(baseDirectory);
if (pom.isFile()) {
return pom;
} }
} }
static int calculateDegreeOfConcurrencyWithCoreMultiplier(String threadConfiguration) { return null;
}
// Visible for testing
static void performProjectActivation(final CommandLine commandLine, final ProjectActivation projectActivation) {
if (commandLine.hasOption(CLIManager.PROJECT_LIST)) {
final String[] optionValues = commandLine.getOptionValues(CLIManager.PROJECT_LIST);
if (optionValues == null || optionValues.length == 0) {
return;
}
for (final String optionValue : optionValues) {
for (String token : optionValue.split(",")) {
String selector = token.trim();
boolean active = true;
if (selector.charAt(0) == '-' || selector.charAt(0) == '!') {
active = false;
selector = selector.substring(1);
} else if (token.charAt(0) == '+') {
selector = selector.substring(1);
}
boolean optional = selector.charAt(0) == '?';
selector = selector.substring(optional ? 1 : 0);
projectActivation.addProjectActivation(selector, active, optional);
}
}
}
}
// Visible for testing
static void performProfileActivation(final CommandLine commandLine, final ProfileActivation profileActivation) {
if (commandLine.hasOption(CLIManager.ACTIVATE_PROFILES)) {
final String[] optionValues = commandLine.getOptionValues(CLIManager.ACTIVATE_PROFILES);
if (optionValues == null || optionValues.length == 0) {
return;
}
for (final String optionValue : optionValues) {
for (String token : optionValue.split(",")) {
String profileId = token.trim();
boolean active = true;
if (profileId.charAt(0) == '-' || profileId.charAt(0) == '!') {
active = false;
profileId = profileId.substring(1);
} else if (token.charAt(0) == '+') {
profileId = profileId.substring(1);
}
boolean optional = profileId.charAt(0) == '?';
profileId = profileId.substring(optional ? 1 : 0);
profileActivation.addProfileActivation(profileId, active, optional);
}
}
}
}
private ExecutionListener determineExecutionListener(EventSpyDispatcher eventSpyDispatcher) {
ExecutionListener executionListener = new ExecutionEventLogger();
if (eventSpyDispatcher != null) {
return eventSpyDispatcher.chainListener(executionListener);
} else {
return executionListener;
}
}
private String determineReactorFailureBehaviour(final CommandLine commandLine) {
if (commandLine.hasOption(CLIManager.FAIL_FAST)) {
return MavenExecutionRequest.REACTOR_FAIL_FAST;
} else if (commandLine.hasOption(CLIManager.FAIL_AT_END)) {
return MavenExecutionRequest.REACTOR_FAIL_AT_END;
} else if (commandLine.hasOption(CLIManager.FAIL_NEVER)) {
return MavenExecutionRequest.REACTOR_FAIL_NEVER;
} else {
// this is the default behavior.
return MavenExecutionRequest.REACTOR_FAIL_FAST;
}
}
private String determineMakeBehavior(final CommandLine cl) {
if (cl.hasOption(CLIManager.ALSO_MAKE) && !cl.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
return MavenExecutionRequest.REACTOR_MAKE_UPSTREAM;
} else if (!cl.hasOption(CLIManager.ALSO_MAKE) && cl.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
return MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM;
} else if (cl.hasOption(CLIManager.ALSO_MAKE) && cl.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
return MavenExecutionRequest.REACTOR_MAKE_BOTH;
} else {
return null;
}
}
private String determineGlobalCheckPolicy(final CommandLine commandLine) {
if (commandLine.hasOption(CLIManager.CHECKSUM_FAILURE_POLICY)) {
return MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
} else if (commandLine.hasOption(CLIManager.CHECKSUM_WARNING_POLICY)) {
return MavenExecutionRequest.CHECKSUM_POLICY_WARN;
} else {
return null;
}
}
private void disableOnPresentOption(final CommandLine commandLine,
final String option,
final Consumer<Boolean> setting) {
if (commandLine.hasOption(option)) {
setting.accept(false);
}
}
private void disableOnPresentOption(final CommandLine commandLine,
final char option,
final Consumer<Boolean> setting) {
disableOnPresentOption(commandLine, String.valueOf(option), setting);
}
private void enableOnPresentOption(final CommandLine commandLine,
final String option,
final Consumer<Boolean> setting) {
if (commandLine.hasOption(option)) {
setting.accept(true);
}
}
private void enableOnPresentOption(final CommandLine commandLine,
final char option,
final Consumer<Boolean> setting) {
enableOnPresentOption(commandLine, String.valueOf(option), setting);
}
private void enableOnAbsentOption(final CommandLine commandLine,
final char option,
final Consumer<Boolean> setting) {
if (!commandLine.hasOption(option)) {
setting.accept(true);
}
}
int calculateDegreeOfConcurrency(String threadConfiguration) {
if (threadConfiguration.endsWith("C")) {
threadConfiguration = threadConfiguration.substring(0, threadConfiguration.length() - 1);
if (!NumberUtils.isParsable(threadConfiguration)) {
throw new IllegalArgumentException("Invalid threads core multiplier value: '" + threadConfiguration
+ "C'. Supported are int and float values ending with C.");
}
float coreMultiplier = Float.parseFloat(threadConfiguration);
if (coreMultiplier <= 0.0f) {
throw new IllegalArgumentException("Invalid threads core multiplier value: '" + threadConfiguration
+ "C'. Value must be positive.");
}
int procs = Runtime.getRuntime().availableProcessors(); int procs = Runtime.getRuntime().availableProcessors();
return (int) (Float.parseFloat(threadConfiguration.replace("C", "")) * procs); int threads = (int) (coreMultiplier * procs);
return threads == 0 ? 1 : threads;
} else {
if (!NumberUtils.isParsable(threadConfiguration)) {
throw new IllegalArgumentException("Invalid threads value: '" + threadConfiguration
+ "'. Supported are int values.");
}
try {
int threads = Integer.parseInt(threadConfiguration);
if (threads <= 0) {
throw new IllegalArgumentException("Invalid threads value: '" + threadConfiguration
+ "'. Value must be positive.");
}
return threads;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid threads value: '" + threadConfiguration
+ "'. Supported are integer values.");
}
}
} }
static File resolveFile(File file, String workingDirectory) { static File resolveFile(File file, String workingDirectory) {
@@ -1280,15 +1302,10 @@ public class DaemonMavenCli {
// are most dominant. // are most dominant.
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
if (commandLine.hasOption(CLIManager.SET_SYSTEM_PROPERTY)) { final Properties userSpecifiedProperties = commandLine.getOptionProperties(
String[] defStrs = commandLine.getOptionValues(CLIManager.SET_SYSTEM_PROPERTY); String.valueOf(CLIManager.SET_SYSTEM_PROPERTY));
userSpecifiedProperties.forEach(
if (defStrs != null) { (prop, value) -> setCliProperty((String) prop, (String) value, userProperties));
for (String defStr : defStrs) {
setCliProperty(defStr, userProperties);
}
}
}
SystemProperties.addSystemProperties(systemProperties); SystemProperties.addSystemProperties(systemProperties);
@@ -1316,23 +1333,7 @@ public class DaemonMavenCli {
} }
} }
private static void setCliProperty(String property, Properties properties) { private static void setCliProperty(String name, String value, Properties properties) {
String name;
String value;
int i = property.indexOf('=');
if (i <= 0) {
name = property.trim();
value = "true";
} else {
name = property.substring(0, i).trim();
value = property.substring(i + 1);
}
properties.setProperty(name, value); properties.setProperty(name, value);
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------

View File

@@ -31,6 +31,7 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -41,6 +42,7 @@ import org.apache.maven.artifact.InvalidRepositoryException;
import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.LegacyLocalRepositoryManager; import org.apache.maven.artifact.repository.LegacyLocalRepositoryManager;
import org.apache.maven.bridge.MavenRepositorySystem; import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.feature.Features;
import org.apache.maven.model.Build; import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency; import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement; import org.apache.maven.model.DependencyManagement;
@@ -50,6 +52,7 @@ import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin; import org.apache.maven.model.Plugin;
import org.apache.maven.model.Profile; import org.apache.maven.model.Profile;
import org.apache.maven.model.ReportPlugin; import org.apache.maven.model.ReportPlugin;
import org.apache.maven.model.building.ArtifactModelSource;
import org.apache.maven.model.building.DefaultModelBuildingRequest; import org.apache.maven.model.building.DefaultModelBuildingRequest;
import org.apache.maven.model.building.DefaultModelProblem; import org.apache.maven.model.building.DefaultModelProblem;
import org.apache.maven.model.building.FileModelSource; import org.apache.maven.model.building.FileModelSource;
@@ -62,11 +65,15 @@ import org.apache.maven.model.building.ModelProblem;
import org.apache.maven.model.building.ModelProcessor; import org.apache.maven.model.building.ModelProcessor;
import org.apache.maven.model.building.ModelSource; import org.apache.maven.model.building.ModelSource;
import org.apache.maven.model.building.StringModelSource; import org.apache.maven.model.building.StringModelSource;
import org.apache.maven.model.building.TransformerContext;
import org.apache.maven.model.building.TransformerContextBuilder;
import org.apache.maven.model.resolution.ModelResolver; import org.apache.maven.model.resolution.ModelResolver;
import org.apache.maven.repository.internal.ArtifactDescriptorUtils; import org.apache.maven.repository.internal.ArtifactDescriptorUtils;
import org.apache.maven.repository.internal.DefaultModelCache;
import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.Os; import org.codehaus.plexus.util.Os;
import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.StringUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.RequestTrace; import org.eclipse.aether.RequestTrace;
import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.impl.RemoteRepositoryManager;
@@ -76,17 +83,12 @@ import org.eclipse.aether.repository.WorkspaceRepository;
import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResult; import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.sisu.Priority; import org.eclipse.sisu.Priority;
import org.eclipse.sisu.Typed;
/** /**
* DefaultProjectBuilder * CachingProjectBuilder
*
* File origin:
* https://github.com/apache/maven/blob/maven-3.6.2/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
*/ */
@Named @Named
@Singleton @Singleton
@Typed(ProjectBuilder.class)
@Priority(10) @Priority(10)
public class CachingProjectBuilder public class CachingProjectBuilder
implements ProjectBuilder { implements ProjectBuilder {
@@ -115,10 +117,7 @@ public class CachingProjectBuilder
@Inject @Inject
private ProjectDependenciesResolver dependencyResolver; private ProjectDependenciesResolver dependencyResolver;
private final ModelCache modelCache = new ReactorModelCache(); private final ModelCache modelCache = DefaultModelCache.newInstance(new DefaultRepositorySystemSession());
public CachingProjectBuilder() {
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// MavenProjectBuilder Implementation // MavenProjectBuilder Implementation
@@ -128,14 +127,14 @@ public class CachingProjectBuilder
public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest request) public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest request)
throws ProjectBuildingException { throws ProjectBuildingException {
return build(pomFile, new FileModelSource(pomFile), return build(pomFile, new FileModelSource(pomFile),
new InternalConfig(request, null, new SnapshotModelCache(getModelCache()))); new InternalConfig(request, null, null));
} }
@Override @Override
public ProjectBuildingResult build(ModelSource modelSource, ProjectBuildingRequest request) public ProjectBuildingResult build(ModelSource modelSource, ProjectBuildingRequest request)
throws ProjectBuildingException { throws ProjectBuildingException {
return build(null, modelSource, return build(null, modelSource,
new InternalConfig(request, null, new SnapshotModelCache(getModelCache()))); new InternalConfig(request, null, null));
} }
private ProjectBuildingResult build(File pomFile, ModelSource modelSource, InternalConfig config) private ProjectBuildingResult build(File pomFile, ModelSource modelSource, InternalConfig config)
@@ -170,8 +169,7 @@ public class CachingProjectBuilder
} catch (ModelBuildingException e) { } catch (ModelBuildingException e) {
result = e.getResult(); result = e.getResult();
if (result == null || result.getEffectiveModel() == null) { if (result == null || result.getEffectiveModel() == null) {
throw (ProjectBuildingException) new ProjectBuildingException(e.getModelId(), e.getMessage(), pomFile) throw new ProjectBuildingException(e.getModelId(), e.getMessage(), pomFile, e);
.initCause(e);
} }
// validation error, continue project building and delay failing to help IDEs // validation error, continue project building and delay failing to help IDEs
error = e; error = e;
@@ -179,8 +177,8 @@ public class CachingProjectBuilder
modelProblems = result.getProblems(); modelProblems = result.getProblems();
initProject(project, Collections.<String, MavenProject> emptyMap(), true, initProject(project, Collections.emptyMap(), true,
result, new HashMap<File, Boolean>(), projectBuildingRequest); result, new HashMap<>(), projectBuildingRequest);
} else if (projectBuildingRequest.isResolveDependencies()) { } else if (projectBuildingRequest.isResolveDependencies()) {
projectBuildingHelper.selectProjectRealm(project); projectBuildingHelper.selectProjectRealm(project);
} }
@@ -235,13 +233,7 @@ public class CachingProjectBuilder
} }
private List<String> getProfileIds(List<Profile> profiles) { private List<String> getProfileIds(List<Profile> profiles) {
List<String> ids = new ArrayList<>(profiles.size()); return profiles.stream().map(Profile::getId).collect(Collectors.toList());
for (Profile profile : profiles) {
ids.add(profile.getId());
}
return ids;
} }
private ModelBuildingRequest getModelBuildingRequest(InternalConfig config) { private ModelBuildingRequest getModelBuildingRequest(InternalConfig config) {
@@ -264,7 +256,11 @@ public class CachingProjectBuilder
request.setUserProperties(configuration.getUserProperties()); request.setUserProperties(configuration.getUserProperties());
request.setBuildStartTime(configuration.getBuildStartTime()); request.setBuildStartTime(configuration.getBuildStartTime());
request.setModelResolver(resolver); request.setModelResolver(resolver);
request.setModelCache(config.modelCache); // this is a hint that we want to build 1 file, so don't cache. See MNG-7063
if (config.modelPool != null) {
request.setModelCache(new SnapshotModelCache(modelCache, DefaultModelCache.newInstance(config.session)));
}
request.setTransformerContextBuilder(config.transformerContextBuilder);
return request; return request;
} }
@@ -281,7 +277,7 @@ public class CachingProjectBuilder
org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact(artifact); org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact(artifact);
pomArtifact = ArtifactDescriptorUtils.toPomArtifact(pomArtifact); pomArtifact = ArtifactDescriptorUtils.toPomArtifact(pomArtifact);
InternalConfig config = new InternalConfig(request, null, new SnapshotModelCache(getModelCache())); InternalConfig config = new InternalConfig(request, null, null);
boolean localProject; boolean localProject;
@@ -309,7 +305,13 @@ public class CachingProjectBuilder
artifact.setResolved(true); artifact.setResolved(true);
} }
return build(localProject ? pomFile : null, new FileModelSource(pomFile), config); if (localProject) {
return build(pomFile, new FileModelSource(pomFile), config);
} else {
return build(null, new ArtifactModelSource(pomFile, artifact.getGroupId(), artifact.getArtifactId(),
artifact.getVersion()),
config);
}
} }
private ModelSource createStubModelSource(Artifact artifact) { private ModelSource createStubModelSource(Artifact artifact) {
@@ -334,26 +336,32 @@ public class CachingProjectBuilder
List<InterimResult> interimResults = new ArrayList<>(); List<InterimResult> interimResults = new ArrayList<>();
ReactorModelPool modelPool = new ReactorModelPool(); ReactorModelPool.Builder poolBuilder = new ReactorModelPool.Builder();
final ReactorModelPool modelPool = poolBuilder.build();
InternalConfig config = new InternalConfig(request, modelPool, new SnapshotModelCache(getModelCache())); InternalConfig config = new InternalConfig(request, modelPool, modelBuilder.newTransformerContextBuilder());
Map<String, MavenProject> projectIndex = new HashMap<>(256); Map<File, MavenProject> projectIndex = new HashMap<>(256);
boolean noErrors = build(results, interimResults, projectIndex, pomFiles, new LinkedHashSet<File>(), true, recursive, // phase 1: get file Models from the reactor.
config); boolean noErrors = build(results, interimResults, projectIndex, pomFiles, new LinkedHashSet<>(), true, recursive,
config, poolBuilder);
populateReactorModelPool(modelPool, interimResults);
ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader(); ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
try { try {
noErrors = build(results, new ArrayList<MavenProject>(), projectIndex, interimResults, request, // Phase 2: get effective models from the reactor
new HashMap<File, Boolean>(), config.session) && noErrors; noErrors = build(results, new ArrayList<>(), projectIndex, interimResults, request,
new HashMap<>(), config.session) && noErrors;
} finally { } finally {
Thread.currentThread().setContextClassLoader(oldContextClassLoader); Thread.currentThread().setContextClassLoader(oldContextClassLoader);
} }
if (Features.buildConsumer(request.getUserProperties()).isActive()) {
request.getRepositorySession().getData().set(TransformerContext.KEY,
config.transformerContextBuilder.build());
}
if (!noErrors) { if (!noErrors) {
throw new ProjectBuildingException(results); throw new ProjectBuildingException(results);
} }
@@ -363,14 +371,16 @@ public class CachingProjectBuilder
@SuppressWarnings("checkstyle:parameternumber") @SuppressWarnings("checkstyle:parameternumber")
private boolean build(List<ProjectBuildingResult> results, List<InterimResult> interimResults, private boolean build(List<ProjectBuildingResult> results, List<InterimResult> interimResults,
Map<String, MavenProject> projectIndex, List<File> pomFiles, Set<File> aggregatorFiles, Map<File, MavenProject> projectIndex, List<File> pomFiles, Set<File> aggregatorFiles,
boolean isRoot, boolean recursive, InternalConfig config) { boolean root, boolean recursive, InternalConfig config,
ReactorModelPool.Builder poolBuilder) {
boolean noErrors = true; boolean noErrors = true;
for (File pomFile : pomFiles) { for (File pomFile : pomFiles) {
aggregatorFiles.add(pomFile); aggregatorFiles.add(pomFile);
if (!build(results, interimResults, projectIndex, pomFile, aggregatorFiles, isRoot, recursive, config)) { if (!build(results, interimResults, projectIndex, pomFile, aggregatorFiles, root, recursive, config,
poolBuilder)) {
noErrors = false; noErrors = false;
} }
@@ -382,18 +392,18 @@ public class CachingProjectBuilder
@SuppressWarnings("checkstyle:parameternumber") @SuppressWarnings("checkstyle:parameternumber")
private boolean build(List<ProjectBuildingResult> results, List<InterimResult> interimResults, private boolean build(List<ProjectBuildingResult> results, List<InterimResult> interimResults,
Map<String, MavenProject> projectIndex, File pomFile, Set<File> aggregatorFiles, Map<File, MavenProject> projectIndex, File pomFile, Set<File> aggregatorFiles,
boolean isRoot, boolean recursive, InternalConfig config) { boolean isRoot, boolean recursive, InternalConfig config,
ReactorModelPool.Builder poolBuilder) {
boolean noErrors = true; boolean noErrors = true;
ModelBuildingRequest request = getModelBuildingRequest(config);
MavenProject project = new MavenProject(); MavenProject project = new MavenProject();
project.setFile(pomFile); project.setFile(pomFile);
request.setPomFile(pomFile); ModelBuildingRequest request = getModelBuildingRequest(config)
request.setTwoPhaseBuilding(true); .setPomFile(pomFile)
request.setLocationTracking(true); .setTwoPhaseBuilding(true)
.setLocationTracking(true);
DefaultModelBuildingListener listener = new DefaultModelBuildingListener(project, projectBuildingHelper, DefaultModelBuildingListener listener = new DefaultModelBuildingListener(project, projectBuildingHelper,
config.request); config.request);
@@ -404,7 +414,7 @@ public class CachingProjectBuilder
result = modelBuilder.build(request); result = modelBuilder.build(request);
} catch (ModelBuildingException e) { } catch (ModelBuildingException e) {
result = e.getResult(); result = e.getResult();
if (result == null || result.getEffectiveModel() == null) { if (result == null || result.getFileModel() == null) {
results.add(new DefaultProjectBuildingResult(e.getModelId(), pomFile, e.getProblems())); results.add(new DefaultProjectBuildingResult(e.getModelId(), pomFile, e.getProblems()));
return false; return false;
@@ -414,25 +424,16 @@ public class CachingProjectBuilder
noErrors = false; noErrors = false;
} }
Model model = result.getEffectiveModel(); Model model = result.getFileModel().clone();
try {
// first pass: build without building parent.
initProject(project, projectIndex, false, result, new HashMap<File, Boolean>(0), config.request);
} catch (InvalidArtifactRTException iarte) {
result.getProblems().add(new DefaultModelProblem(null, ModelProblem.Severity.ERROR, null, model, -1, -1,
iarte));
}
projectIndex.put(result.getModelIds().get(0), project); poolBuilder.put(model.getPomFile().toPath(), model);
InterimResult interimResult = new InterimResult(pomFile, request, result, listener, isRoot); InterimResult interimResult = new InterimResult(pomFile, request, result, listener, isRoot);
interimResults.add(interimResult); interimResults.add(interimResult);
if (recursive && !model.getModules().isEmpty()) { if (recursive) {
File basedir = pomFile.getParentFile(); File basedir = pomFile.getParentFile();
List<File> moduleFiles = new ArrayList<>(); List<File> moduleFiles = new ArrayList<>();
for (String module : model.getModules()) { for (String module : model.getModules()) {
if (StringUtils.isEmpty(module)) { if (StringUtils.isEmpty(module)) {
continue; continue;
@@ -491,11 +492,13 @@ public class CachingProjectBuilder
interimResult.modules = new ArrayList<>(); interimResult.modules = new ArrayList<>();
if (!build(results, interimResult.modules, projectIndex, moduleFiles, aggregatorFiles, false, if (!build(results, interimResult.modules, projectIndex, moduleFiles, aggregatorFiles, false,
recursive, config)) { recursive, config, poolBuilder)) {
noErrors = false; noErrors = false;
} }
} }
projectIndex.put(pomFile, project);
return noErrors; return noErrors;
} }
@@ -524,17 +527,8 @@ public class CachingProjectBuilder
} }
private void populateReactorModelPool(ReactorModelPool reactorModelPool, List<InterimResult> interimResults) {
for (InterimResult interimResult : interimResults) {
Model model = interimResult.result.getEffectiveModel();
reactorModelPool.put(model.getGroupId(), model.getArtifactId(), model.getVersion(), model.getPomFile());
populateReactorModelPool(reactorModelPool, interimResult.modules);
}
}
private boolean build(List<ProjectBuildingResult> results, List<MavenProject> projects, private boolean build(List<ProjectBuildingResult> results, List<MavenProject> projects,
Map<String, MavenProject> projectIndex, List<InterimResult> interimResults, Map<File, MavenProject> projectIndex, List<InterimResult> interimResults,
ProjectBuildingRequest request, Map<File, Boolean> profilesXmls, ProjectBuildingRequest request, Map<File, Boolean> profilesXmls,
RepositorySystemSession session) { RepositorySystemSession session) {
boolean noErrors = true; boolean noErrors = true;
@@ -569,9 +563,11 @@ public class CachingProjectBuilder
results.add(new DefaultProjectBuildingResult(project, result.getProblems(), resolutionResult)); results.add(new DefaultProjectBuildingResult(project, result.getProblems(), resolutionResult));
} catch (ModelBuildingException e) { } catch (ModelBuildingException e) {
DefaultProjectBuildingResult result = null; DefaultProjectBuildingResult result = null;
if (project == null) { if (project == null || interimResult.result.getEffectiveModel() == null) {
result = new DefaultProjectBuildingResult(e.getModelId(), interimResult.pomFile, e.getProblems()); result = new DefaultProjectBuildingResult(e.getModelId(), interimResult.pomFile, e.getProblems());
} else { } else {
project.setModel(interimResult.result.getEffectiveModel());
result = new DefaultProjectBuildingResult(project, e.getProblems(), null); result = new DefaultProjectBuildingResult(project, e.getProblems(), null);
} }
results.add(result); results.add(result);
@@ -584,14 +580,13 @@ public class CachingProjectBuilder
} }
@SuppressWarnings("checkstyle:methodlength") @SuppressWarnings("checkstyle:methodlength")
private void initProject(MavenProject project, Map<String, MavenProject> projects, private void initProject(MavenProject project, Map<File, MavenProject> projects,
boolean buildParentIfNotExisting, ModelBuildingResult result, boolean buildParentIfNotExisting, ModelBuildingResult result,
Map<File, Boolean> profilesXmls, ProjectBuildingRequest projectBuildingRequest) { Map<File, Boolean> profilesXmls, ProjectBuildingRequest projectBuildingRequest) {
Model model = result.getEffectiveModel(); Model model = result.getEffectiveModel();
project.setModel(model); project.setModel(model);
project.setOriginalModel(result.getRawModel()); project.setOriginalModel(result.getFileModel());
project.setFile(model.getPomFile());
initParent(project, projects, buildParentIfNotExisting, result, projectBuildingRequest); initParent(project, projects, buildParentIfNotExisting, result, projectBuildingRequest);
@@ -618,14 +613,6 @@ public class CachingProjectBuilder
project.setInjectedProfileIds(modelId, getProfileIds(result.getActivePomProfiles(modelId))); project.setInjectedProfileIds(modelId, getProfileIds(result.getActivePomProfiles(modelId)));
} }
String modelId = findProfilesXml(result, profilesXmls);
if (modelId != null) {
ModelProblem problem = new DefaultModelProblem("Detected profiles.xml alongside " + modelId
+ ", this file is no longer supported and was ignored" + ", please use the settings.xml instead",
ModelProblem.Severity.WARNING, ModelProblem.Version.V30, model, -1, -1, null);
result.getProblems().add(problem);
}
// //
// All the parts that were taken out of MavenProject for Maven 4.0.0 // All the parts that were taken out of MavenProject for Maven 4.0.0
// //
@@ -747,7 +734,7 @@ public class CachingProjectBuilder
try { try {
DeploymentRepository r = project.getDistributionManagement().getRepository(); DeploymentRepository r = project.getDistributionManagement().getRepository();
if (!StringUtils.isEmpty(r.getId()) && !StringUtils.isEmpty(r.getUrl())) { if (!StringUtils.isEmpty(r.getId()) && !StringUtils.isEmpty(r.getUrl())) {
ArtifactRepository repo = repositorySystem.buildArtifactRepository(r); ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(r);
repositorySystem.injectProxy(projectBuildingRequest.getRepositorySession(), repositorySystem.injectProxy(projectBuildingRequest.getRepositorySession(),
Arrays.asList(repo)); Arrays.asList(repo));
repositorySystem.injectAuthentication(projectBuildingRequest.getRepositorySession(), repositorySystem.injectAuthentication(projectBuildingRequest.getRepositorySession(),
@@ -766,7 +753,7 @@ public class CachingProjectBuilder
try { try {
DeploymentRepository r = project.getDistributionManagement().getSnapshotRepository(); DeploymentRepository r = project.getDistributionManagement().getSnapshotRepository();
if (!StringUtils.isEmpty(r.getId()) && !StringUtils.isEmpty(r.getUrl())) { if (!StringUtils.isEmpty(r.getId()) && !StringUtils.isEmpty(r.getUrl())) {
ArtifactRepository repo = repositorySystem.buildArtifactRepository(r); ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(r);
repositorySystem.injectProxy(projectBuildingRequest.getRepositorySession(), repositorySystem.injectProxy(projectBuildingRequest.getRepositorySession(),
Arrays.asList(repo)); Arrays.asList(repo));
repositorySystem.injectAuthentication(projectBuildingRequest.getRepositorySession(), repositorySystem.injectAuthentication(projectBuildingRequest.getRepositorySession(),
@@ -780,7 +767,7 @@ public class CachingProjectBuilder
} }
} }
private void initParent(MavenProject project, Map<String, MavenProject> projects, boolean buildParentIfNotExisting, private void initParent(MavenProject project, Map<File, MavenProject> projects, boolean buildParentIfNotExisting,
ModelBuildingResult result, ProjectBuildingRequest projectBuildingRequest) { ModelBuildingResult result, ProjectBuildingRequest projectBuildingRequest) {
Model parentModel = result.getModelIds().size() > 1 && !result.getModelIds().get(1).isEmpty() Model parentModel = result.getModelIds().size() > 1 && !result.getModelIds().get(1).isEmpty()
? result.getRawModel(result.getModelIds().get(1)) ? result.getRawModel(result.getModelIds().get(1))
@@ -797,7 +784,7 @@ public class CachingProjectBuilder
// org.apache.maven.its.mng4834:parent:0.1 // org.apache.maven.its.mng4834:parent:0.1
String parentModelId = result.getModelIds().get(1); String parentModelId = result.getModelIds().get(1);
File parentPomFile = result.getRawModel(parentModelId).getPomFile(); File parentPomFile = result.getRawModel(parentModelId).getPomFile();
MavenProject parent = projects.get(parentModelId); MavenProject parent = projects.get(parentPomFile);
if (parent == null && buildParentIfNotExisting) { if (parent == null && buildParentIfNotExisting) {
// //
// At this point the DefaultModelBuildingListener has fired and it populates the // At this point the DefaultModelBuildingListener has fired and it populates the
@@ -872,28 +859,6 @@ public class CachingProjectBuilder
return version; return version;
} }
private String findProfilesXml(ModelBuildingResult result, Map<File, Boolean> profilesXmls) {
for (String modelId : result.getModelIds()) {
Model model = result.getRawModel(modelId);
File basedir = model.getProjectDirectory();
if (basedir == null) {
break;
}
Boolean profilesXml = profilesXmls.get(basedir);
if (profilesXml == null) {
profilesXml = new File(basedir, "profiles.xml").exists();
profilesXmls.put(basedir, profilesXml);
}
if (profilesXml) {
return modelId;
}
}
return null;
}
/** /**
* InternalConfig * InternalConfig
*/ */
@@ -907,21 +872,20 @@ public class CachingProjectBuilder
private final ReactorModelPool modelPool; private final ReactorModelPool modelPool;
private final ModelCache modelCache; private final TransformerContextBuilder transformerContextBuilder;
InternalConfig(ProjectBuildingRequest request, ReactorModelPool modelPool, ModelCache modelCache) { InternalConfig(ProjectBuildingRequest request, ReactorModelPool modelPool,
TransformerContextBuilder transformerContextBuilder) {
this.request = request; this.request = request;
this.modelPool = modelPool; this.modelPool = modelPool;
this.modelCache = modelCache; this.transformerContextBuilder = transformerContextBuilder;
session = LegacyLocalRepositoryManager.overlay(request.getLocalRepository(), request.getRepositorySession(), session = LegacyLocalRepositoryManager.overlay(request.getLocalRepository(), request.getRepositorySession(),
repoSystem); repoSystem);
repositories = RepositoryUtils.toRepos(request.getRemoteRepositories()); repositories = RepositoryUtils.toRepos(request.getRemoteRepositories());
} }
} }
private ModelCache getModelCache() {
return this.modelCache;
}
} }

View File

@@ -22,9 +22,9 @@ public class SnapshotModelCache implements ModelCache {
private final ModelCache globalCache; private final ModelCache globalCache;
private final ModelCache reactorCache; private final ModelCache reactorCache;
public SnapshotModelCache(ModelCache globalCache) { public SnapshotModelCache(ModelCache globalCache, ModelCache reactorCache) {
this.globalCache = globalCache; this.globalCache = globalCache;
this.reactorCache = new ReactorModelCache(); this.reactorCache = reactorCache;
} }
@Override @Override

View File

@@ -1,52 +0,0 @@
/*
* Copyright 2019 the original author or authors.
*
* 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.
*/
package org.mvndaemon.mvnd.execution;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.util.Optional;
import org.apache.maven.execution.MavenExecutionResult;
/**
* Instances of this class are responsible for determining whether it makes sense to "resume" a build (i.e., using
* the {@code --resume} flag.
*/
public interface BuildResumptionAnalyzer {
/**
* Construct an instance of {@link BuildResumptionData} based on the outcome of the current Maven build.
*
* @param result Outcome of the current Maven build.
* @return A {@link BuildResumptionData} instance or {@link Optional#empty()} if resuming the build is not
* possible.
*/
Optional<BuildResumptionData> determineBuildResumptionData(final MavenExecutionResult result);
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright 2019 the original author or authors.
*
* 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.
*/
package org.mvndaemon.mvnd.execution;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.util.List;
/**
* This class holds the information required to enable resuming a Maven build with {@code --resume}.
*/
public class BuildResumptionData {
/**
* The list of projects that remain to be built.
*/
private final List<String> remainingProjects;
public BuildResumptionData(final List<String> remainingProjects) {
this.remainingProjects = remainingProjects;
}
/**
* Returns the projects that still need to be built when resuming.
*
* @return A list containing the group and artifact id of the projects.
*/
public List<String> getRemainingProjects() {
return this.remainingProjects;
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright 2019 the original author or authors.
*
* 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.
*/
package org.mvndaemon.mvnd.execution;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.project.MavenProject;
/**
* Instances of this interface retrieve and store data for the --resume / -r feature. This data is used to ensure newer
* builds of the same project, that have the -r command-line flag, skip successfully built projects during earlier
* invocations of Maven.
*/
public interface BuildResumptionDataRepository {
/**
* Persists any data needed to resume the build at a later point in time, using a new Maven invocation. This method
* may also decide it is not needed or meaningful to persist such data, and return <code>false</code> to indicate
* so.
*
* @param rootProject The root project that is being built.
* @param buildResumptionData Information needed to resume the build.
* @throws BuildResumptionPersistenceException When an error occurs while persisting data.
*/
void persistResumptionData(final MavenProject rootProject, final BuildResumptionData buildResumptionData)
throws BuildResumptionPersistenceException;
/**
* Uses previously stored resumption data to enrich an existing execution request.
*
* @param request The execution request that will be enriched.
* @param rootProject The root project that is being built.
*/
void applyResumptionData(final MavenExecutionRequest request, final MavenProject rootProject);
/**
* Removes previously stored resumption data.
*
* @param rootProject The root project that is being built.
*/
void removeResumptionData(final MavenProject rootProject);
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright 2019 the original author or authors.
*
* 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.
*/
package org.mvndaemon.mvnd.execution;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
/**
* This exception will be thrown when something fails while persisting build resumption data.
*
* @see BuildResumptionDataRepository#persistResumptionData
*/
public class BuildResumptionPersistenceException extends Exception {
public BuildResumptionPersistenceException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright 2019 the original author or authors.
*
* 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.
*/
package org.mvndaemon.mvnd.execution;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.maven.execution.BuildFailure;
import org.apache.maven.execution.BuildSuccess;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Default implementation of {@link BuildResumptionAnalyzer}.
*/
@Named
@Singleton
public class DefaultBuildResumptionAnalyzer implements BuildResumptionAnalyzer {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultBuildResumptionAnalyzer.class);
@Override
public Optional<BuildResumptionData> determineBuildResumptionData(final MavenExecutionResult result) {
if (!result.hasExceptions()) {
return Optional.empty();
}
List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
boolean hasNoSuccess = sortedProjects.stream()
.noneMatch(project -> result.getBuildSummary(project) instanceof BuildSuccess);
if (hasNoSuccess) {
return Optional.empty();
}
List<String> remainingProjects = sortedProjects.stream()
.filter(project -> result.getBuildSummary(project) == null
|| result.getBuildSummary(project) instanceof BuildFailure)
.map(project -> project.getGroupId() + ":" + project.getArtifactId())
.collect(Collectors.toList());
if (remainingProjects.isEmpty()) {
LOGGER.info("No remaining projects found, resuming the build would not make sense.");
return Optional.empty();
}
return Optional.of(new BuildResumptionData(remainingProjects));
}
}

View File

@@ -1,150 +0,0 @@
/*
* Copyright 2019 the original author or authors.
*
* 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.
*/
package org.mvndaemon.mvnd.execution;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.stream.Stream;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This implementation of {@link BuildResumptionDataRepository} persists information in a properties file. The file is
* stored in the build output directory under the Maven execution root.
*/
@Named
@Singleton
public class DefaultBuildResumptionDataRepository implements BuildResumptionDataRepository {
private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
private static final String REMAINING_PROJECTS = "remainingProjects";
private static final String PROPERTY_DELIMITER = ", ";
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultBuildResumptionDataRepository.class);
@Override
public void persistResumptionData(MavenProject rootProject, BuildResumptionData buildResumptionData)
throws BuildResumptionPersistenceException {
Path directory = Paths.get(rootProject.getBuild().getDirectory());
persistResumptionData(directory, buildResumptionData);
}
public void persistResumptionData(Path directory, BuildResumptionData buildResumptionData)
throws BuildResumptionPersistenceException {
Properties properties = convertToProperties(buildResumptionData);
Path resumeProperties = directory.resolve(RESUME_PROPERTIES_FILENAME);
try {
Files.createDirectories(resumeProperties.getParent());
try (Writer writer = Files.newBufferedWriter(resumeProperties)) {
properties.store(writer, null);
}
} catch (IOException e) {
String message = "Could not create " + RESUME_PROPERTIES_FILENAME + " file.";
throw new BuildResumptionPersistenceException(message, e);
}
}
private Properties convertToProperties(final BuildResumptionData buildResumptionData) {
Properties properties = new Properties();
String value = String.join(PROPERTY_DELIMITER, buildResumptionData.getRemainingProjects());
properties.setProperty(REMAINING_PROJECTS, value);
return properties;
}
@Override
public void applyResumptionData(MavenExecutionRequest request, MavenProject rootProject) {
Path directory = Paths.get(rootProject.getBuild().getDirectory());
applyResumptionData(request, directory);
}
public void applyResumptionData(MavenExecutionRequest request, Path directory) {
Properties properties = loadResumptionFile(directory);
applyResumptionProperties(request, properties);
}
@Override
public void removeResumptionData(MavenProject rootProject) {
Path directory = Paths.get(rootProject.getBuild().getDirectory());
removeResumptionData(directory);
}
public void removeResumptionData(Path directory) {
Path resumeProperties = directory.resolve(RESUME_PROPERTIES_FILENAME);
try {
Files.deleteIfExists(resumeProperties);
} catch (IOException e) {
LOGGER.warn("Could not delete {} file. ", RESUME_PROPERTIES_FILENAME, e);
}
}
private Properties loadResumptionFile(Path rootBuildDirectory) {
Properties properties = new Properties();
Path path = rootBuildDirectory.resolve(RESUME_PROPERTIES_FILENAME);
if (!Files.exists(path)) {
LOGGER.warn("The {} file does not exist. The --resume / -r feature will not work.", path);
return properties;
}
try (Reader reader = Files.newBufferedReader(path)) {
properties.load(reader);
} catch (IOException e) {
LOGGER.warn("Unable to read {}. The --resume / -r feature will not work.", path);
}
return properties;
}
// This method is made package-private for testing purposes
void applyResumptionProperties(MavenExecutionRequest request, Properties properties) {
if (properties.containsKey(REMAINING_PROJECTS)
&& StringUtils.isEmpty(request.getResumeFrom())) {
String propertyValue = properties.getProperty(REMAINING_PROJECTS);
Stream.of(propertyValue.split(PROPERTY_DELIMITER))
.filter(StringUtils::isNotEmpty)
.forEach(request.getSelectedProjects()::add);
LOGGER.info("Resuming from {} due to the --resume / -r feature.", propertyValue);
}
}
}

View File

@@ -19,15 +19,20 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.apache.maven.artifact.repository.metadata.io.MetadataReader;
import org.apache.maven.plugin.MavenPluginManager;
import org.apache.maven.plugin.version.PluginVersionRequest; import org.apache.maven.plugin.version.PluginVersionRequest;
import org.apache.maven.plugin.version.PluginVersionResolutionException; import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.plugin.version.PluginVersionResolver; import org.apache.maven.plugin.version.PluginVersionResolver;
import org.apache.maven.plugin.version.PluginVersionResult; import org.apache.maven.plugin.version.PluginVersionResult;
import org.apache.maven.plugin.version.internal.DefaultPluginVersionResolver; import org.apache.maven.plugin.version.internal.DefaultPluginVersionResolver;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.SessionData; import org.eclipse.aether.SessionData;
import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.version.VersionScheme;
import org.eclipse.sisu.Priority; import org.eclipse.sisu.Priority;
import org.eclipse.sisu.Typed; import org.eclipse.sisu.Typed;
@@ -39,6 +44,12 @@ public class CachingPluginVersionResolver extends DefaultPluginVersionResolver {
private static final Object CACHE_KEY = new Object(); private static final Object CACHE_KEY = new Object();
@Inject
public CachingPluginVersionResolver(RepositorySystem repositorySystem, MetadataReader metadataReader,
MavenPluginManager pluginManager, VersionScheme versionScheme) {
super(repositorySystem, metadataReader, pluginManager, versionScheme);
}
@Override @Override
public PluginVersionResult resolve(PluginVersionRequest request) throws PluginVersionResolutionException { public PluginVersionResult resolve(PluginVersionRequest request) throws PluginVersionResolutionException {
Map<String, PluginVersionResult> cache = getCache(request.getRepositorySession().getData()); Map<String, PluginVersionResult> cache = getCache(request.getRepositorySession().getData());

View File

@@ -47,13 +47,11 @@ import org.apache.maven.classrealm.ClassRealmManager;
import org.apache.maven.execution.MavenSession; import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule; import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
import org.apache.maven.model.Plugin; import org.apache.maven.model.Plugin;
import org.apache.maven.monitor.logging.DefaultLog;
import org.apache.maven.plugin.ContextEnabled; import org.apache.maven.plugin.ContextEnabled;
import org.apache.maven.plugin.DebugConfigurationListener; import org.apache.maven.plugin.DebugConfigurationListener;
import org.apache.maven.plugin.ExtensionRealmCache; import org.apache.maven.plugin.ExtensionRealmCache;
import org.apache.maven.plugin.InvalidPluginDescriptorException; import org.apache.maven.plugin.InvalidPluginDescriptorException;
import org.apache.maven.plugin.MavenPluginManager; import org.apache.maven.plugin.MavenPluginManager;
import org.apache.maven.plugin.MavenPluginValidator;
import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.Mojo;
import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoNotFoundException; import org.apache.maven.plugin.MojoNotFoundException;
@@ -72,6 +70,7 @@ import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.Parameter; import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.plugin.internal.MojoLogWrapper;
import org.apache.maven.plugin.internal.PluginDependenciesResolver; import org.apache.maven.plugin.internal.PluginDependenciesResolver;
import org.apache.maven.plugin.version.DefaultPluginVersionRequest; import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
import org.apache.maven.plugin.version.PluginVersionRequest; import org.apache.maven.plugin.version.PluginVersionRequest;
@@ -97,7 +96,6 @@ import org.codehaus.plexus.component.repository.exception.ComponentLookupExcepti
import org.codehaus.plexus.configuration.PlexusConfiguration; import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.configuration.PlexusConfigurationException; import org.codehaus.plexus.configuration.PlexusConfigurationException;
import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.logging.LoggerManager; import org.codehaus.plexus.logging.LoggerManager;
import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.StringUtils;
@@ -112,6 +110,8 @@ import org.eclipse.sisu.Priority;
import org.eclipse.sisu.Typed; import org.eclipse.sisu.Typed;
import org.mvndaemon.mvnd.cache.invalidating.InvalidatingPluginDescriptorCache; import org.mvndaemon.mvnd.cache.invalidating.InvalidatingPluginDescriptorCache;
import org.mvndaemon.mvnd.cache.invalidating.InvalidatingPluginRealmCache; import org.mvndaemon.mvnd.cache.invalidating.InvalidatingPluginRealmCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/* /*
* gnodet: This file is based on maven DefaultMavenPluginManager and changed in order * gnodet: This file is based on maven DefaultMavenPluginManager and changed in order
@@ -143,8 +143,7 @@ public class CliMavenPluginManager
*/ */
public static final String KEY_EXTENSIONS_REALMS = CliMavenPluginManager.class.getName() + "/extensionsRealms"; public static final String KEY_EXTENSIONS_REALMS = CliMavenPluginManager.class.getName() + "/extensionsRealms";
@Inject private final Logger logger = LoggerFactory.getLogger(getClass());
private Logger logger;
@Inject @Inject
private LoggerManager loggerManager; private LoggerManager loggerManager;
@@ -236,13 +235,12 @@ public class CliMavenPluginManager
throw new PluginDescriptorParsingException(plugin, pluginFile.getAbsolutePath(), e); throw new PluginDescriptorParsingException(plugin, pluginFile.getAbsolutePath(), e);
} }
MavenPluginValidator validator = new MavenPluginValidator(pluginArtifact); List<String> errors = new ArrayList<>();
validate(pluginArtifact, pluginDescriptor, errors);
validator.validate(pluginDescriptor); if (!errors.isEmpty()) {
if (validator.hasErrors()) {
throw new InvalidPluginDescriptorException( throw new InvalidPluginDescriptorException(
"Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", validator.getErrors()); "Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", errors);
} }
pluginDescriptor.setPluginArtifact(pluginArtifact); pluginDescriptor.setPluginArtifact(pluginArtifact);
@@ -250,6 +248,20 @@ public class CliMavenPluginManager
return pluginDescriptor; return pluginDescriptor;
} }
private void validate(Artifact pluginArtifact, PluginDescriptor pluginDescriptor, List<String> errors) {
if (!pluginArtifact.getGroupId().equals(pluginDescriptor.getGroupId())) {
errors.add("Plugin's descriptor contains the wrong group ID: " + pluginDescriptor.getGroupId());
}
if (!pluginArtifact.getArtifactId().equals(pluginDescriptor.getArtifactId())) {
errors.add("Plugin's descriptor contains the wrong artifact ID: " + pluginDescriptor.getArtifactId());
}
if (!pluginArtifact.getBaseVersion().equals(pluginDescriptor.getVersion())) {
errors.add("Plugin's descriptor contains the wrong version: " + pluginDescriptor.getVersion());
}
}
private String getPluginDescriptorLocation() { private String getPluginDescriptorLocation() {
return "META-INF/maven/plugin.xml"; return "META-INF/maven/plugin.xml";
} }
@@ -516,8 +528,8 @@ public class CliMavenPluginManager
} }
if (mojo instanceof Mojo) { if (mojo instanceof Mojo) {
Logger mojoLogger = loggerManager.getLoggerForComponent(mojoDescriptor.getImplementation()); org.slf4j.Logger mojoLogger = LoggerFactory.getLogger(mojoDescriptor.getImplementation());
((Mojo) mojo).setLog(new DefaultLog(mojoLogger)); ((Mojo) mojo).setLog(new MojoLogWrapper(mojoLogger));
} }
Xpp3Dom dom = mojoExecution.getConfiguration(); Xpp3Dom dom = mojoExecution.getConfiguration();

View File

@@ -21,5 +21,10 @@ under the License.
<extension> <extension>
<exportedPackages> <exportedPackages>
<exportedPackage>org.apache.commons.logging.*</exportedPackage> <exportedPackage>org.apache.commons.logging.*</exportedPackage>
<exportedPackage>org.codehaus.plexus.components.interactivity.*</exportedPackage>
</exportedPackages> </exportedPackages>
<exportedArtifacts>
<exportedArtifact>org.codehaus.plexus:plexus-interactivity-api</exportedArtifact>
</exportedArtifacts>
</extension> </extension>

View File

@@ -20,12 +20,13 @@
<artifactSet to="/mvn"> <artifactSet to="/mvn">
<artifact id="org.apache.maven:apache-maven:tar.gz:bin"> <artifact id="org.apache.maven:apache-maven:tar.gz:bin">
<unpack useRoot="false" <unpack useRoot="false"
excludes="lib/*slf4j*,conf/logging/*,lib/maven-slf4j-provider*,bin/mvn*,lib/jansi-*.jar,lib/jansi-native/*,lib/maven-resolver-api-*,lib/maven-resolver-impl-*,lib/maven-resolver-spi-*,lib/maven-resolver-util-*,lib/maven-resolver-connector-*,lib/maven-resolver-transport-*"/> excludes="conf/logging/*,lib/maven-slf4j-provider*,bin/mvn*,lib/jansi-*.jar,lib/jansi-native/*,lib/plexus-utils-3.*"/>
</artifact> </artifact>
</artifactSet> </artifactSet>
<artifactSet to="/mvn/lib"> <artifactSet to="/mvn/lib">
<exclusion id="javax.annotation:javax.annotation-api"/> <exclusion id="javax.annotation:javax.annotation-api"/>
<exclusion id="org.codehaus.plexus:plexus-utils"/>
<artifact id="org.apache.maven.resolver:maven-resolver-api"/> <artifact id="org.apache.maven.resolver:maven-resolver-api"/>
<artifact id="org.apache.maven.resolver:maven-resolver-impl"/> <artifact id="org.apache.maven.resolver:maven-resolver-impl"/>
<artifact id="org.apache.maven.resolver:maven-resolver-spi"/> <artifact id="org.apache.maven.resolver:maven-resolver-spi"/>
@@ -38,6 +39,7 @@
<exclusion id="org.slf4j:slf4j-api"/> <exclusion id="org.slf4j:slf4j-api"/>
<artifact id="org.apache.maven.daemon:mvnd-daemon:${project.version}"> <artifact id="org.apache.maven.daemon:mvnd-daemon:${project.version}">
<exclusion id="org.codehaus.plexus:plexus-classworlds"/> <exclusion id="org.codehaus.plexus:plexus-classworlds"/>
<exclusion id="org.codehaus.plexus:plexus-utils"/>
<exclusion id="*:cdi-api"/> <exclusion id="*:cdi-api"/>
<exclusion id="*:commons-cli"/> <exclusion id="*:commons-cli"/>
<exclusion id="*:commons-io"/> <exclusion id="*:commons-io"/>
@@ -45,7 +47,10 @@
<exclusion id="*:guava"/> <exclusion id="*:guava"/>
<exclusion id="*:guice"/> <exclusion id="*:guice"/>
<exclusion id="*:javax.inject"/> <exclusion id="*:javax.inject"/>
<exclusion id="*:jcl-over-slf4j"/>
<exclusion id="*:jul-to-slf4j"/>
<exclusion id="*:jsr250-api"/> <exclusion id="*:jsr250-api"/>
<exclusion id="*:log4j-over-slf4j"/>
<exclusion id="*:maven-artifact"/> <exclusion id="*:maven-artifact"/>
<exclusion id="*:maven-builder-support"/> <exclusion id="*:maven-builder-support"/>
<exclusion id="*:maven-core"/> <exclusion id="*:maven-core"/>
@@ -70,6 +75,7 @@
<exclusion id="*:plexus-sec-dispatcher"/> <exclusion id="*:plexus-sec-dispatcher"/>
<exclusion id="*:plexus-utils"/> <exclusion id="*:plexus-utils"/>
<exclusion id="*:plexus-container-default"/> <exclusion id="*:plexus-container-default"/>
<exclusion id="*:slf4j-api"/>
</artifact> </artifact>
<artifact id="org.apache.maven.daemon:mvnd-client:${project.version}"> <artifact id="org.apache.maven.daemon:mvnd-client:${project.version}">
<exclusion id="*:*"/> <exclusion id="*:*"/>

View File

@@ -19,6 +19,7 @@ import java.io.IOException;
import javax.inject.Inject; import javax.inject.Inject;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.mvndaemon.mvnd.assertj.TestClientOutput; import org.mvndaemon.mvnd.assertj.TestClientOutput;
import org.mvndaemon.mvnd.client.Client; import org.mvndaemon.mvnd.client.Client;
import org.mvndaemon.mvnd.client.DaemonParameters; import org.mvndaemon.mvnd.client.DaemonParameters;
@@ -27,6 +28,7 @@ import org.mvndaemon.mvnd.common.Message.Prompt;
import org.mvndaemon.mvnd.junit.MvndTest; import org.mvndaemon.mvnd.junit.MvndTest;
@MvndTest(projectDir = "src/test/projects/single-module") @MvndTest(projectDir = "src/test/projects/single-module")
@Timeout(300)
public class InteractiveTest { public class InteractiveTest {
@Inject @Inject

View File

@@ -61,6 +61,10 @@ public class NewManagedModuleNativeIT {
registry.awaitIdle(d.getId()); registry.awaitIdle(d.getId());
/* Do the changes */ /* Do the changes */
System.gc();
Thread.sleep(100);
System.gc();
final Path srcDir = parentDir.resolve("../changes").normalize(); final Path srcDir = parentDir.resolve("../changes").normalize();
try (Stream<Path> files = Files.walk(srcDir)) { try (Stream<Path> files = Files.walk(srcDir)) {
files.forEach(source -> { files.forEach(source -> {

11
pom.xml
View File

@@ -64,8 +64,8 @@
<jline.version>3.21.0</jline.version> <jline.version>3.21.0</jline.version>
<junit.jupiter.version>5.7.2</junit.jupiter.version> <junit.jupiter.version>5.7.2</junit.jupiter.version>
<logback.version>1.2.10</logback.version> <logback.version>1.2.10</logback.version>
<maven.version>3.8.6</maven.version> <maven.version>4.0.0-alpha-2</maven.version>
<maven.resolver.version>1.7.3</maven.resolver.version> <maven.resolver.version>1.8.2</maven.resolver.version>
<slf4j.version>1.7.35</slf4j.version> <slf4j.version>1.7.35</slf4j.version>
<sisu.version>0.3.5</sisu.version> <sisu.version>0.3.5</sisu.version>
@@ -412,6 +412,13 @@ limitations under the License.</inlineHeader>
<skip>${format.skip}</skip> <skip>${format.skip}</skip>
<cachedir>${project.build.directory}/cache</cachedir> <cachedir>${project.build.directory}/cache</cachedir>
</configuration> </configuration>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>plexus-utils</artifactId>
<version>${maven.version}</version>
</dependency>
</dependencies>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>