This is an automated email from the ASF dual-hosted git repository. cstamas pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/master by this push: new 5b7a6de55a [MNG-8421] Move all of logging setup to LookupInvoker; mvnenc IT (#1964) 5b7a6de55a is described below commit 5b7a6de55aede5f0f92b13de1f5aeac9b8436329 Author: Tamas Cservenak <ta...@cservenak.net> AuthorDate: Thu Dec 12 09:43:12 2024 +0100 [MNG-8421] Move all of logging setup to LookupInvoker; mvnenc IT (#1964) Currently mvnenc is unable to log to file (-l) as logging setup is incomplete, move all of this logic to LookupInvoker. Also, create prompt in mvnenc only when needed. Finally, implement needed changes to support mvnenc ITs and add mvnenc IT. Other changes: * get rid of `distributionFileName` dirty hack, is remnant from old ITs * fix CI re removal of that above and use of site that is brain-dead --- https://issues.apache.org/jira/browse/MNG-8421 --- .github/workflows/maven.yml | 21 +++++-- apache-maven/pom.xml | 5 -- .../apache/maven/cling/invoker/LookupContext.java | 3 + .../apache/maven/cling/invoker/LookupInvoker.java | 20 ++++++ .../maven/cling/invoker/mvn/MavenContext.java | 2 - .../maven/cling/invoker/mvn/MavenInvoker.java | 25 -------- .../maven/cling/invoker/mvnenc/EncryptContext.java | 2 - .../maven/cling/invoker/mvnenc/EncryptInvoker.java | 23 ++----- .../mvnenc/goals/ConfiguredGoalSupport.java | 58 ++++++++--------- .../maven/cling/invoker/mvnenc/goals/Diag.java | 9 ++- .../maven/cling/invoker/mvnenc/goals/Init.java | 29 +++++---- impl/maven-executor/pom.xml | 29 ++++++--- .../executor/embedded/EmbeddedMavenExecutor.java | 51 ++++++++++++--- .../maven/cling/executor/internal/HelperImpl.java | 4 +- .../cling/executor/MavenExecutorTestSupport.java | 19 ++++++ its/core-it-suite/pom.xml | 4 +- .../it/MavenITmng8421MavenEncryptionTest.java | 73 ++++++++++++++++++++++ .../org/apache/maven/it/TestSuiteOrdering.java | 1 + .../src/test/resources/mng-8421/home1/readme.txt | 1 + .../mng-8421/home2/.m2/settings-security.xml | 25 ++++++++ .../mng-8421/home2/.m2/settings-security4.xml | 42 +++++++++++++ .../src/test/resources/mng-8421/home2/readme.txt | 1 + .../main/java/org/apache/maven/it/Verifier.java | 15 ++++- 23 files changed, 336 insertions(+), 126 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index f00bc6f0c1..92153927f5 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -56,7 +56,7 @@ jobs: - name: Build Maven distributions shell: bash - run: ./mvnw verify -e -B -V -DdistributionFileName=apache-maven -Dmaven.repo.local=$HOME/.m2/repository/cached + run: ./mvnw verify -e -B -V -Dmaven.repo.local=$HOME/.m2/repository/cached - name: List contents of target directory shell: bash @@ -117,9 +117,14 @@ jobs: run: | mkdir -p maven-local if [ "${{ runner.os }}" = "Windows" ]; then - unzip maven-dist/apache-maven-bin.zip -d maven-local + unzip maven-dist/apache-maven-*-bin.zip -d maven-local + # Get the name of the extracted directory + MAVEN_DIR=$(ls maven-local) + # Move contents up one level + mv "maven-local/$MAVEN_DIR"/* maven-local/ + rm -r "maven-local/$MAVEN_DIR" else - tar xzf maven-dist/apache-maven-bin.tar.gz -C maven-local --strip-components 1 + tar xzf maven-dist/apache-maven-*-bin.tar.gz -C maven-local --strip-components 1 fi echo "MAVEN_HOME=$PWD/maven-local" >> $GITHUB_ENV echo "$PWD/maven-local/bin" >> $GITHUB_PATH @@ -133,9 +138,13 @@ jobs: maven-${{ runner.os }}-full- maven-${{ runner.os }}- + - name: Build with downloaded Maven + shell: bash + run: mvn verify -e -B -V -Dmaven.repo.local=$HOME/.m2/repository/cached + - name: Build site with downloaded Maven shell: bash - run: mvn verify site -e -B -V -Preporting -Dmaven.repo.local=$HOME/.m2/repository/cached + run: mvn site -e -B -V -Preporting -Dmaven.repo.local=$HOME/.m2/repository/cached integration-tests: needs: initial-build @@ -172,14 +181,14 @@ jobs: run: | mkdir -p maven-local if [ "${{ runner.os }}" = "Windows" ]; then - unzip maven-dist/apache-maven-bin.zip -d maven-local + unzip maven-dist/apache-maven-*-bin.zip -d maven-local # Get the name of the extracted directory MAVEN_DIR=$(ls maven-local) # Move contents up one level mv "maven-local/$MAVEN_DIR"/* maven-local/ rm -r "maven-local/$MAVEN_DIR" else - tar xzf maven-dist/apache-maven-bin.tar.gz -C maven-local --strip-components 1 + tar xzf maven-dist/apache-maven-*-bin.tar.gz -C maven-local --strip-components 1 fi echo "MAVEN_HOME=$PWD/maven-local" >> $GITHUB_ENV echo "$PWD/maven-local/bin" >> $GITHUB_PATH diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml index cb7a32de41..39cc762fa2 100644 --- a/apache-maven/pom.xml +++ b/apache-maven/pom.xml @@ -32,10 +32,6 @@ under the License. <name>Apache Maven Distribution</name> <description>The Apache Maven distribution, source and binary, in zip and tar.gz formats.</description> - <properties> - <distributionFileName>${distributionId}-${project.version}</distributionFileName> - </properties> - <dependencies> <dependency> <groupId>org.apache.maven</groupId> @@ -162,7 +158,6 @@ under the License. </pluginRepositories> <build> - <finalName>${distributionFileName}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java index 2b29f846ed..8c7fd1df5f 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java @@ -35,6 +35,7 @@ import org.apache.maven.api.cli.Logger; import org.apache.maven.api.services.Lookup; import org.apache.maven.api.settings.Settings; import org.apache.maven.cling.logging.Slf4jConfiguration; +import org.apache.maven.logging.BuildEventListener; import org.jline.terminal.Terminal; import org.slf4j.ILoggerFactory; @@ -86,6 +87,8 @@ public class LookupContext implements AutoCloseable { public ContainerCapsule containerCapsule; public Lookup lookup; + public BuildEventListener buildEventListener; + // paths user can override from CLI, and we need to set on MavenExReq public Path installationSettingsPath; public Path projectSettingsPath; diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java index 8c6aab340c..48c4c56c0a 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java @@ -69,7 +69,10 @@ import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.internal.impl.SettingsUtilsV4; import org.apache.maven.jline.FastTerminal; import org.apache.maven.jline.MessageUtils; +import org.apache.maven.logging.BuildEventListener; import org.apache.maven.logging.LoggingOutputStream; +import org.apache.maven.logging.ProjectBuildLogAppender; +import org.apache.maven.logging.SimpleBuildEventListener; import org.apache.maven.logging.api.LogLevelRecorder; import org.apache.maven.slf4j.MavenSimpleLogger; import org.jline.terminal.Terminal; @@ -228,6 +231,23 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker context.slf4jConfiguration.setRootLoggerLevel(context.loggerLevel); // else fall back to default log level specified in conf // see https://issues.apache.org/jira/browse/MNG-2570 + + // Create the build log appender; also sets MavenSimpleLogger sink + ProjectBuildLogAppender projectBuildLogAppender = + new ProjectBuildLogAppender(determineBuildEventListener(context)); + context.closeables.add(projectBuildLogAppender); + } + + protected BuildEventListener determineBuildEventListener(C context) { + if (context.buildEventListener == null) { + context.buildEventListener = doDetermineBuildEventListener(context); + } + return context.buildEventListener; + } + + protected BuildEventListener doDetermineBuildEventListener(C context) { + Consumer<String> writer = determineWriter(context); + return new SimpleBuildEventListener(writer); } protected void createTerminal(C context) { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java index c533b601ac..18f61aea36 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java @@ -22,7 +22,6 @@ import org.apache.maven.Maven; import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.cling.invoker.LookupContext; import org.apache.maven.eventspy.internal.EventSpyDispatcher; -import org.apache.maven.logging.BuildEventListener; @SuppressWarnings("VisibilityModifier") public class MavenContext extends LookupContext { @@ -30,7 +29,6 @@ public class MavenContext extends LookupContext { super(invokerRequest); } - public BuildEventListener buildEventListener; public EventSpyDispatcher eventSpyDispatcher; public Maven maven; diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java index 5e75e96b6f..667fc55623 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java @@ -27,7 +27,6 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -68,11 +67,8 @@ import org.apache.maven.execution.ProfileActivation; import org.apache.maven.execution.ProjectActivation; import org.apache.maven.jline.MessageUtils; import org.apache.maven.lifecycle.LifecycleExecutionException; -import org.apache.maven.logging.BuildEventListener; import org.apache.maven.logging.LoggingExecutionListener; import org.apache.maven.logging.MavenTransferListener; -import org.apache.maven.logging.ProjectBuildLogAppender; -import org.apache.maven.logging.SimpleBuildEventListener; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.PlexusContainer; import org.eclipse.aether.DefaultRepositoryCache; @@ -149,27 +145,6 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker } } - @Override - protected void configureLogging(C context) throws Exception { - super.configureLogging(context); - // Create the build log appender - ProjectBuildLogAppender projectBuildLogAppender = - new ProjectBuildLogAppender(determineBuildEventListener(context)); - context.closeables.add(projectBuildLogAppender); - } - - protected BuildEventListener determineBuildEventListener(C context) { - if (context.buildEventListener == null) { - context.buildEventListener = doDetermineBuildEventListener(context); - } - return context.buildEventListener; - } - - protected BuildEventListener doDetermineBuildEventListener(C context) { - Consumer<String> writer = determineWriter(context); - return new SimpleBuildEventListener(writer); - } - @Override protected void customizeSettingsRequest(C context, SettingsBuilderRequest settingsBuilderRequest) throws Exception { if (context.eventSpyDispatcher != null) { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptContext.java index 41845f48d2..7f1e97abcb 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptContext.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptContext.java @@ -23,7 +23,6 @@ import java.util.Map; import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.cling.invoker.LookupContext; -import org.jline.consoleui.prompt.ConsolePrompt; import org.jline.reader.LineReader; import org.jline.utils.AttributedString; import org.jline.utils.AttributedStringBuilder; @@ -40,7 +39,6 @@ public class EncryptContext extends LookupContext { public List<AttributedString> header; public AttributedStyle style; public LineReader reader; - public ConsolePrompt prompt; public void addInHeader(String text) { addInHeader(AttributedStyle.DEFAULT, text); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvoker.java index 6ad5b0cbd4..1c52752377 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvoker.java @@ -26,13 +26,11 @@ import org.apache.maven.api.cli.mvnenc.EncryptOptions; import org.apache.maven.cling.invoker.LookupInvoker; import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.utils.CLIReportingUtils; -import org.jline.consoleui.prompt.ConsolePrompt; import org.jline.reader.LineReaderBuilder; import org.jline.reader.UserInterruptException; import org.jline.terminal.Terminal; import org.jline.utils.AttributedStyle; import org.jline.utils.Colors; -import org.jline.utils.OSUtils; /** * mvnenc invoker implementation. @@ -76,17 +74,9 @@ public class EncryptInvoker extends LookupInvoker<EncryptContext> { Thread executeThread = Thread.currentThread(); context.terminal.handle(Terminal.Signal.INT, signal -> executeThread.interrupt()); - ConsolePrompt.UiConfig config; - if (OSUtils.IS_WINDOWS) { - config = new ConsolePrompt.UiConfig(">", "( )", "(x)", "( )"); - } else { - config = new ConsolePrompt.UiConfig("❯", "◯ ", "◉ ", "◯ "); - } - config.setCancellableFirstPrompt(true); context.reader = LineReaderBuilder.builder().terminal(context.terminal).build(); - context.prompt = new ConsolePrompt(context.reader, context.terminal, config); EncryptOptions options = (EncryptOptions) context.invokerRequest.options(); if (options.goals().isEmpty() || options.goals().get().size() != 1) { @@ -102,14 +92,13 @@ public class EncryptInvoker extends LookupInvoker<EncryptContext> { return goal.execute(context); } catch (InterruptedException | InterruptedIOException | UserInterruptException e) { - context.terminal.writer().println("Goal canceled by user."); + context.logger.error("Goal canceled by user."); return CANCELED; } catch (Exception e) { if (context.invokerRequest.options().showErrors().orElse(false)) { - context.terminal.writer().println(e.getMessage()); - e.printStackTrace(context.terminal.writer()); + context.logger.error(e.getMessage(), e); } else { - context.terminal.writer().println(e.getMessage()); + context.logger.error(e.getMessage()); } return ERROR; } finally { @@ -118,9 +107,9 @@ public class EncryptInvoker extends LookupInvoker<EncryptContext> { } protected int badGoalsErrorMessage(String message, EncryptContext context) { - context.terminal.writer().println(message); - context.terminal.writer().println("Supported goals are: " + String.join(", ", context.goals.keySet())); - context.terminal.writer().println("Use -h to display help."); + context.logger.error(message); + context.logger.error("Supported goals are: " + String.join(", ", context.goals.keySet())); + context.logger.error("Use -h to display help."); return BAD_OPERATION; } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/ConfiguredGoalSupport.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/ConfiguredGoalSupport.java index fc9a51ad84..a3647a1f6b 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/ConfiguredGoalSupport.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/ConfiguredGoalSupport.java @@ -39,12 +39,10 @@ public abstract class ConfiguredGoalSupport extends GoalSupport { @Override public int execute(EncryptContext context) throws Exception { if (!validateConfiguration(context)) { - context.terminal - .writer() - .println(messageBuilderFactory - .builder() - .error("Maven Encryption is not configured, run `mvnenc init` first.") - .build()); + context.logger.error(messageBuilderFactory + .builder() + .error("Maven Encryption is not configured, run `mvnenc init` first.") + .build()); return ERROR; } return doExecute(context); @@ -59,36 +57,32 @@ public abstract class ConfiguredGoalSupport extends GoalSupport { } protected void dumpResponse(EncryptContext context, String indent, SecDispatcher.ValidationResponse response) { - context.terminal - .writer() - .println(messageBuilderFactory - .builder() - .format( - response.isValid() - ? messageBuilderFactory - .builder() - .success("%sConfiguration validation of %s: %s") - .build() - : messageBuilderFactory - .builder() - .failure("%sConfiguration validation of %s: %s") - .build(), - indent, - response.getSource(), - response.isValid() ? "VALID" : "INVALID")); + context.logger.info(messageBuilderFactory + .builder() + .format( + response.isValid() + ? messageBuilderFactory + .builder() + .success("%sConfiguration validation of %s: %s") + .build() + : messageBuilderFactory + .builder() + .failure("%sConfiguration validation of %s: %s") + .build(), + indent, + response.getSource(), + response.isValid() ? "VALID" : "INVALID") + .build()); for (Map.Entry<SecDispatcher.ValidationResponse.Level, List<String>> entry : response.getReport().entrySet()) { - Consumer<String> consumer = s -> context.terminal - .writer() - .println(messageBuilderFactory.builder().info(s).build()); + Consumer<String> consumer = s -> + context.logger.info(messageBuilderFactory.builder().info(s).build()); if (entry.getKey() == SecDispatcher.ValidationResponse.Level.ERROR) { - consumer = s -> context.terminal - .writer() - .println(messageBuilderFactory.builder().error(s).build()); + consumer = s -> context.logger.error( + messageBuilderFactory.builder().error(s).build()); } else if (entry.getKey() == SecDispatcher.ValidationResponse.Level.WARNING) { - consumer = s -> context.terminal - .writer() - .println(messageBuilderFactory.builder().warning(s).build()); + consumer = s -> context.logger.warn( + messageBuilderFactory.builder().warning(s).build()); } for (String line : entry.getValue()) { consumer.accept(indent + " " + line); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Diag.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Diag.java index 700ed47bc3..f6271d15cb 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Diag.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Diag.java @@ -29,7 +29,7 @@ import org.codehaus.plexus.components.secdispatcher.SecDispatcher; import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK; /** - * The "diag" goal. + * The "diag" goal. It should always run, despite it overrides configured goal support. */ @Singleton @Named("diag") @@ -40,8 +40,13 @@ public class Diag extends ConfiguredGoalSupport { } @Override - protected int doExecute(EncryptContext context) { + public int execute(EncryptContext context) { dumpResponse(context, "", secDispatcher.validateConfiguration()); return OK; } + + @Override + protected int doExecute(EncryptContext context) throws Exception { + throw new IllegalStateException("Cannot reach here"); + } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java index 7dfd1fba5f..ddaeed2846 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java @@ -45,6 +45,7 @@ import org.jline.reader.Completer; import org.jline.reader.LineReader; import org.jline.reader.ParsedLine; import org.jline.utils.Colors; +import org.jline.utils.OSUtils; import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.BAD_OPERATION; import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK; @@ -64,26 +65,30 @@ public class Init extends InteractiveGoalSupport { @Override public int doExecute(EncryptContext context) throws Exception { - context.addInHeader(context.style.italic().bold().foreground(Colors.rgbColor("yellow")), "goal: init"); - context.addInHeader(""); - - ConsolePrompt prompt = context.prompt; - EncryptOptions options = (EncryptOptions) context.invokerRequest.options(); boolean force = options.force().orElse(false); boolean yes = options.yes().orElse(false); if (configExists() && !force) { - context.terminal - .writer() - .println( - messageBuilderFactory - .builder() - .error( - "Error: configuration exist. Use --force if you want to reset existing configuration.")); + context.logger.error(messageBuilderFactory + .builder() + .error("Error: configuration exist. Use --force if you want to reset existing configuration.") + .build()); return BAD_OPERATION; } + context.addInHeader(context.style.italic().bold().foreground(Colors.rgbColor("yellow")), "goal: init"); + context.addInHeader(""); + + ConsolePrompt.UiConfig promptConfig; + if (OSUtils.IS_WINDOWS) { + promptConfig = new ConsolePrompt.UiConfig(">", "( )", "(x)", "( )"); + } else { + promptConfig = new ConsolePrompt.UiConfig("❯", "◯ ", "◉ ", "◯ "); + } + promptConfig.setCancellableFirstPrompt(true); + ConsolePrompt prompt = new ConsolePrompt(context.reader, context.terminal, promptConfig); + SettingsSecurity config = secDispatcher.readConfiguration(true); // reset config diff --git a/impl/maven-executor/pom.xml b/impl/maven-executor/pom.xml index 4e1060714b..73e76d9819 100644 --- a/impl/maven-executor/pom.xml +++ b/impl/maven-executor/pom.xml @@ -35,7 +35,7 @@ under the License. <properties> <maven3version>3.9.9</maven3version> - <maven4version>4.0.0-rc-1</maven4version> + <maven4version>${project.version}</maven4version> </properties> <dependencies> @@ -55,6 +55,14 @@ under the License. <artifactId>junit-jupiter-params</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>apache-maven</artifactId> + <version>${project.version}</version> + <classifier>bin</classifier> + <type>zip</type> + <scope>test</scope> + </dependency> </dependencies> <build> @@ -64,7 +72,17 @@ under the License. <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> - <id>prepare-maven-distros</id> + <id>prepare-maven4-distro</id> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <phase>generate-test-resources</phase> + <configuration> + <includeArtifactIds>apache-maven</includeArtifactIds> + </configuration> + </execution> + <execution> + <id>prepare-maven3-distro</id> <goals> <goal>unpack</goal> </goals> @@ -78,13 +96,6 @@ under the License. <classifier>bin</classifier> <type>zip</type> </artifactItem> - <artifactItem> - <groupId>org.apache.maven</groupId> - <artifactId>apache-maven</artifactId> - <version>${maven4version}</version> - <classifier>bin</classifier> - <type>zip</type> - </artifactItem> </artifactItems> </configuration> </execution> diff --git a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutor.java b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutor.java index 32b936a448..0bbacf9f66 100644 --- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutor.java +++ b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutor.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Properties; import java.util.Set; @@ -54,6 +55,9 @@ import static java.util.Objects.requireNonNull; * long as instance of this class is not closed. Subsequent execution requests over same installation home are cached. */ public class EmbeddedMavenExecutor implements Executor { + protected static final Map<String, String> MAIN_CLASSES = + Map.of("mvn", "org.apache.maven.cling.MavenCling", "mvnenc", "org.apache.maven.cling.MavenEncCling"); + protected static final class Context { private final URLClassLoader bootClassLoader; private final String version; @@ -62,7 +66,7 @@ public class EmbeddedMavenExecutor implements Executor { private final ClassLoader tccl; private final Function<ExecutorRequest, Integer> exec; - public Context( + private Context( URLClassLoader bootClassLoader, String version, Object classWorld, @@ -78,13 +82,38 @@ public class EmbeddedMavenExecutor implements Executor { } } + protected static class Key { + private final Path installationDirectory; + private final String command; + + private Key(Path installationDirectory, String command) { + this.installationDirectory = installationDirectory; + this.command = command; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + Key key = (Key) o; + return Objects.equals(installationDirectory, key.installationDirectory) + && Objects.equals(command, key.command); + } + + @Override + public int hashCode() { + return Objects.hash(installationDirectory, command); + } + } + protected final boolean cacheContexts; protected final AtomicBoolean closed; protected final PrintStream originalStdout; protected final PrintStream originalStderr; protected final Properties originalProperties; protected final ClassLoader originalClassLoader; - protected final ConcurrentHashMap<Path, Context> contexts; + protected final ConcurrentHashMap<Key, Context> contexts; public EmbeddedMavenExecutor() { this(true); @@ -163,8 +192,10 @@ public class EmbeddedMavenExecutor implements Executor { protected Context mayCreate(ExecutorRequest executorRequest) { Path mavenHome = ExecutorRequest.getCanonicalPath(executorRequest.installationDirectory()); + String command = executorRequest.command(); + Key key = new Key(mavenHome, command); if (cacheContexts) { - return contexts.computeIfAbsent(mavenHome, k -> doCreate(mavenHome, executorRequest)); + return contexts.computeIfAbsent(key, k -> doCreate(mavenHome, executorRequest)); } else { return doCreate(mavenHome, executorRequest); } @@ -172,9 +203,9 @@ public class EmbeddedMavenExecutor implements Executor { protected Context doCreate(Path mavenHome, ExecutorRequest executorRequest) { if (!Files.isDirectory(mavenHome)) { - throw new IllegalArgumentException("Installation directory must point to existing directory"); + throw new IllegalArgumentException("Installation directory must point to existing directory: " + mavenHome); } - if (!Objects.equals(executorRequest.command(), ExecutorRequest.MVN)) { + if (!MAIN_CLASSES.containsKey(executorRequest.command())) { throw new IllegalArgumentException( getClass().getSimpleName() + " does not support command " + executorRequest.command()); } @@ -187,7 +218,8 @@ public class EmbeddedMavenExecutor implements Executor { Path boot = mavenHome.resolve("boot"); Path m2conf = mavenHome.resolve("bin/m2.conf"); if (!Files.isDirectory(boot) || !Files.isRegularFile(m2conf)) { - throw new IllegalArgumentException("Installation directory does not point to Maven installation"); + throw new IllegalArgumentException( + "Installation directory does not point to Maven installation: " + mavenHome); } Properties properties = prepareProperties(executorRequest); @@ -220,6 +252,10 @@ public class EmbeddedMavenExecutor implements Executor { if (version.startsWith("3.")) { // 3.x + if (!ExecutorRequest.MVN.equals(executorRequest.command())) { + throw new IllegalArgumentException(getClass().getSimpleName() + "w/ mvn3 does not support command " + + executorRequest.command()); + } Constructor<?> newMavenCli = cliClass.getConstructor(classWorld.getClass()); Object mavenCli = newMavenCli.newInstance(classWorld); Class<?>[] parameterTypes = {String[].class, String.class, PrintStream.class, PrintStream.class}; @@ -284,7 +320,8 @@ public class EmbeddedMavenExecutor implements Executor { properties.setProperty("maven.home", mavenHome.toString()); properties.setProperty( "maven.multiModuleProjectDirectory", request.cwd().toString()); - properties.setProperty("maven.mainClass", "org.apache.maven.cling.MavenCling"); + String mainClass = requireNonNull(MAIN_CLASSES.get(request.command()), "mainClass"); + properties.setProperty("maven.mainClass", mainClass); properties.setProperty( "library.jline.path", mavenHome.resolve("lib/jline-native").toString()); // TODO: is this needed? diff --git a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/internal/HelperImpl.java b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/internal/HelperImpl.java index d78a9161a1..e33af152bc 100644 --- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/internal/HelperImpl.java +++ b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/internal/HelperImpl.java @@ -22,7 +22,6 @@ import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import org.apache.maven.api.annotations.Nullable; @@ -112,8 +111,7 @@ public class HelperImpl implements ExecutorHelper { } private Executor getExecutorByRequest(ExecutorRequest request) { - if (Objects.equals(request.command(), ExecutorRequest.MVN) - && request.environmentVariables().orElse(Collections.emptyMap()).isEmpty() + if (request.environmentVariables().orElse(Collections.emptyMap()).isEmpty() && request.jvmArguments().orElse(Collections.emptyList()).isEmpty()) { return getExecutor(Mode.EMBEDDED, request); } else { diff --git a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/MavenExecutorTestSupport.java b/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/MavenExecutorTestSupport.java index 0bf1b30f6a..42c6171a21 100644 --- a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/MavenExecutorTestSupport.java +++ b/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/MavenExecutorTestSupport.java @@ -35,6 +35,25 @@ import org.junit.jupiter.api.io.TempDir; import static org.junit.jupiter.api.Assertions.assertEquals; public abstract class MavenExecutorTestSupport { + @Test + void mvnenc( + @TempDir(cleanup = CleanupMode.ON_SUCCESS) Path cwd, + @TempDir(cleanup = CleanupMode.ON_SUCCESS) Path userHome) + throws Exception { + String logfile = "m4.log"; + execute( + cwd.resolve(logfile), + List.of(mvn4ExecutorRequestBuilder() + .command("mvnenc") + .cwd(cwd) + .userHomeDirectory(userHome) + .argument("diag") + .argument("-l") + .argument(logfile) + .build())); + System.out.println(Files.readString(cwd.resolve(logfile))); + } + @Disabled("JUnit on Windows fails to clean up as mvn3 seems does not close log file properly") @Test void dump3( diff --git a/its/core-it-suite/pom.xml b/its/core-it-suite/pom.xml index 87c8a91f5f..b236580ac0 100644 --- a/its/core-it-suite/pom.xml +++ b/its/core-it-suite/pom.xml @@ -715,7 +715,7 @@ under the License. <unzip dest="${mavenHome}" src="${project.build.directory}/maven-bin.zip"> <globmapper from="apache-maven-${mavenVersion}/*" handledirsep="true" to="*" /> </unzip> - <chmod dir="${mavenHome}/bin" includes="mvn,mvnDebug" perm="ugo+rx" /> + <chmod dir="${mavenHome}/bin" includes="mvn,mvnDebug,mvnenc" perm="ugo+rx" /> </target> </configuration> </execution> @@ -758,7 +758,7 @@ under the License. <unzip dest="${mavenHome}" src="${mavenDistro}"> <regexpmapper from="^([^/]+)/(.*)$" handledirsep="true" to="\2" /> </unzip> - <chmod dir="${mavenHome}/bin" includes="mvn,mvnDebug" perm="ugo+rx" /> + <chmod dir="${mavenHome}/bin" includes="mvn,mvnDebug,mvnenc" perm="ugo+rx" /> </target> </configuration> </execution> diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8421MavenEncryptionTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8421MavenEncryptionTest.java new file mode 100644 index 0000000000..8fdcffaf8e --- /dev/null +++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8421MavenEncryptionTest.java @@ -0,0 +1,73 @@ +/* + * 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. + */ +package org.apache.maven.it; + +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; + +/** + * This is a test set for <a href="https://issues.apache.org/jira/browse/MNG-8421">MNG-8421</a>. + */ +class MavenITmng8421MavenEncryptionTest extends AbstractMavenIntegrationTestCase { + + MavenITmng8421MavenEncryptionTest() { + super("[4.0.0-rc-2-SNAPSHOT,)"); + } + + /** + * Verify that empty home causes diag output as expected. + */ + @Test + void testEmptyHome() throws Exception { + Path basedir = extractResources("/mng-8421").getAbsoluteFile().toPath(); + + Path home = basedir.resolve("home1"); + + Verifier verifier = newVerifier(basedir.toString()); + verifier.setLogFileName("home1.txt"); + verifier.setUserHomeDirectory(home); + verifier.setExecutable("mvnenc"); + verifier.addCliArgument("diag"); + verifier.execute(); + verifier.verifyTextInLog("[ERROR]"); + verifier.verifyTextInLog("No configuration file found"); + verifier.verifyTextInLog("settings-security4.xml"); + } + + /** + * Verify that set-upo home causes diag output as expected. + */ + @Test + void testSetupHome() throws Exception { + Path basedir = extractResources("/mng-8421").getAbsoluteFile().toPath(); + + Path home = basedir.resolve("home2"); + + Verifier verifier = newVerifier(basedir.toString()); + verifier.setLogFileName("home2.txt"); + verifier.setUserHomeDirectory(home); + verifier.setExecutable("mvnenc"); + verifier.addCliArgument("diag"); + verifier.execute(); + verifier.verifyErrorFreeLog(); + verifier.verifyTextInLog("[INFO] Configuration validation of MavenSecDispatcher: VALID"); + verifier.verifyTextInLog("[WARNING] Configured environment variable not exist"); + } +} diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java b/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java index 79d20af271..ac5b592a86 100644 --- a/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java +++ b/its/core-it-suite/src/test/java/org/apache/maven/it/TestSuiteOrdering.java @@ -100,6 +100,7 @@ public class TestSuiteOrdering implements ClassOrderer { * the tests are to finishing. Newer tests are also more likely to fail, so this is * a fail fast technique as well. */ + suite.addTestSuite(MavenITmng8421MavenEncryptionTest.class); suite.addTestSuite(MavenITmng8400CanonicalMavenHomeTest.class); suite.addTestSuite(MavenITmng8385PropertyContributoSPITest.class); suite.addTestSuite(MavenITmng8383UnknownTypeDependenciesTest.class); diff --git a/its/core-it-suite/src/test/resources/mng-8421/home1/readme.txt b/its/core-it-suite/src/test/resources/mng-8421/home1/readme.txt new file mode 100644 index 0000000000..c33570fdcb --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-8421/home1/readme.txt @@ -0,0 +1 @@ +This is an empty home \ No newline at end of file diff --git a/its/core-it-suite/src/test/resources/mng-8421/home2/.m2/settings-security.xml b/its/core-it-suite/src/test/resources/mng-8421/home2/.m2/settings-security.xml new file mode 100644 index 0000000000..ee2e241583 --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-8421/home2/.m2/settings-security.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- +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. +--> + +<settingsSecurity> + <!-- created with Maven 3.9.9: "masterpassword" --> + <master>{biSS3+PaKIMH9acY9wBZjfuzSTrkkrXjgDa7jWvW+ew=}</master> +</settingsSecurity> \ No newline at end of file diff --git a/its/core-it-suite/src/test/resources/mng-8421/home2/.m2/settings-security4.xml b/its/core-it-suite/src/test/resources/mng-8421/home2/.m2/settings-security4.xml new file mode 100644 index 0000000000..a1b2a049ac --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-8421/home2/.m2/settings-security4.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- +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. +--> + +<settingsSecurity xmlns="http://codehaus-plexus.github.io/plexus-sec-dispatcher/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://codehaus-plexus.github.io/plexus-sec-dispatcher/4.0.0 https://codehaus-plexus.github.io/xsd/plexus-sec-dispatcher-4.0.0.xsd"> + <modelVersion>4.0</modelVersion> + <defaultDispatcher>master</defaultDispatcher> + <configurations> + <configuration> + <name>master</name> + <properties> + <property> + <name>source</name> + <value>env:MAVEN_MASTER_PASSWORD</value> + </property> + <property> + <name>cipher</name> + <value>AES/GCM/NoPadding</value> + </property> + </properties> + </configuration> + </configurations> +</settingsSecurity> diff --git a/its/core-it-suite/src/test/resources/mng-8421/home2/readme.txt b/its/core-it-suite/src/test/resources/mng-8421/home2/readme.txt new file mode 100644 index 0000000000..01f0e09e25 --- /dev/null +++ b/its/core-it-suite/src/test/resources/mng-8421/home2/readme.txt @@ -0,0 +1 @@ +This is fully setup home \ No newline at end of file diff --git a/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/it/Verifier.java b/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/it/Verifier.java index 1755bf14a1..7e74123d9f 100644 --- a/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/it/Verifier.java +++ b/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/it/Verifier.java @@ -92,7 +92,7 @@ public class Verifier { private final Path tempBasedir; // empty basedir for queries - private final Path userHomeDirectory; + private Path userHomeDirectory; private final List<String> defaultCliArguments; @@ -102,6 +102,8 @@ public class Verifier { private final List<String> cliArguments = new ArrayList<>(); + private String executable = ExecutorRequest.MVN; + private boolean autoClean = true; private boolean forkJvm = false; @@ -144,8 +146,16 @@ public class Verifier { } } + public void setUserHomeDirectory(Path userHomeDirectory) { + this.userHomeDirectory = requireNonNull(userHomeDirectory); + } + public String getExecutable() { - return ExecutorRequest.MVN; + return executable; + } + + public void setExecutable(String executable) { + this.executable = requireNonNull(executable); } public void execute() throws VerificationException { @@ -221,6 +231,7 @@ public class Verifier { try { ExecutorRequest.Builder builder = executorHelper .executorRequest() + .command(executable) .cwd(basedir) .userHomeDirectory(userHomeDirectory) .arguments(args);