You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2026/05/29 19:50:14 UTC
(maven) branch master updated: Feat: Pull out maven-executor into its own project (#12004)
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 15d19f2f62 Feat: Pull out maven-executor into its own project (#12004)
15d19f2f62 is described below
commit 15d19f2f623fc6e2e5489552913215f24e920c60
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri May 29 21:50:07 2026 +0200
Feat: Pull out maven-executor into its own project (#12004)
The main goal of `maven-executor` is ability to execute Maven 3/4 in "embedded" and "forked" mode, and has not related with Maven release lifecycle itself (and is dependency-less as well). So, let's move it out into own project.
https://github.com/apache/maven-executor
The new library executes Maven in:
* forked or embedded mode, but introduces other providers as well
* supports Maven 3 and 4
* the main `maven-executor` module is Java 8, dependency-less library (is MR-JAR, and on 9+ is modular and provides ToolProvider SPI integration as well)
---
.mvn/maven.config | 5 +-
impl/maven-executor/pom.xml | 149 ------
.../org/apache/maven/cling/executor/Executor.java | 75 ---
.../maven/cling/executor/ExecutorException.java | 51 --
.../maven/cling/executor/ExecutorHelper.java | 80 ----
.../maven/cling/executor/ExecutorRequest.java | 518 ---------------------
.../apache/maven/cling/executor/ExecutorTool.java | 74 ---
.../executor/embedded/EmbeddedMavenExecutor.java | 457 ------------------
.../cling/executor/forked/ForkedMavenExecutor.java | 226 ---------
.../maven/cling/executor/internal/HelperImpl.java | 102 ----
.../maven/cling/executor/internal/ToolboxTool.java | 170 -------
impl/maven-executor/src/site/site.xml | 35 --
.../apache/maven/cling/executor/Environment.java | 25 -
.../cling/executor/MavenExecutorTestSupport.java | 412 ----------------
.../embedded/EmbeddedMavenExecutorTest.java | 33 --
.../executor/forked/ForkedMavenExecutorTest.java | 33 --
.../maven/cling/executor/impl/ToolboxToolTest.java | 211 ---------
impl/pom.xml | 1 -
its/core-it-support/maven-it-helper/pom.xml | 2 +-
.../main/java/org/apache/maven/it/Verifier.java | 71 +--
its/pom.xml | 5 +-
21 files changed, 45 insertions(+), 2690 deletions(-)
diff --git a/.mvn/maven.config b/.mvn/maven.config
index caa8f5f80c..951ab8ff12 100644
--- a/.mvn/maven.config
+++ b/.mvn/maven.config
@@ -1 +1,4 @@
--DsessionRootDirectory=${session.rootDirectory}
+-D
+sessionRootDirectory=${session.rootDirectory}
+-D
+apache.snapshots
diff --git a/impl/maven-executor/pom.xml b/impl/maven-executor/pom.xml
deleted file mode 100644
index c4712962ce..0000000000
--- a/impl/maven-executor/pom.xml
+++ /dev/null
@@ -1,149 +0,0 @@
-<?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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.maven</groupId>
- <artifactId>maven-impl-modules</artifactId>
- <version>4.1.0-SNAPSHOT</version>
- </parent>
-
- <artifactId>maven-executor</artifactId>
-
- <name>Maven 4 Executor</name>
- <description>Maven 4 Executor, for executing Maven 3/4.</description>
-
- <properties>
- <maven3version>3.9.14</maven3version>
- <maven4version>${project.version}</maven4version>
- <testTmpDir>${project.build.directory}/tmp</testTmpDir>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.maven</groupId>
- <artifactId>maven-api-annotations</artifactId>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-api</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-params</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>eu.maveniverse.maven.mimir</groupId>
- <artifactId>testing</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>
- <exclusions>
- <exclusion>
- <groupId>*</groupId>
- <artifactId>*</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- <executions>
- <execution>
- <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>
- <phase>generate-test-resources</phase>
- <configuration>
- <artifactItems>
- <artifactItem>
- <groupId>org.apache.maven</groupId>
- <artifactId>apache-maven</artifactId>
- <version>${maven3version}</version>
- <classifier>bin</classifier>
- <type>zip</type>
- </artifactItem>
- </artifactItems>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
- <execution>
- <id>create-tmp-dir</id>
- <goals>
- <goal>run</goal>
- </goals>
- <phase>process-test-resources</phase>
- <configuration>
- <target>
- <mkdir dir="${testTmpDir}" />
- </target>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <promoteUserPropertiesToSystemProperties>false</promoteUserPropertiesToSystemProperties>
- <systemPropertyVariables>
- <maven3version>${maven3version}</maven3version>
- <maven4version>${maven4version}</maven4version>
- <maven3home>${project.build.directory}/dependency/apache-maven-${maven3version}</maven3home>
- <maven4home>${project.build.directory}/dependency/apache-maven-${maven4version}</maven4home>
- <localRepository>${settings.localRepository}</localRepository>
- </systemPropertyVariables>
- <argLine>-Xmx256m @{jacocoArgLine} -Djava.io.tmpdir=${testTmpDir}</argLine>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/Executor.java b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/Executor.java
deleted file mode 100644
index 80107a9b8c..0000000000
--- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/Executor.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.cling.executor;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Nonnull;
-
-/**
- * Defines the contract for a component responsible for executing a Maven tool
- * using the information provided in an {@link ExecutorRequest}. This interface is central
- * to the execution of Maven commands and builds, but it does not construct nor fully parses arguments.
- *
- * @since 4.0.0
- */
-@Experimental
-public interface Executor extends AutoCloseable {
- // Logic borrowed from Commons-Lang3
- boolean IS_WINDOWS = System.getProperty("os.name", "unknown").startsWith("Windows");
-
- /**
- * Maven version string returned when the actual version of Maven cannot be determined.
- */
- String UNKNOWN_VERSION = "unknown";
-
- /**
- * Invokes the tool application using the provided {@link ExecutorRequest}.
- * This method is responsible for executing the command or build
- * process based on the information contained in the request.
- *
- * @param executorRequest the request containing all necessary information for the execution
- * @return an integer representing the exit code of the execution (0 typically indicates success)
- * @throws ExecutorException if an error occurs during the execution process
- */
- int execute(@Nonnull ExecutorRequest executorRequest) throws ExecutorException;
-
- /**
- * Returns the Maven version that provided {@link ExecutorRequest} point at (would use). This
- * operation, depending on the underlying implementation, can be costly. If a caller uses this method often, it is
- * the caller's responsibility to properly cache returned values. (key can be {@link ExecutorRequest#installationDirectory()}.
- *
- * @param executorRequest the request containing all necessary information for the execution
- * @return a string representing the Maven version or {@link #UNKNOWN_VERSION}
- * @throws ExecutorException if an error occurs during the execution process
- */
- @Nonnull
- String mavenVersion(@Nonnull ExecutorRequest executorRequest) throws ExecutorException;
-
- /**
- * Closes and disposes of this {@link Executor} instance, releasing any resources it may hold.
- * This method is called automatically when using try-with-resources statements.
- *
- * <p>The default implementation does nothing. Subclasses should override this method
- * if they need to perform cleanup operations.</p>
- *
- * @throws ExecutorException if an error occurs while closing the {@link Executor}
- */
- @Override
- void close() throws ExecutorException;
-}
diff --git a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorException.java b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorException.java
deleted file mode 100644
index 8d8fbfde43..0000000000
--- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.cling.executor;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Nullable;
-
-/**
- * Represents an exception that occurs during the execution of a Maven build or command.
- * This exception is typically thrown when there are errors during the execution of a Maven
- * process, such as wrong cwd, non-existent installation directory, or other runtime issues.
- *
- * @since 4.0.0
- */
-@Experimental
-public class ExecutorException extends RuntimeException {
- /**
- * Constructs a new {@code InvokerException} with the specified detail message.
- *
- * @param message the detail message explaining the cause of the exception
- */
- public ExecutorException(@Nullable String message) {
- super(message);
- }
-
- /**
- * Constructs a new {@code InvokerException} with the specified detail message and cause.
- *
- * @param message the detail message explaining the cause of the exception
- * @param cause the underlying cause of the exception
- */
- public ExecutorException(@Nullable String message, @Nullable Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorHelper.java b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorHelper.java
deleted file mode 100644
index 8aea8b2a52..0000000000
--- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorHelper.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.cling.executor;
-
-import org.apache.maven.api.annotations.Nonnull;
-
-/**
- * Helper class for routing Maven execution based on preferences and/or issued execution requests.
- */
-public interface ExecutorHelper {
- /**
- * The modes of execution.
- */
- enum Mode {
- /**
- * Automatically decide. For example, presence of {@link ExecutorRequest#environmentVariables()} or
- * {@link ExecutorRequest#jvmArguments()} will result in choosing {@link #FORKED} executor. Otherwise,
- * {@link #EMBEDDED} executor is preferred.
- */
- AUTO,
- /**
- * Forces embedded execution. May fail if {@link ExecutorRequest} contains input unsupported by executor.
- */
- EMBEDDED,
- /**
- * Forces forked execution. Always carried out, most isolated and "most correct", but is slow as it uses child process.
- */
- FORKED
- }
-
- /**
- * Returns the preferred mode of this helper.
- */
- @Nonnull
- Mode getDefaultMode();
-
- /**
- * Creates pre-populated builder for {@link ExecutorRequest}. Users of helper must use this method to create
- * properly initialized request builder.
- */
- @Nonnull
- ExecutorRequest.Builder executorRequest();
-
- /**
- * Executes the request with preferred mode executor.
- */
- default int execute(ExecutorRequest executorRequest) throws ExecutorException {
- return execute(getDefaultMode(), executorRequest);
- }
-
- /**
- * Executes the request with passed in mode executor.
- */
- int execute(Mode mode, ExecutorRequest executorRequest) throws ExecutorException;
-
- /**
- * High level operation, returns the version of the Maven covered by this helper. This method call caches
- * underlying operation, and is safe to invoke as many times needed.
- *
- * @see Executor#mavenVersion(ExecutorRequest)
- */
- @Nonnull
- String mavenVersion();
-}
diff --git a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorRequest.java b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorRequest.java
deleted file mode 100644
index 1e7118f0b6..0000000000
--- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorRequest.java
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * 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.cling.executor;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Immutable;
-import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.annotations.Nullable;
-
-import static java.util.Objects.requireNonNull;
-
-/**
- * Represents a request to execute Maven with command-line arguments.
- * This interface encapsulates all the necessary information needed to execute
- * Maven command with arguments. The arguments are not parsed, they are just passed over
- * to executed tool.
- *
- * @since 4.0.0
- */
-@Immutable
-@Experimental
-public interface ExecutorRequest {
- /**
- * The Maven command.
- */
- String MVN = "mvn";
-
- /**
- * The command to execute, ie "mvn".
- */
- @Nonnull
- String command();
-
- /**
- * The immutable list of arguments to pass to the command.
- */
- @Nonnull
- List<String> arguments();
-
- /**
- * Returns the current working directory for the Maven execution.
- * This is typically the directory from which Maven was invoked.
- *
- * @return the current working directory path
- */
- @Nonnull
- Path cwd();
-
- /**
- * Returns the Maven installation directory.
- * This is usually set by the Maven launcher script using the "maven.home" system property.
- *
- * @return the Maven installation directory path
- */
- @Nonnull
- Path installationDirectory();
-
- /**
- * Returns the user's home directory.
- * This is typically obtained from the "user.home" system property.
- *
- * @return the user's home directory path
- */
- @Nonnull
- Path userHomeDirectory();
-
- /**
- * Returns the map of Java System Properties to set before executing process.
- *
- * @return an Optional containing the map of Java System Properties, or empty if not specified
- */
- @Nonnull
- Optional<Map<String, String>> jvmSystemProperties();
-
- /**
- * Returns the map of environment variables to set before executing process.
- * This property is used ONLY by executors that spawn a new JVM.
- *
- * @return an Optional containing the map of environment variables, or empty if not specified
- */
- @Nonnull
- Optional<Map<String, String>> environmentVariables();
-
- /**
- * Returns the list of extra JVM arguments to be passed to the forked process.
- * These arguments allow for customization of the JVM environment in which tool will run.
- * This property is used ONLY by executors that spawn a new JVM.
- *
- * @return an Optional containing the list of extra JVM arguments, or empty if not specified
- */
- @Nonnull
- Optional<List<String>> jvmArguments();
-
- /**
- * Optional provider for STD in of the Maven. If given, this provider will be piped into std input of
- * Maven.
- *
- * @return an Optional containing the stdin provider, or empty if not specified.
- */
- Optional<InputStream> stdIn();
-
- /**
- * Optional consumer for STD out of the Maven. If given, this consumer will get all output from the std out of
- * Maven. Note: whether consumer gets to consume anything depends on invocation arguments passed in
- * {@link #arguments()}, as if log file is set, not much will go to stdout.
- *
- * @return an Optional containing the stdout consumer, or empty if not specified.
- */
- Optional<OutputStream> stdOut();
-
- /**
- * Optional consumer for STD err of the Maven. If given, this consumer will get all output from the std err of
- * Maven. Note: whether consumer gets to consume anything depends on invocation arguments passed in
- * {@link #arguments()}, as if log file is set, not much will go to stderr.
- *
- * @return an Optional containing the stderr consumer, or empty if not specified.
- */
- Optional<OutputStream> stdErr();
-
- /**
- * Indicate if {@code ~/.mavenrc} should be skipped during execution.
- * <p>
- * Affected only for forked executor by adding MAVEN_SKIP_RC environment variable
- */
- boolean skipMavenRc();
-
- /**
- * Returns {@link Builder} created from this instance.
- */
- @Nonnull
- default Builder toBuilder() {
- return new Builder(
- command(),
- arguments(),
- cwd(),
- installationDirectory(),
- userHomeDirectory(),
- jvmSystemProperties().orElse(null),
- environmentVariables().orElse(null),
- jvmArguments().orElse(null),
- stdIn().orElse(null),
- stdOut().orElse(null),
- stdErr().orElse(null),
- skipMavenRc());
- }
-
- /**
- * Returns new builder pre-set to run Maven. The discovery of maven home is attempted, user cwd and home are
- * also discovered by standard means.
- */
- @Nonnull
- static Builder mavenBuilder(@Nullable Path installationDirectory) {
- return new Builder(
- MVN,
- null,
- getCanonicalPath(Paths.get(System.getProperty("user.dir"))),
- installationDirectory != null
- ? getCanonicalPath(installationDirectory)
- : discoverInstallationDirectory(),
- getCanonicalPath(Paths.get(System.getProperty("user.home"))),
- null,
- null,
- null,
- null,
- null,
- null,
- false);
- }
-
- class Builder {
- private String command;
- private List<String> arguments;
- private Path cwd;
- private Path installationDirectory;
- private Path userHomeDirectory;
- private Map<String, String> jvmSystemProperties;
- private Map<String, String> environmentVariables;
- private List<String> jvmArguments;
- private InputStream stdIn;
- private OutputStream stdOut;
- private OutputStream stdErr;
- private boolean skipMavenRc;
-
- private Builder() {}
-
- @SuppressWarnings("ParameterNumber")
- private Builder(
- String command,
- List<String> arguments,
- Path cwd,
- Path installationDirectory,
- Path userHomeDirectory,
- Map<String, String> jvmSystemProperties,
- Map<String, String> environmentVariables,
- List<String> jvmArguments,
- InputStream stdIn,
- OutputStream stdOut,
- OutputStream stdErr,
- boolean skipMavenRc) {
- this.command = command;
- this.arguments = arguments;
- this.cwd = cwd;
- this.installationDirectory = installationDirectory;
- this.userHomeDirectory = userHomeDirectory;
- this.jvmSystemProperties = jvmSystemProperties;
- this.environmentVariables = environmentVariables;
- this.jvmArguments = jvmArguments;
- this.stdIn = stdIn;
- this.stdOut = stdOut;
- this.stdErr = stdErr;
- this.skipMavenRc = skipMavenRc;
- }
-
- @Nonnull
- public Builder command(String command) {
- this.command = requireNonNull(command, "command");
- return this;
- }
-
- @Nonnull
- public Builder arguments(List<String> arguments) {
- this.arguments = requireNonNull(arguments, "arguments");
- return this;
- }
-
- @Nonnull
- public Builder argument(String argument) {
- if (arguments == null) {
- arguments = new ArrayList<>();
- }
- this.arguments.add(requireNonNull(argument, "argument"));
- return this;
- }
-
- @Nonnull
- public Builder cwd(Path cwd) {
- this.cwd = getCanonicalPath(requireNonNull(cwd, "cwd"));
- return this;
- }
-
- @Nonnull
- public Builder installationDirectory(Path installationDirectory) {
- this.installationDirectory =
- getCanonicalPath(requireNonNull(installationDirectory, "installationDirectory"));
- return this;
- }
-
- @Nonnull
- public Builder userHomeDirectory(Path userHomeDirectory) {
- this.userHomeDirectory = getCanonicalPath(requireNonNull(userHomeDirectory, "userHomeDirectory"));
- return this;
- }
-
- @Nonnull
- public Builder jvmSystemProperties(Map<String, String> jvmSystemProperties) {
- this.jvmSystemProperties = jvmSystemProperties;
- return this;
- }
-
- @Nonnull
- public Builder jvmSystemProperty(String key, String value) {
- requireNonNull(key, "env key");
- requireNonNull(value, "env value");
- if (jvmSystemProperties == null) {
- this.jvmSystemProperties = new HashMap<>();
- }
- this.jvmSystemProperties.put(key, value);
- return this;
- }
-
- @Nonnull
- public Builder environmentVariables(Map<String, String> environmentVariables) {
- this.environmentVariables = environmentVariables;
- return this;
- }
-
- @Nonnull
- public Builder environmentVariable(String key, String value) {
- requireNonNull(key, "env key");
- requireNonNull(value, "env value");
- if (environmentVariables == null) {
- this.environmentVariables = new HashMap<>();
- }
- this.environmentVariables.put(key, value);
- return this;
- }
-
- @Nonnull
- public Builder jvmArguments(List<String> jvmArguments) {
- this.jvmArguments = jvmArguments;
- return this;
- }
-
- @Nonnull
- public Builder jvmArgument(String jvmArgument) {
- if (jvmArguments == null) {
- jvmArguments = new ArrayList<>();
- }
- this.jvmArguments.add(requireNonNull(jvmArgument, "jvmArgument"));
- return this;
- }
-
- @Nonnull
- public Builder stdIn(InputStream stdIn) {
- this.stdIn = stdIn;
- return this;
- }
-
- @Nonnull
- public Builder stdOut(OutputStream stdOut) {
- this.stdOut = stdOut;
- return this;
- }
-
- @Nonnull
- public Builder stdErr(OutputStream stdErr) {
- this.stdErr = stdErr;
- return this;
- }
-
- @Nonnull
- public Builder skipMavenRc(boolean skipMavenRc) {
- this.skipMavenRc = skipMavenRc;
- return this;
- }
-
- @Nonnull
- public ExecutorRequest build() {
- return new Impl(
- command,
- arguments,
- cwd,
- installationDirectory,
- userHomeDirectory,
- jvmSystemProperties,
- environmentVariables,
- jvmArguments,
- stdIn,
- stdOut,
- stdErr,
- skipMavenRc);
- }
-
- private static class Impl implements ExecutorRequest {
- private final String command;
- private final List<String> arguments;
- private final Path cwd;
- private final Path installationDirectory;
- private final Path userHomeDirectory;
- private final Map<String, String> jvmSystemProperties;
- private final Map<String, String> environmentVariables;
- private final List<String> jvmArguments;
- private final InputStream stdIn;
- private final OutputStream stdOut;
- private final OutputStream stdErr;
- private final boolean skipMavenRc;
-
- @SuppressWarnings("ParameterNumber")
- private Impl(
- String command,
- List<String> arguments,
- Path cwd,
- Path installationDirectory,
- Path userHomeDirectory,
- Map<String, String> jvmSystemProperties,
- Map<String, String> environmentVariables,
- List<String> jvmArguments,
- InputStream stdIn,
- OutputStream stdOut,
- OutputStream stdErr,
- boolean skipMavenRc) {
- this.command = requireNonNull(command);
- this.arguments = arguments == null ? List.of() : List.copyOf(arguments);
- this.cwd = getCanonicalPath(requireNonNull(cwd));
- this.installationDirectory = getCanonicalPath(requireNonNull(installationDirectory));
- this.userHomeDirectory = getCanonicalPath(requireNonNull(userHomeDirectory));
- this.jvmSystemProperties = jvmSystemProperties != null && !jvmSystemProperties.isEmpty()
- ? Map.copyOf(jvmSystemProperties)
- : null;
- this.environmentVariables = environmentVariables != null && !environmentVariables.isEmpty()
- ? Map.copyOf(environmentVariables)
- : null;
- this.jvmArguments = jvmArguments != null && !jvmArguments.isEmpty() ? List.copyOf(jvmArguments) : null;
- this.stdIn = stdIn;
- this.stdOut = stdOut;
- this.stdErr = stdErr;
- this.skipMavenRc = skipMavenRc;
- }
-
- @Override
- public String command() {
- return command;
- }
-
- @Override
- public List<String> arguments() {
- return arguments;
- }
-
- @Override
- public Path cwd() {
- return cwd;
- }
-
- @Override
- public Path installationDirectory() {
- return installationDirectory;
- }
-
- @Override
- public Path userHomeDirectory() {
- return userHomeDirectory;
- }
-
- @Override
- public Optional<Map<String, String>> jvmSystemProperties() {
- return Optional.ofNullable(jvmSystemProperties);
- }
-
- @Override
- public Optional<Map<String, String>> environmentVariables() {
- return Optional.ofNullable(environmentVariables);
- }
-
- @Override
- public Optional<List<String>> jvmArguments() {
- return Optional.ofNullable(jvmArguments);
- }
-
- @Override
- public Optional<InputStream> stdIn() {
- return Optional.ofNullable(stdIn);
- }
-
- @Override
- public Optional<OutputStream> stdOut() {
- return Optional.ofNullable(stdOut);
- }
-
- @Override
- public Optional<OutputStream> stdErr() {
- return Optional.ofNullable(stdErr);
- }
-
- @Override
- public boolean skipMavenRc() {
- return skipMavenRc;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "{" + "command='"
- + command + '\'' + ", arguments="
- + arguments + ", cwd="
- + cwd + ", installationDirectory="
- + installationDirectory + ", userHomeDirectory="
- + userHomeDirectory + ", jvmSystemProperties="
- + jvmSystemProperties + ", environmentVariables="
- + environmentVariables + ", jvmArguments="
- + jvmArguments + ", stdinProvider="
- + stdIn + ", stdoutConsumer="
- + stdOut + ", stderrConsumer="
- + stdErr + ", skipMavenRc="
- + skipMavenRc + "}";
- }
- }
- }
-
- @Nonnull
- static Path discoverInstallationDirectory() {
- String mavenHome = System.getProperty("maven.home");
- if (mavenHome == null) {
- throw new ExecutorException("requires maven.home Java System Property set");
- }
- return getCanonicalPath(Paths.get(mavenHome));
- }
-
- @Nonnull
- static Path discoverUserHomeDirectory() {
- String userHome = System.getProperty("user.home");
- if (userHome == null) {
- throw new ExecutorException("requires user.home Java System Property set");
- }
- return getCanonicalPath(Paths.get(userHome));
- }
-
- @Nonnull
- static Path getCanonicalPath(Path path) {
- requireNonNull(path, "path");
- return path.toAbsolutePath().normalize();
- }
-}
diff --git a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorTool.java b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorTool.java
deleted file mode 100644
index 4a9776742f..0000000000
--- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/ExecutorTool.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.cling.executor;
-
-import java.util.Map;
-
-import org.apache.maven.api.annotations.Nullable;
-
-/**
- * A tool implementing some common Maven operations.
- */
-public interface ExecutorTool {
- /**
- * Performs a diagnostic dump of the environment.
- *
- * @param request never {@code null}
- */
- Map<String, String> dump(ExecutorRequest.Builder request) throws ExecutorException;
-
- /**
- * Returns the location of local repository, as detected by Maven. The {@code userSettings} param may contain
- * some override (equivalent of {@code -s settings.xml} on CLI).
- *
- * @param request never {@code null}
- */
- String localRepository(ExecutorRequest.Builder request) throws ExecutorException;
-
- /**
- * Returns relative (to {@link #localRepository(ExecutorRequest.Builder)}) path of given artifact in local repository.
- *
- * @param request never {@code null}
- * @param gav the usual resolver artifact GAV string, never {@code null}
- * @param repositoryId the remote repository ID in case "remote artifact" is asked for
- */
- String artifactPath(ExecutorRequest.Builder request, String gav, @Nullable String repositoryId)
- throws ExecutorException;
-
- /**
- * Returns relative (to {@link #localRepository(ExecutorRequest.Builder)}) path of given metadata in local repository.
- * The metadata coordinates in form of {@code [G]:[A]:[V]:[type]}. Absence of {@code A} implies absence of {@code V}
- * as well (in other words, it can be {@code G}, {@code G:A} or {@code G:A:V}). The absence of {@code type} implies
- * it is "maven-metadata.xml". The simplest spec string is {@code :::}.
- * <p>
- * Examples:
- * <ul>
- * <li>{@code :::} is root metadata named "maven-metadata.xml"</li>
- * <li>{@code :::my-metadata.xml} is root metadata named "my-metadata.xml"</li>
- * <li>{@code G:::} equals to {@code G:::maven-metadata.xml}</li>
- * <li>{@code G:A::} equals to {@code G:A::maven-metadata.xml}</li>
- * </ul>
- *
- * @param request never {@code null}
- * @param gav the resolver metadata GAV string
- * @param repositoryId the remote repository ID in case "remote metadata" is asked for
- */
- String metadataPath(ExecutorRequest.Builder request, String gav, @Nullable String repositoryId)
- throws ExecutorException;
-}
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
deleted file mode 100644
index 0e2ddaa4f6..0000000000
--- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutor.java
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * 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.cling.executor.embedded;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Function;
-import java.util.stream.Stream;
-
-import org.apache.maven.cling.executor.Executor;
-import org.apache.maven.cling.executor.ExecutorException;
-import org.apache.maven.cling.executor.ExecutorRequest;
-
-import static java.util.Objects.requireNonNull;
-
-/**
- * Embedded executor implementation, that invokes Maven from installation directory within this same JVM but in isolated
- * classloader. This class supports Maven 4.x and Maven 3.x as well. The ClassWorld of Maven is kept in memory as
- * long as instance of this class is not closed. Subsequent execution requests over same installation home are cached.
- */
-public class EmbeddedMavenExecutor implements Executor {
- /**
- * Maven4 supports multiple commands from same installation directory.
- */
- protected static final Map<String, String> MVN4_MAIN_CLASSES = Map.of(
- "mvn",
- "org.apache.maven.cling.MavenCling",
- "mvnenc",
- "org.apache.maven.cling.MavenEncCling",
- "mvnsh",
- "org.apache.maven.cling.MavenShellCling");
-
- /**
- * Context holds things loaded up from given Maven Installation Directory.
- */
- protected static final class Context {
- private final URLClassLoader bootClassLoader;
- private final String version;
- private final Object classWorld;
- private final Set<String> originalClassRealmIds;
- private final ClassLoader tccl;
- private final Map<String, Function<ExecutorRequest, Integer>> commands; // the commands
- private final Collection<Object> keepAlive; // refs things to make sure no GC takes it away
-
- private Context(
- URLClassLoader bootClassLoader,
- String version,
- Object classWorld,
- Set<String> originalClassRealmIds,
- ClassLoader tccl,
- Map<String, Function<ExecutorRequest, Integer>> commands,
- Collection<Object> keepAlive) {
- this.bootClassLoader = bootClassLoader;
- this.version = version;
- this.classWorld = classWorld;
- this.originalClassRealmIds = originalClassRealmIds;
- this.tccl = tccl;
- this.commands = commands;
- this.keepAlive = keepAlive;
- }
- }
-
- protected final boolean cacheContexts;
- protected final boolean useMavenArgsEnv;
- protected final AtomicBoolean closed;
- protected final InputStream originalStdin;
- protected final PrintStream originalStdout;
- protected final PrintStream originalStderr;
- protected final Properties originalProperties;
- protected final ClassLoader originalClassLoader;
- protected final ConcurrentHashMap<Path, Context> contexts;
-
- public EmbeddedMavenExecutor() {
- this(true, true);
- }
-
- public EmbeddedMavenExecutor(boolean cacheContexts, boolean useMavenArgsEnv) {
- this.cacheContexts = cacheContexts;
- this.useMavenArgsEnv = useMavenArgsEnv;
- this.closed = new AtomicBoolean(false);
- this.originalStdin = System.in;
- this.originalStdout = System.out;
- this.originalStderr = System.err;
- this.originalClassLoader = Thread.currentThread().getContextClassLoader();
- this.contexts = new ConcurrentHashMap<>();
- this.originalProperties = new Properties();
- this.originalProperties.putAll(System.getProperties());
- }
-
- @Override
- public int execute(ExecutorRequest executorRequest) throws ExecutorException {
- requireNonNull(executorRequest);
- if (closed.get()) {
- throw new ExecutorException("Executor is closed");
- }
- validate(executorRequest);
- Context context = mayCreate(executorRequest);
- String command = executorRequest.command();
- Function<ExecutorRequest, Integer> exec = context.commands.get(command);
- if (exec == null) {
- throw new IllegalArgumentException(
- "Unknown command: '" + command + "' for '" + executorRequest.installationDirectory() + "'");
- }
-
- Thread.currentThread().setContextClassLoader(context.tccl);
- try {
- return exec.apply(executorRequest);
- } catch (Exception e) {
- throw new ExecutorException("Failed to execute", e);
- } finally {
- try {
- disposeRuntimeCreatedRealms(context);
- } finally {
- System.setIn(originalStdin);
- System.setOut(originalStdout);
- System.setErr(originalStderr);
- Thread.currentThread().setContextClassLoader(originalClassLoader);
- System.setProperties(originalProperties);
- if (!cacheContexts) {
- doClose(context);
- }
- }
- }
- }
-
- /**
- * Unloads dynamically loaded things, like extensions created realms. Makes sure we go back to "initial state".
- */
- protected void disposeRuntimeCreatedRealms(Context context) {
- try {
- Method getRealms = context.classWorld.getClass().getMethod("getRealms");
- Method disposeRealm = context.classWorld.getClass().getMethod("disposeRealm", String.class);
- List<Object> realms = (List<Object>) getRealms.invoke(context.classWorld);
- for (Object realm : realms) {
- String realmId = (String) realm.getClass().getMethod("getId").invoke(realm);
- if (!context.originalClassRealmIds.contains(realmId)) {
- disposeRealm.invoke(context.classWorld, realmId);
- }
- }
- } catch (Exception e) {
- throw new ExecutorException("Failed to dispose runtime created realms", e);
- }
- }
-
- @Override
- public String mavenVersion(ExecutorRequest executorRequest) throws ExecutorException {
- requireNonNull(executorRequest);
- if (closed.get()) {
- throw new ExecutorException("Executor is closed");
- }
- validate(executorRequest);
- return mayCreate(executorRequest).version;
- }
-
- protected Context mayCreate(ExecutorRequest executorRequest) {
- Path mavenHome = ExecutorRequest.getCanonicalPath(executorRequest.installationDirectory());
- if (cacheContexts) {
- return contexts.computeIfAbsent(mavenHome, k -> doCreate(mavenHome, executorRequest));
- } else {
- return doCreate(mavenHome, executorRequest);
- }
- }
-
- protected Context doCreate(Path mavenHome, ExecutorRequest executorRequest) {
- if (!Files.isDirectory(mavenHome)) {
- throw new IllegalArgumentException("Installation directory must point to existing directory: " + mavenHome);
- }
- if (!MVN4_MAIN_CLASSES.containsKey(executorRequest.command())) {
- throw new IllegalArgumentException(
- getClass().getSimpleName() + " does not support command " + executorRequest.command());
- }
- if (executorRequest.environmentVariables().isPresent()) {
- throw new IllegalArgumentException(getClass().getSimpleName() + " does not support environment variables: "
- + executorRequest.environmentVariables().get());
- }
- if (executorRequest.jvmArguments().isPresent()) {
- throw new IllegalArgumentException(getClass().getSimpleName() + " does not support jvmArguments: "
- + executorRequest.jvmArguments().get());
- }
- 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: " + mavenHome);
- }
-
- ArrayList<String> mavenArgs = new ArrayList<>();
- String mavenArgsEnv = System.getenv("MAVEN_ARGS");
- if (useMavenArgsEnv && mavenArgsEnv != null && !mavenArgsEnv.isEmpty()) {
- Arrays.stream(mavenArgsEnv.split(" "))
- .filter(s -> !s.trim().isEmpty())
- .forEach(s -> mavenArgs.add(0, s));
- }
-
- Properties properties = prepareProperties(executorRequest);
- // set ahead of time, if the mavenHome points to Maven4, as ClassWorld Launcher needs this property
- properties.setProperty(
- "maven.mainClass", requireNonNull(MVN4_MAIN_CLASSES.get(ExecutorRequest.MVN), "mainClass"));
- System.setProperties(properties);
- URLClassLoader bootClassLoader = createMavenBootClassLoader(boot, Collections.emptyList());
- Thread.currentThread().setContextClassLoader(bootClassLoader);
- try {
- Class<?> launcherClass = bootClassLoader.loadClass("org.codehaus.plexus.classworlds.launcher.Launcher");
- Object launcher = launcherClass.getDeclaredConstructor().newInstance();
- Method configure = launcherClass.getMethod("configure", InputStream.class);
- try (InputStream inputStream = Files.newInputStream(m2conf)) {
- configure.invoke(launcher, inputStream);
- }
- Object classWorld = launcherClass.getMethod("getWorld").invoke(launcher);
- Set<String> originalClassRealmIds = new HashSet<>();
-
- // collect pre-created (in m2.conf) class realms as "original ones"; the rest are created at runtime
- Method getRealms = classWorld.getClass().getMethod("getRealms");
- List<Object> realms = (List<Object>) getRealms.invoke(classWorld);
- for (Object realm : realms) {
- Method realmGetId = realm.getClass().getMethod("getId");
- originalClassRealmIds.add((String) realmGetId.invoke(realm));
- }
-
- Class<?> cliClass =
- (Class<?>) launcherClass.getMethod("getMainClass").invoke(launcher);
- String version = getMavenVersion(cliClass);
- Map<String, Function<ExecutorRequest, Integer>> commands = new HashMap<>();
- ArrayList<Object> keepAlive = new ArrayList<>();
-
- 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());
- }
- // 3.9.x
- mayAddToKeepAlive(keepAlive, cliClass, "org.fusesource.jansi.internal.JansiLoader");
- // 3.10.x
- mayAddToKeepAlive(keepAlive, cliClass, "org.jline.nativ.JLineNativeLoader");
-
- Constructor<?> newMavenCli = cliClass.getConstructor(classWorld.getClass());
- Object mavenCli = newMavenCli.newInstance(classWorld);
- Class<?>[] parameterTypes = {String[].class, String.class, PrintStream.class, PrintStream.class};
- Method doMain = cliClass.getMethod("doMain", parameterTypes);
- commands.put(ExecutorRequest.MVN, r -> {
- System.setProperties(prepareProperties(r));
- try {
- ArrayList<String> args = new ArrayList<>(mavenArgs);
- args.addAll(r.arguments());
- PrintStream stdout = r.stdOut().isEmpty()
- ? null
- : new PrintStream(r.stdOut().orElseThrow(), true);
- PrintStream stderr = r.stdErr().isEmpty()
- ? null
- : new PrintStream(r.stdErr().orElseThrow(), true);
- return (int) doMain.invoke(mavenCli, new Object[] {
- args.toArray(new String[0]), r.cwd().toString(), stdout, stderr
- });
- } catch (Exception e) {
- throw new ExecutorException("Failed to execute", e);
- }
- });
- } else {
- // assume 4.x
- mayAddToKeepAlive(keepAlive, cliClass, "org.jline.nativ.JLineNativeLoader");
- for (Map.Entry<String, String> cmdEntry : MVN4_MAIN_CLASSES.entrySet()) {
- Class<?> cmdClass = cliClass.getClassLoader().loadClass(cmdEntry.getValue());
- Method mainMethod = cmdClass.getMethod(
- "main",
- String[].class,
- classWorld.getClass(),
- InputStream.class,
- OutputStream.class,
- OutputStream.class);
- commands.put(cmdEntry.getKey(), r -> {
- System.setProperties(prepareProperties(r));
- try {
- ArrayList<String> args = new ArrayList<>(mavenArgs);
- args.addAll(r.arguments());
- return (int) mainMethod.invoke(
- null,
- args.toArray(new String[0]),
- classWorld,
- r.stdIn().orElse(null),
- r.stdOut().orElse(null),
- r.stdErr().orElse(null));
- } catch (Exception e) {
- throw new ExecutorException("Failed to execute", e);
- }
- });
- }
- }
-
- return new Context(
- bootClassLoader,
- version,
- classWorld,
- originalClassRealmIds,
- cliClass.getClassLoader(),
- commands,
- keepAlive);
- } catch (Exception e) {
- throw new ExecutorException("Failed to create executor", e);
- } finally {
- Thread.currentThread().setContextClassLoader(originalClassLoader);
- System.setProperties(originalProperties);
- }
- }
-
- private boolean mayAddToKeepAlive(List<Object> keepAlive, Class<?> cliClass, String className) {
- try {
- keepAlive.add(cliClass.getClassLoader().loadClass(className));
- return true;
- } catch (ClassNotFoundException e) {
- return false;
- }
- }
-
- protected Properties prepareProperties(ExecutorRequest request) {
- System.setProperties(null); // this "inits" them!
-
- Properties properties = new Properties();
- properties.putAll(System.getProperties()); // get mandatory/expected init-ed above
-
- properties.setProperty("user.dir", request.cwd().toString());
- properties.setProperty("user.home", request.userHomeDirectory().toString());
-
- Path mavenHome = request.installationDirectory();
- properties.setProperty("maven.home", mavenHome.toString());
- properties.setProperty(
- "maven.multiModuleProjectDirectory", request.cwd().toString());
-
- // Maven 3.x
- properties.setProperty(
- "library.jansi.path", mavenHome.resolve("lib/jansi-native").toString());
-
- // Maven 4.x
- properties.setProperty(
- "library.jline.path", mavenHome.resolve("lib/jline-native").toString());
-
- if (request.jvmSystemProperties().isPresent()) {
- properties.putAll(request.jvmSystemProperties().get());
- }
-
- return properties;
- }
-
- @Override
- public void close() throws ExecutorException {
- if (closed.compareAndExchange(false, true)) {
- try {
- ArrayList<Exception> exceptions = new ArrayList<>();
- for (Context context : contexts.values()) {
- try {
- doClose(context);
- } catch (Exception e) {
- exceptions.add(e);
- }
- }
- if (!exceptions.isEmpty()) {
- ExecutorException e = new ExecutorException("Could not close cleanly");
- exceptions.forEach(e::addSuppressed);
- throw e;
- }
- } finally {
- System.setProperties(originalProperties);
- }
- }
- }
-
- protected void doClose(Context context) throws ExecutorException {
- Thread.currentThread().setContextClassLoader(context.bootClassLoader);
- try {
- try {
- ((Closeable) context.classWorld).close();
- } finally {
- context.bootClassLoader.close();
- }
- } catch (Exception e) {
- throw new ExecutorException("Failed to close cleanly", e);
- } finally {
- Thread.currentThread().setContextClassLoader(originalClassLoader);
- }
- }
-
- protected void validate(ExecutorRequest executorRequest) throws ExecutorException {}
-
- protected URLClassLoader createMavenBootClassLoader(Path boot, List<URL> extraClasspath) {
- ArrayList<URL> urls = new ArrayList<>(extraClasspath);
- try (Stream<Path> stream = Files.list(boot)) {
- stream.filter(Files::isRegularFile)
- .filter(p -> p.toString().endsWith(".jar"))
- .forEach(f -> {
- try {
- urls.add(f.toUri().toURL());
- } catch (MalformedURLException e) {
- throw new ExecutorException("Failed to build classpath: " + f, e);
- }
- });
- } catch (IOException e) {
- throw new ExecutorException("Failed to build classpath: " + e, e);
- }
- if (urls.isEmpty()) {
- throw new IllegalArgumentException("Invalid Maven home directory; boot is empty");
- }
- return new URLClassLoader(
- urls.toArray(new URL[0]), ClassLoader.getSystemClassLoader().getParent());
- }
-
- protected String getMavenVersion(Class<?> clazz) throws IOException {
- Properties props = new Properties();
- try (InputStream is = clazz.getResourceAsStream("/META-INF/maven/org.apache.maven/maven-core/pom.properties")) {
- if (is != null) {
- props.load(is);
- }
- String version = props.getProperty("version");
- if (version != null) {
- return version;
- }
- return UNKNOWN_VERSION;
- }
- }
-}
diff --git a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/forked/ForkedMavenExecutor.java b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/forked/ForkedMavenExecutor.java
deleted file mode 100644
index 4671c74276..0000000000
--- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/forked/ForkedMavenExecutor.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * 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.cling.executor.forked;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UncheckedIOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.maven.cling.executor.Executor;
-import org.apache.maven.cling.executor.ExecutorException;
-import org.apache.maven.cling.executor.ExecutorRequest;
-
-import static java.util.Objects.requireNonNull;
-import static org.apache.maven.cling.executor.ExecutorRequest.getCanonicalPath;
-
-/**
- * Forked executor implementation, that spawns a subprocess with Maven from the installation directory. Very costly
- * but provides the best isolation.
- */
-public class ForkedMavenExecutor implements Executor {
- protected final boolean useMavenArgsEnv;
- protected final AtomicBoolean closed;
-
- public ForkedMavenExecutor() {
- this(true);
- }
-
- public ForkedMavenExecutor(boolean useMavenArgsEnv) {
- this.useMavenArgsEnv = useMavenArgsEnv;
- this.closed = new AtomicBoolean(false);
- }
-
- @Override
- public int execute(ExecutorRequest executorRequest) throws ExecutorException {
- requireNonNull(executorRequest);
- if (closed.get()) {
- throw new ExecutorException("Executor is closed");
- }
- validate(executorRequest);
-
- return doExecute(executorRequest);
- }
-
- @Override
- public String mavenVersion(ExecutorRequest executorRequest) throws ExecutorException {
- requireNonNull(executorRequest);
- if (closed.get()) {
- throw new ExecutorException("Executor is closed");
- }
- validate(executorRequest);
- try {
- Path cwd = Files.createTempDirectory("forked-executor-maven-version");
- try {
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- int exitCode = execute(executorRequest.toBuilder()
- .cwd(cwd)
- .arguments(List.of("--version", "--quiet"))
- .stdOut(stdout)
- .build());
- if (exitCode == 0) {
- if (stdout.size() > 0) {
- return stdout.toString()
- .replace("\n", "")
- .replace("\r", "")
- .trim();
- }
- return UNKNOWN_VERSION;
- } else {
- throw new ExecutorException(
- "Maven version query unexpected exitCode=" + exitCode + "\nLog: " + stdout);
- }
- } finally {
- Files.deleteIfExists(cwd);
- }
- } catch (IOException e) {
- throw new ExecutorException("Failed to determine maven version", e);
- }
- }
-
- protected void validate(ExecutorRequest executorRequest) throws ExecutorException {}
-
- protected int doExecute(ExecutorRequest executorRequest) throws ExecutorException {
- ArrayList<String> cmdAndArguments = new ArrayList<>();
- cmdAndArguments.add(executorRequest
- .installationDirectory()
- .resolve("bin")
- .resolve(IS_WINDOWS ? executorRequest.command() + ".cmd" : executorRequest.command())
- .toString());
-
- String mavenArgsEnv = System.getenv("MAVEN_ARGS");
- if (useMavenArgsEnv && mavenArgsEnv != null && !mavenArgsEnv.isEmpty()) {
- Arrays.stream(mavenArgsEnv.split(" "))
- .filter(s -> !s.trim().isEmpty())
- .forEach(cmdAndArguments::add);
- }
-
- cmdAndArguments.addAll(executorRequest.arguments());
-
- ArrayList<String> jvmArgs = new ArrayList<>();
- if (!executorRequest.userHomeDirectory().equals(getCanonicalPath(Paths.get(System.getProperty("user.home"))))) {
- jvmArgs.add("-Duser.home=" + executorRequest.userHomeDirectory().toString());
- }
- if (executorRequest.jvmArguments().isPresent()) {
- jvmArgs.addAll(executorRequest.jvmArguments().get());
- }
- if (executorRequest.jvmSystemProperties().isPresent()) {
- jvmArgs.addAll(executorRequest.jvmSystemProperties().get().entrySet().stream()
- .map(e -> "-D" + e.getKey() + "=" + e.getValue())
- .toList());
- }
-
- HashMap<String, String> env = new HashMap<>();
- if (executorRequest.environmentVariables().isPresent()) {
- env.putAll(executorRequest.environmentVariables().get());
- }
- if (!jvmArgs.isEmpty()) {
- String mavenOpts = env.getOrDefault("MAVEN_OPTS", "");
- if (!mavenOpts.isEmpty()) {
- mavenOpts += " ";
- }
- mavenOpts += String.join(" ", jvmArgs);
- env.put("MAVEN_OPTS", mavenOpts);
- }
- env.remove("MAVEN_ARGS"); // we already used it if configured to do so
-
- if (executorRequest.skipMavenRc()) {
- env.put("MAVEN_SKIP_RC", "true");
- }
-
- try {
- ProcessBuilder pb = new ProcessBuilder()
- .directory(executorRequest.cwd().toFile())
- .command(cmdAndArguments);
- if (!env.isEmpty()) {
- pb.environment().putAll(env);
- }
-
- Process process = pb.start();
- pump(process, executorRequest).await();
- return process.waitFor();
- } catch (IOException e) {
- throw new ExecutorException("IO problem while executing command: " + cmdAndArguments, e);
- } catch (InterruptedException e) {
- throw new ExecutorException("Interrupted while executing command: " + cmdAndArguments, e);
- }
- }
-
- protected CountDownLatch pump(Process p, ExecutorRequest executorRequest) {
- CountDownLatch latch = new CountDownLatch(3);
- String suffix = "-pump-" + p.pid();
- Thread stdoutPump = new Thread(() -> {
- try {
- OutputStream stdout = executorRequest.stdOut().orElse(OutputStream.nullOutputStream());
- p.getInputStream().transferTo(stdout);
- stdout.flush();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- } finally {
- latch.countDown();
- }
- });
- stdoutPump.setName("stdout" + suffix);
- stdoutPump.start();
- Thread stderrPump = new Thread(() -> {
- try {
- OutputStream stderr = executorRequest.stdErr().orElse(OutputStream.nullOutputStream());
- p.getErrorStream().transferTo(stderr);
- stderr.flush();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- } finally {
- latch.countDown();
- }
- });
- stderrPump.setName("stderr" + suffix);
- stderrPump.start();
- Thread stdinPump = new Thread(() -> {
- try {
- OutputStream in = p.getOutputStream();
- executorRequest.stdIn().orElse(InputStream.nullInputStream()).transferTo(in);
- in.flush();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- } finally {
- latch.countDown();
- }
- });
- stdinPump.setName("stdin" + suffix);
- stdinPump.start();
- return latch;
- }
-
- @Override
- public void close() throws ExecutorException {
- if (closed.compareAndExchange(false, true)) {
- // nothing yet
- }
- }
-}
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
deleted file mode 100644
index d8109ba3e2..0000000000
--- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/internal/HelperImpl.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.cling.executor.internal;
-
-import java.nio.file.Path;
-import java.util.HashMap;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.maven.api.annotations.Nullable;
-import org.apache.maven.cling.executor.Executor;
-import org.apache.maven.cling.executor.ExecutorException;
-import org.apache.maven.cling.executor.ExecutorHelper;
-import org.apache.maven.cling.executor.ExecutorRequest;
-
-import static java.util.Objects.requireNonNull;
-
-/**
- * Simple router to executors, and delegate to executor tool.
- */
-public class HelperImpl implements ExecutorHelper {
- private final Mode defaultMode;
- private final Path installationDirectory;
- private final Path userHomeDirectory;
- private final HashMap<Mode, Executor> executors;
-
- private final ConcurrentHashMap<String, String> cache;
-
- public HelperImpl(
- Mode defaultMode,
- @Nullable Path installationDirectory,
- @Nullable Path userHomeDirectory,
- Executor embedded,
- Executor forked) {
- this.defaultMode = requireNonNull(defaultMode);
- this.installationDirectory = installationDirectory != null
- ? ExecutorRequest.getCanonicalPath(installationDirectory)
- : ExecutorRequest.discoverInstallationDirectory();
- this.userHomeDirectory = userHomeDirectory != null
- ? ExecutorRequest.getCanonicalPath(userHomeDirectory)
- : ExecutorRequest.discoverUserHomeDirectory();
- this.executors = new HashMap<>();
-
- this.executors.put(Mode.EMBEDDED, requireNonNull(embedded, "embedded"));
- this.executors.put(Mode.FORKED, requireNonNull(forked, "forked"));
- this.cache = new ConcurrentHashMap<>();
- }
-
- @Override
- public Mode getDefaultMode() {
- return defaultMode;
- }
-
- @Override
- public ExecutorRequest.Builder executorRequest() {
- return ExecutorRequest.mavenBuilder(installationDirectory).userHomeDirectory(userHomeDirectory);
- }
-
- @Override
- public int execute(Mode mode, ExecutorRequest executorRequest) throws ExecutorException {
- return getExecutor(mode, executorRequest).execute(executorRequest);
- }
-
- @Override
- public String mavenVersion() {
- return cache.computeIfAbsent("maven.version", k -> {
- ExecutorRequest request = executorRequest().build();
- return getExecutor(Mode.AUTO, request).mavenVersion(request);
- });
- }
-
- protected Executor getExecutor(Mode mode, ExecutorRequest request) throws ExecutorException {
- return switch (mode) {
- case AUTO -> getExecutorByRequest(request);
- case EMBEDDED -> executors.get(Mode.EMBEDDED);
- case FORKED -> executors.get(Mode.FORKED);
- };
- }
-
- private Executor getExecutorByRequest(ExecutorRequest request) {
- if (request.environmentVariables().isEmpty() && request.jvmArguments().isEmpty()) {
- return getExecutor(Mode.EMBEDDED, request);
- } else {
- return getExecutor(Mode.FORKED, request);
- }
- }
-}
diff --git a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/internal/ToolboxTool.java b/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/internal/ToolboxTool.java
deleted file mode 100644
index 2adc21c438..0000000000
--- a/impl/maven-executor/src/main/java/org/apache/maven/cling/executor/internal/ToolboxTool.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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.cling.executor.internal;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.stream.Collectors;
-
-import org.apache.maven.cling.executor.ExecutorException;
-import org.apache.maven.cling.executor.ExecutorHelper;
-import org.apache.maven.cling.executor.ExecutorRequest;
-import org.apache.maven.cling.executor.ExecutorTool;
-
-import static java.util.Objects.requireNonNull;
-
-/**
- * {@link ExecutorTool} implementation based on Maveniverse Toolbox. It uses Toolbox mojos to implement all the
- * required operations.
- *
- * @see <a href="https://github.com/maveniverse/toolbox">Maveniverse Toolbox</a>
- */
-public class ToolboxTool implements ExecutorTool {
- private static final String TOOLBOX_PREFIX = "eu.maveniverse.maven.plugins:toolbox:";
-
- private final ExecutorHelper helper;
- private final String toolboxVersion;
- private final ExecutorHelper.Mode forceMode;
-
- /**
- * @deprecated Better specify required version yourself. This one is "cemented" to 0.13.7
- */
- @Deprecated
- public ToolboxTool(ExecutorHelper helper) {
- this(helper, "0.13.7");
- }
-
- public ToolboxTool(ExecutorHelper helper, String toolboxVersion) {
- this(helper, toolboxVersion, null);
- }
-
- public ToolboxTool(ExecutorHelper helper, String toolboxVersion, ExecutorHelper.Mode forceMode) {
- this.helper = requireNonNull(helper);
- this.toolboxVersion = requireNonNull(toolboxVersion);
- this.forceMode = forceMode; // nullable
- }
-
- @Override
- public Map<String, String> dump(ExecutorRequest.Builder executorRequest) throws ExecutorException {
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- ByteArrayOutputStream stderr = new ByteArrayOutputStream();
- ExecutorRequest.Builder builder = mojo(executorRequest, "gav-dump")
- .argument("-DasProperties")
- .stdOut(stdout)
- .stdErr(stderr);
- doExecute(builder);
- try {
- Properties properties = new Properties();
- properties.load(new ByteArrayInputStream(
- validateOutput(false, stdout, stderr).getBytes()));
- return properties.entrySet().stream()
- .collect(Collectors.toMap(
- e -> String.valueOf(e.getKey()),
- e -> String.valueOf(e.getValue()),
- (prev, next) -> next,
- HashMap::new));
- } catch (IOException e) {
- throw new ExecutorException("Unable to parse properties", e);
- }
- }
-
- @Override
- public String localRepository(ExecutorRequest.Builder executorRequest) throws ExecutorException {
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- ByteArrayOutputStream stderr = new ByteArrayOutputStream();
- ExecutorRequest.Builder builder = mojo(executorRequest, "gav-local-repository-path")
- .stdOut(stdout)
- .stdErr(stderr);
- doExecute(builder);
- return validateOutput(true, stdout, stderr);
- }
-
- @Override
- public String artifactPath(ExecutorRequest.Builder executorRequest, String gav, String repositoryId)
- throws ExecutorException {
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- ByteArrayOutputStream stderr = new ByteArrayOutputStream();
- ExecutorRequest.Builder builder = mojo(executorRequest, "gav-artifact-path")
- .argument("-Dgav=" + gav)
- .stdOut(stdout)
- .stdErr(stderr);
- if (repositoryId != null) {
- builder.argument("-Drepository=" + repositoryId + "::unimportant");
- }
- doExecute(builder);
- return validateOutput(true, stdout, stderr);
- }
-
- @Override
- public String metadataPath(ExecutorRequest.Builder executorRequest, String gav, String repositoryId)
- throws ExecutorException {
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- ByteArrayOutputStream stderr = new ByteArrayOutputStream();
- ExecutorRequest.Builder builder = mojo(executorRequest, "gav-metadata-path")
- .argument("-Dgav=" + gav)
- .stdOut(stdout)
- .stdErr(stderr);
- if (repositoryId != null) {
- builder.argument("-Drepository=" + repositoryId + "::unimportant");
- }
- doExecute(builder);
- return validateOutput(true, stdout, stderr);
- }
-
- private ExecutorRequest.Builder mojo(ExecutorRequest.Builder builder, String mojo) {
- if (helper.mavenVersion().startsWith("4.")) {
- builder.argument("--raw-streams");
- }
- return builder.argument(TOOLBOX_PREFIX + toolboxVersion + ":" + mojo)
- .argument("--quiet")
- .argument("-DforceStdout");
- }
-
- private void doExecute(ExecutorRequest.Builder builder) {
- ExecutorRequest request = builder.build();
- int ec = forceMode == null ? helper.execute(request) : helper.execute(forceMode, request);
- if (ec != 0) {
- throw new ExecutorException("Unexpected exit code=" + ec + "; stdout="
- + request.stdOut().orElse(null) + "; stderr="
- + request.stdErr().orElse(null));
- }
- }
-
- /**
- * Performs "sanity check" for output, making sure no insane values like empty strings are returned.
- */
- private String validateOutput(boolean shave, ByteArrayOutputStream stdout, ByteArrayOutputStream stderr) {
- String result = stdout.toString();
- if (shave) {
- result = result.replace("\n", "").replace("\r", "");
- }
- // sanity checks: stderr has any OR result is empty string (no method should emit empty string)
- if (result.trim().isEmpty()) {
- // see bug https://github.com/apache/maven/pull/11303 Fail in this case
- // tl;dr We NEVER expect empty string as output from this tool; so fail here instead to chase ghosts
- throw new IllegalStateException("Empty output from Toolbox; stdout[" + stdout.size() + "]=" + stdout
- + "; stderr[" + stderr.size() + "]=" + stderr);
- }
- return result;
- }
-}
diff --git a/impl/maven-executor/src/site/site.xml b/impl/maven-executor/src/site/site.xml
deleted file mode 100644
index 4ee3b709cf..0000000000
--- a/impl/maven-executor/src/site/site.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-
-<site xmlns="http://maven.apache.org/SITE/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/SITE/2.0.0 https://maven.apache.org/xsd/site-2.0.0.xsd">
-
- <edit>${project.scm.url}</edit>
-
- <body>
- <menu name="Overview">
- <item name="Introduction" href="index.html"/>
- <item name="Javadocs" href="apidocs/index.html"/>
- <item name="Source Xref" href="xref/index.html"/>
- <!--item name="FAQ" href="faq.html"/-->
- </menu>
- </body>
-</site>
diff --git a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/Environment.java b/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/Environment.java
deleted file mode 100644
index 771661a435..0000000000
--- a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/Environment.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.cling.executor;
-
-public final class Environment {
- private Environment() {}
-
- public static final String TOOLBOX_VERSION = System.getProperty("version.toolbox", "UNSET version.toolbox");
-}
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
deleted file mode 100644
index a2a095271c..0000000000
--- a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/MavenExecutorTestSupport.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * 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.cling.executor;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Collection;
-import java.util.List;
-
-import eu.maveniverse.maven.mimir.testing.MimirInfuser;
-import org.apache.maven.api.annotations.Nullable;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
-import org.junit.jupiter.api.Timeout;
-import org.junit.jupiter.api.condition.DisabledOnOs;
-import org.junit.jupiter.api.io.CleanupMode;
-import org.junit.jupiter.api.io.TempDir;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.condition.OS.WINDOWS;
-
-@Timeout(60)
-public abstract class MavenExecutorTestSupport {
- @TempDir(cleanup = CleanupMode.NEVER)
- private static Path tempDir;
-
- private Path cwd;
-
- private Path userHome;
-
- @BeforeEach
- void beforeEach(TestInfo testInfo) throws Exception {
- cwd = tempDir.resolve(testInfo.getTestMethod().orElseThrow().getName()).resolve("cwd");
- Files.createDirectories(cwd.resolve(".mvn"));
- userHome = tempDir.resolve(testInfo.getTestMethod().orElseThrow().getName())
- .resolve("home");
- Files.createDirectories(userHome);
-
- System.out.println("=== " + testInfo.getTestMethod().orElseThrow().getName());
- }
-
- private static Executor executor;
-
- protected final Executor createAndMemoizeExecutor() {
- if (executor == null) {
- executor = doSelectExecutor();
- }
- return executor;
- }
-
- @AfterAll
- static void afterAll() {
- if (executor != null) {
- executor.close();
- executor = null;
- }
- }
-
- protected abstract Executor doSelectExecutor();
-
- @Test
- void mvnenc4() 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)));
- }
-
- @DisabledOnOs(
- value = WINDOWS,
- disabledReason = "JUnit on Windows fails to clean up as mvn3 does not close log file properly")
- @Test
- void dump3() throws Exception {
- String logfile = "m3.log";
- execute(
- cwd.resolve(logfile),
- List.of(mvn3ExecutorRequestBuilder()
- .cwd(cwd)
- .userHomeDirectory(userHome)
- .argument("eu.maveniverse.maven.plugins:toolbox:" + Environment.TOOLBOX_VERSION + ":gav-dump")
- .argument("-l")
- .argument(logfile)
- .build()));
- System.out.println(Files.readString(cwd.resolve(logfile)));
- }
-
- @Test
- void dump4() throws Exception {
- String logfile = "m4.log";
- execute(
- cwd.resolve(logfile),
- List.of(mvn4ExecutorRequestBuilder()
- .cwd(cwd)
- .userHomeDirectory(userHome)
- .argument("eu.maveniverse.maven.plugins:toolbox:" + Environment.TOOLBOX_VERSION + ":gav-dump")
- .argument("-l")
- .argument(logfile)
- .build()));
- System.out.println(Files.readString(cwd.resolve(logfile)));
- }
-
- @DisabledOnOs(
- value = WINDOWS,
- disabledReason = "JUnit on Windows fails to clean up as mvn3 does not close log file properly")
- @Test
- void defaultFs3() throws Exception {
- layDownFiles(cwd);
- String logfile = "m3.log";
- execute(
- cwd.resolve(logfile),
- List.of(mvn3ExecutorRequestBuilder()
- .cwd(cwd)
- .argument("-V")
- .argument("verify")
- .argument("-l")
- .argument(logfile)
- .build()));
- System.out.println(Files.readString(cwd.resolve(logfile)));
- }
-
- @Test
- void defaultFs4() throws Exception {
- layDownFiles(cwd);
- String logfile = "m4.log";
- execute(
- cwd.resolve(logfile),
- List.of(mvn4ExecutorRequestBuilder()
- .cwd(cwd)
- .argument("-V")
- .argument("verify")
- .argument("-l")
- .argument(logfile)
- .build()));
- System.out.println(Files.readString(cwd.resolve(logfile)));
- }
-
- @Test
- void version3() throws Exception {
- assertEquals(
- System.getProperty("maven3version"),
- mavenVersion(mvn3ExecutorRequestBuilder().build()));
- }
-
- @Test
- void version4() throws Exception {
- assertEquals(
- System.getProperty("maven4version"),
- mavenVersion(mvn4ExecutorRequestBuilder().build()));
- }
-
- @Test
- void defaultFs4CaptureOutput() throws Exception {
- layDownFiles(cwd);
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- execute(
- null,
- List.of(mvn4ExecutorRequestBuilder()
- .cwd(cwd)
- .argument("-V")
- .argument("verify")
- .stdOut(stdout)
- .build()));
- System.out.println(stdout);
- assertFalse(stdout.toString().contains("[\u001B["), "By default no ANSI color codes");
- assertTrue(stdout.toString().contains("INFO"), "No INFO found");
- }
-
- @Test
- void defaultFs4CaptureOutputWithForcedColor() throws Exception {
- layDownFiles(cwd);
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- execute(
- null,
- List.of(mvn4ExecutorRequestBuilder()
- .cwd(cwd)
- .argument("-V")
- .argument("verify")
- .argument("--color=yes")
- .stdOut(stdout)
- .build()));
- System.out.println(stdout);
- assertTrue(stdout.toString().contains("[\u001B["), "No ANSI codes present");
- assertTrue(stdout.toString().contains("INFO"), "No INFO found");
- }
-
- @Test
- void defaultFs4CaptureOutputWithForcedOffColor() throws Exception {
- layDownFiles(cwd);
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- execute(
- null,
- List.of(mvn4ExecutorRequestBuilder()
- .cwd(cwd)
- .argument("-V")
- .argument("verify")
- .argument("--color=no")
- .stdOut(stdout)
- .build()));
- System.out.println(stdout);
- assertFalse(stdout.toString().contains("[\u001B["), "No ANSI codes present");
- assertTrue(stdout.toString().contains("INFO"), "No INFO found");
- }
-
- @Test
- void defaultFs3CaptureOutput() throws Exception {
- layDownFiles(cwd);
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- execute(
- null,
- List.of(mvn3ExecutorRequestBuilder()
- .cwd(cwd)
- .argument("-V")
- .argument("verify")
- .stdOut(stdout)
- .build()));
- System.out.println(stdout);
- // Note: we do not validate ANSI as Maven3 is weird in this respect (thinks is color but is not)
- // assertTrue(stdout.toString().contains("[\u001B["), "No ANSI codes present");
- assertTrue(stdout.toString().contains("INFO"), "No INFO found");
- }
-
- @Test
- void defaultFs3CaptureOutputWithForcedColor() throws Exception {
- layDownFiles(cwd);
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- execute(
- null,
- List.of(mvn3ExecutorRequestBuilder()
- .cwd(cwd)
- .argument("-V")
- .argument("verify")
- .argument("--color=yes")
- .stdOut(stdout)
- .build()));
- System.out.println(stdout);
- assertTrue(stdout.toString().contains("[\u001B["), "No ANSI codes present");
- assertTrue(stdout.toString().contains("INFO"), "No INFO found");
- }
-
- @Test
- void defaultFs3CaptureOutputWithForcedOffColor() throws Exception {
- layDownFiles(cwd);
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- execute(
- null,
- List.of(mvn3ExecutorRequestBuilder()
- .cwd(cwd)
- .argument("-V")
- .argument("verify")
- .argument("--color=no")
- .stdOut(stdout)
- .build()));
- System.out.println(stdout);
- assertFalse(stdout.toString().contains("[\u001B["), "No ANSI codes present");
- assertTrue(stdout.toString().contains("INFO"), "No INFO found");
- }
-
- public static final String POM_STRING = """
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>org.apache.maven.samples</groupId>
- <artifactId>sample</artifactId>
- <version>1.0.0</version>
-
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.junit</groupId>
- <artifactId>junit-bom</artifactId>
- <version>5.11.1</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
- <dependencies>
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-api</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- </project>
- """;
-
- public static final String APP_JAVA_STRING = """
- package org.apache.maven.samples.sample;
-
- public class App {
- public static void main(String... args) {
- System.out.println("Hello World!");
- }
- }
- """;
-
- protected void execute(@Nullable Path logFile, Collection<ExecutorRequest> requests) throws Exception {
- Executor invoker = createAndMemoizeExecutor();
- for (ExecutorRequest request : requests) {
- if (MimirInfuser.isMimirPresentUW()) {
- if (maven3Home().equals(request.installationDirectory())) {
- MimirInfuser.doInfusePW(request.cwd(), request.userHomeDirectory());
- } else if (maven4Home().equals(request.installationDirectory())) {
- MimirInfuser.doInfuseUW(request.userHomeDirectory());
- }
- MimirInfuser.preseedItselfIntoInnerUserHome(request.userHomeDirectory());
- }
- int exitCode = invoker.execute(request);
- if (exitCode != 0) {
- throw new FailedExecution(request, exitCode, logFile == null ? "" : Files.readString(logFile));
- }
- }
- }
-
- protected String mavenVersion(ExecutorRequest request) throws Exception {
- return createAndMemoizeExecutor().mavenVersion(request);
- }
-
- public ExecutorRequest.Builder mvn3ExecutorRequestBuilder() {
- return customize(ExecutorRequest.mavenBuilder(maven3Home()));
- }
-
- private Path maven3Home() {
- return ExecutorRequest.getCanonicalPath(Paths.get(System.getProperty("maven3home")));
- }
-
- public ExecutorRequest.Builder mvn4ExecutorRequestBuilder() {
- return customize(ExecutorRequest.mavenBuilder(maven4Home()));
- }
-
- private Path maven4Home() {
- return ExecutorRequest.getCanonicalPath(Paths.get(System.getProperty("maven4home")));
- }
-
- private ExecutorRequest.Builder customize(ExecutorRequest.Builder builder) {
- builder =
- builder.cwd(cwd).userHomeDirectory(userHome).argument("-Daether.remoteRepositoryFilter.prefixes=false");
- if (System.getProperty("localRepository") != null) {
- builder.argument("-Dmaven.repo.local.tail=" + System.getProperty("localRepository"));
- }
- return builder;
- }
-
- protected void layDownFiles(Path cwd) throws IOException {
- Path pom = cwd.resolve("pom.xml").toAbsolutePath();
- Files.writeString(pom, POM_STRING);
- Path appJava = cwd.resolve("src/main/java/org/apache/maven/samples/sample/App.java");
- Files.createDirectories(appJava.getParent());
- Files.writeString(appJava, APP_JAVA_STRING);
- }
-
- protected static class FailedExecution extends Exception {
- private final ExecutorRequest request;
- private final int exitCode;
- private final String log;
-
- public FailedExecution(ExecutorRequest request, int exitCode, String log) {
- super(request.toString() + " => " + exitCode + "\n" + log);
- this.request = request;
- this.exitCode = exitCode;
- this.log = log;
- }
-
- public ExecutorRequest getRequest() {
- return request;
- }
-
- public int getExitCode() {
- return exitCode;
- }
-
- public String getLog() {
- return log;
- }
- }
-}
diff --git a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutorTest.java b/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutorTest.java
deleted file mode 100644
index 6433235b69..0000000000
--- a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutorTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.cling.executor.embedded;
-
-import org.apache.maven.cling.executor.Executor;
-import org.apache.maven.cling.executor.MavenExecutorTestSupport;
-
-/**
- * Embedded executor UT
- */
-public class EmbeddedMavenExecutorTest extends MavenExecutorTestSupport {
-
- @Override
- protected Executor doSelectExecutor() {
- return new EmbeddedMavenExecutor();
- }
-}
diff --git a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/forked/ForkedMavenExecutorTest.java b/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/forked/ForkedMavenExecutorTest.java
deleted file mode 100644
index a1f4362eac..0000000000
--- a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/forked/ForkedMavenExecutorTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.cling.executor.forked;
-
-import org.apache.maven.cling.executor.Executor;
-import org.apache.maven.cling.executor.MavenExecutorTestSupport;
-
-/**
- * Forked executor UT
- */
-public class ForkedMavenExecutorTest extends MavenExecutorTestSupport {
-
- @Override
- protected Executor doSelectExecutor() {
- return new ForkedMavenExecutor();
- }
-}
diff --git a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/impl/ToolboxToolTest.java b/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/impl/ToolboxToolTest.java
deleted file mode 100644
index fc85626824..0000000000
--- a/impl/maven-executor/src/test/java/org/apache/maven/cling/executor/impl/ToolboxToolTest.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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.cling.executor.impl;
-
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Map;
-
-import eu.maveniverse.maven.mimir.testing.MimirInfuser;
-import org.apache.maven.cling.executor.Environment;
-import org.apache.maven.cling.executor.Executor;
-import org.apache.maven.cling.executor.ExecutorHelper;
-import org.apache.maven.cling.executor.ExecutorRequest;
-import org.apache.maven.cling.executor.embedded.EmbeddedMavenExecutor;
-import org.apache.maven.cling.executor.forked.ForkedMavenExecutor;
-import org.apache.maven.cling.executor.internal.HelperImpl;
-import org.apache.maven.cling.executor.internal.ToolboxTool;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.TestInfo;
-import org.junit.jupiter.api.Timeout;
-import org.junit.jupiter.api.io.CleanupMode;
-import org.junit.jupiter.api.io.TempDir;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.EnumSource;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-@Timeout(60)
-public class ToolboxToolTest {
- private static final Executor EMBEDDED_MAVEN_EXECUTOR = new EmbeddedMavenExecutor();
- private static final Executor FORKED_MAVEN_EXECUTOR = new ForkedMavenExecutor();
-
- @TempDir(cleanup = CleanupMode.NEVER)
- private static Path tempDir;
-
- private Path userHome;
- private Path cwd;
-
- @BeforeEach
- void beforeEach(TestInfo testInfo) throws Exception {
- String testName = testInfo.getTestMethod().orElseThrow().getName();
- userHome = tempDir.resolve(testName);
- cwd = userHome.resolve("cwd");
- Files.createDirectories(cwd.resolve(".mvn"));
-
- if (MimirInfuser.isMimirPresentUW()) {
- if (testName.contains("3")) {
- MimirInfuser.doInfusePW(cwd, userHome);
- } else {
- MimirInfuser.doInfuseUW(userHome);
- }
- MimirInfuser.preseedItselfIntoInnerUserHome(userHome);
- }
-
- System.out.println("=== " + testInfo.getTestMethod().orElseThrow().getName());
- }
-
- private ExecutorRequest.Builder getExecutorRequest(ExecutorHelper helper) {
- ExecutorRequest.Builder builder =
- helper.executorRequest().cwd(cwd).argument("-Daether.remoteRepositoryFilter.prefixes=false");
- if (System.getProperty("localRepository") != null) {
- builder.argument("-Dmaven.repo.local.tail=" + System.getProperty("localRepository"));
- }
- return builder;
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void dump3(ExecutorHelper.Mode mode) throws Exception {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn3Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- Map<String, String> dump =
- new ToolboxTool(helper, Environment.TOOLBOX_VERSION).dump(getExecutorRequest(helper));
- System.out.println(mode.name() + ": " + dump.toString());
- assertEquals(System.getProperty("maven3version"), dump.get("maven.version"));
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void dump4(ExecutorHelper.Mode mode) throws Exception {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn4Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- Map<String, String> dump =
- new ToolboxTool(helper, Environment.TOOLBOX_VERSION).dump(getExecutorRequest(helper));
- System.out.println(mode.name() + ": " + dump.toString());
- assertEquals(System.getProperty("maven4version"), dump.get("maven.version"));
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void version3(ExecutorHelper.Mode mode) {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn3Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- System.out.println(mode.name() + ": " + helper.mavenVersion());
- assertEquals(System.getProperty("maven3version"), helper.mavenVersion());
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void version4(ExecutorHelper.Mode mode) {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn4Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- System.out.println(mode.name() + ": " + helper.mavenVersion());
- assertEquals(System.getProperty("maven4version"), helper.mavenVersion());
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void localRepository3(ExecutorHelper.Mode mode) {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn3Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- String localRepository =
- new ToolboxTool(helper, Environment.TOOLBOX_VERSION).localRepository(getExecutorRequest(helper));
- System.out.println(mode.name() + ": " + localRepository);
- Path local = Paths.get(localRepository);
- assertTrue(Files.isDirectory(local));
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void localRepository4(ExecutorHelper.Mode mode) {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn4Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- String localRepository =
- new ToolboxTool(helper, Environment.TOOLBOX_VERSION).localRepository(getExecutorRequest(helper));
- System.out.println(mode.name() + ": " + localRepository);
- Path local = Paths.get(localRepository);
- assertTrue(Files.isDirectory(local));
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void artifactPath3(ExecutorHelper.Mode mode) {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn3Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- String path = new ToolboxTool(helper, Environment.TOOLBOX_VERSION)
- .artifactPath(getExecutorRequest(helper), "aopalliance:aopalliance:1.0", "central");
- System.out.println(mode.name() + ": " + path);
- // split repository: assert "ends with" as split may introduce prefixes
- assertTrue(
- path.endsWith("aopalliance" + File.separator + "aopalliance" + File.separator + "1.0" + File.separator
- + "aopalliance-1.0.jar"),
- "path=" + path);
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void artifactPath4(ExecutorHelper.Mode mode) {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn4Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- String path = new ToolboxTool(helper, Environment.TOOLBOX_VERSION)
- .artifactPath(getExecutorRequest(helper), "aopalliance:aopalliance:1.0", "central");
- System.out.println(mode.name() + ": " + path);
- // split repository: assert "ends with" as split may introduce prefixes
- assertTrue(
- path.endsWith("aopalliance" + File.separator + "aopalliance" + File.separator + "1.0" + File.separator
- + "aopalliance-1.0.jar"),
- "path=" + path);
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void metadataPath3(ExecutorHelper.Mode mode) {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn4Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- String path = new ToolboxTool(helper, Environment.TOOLBOX_VERSION)
- .metadataPath(getExecutorRequest(helper), "aopalliance", "someremote");
- System.out.println(mode.name() + ": " + path);
- // split repository: assert "ends with" as split may introduce prefixes
- assertTrue(path.endsWith("aopalliance" + File.separator + "maven-metadata-someremote.xml"), "path=" + path);
- }
-
- @ParameterizedTest
- @EnumSource(ExecutorHelper.Mode.class)
- void metadataPath4(ExecutorHelper.Mode mode) {
- ExecutorHelper helper =
- new HelperImpl(mode, mvn4Home(), userHome, EMBEDDED_MAVEN_EXECUTOR, FORKED_MAVEN_EXECUTOR);
- String path = new ToolboxTool(helper, Environment.TOOLBOX_VERSION)
- .metadataPath(getExecutorRequest(helper), "aopalliance", "someremote");
- System.out.println(mode.name() + ": " + path);
- // split repository: assert "ends with" as split may introduce prefixes
- assertTrue(path.endsWith("aopalliance" + File.separator + "maven-metadata-someremote.xml"), "path=" + path);
- }
-
- public Path mvn3Home() {
- return Paths.get(System.getProperty("maven3home"));
- }
-
- public Path mvn4Home() {
- return Paths.get(System.getProperty("maven4home"));
- }
-}
diff --git a/impl/pom.xml b/impl/pom.xml
index df83a63a01..b41717c555 100644
--- a/impl/pom.xml
+++ b/impl/pom.xml
@@ -40,7 +40,6 @@ under the License.
<module>maven-core</module>
<module>maven-cli</module>
<module>maven-testing</module>
- <module>maven-executor</module>
</modules>
<properties>
diff --git a/its/core-it-support/maven-it-helper/pom.xml b/its/core-it-support/maven-it-helper/pom.xml
index 960eb651e3..2e9fc52736 100644
--- a/its/core-it-support/maven-it-helper/pom.xml
+++ b/its/core-it-support/maven-it-helper/pom.xml
@@ -32,7 +32,7 @@ under the License.
<dependencies>
<dependency>
- <groupId>org.apache.maven</groupId>
+ <groupId>org.apache.maven.executor</groupId>
<artifactId>maven-executor</artifactId>
<!-- Version inherited from parent dependency management -->
</dependency>
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 c0f29a2b3d..20b784a617 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
@@ -45,14 +45,15 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.apache.maven.cling.executor.ExecutorException;
-import org.apache.maven.cling.executor.ExecutorRequest;
-import org.apache.maven.cling.executor.ExecutorHelper;
-import org.apache.maven.cling.executor.ExecutorTool;
-import org.apache.maven.cling.executor.embedded.EmbeddedMavenExecutor;
-import org.apache.maven.cling.executor.forked.ForkedMavenExecutor;
-import org.apache.maven.cling.executor.internal.HelperImpl;
-import org.apache.maven.cling.executor.internal.ToolboxTool;
+import org.apache.maven.executor.Executor;
+import org.apache.maven.executor.ExecutorException;
+import org.apache.maven.executor.ExecutorRequest;
+import org.apache.maven.executor.ExecutorHelper;
+import org.apache.maven.executor.ExecutorResult;
+import org.apache.maven.executor.ExecutorTool;
+import org.apache.maven.executor.embedded.EmbeddedMavenExecutor;
+import org.apache.maven.executor.forked.ForkedMavenExecutor;
+import org.apache.maven.executor.support.ToolboxExecutorTool;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
@@ -62,17 +63,21 @@
*
*/
public class Verifier {
+ /**
+ * The Maven home/installation directory we are testing/executing with Executor.
+ */
+ private static final Path MAVEN_HOME = Paths.get(System.getProperty("maven.home"));
/**
* Keep executor alive, as long as Verifier is in classloader. Embedded classloader keeps embedded Maven
* ClassWorld alive, instead to re-create it per invocation, making embedded execution fast(er).
+ * Points to test subjected Maven home.
*/
- private static final EmbeddedMavenExecutor EMBEDDED_MAVEN_EXECUTOR = new EmbeddedMavenExecutor();
+ private static final EmbeddedMavenExecutor EMBEDDED_MAVEN_EXECUTOR = new EmbeddedMavenExecutor(MAVEN_HOME);
/**
* Keep executor alive, as long as Verifier is in classloader. For forked this means nothing, but is
- * at least "handled the same" as embedded counterpart. Later on, we could have some similar solution like
- * mvnd has, and keep pool of "hot" processes maybe?
+ * at least "handled the same" as embedded counterpart. Points to test subjected Maven home.
*/
- private static final ForkedMavenExecutor FORKED_MAVEN_EXECUTOR = new ForkedMavenExecutor();
+ private static final ForkedMavenExecutor FORKED_MAVEN_EXECUTOR = new ForkedMavenExecutor(MAVEN_HOME);
/**
* The "preferred" fork mode of Verifier, defaults to "auto". In fact, am unsure is any other fork mode usable,
@@ -164,13 +169,11 @@ public Verifier(String basedir, List<String> defaultCliArguments, boolean create
this.userHomeDirectory = Paths.get(System.getProperty("maven.test.user.home", "user.home"));
Files.createDirectories(this.userHomeDirectory);
this.outerLocalRepository = Paths.get(System.getProperty("maven.test.repo.outer", ".m2/repository"));
- this.executorHelper = new HelperImpl(
+ this.executorHelper = ExecutorHelper.forExecutors(
VERIFIER_FORK_MODE,
- Paths.get(System.getProperty("maven.home")),
- this.userHomeDirectory,
EMBEDDED_MAVEN_EXECUTOR,
FORKED_MAVEN_EXECUTOR);
- this.executorTool = new ToolboxTool(executorHelper, toolboxVersion);
+ this.executorTool = new ToolboxExecutorTool(executorHelper, toolboxVersion);
this.defaultCliArguments =
new ArrayList<>(defaultCliArguments != null ? defaultCliArguments : DEFAULT_CLI_ARGUMENTS);
this.logFile = this.basedir.resolve(logFileName);
@@ -248,11 +251,9 @@ public void execute() throws VerificationException {
args.add("-Daether.remoteRepositoryFilter.prefixes=false");
try {
- ExecutorRequest.Builder builder = executorHelper
- .executorRequest()
+ ExecutorRequest.Builder builder = executorRequest()
.command(executable)
.cwd(basedir)
- .userHomeDirectory(userHomeDirectory)
.jvmArguments(jvmArguments)
.arguments(args)
.skipMavenRc(skipMavenRc);
@@ -283,7 +284,7 @@ public void execute() throws VerificationException {
}
}
- int ret = executorHelper.execute(mode, request);
+ ExecutorResult result = executorHelper.execute(mode, request);
// After execution, prepend the command line to the log file
if (commandLineHeader != null && Files.exists(logFile)) {
@@ -320,14 +321,14 @@ public void execute() throws VerificationException {
}
}
- if (ret > 0) {
+ if (!result.success()) {
String dump;
try {
dump = executorTool.dump(request.toBuilder()).toString();
} catch (Exception e) {
dump = "FAILED: " + e.getMessage();
}
- throw new VerificationException("Exit code was non-zero: " + ret + "; command line and log = \n"
+ throw new VerificationException("Exit code was non-zero: " + result.exitCode().orElse(-1) + "; command line and log = \n"
+ getExecutable() + " "
+ "\nstdout: " + stdout
+ "\nstderr: " + stderr
@@ -442,10 +443,8 @@ public String getLocalRepositoryWithSettings(String settingsXml) {
if (!Files.isRegularFile(settingsFile)) {
throw new IllegalArgumentException("settings xml does not exist: " + settingsXml);
}
- return executorTool.localRepository(executorHelper
- .executorRequest()
+ return executorTool.localRepository(executorRequest()
.cwd(tempBasedir)
- .userHomeDirectory(userHomeDirectory)
.argument("-s")
.argument(settingsFile.toString()));
} else {
@@ -454,7 +453,7 @@ public String getLocalRepositoryWithSettings(String settingsXml) {
return outerHead;
} else {
return executorTool.localRepository(
- executorHelper.executorRequest().cwd(tempBasedir).userHomeDirectory(userHomeDirectory));
+ executorRequest().cwd(tempBasedir));
}
}
}
@@ -476,12 +475,12 @@ private String formatCommandLine(ExecutorRequest request, ExecutorHelper.Mode mo
cmdLine.append("# Command line: ");
// Add the Maven executable path
- Path mavenExecutable = request.installationDirectory()
+ Path mavenExecutable = MAVEN_HOME
.resolve("bin")
- .resolve(System.getProperty("os.name").toLowerCase().contains("windows")
+ .resolve(Executor.IS_WINDOWS
? request.command() + ".cmd"
: request.command());
- cmdLine.append(mavenExecutable.toString());
+ cmdLine.append(mavenExecutable);
// Add MAVEN_ARGS if they would be used (only for forked mode)
if (mode == ExecutorHelper.Mode.FORKED || mode == ExecutorHelper.Mode.AUTO) {
@@ -865,7 +864,11 @@ public String getArtifactPath(String gid, String aid, String version, String ext
}
return getLocalRepository()
+ File.separator
- + executorTool.artifactPath(executorHelper.executorRequest(), gav, null);
+ + executorTool.artifactPath(executorRequest(), gav, null);
+ }
+
+ private ExecutorRequest.Builder executorRequest() {
+ return ExecutorRequest.mavenBuilder().userHomeDirectory(userHomeDirectory);
}
private String getSupportArtifactPath(String artifact) {
@@ -923,7 +926,7 @@ public String getSupportArtifactPath(String gid, String aid, String version, Str
}
return outerLocalRepository
.resolve(executorTool.artifactPath(
- executorHelper.executorRequest().argument("-Dmaven.repo.local=" + outerLocalRepository),
+ executorRequest().argument("-Dmaven.repo.local=" + outerLocalRepository),
gav,
null))
.toString();
@@ -997,7 +1000,7 @@ public String getArtifactMetadataPath(String gid, String aid, String version, St
gav += filename;
return getLocalRepository()
+ File.separator
- + executorTool.metadataPath(executorHelper.executorRequest(), gav, repoId);
+ + executorTool.metadataPath(executorRequest(), gav, repoId);
}
/**
@@ -1027,7 +1030,7 @@ public void deleteArtifact(String org, String name, String version, String ext)
* @since 1.2
*/
public void deleteArtifacts(String gid) throws IOException {
- String mdPath = executorTool.metadataPath(executorHelper.executorRequest(), gid, null);
+ String mdPath = executorTool.metadataPath(executorRequest(), gid, null);
Path dir = Paths.get(getLocalRepository()).resolve(mdPath).getParent();
FileUtils.deleteDirectory(dir.toFile());
}
@@ -1047,7 +1050,7 @@ public void deleteArtifacts(String gid, String aid, String version) throws IOExc
requireNonNull(version, "version is null");
String mdPath =
- executorTool.metadataPath(executorHelper.executorRequest(), gid + ":" + aid + ":" + version, null);
+ executorTool.metadataPath(executorRequest(), gid + ":" + aid + ":" + version, null);
Path dir = Paths.get(getLocalRepository()).resolve(mdPath).getParent();
FileUtils.deleteDirectory(dir.toFile());
}
diff --git a/its/pom.xml b/its/pom.xml
index 750ef41466..923aec65d9 100644
--- a/its/pom.xml
+++ b/its/pom.xml
@@ -263,10 +263,11 @@ under the License.
<artifactId>maven-compat</artifactId>
<version>${maven-version}</version>
</dependency>
+
<dependency>
- <groupId>org.apache.maven</groupId>
+ <groupId>org.apache.maven.executor</groupId>
<artifactId>maven-executor</artifactId>
- <version>${maven-version}</version>
+ <version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>