From bcab57af03b8156a9d12f3256829991328f0b5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Mon, 18 Mar 2024 19:13:05 +0100 Subject: [PATCH 01/76] Extract test helper module --- pom.xml | 6 +++ .../dependency-resolution-tests/pom.xml | 13 ----- .../pom.xml | 17 ++++++- .../private-artifact-repository-tests/pom.xml | 9 ---- .../sbm/PrivateArtifactRepositoryTest.java | 4 +- spring-rewrite-commons-launcher/pom.xml | 15 +++--- .../test/util/ParserExecutionHelper.java | 4 +- spring-rewrite-commons-test/pom.xml | 50 +++++++++++++++++++ .../rewrite/test/util/DummyResource.java | 0 .../rewrite/test/util/TestProjectHelper.java | 15 +++++- spring-rewrite-commons-utils/pom.xml | 17 +++++++ .../rewrite/utils/ResourceUtil.java | 0 12 files changed, 112 insertions(+), 38 deletions(-) create mode 100644 spring-rewrite-commons-test/pom.xml rename {spring-rewrite-commons-launcher/src/test => spring-rewrite-commons-test/src/main}/java/org/springframework/rewrite/test/util/DummyResource.java (100%) rename {spring-rewrite-commons-launcher/src/test => spring-rewrite-commons-test/src/main}/java/org/springframework/rewrite/test/util/TestProjectHelper.java (88%) create mode 100644 spring-rewrite-commons-utils/pom.xml rename {spring-rewrite-commons-launcher => spring-rewrite-commons-utils}/src/main/java/org/springframework/rewrite/utils/ResourceUtil.java (100%) diff --git a/pom.xml b/pom.xml index 7a00c973..4e620c2c 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ spring-rewrite-commons-starters spring-rewrite-commons-gradle spring-rewrite-commons-plugin-invoker + spring-rewrite-commons-test @@ -129,6 +130,11 @@ rewrite-core ${rewrite.version} + + org.springframework.rewrite + spring-rewrite-commons-test + ${project.version} + diff --git a/spring-rewrite-commons-functional-tests/dependency-resolution-tests/pom.xml b/spring-rewrite-commons-functional-tests/dependency-resolution-tests/pom.xml index a0b0bb90..3cfa1c88 100644 --- a/spring-rewrite-commons-functional-tests/dependency-resolution-tests/pom.xml +++ b/spring-rewrite-commons-functional-tests/dependency-resolution-tests/pom.xml @@ -28,19 +28,6 @@ org.openrewrite rewrite-java - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.rewrite - spring-rewrite-commons-launcher - test - test-jar - 0.1.0-SNAPSHOT - test - \ No newline at end of file diff --git a/spring-rewrite-commons-functional-tests/pom.xml b/spring-rewrite-commons-functional-tests/pom.xml index 9df71749..6602565b 100644 --- a/spring-rewrite-commons-functional-tests/pom.xml +++ b/spring-rewrite-commons-functional-tests/pom.xml @@ -53,6 +53,21 @@ import - + + + + org.springframework.rewrite + spring-rewrite-commons-test + test + + + org.springframework.rewrite + spring-rewrite-commons-launcher + test + test-jar + 0.1.0-SNAPSHOT + test + + \ No newline at end of file diff --git a/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/pom.xml b/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/pom.xml index 58172e7e..f4a54efc 100644 --- a/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/pom.xml +++ b/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/pom.xml @@ -21,14 +21,6 @@ spring-rewrite-commons-launcher 0.1.0-SNAPSHOT - - org.springframework.rewrite - spring-rewrite-commons-launcher - test - test-jar - 0.1.0-SNAPSHOT - test - @@ -169,7 +161,6 @@ 2.11.3 test - \ No newline at end of file diff --git a/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/src/test/java/org/springframework/sbm/PrivateArtifactRepositoryTest.java b/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/src/test/java/org/springframework/sbm/PrivateArtifactRepositoryTest.java index 620c17d5..96270f9b 100644 --- a/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/src/test/java/org/springframework/sbm/PrivateArtifactRepositoryTest.java +++ b/spring-rewrite-commons-functional-tests/private-artifact-repository-tests/src/test/java/org/springframework/sbm/PrivateArtifactRepositoryTest.java @@ -33,7 +33,6 @@ import org.springframework.rewrite.RewriteProjectParser; import org.springframework.rewrite.boot.autoconfigure.RewriteLauncherConfiguration; import org.springframework.rewrite.parser.RewriteProjectParsingResult; -import org.springframework.rewrite.parser.maven.SbmTestConfiguration; import org.springframework.util.FileSystemUtils; import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; @@ -87,8 +86,7 @@ * * @author Fabian Krüger */ -@SpringBootTest(classes = { MavenArtifactCacheTestConfig.class, RewriteLauncherConfiguration.class, - SbmTestConfiguration.class }) +@SpringBootTest(classes = { MavenArtifactCacheTestConfig.class, RewriteLauncherConfiguration.class }) @Testcontainers public class PrivateArtifactRepositoryTest { diff --git a/spring-rewrite-commons-launcher/pom.xml b/spring-rewrite-commons-launcher/pom.xml index b1ceb082..16757cb3 100644 --- a/spring-rewrite-commons-launcher/pom.xml +++ b/spring-rewrite-commons-launcher/pom.xml @@ -26,6 +26,11 @@ spring-boot-configuration-processor true + + org.springframework.rewrite + spring-rewrite-commons-utils + 0.1.0-SNAPSHOT + org.openrewrite rewrite-maven @@ -162,14 +167,8 @@ - org.springframework.boot - spring-boot-starter-test - test - - - org.junit-pioneer - junit-pioneer - ${junit-pioneer.version} + org.springframework.rewrite + spring-rewrite-commons-test test diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/ParserExecutionHelper.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/ParserExecutionHelper.java index 8d9a0a24..885e10ae 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/ParserExecutionHelper.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/ParserExecutionHelper.java @@ -20,8 +20,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.rewrite.boot.autoconfigure.SpringRewriteCommonsConfiguration; import org.springframework.rewrite.RewriteProjectParser; +import org.springframework.rewrite.boot.autoconfigure.RewriteLauncherConfiguration; import org.springframework.rewrite.parser.RewriteProjectParsingResult; import org.springframework.rewrite.parser.SpringRewriteProperties; import org.springframework.rewrite.parser.maven.ComparingParserFactory; @@ -109,7 +109,7 @@ public RewriteProjectParsingResult parseWithComparingParser(Path baseDir, public RewriteProjectParsingResult parseWithRewriteProjectParser(Path baseDir, SpringRewriteProperties springRewriteProperties) { AtomicReference atomicRef = new AtomicReference<>(); - new ApplicationContextRunner().withUserConfiguration(SpringRewriteCommonsConfiguration.class) + new ApplicationContextRunner().withUserConfiguration(RewriteLauncherConfiguration.class) .withBean("spring.rewrite-" + SpringRewriteProperties.class.getName(), SpringRewriteProperties.class, () -> springRewriteProperties) .run(appCtx -> { diff --git a/spring-rewrite-commons-test/pom.xml b/spring-rewrite-commons-test/pom.xml new file mode 100644 index 00000000..fb6d52e7 --- /dev/null +++ b/spring-rewrite-commons-test/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + org.springframework.rewrite + spring-rewrite-commons + 0.1.0-SNAPSHOT + ../pom.xml + + + spring-rewrite-commons-test + + + 17 + 17 + UTF-8 + + + + + org.springframework.rewrite + spring-rewrite-commons-utils + 0.1.0-SNAPSHOT + + + commons-io + commons-io + 2.11.0 + + + + org.openrewrite + rewrite-core + ${rewrite.version} + + + org.springframework.boot + spring-boot-starter-test + + + org.junit-pioneer + junit-pioneer + ${junit-pioneer.version} + compile + + + \ No newline at end of file diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/DummyResource.java b/spring-rewrite-commons-test/src/main/java/org/springframework/rewrite/test/util/DummyResource.java similarity index 100% rename from spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/DummyResource.java rename to spring-rewrite-commons-test/src/main/java/org/springframework/rewrite/test/util/DummyResource.java diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/TestProjectHelper.java b/spring-rewrite-commons-test/src/main/java/org/springframework/rewrite/test/util/TestProjectHelper.java similarity index 88% rename from spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/TestProjectHelper.java rename to spring-rewrite-commons-test/src/main/java/org/springframework/rewrite/test/util/TestProjectHelper.java index befece96..98dcc893 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/TestProjectHelper.java +++ b/spring-rewrite-commons-test/src/main/java/org/springframework/rewrite/test/util/TestProjectHelper.java @@ -45,6 +45,8 @@ public class TestProjectHelper { private boolean deleteDirIfExists = false; + private String gitHash = null; + public TestProjectHelper(Path targetDir) { this.targetDir = targetDir; } @@ -76,6 +78,11 @@ public TestProjectHelper cloneGitProject(String url) { return this; } + public TestProjectHelper checkoutHash(String gitHash) { + this.gitHash = gitHash; + return this; + } + public TestProjectHelper checkoutTag(String tag) { this.gitTag = tag; return this; @@ -110,8 +117,12 @@ else if (gitUrl != null) { Git git = Git.cloneRepository().setDirectory(directory).setURI(this.gitUrl).call(); if (gitTag != null) { - git.checkout().setName("refs/tags/" + gitTag).call(); - } + git.checkout().setName("refs/tags/" + gitTag).setCreateBranch(false).call(); + } /* + * else if(gitHash != null) { // + * git.checkout().setAllPaths(true).setStartPoint(gitHash).call(); + * git.checkout().setOrphan(true).setStartPoint(gitHash).call(); } + */ } catch (GitAPIException e) { throw new RuntimeException(e); diff --git a/spring-rewrite-commons-utils/pom.xml b/spring-rewrite-commons-utils/pom.xml new file mode 100644 index 00000000..29674328 --- /dev/null +++ b/spring-rewrite-commons-utils/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + + org.springframework.rewrite + spring-rewrite-commons + 0.1.0-SNAPSHOT + ../pom.xml + + + spring-rewrite-commons-utils + + Utils + + \ No newline at end of file diff --git a/spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/ResourceUtil.java b/spring-rewrite-commons-utils/src/main/java/org/springframework/rewrite/utils/ResourceUtil.java similarity index 100% rename from spring-rewrite-commons-launcher/src/main/java/org/springframework/rewrite/utils/ResourceUtil.java rename to spring-rewrite-commons-utils/src/main/java/org/springframework/rewrite/utils/ResourceUtil.java From 6edd20d4218e7be47547539362dee96a76bab644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= Date: Thu, 8 Feb 2024 21:41:33 +0100 Subject: [PATCH 02/76] Cloned MavenCli compiles --- .../CustomExecutionListener.java | 120 ++ .../DelegatingCliRequest.java | 87 + .../maveninvokerplayground/MavenCli.java | 1528 +++++++++++++++++ .../MavenExecutionResult.java | 22 + .../MyExecutionListener.java | 109 ++ 5 files changed, 1866 insertions(+) create mode 100644 maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/CustomExecutionListener.java create mode 100644 maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/DelegatingCliRequest.java create mode 100644 maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/MavenCli.java create mode 100644 maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/MavenExecutionResult.java create mode 100644 maven-invoker-playground/src/test/java/org/springframework/rewrite/maveninvokerplayground/MyExecutionListener.java diff --git a/maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/CustomExecutionListener.java b/maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/CustomExecutionListener.java new file mode 100644 index 00000000..82d5f84d --- /dev/null +++ b/maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/CustomExecutionListener.java @@ -0,0 +1,120 @@ +package org.springframework.rewrite.maveninvokerplayground; + +import org.apache.maven.eventspy.AbstractEventSpy; +import org.apache.maven.execution.ExecutionEvent; +import org.apache.maven.execution.ExecutionListener; +import org.apache.maven.plugin.MojoExecutionException; +import org.codehaus.plexus.component.annotations.Component; + +import java.util.function.Consumer; + +@Component(role = AbstractEventSpy.class, hint = "customExecutionListener") +public class CustomExecutionListener extends AbstractEventSpy implements ExecutionListener { + + private final Consumer eventConsumer; + + public CustomExecutionListener(Consumer eventConsumer) { + this.eventConsumer = eventConsumer; + } + + @Override + public void init(Context context) throws Exception { + // Initialization code here + } + + @Override + public void onEvent(Object event) throws Exception { + eventConsumer.accept(event); + if (event instanceof ExecutionEvent) { + // Handle the execution event + eventConsumer.accept(event); + } + } + + @Override + public void projectDiscoveryStarted(ExecutionEvent executionEvent) { + + } + + @Override + public void sessionStarted(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void sessionEnded(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void projectSkipped(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void projectStarted(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void projectSucceeded(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void projectFailed(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void mojoSkipped(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void mojoStarted(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void mojoSucceeded(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void mojoFailed(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void forkStarted(ExecutionEvent executionEvent) { + eventConsumer.accept(executionEvent); + } + + @Override + public void forkSucceeded(ExecutionEvent executionEvent) { + + } + + @Override + public void forkFailed(ExecutionEvent executionEvent) { + + } + + @Override + public void forkedProjectStarted(ExecutionEvent executionEvent) { + + } + + @Override + public void forkedProjectSucceeded(ExecutionEvent executionEvent) { + + } + + @Override + public void forkedProjectFailed(ExecutionEvent executionEvent) { + + } + + // Implement other methods (mojoFailed, mojoSucceeded, etc.) as needed +} diff --git a/maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/DelegatingCliRequest.java b/maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/DelegatingCliRequest.java new file mode 100644 index 00000000..3f4d31c4 --- /dev/null +++ b/maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/DelegatingCliRequest.java @@ -0,0 +1,87 @@ +package org.springframework.rewrite.maveninvokerplayground; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Properties; + +import org.apache.commons.cli.CommandLine; +import org.apache.maven.cli.CliRequest; +import org.apache.maven.execution.MavenExecutionRequest; +import org.codehaus.plexus.classworlds.ClassWorld; + +/** + * DelegatingCliRequest + */ +public class DelegatingCliRequest extends org.apache.maven.cli.CliRequest { + private final CliRequest delegate1; + + public DelegatingCliRequest(CliRequest delegate){ + delegate1 = delegate; + } + + + @Override + public String[] getArgs() { + return delegate.getArgs(); + } + + @Override + public CommandLine getCommandLine() { + return delegate.getCommandLine(); + } + + @Override + public ClassWorld getClassWorld() { + return delegate.getClassWorld(); + } + + @Override + public String getWorkingDirectory() { + return delegate.getWorkingDirectory(); + } + + @Override + public File getMultiModuleProjectDirectory() { + return delegate.getMultiModuleProjectDirectory(); + } + + @Override + public boolean isDebug() { + return delegate.isDebug(); + } + + @Override + public boolean isQuiet() { + return delegate.isQuiet(); + } + + @Override + public boolean isShowErrors() { + return delegate.isShowErrors(); + } + + @Override + public Properties getUserProperties() { + return delegate.getUserProperties(); + } + + @Override + public Properties getSystemProperties() { + return delegate.getSystemProperties(); + } + + @Override + public MavenExecutionRequest getRequest() { + return delegate.getRequest(); + } + + @Override + public void setUserProperties(Properties properties) { + delegate.setUserProperties(properties); + } + + private final org.apache.maven.cli.CliRequest delegate; + + +} \ No newline at end of file diff --git a/maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/MavenCli.java b/maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/MavenCli.java new file mode 100644 index 00000000..9bb17fd0 --- /dev/null +++ b/maven-invoker-playground/src/main/java/org/springframework/rewrite/maveninvokerplayground/MavenCli.java @@ -0,0 +1,1528 @@ +/* + * Copyright 2021 - 2023 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 + * + * https://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.springframework.rewrite.maveninvokerplayground; + +import com.google.inject.AbstractModule; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.UnrecognizedOptionException; +import org.apache.maven.BuildAbort; +import org.apache.maven.InternalErrorException; +import org.apache.maven.Maven; +import org.apache.maven.building.FileSource; +import org.apache.maven.building.Problem; +import org.apache.maven.building.Source; +import org.apache.maven.cli.CLIManager; +import org.apache.maven.cli.CLIReportingUtils; +import org.apache.maven.cli.CliRequest; +import org.apache.maven.cli.configuration.ConfigurationProcessor; +import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor; +import org.apache.maven.cli.event.DefaultEventSpyContext; +import org.apache.maven.cli.event.ExecutionEventLogger; +import org.apache.maven.cli.internal.BootstrapCoreExtensionManager; +import org.apache.maven.cli.internal.extension.model.CoreExtension; +import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader; +import org.apache.maven.cli.logging.Slf4jConfiguration; +import org.apache.maven.cli.logging.Slf4jConfigurationFactory; +import org.apache.maven.cli.logging.Slf4jLoggerManager; +import org.apache.maven.cli.logging.Slf4jStdoutLogger; +import org.apache.maven.cli.transfer.ConsoleMavenTransferListener; +import org.apache.maven.cli.transfer.QuietMavenTransferListener; +import org.apache.maven.cli.transfer.Slf4jMavenTransferListener; +import org.apache.maven.eventspy.internal.EventSpyDispatcher; +import org.apache.maven.exception.DefaultExceptionHandler; +import org.apache.maven.exception.ExceptionHandler; +import org.apache.maven.exception.ExceptionSummary; +import org.apache.maven.execution.*; +import org.apache.maven.execution.MavenExecutionResult; +import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule; +import org.apache.maven.extension.internal.CoreExports; +import org.apache.maven.extension.internal.CoreExtensionEntry; +import org.apache.maven.lifecycle.LifecycleExecutionException; +import org.apache.maven.model.building.ModelProcessor; +import org.apache.maven.project.MavenProject; +import org.apache.maven.properties.internal.EnvironmentUtils; +import org.apache.maven.properties.internal.SystemProperties; +import org.apache.maven.session.scope.internal.SessionScopeModule; +import org.apache.maven.shared.utils.logging.MessageBuilder; +import org.apache.maven.shared.utils.logging.MessageUtils; +import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest; +import org.apache.maven.toolchain.building.ToolchainsBuilder; +import org.apache.maven.toolchain.building.ToolchainsBuildingResult; +import org.codehaus.plexus.*; +import org.codehaus.plexus.classworlds.ClassWorld; +import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.logging.LoggerManager; +import org.codehaus.plexus.util.StringUtils; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.eclipse.aether.transfer.TransferListener; +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonatype.plexus.components.cipher.DefaultPlexusCipher; +import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher; +import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; +import org.sonatype.plexus.components.sec.dispatcher.SecUtil; +import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity; + +import java.io.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Files; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.apache.maven.cli.CLIManager.COLOR; +import static org.apache.maven.cli.ResolveFile.resolveFile; +import static org.apache.maven.shared.utils.logging.MessageUtils.buffer; + +/** + * Starts a Maven build in the same process. + * Using {@link MavenCli} does not provide a way to register execution listeners. + * A {@link org.apache.maven.execution.ExecutionListener} is required to access the {@link MavenSession}. + * The {@link MavenSession} provides access to teh gathered build information required in the subsequent parsing. + * + * @author Fabian Krüger + */ +public class MavenCli { + public static final String LOCAL_REPO_PROPERTY = "maven.repo.local"; + + public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory"; + + public static final String USER_HOME = System.getProperty("user.home"); + + public static final File USER_MAVEN_CONFIGURATION_HOME = new File(USER_HOME, ".m2"); + + public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File(USER_MAVEN_CONFIGURATION_HOME, "toolchains.xml"); + + public static final File DEFAULT_GLOBAL_TOOLCHAINS_FILE = + new File(System.getProperty("maven.conf"), "toolchains.xml"); + + private static final String EXT_CLASS_PATH = "maven.ext.class.path"; + + private static final String EXTENSIONS_FILENAME = ".mvn/extensions.xml"; + + private static final String MVN_MAVEN_CONFIG = ".mvn/maven.config"; + + public static final String STYLE_COLOR_PROPERTY = "style.color"; + + private ClassWorld classWorld; + + private LoggerManager plexusLoggerManager; + + private ILoggerFactory slf4jLoggerFactory; + + private Logger slf4jLogger; + + private EventSpyDispatcher eventSpyDispatcher; + + private ModelProcessor modelProcessor; + + private Maven maven; + + private MavenExecutionRequestPopulator executionRequestPopulator; + + private ToolchainsBuilder toolchainsBuilder; + + private DefaultSecDispatcher dispatcher; + + private Map configurationProcessors; + + private CLIManager cliManager; + + public MavenCli() { + this(null); + } + + // This supports painless invocation by the Verifier during embedded execution of the core ITs + public MavenCli(ClassWorld classWorld) { + this.classWorld = classWorld; + } + + public static void main(String[] args) { + int result = main(args, null); + + System.exit(result); + } + + public static int main(String[] args, ClassWorld classWorld) { + MavenCli cli = new MavenCli(); + + MessageUtils.systemInstall(); + MessageUtils.registerShutdownHook(); + DelegatingCliRequest cliRequest = createCliRequest(args, classWorld); + int result = cli.doMain(cliRequest); + MessageUtils.systemUninstall(); + + return result; + } + + private static CliRequest createCliRequest(String[] args, ClassWorld classWorld) { + try { + Constructor constructor = CliRequest.class.getDeclaredConstructor(String[].class, classWorld.getClass()); + constructor.setAccessible(true); // Make the constructor accessible + CliRequest delegate = constructor.newInstance(args, classWorld); + return delegate; + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + // TODO need to externalize DelegatingCliRequest + public static int doMain(String[] args, ClassWorld classWorld) { + MavenCli cli = new MavenCli(); + return cli.doMain(new DelegatingCliRequest(args, classWorld)); + } + + /** + * This supports painless invocation by the Verifier during embedded execution of the core ITs. + * See + * Embedded3xLauncher in maven-verifier + */ + public int doMain(String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr) { + PrintStream oldout = System.out; + PrintStream olderr = System.err; + + final Set realms; + if (classWorld != null) { + realms = new HashSet<>(); + for (ClassRealm realm : classWorld.getRealms()) { + realms.add(realm.getId()); + } + } else { + realms = Collections.emptySet(); + } + + try { + if (stdout != null) { + System.setOut(stdout); + } + if (stderr != null) { + System.setErr(stderr); + } + + DelegatingCliRequest cliRequest = new DelegatingCliRequest(args, classWorld); + cliRequest.workingDirectory = workingDirectory; + + return doMain(cliRequest); + } finally { + if (classWorld != null) { + for (ClassRealm realm : new ArrayList<>(classWorld.getRealms())) { + String realmId = realm.getId(); + if (!realms.contains(realmId)) { + try { + classWorld.disposeRealm(realmId); + } catch (NoSuchRealmException ignored) { + // can't happen + } + } + } + } + System.setOut(oldout); + System.setErr(olderr); + } + } + + // TODO need to externalize DelegatingCliRequest + public int doMain(DelegatingCliRequest cliRequest) { + PlexusContainer localContainer = null; + try { + initialize(cliRequest); + cli(cliRequest); + properties(cliRequest); + logging(cliRequest); + informativeCommands(cliRequest); + version(cliRequest); + localContainer = container(cliRequest); + commands(cliRequest); + configure(cliRequest); + toolchains(cliRequest); + populateRequest(cliRequest); + encryption(cliRequest); + repository(cliRequest); + return execute(cliRequest); + } catch (MavenCli.ExitException e) { + return e.exitCode; + } catch (UnrecognizedOptionException e) { + // pure user error, suppress stack trace + return 1; + } catch (BuildAbort e) { + CLIReportingUtils.showError(slf4jLogger, "ABORTED", e, cliRequest.showErrors); + + return 2; + } catch (Exception e) { + CLIReportingUtils.showError(slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors); + + return 1; + } finally { + if (localContainer != null) { + localContainer.dispose(); + } + } + } + + void initialize(DelegatingCliRequest cliRequest) + throws MavenCli.ExitException { + if (cliRequest.workingDirectory == null) { + cliRequest.workingDirectory = System.getProperty("user.dir"); + } + + if (cliRequest.multiModuleProjectDirectory == null) { + String basedirProperty = System.getProperty(MULTIMODULE_PROJECT_DIRECTORY); + if (basedirProperty == null) { + System.err.format( + "-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY); + throw new MavenCli.ExitException(1); + } + File basedir = basedirProperty != null ? new File(basedirProperty) : new File(""); + try { + cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile(); + } catch (IOException e) { + cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile(); + } + } + + // + // Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative + // Windows paths. + // + String mavenHome = System.getProperty("maven.home"); + + if (mavenHome != null) { + System.setProperty("maven.home", new File(mavenHome).getAbsolutePath()); + } + } + + void cli(DelegatingCliRequest cliRequest) + throws Exception { + // + // Parsing errors can happen during the processing of the arguments and we prefer not having to check if + // the logger is null and construct this so we can use an SLF4J logger everywhere. + // + slf4jLogger = new Slf4jStdoutLogger(); + + cliManager = new CLIManager(); + + List args = new ArrayList<>(); + CommandLine mavenConfig = null; + try { + File configFile = new File(cliRequest.multiModuleProjectDirectory, MVN_MAVEN_CONFIG); + + if (configFile.isFile()) { + for (String arg : new String(Files.readAllBytes(configFile.toPath())).split("\\s+")) { + if (!arg.isEmpty()) { + args.add(arg); + } + } + + mavenConfig = cliManager.parse(args.toArray(new String[0])); + List unrecongized = mavenConfig.getArgList(); + if (!unrecongized.isEmpty()) { + throw new ParseException("Unrecognized maven.config entries: " + unrecongized); + } + } + } catch (ParseException e) { + System.err.println("Unable to parse maven.config: " + e.getMessage()); + cliManager.displayHelp(System.out); + throw e; + } + + try { + if (mavenConfig == null) { + cliRequest.commandLine = cliManager.parse(cliRequest.args); + } else { + cliRequest.commandLine = cliMerge(cliManager.parse(cliRequest.args), mavenConfig); + } + } catch (ParseException e) { + System.err.println("Unable to parse command line options: " + e.getMessage()); + cliManager.displayHelp(System.out); + throw e; + } + } + + private void informativeCommands(DelegatingCliRequest cliRequest) throws MavenCli.ExitException { + if (cliRequest.commandLine.hasOption(CLIManager.HELP)) { + cliManager.displayHelp(System.out); + throw new MavenCli.ExitException(0); + } + + if (cliRequest.commandLine.hasOption(CLIManager.VERSION)) { + if (cliRequest.commandLine.hasOption(CLIManager.QUIET)) { + System.out.println(CLIReportingUtils.showVersionMinimal()); + } else { + System.out.println(CLIReportingUtils.showVersion()); + } + throw new MavenCli.ExitException(0); + } + } + + private CommandLine cliMerge(CommandLine mavenArgs, CommandLine mavenConfig) { + CommandLine.Builder commandLineBuilder = new CommandLine.Builder(); + + // the args are easy, cli first then config file + for (String arg : mavenArgs.getArgs()) { + commandLineBuilder.addArg(arg); + } + for (String arg : mavenConfig.getArgs()) { + commandLineBuilder.addArg(arg); + } + + // now add all options, except for -D with cli first then config file + List