From 52b5dcffb6c2b6b7ef4d4149aac8c37c06651ecf Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 11 Nov 2024 16:12:46 +0100 Subject: [PATCH 01/16] CLIng diet First part was to "reverse" MavenCli into CLIng, that also became a huge and complex beast. Now, sanitization comes, tearing down unneeded stuff. WIP --- .../org/apache/maven/api/cli/Invoker.java | 6 +- .../maven/api/cli/InvokerException.java | 17 ++ .../apache/maven/api/cli/InvokerRequest.java | 16 +- .../java/org/apache/maven/api/cli/Parser.java | 25 +-- .../maven/api/cli/mvn/MavenInvoker.java | 47 ------ .../api/cli/mvn/MavenInvokerRequest.java | 39 ----- .../apache/maven/api/cli/mvn/MavenParser.java | 51 ------ .../mvn/forked/ForkedMavenInvokerRequest.java | 45 ------ .../api/cli/mvn/forked/ForkedMavenParser.java | 49 ------ .../api/cli/mvn/local/LocalMavenInvoker.java | 32 ---- .../mvn/resident/ResidentMavenInvoker.java | 39 ----- .../maven/api/cli/mvnenc/EncryptInvoker.java | 47 ------ .../api/cli/mvnenc/EncryptInvokerRequest.java | 37 ----- .../maven/api/cli/mvnenc/EncryptParser.java | 49 ------ .../org/apache/maven/cling/ClingSupport.java | 12 +- .../org/apache/maven/cling/MavenCling.java | 15 +- .../org/apache/maven/cling/MavenEncCling.java | 9 +- .../cling/invoker/BaseInvokerRequest.java | 13 +- .../maven/cling/invoker/BaseParser.java | 12 +- .../maven/cling/invoker/ContainerCapsule.java | 8 + .../invoker/ContainerCapsuleFactory.java | 12 +- .../maven/cling/invoker/LookupInvoker.java | 153 +++--------------- .../cling/invoker/LookupInvokerContext.java | 111 +++++++++++++ .../cling/invoker/PlexusContainerCapsule.java | 7 + .../PlexusContainerCapsuleFactory.java | 37 ++--- .../cling/invoker/mvn/DefaultMavenParser.java | 62 ------- ...ultMavenInvoker.java => MavenInvoker.java} | 105 ++++++------ ...rRequest.java => MavenInvokerRequest.java} | 18 +-- ...{BaseMavenParser.java => MavenParser.java} | 49 ++++-- .../DefaultForkedMavenInvokerRequest.java | 78 --------- ...enInvoker.java => ForkedMavenInvoker.java} | 14 +- ...avenParser.java => ForkedMavenParser.java} | 34 +--- .../mvn/local/DefaultLocalMavenInvoker.java | 54 ------- ...Invoker.java => ResidentMavenInvoker.java} | 18 +-- .../mvnenc/CommonsCliEncryptOptions.java | 3 + .../invoker/mvnenc/DefaultEncryptInvoker.java | 28 ++-- .../mvnenc/DefaultEncryptInvokerRequest.java | 6 +- .../invoker/mvnenc/DefaultEncryptParser.java | 12 +- .../cling/invoker/mvnenc/goals/Init.java | 7 +- .../maven/cling/invoker/package-info.java | 12 +- .../invoker/mvn/MavenInvokerTestSupport.java | 4 +- ...rTest.java => ForkedMavenInvokerTest.java} | 7 +- .../local/DefaultLocalMavenInvokerTest.java | 2 - .../DefaultResidentMavenInvokerTest.java | 4 +- 44 files changed, 396 insertions(+), 1009 deletions(-) delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenInvoker.java delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenInvokerRequest.java delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenParser.java delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenInvokerRequest.java delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenParser.java delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/local/LocalMavenInvoker.java delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/resident/ResidentMavenInvoker.java delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptInvoker.java delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptInvokerRequest.java delete mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptParser.java create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvokerContext.java delete mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenParser.java rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/{DefaultMavenInvoker.java => MavenInvoker.java} (88%) rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/{DefaultMavenInvokerRequest.java => MavenInvokerRequest.java} (85%) rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/{BaseMavenParser.java => MavenParser.java} (55%) delete mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvokerRequest.java rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/{DefaultForkedMavenInvoker.java => ForkedMavenInvoker.java} (94%) rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/{DefaultForkedMavenParser.java => ForkedMavenParser.java} (63%) delete mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvoker.java rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/{DefaultResidentMavenInvoker.java => ResidentMavenInvoker.java} (87%) rename api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenInvoker.java => impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/package-info.java (73%) rename impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/{DefaultForkedMavenInvokerTest.java => ForkedMavenInvokerTest.java} (85%) diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Invoker.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Invoker.java index bc5f879895ea..dc26cbcbaf1b 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Invoker.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Invoker.java @@ -30,12 +30,10 @@ * that can handle various types of {@link InvokerRequest InvokerRequests}. It also implements * {@link AutoCloseable} to ensure proper resource management.

* - * @param The specific type of {@link InvokerRequest} this {@code Invoker} can handle, extending {@link InvokerRequest} - * * @since 4.0.0 */ @Experimental -public interface Invoker> extends AutoCloseable { +public interface Invoker extends AutoCloseable { /** * Invokes the Maven application using the provided {@link InvokerRequest}. * This method is responsible for executing the Maven command or build @@ -45,7 +43,7 @@ public interface Invoker> extends Au * @return an integer representing the exit code of the invocation (0 typically indicates success) * @throws InvokerException if an error occurs during the invocation process */ - int invoke(@Nonnull R invokerRequest) throws InvokerException; + int invoke(@Nonnull InvokerRequest invokerRequest) throws InvokerException; /** * Closes and disposes of this {@link Invoker} instance, releasing any resources it may hold. diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerException.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerException.java index 08c8df20efd0..d1a479b71127 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerException.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerException.java @@ -49,4 +49,21 @@ public InvokerException(@Nullable String message) { public InvokerException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } + + /** + * Exception for intentional exit: No message or anything will be displayed, just the + * carried exit code will be returned from invoker {@link Invoker#invoke(InvokerRequest)} method. + */ + public static final class ExitException extends InvokerException { + private final int exitCode; + + public ExitException(int exitCode) { + super("EXIT"); + this.exitCode = exitCode; + } + + public int getExitCode() { + return exitCode; + } + } } diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerRequest.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerRequest.java index d38d0cc6334d..229f9b6364ca 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerRequest.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerRequest.java @@ -36,13 +36,11 @@ * Represents a Maven execution request, encapsulating all necessary information * for invoking a Maven build or command. * - * @param the type of {@link Options} used for this request, extending the base {@link Options} interface - * * @since 4.0.0 */ @Immutable @Experimental -public interface InvokerRequest { +public interface InvokerRequest { /** * The parser request this instance was created from. */ @@ -166,11 +164,21 @@ default Lookup lookup() { @Nonnull Optional> coreExtensions(); + /** + * Returns the list of extra JVM arguments to be passed to the forked Maven process. + * These arguments allow for customization of the JVM environment in which Maven will run. + * This property is used ONLY by invokers that spawn a new JVM and is fully ignored by others. + * + * @return an Optional containing the list of extra JVM arguments, or empty if not specified + */ + @Nonnull + Optional> jvmArguments(); + /** * Returns the options associated with this invocation request. * * @return the options object */ @Nonnull - O options(); + Options options(); } diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Parser.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Parser.java index a47a76f4e79c..89f1d4278c2b 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Parser.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Parser.java @@ -22,37 +22,16 @@ import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.services.MessageBuilderFactory; /** * Defines the contract for parsing Maven command-line arguments and creating an InvokerRequest. * This interface is responsible for interpreting the command-line input and constructing * the appropriate {@link InvokerRequest} object. * - * @param the type of {@link InvokerRequest} produced by this parser, extending {@link InvokerRequest} - * * @since 4.0.0 */ @Experimental -public interface Parser> { - /** - * Parses the given Maven arguments to create an InvokerRequest. - * This is a convenience method that internally creates a ParserRequest using - * {@link ParserRequest#mvn(String[], Logger, MessageBuilderFactory)}. - * - * @param args the command-line arguments - * @param logger the logger to use during parsing - * @param messageBuilderFactory the factory for creating message builders - * @return the parsed InvokerRequest - * @throws ParserException if there's an error during parsing of the command or arguments - * @throws IOException if there's an I/O error during the parsing process - */ - @Nonnull - default R mvn(@Nonnull String[] args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) - throws ParserException, IOException { - return parse(ParserRequest.mvn(args, logger, messageBuilderFactory).build()); - } - +public interface Parser { /** * Parses the given ParserRequest to create an InvokerRequest. * This method is responsible for interpreting the contents of the ParserRequest @@ -64,5 +43,5 @@ default R mvn(@Nonnull String[] args, @Nonnull Logger logger, @Nonnull MessageBu * @throws IOException if there's an I/O error during the parsing process */ @Nonnull - R parse(@Nonnull ParserRequest parserRequest) throws ParserException, IOException; + InvokerRequest parse(@Nonnull ParserRequest parserRequest) throws ParserException, IOException; } diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenInvoker.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenInvoker.java deleted file mode 100644 index c7e96730645e..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenInvoker.java +++ /dev/null @@ -1,47 +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.api.cli.mvn; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.cli.Invoker; -import org.apache.maven.api.cli.InvokerException; - -/** - * Defines the contract for a component responsible for invoking Maven using information provided in an invoker request. - * This interface extends the general {@link Invoker} interface, specializing it for Maven-specific operations. - * - * @param The specific type of {@link MavenInvokerRequest} this invoker can handle - * - * @since 4.0.0 - */ -@Experimental -public interface MavenInvoker> extends Invoker { - /** - * Invokes Maven using the provided MavenInvokerRequest. - * This method is responsible for executing the Maven build process - * based on the information contained in the request. - * - * @param invokerRequest the request containing all necessary information for the Maven invocation - * @return an integer representing the exit code of the Maven invocation (0 typically indicates success) - * @throws InvokerException if an error occurs during the Maven invocation process - */ - @Override - int invoke(@Nonnull R invokerRequest) throws InvokerException; -} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenInvokerRequest.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenInvokerRequest.java deleted file mode 100644 index 4030c5320b16..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenInvokerRequest.java +++ /dev/null @@ -1,39 +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.api.cli.mvn; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.cli.InvokerRequest; - -/** - * Represents a request to invoke Maven. - * This interface extends the general {@link InvokerRequest}, specializing it for Maven-specific operations. - * - *

A {@link MavenInvokerRequest} encapsulates all the necessary information needed to perform - * a Maven build, including any Maven-specific options defined in {@link MavenOptions}.

- * - * @param The specific Options type this request carries - * - * @since 4.0.0 - */ -@Experimental -public interface MavenInvokerRequest extends InvokerRequest { - // This interface doesn't declare any additional methods beyond those inherited from InvokerRequest. - // It serves to type-specify the Options as MavenOptions for Maven-specific requests. -} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenParser.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenParser.java deleted file mode 100644 index bb9e5bcb8cb5..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/MavenParser.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.api.cli.mvn; - -import java.io.IOException; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.cli.Parser; -import org.apache.maven.api.cli.ParserException; -import org.apache.maven.api.cli.ParserRequest; - -/** - * Defines the contract for parsing Maven-specific command-line arguments and creating a MavenInvokerRequest. - * This interface extends the general {@link Parser} interface, specializing it for Maven operations. - * - * @param The specific type of MavenInvokerRequest this parser produces - * - * @since 4.0.0 - */ -@Experimental -public interface MavenParser> extends Parser { - /** - * Parses the given {@link ParserRequest} to create a {@link MavenInvokerRequest}. - * This method is responsible for interpreting the contents of the ParserRequest - * and constructing the appropriate {@link MavenInvokerRequest} object for Maven operations. - * - * @param parserRequest the request containing all necessary information for parsing - * @return the parsed {@link MavenInvokerRequest} - * @throws ParserException if there's an error during parsing of the request - * @throws IOException if there's an I/O error during the parsing process - */ - @Nonnull - R parse(@Nonnull ParserRequest parserRequest) throws ParserException, IOException; -} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenInvokerRequest.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenInvokerRequest.java deleted file mode 100644 index f8a363763fe9..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenInvokerRequest.java +++ /dev/null @@ -1,45 +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.api.cli.mvn.forked; - -import java.util.List; -import java.util.Optional; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; -import org.apache.maven.api.cli.mvn.MavenOptions; - -/** - * Represents a request to invoke Maven in a forked JVM. - * This interface extends the {@link MavenInvokerRequest}, adding capabilities specific to forked Maven executions. - * - * @since 4.0.0 - */ -@Experimental -public interface ForkedMavenInvokerRequest extends MavenInvokerRequest { - /** - * Returns the list of extra JVM arguments to be passed to the forked Maven process. - * These arguments allow for customization of the JVM environment in which Maven will run. - * - * @return an Optional containing the list of extra JVM arguments, or empty if not specified - */ - @Nonnull - Optional> jvmArguments(); -} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenParser.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenParser.java deleted file mode 100644 index 8d21f864c0d9..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenParser.java +++ /dev/null @@ -1,49 +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.api.cli.mvn.forked; - -import java.io.IOException; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.cli.ParserException; -import org.apache.maven.api.cli.ParserRequest; -import org.apache.maven.api.cli.mvn.MavenParser; - -/** - * Defines the contract for parsing command-line arguments specific to forked Maven executions. - * This interface extends the {@link MavenParser}, specializing it for creating {@link ForkedMavenInvokerRequest} objects. - * - * @since 4.0.0 - */ -@Experimental -public interface ForkedMavenParser extends MavenParser { - /** - * Parses the given ParserRequest to create a ForkedMavenInvokerRequest. - * This method is responsible for interpreting the contents of the ParserRequest - * and constructing the appropriate ForkedMavenInvokerRequest object for forked Maven operations. - * - * @param parserRequest the request containing all necessary information for parsing - * @return the parsed ForkedMavenInvokerRequest - * @throws ParserException if there's an error during parsing of the request - * @throws IOException if there's an I/O error during the parsing process - */ - @Nonnull - ForkedMavenInvokerRequest parse(@Nonnull ParserRequest parserRequest) throws ParserException, IOException; -} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/local/LocalMavenInvoker.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/local/LocalMavenInvoker.java deleted file mode 100644 index ed429c2220e2..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/local/LocalMavenInvoker.java +++ /dev/null @@ -1,32 +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.api.cli.mvn.local; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.cli.mvn.MavenInvoker; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; -import org.apache.maven.api.cli.mvn.MavenOptions; - -/** - * Local Maven invoker, it expects all the Maven be present in classpath. - * - * @since 4.0.0 - */ -@Experimental -public interface LocalMavenInvoker extends MavenInvoker> {} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/resident/ResidentMavenInvoker.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/resident/ResidentMavenInvoker.java deleted file mode 100644 index 5743c7bb2c97..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/resident/ResidentMavenInvoker.java +++ /dev/null @@ -1,39 +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.api.cli.mvn.resident; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.cli.InvokerException; -import org.apache.maven.api.cli.mvn.MavenInvoker; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; -import org.apache.maven.api.cli.mvn.MavenOptions; - -/** - * Resident Maven invoker, similar to local. Instance is shut down when this instance is closed. - * - * @since 4.0.0 - */ -@Experimental -public interface ResidentMavenInvoker extends MavenInvoker> { - /** - * Closes cleanly the daemon. - */ - @Override - void close() throws InvokerException; -} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptInvoker.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptInvoker.java deleted file mode 100644 index 875b4c1c0107..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptInvoker.java +++ /dev/null @@ -1,47 +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.api.cli.mvnenc; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.cli.Invoker; -import org.apache.maven.api.cli.InvokerException; - -/** - * Defines the contract for a component responsible for invoking the Maven encryption tool. - * This interface extends the general Invoker interface, specializing it for encryption-related operations. - * - *

The EncryptInvoker is designed to handle encryption tasks within the Maven ecosystem, - * such as encrypting passwords or other sensitive information in Maven settings files.

- * - * @since 4.0.0 - */ -@Experimental -public interface EncryptInvoker extends Invoker { - /** - * Invokes the encryption tool using the provided EncryptInvokerRequest. - * This method is responsible for executing the encryption command or process - * based on the information contained in the request. - * - * @param invokerRequest the request containing all necessary information for the encryption invocation - * @return an integer representing the exit code of the invocation (0 typically indicates success) - * @throws InvokerException if an error occurs during the encryption process - */ - @Override - int invoke(EncryptInvokerRequest invokerRequest) throws InvokerException; -} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptInvokerRequest.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptInvokerRequest.java deleted file mode 100644 index 229ee7d22c65..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptInvokerRequest.java +++ /dev/null @@ -1,37 +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.api.cli.mvnenc; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.cli.InvokerRequest; - -/** - * Represents a request to invoke the Maven encryption tool. - * This interface extends the general InvokerRequest, specializing it for encryption-related operations. - * - *

An EncryptInvokerRequest encapsulates all the necessary information needed to perform - * an encryption operation, including any encryption-specific options defined in EncryptOptions.

- * - * @since 4.0.0 - */ -@Experimental -public interface EncryptInvokerRequest extends InvokerRequest { - // This interface doesn't declare any additional methods beyond those inherited from InvokerRequest. - // It serves to type-specify the Options as EncryptOptions for encryption-related requests. -} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptParser.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptParser.java deleted file mode 100644 index bf3eb9d7e690..000000000000 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvnenc/EncryptParser.java +++ /dev/null @@ -1,49 +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.api.cli.mvnenc; - -import java.io.IOException; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.cli.Parser; -import org.apache.maven.api.cli.ParserException; -import org.apache.maven.api.cli.ParserRequest; - -/** - * Defines the contract for parsing encryption-related command-line arguments and creating an EncryptInvokerRequest. - * This interface extends the general {@link Parser} interface, specializing it for encryption operations. - * - * @since 4.0.0 - */ -@Experimental -public interface EncryptParser extends Parser { - /** - * Parses the given ParserRequest to create an EncryptInvokerRequest. - * This method is responsible for interpreting the contents of the ParserRequest - * and constructing the appropriate EncryptInvokerRequest object for encryption operations. - * - * @param parserRequest the request containing all necessary information for parsing - * @return the parsed EncryptInvokerRequest - * @throws ParserException if there's an error during parsing of the request - * @throws IOException if there's an I/O error during the parsing process - */ - @Nonnull - EncryptInvokerRequest parse(@Nonnull ParserRequest parserRequest) throws ParserException, IOException; -} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/ClingSupport.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/ClingSupport.java index ba65331388fe..3f1a207520fe 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/ClingSupport.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/ClingSupport.java @@ -23,7 +23,6 @@ import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerRequest; -import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.ParserException; import org.codehaus.plexus.classworlds.ClassWorld; @@ -31,11 +30,8 @@ /** * The CLI "new-gen". - * - * @param the options type - * @param the request type */ -public abstract class ClingSupport> { +public abstract class ClingSupport { static final String CORE_CLASS_REALM_ID = "plexus.core"; protected final ClassWorld classWorld; @@ -64,7 +60,7 @@ private ClingSupport(ClassWorld classWorld, boolean classWorldManaged) { * The main entry point. */ public int run(String[] args) throws IOException { - try (Invoker invoker = createInvoker()) { + try (Invoker invoker = createInvoker()) { return invoker.invoke(parseArguments(args)); } catch (ParserException e) { System.err.println(e.getMessage()); @@ -78,7 +74,7 @@ public int run(String[] args) throws IOException { } } - protected abstract Invoker createInvoker(); + protected abstract Invoker createInvoker(); - protected abstract R parseArguments(String[] args) throws ParserException, IOException; + protected abstract InvokerRequest parseArguments(String[] args) throws ParserException, IOException; } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java index b8b204d5f470..b24c04057523 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java @@ -21,12 +21,11 @@ import java.io.IOException; import org.apache.maven.api.cli.Invoker; +import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.ParserException; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; -import org.apache.maven.api.cli.mvn.MavenOptions; +import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.cling.invoker.ProtoLookup; -import org.apache.maven.cling.invoker.mvn.DefaultMavenParser; import org.apache.maven.cling.invoker.mvn.local.DefaultLocalMavenInvoker; import org.apache.maven.jline.JLineMessageBuilderFactory; import org.codehaus.plexus.classworlds.ClassWorld; @@ -34,7 +33,7 @@ /** * Maven CLI "new-gen". */ -public class MavenCling extends ClingSupport> { +public class MavenCling extends ClingSupport { /** * "Normal" Java entry point. Note: Maven uses ClassWorld Launcher and this entry point is NOT used under normal * circumstances. @@ -60,13 +59,15 @@ public MavenCling(ClassWorld classWorld) { } @Override - protected Invoker> createInvoker() { + protected Invoker createInvoker() { return new DefaultLocalMavenInvoker( ProtoLookup.builder().addMapping(ClassWorld.class, classWorld).build()); } @Override - protected MavenInvokerRequest parseArguments(String[] args) throws ParserException, IOException { - return new DefaultMavenParser().mvn(args, new ProtoLogger(), new JLineMessageBuilderFactory()); + protected InvokerRequest parseArguments(String[] args) throws ParserException, IOException { + return new DefaultMavenParser() + .parse(ParserRequest.mvn(args, new ProtoLogger(), new JLineMessageBuilderFactory()) + .build()); } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java index 488eb9eae44a..63752de3fd68 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java @@ -21,10 +21,9 @@ import java.io.IOException; import org.apache.maven.api.cli.Invoker; +import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.ParserException; import org.apache.maven.api.cli.ParserRequest; -import org.apache.maven.api.cli.mvnenc.EncryptInvokerRequest; -import org.apache.maven.api.cli.mvnenc.EncryptOptions; import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker; @@ -35,7 +34,7 @@ /** * Maven encrypt CLI "new-gen". */ -public class MavenEncCling extends ClingSupport { +public class MavenEncCling extends ClingSupport { /** * "Normal" Java entry point. Note: Maven uses ClassWorld Launcher and this entry point is NOT used under normal * circumstances. @@ -61,13 +60,13 @@ public MavenEncCling(ClassWorld classWorld) { } @Override - protected Invoker createInvoker() { + protected Invoker createInvoker() { return new DefaultEncryptInvoker( ProtoLookup.builder().addMapping(ClassWorld.class, classWorld).build()); } @Override - protected EncryptInvokerRequest parseArguments(String[] args) throws ParserException, IOException { + protected InvokerRequest parseArguments(String[] args) throws ParserException, IOException { return new DefaultEncryptParser() .parse(ParserRequest.mvnenc(args, new ProtoLogger(), new JLineMessageBuilderFactory()) .build()); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseInvokerRequest.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseInvokerRequest.java index 0b1bd847d704..46530eee8528 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseInvokerRequest.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseInvokerRequest.java @@ -28,13 +28,12 @@ import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.cli.InvokerRequest; -import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.api.cli.extensions.CoreExtension; import static java.util.Objects.requireNonNull; -public abstract class BaseInvokerRequest implements InvokerRequest { +public abstract class BaseInvokerRequest implements InvokerRequest { private final ParserRequest parserRequest; private final Path cwd; private final Path installationDirectory; @@ -48,6 +47,7 @@ public abstract class BaseInvokerRequest implements InvokerRe private final OutputStream out; private final OutputStream err; private final List coreExtensions; + private final List jvmArguments; @SuppressWarnings("ParameterNumber") public BaseInvokerRequest( @@ -62,7 +62,8 @@ public BaseInvokerRequest( @Nullable InputStream in, @Nullable OutputStream out, @Nullable OutputStream err, - @Nullable List coreExtensions) { + @Nullable List coreExtensions, + @Nullable List jvmArguments) { this.parserRequest = requireNonNull(parserRequest); this.cwd = requireNonNull(cwd); this.installationDirectory = requireNonNull(installationDirectory); @@ -76,6 +77,7 @@ public BaseInvokerRequest( this.out = out; this.err = err; this.coreExtensions = coreExtensions; + this.jvmArguments = jvmArguments; } @Override @@ -137,4 +139,9 @@ public Optional err() { public Optional> coreExtensions() { return Optional.ofNullable(coreExtensions); } + + @Override + public Optional> jvmArguments() { + return Optional.ofNullable(jvmArguments); + } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java index 4dc2550d11ff..7071b7769c03 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java @@ -57,7 +57,7 @@ import static org.apache.maven.cling.invoker.Utils.stripLeadingAndTrailingQuotes; import static org.apache.maven.cling.invoker.Utils.toMap; -public abstract class BaseParser> implements Parser { +public abstract class BaseParser implements Parser { @SuppressWarnings("VisibilityModifier") public static class LocalContext { @@ -93,7 +93,7 @@ public Map extraInterpolationSource() { } @Override - public R parse(ParserRequest parserRequest) throws ParserException, IOException { + public InvokerRequest parse(ParserRequest parserRequest) throws ParserException, IOException { requireNonNull(parserRequest); LocalContext context = new LocalContext(parserRequest); @@ -108,7 +108,7 @@ public R parse(ParserRequest parserRequest) throws ParserException, IOException context.rootDirectory = getRootDirectory(context); // options - List parsedOptions = parseCliOptions(context); + List parsedOptions = parseCliOptions(context); // warn about deprecated options PrintWriter printWriter = new PrintWriter(parserRequest.out() != null ? parserRequest.out() : System.out, true); @@ -131,7 +131,7 @@ public R parse(ParserRequest parserRequest) throws ParserException, IOException return getInvokerRequest(context); } - protected abstract R getInvokerRequest(LocalContext context); + protected abstract InvokerRequest getInvokerRequest(LocalContext context); protected Path getCwd(LocalContext context) throws ParserException { if (context.parserRequest.cwd() != null) { @@ -271,9 +271,9 @@ protected Map populateUserProperties(LocalContext context) throw return toMap(userProperties); } - protected abstract List parseCliOptions(LocalContext context) throws ParserException, IOException; + protected abstract List parseCliOptions(LocalContext context) throws ParserException, IOException; - protected abstract O assembleOptions(List parsedOptions); + protected abstract Options assembleOptions(List parsedOptions); protected List readCoreExtensionsDescriptor(LocalContext context) throws ParserException, IOException { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsule.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsule.java index 39836fe043f8..a8c80ed983a9 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsule.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsule.java @@ -18,6 +18,8 @@ */ package org.apache.maven.cling.invoker; +import java.util.Optional; + import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.services.Lookup; @@ -32,6 +34,12 @@ public interface ContainerCapsule extends AutoCloseable { @Nonnull Lookup getLookup(); + /** + * The TCCL, if implementation requires it. + */ + @Nonnull + Optional currentThreadClassLoader(); + /** * Performs a clean shutdown of backing container. */ diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsuleFactory.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsuleFactory.java index ee01e3036f26..ff326daa69b4 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsuleFactory.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsuleFactory.java @@ -20,21 +20,15 @@ import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.cli.InvokerException; -import org.apache.maven.api.cli.InvokerRequest; -import org.apache.maven.api.cli.Options; +import org.apache.maven.api.services.Lookup; /** * Container capsule factory. - * - * @param the options type - * @param the invoker request type - * @param the invoker context type */ -public interface ContainerCapsuleFactory< - O extends Options, R extends InvokerRequest, C extends LookupInvoker.LookupInvokerContext> { +public interface ContainerCapsuleFactory { /** * Creates container capsule. */ @Nonnull - ContainerCapsule createContainerCapsule(C context) throws InvokerException; + ContainerCapsule createContainerCapsule(Lookup invokerLookup, LookupInvokerContext context) throws InvokerException; } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java index dc6ca2a698e1..d2487e5be142 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java @@ -24,8 +24,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -35,7 +33,6 @@ import java.util.function.Function; import org.apache.maven.api.Constants; -import org.apache.maven.api.Session; import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerRequest; @@ -43,7 +40,6 @@ import org.apache.maven.api.cli.Options; import org.apache.maven.api.services.BuilderProblem; import org.apache.maven.api.services.Interpolator; -import org.apache.maven.api.services.Lookup; import org.apache.maven.api.services.MavenException; import org.apache.maven.api.services.MessageBuilder; import org.apache.maven.api.services.SettingsBuilder; @@ -62,7 +58,6 @@ import org.apache.maven.artifact.repository.MavenArtifactRepository; import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; import org.apache.maven.bridge.MavenRepositorySystem; -import org.apache.maven.cling.invoker.mvn.ProtoSession; import org.apache.maven.cling.logging.Slf4jConfiguration; import org.apache.maven.cling.logging.Slf4jConfigurationFactory; import org.apache.maven.cling.transfer.ConsoleMavenTransferListener; @@ -82,7 +77,6 @@ import org.jline.terminal.TerminalBuilder; import org.jline.terminal.impl.AbstractPosixTerminal; import org.jline.terminal.spi.TerminalExt; -import org.slf4j.ILoggerFactory; import org.slf4j.LoggerFactory; import org.slf4j.spi.LocationAwareLogger; @@ -91,108 +85,11 @@ import static org.apache.maven.cling.invoker.Utils.toProperties; /** - * Plexus invoker implementation, that boots up Plexus DI container. This class expects fully setup ClassWorld via constructor. + * Lookup invoker implementation, that boots up DI container. * - * @param the options type - * @param the request type - * @param the context type + * @param The context type. */ -public abstract class LookupInvoker< - O extends Options, R extends InvokerRequest, C extends LookupInvoker.LookupInvokerContext> - implements Invoker { - - /** - * Exception for intentional exit: No message or anything will be displayed, just the - * carried exit code will be returned from {@link #invoke(InvokerRequest)} method. - */ - public static final class ExitException extends InvokerException { - private final int exitCode; - - public ExitException(int exitCode) { - super("EXIT"); - this.exitCode = exitCode; - } - } - - @SuppressWarnings("VisibilityModifier") - public static class LookupInvokerContext< - O extends Options, R extends InvokerRequest, C extends LookupInvokerContext> - implements AutoCloseable { - public final LookupInvoker invoker; - public final ProtoLookup protoLookup; - public final R invokerRequest; - public final Function cwdResolver; - public final Function installationResolver; - public final Function userResolver; - public final Session session; - - protected LookupInvokerContext(LookupInvoker invoker, R invokerRequest) { - this.invoker = invoker; - this.protoLookup = invoker.protoLookup; - this.invokerRequest = requireNonNull(invokerRequest); - this.cwdResolver = s -> invokerRequest.cwd().resolve(s).normalize().toAbsolutePath(); - this.installationResolver = s -> invokerRequest - .installationDirectory() - .resolve(s) - .normalize() - .toAbsolutePath(); - this.userResolver = s -> - invokerRequest.userHomeDirectory().resolve(s).normalize().toAbsolutePath(); - this.logger = invokerRequest.parserRequest().logger(); - - Map user = new HashMap<>(invokerRequest.userProperties()); - user.put("session.rootDirectory", invokerRequest.rootDirectory().toString()); - user.put("session.topDirectory", invokerRequest.topDirectory().toString()); - Map system = new HashMap<>(invokerRequest.systemProperties()); - this.session = ProtoSession.create(user, system); - } - - public Logger logger; - public ILoggerFactory loggerFactory; - public Slf4jConfiguration slf4jConfiguration; - public Slf4jConfiguration.Level loggerLevel; - public Boolean coloredOutput; - public Terminal terminal; - public Consumer writer; - public ClassLoader currentThreadContextClassLoader; - public ContainerCapsule containerCapsule; - public Lookup lookup; - public SettingsBuilder settingsBuilder; - - public boolean interactive; - public Path localRepositoryPath; - public Path installationSettingsPath; - public Path projectSettingsPath; - public Path userSettingsPath; - public Settings effectiveSettings; - - public final List closeables = new ArrayList<>(); - - @Override - public void close() throws InvokerException { - List causes = null; - List cs = new ArrayList<>(closeables); - Collections.reverse(cs); - for (AutoCloseable c : cs) { - if (c != null) { - try { - c.close(); - } catch (Exception e) { - if (causes == null) { - causes = new ArrayList<>(); - } - causes.add(e); - } - } - } - if (causes != null) { - InvokerException exception = new InvokerException("Unable to close context"); - causes.forEach(exception::addSuppressed); - throw exception; - } - } - } - +public abstract class LookupInvoker implements Invoker { protected final ProtoLookup protoLookup; public LookupInvoker(ProtoLookup protoLookup) { @@ -200,19 +97,22 @@ public LookupInvoker(ProtoLookup protoLookup) { } @Override - public int invoke(R invokerRequest) throws InvokerException { + public int invoke(InvokerRequest invokerRequest) throws InvokerException { requireNonNull(invokerRequest); Properties oldProps = (Properties) System.getProperties().clone(); ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); try (C context = createContext(invokerRequest)) { try { - if (context.currentThreadContextClassLoader != null) { - Thread.currentThread().setContextClassLoader(context.currentThreadContextClassLoader); + if (context.containerCapsule.currentThreadClassLoader().isPresent()) { + Thread.currentThread() + .setContextClassLoader(context.containerCapsule + .currentThreadClassLoader() + .get()); } return doInvoke(context); - } catch (ExitException e) { - return e.exitCode; + } catch (InvokerException.ExitException e) { + return e.getExitCode(); } catch (Exception e) { throw handleException(context, e); } @@ -238,8 +138,7 @@ protected int doInvoke(C context) throws Exception { return execute(context); } - protected InvokerException handleException(LookupInvokerContext context, Exception e) - throws InvokerException { + protected InvokerException handleException(C context, Exception e) throws InvokerException { boolean showStackTrace = context.invokerRequest.options().showErrors().orElse(false); if (showStackTrace) { context.logger.error( @@ -255,10 +154,10 @@ protected InvokerException handleException(LookupInvokerContext context return new InvokerException(e.getMessage(), e); } - protected abstract C createContext(R invokerRequest) throws InvokerException; + protected abstract C createContext(InvokerRequest invokerRequest) throws InvokerException; protected void pushProperties(C context) throws Exception { - R invokerRequest = context.invokerRequest; + InvokerRequest invokerRequest = context.invokerRequest; HashSet sys = new HashSet<>(invokerRequest.systemProperties().keySet()); invokerRequest.userProperties().entrySet().stream() .filter(k -> !sys.contains(k.getKey())) @@ -272,7 +171,7 @@ protected void validate(C context) throws Exception {} protected void prepare(C context) throws Exception {} protected void configureLogging(C context) throws Exception { - R invokerRequest = context.invokerRequest; + InvokerRequest invokerRequest = context.invokerRequest; // LOG COLOR Options mavenOptions = invokerRequest.options(); Map userProperties = invokerRequest.userProperties(); @@ -338,7 +237,7 @@ protected Terminal createTerminal(C context) { } protected void doConfigureWithTerminal(C context, Terminal terminal) { - O options = context.invokerRequest.options(); + Options options = context.invokerRequest.options(); if (options.rawStreams().isEmpty() || !options.rawStreams().get()) { MavenSimpleLogger stdout = (MavenSimpleLogger) context.loggerFactory.getLogger("stdout"); MavenSimpleLogger stderr = (MavenSimpleLogger) context.loggerFactory.getLogger("stderr"); @@ -358,7 +257,7 @@ protected Consumer determineWriter(C context) { } protected Consumer doDetermineWriter(C context) { - O options = context.invokerRequest.options(); + Options options = context.invokerRequest.options(); if (options.logFile().isPresent()) { Path logFile = context.cwdResolver.apply(options.logFile().get()); try { @@ -380,7 +279,7 @@ protected Consumer doDetermineWriter(C context) { } protected void activateLogging(C context) throws Exception { - R invokerRequest = context.invokerRequest; + InvokerRequest invokerRequest = context.invokerRequest; Options mavenOptions = invokerRequest.options(); context.slf4jConfiguration.activate(); @@ -412,21 +311,21 @@ protected void activateLogging(C context) throws Exception { } protected void helpOrVersionAndMayExit(C context) throws Exception { - R invokerRequest = context.invokerRequest; + InvokerRequest invokerRequest = context.invokerRequest; if (invokerRequest.options().help().isPresent()) { Consumer writer = determineWriter(context); invokerRequest.options().displayHelp(context.invokerRequest.parserRequest(), writer); - throw new ExitException(0); + throw new InvokerException.ExitException(0); } if (invokerRequest.options().showVersionAndExit().isPresent()) { showVersion(context); - throw new ExitException(0); + throw new InvokerException.ExitException(0); } } protected void showVersion(C context) { Consumer writer = determineWriter(context); - R invokerRequest = context.invokerRequest; + InvokerRequest invokerRequest = context.invokerRequest; if (invokerRequest.options().quiet().orElse(false)) { writer.accept(CLIReportingUtils.showVersionMinimal()); } else if (invokerRequest.options().verbose().orElse(false)) { @@ -466,7 +365,7 @@ protected void preCommands(C context) throws Exception { } protected void container(C context) throws Exception { - context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(context); + context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(protoLookup, context); context.closeables.add(context.containerCapsule); context.lookup = context.containerCapsule.getLookup(); context.settingsBuilder = context.lookup.lookup(SettingsBuilder.class); @@ -478,8 +377,8 @@ protected void container(C context) throws Exception { .log(message); } - protected ContainerCapsuleFactory createContainerCapsuleFactory() { - return new PlexusContainerCapsuleFactory<>(); + protected ContainerCapsuleFactory createContainerCapsuleFactory() { + return new PlexusContainerCapsuleFactory(); } protected void lookup(C context) throws Exception {} @@ -487,7 +386,7 @@ protected void lookup(C context) throws Exception {} protected void init(C context) throws Exception {} protected void postCommands(C context) throws Exception { - R invokerRequest = context.invokerRequest; + InvokerRequest invokerRequest = context.invokerRequest; Logger logger = context.logger; if (invokerRequest.options().showErrors().orElse(false)) { logger.info("Error stacktraces are turned on."); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvokerContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvokerContext.java new file mode 100644 index 000000000000..84fe7b60dd56 --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvokerContext.java @@ -0,0 +1,111 @@ +/* + * 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.invoker; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.apache.maven.api.Session; +import org.apache.maven.api.cli.InvokerException; +import org.apache.maven.api.cli.InvokerRequest; +import org.apache.maven.api.cli.Logger; +import org.apache.maven.api.services.Lookup; +import org.apache.maven.api.services.SettingsBuilder; +import org.apache.maven.api.settings.Settings; +import org.apache.maven.cling.invoker.mvn.ProtoSession; +import org.apache.maven.cling.logging.Slf4jConfiguration; +import org.jline.terminal.Terminal; +import org.slf4j.ILoggerFactory; + +import static java.util.Objects.requireNonNull; + +@SuppressWarnings("VisibilityModifier") +public class LookupInvokerContext implements AutoCloseable { + public final InvokerRequest invokerRequest; + public final Function cwdResolver; + public final Function installationResolver; + public final Function userResolver; + public final Session session; + + protected LookupInvokerContext(InvokerRequest invokerRequest) { + this.invokerRequest = requireNonNull(invokerRequest); + this.cwdResolver = s -> invokerRequest.cwd().resolve(s).normalize().toAbsolutePath(); + this.installationResolver = s -> + invokerRequest.installationDirectory().resolve(s).normalize().toAbsolutePath(); + this.userResolver = + s -> invokerRequest.userHomeDirectory().resolve(s).normalize().toAbsolutePath(); + this.logger = invokerRequest.parserRequest().logger(); + + Map user = new HashMap<>(invokerRequest.userProperties()); + user.put("session.rootDirectory", invokerRequest.rootDirectory().toString()); + user.put("session.topDirectory", invokerRequest.topDirectory().toString()); + Map system = new HashMap<>(invokerRequest.systemProperties()); + this.session = ProtoSession.create(user, system); + } + + public Logger logger; + public ILoggerFactory loggerFactory; + public Slf4jConfiguration slf4jConfiguration; + public Slf4jConfiguration.Level loggerLevel; + public Boolean coloredOutput; + public Terminal terminal; + public Consumer writer; + public ContainerCapsule containerCapsule; + public Lookup lookup; + public SettingsBuilder settingsBuilder; + + public boolean interactive; + public Path localRepositoryPath; + public Path installationSettingsPath; + public Path projectSettingsPath; + public Path userSettingsPath; + public Settings effectiveSettings; + + public final List closeables = new ArrayList<>(); + + @Override + public void close() throws InvokerException { + List causes = null; + List cs = new ArrayList<>(closeables); + Collections.reverse(cs); + for (AutoCloseable c : cs) { + if (c != null) { + try { + c.close(); + } catch (Exception e) { + if (causes == null) { + causes = new ArrayList<>(); + } + causes.add(e); + } + } + } + if (causes != null) { + InvokerException exception = new InvokerException("Unable to close context"); + causes.forEach(exception::addSuppressed); + throw exception; + } + } +} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsule.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsule.java index bd9b9507c8f4..05d53272d309 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsule.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsule.java @@ -18,6 +18,8 @@ */ package org.apache.maven.cling.invoker; +import java.util.Optional; + import org.apache.maven.api.services.Lookup; import org.apache.maven.internal.impl.DefaultLookup; import org.codehaus.plexus.PlexusContainer; @@ -43,6 +45,11 @@ public Lookup getLookup() { return lookup; } + @Override + public Optional currentThreadClassLoader() { + return Optional.of(plexusContainer.getContainerRealm()); + } + @Override public void close() { try { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java index 3e70d4c9714f..cf1235bfde56 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java @@ -33,8 +33,8 @@ import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.Logger; -import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.extensions.CoreExtension; +import org.apache.maven.api.services.Lookup; import org.apache.maven.api.services.MessageBuilderFactory; import org.apache.maven.api.services.SettingsBuilder; import org.apache.maven.cling.extensions.BootstrapCoreExtensionManager; @@ -64,25 +64,21 @@ /** * Container capsule backed by Plexus Container. - * - * @param the options type - * @param the invoker request type - * @param the invoker context type */ -public class PlexusContainerCapsuleFactory< - O extends Options, R extends InvokerRequest, C extends LookupInvoker.LookupInvokerContext> - implements ContainerCapsuleFactory { +public class PlexusContainerCapsuleFactory implements ContainerCapsuleFactory { @Override - public ContainerCapsule createContainerCapsule(C context) throws InvokerException { + public ContainerCapsule createContainerCapsule(Lookup invokerLookup, LookupInvokerContext context) + throws InvokerException { try { - return new PlexusContainerCapsule(Thread.currentThread().getContextClassLoader(), container(context)); + return new PlexusContainerCapsule( + Thread.currentThread().getContextClassLoader(), container(invokerLookup, context)); } catch (Exception e) { throw new InvokerException("Failed to create plexus container capsule", e); } } - protected PlexusContainer container(C context) throws Exception { - ClassWorld classWorld = context.protoLookup.lookup(ClassWorld.class); + protected PlexusContainer container(Lookup invokerLookup, LookupInvokerContext context) throws Exception { + ClassWorld classWorld = invokerLookup.lookup(ClassWorld.class); ClassRealm coreRealm = classWorld.getClassRealm("plexus.core"); List extClassPath = parseExtClasspath(context); CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom(coreRealm); @@ -112,7 +108,7 @@ protected PlexusContainer container(C context) throws Exception { Thread.currentThread().setContextClassLoader(container.getContainerRealm()); container.setLoggerManager(createLoggerManager()); - R invokerRequest = context.invokerRequest; + InvokerRequest invokerRequest = context.invokerRequest; Function extensionSource = expression -> { String value = invokerRequest.userProperties().get(expression); if (value == null) { @@ -173,7 +169,7 @@ protected Set collectExportedPackages( * where the components are on index (are annotated with JSR330 annotations and Sisu index is created) and, they * have priorities set. */ - protected Module getCustomModule(C context, CoreExports exports) { + protected Module getCustomModule(LookupInvokerContext context, CoreExports exports) { return new AbstractModule() { @Override protected void configure() { @@ -188,12 +184,13 @@ protected LoggerManager createLoggerManager() { return new Slf4jLoggerManager(); } - protected void customizeContainerConfiguration(C context, ContainerConfiguration configuration) throws Exception {} + protected void customizeContainerConfiguration(LookupInvokerContext context, ContainerConfiguration configuration) + throws Exception {} - protected void customizeContainer(C context, PlexusContainer container) throws Exception {} + protected void customizeContainer(LookupInvokerContext context, PlexusContainer container) throws Exception {} - protected List parseExtClasspath(C context) throws Exception { - R invokerRequest = context.invokerRequest; + protected List parseExtClasspath(LookupInvokerContext context) throws Exception { + InvokerRequest invokerRequest = context.invokerRequest; String extClassPath = invokerRequest.userProperties().get(Constants.MAVEN_EXT_CLASS_PATH); if (extClassPath == null) { extClassPath = invokerRequest.systemProperties().get(Constants.MAVEN_EXT_CLASS_PATH); @@ -255,8 +252,8 @@ protected ClassRealm setupContainerRealm( } protected List loadCoreExtensions( - C context, ClassRealm containerRealm, Set providedArtifacts) throws Exception { - R invokerRequest = context.invokerRequest; + LookupInvokerContext context, ClassRealm containerRealm, Set providedArtifacts) throws Exception { + InvokerRequest invokerRequest = context.invokerRequest; if (invokerRequest.coreExtensions().isEmpty() || invokerRequest.coreExtensions().get().isEmpty()) { return Collections.emptyList(); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenParser.java deleted file mode 100644 index 78db2be0848b..000000000000 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenParser.java +++ /dev/null @@ -1,62 +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.invoker.mvn; - -import java.util.List; - -import org.apache.commons.cli.ParseException; -import org.apache.maven.api.cli.ParserException; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; -import org.apache.maven.api.cli.mvn.MavenOptions; -import org.apache.maven.api.cli.mvn.MavenParser; - -public class DefaultMavenParser extends BaseMavenParser> - implements MavenParser> { - @Override - protected DefaultMavenInvokerRequest getInvokerRequest(LocalContext context) { - return new DefaultMavenInvokerRequest<>( - context.parserRequest, - context.cwd, - context.installationDirectory, - context.userHomeDirectory, - context.userProperties, - context.systemProperties, - context.topDirectory, - context.rootDirectory, - context.parserRequest.in(), - context.parserRequest.out(), - context.parserRequest.err(), - context.extensions, - (MavenOptions) context.options); - } - - @Override - protected MavenOptions parseArgs(String source, List args) throws ParserException { - try { - return CommonsCliMavenOptions.parse(source, args.toArray(new String[0])); - } catch (ParseException e) { - throw new ParserException("Failed to parse source " + source + ": " + e.getMessage(), e.getCause()); - } - } - - @Override - protected MavenOptions assembleOptions(List parsedOptions) { - return LayeredMavenOptions.layerMavenOptions(parsedOptions); - } -} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java similarity index 88% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvoker.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java index 665256d1277f..7a2fba2b7cd9 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java @@ -34,9 +34,9 @@ import org.apache.maven.InternalErrorException; import org.apache.maven.Maven; import org.apache.maven.api.Constants; +import org.apache.maven.api.cli.InvokerException; +import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.Logger; -import org.apache.maven.api.cli.mvn.MavenInvoker; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.api.services.BuilderProblem; import org.apache.maven.api.services.SettingsBuilderRequest; @@ -48,6 +48,7 @@ import org.apache.maven.api.services.model.ModelProcessor; import org.apache.maven.cling.event.ExecutionEventLogger; import org.apache.maven.cling.invoker.LookupInvoker; +import org.apache.maven.cling.invoker.LookupInvokerContext; import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.Utils; import org.apache.maven.cling.utils.CLIReportingUtils; @@ -77,20 +78,15 @@ import static java.util.Comparator.comparing; import static org.apache.maven.cling.invoker.Utils.toProperties; -public abstract class DefaultMavenInvoker< - O extends MavenOptions, - R extends MavenInvokerRequest, - C extends DefaultMavenInvoker.MavenContext> - extends LookupInvoker implements MavenInvoker { +/** + * The "local" Maven invoker, that expects whole Maven on classpath and invokes it. + */ +public class MavenInvoker extends LookupInvoker { @SuppressWarnings("VisibilityModifier") - public static class MavenContext< - O extends MavenOptions, - R extends MavenInvokerRequest, - C extends DefaultMavenInvoker.MavenContext> - extends LookupInvokerContext { - protected MavenContext(DefaultMavenInvoker invoker, R invokerRequest) { - super(invoker, invokerRequest); + public static class MavenContext extends LookupInvokerContext { + protected MavenContext(InvokerRequest invokerRequest) { + super(invokerRequest); } public BuildEventListener buildEventListener; @@ -102,19 +98,24 @@ protected MavenContext(DefaultMavenInvoker invoker, R invokerRequest) { public Maven maven; } - public DefaultMavenInvoker(ProtoLookup protoLookup) { + public MavenInvoker(ProtoLookup protoLookup) { super(protoLookup); } @Override - protected int execute(C context) throws Exception { + protected MavenContext createContext(InvokerRequest invokerRequest) throws InvokerException { + return new MavenContext(invokerRequest); + } + + @Override + protected int execute(MavenContext context) throws Exception { toolchains(context); populateRequest(context, context.mavenExecutionRequest); return doExecute(context); } @Override - protected void prepare(C context) throws Exception { + protected void prepare(MavenContext context) throws Exception { // explicitly fill in "defaults"? DefaultMavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest(); mavenExecutionRequest.setRepositoryCache(new DefaultRepositoryCache()); @@ -133,7 +134,7 @@ protected void prepare(C context) throws Exception { } @Override - protected void lookup(C context) throws Exception { + protected void lookup(MavenContext context) throws Exception { context.eventSpyDispatcher = context.lookup.lookup(EventSpyDispatcher.class); context.mavenExecutionRequestPopulator = context.lookup.lookup(MavenExecutionRequestPopulator.class); context.toolchainsBuilder = context.lookup.lookup(ToolchainsBuilder.class); @@ -142,8 +143,8 @@ protected void lookup(C context) throws Exception { } @Override - protected void init(C context) throws Exception { - MavenInvokerRequest invokerRequest = context.invokerRequest; + protected void init(MavenContext context) throws Exception { + InvokerRequest invokerRequest = context.invokerRequest; Map data = new HashMap<>(); data.put("plexus", context.lookup.lookup(PlexusContainer.class)); data.put("workingDirectory", invokerRequest.cwd().toString()); @@ -154,10 +155,10 @@ protected void init(C context) throws Exception { } @Override - protected void postCommands(C context) throws Exception { + protected void postCommands(MavenContext context) throws Exception { super.postCommands(context); - R invokerRequest = context.invokerRequest; + InvokerRequest invokerRequest = context.invokerRequest; Logger logger = context.logger; if (invokerRequest.options().relaxedChecksums().orElse(false)) { logger.info("Disabling strict checksum verification on all artifact downloads."); @@ -167,7 +168,7 @@ protected void postCommands(C context) throws Exception { } @Override - protected void configureLogging(C context) throws Exception { + protected void configureLogging(MavenContext context) throws Exception { super.configureLogging(context); // Create the build log appender ProjectBuildLogAppender projectBuildLogAppender = @@ -175,33 +176,34 @@ protected void configureLogging(C context) throws Exception { context.closeables.add(projectBuildLogAppender); } - protected BuildEventListener determineBuildEventListener(C context) { + protected BuildEventListener determineBuildEventListener(MavenContext context) { if (context.buildEventListener == null) { context.buildEventListener = doDetermineBuildEventListener(context); } return context.buildEventListener; } - protected BuildEventListener doDetermineBuildEventListener(C context) { + protected BuildEventListener doDetermineBuildEventListener(MavenContext context) { Consumer writer = determineWriter(context); return new SimpleBuildEventListener(writer); } @Override - protected void customizeSettingsRequest(C context, SettingsBuilderRequest settingsBuilderRequest) { + protected void customizeSettingsRequest(MavenContext context, SettingsBuilderRequest settingsBuilderRequest) { if (context.eventSpyDispatcher != null) { context.eventSpyDispatcher.onEvent(settingsBuilderRequest); } } @Override - protected void customizeSettingsResult(C context, SettingsBuilderResult settingsBuilderResult) throws Exception { + protected void customizeSettingsResult(MavenContext context, SettingsBuilderResult settingsBuilderResult) + throws Exception { if (context.eventSpyDispatcher != null) { context.eventSpyDispatcher.onEvent(settingsBuilderResult); } } - protected void toolchains(C context) throws Exception { + protected void toolchains(MavenContext context) throws Exception { Path userToolchainsFile = null; if (context.invokerRequest.options().altUserToolchains().isPresent()) { @@ -281,7 +283,7 @@ protected void toolchains(C context) throws Exception { } @Override - protected void populateRequest(C context, MavenExecutionRequest request) throws Exception { + protected void populateRequest(MavenContext context, MavenExecutionRequest request) throws Exception { super.populateRequest(context, request); if (context.invokerRequest.rootDirectory().isEmpty()) { // maven requires this to be set; so default it (and see below at POM) @@ -290,7 +292,7 @@ protected void populateRequest(C context, MavenExecutionRequest request) throws request.setRootDirectory(context.invokerRequest.topDirectory()); } - MavenOptions options = context.invokerRequest.options(); + MavenOptions options = (MavenOptions) context.invokerRequest.options(); request.setNoSnapshotUpdates(options.suppressSnapshotUpdates().orElse(false)); request.setGoals(options.goals().orElse(List.of())); request.setReactorFailureBehavior(determineReactorFailureBehaviour(context)); @@ -346,9 +348,9 @@ protected void populateRequest(C context, MavenExecutionRequest request) throws // parameters but this is sufficient for now. Ultimately we want components like Builders to provide a way to // extend the command line to accept its own configuration parameters. // - if (context.invokerRequest.options().threads().isPresent()) { - int degreeOfConcurrency = calculateDegreeOfConcurrency( - context.invokerRequest.options().threads().get()); + if (options.threads().isPresent()) { + int degreeOfConcurrency = + calculateDegreeOfConcurrency(options.threads().get()); if (degreeOfConcurrency > 1) { request.setBuilderId("multithreaded"); request.setDegreeOfConcurrency(degreeOfConcurrency); @@ -358,12 +360,12 @@ protected void populateRequest(C context, MavenExecutionRequest request) throws // // Allow the builder to be overridden by the user if requested. The builders are now pluggable. // - if (context.invokerRequest.options().builder().isPresent()) { - request.setBuilderId(context.invokerRequest.options().builder().get()); + if (options.builder().isPresent()) { + request.setBuilderId(options.builder().get()); } } - protected Path determinePom(C context) { + protected Path determinePom(MavenContext context) { Path current = context.invokerRequest.cwd(); if (context.invokerRequest.options().alternatePomFile().isPresent()) { current = context.cwdResolver.apply( @@ -376,8 +378,8 @@ protected Path determinePom(C context) { } } - protected String determineReactorFailureBehaviour(C context) { - MavenOptions mavenOptions = context.invokerRequest.options(); + protected String determineReactorFailureBehaviour(MavenContext context) { + MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.failFast().isPresent()) { return MavenExecutionRequest.REACTOR_FAIL_FAST; } else if (mavenOptions.failAtEnd().isPresent()) { @@ -389,8 +391,8 @@ protected String determineReactorFailureBehaviour(C context) { } } - protected String determineGlobalChecksumPolicy(C context) { - MavenOptions mavenOptions = context.invokerRequest.options(); + protected String determineGlobalChecksumPolicy(MavenContext context) { + MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.strictChecksums().orElse(false)) { return MavenExecutionRequest.CHECKSUM_POLICY_FAIL; } else if (mavenOptions.relaxedChecksums().orElse(false)) { @@ -400,7 +402,7 @@ protected String determineGlobalChecksumPolicy(C context) { } } - protected ExecutionListener determineExecutionListener(C context) { + protected ExecutionListener determineExecutionListener(MavenContext context) { ExecutionListener listener = new ExecutionEventLogger(context.invokerRequest.messageBuilderFactory()); if (context.eventSpyDispatcher != null) { listener = context.eventSpyDispatcher.chainListener(listener); @@ -409,13 +411,13 @@ protected ExecutionListener determineExecutionListener(C context) { return listener; } - protected TransferListener determineTransferListener(C context, boolean noTransferProgress) { + protected TransferListener determineTransferListener(MavenContext context, boolean noTransferProgress) { TransferListener delegate = super.determineTransferListener(context, noTransferProgress); return new MavenTransferListener(delegate, determineBuildEventListener(context)); } - protected String determineMakeBehavior(C context) { - MavenOptions mavenOptions = context.invokerRequest.options(); + protected String determineMakeBehavior(MavenContext context) { + MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.alsoMake().isPresent() && mavenOptions.alsoMakeDependents().isEmpty()) { return MavenExecutionRequest.REACTOR_MAKE_UPSTREAM; @@ -430,8 +432,8 @@ protected String determineMakeBehavior(C context) { } } - protected void performProjectActivation(C context, ProjectActivation projectActivation) { - MavenOptions mavenOptions = context.invokerRequest.options(); + protected void performProjectActivation(MavenContext context, ProjectActivation projectActivation) { + MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.projects().isPresent() && !mavenOptions.projects().get().isEmpty()) { List optionValues = mavenOptions.projects().get(); @@ -458,8 +460,8 @@ protected void performProjectActivation(C context, ProjectActivation projectActi } } - protected void performProfileActivation(C context, ProfileActivation profileActivation) { - MavenOptions mavenOptions = context.invokerRequest.options(); + protected void performProfileActivation(MavenContext context, ProfileActivation profileActivation) { + MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.activatedProfiles().isPresent() && !mavenOptions.activatedProfiles().get().isEmpty()) { List optionValues = mavenOptions.activatedProfiles().get(); @@ -486,7 +488,7 @@ protected void performProfileActivation(C context, ProfileActivation profileActi } } - protected int doExecute(C context) throws Exception { + protected int doExecute(MavenContext context) throws Exception { MavenExecutionRequest request = context.mavenExecutionRequest; context.eventSpyDispatcher.onEvent(request); @@ -560,7 +562,7 @@ protected int doExecute(C context) throws Exception { } } - protected void logBuildResumeHint(C context, String resumeBuildHint) { + protected void logBuildResumeHint(MavenContext context, String resumeBuildHint) { context.logger.error(""); context.logger.error("After correcting the problems, you can resume the build with the command"); context.logger.error( @@ -603,7 +605,8 @@ protected String getResumeFromSelector(List mavenProjects, MavenPr protected static final String ANSI_RESET = "\u001B\u005Bm"; - protected void logSummary(C context, ExceptionSummary summary, Map references, String indent) { + protected void logSummary( + MavenContext context, ExceptionSummary summary, Map references, String indent) { String referenceKey = ""; if (summary.getReference() != null && !summary.getReference().isEmpty()) { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvokerRequest.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvokerRequest.java similarity index 85% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvokerRequest.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvokerRequest.java index 1ae5cf7b7729..788c67e40f8e 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvokerRequest.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvokerRequest.java @@ -27,7 +27,6 @@ import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.api.cli.extensions.CoreExtension; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.cling.invoker.BaseInvokerRequest; @@ -35,15 +34,12 @@ /** * Maven execution request. - * - * @param the options type this request carries */ -public class DefaultMavenInvokerRequest extends BaseInvokerRequest - implements MavenInvokerRequest { - private final O options; +public class MavenInvokerRequest extends BaseInvokerRequest { + private final MavenOptions options; @SuppressWarnings("ParameterNumber") - public DefaultMavenInvokerRequest( + public MavenInvokerRequest( ParserRequest parserRequest, Path cwd, Path installationDirectory, @@ -56,7 +52,8 @@ public DefaultMavenInvokerRequest( OutputStream out, OutputStream err, List coreExtensions, - O options) { + List jvmArguments, + MavenOptions options) { super( parserRequest, cwd, @@ -69,7 +66,8 @@ public DefaultMavenInvokerRequest( in, out, err, - coreExtensions); + coreExtensions, + jvmArguments); this.options = requireNonNull(options); } @@ -77,7 +75,7 @@ public DefaultMavenInvokerRequest( * The mandatory Maven options. */ @Nonnull - public O options() { + public MavenOptions options() { return options; } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/BaseMavenParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java similarity index 55% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/BaseMavenParser.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java index d2b5752f0cb8..528cdd0f13c1 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/BaseMavenParser.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java @@ -26,19 +26,17 @@ import java.util.List; import java.util.stream.Stream; +import org.apache.commons.cli.ParseException; import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.ParserException; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenOptions; -import org.apache.maven.api.cli.mvn.MavenParser; import org.apache.maven.cling.invoker.BaseParser; -public abstract class BaseMavenParser> extends BaseParser - implements MavenParser { +public class MavenParser extends BaseParser { @Override - protected List parseCliOptions(LocalContext context) throws ParserException, IOException { - ArrayList result = new ArrayList<>(); + protected List parseCliOptions(LocalContext context) throws ParserException, IOException { + ArrayList result = new ArrayList<>(); // CLI args result.add(parseMavenCliOptions(context.parserRequest.args())); // maven.config; if exists @@ -49,15 +47,15 @@ protected List parseCliOptions(LocalContext context) throws ParserException, return result; } - protected O parseMavenCliOptions(List args) throws ParserException { + protected MavenOptions parseMavenCliOptions(List args) throws ParserException { return parseArgs(Options.SOURCE_CLI, args); } - protected O parseMavenConfigOptions(Path configFile) throws ParserException, IOException { + protected MavenOptions parseMavenConfigOptions(Path configFile) throws ParserException, IOException { try (Stream lines = Files.lines(configFile, Charset.defaultCharset())) { List args = lines.filter(arg -> !arg.isEmpty() && !arg.startsWith("#")).toList(); - O options = parseArgs("maven.config", args); + MavenOptions options = parseArgs("maven.config", args); if (options.goals().isPresent()) { // This file can only contain options, not args (goals or phases) throw new ParserException("Unrecognized maven.config file entries: " @@ -67,5 +65,36 @@ protected O parseMavenConfigOptions(Path configFile) throws ParserException, IOE } } - protected abstract O parseArgs(String source, List args) throws ParserException; + @Override + protected MavenInvokerRequest getInvokerRequest(LocalContext context) { + return new MavenInvokerRequest( + context.parserRequest, + context.cwd, + context.installationDirectory, + context.userHomeDirectory, + context.userProperties, + context.systemProperties, + context.topDirectory, + context.rootDirectory, + context.parserRequest.in(), + context.parserRequest.out(), + context.parserRequest.err(), + context.extensions, + null, + (MavenOptions) context.options); + } + + protected MavenOptions parseArgs(String source, List args) throws ParserException { + try { + return CommonsCliMavenOptions.parse(source, args.toArray(new String[0])); + } catch (ParseException e) { + throw new ParserException("Failed to parse source " + source + ": " + e.getMessage(), e.getCause()); + } + } + + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + protected MavenOptions assembleOptions(List parsedOptions) { + return LayeredMavenOptions.layerMavenOptions((List) parsedOptions); + } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvokerRequest.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvokerRequest.java deleted file mode 100644 index d62c2b77b4e2..000000000000 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvokerRequest.java +++ /dev/null @@ -1,78 +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.invoker.mvn.forked; - -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import org.apache.maven.api.cli.ParserRequest; -import org.apache.maven.api.cli.extensions.CoreExtension; -import org.apache.maven.api.cli.mvn.MavenOptions; -import org.apache.maven.api.cli.mvn.forked.ForkedMavenInvokerRequest; -import org.apache.maven.cling.invoker.mvn.DefaultMavenInvokerRequest; - -/** - * Maven execution request. - */ -public class DefaultForkedMavenInvokerRequest extends DefaultMavenInvokerRequest - implements ForkedMavenInvokerRequest { - private final List jvmArguments; - - @SuppressWarnings("ParameterNumber") - public DefaultForkedMavenInvokerRequest( - ParserRequest parserRequest, - Path cwd, - Path installationDirectory, - Path userHomeDirectory, - Map userProperties, - Map systemProperties, - Path topDirectory, - Path rootDirectory, - InputStream in, - OutputStream out, - OutputStream err, - List coreExtensions, - List jvmArguments, - MavenOptions options) { - super( - parserRequest, - cwd, - installationDirectory, - userHomeDirectory, - userProperties, - systemProperties, - topDirectory, - rootDirectory, - in, - out, - err, - coreExtensions, - options); - this.jvmArguments = jvmArguments; - } - - @Override - public Optional> jvmArguments() { - return Optional.ofNullable(jvmArguments); - } -} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvoker.java similarity index 94% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvoker.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvoker.java index 647c4a44d9a4..12b8bf491df8 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvoker.java @@ -23,21 +23,21 @@ import java.util.Collections; import java.util.Map; +import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.InvokerException; +import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.mvn.MavenOptions; -import org.apache.maven.api.cli.mvn.forked.ForkedMavenInvoker; -import org.apache.maven.api.cli.mvn.forked.ForkedMavenInvokerRequest; import org.apache.maven.internal.impl.model.profile.Os; import static java.util.Objects.requireNonNull; /** - * Forked invoker implementation, it spawns a subprocess with Maven. + * Forked invoker implementation, that spawns a subprocess with Maven. */ -public class DefaultForkedMavenInvoker implements ForkedMavenInvoker { +public class ForkedMavenInvoker implements Invoker { @SuppressWarnings("MethodLength") @Override - public int invoke(ForkedMavenInvokerRequest invokerRequest) throws InvokerException { + public int invoke(InvokerRequest invokerRequest) throws InvokerException { requireNonNull(invokerRequest); validate(invokerRequest); @@ -51,7 +51,7 @@ public int invoke(ForkedMavenInvokerRequest invokerRequest) throws InvokerExcept : invokerRequest.parserRequest().command()) .toString()); - MavenOptions mavenOptions = invokerRequest.options(); + MavenOptions mavenOptions = (MavenOptions) invokerRequest.options(); if (mavenOptions.userProperties().isPresent()) { for (Map.Entry entry : mavenOptions.userProperties().get().entrySet()) { @@ -216,5 +216,5 @@ public int invoke(ForkedMavenInvokerRequest invokerRequest) throws InvokerExcept } } - protected void validate(ForkedMavenInvokerRequest invokerRequest) throws InvokerException {} + protected void validate(InvokerRequest invokerRequest) throws InvokerException {} } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenParser.java similarity index 63% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenParser.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenParser.java index c46164e822b5..34d9187a48f5 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenParser.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenParser.java @@ -26,25 +26,19 @@ import java.util.List; import java.util.stream.Collectors; -import org.apache.commons.cli.ParseException; -import org.apache.maven.api.cli.ParserException; import org.apache.maven.api.cli.mvn.MavenOptions; -import org.apache.maven.api.cli.mvn.forked.ForkedMavenInvokerRequest; -import org.apache.maven.api.cli.mvn.forked.ForkedMavenParser; -import org.apache.maven.cling.invoker.mvn.BaseMavenParser; -import org.apache.maven.cling.invoker.mvn.CommonsCliMavenOptions; -import org.apache.maven.cling.invoker.mvn.LayeredMavenOptions; +import org.apache.maven.cling.invoker.mvn.MavenInvokerRequest; +import org.apache.maven.cling.invoker.mvn.MavenParser; /** - * Forked invoker that invokes Maven in a child process. + * Forked invoker parser that collects JVM arguments as well. */ -public class DefaultForkedMavenParser extends BaseMavenParser - implements ForkedMavenParser { +public class ForkedMavenParser extends MavenParser { @SuppressWarnings("ParameterNumber") @Override - protected ForkedMavenInvokerRequest getInvokerRequest(LocalContext context) { - return new DefaultForkedMavenInvokerRequest( + protected MavenInvokerRequest getInvokerRequest(LocalContext context) { + return new MavenInvokerRequest( context.parserRequest, context.cwd, context.installationDirectory, @@ -77,20 +71,4 @@ protected List getJvmArguments(Path rootDirectory) { } return null; } - - // TODO: same is in DefaultMavenParser!!! (duplication) - @Override - protected MavenOptions parseArgs(String source, List args) throws ParserException { - try { - return CommonsCliMavenOptions.parse(source, args.toArray(new String[0])); - } catch (ParseException e) { - throw new ParserException("Failed to parse source " + source, e.getCause()); - } - } - - // TODO: same is in DefaultMavenParser!!! (duplication) - @Override - protected MavenOptions assembleOptions(List parsedOptions) { - return LayeredMavenOptions.layerMavenOptions(parsedOptions); - } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvoker.java deleted file mode 100644 index 0f68baccdae2..000000000000 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvoker.java +++ /dev/null @@ -1,54 +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.invoker.mvn.local; - -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; -import org.apache.maven.api.cli.mvn.MavenOptions; -import org.apache.maven.api.cli.mvn.local.LocalMavenInvoker; -import org.apache.maven.cling.invoker.ProtoLookup; -import org.apache.maven.cling.invoker.mvn.DefaultMavenInvoker; - -/** - * Local invoker implementation, when Maven CLI is being run. System uses ClassWorld launcher, and class world - * instance is passed in via "enhanced" main method. Hence, this class expects fully setup ClassWorld via constructor. - * - * @see org.apache.maven.cling.MavenCling - */ -public class DefaultLocalMavenInvoker - extends DefaultMavenInvoker< - MavenOptions, MavenInvokerRequest, DefaultLocalMavenInvoker.LocalContext> - implements LocalMavenInvoker { - - public static class LocalContext - extends DefaultMavenInvoker.MavenContext< - MavenOptions, MavenInvokerRequest, DefaultLocalMavenInvoker.LocalContext> { - protected LocalContext(DefaultLocalMavenInvoker invoker, MavenInvokerRequest invokerRequest) { - super(invoker, invokerRequest); - } - } - - public DefaultLocalMavenInvoker(ProtoLookup protoLookup) { - super(protoLookup); - } - - @Override - protected LocalContext createContext(MavenInvokerRequest invokerRequest) { - return new LocalContext(this, invokerRequest); - } -} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java similarity index 87% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvoker.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java index 77890e9248e1..623b46624cd6 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java @@ -22,27 +22,25 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.maven.api.cli.InvokerException; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvoker; import org.apache.maven.cling.invoker.ProtoLookup; -import org.apache.maven.cling.invoker.mvn.DefaultMavenInvoker; +import org.apache.maven.cling.invoker.mvn.MavenInvoker; /** * Local resident invoker implementation, similar to "local" but keeps Maven instance resident. This implies, that * things like environment, system properties, extensions etc. are loaded only once. It is caller duty to ensure * that subsequent call is right for the resident instance (ie no env change or different extension needed). */ -public class DefaultResidentMavenInvoker - extends DefaultMavenInvoker< - MavenOptions, MavenInvokerRequest, DefaultResidentMavenInvoker.LocalContext> +public class ResidentMavenInvoker + extends MavenInvoker, ResidentMavenInvoker.LocalContext> implements ResidentMavenInvoker { public static class LocalContext - extends DefaultMavenInvoker.MavenContext< - MavenOptions, MavenInvokerRequest, DefaultResidentMavenInvoker.LocalContext> { + extends MavenInvoker.MavenContext< + MavenOptions, MavenInvokerRequest, ResidentMavenInvoker.LocalContext> { - protected LocalContext(DefaultResidentMavenInvoker invoker, MavenInvokerRequest invokerRequest) { + protected LocalContext(ResidentMavenInvoker invoker, MavenInvokerRequest invokerRequest) { super(invoker, invokerRequest); } @@ -59,7 +57,7 @@ public LocalContext copy(MavenInvokerRequest invokerRequest) { if (invokerRequest == this.invokerRequest) { return this; } - LocalContext shadow = new LocalContext((DefaultResidentMavenInvoker) invoker, invokerRequest); + LocalContext shadow = new LocalContext((ResidentMavenInvoker) invoker, invokerRequest); shadow.logger = logger; shadow.loggerFactory = loggerFactory; @@ -88,7 +86,7 @@ public LocalContext copy(MavenInvokerRequest invokerRequest) { private final ConcurrentHashMap residentContext; - public DefaultResidentMavenInvoker(ProtoLookup protoLookup) { + public ResidentMavenInvoker(ProtoLookup protoLookup) { super(protoLookup); this.residentContext = new ConcurrentHashMap<>(); } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/CommonsCliEncryptOptions.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/CommonsCliEncryptOptions.java index 9ee6ecd1f5be..7ec71cb78778 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/CommonsCliEncryptOptions.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/CommonsCliEncryptOptions.java @@ -35,6 +35,9 @@ import static org.apache.maven.cling.invoker.Utils.createInterpolator; +/** + * Implementation of {@link EncryptOptions} (base + mvnenc). + */ public class CommonsCliEncryptOptions extends CommonsCliOptions implements EncryptOptions { public static CommonsCliEncryptOptions parse(String[] args) throws ParseException { CLIManager cliManager = new CLIManager(); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvoker.java index cbe3cd3ecdc8..826a1d9faddf 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvoker.java @@ -23,10 +23,10 @@ import java.util.List; import java.util.Map; -import org.apache.maven.api.cli.mvnenc.EncryptInvoker; -import org.apache.maven.api.cli.mvnenc.EncryptInvokerRequest; +import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.mvnenc.EncryptOptions; import org.apache.maven.cling.invoker.LookupInvoker; +import org.apache.maven.cling.invoker.LookupInvokerContext; import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.utils.CLIReportingUtils; import org.jline.consoleui.prompt.ConsolePrompt; @@ -41,18 +41,14 @@ import org.jline.utils.OSUtils; /** - * Encrypt invoker implementation, when Encrypt CLI is being run. System uses ClassWorld launcher, and class world - * instance is passed in via "enhanced" main method. Hence, this class expects fully setup ClassWorld via constructor. + * mvnenc invoker implementation. */ -public class DefaultEncryptInvoker - extends LookupInvoker - implements EncryptInvoker { +public class DefaultEncryptInvoker extends LookupInvoker { @SuppressWarnings("VisibilityModifier") - public static class LocalContext - extends LookupInvokerContext { - protected LocalContext(DefaultEncryptInvoker invoker, EncryptInvokerRequest invokerRequest) { - super(invoker, invokerRequest); + public static class LocalContext extends LookupInvokerContext { + protected LocalContext(DefaultEncryptInvokerRequest invokerRequest) { + super(invokerRequest); } public Map goals; @@ -83,8 +79,8 @@ protected int execute(LocalContext context) throws Exception { } @Override - protected LocalContext createContext(EncryptInvokerRequest invokerRequest) { - return new LocalContext(this, invokerRequest); + protected LocalContext createContext(InvokerRequest invokerRequest) { + return new LocalContext((DefaultEncryptInvokerRequest) invokerRequest); } @Override @@ -139,12 +135,12 @@ protected int doExecute(LocalContext context) throws Exception { LineReaderBuilder.builder().terminal(context.terminal).build(); context.prompt = new ConsolePrompt(context.reader, context.terminal, config); - if (context.invokerRequest.options().goals().isEmpty() - || context.invokerRequest.options().goals().get().size() != 1) { + EncryptOptions options = (EncryptOptions) context.invokerRequest.options(); + if (options.goals().isEmpty() || options.goals().get().size() != 1) { return badGoalsErrorMessage("No goal or multiple goals specified, specify only one goal.", context); } - String goalName = context.invokerRequest.options().goals().get().get(0); + String goalName = options.goals().get().get(0); Goal goal = context.goals.get(goalName); if (goal == null) { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvokerRequest.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvokerRequest.java index de8b52eb6f7c..9cb2dcd1ba5a 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvokerRequest.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvokerRequest.java @@ -28,13 +28,12 @@ import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.api.cli.extensions.CoreExtension; -import org.apache.maven.api.cli.mvnenc.EncryptInvokerRequest; import org.apache.maven.api.cli.mvnenc.EncryptOptions; import org.apache.maven.cling.invoker.BaseInvokerRequest; import static java.util.Objects.requireNonNull; -public class DefaultEncryptInvokerRequest extends BaseInvokerRequest implements EncryptInvokerRequest { +public class DefaultEncryptInvokerRequest extends BaseInvokerRequest { private final EncryptOptions options; @SuppressWarnings("ParameterNumber") @@ -64,7 +63,8 @@ public DefaultEncryptInvokerRequest( in, out, err, - coreExtensions); + coreExtensions, + null); this.options = (EncryptOptions) requireNonNull(options); } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptParser.java index 601563c0dd94..f1f45ccf6bc8 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptParser.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptParser.java @@ -22,15 +22,13 @@ import java.util.List; import org.apache.commons.cli.ParseException; +import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.ParserException; -import org.apache.maven.api.cli.mvnenc.EncryptInvokerRequest; -import org.apache.maven.api.cli.mvnenc.EncryptOptions; -import org.apache.maven.api.cli.mvnenc.EncryptParser; import org.apache.maven.cling.invoker.BaseParser; -public class DefaultEncryptParser extends BaseParser implements EncryptParser { +public class DefaultEncryptParser extends BaseParser { @Override - protected EncryptInvokerRequest getInvokerRequest(LocalContext context) { + protected DefaultEncryptInvokerRequest getInvokerRequest(LocalContext context) { return new DefaultEncryptInvokerRequest( context.parserRequest, context.cwd, @@ -48,7 +46,7 @@ protected EncryptInvokerRequest getInvokerRequest(LocalContext context) { } @Override - protected List parseCliOptions(LocalContext context) throws ParserException { + protected List parseCliOptions(LocalContext context) throws ParserException { return Collections.singletonList(parseEncryptCliOptions(context.parserRequest.args())); } @@ -61,7 +59,7 @@ protected CommonsCliEncryptOptions parseEncryptCliOptions(List args) thr } @Override - protected EncryptOptions assembleOptions(List parsedOptions) { + protected Options assembleOptions(List parsedOptions) { // nothing to assemble, we deal with CLI only return parsedOptions.get(0); } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java index 0a98d6c0b194..498ae0bec726 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Objects; +import org.apache.maven.api.cli.mvnenc.EncryptOptions; import org.apache.maven.api.services.MessageBuilderFactory; import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker; import org.codehaus.plexus.components.secdispatcher.DispatcherMeta; @@ -67,8 +68,10 @@ public int execute(DefaultEncryptInvoker.LocalContext context) throws Exception context.addInHeader(""); ConsolePrompt prompt = context.prompt; - boolean force = context.invokerRequest.options().force().orElse(false); - boolean yes = context.invokerRequest.options().yes().orElse(false); + + EncryptOptions options = (EncryptOptions) context.invokerRequest.options(); + boolean force = options.force().orElse(false); + boolean yes = options.yes().orElse(false); if (configExists() && !force) { context.terminal diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/package-info.java similarity index 73% rename from api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenInvoker.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/package-info.java index ee75b2400b1d..65d166c16846 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/mvn/forked/ForkedMavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/package-info.java @@ -16,15 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.maven.api.cli.mvn.forked; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.cli.mvn.MavenInvoker; /** - * Forked Maven invoker. - * - * @since 4.0.0 + * This package contain support (hence abstract) classes mainly, that implements "base" of CLIng. + * In packages below you find actual implementations. */ -@Experimental -public interface ForkedMavenInvoker extends MavenInvoker {} +package org.apache.maven.cling.invoker; diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java index e2dd847053a8..2627e31f020e 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java @@ -27,7 +27,6 @@ import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Parser; import org.apache.maven.api.cli.ParserRequest; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.jline.JLineMessageBuilderFactory; @@ -35,7 +34,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public abstract class MavenInvokerTestSupport> { +public abstract class MavenInvokerTestSupport< + O extends MavenOptions, R extends org.apache.maven.api.cli.InvokerRequest> { protected void invoke(Path cwd, Collection goals) throws Exception { // works only in recent Maven4 diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvokerTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java similarity index 85% rename from impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvokerTest.java rename to impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java index f03c161d4c9e..28ccdfc3a6de 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/DefaultForkedMavenInvokerTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java @@ -24,7 +24,6 @@ import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Parser; import org.apache.maven.api.cli.mvn.MavenOptions; -import org.apache.maven.api.cli.mvn.forked.ForkedMavenInvokerRequest; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.CleanupMode; @@ -33,16 +32,16 @@ /** * Forked UT: it cannot use jimFS as it runs in child process. */ -public class DefaultForkedMavenInvokerTest extends MavenInvokerTestSupport { +public class ForkedMavenInvokerTest extends MavenInvokerTestSupport { @Override protected Invoker createInvoker() { - return new DefaultForkedMavenInvoker(); + return new ForkedMavenInvoker(); } @Override protected Parser createParser() { - return new DefaultForkedMavenParser(); + return new ForkedMavenParser(); } @Test diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvokerTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvokerTest.java index 904ac1cff01d..c877597ea850 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvokerTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvokerTest.java @@ -26,10 +26,8 @@ import com.google.common.jimfs.Jimfs; import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Parser; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.cling.invoker.ProtoLookup; -import org.apache.maven.cling.invoker.mvn.DefaultMavenParser; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport; import org.codehaus.plexus.classworlds.ClassWorld; import org.junit.jupiter.api.Disabled; diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvokerTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvokerTest.java index 73485b9797ce..34be76a74ecf 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvokerTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvokerTest.java @@ -26,10 +26,8 @@ import com.google.common.jimfs.Jimfs; import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Parser; -import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.cling.invoker.ProtoLookup; -import org.apache.maven.cling.invoker.mvn.DefaultMavenParser; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport; import org.codehaus.plexus.classworlds.ClassWorld; import org.junit.jupiter.api.Disabled; @@ -47,7 +45,7 @@ public class DefaultResidentMavenInvokerTest @Override protected Invoker> createInvoker() { - return new DefaultResidentMavenInvoker(ProtoLookup.builder() + return new ResidentMavenInvoker(ProtoLookup.builder() .addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader())) .build()); } From 6f1a303af9bd816dd7afb5e006e39fc0e647d48b Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Mon, 11 Nov 2024 16:34:47 +0100 Subject: [PATCH 02/16] Kill one more class Just parse jvm arguments, if any, and invoker will use it or not use it, imple dependant. --- .../maven/cling/invoker/mvn/MavenParser.java | 38 +++++++--- .../invoker/mvn/forked/ForkedMavenParser.java | 74 ------------------- 2 files changed, 29 insertions(+), 83 deletions(-) delete mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenParser.java diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java index 528cdd0f13c1..1b9fac64cfc6 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java @@ -19,11 +19,14 @@ package org.apache.maven.cling.invoker.mvn; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.cli.ParseException; @@ -65,6 +68,31 @@ protected MavenOptions parseMavenConfigOptions(Path configFile) throws ParserExc } } + protected MavenOptions parseArgs(String source, List args) throws ParserException { + try { + return CommonsCliMavenOptions.parse(source, args.toArray(new String[0])); + } catch (ParseException e) { + throw new ParserException("Failed to parse source " + source + ": " + e.getMessage(), e.getCause()); + } + } + + protected List getJvmArguments(Path rootDirectory) { + if (rootDirectory != null) { + Path jvmConfig = rootDirectory.resolve(".mvn/jvm.config"); + if (Files.exists(jvmConfig)) { + try { + return Files.readAllLines(jvmConfig).stream() + .filter(l -> !l.isBlank() && !l.startsWith("#")) + .flatMap(l -> Arrays.stream(l.split(" "))) + .collect(Collectors.toList()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + return null; + } + @Override protected MavenInvokerRequest getInvokerRequest(LocalContext context) { return new MavenInvokerRequest( @@ -80,18 +108,10 @@ protected MavenInvokerRequest getInvokerRequest(LocalContext context) { context.parserRequest.out(), context.parserRequest.err(), context.extensions, - null, + getJvmArguments(context.rootDirectory), (MavenOptions) context.options); } - protected MavenOptions parseArgs(String source, List args) throws ParserException { - try { - return CommonsCliMavenOptions.parse(source, args.toArray(new String[0])); - } catch (ParseException e) { - throw new ParserException("Failed to parse source " + source + ": " + e.getMessage(), e.getCause()); - } - } - @Override @SuppressWarnings({"unchecked", "rawtypes"}) protected MavenOptions assembleOptions(List parsedOptions) { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenParser.java deleted file mode 100644 index 34d9187a48f5..000000000000 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenParser.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.invoker.mvn.forked; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import org.apache.maven.api.cli.mvn.MavenOptions; -import org.apache.maven.cling.invoker.mvn.MavenInvokerRequest; -import org.apache.maven.cling.invoker.mvn.MavenParser; - -/** - * Forked invoker parser that collects JVM arguments as well. - */ -public class ForkedMavenParser extends MavenParser { - - @SuppressWarnings("ParameterNumber") - @Override - protected MavenInvokerRequest getInvokerRequest(LocalContext context) { - return new MavenInvokerRequest( - context.parserRequest, - context.cwd, - context.installationDirectory, - context.userHomeDirectory, - context.userProperties, - context.systemProperties, - context.topDirectory, - context.rootDirectory, - context.parserRequest.in(), - context.parserRequest.out(), - context.parserRequest.err(), - context.extensions, - getJvmArguments(context.rootDirectory), - (MavenOptions) context.options); - } - - protected List getJvmArguments(Path rootDirectory) { - if (rootDirectory != null) { - Path jvmConfig = rootDirectory.resolve(".mvn/jvm.config"); - if (Files.exists(jvmConfig)) { - try { - return Files.readAllLines(jvmConfig).stream() - .filter(l -> !l.isBlank() && !l.startsWith("#")) - .flatMap(l -> Arrays.stream(l.split(" "))) - .collect(Collectors.toList()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - } - return null; - } -} From 4f4d88d074b4bd66e4df18dbc7fe8bcac7254246 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 11:52:04 +0100 Subject: [PATCH 03/16] Sort out last bits --- .../org/apache/maven/cling/MavenCling.java | 7 +- .../org/apache/maven/cling/MavenEncCling.java | 8 +- .../invoker/ContainerCapsuleFactory.java | 7 +- ...InvokerContext.java => LookupContext.java} | 4 +- .../maven/cling/invoker/LookupInvoker.java | 8 +- .../PlexusContainerCapsuleFactory.java | 34 +++---- .../maven/cling/invoker/mvn/MavenContext.java | 44 ++++++++++ .../maven/cling/invoker/mvn/MavenInvoker.java | 88 +++++++------------ .../invoker/mvn/local/LocalMavenInvoker.java | 41 +++++++++ .../mvn/resident/ResidentMavenContext.java | 69 +++++++++++++++ .../mvn/resident/ResidentMavenInvoker.java | 69 ++------------- .../cling/invoker/mvnenc/EncryptContext.java | 54 ++++++++++++ ...ncryptInvoker.java => EncryptInvoker.java} | 46 ++-------- ...equest.java => EncryptInvokerRequest.java} | 4 +- ...tEncryptParser.java => EncryptParser.java} | 6 +- .../maven/cling/invoker/mvnenc/Goal.java | 2 +- .../mvnenc/goals/ConfiguredGoalSupport.java | 13 ++- .../cling/invoker/mvnenc/goals/Decrypt.java | 8 +- .../cling/invoker/mvnenc/goals/Diag.java | 6 +- .../cling/invoker/mvnenc/goals/Encrypt.java | 6 +- .../cling/invoker/mvnenc/goals/Init.java | 11 ++- .../maven/cling/invoker/package-info.java | 2 +- .../invoker/mvn/MavenInvokerTestSupport.java | 12 ++- .../mvn/forked/ForkedMavenInvokerTest.java | 10 +-- .../local/DefaultLocalMavenInvokerTest.java | 13 ++- .../DefaultResidentMavenInvokerTest.java | 11 ++- 26 files changed, 342 insertions(+), 241 deletions(-) rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/{LookupInvokerContext.java => LookupContext.java} (97%) create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/LocalMavenInvoker.java create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptContext.java rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/{DefaultEncryptInvoker.java => EncryptInvoker.java} (78%) rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/{DefaultEncryptInvokerRequest.java => EncryptInvokerRequest.java} (95%) rename impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/{DefaultEncryptParser.java => EncryptParser.java} (92%) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java index b24c04057523..7a2f646548c8 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java @@ -26,7 +26,8 @@ import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.cling.invoker.ProtoLookup; -import org.apache.maven.cling.invoker.mvn.local.DefaultLocalMavenInvoker; +import org.apache.maven.cling.invoker.mvn.MavenParser; +import org.apache.maven.cling.invoker.mvn.local.LocalMavenInvoker; import org.apache.maven.jline.JLineMessageBuilderFactory; import org.codehaus.plexus.classworlds.ClassWorld; @@ -60,13 +61,13 @@ public MavenCling(ClassWorld classWorld) { @Override protected Invoker createInvoker() { - return new DefaultLocalMavenInvoker( + return new LocalMavenInvoker( ProtoLookup.builder().addMapping(ClassWorld.class, classWorld).build()); } @Override protected InvokerRequest parseArguments(String[] args) throws ParserException, IOException { - return new DefaultMavenParser() + return new MavenParser() .parse(ParserRequest.mvn(args, new ProtoLogger(), new JLineMessageBuilderFactory()) .build()); } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java index 63752de3fd68..66ebe9f1a0bb 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java @@ -26,8 +26,8 @@ import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.cling.invoker.ProtoLookup; -import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker; -import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptParser; +import org.apache.maven.cling.invoker.mvnenc.EncryptInvoker; +import org.apache.maven.cling.invoker.mvnenc.EncryptParser; import org.apache.maven.jline.JLineMessageBuilderFactory; import org.codehaus.plexus.classworlds.ClassWorld; @@ -61,13 +61,13 @@ public MavenEncCling(ClassWorld classWorld) { @Override protected Invoker createInvoker() { - return new DefaultEncryptInvoker( + return new EncryptInvoker( ProtoLookup.builder().addMapping(ClassWorld.class, classWorld).build()); } @Override protected InvokerRequest parseArguments(String[] args) throws ParserException, IOException { - return new DefaultEncryptParser() + return new EncryptParser() .parse(ParserRequest.mvnenc(args, new ProtoLogger(), new JLineMessageBuilderFactory()) .build()); } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsuleFactory.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsuleFactory.java index ff326daa69b4..171980fea7dc 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsuleFactory.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ContainerCapsuleFactory.java @@ -20,15 +20,16 @@ import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.cli.InvokerException; -import org.apache.maven.api.services.Lookup; /** * Container capsule factory. + * + * @param The context type. */ -public interface ContainerCapsuleFactory { +public interface ContainerCapsuleFactory { /** * Creates container capsule. */ @Nonnull - ContainerCapsule createContainerCapsule(Lookup invokerLookup, LookupInvokerContext context) throws InvokerException; + ContainerCapsule createContainerCapsule(LookupInvoker invoker, C context) throws InvokerException; } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvokerContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java similarity index 97% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvokerContext.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java index 84fe7b60dd56..42dad4162c7b 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvokerContext.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java @@ -42,14 +42,14 @@ import static java.util.Objects.requireNonNull; @SuppressWarnings("VisibilityModifier") -public class LookupInvokerContext implements AutoCloseable { +public class LookupContext implements AutoCloseable { public final InvokerRequest invokerRequest; public final Function cwdResolver; public final Function installationResolver; public final Function userResolver; public final Session session; - protected LookupInvokerContext(InvokerRequest invokerRequest) { + protected LookupContext(InvokerRequest invokerRequest) { this.invokerRequest = requireNonNull(invokerRequest); this.cwdResolver = s -> invokerRequest.cwd().resolve(s).normalize().toAbsolutePath(); this.installationResolver = s -> diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java index d2487e5be142..0187b2dfd01c 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java @@ -89,7 +89,7 @@ * * @param The context type. */ -public abstract class LookupInvoker implements Invoker { +public abstract class LookupInvoker implements Invoker { protected final ProtoLookup protoLookup; public LookupInvoker(ProtoLookup protoLookup) { @@ -365,7 +365,7 @@ protected void preCommands(C context) throws Exception { } protected void container(C context) throws Exception { - context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(protoLookup, context); + context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(this, context); context.closeables.add(context.containerCapsule); context.lookup = context.containerCapsule.getLookup(); context.settingsBuilder = context.lookup.lookup(SettingsBuilder.class); @@ -377,8 +377,8 @@ protected void container(C context) throws Exception { .log(message); } - protected ContainerCapsuleFactory createContainerCapsuleFactory() { - return new PlexusContainerCapsuleFactory(); + protected ContainerCapsuleFactory createContainerCapsuleFactory() { + return new PlexusContainerCapsuleFactory<>(); } protected void lookup(C context) throws Exception {} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java index cf1235bfde56..bfcef512825d 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/PlexusContainerCapsuleFactory.java @@ -34,7 +34,6 @@ import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.Logger; import org.apache.maven.api.cli.extensions.CoreExtension; -import org.apache.maven.api.services.Lookup; import org.apache.maven.api.services.MessageBuilderFactory; import org.apache.maven.api.services.SettingsBuilder; import org.apache.maven.cling.extensions.BootstrapCoreExtensionManager; @@ -64,25 +63,27 @@ /** * Container capsule backed by Plexus Container. + * + * @param The context type. */ -public class PlexusContainerCapsuleFactory implements ContainerCapsuleFactory { +public class PlexusContainerCapsuleFactory implements ContainerCapsuleFactory { @Override - public ContainerCapsule createContainerCapsule(Lookup invokerLookup, LookupInvokerContext context) - throws InvokerException { + public ContainerCapsule createContainerCapsule(LookupInvoker invoker, C context) throws InvokerException { try { return new PlexusContainerCapsule( - Thread.currentThread().getContextClassLoader(), container(invokerLookup, context)); + Thread.currentThread().getContextClassLoader(), container(invoker, context)); } catch (Exception e) { throw new InvokerException("Failed to create plexus container capsule", e); } } - protected PlexusContainer container(Lookup invokerLookup, LookupInvokerContext context) throws Exception { - ClassWorld classWorld = invokerLookup.lookup(ClassWorld.class); + protected PlexusContainer container(LookupInvoker invoker, C context) throws Exception { + ClassWorld classWorld = invoker.protoLookup.lookup(ClassWorld.class); ClassRealm coreRealm = classWorld.getClassRealm("plexus.core"); List extClassPath = parseExtClasspath(context); CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom(coreRealm); - List extensions = loadCoreExtensions(context, coreRealm, coreEntry.getExportedArtifacts()); + List extensions = + loadCoreExtensions(invoker, context, coreRealm, coreEntry.getExportedArtifacts()); ClassRealm containerRealm = setupContainerRealm(context.logger, classWorld, coreRealm, extClassPath, extensions); ContainerConfiguration cc = new DefaultContainerConfiguration() @@ -104,7 +105,6 @@ protected PlexusContainer container(Lookup invokerLookup, LookupInvokerContext c // NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups container.setLookupRealm(null); - context.currentThreadContextClassLoader = container.getContainerRealm(); Thread.currentThread().setContextClassLoader(container.getContainerRealm()); container.setLoggerManager(createLoggerManager()); @@ -169,7 +169,7 @@ protected Set collectExportedPackages( * where the components are on index (are annotated with JSR330 annotations and Sisu index is created) and, they * have priorities set. */ - protected Module getCustomModule(LookupInvokerContext context, CoreExports exports) { + protected Module getCustomModule(C context, CoreExports exports) { return new AbstractModule() { @Override protected void configure() { @@ -184,12 +184,11 @@ protected LoggerManager createLoggerManager() { return new Slf4jLoggerManager(); } - protected void customizeContainerConfiguration(LookupInvokerContext context, ContainerConfiguration configuration) - throws Exception {} + protected void customizeContainerConfiguration(C context, ContainerConfiguration configuration) throws Exception {} - protected void customizeContainer(LookupInvokerContext context, PlexusContainer container) throws Exception {} + protected void customizeContainer(C context, PlexusContainer container) throws Exception {} - protected List parseExtClasspath(LookupInvokerContext context) throws Exception { + protected List parseExtClasspath(C context) throws Exception { InvokerRequest invokerRequest = context.invokerRequest; String extClassPath = invokerRequest.userProperties().get(Constants.MAVEN_EXT_CLASS_PATH); if (extClassPath == null) { @@ -252,7 +251,8 @@ protected ClassRealm setupContainerRealm( } protected List loadCoreExtensions( - LookupInvokerContext context, ClassRealm containerRealm, Set providedArtifacts) throws Exception { + LookupInvoker invoker, C context, ClassRealm containerRealm, Set providedArtifacts) + throws Exception { InvokerRequest invokerRequest = context.invokerRequest; if (invokerRequest.coreExtensions().isEmpty() || invokerRequest.coreExtensions().get().isEmpty()) { @@ -283,10 +283,10 @@ protected void configure() { container.getLoggerManager().setThresholds(toPlexusLoggingLevel(context.loggerLevel)); Thread.currentThread().setContextClassLoader(container.getContainerRealm()); - context.invoker.settings(context, container.lookup(SettingsBuilder.class)); + invoker.settings(context, container.lookup(SettingsBuilder.class)); MavenExecutionRequest mer = new DefaultMavenExecutionRequest(); - context.invoker.populateRequest(context, mer); + invoker.populateRequest(context, mer); mer = container.lookup(MavenExecutionRequestPopulator.class).populateDefaults(mer); return Collections.unmodifiableList(container .lookup(BootstrapCoreExtensionManager.class) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java new file mode 100644 index 000000000000..92a7a5226618 --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java @@ -0,0 +1,44 @@ +/* + * 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.invoker.mvn; + +import org.apache.maven.Maven; +import org.apache.maven.api.cli.InvokerRequest; +import org.apache.maven.api.services.ToolchainsBuilder; +import org.apache.maven.api.services.model.ModelProcessor; +import org.apache.maven.cling.invoker.LookupContext; +import org.apache.maven.eventspy.internal.EventSpyDispatcher; +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.execution.MavenExecutionRequestPopulator; +import org.apache.maven.logging.BuildEventListener; + +@SuppressWarnings("VisibilityModifier") +public class MavenContext extends LookupContext { + public MavenContext(InvokerRequest invokerRequest) { + super(invokerRequest); + } + + public BuildEventListener buildEventListener; + public MavenExecutionRequest mavenExecutionRequest; + public EventSpyDispatcher eventSpyDispatcher; + public MavenExecutionRequestPopulator mavenExecutionRequestPopulator; + public ToolchainsBuilder toolchainsBuilder; + public ModelProcessor modelProcessor; + public Maven maven; +} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java index 7a2fba2b7cd9..8f141c974474 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java @@ -34,7 +34,6 @@ import org.apache.maven.InternalErrorException; import org.apache.maven.Maven; import org.apache.maven.api.Constants; -import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.Logger; import org.apache.maven.api.cli.mvn.MavenOptions; @@ -48,7 +47,6 @@ import org.apache.maven.api.services.model.ModelProcessor; import org.apache.maven.cling.event.ExecutionEventLogger; import org.apache.maven.cling.invoker.LookupInvoker; -import org.apache.maven.cling.invoker.LookupInvokerContext; import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.Utils; import org.apache.maven.cling.utils.CLIReportingUtils; @@ -80,42 +78,23 @@ /** * The "local" Maven invoker, that expects whole Maven on classpath and invokes it. + * + * @param The context type. */ -public class MavenInvoker extends LookupInvoker { - - @SuppressWarnings("VisibilityModifier") - public static class MavenContext extends LookupInvokerContext { - protected MavenContext(InvokerRequest invokerRequest) { - super(invokerRequest); - } - - public BuildEventListener buildEventListener; - public MavenExecutionRequest mavenExecutionRequest; - public EventSpyDispatcher eventSpyDispatcher; - public MavenExecutionRequestPopulator mavenExecutionRequestPopulator; - public ToolchainsBuilder toolchainsBuilder; - public ModelProcessor modelProcessor; - public Maven maven; - } - +public abstract class MavenInvoker extends LookupInvoker { public MavenInvoker(ProtoLookup protoLookup) { super(protoLookup); } @Override - protected MavenContext createContext(InvokerRequest invokerRequest) throws InvokerException { - return new MavenContext(invokerRequest); - } - - @Override - protected int execute(MavenContext context) throws Exception { + protected int execute(C context) throws Exception { toolchains(context); populateRequest(context, context.mavenExecutionRequest); return doExecute(context); } @Override - protected void prepare(MavenContext context) throws Exception { + protected void prepare(C context) throws Exception { // explicitly fill in "defaults"? DefaultMavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest(); mavenExecutionRequest.setRepositoryCache(new DefaultRepositoryCache()); @@ -134,7 +113,7 @@ protected void prepare(MavenContext context) throws Exception { } @Override - protected void lookup(MavenContext context) throws Exception { + protected void lookup(C context) throws Exception { context.eventSpyDispatcher = context.lookup.lookup(EventSpyDispatcher.class); context.mavenExecutionRequestPopulator = context.lookup.lookup(MavenExecutionRequestPopulator.class); context.toolchainsBuilder = context.lookup.lookup(ToolchainsBuilder.class); @@ -143,7 +122,7 @@ protected void lookup(MavenContext context) throws Exception { } @Override - protected void init(MavenContext context) throws Exception { + protected void init(C context) throws Exception { InvokerRequest invokerRequest = context.invokerRequest; Map data = new HashMap<>(); data.put("plexus", context.lookup.lookup(PlexusContainer.class)); @@ -155,20 +134,21 @@ protected void init(MavenContext context) throws Exception { } @Override - protected void postCommands(MavenContext context) throws Exception { + protected void postCommands(C context) throws Exception { super.postCommands(context); InvokerRequest invokerRequest = context.invokerRequest; + MavenOptions options = (MavenOptions) invokerRequest.options(); Logger logger = context.logger; - if (invokerRequest.options().relaxedChecksums().orElse(false)) { + if (options.relaxedChecksums().orElse(false)) { logger.info("Disabling strict checksum verification on all artifact downloads."); - } else if (invokerRequest.options().strictChecksums().orElse(false)) { + } else if (options.strictChecksums().orElse(false)) { logger.info("Enabling strict checksum verification on all artifact downloads."); } } @Override - protected void configureLogging(MavenContext context) throws Exception { + protected void configureLogging(C context) throws Exception { super.configureLogging(context); // Create the build log appender ProjectBuildLogAppender projectBuildLogAppender = @@ -176,34 +156,33 @@ protected void configureLogging(MavenContext context) throws Exception { context.closeables.add(projectBuildLogAppender); } - protected BuildEventListener determineBuildEventListener(MavenContext context) { + protected BuildEventListener determineBuildEventListener(C context) { if (context.buildEventListener == null) { context.buildEventListener = doDetermineBuildEventListener(context); } return context.buildEventListener; } - protected BuildEventListener doDetermineBuildEventListener(MavenContext context) { + protected BuildEventListener doDetermineBuildEventListener(C context) { Consumer writer = determineWriter(context); return new SimpleBuildEventListener(writer); } @Override - protected void customizeSettingsRequest(MavenContext context, SettingsBuilderRequest settingsBuilderRequest) { + protected void customizeSettingsRequest(C context, SettingsBuilderRequest settingsBuilderRequest) { if (context.eventSpyDispatcher != null) { context.eventSpyDispatcher.onEvent(settingsBuilderRequest); } } @Override - protected void customizeSettingsResult(MavenContext context, SettingsBuilderResult settingsBuilderResult) - throws Exception { + protected void customizeSettingsResult(C context, SettingsBuilderResult settingsBuilderResult) throws Exception { if (context.eventSpyDispatcher != null) { context.eventSpyDispatcher.onEvent(settingsBuilderResult); } } - protected void toolchains(MavenContext context) throws Exception { + protected void toolchains(C context) throws Exception { Path userToolchainsFile = null; if (context.invokerRequest.options().altUserToolchains().isPresent()) { @@ -283,7 +262,7 @@ protected void toolchains(MavenContext context) throws Exception { } @Override - protected void populateRequest(MavenContext context, MavenExecutionRequest request) throws Exception { + protected void populateRequest(C context, MavenExecutionRequest request) throws Exception { super.populateRequest(context, request); if (context.invokerRequest.rootDirectory().isEmpty()) { // maven requires this to be set; so default it (and see below at POM) @@ -365,11 +344,11 @@ protected void populateRequest(MavenContext context, MavenExecutionRequest reque } } - protected Path determinePom(MavenContext context) { + protected Path determinePom(C context) { Path current = context.invokerRequest.cwd(); - if (context.invokerRequest.options().alternatePomFile().isPresent()) { - current = context.cwdResolver.apply( - context.invokerRequest.options().alternatePomFile().get()); + MavenOptions options = (MavenOptions) context.invokerRequest.options(); + if (options.alternatePomFile().isPresent()) { + current = context.cwdResolver.apply(options.alternatePomFile().get()); } if (context.modelProcessor != null) { return context.modelProcessor.locateExistingPom(current); @@ -378,7 +357,7 @@ protected Path determinePom(MavenContext context) { } } - protected String determineReactorFailureBehaviour(MavenContext context) { + protected String determineReactorFailureBehaviour(C context) { MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.failFast().isPresent()) { return MavenExecutionRequest.REACTOR_FAIL_FAST; @@ -391,7 +370,7 @@ protected String determineReactorFailureBehaviour(MavenContext context) { } } - protected String determineGlobalChecksumPolicy(MavenContext context) { + protected String determineGlobalChecksumPolicy(C context) { MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.strictChecksums().orElse(false)) { return MavenExecutionRequest.CHECKSUM_POLICY_FAIL; @@ -402,7 +381,7 @@ protected String determineGlobalChecksumPolicy(MavenContext context) { } } - protected ExecutionListener determineExecutionListener(MavenContext context) { + protected ExecutionListener determineExecutionListener(C context) { ExecutionListener listener = new ExecutionEventLogger(context.invokerRequest.messageBuilderFactory()); if (context.eventSpyDispatcher != null) { listener = context.eventSpyDispatcher.chainListener(listener); @@ -411,12 +390,12 @@ protected ExecutionListener determineExecutionListener(MavenContext context) { return listener; } - protected TransferListener determineTransferListener(MavenContext context, boolean noTransferProgress) { + protected TransferListener determineTransferListener(C context, boolean noTransferProgress) { TransferListener delegate = super.determineTransferListener(context, noTransferProgress); return new MavenTransferListener(delegate, determineBuildEventListener(context)); } - protected String determineMakeBehavior(MavenContext context) { + protected String determineMakeBehavior(C context) { MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.alsoMake().isPresent() && mavenOptions.alsoMakeDependents().isEmpty()) { @@ -432,7 +411,7 @@ protected String determineMakeBehavior(MavenContext context) { } } - protected void performProjectActivation(MavenContext context, ProjectActivation projectActivation) { + protected void performProjectActivation(C context, ProjectActivation projectActivation) { MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.projects().isPresent() && !mavenOptions.projects().get().isEmpty()) { @@ -460,7 +439,7 @@ protected void performProjectActivation(MavenContext context, ProjectActivation } } - protected void performProfileActivation(MavenContext context, ProfileActivation profileActivation) { + protected void performProfileActivation(C context, ProfileActivation profileActivation) { MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options(); if (mavenOptions.activatedProfiles().isPresent() && !mavenOptions.activatedProfiles().get().isEmpty()) { @@ -488,7 +467,7 @@ protected void performProfileActivation(MavenContext context, ProfileActivation } } - protected int doExecute(MavenContext context) throws Exception { + protected int doExecute(C context) throws Exception { MavenExecutionRequest request = context.mavenExecutionRequest; context.eventSpyDispatcher.onEvent(request); @@ -551,7 +530,7 @@ protected int doExecute(MavenContext context) throws Exception { } } - if (context.invokerRequest.options().failNever().orElse(false)) { + if (((MavenOptions) context.invokerRequest.options()).failNever().orElse(false)) { context.logger.info("Build failures were ignored."); return 0; } else { @@ -562,7 +541,7 @@ protected int doExecute(MavenContext context) throws Exception { } } - protected void logBuildResumeHint(MavenContext context, String resumeBuildHint) { + protected void logBuildResumeHint(C context, String resumeBuildHint) { context.logger.error(""); context.logger.error("After correcting the problems, you can resume the build with the command"); context.logger.error( @@ -605,8 +584,7 @@ protected String getResumeFromSelector(List mavenProjects, MavenPr protected static final String ANSI_RESET = "\u001B\u005Bm"; - protected void logSummary( - MavenContext context, ExceptionSummary summary, Map references, String indent) { + protected void logSummary(C context, ExceptionSummary summary, Map references, String indent) { String referenceKey = ""; if (summary.getReference() != null && !summary.getReference().isEmpty()) { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/LocalMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/LocalMavenInvoker.java new file mode 100644 index 000000000000..3fdc065b76d9 --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/LocalMavenInvoker.java @@ -0,0 +1,41 @@ +/* + * 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.invoker.mvn.local; + +import org.apache.maven.api.cli.InvokerException; +import org.apache.maven.api.cli.InvokerRequest; +import org.apache.maven.cling.invoker.ProtoLookup; +import org.apache.maven.cling.invoker.mvn.MavenContext; +import org.apache.maven.cling.invoker.mvn.MavenInvoker; + +/** + * Local resident invoker implementation, similar to "local" but keeps Maven instance resident. This implies, that + * things like environment, system properties, extensions etc. are loaded only once. It is caller duty to ensure + * that subsequent call is right for the resident instance (ie no env change or different extension needed). + */ +public class LocalMavenInvoker extends MavenInvoker { + public LocalMavenInvoker(ProtoLookup protoLookup) { + super(protoLookup); + } + + @Override + protected MavenContext createContext(InvokerRequest invokerRequest) throws InvokerException { + return new MavenContext(invokerRequest); + } +} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java new file mode 100644 index 000000000000..7e34b0a449c6 --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java @@ -0,0 +1,69 @@ +/* + * 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.invoker.mvn.resident; + +import org.apache.maven.api.cli.InvokerException; +import org.apache.maven.api.cli.InvokerRequest; +import org.apache.maven.cling.invoker.mvn.MavenContext; + +public class ResidentMavenContext extends MavenContext { + + protected ResidentMavenContext(InvokerRequest invokerRequest) { + super(invokerRequest); + } + + @Override + public void close() throws InvokerException { + // we are resident, we do not shut down here + } + + public void shutDown() throws InvokerException { + super.close(); + } + + public ResidentMavenContext copy(InvokerRequest invokerRequest) { + if (invokerRequest == this.invokerRequest) { + return this; + } + ResidentMavenContext shadow = new ResidentMavenContext(invokerRequest); + + shadow.logger = logger; + shadow.loggerFactory = loggerFactory; + shadow.loggerLevel = loggerLevel; + shadow.containerCapsule = containerCapsule; + shadow.lookup = lookup; + shadow.settingsBuilder = settingsBuilder; + + shadow.interactive = interactive; + shadow.localRepositoryPath = localRepositoryPath; + shadow.installationSettingsPath = installationSettingsPath; + shadow.projectSettingsPath = projectSettingsPath; + shadow.userSettingsPath = userSettingsPath; + shadow.effectiveSettings = effectiveSettings; + + shadow.mavenExecutionRequest = mavenExecutionRequest; + shadow.eventSpyDispatcher = eventSpyDispatcher; + shadow.mavenExecutionRequestPopulator = mavenExecutionRequestPopulator; + shadow.toolchainsBuilder = toolchainsBuilder; + shadow.modelProcessor = modelProcessor; + shadow.maven = maven; + + return shadow; + } +} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java index 623b46624cd6..8e3bd243c628 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java @@ -22,8 +22,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.maven.api.cli.InvokerException; -import org.apache.maven.api.cli.mvn.MavenOptions; -import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvoker; +import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.mvn.MavenInvoker; @@ -32,59 +31,9 @@ * things like environment, system properties, extensions etc. are loaded only once. It is caller duty to ensure * that subsequent call is right for the resident instance (ie no env change or different extension needed). */ -public class ResidentMavenInvoker - extends MavenInvoker, ResidentMavenInvoker.LocalContext> - implements ResidentMavenInvoker { +public class ResidentMavenInvoker extends MavenInvoker { - public static class LocalContext - extends MavenInvoker.MavenContext< - MavenOptions, MavenInvokerRequest, ResidentMavenInvoker.LocalContext> { - - protected LocalContext(ResidentMavenInvoker invoker, MavenInvokerRequest invokerRequest) { - super(invoker, invokerRequest); - } - - @Override - public void close() throws InvokerException { - // we are resident, we do not shut down here - } - - public void shutDown() throws InvokerException { - super.close(); - } - - public LocalContext copy(MavenInvokerRequest invokerRequest) { - if (invokerRequest == this.invokerRequest) { - return this; - } - LocalContext shadow = new LocalContext((ResidentMavenInvoker) invoker, invokerRequest); - - shadow.logger = logger; - shadow.loggerFactory = loggerFactory; - shadow.loggerLevel = loggerLevel; - shadow.containerCapsule = containerCapsule; - shadow.lookup = lookup; - shadow.settingsBuilder = settingsBuilder; - - shadow.interactive = interactive; - shadow.localRepositoryPath = localRepositoryPath; - shadow.installationSettingsPath = installationSettingsPath; - shadow.projectSettingsPath = projectSettingsPath; - shadow.userSettingsPath = userSettingsPath; - shadow.effectiveSettings = effectiveSettings; - - shadow.mavenExecutionRequest = mavenExecutionRequest; - shadow.eventSpyDispatcher = eventSpyDispatcher; - shadow.mavenExecutionRequestPopulator = mavenExecutionRequestPopulator; - shadow.toolchainsBuilder = toolchainsBuilder; - shadow.modelProcessor = modelProcessor; - shadow.maven = maven; - - return shadow; - } - } - - private final ConcurrentHashMap residentContext; + private final ConcurrentHashMap residentContext; public ResidentMavenInvoker(ProtoLookup protoLookup) { super(protoLookup); @@ -94,7 +43,7 @@ public ResidentMavenInvoker(ProtoLookup protoLookup) { @Override public void close() throws InvokerException { ArrayList exceptions = new ArrayList<>(); - for (LocalContext context : residentContext.values()) { + for (ResidentMavenContext context : residentContext.values()) { try { context.shutDown(); } catch (InvokerException e) { @@ -109,27 +58,27 @@ public void close() throws InvokerException { } @Override - protected LocalContext createContext(MavenInvokerRequest invokerRequest) { + protected ResidentMavenContext createContext(InvokerRequest invokerRequest) { return residentContext - .computeIfAbsent(getContextId(invokerRequest), k -> new LocalContext(this, invokerRequest)) + .computeIfAbsent(getContextId(invokerRequest), k -> new ResidentMavenContext(invokerRequest)) .copy(invokerRequest); } - protected String getContextId(MavenInvokerRequest invokerRequest) { + protected String getContextId(InvokerRequest invokerRequest) { // TODO: in a moment Maven stop pushing user properties to system properties (and maybe something more) // and allow multiple instances per JVM, this may become a pool? return "resident"; } @Override - protected void container(LocalContext context) throws Exception { + protected void container(ResidentMavenContext context) throws Exception { if (context.containerCapsule == null) { super.container(context); } } @Override - protected void lookup(LocalContext context) throws Exception { + protected void lookup(ResidentMavenContext context) throws Exception { if (context.maven == null) { super.lookup(context); } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptContext.java new file mode 100644 index 000000000000..41845f48d2f7 --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptContext.java @@ -0,0 +1,54 @@ +/* + * 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.invoker.mvnenc; + +import java.util.List; +import java.util.Map; + +import org.apache.maven.api.cli.InvokerRequest; +import org.apache.maven.cling.invoker.LookupContext; +import org.jline.consoleui.prompt.ConsolePrompt; +import org.jline.reader.LineReader; +import org.jline.utils.AttributedString; +import org.jline.utils.AttributedStringBuilder; +import org.jline.utils.AttributedStyle; + +@SuppressWarnings("VisibilityModifier") +public class EncryptContext extends LookupContext { + protected EncryptContext(InvokerRequest invokerRequest) { + super(invokerRequest); + } + + public Map goals; + + public List header; + public AttributedStyle style; + public LineReader reader; + public ConsolePrompt prompt; + + public void addInHeader(String text) { + addInHeader(AttributedStyle.DEFAULT, text); + } + + public void addInHeader(AttributedStyle style, String text) { + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.style(style).append(text); + header.add(asb.toAttributedString()); + } +} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvoker.java similarity index 78% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvoker.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvoker.java index 826a1d9faddf..87e5425495d6 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvoker.java @@ -20,22 +20,16 @@ import java.io.InterruptedIOException; import java.util.ArrayList; -import java.util.List; -import java.util.Map; import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.mvnenc.EncryptOptions; import org.apache.maven.cling.invoker.LookupInvoker; -import org.apache.maven.cling.invoker.LookupInvokerContext; import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.utils.CLIReportingUtils; import org.jline.consoleui.prompt.ConsolePrompt; -import org.jline.reader.LineReader; import org.jline.reader.LineReaderBuilder; import org.jline.reader.UserInterruptException; import org.jline.terminal.Terminal; -import org.jline.utils.AttributedString; -import org.jline.utils.AttributedStringBuilder; import org.jline.utils.AttributedStyle; import org.jline.utils.Colors; import org.jline.utils.OSUtils; @@ -43,48 +37,24 @@ /** * mvnenc invoker implementation. */ -public class DefaultEncryptInvoker extends LookupInvoker { +public class EncryptInvoker extends LookupInvoker { - @SuppressWarnings("VisibilityModifier") - public static class LocalContext extends LookupInvokerContext { - protected LocalContext(DefaultEncryptInvokerRequest invokerRequest) { - super(invokerRequest); - } - - public Map goals; - - public List header; - public AttributedStyle style; - public LineReader reader; - public ConsolePrompt prompt; - - public void addInHeader(String text) { - addInHeader(AttributedStyle.DEFAULT, text); - } - - public void addInHeader(AttributedStyle style, String text) { - AttributedStringBuilder asb = new AttributedStringBuilder(); - asb.style(style).append(text); - header.add(asb.toAttributedString()); - } - } - - public DefaultEncryptInvoker(ProtoLookup protoLookup) { + public EncryptInvoker(ProtoLookup protoLookup) { super(protoLookup); } @Override - protected int execute(LocalContext context) throws Exception { + protected int execute(EncryptContext context) throws Exception { return doExecute(context); } @Override - protected LocalContext createContext(InvokerRequest invokerRequest) { - return new LocalContext((DefaultEncryptInvokerRequest) invokerRequest); + protected EncryptContext createContext(InvokerRequest invokerRequest) { + return new EncryptContext(invokerRequest); } @Override - protected void lookup(LocalContext context) { + protected void lookup(EncryptContext context) { context.goals = context.lookup.lookupMap(Goal.class); } @@ -93,7 +63,7 @@ protected void lookup(LocalContext context) { public static final int BAD_OPERATION = 2; // bad user input or alike public static final int CANCELED = 3; // user canceled - protected int doExecute(LocalContext context) throws Exception { + protected int doExecute(EncryptContext context) throws Exception { try { if (!context.interactive) { context.terminal.writer().println("This tool works only in interactive mode!"); @@ -164,7 +134,7 @@ protected int doExecute(LocalContext context) throws Exception { } } - protected int badGoalsErrorMessage(String message, LocalContext context) { + protected int badGoalsErrorMessage(String message, EncryptContext context) { context.terminal.writer().println(message); context.terminal.writer().println("Supported goals are: " + String.join(", ", context.goals.keySet())); context.terminal.writer().println("Use -h to display help."); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvokerRequest.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvokerRequest.java similarity index 95% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvokerRequest.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvokerRequest.java index 9cb2dcd1ba5a..425f4d318db5 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptInvokerRequest.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvokerRequest.java @@ -33,11 +33,11 @@ import static java.util.Objects.requireNonNull; -public class DefaultEncryptInvokerRequest extends BaseInvokerRequest { +public class EncryptInvokerRequest extends BaseInvokerRequest { private final EncryptOptions options; @SuppressWarnings("ParameterNumber") - public DefaultEncryptInvokerRequest( + public EncryptInvokerRequest( ParserRequest parserRequest, Path cwd, Path installationDirectory, diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptParser.java similarity index 92% rename from impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptParser.java rename to impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptParser.java index f1f45ccf6bc8..07d1a5ad0ce3 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/DefaultEncryptParser.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptParser.java @@ -26,10 +26,10 @@ import org.apache.maven.api.cli.ParserException; import org.apache.maven.cling.invoker.BaseParser; -public class DefaultEncryptParser extends BaseParser { +public class EncryptParser extends BaseParser { @Override - protected DefaultEncryptInvokerRequest getInvokerRequest(LocalContext context) { - return new DefaultEncryptInvokerRequest( + protected EncryptInvokerRequest getInvokerRequest(LocalContext context) { + return new EncryptInvokerRequest( context.parserRequest, context.cwd, context.installationDirectory, diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/Goal.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/Goal.java index d493b289e36c..43d2dc8b29ac 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/Goal.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/Goal.java @@ -22,5 +22,5 @@ * The mvnenc tool goal. */ public interface Goal { - int execute(DefaultEncryptInvoker.LocalContext context) throws Exception; + int execute(EncryptContext context) throws Exception; } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/ConfiguredGoalSupport.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/ConfiguredGoalSupport.java index efd4792f5c95..fc9a51ad846d 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/ConfiguredGoalSupport.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/ConfiguredGoalSupport.java @@ -23,10 +23,10 @@ import java.util.function.Consumer; import org.apache.maven.api.services.MessageBuilderFactory; -import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker; +import org.apache.maven.cling.invoker.mvnenc.EncryptContext; import org.codehaus.plexus.components.secdispatcher.SecDispatcher; -import static org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker.ERROR; +import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.ERROR; /** * The support class for goal implementations that requires valid/workable config. @@ -37,7 +37,7 @@ protected ConfiguredGoalSupport(MessageBuilderFactory messageBuilderFactory, Sec } @Override - public int execute(DefaultEncryptInvoker.LocalContext context) throws Exception { + public int execute(EncryptContext context) throws Exception { if (!validateConfiguration(context)) { context.terminal .writer() @@ -50,7 +50,7 @@ public int execute(DefaultEncryptInvoker.LocalContext context) throws Exception return doExecute(context); } - protected boolean validateConfiguration(DefaultEncryptInvoker.LocalContext context) { + protected boolean validateConfiguration(EncryptContext context) { SecDispatcher.ValidationResponse response = secDispatcher.validateConfiguration(); if (!response.isValid() || context.invokerRequest.options().verbose().orElse(false)) { dumpResponse(context, "", response); @@ -58,8 +58,7 @@ protected boolean validateConfiguration(DefaultEncryptInvoker.LocalContext conte return response.isValid(); } - protected void dumpResponse( - DefaultEncryptInvoker.LocalContext context, String indent, SecDispatcher.ValidationResponse response) { + protected void dumpResponse(EncryptContext context, String indent, SecDispatcher.ValidationResponse response) { context.terminal .writer() .println(messageBuilderFactory @@ -100,5 +99,5 @@ protected void dumpResponse( } } - protected abstract int doExecute(DefaultEncryptInvoker.LocalContext context) throws Exception; + protected abstract int doExecute(EncryptContext context) throws Exception; } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Decrypt.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Decrypt.java index 43be1949e5a7..e58ac80bcd9b 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Decrypt.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Decrypt.java @@ -23,11 +23,11 @@ import javax.inject.Singleton; import org.apache.maven.api.services.MessageBuilderFactory; -import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker; +import org.apache.maven.cling.invoker.mvnenc.EncryptContext; import org.codehaus.plexus.components.secdispatcher.SecDispatcher; -import static org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker.BAD_OPERATION; -import static org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker.OK; +import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.BAD_OPERATION; +import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK; /** * The "decrypt" goal. @@ -41,7 +41,7 @@ public Decrypt(MessageBuilderFactory messageBuilderFactory, SecDispatcher secDis } @Override - protected int doExecute(DefaultEncryptInvoker.LocalContext context) throws Exception { + protected int doExecute(EncryptContext context) throws Exception { String encrypted = context.reader.readLine("Enter the password to decrypt: "); if (secDispatcher.isAnyEncryptedString(encrypted)) { context.terminal.writer().println(secDispatcher.decrypt(encrypted)); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Diag.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Diag.java index 1f85bbed48b5..700ed47bc3eb 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Diag.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Diag.java @@ -23,10 +23,10 @@ import javax.inject.Singleton; import org.apache.maven.api.services.MessageBuilderFactory; -import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker; +import org.apache.maven.cling.invoker.mvnenc.EncryptContext; import org.codehaus.plexus.components.secdispatcher.SecDispatcher; -import static org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker.OK; +import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK; /** * The "diag" goal. @@ -40,7 +40,7 @@ public Diag(MessageBuilderFactory messageBuilderFactory, SecDispatcher secDispat } @Override - protected int doExecute(DefaultEncryptInvoker.LocalContext context) { + protected int doExecute(EncryptContext context) { dumpResponse(context, "", secDispatcher.validateConfiguration()); return OK; } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Encrypt.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Encrypt.java index a3fce98d61d0..bbe77f54a002 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Encrypt.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Encrypt.java @@ -23,10 +23,10 @@ import javax.inject.Singleton; import org.apache.maven.api.services.MessageBuilderFactory; -import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker; +import org.apache.maven.cling.invoker.mvnenc.EncryptContext; import org.codehaus.plexus.components.secdispatcher.SecDispatcher; -import static org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker.OK; +import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK; /** * The "encrypt" goal. @@ -40,7 +40,7 @@ public Encrypt(MessageBuilderFactory messageBuilderFactory, SecDispatcher secDis } @Override - protected int doExecute(DefaultEncryptInvoker.LocalContext context) throws Exception { + protected int doExecute(EncryptContext context) throws Exception { String cleartext = context.reader.readLine("Enter the password to encrypt: ", '*'); context.terminal.writer().println(secDispatcher.encrypt(cleartext, null)); return OK; diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java index 498ae0bec726..3c78188376f8 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/goals/Init.java @@ -28,7 +28,7 @@ import org.apache.maven.api.cli.mvnenc.EncryptOptions; import org.apache.maven.api.services.MessageBuilderFactory; -import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker; +import org.apache.maven.cling.invoker.mvnenc.EncryptContext; import org.codehaus.plexus.components.secdispatcher.DispatcherMeta; import org.codehaus.plexus.components.secdispatcher.SecDispatcher; import org.codehaus.plexus.components.secdispatcher.model.Config; @@ -46,8 +46,8 @@ import org.jline.reader.ParsedLine; import org.jline.utils.Colors; -import static org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker.BAD_OPERATION; -import static org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker.OK; +import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.BAD_OPERATION; +import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK; /** * The "init" goal. @@ -63,7 +63,7 @@ public Init(MessageBuilderFactory messageBuilderFactory, SecDispatcher secDispat } @Override - public int execute(DefaultEncryptInvoker.LocalContext context) throws Exception { + public int execute(EncryptContext context) throws Exception { context.addInHeader(context.style.italic().bold().foreground(Colors.rgbColor("yellow")), "goal: init"); context.addInHeader(""); @@ -241,8 +241,7 @@ protected PromptBuilder dispatcherPrompt(PromptBuilder promptBuilder) { } private PromptBuilder configureDispatcher( - DefaultEncryptInvoker.LocalContext context, DispatcherMeta dispatcherMeta, PromptBuilder promptBuilder) - throws Exception { + EncryptContext context, DispatcherMeta dispatcherMeta, PromptBuilder promptBuilder) throws Exception { context.addInHeader( context.style.italic().bold().foreground(Colors.rgbColor("yellow")), "Configure " + dispatcherMeta.displayName()); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/package-info.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/package-info.java index 65d166c16846..b169eba8dbf4 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/package-info.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/package-info.java @@ -18,7 +18,7 @@ */ /** - * This package contain support (hence abstract) classes mainly, that implements "base" of CLIng. + * This package contain support (mostly abstract) classes, that implement "base" of CLIng. * In packages below you find actual implementations. */ package org.apache.maven.cling.invoker; diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java index 2627e31f020e..24ea2f6cb575 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java @@ -27,15 +27,13 @@ import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Parser; import org.apache.maven.api.cli.ParserRequest; -import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.jline.JLineMessageBuilderFactory; import org.junit.jupiter.api.Assumptions; import static org.junit.jupiter.api.Assertions.assertEquals; -public abstract class MavenInvokerTestSupport< - O extends MavenOptions, R extends org.apache.maven.api.cli.InvokerRequest> { +public abstract class MavenInvokerTestSupport { protected void invoke(Path cwd, Collection goals) throws Exception { // works only in recent Maven4 @@ -98,8 +96,8 @@ public static void main(String... args) { Files.createDirectories(appJava.getParent()); Files.writeString(appJava, appJavaString); - Parser parser = createParser(); - try (Invoker invoker = createInvoker()) { + Parser parser = createParser(); + try (Invoker invoker = createInvoker()) { for (String goal : goals) { Path logFile = cwd.resolve(goal + "-build.log").toAbsolutePath(); int exitCode = invoker.invoke(parser.parse(ParserRequest.mvn( @@ -114,7 +112,7 @@ public static void main(String... args) { } } - protected abstract Invoker createInvoker(); + protected abstract Invoker createInvoker(); - protected abstract Parser createParser(); + protected abstract Parser createParser(); } diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java index 28ccdfc3a6de..8698f5a78eeb 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java @@ -23,8 +23,8 @@ import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Parser; -import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport; +import org.apache.maven.cling.invoker.mvn.MavenParser; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDir; @@ -32,16 +32,16 @@ /** * Forked UT: it cannot use jimFS as it runs in child process. */ -public class ForkedMavenInvokerTest extends MavenInvokerTestSupport { +public class ForkedMavenInvokerTest extends MavenInvokerTestSupport { @Override - protected Invoker createInvoker() { + protected Invoker createInvoker() { return new ForkedMavenInvoker(); } @Override - protected Parser createParser() { - return new ForkedMavenParser(); + protected Parser createParser() { + return new MavenParser(); } @Test diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvokerTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvokerTest.java index c877597ea850..d4389788fab9 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvokerTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/local/DefaultLocalMavenInvokerTest.java @@ -26,9 +26,9 @@ import com.google.common.jimfs.Jimfs; import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Parser; -import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport; +import org.apache.maven.cling.invoker.mvn.MavenParser; import org.codehaus.plexus.classworlds.ClassWorld; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -40,18 +40,17 @@ */ @Disabled( "The tests reuse properties from the JVM being launched, thus may lead to failures depending on which options are used") -public class DefaultLocalMavenInvokerTest - extends MavenInvokerTestSupport> { +public class DefaultLocalMavenInvokerTest extends MavenInvokerTestSupport { @Override - protected Invoker> createInvoker() { - return new DefaultLocalMavenInvoker(ProtoLookup.builder() + protected Invoker createInvoker() { + return new LocalMavenInvoker(ProtoLookup.builder() .addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader())) .build()); } @Override - protected Parser> createParser() { - return new DefaultMavenParser(); + protected Parser createParser() { + return new MavenParser(); } @Test diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvokerTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvokerTest.java index 34be76a74ecf..de65db950313 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvokerTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/resident/DefaultResidentMavenInvokerTest.java @@ -26,9 +26,9 @@ import com.google.common.jimfs.Jimfs; import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Parser; -import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport; +import org.apache.maven.cling.invoker.mvn.MavenParser; import org.codehaus.plexus.classworlds.ClassWorld; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -40,19 +40,18 @@ */ @Disabled( "The tests reuse properties from the JVM being launched, thus may lead to failures depending on which options are used") -public class DefaultResidentMavenInvokerTest - extends MavenInvokerTestSupport> { +public class DefaultResidentMavenInvokerTest extends MavenInvokerTestSupport { @Override - protected Invoker> createInvoker() { + protected Invoker createInvoker() { return new ResidentMavenInvoker(ProtoLookup.builder() .addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader())) .build()); } @Override - protected Parser> createParser() { - return new DefaultMavenParser(); + protected Parser createParser() { + return new MavenParser(); } @Test From ef0e6965704b23fd77722a89bbba0c5b64399e55 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 12:07:04 +0100 Subject: [PATCH 04/16] Smaller bugs --- .../java/org/apache/maven/cling/invoker/LookupInvoker.java | 3 ++- .../main/java/org/apache/maven/cling/invoker/ProtoLogger.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java index 0187b2dfd01c..0fa68f0814be 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java @@ -104,7 +104,8 @@ public int invoke(InvokerRequest invokerRequest) throws InvokerException { ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); try (C context = createContext(invokerRequest)) { try { - if (context.containerCapsule.currentThreadClassLoader().isPresent()) { + if (context.containerCapsule != null + && context.containerCapsule.currentThreadClassLoader().isPresent()) { Thread.currentThread() .setContextClassLoader(context.containerCapsule .currentThreadClassLoader() diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ProtoLogger.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ProtoLogger.java index 0f9e6dd252aa..7c795e8d809a 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ProtoLogger.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/ProtoLogger.java @@ -61,7 +61,7 @@ private PrintStream toPsOrDef(OutputStream outputStream, PrintStream def) { public void log(Level level, String message, Throwable error) { PrintWriter pw = level == Level.ERROR ? err : level == Level.WARN ? out : null; if (pw != null) { - pw.print(level.name() + " " + message); + pw.println(level.name() + " " + message); if (error != null) { error.printStackTrace(pw); } From 616b53113274b70248f68ee3b6689dca6d61fbf5 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 12:22:59 +0100 Subject: [PATCH 05/16] Remove, lookup when needed this is a prototype anyway --- .../java/org/apache/maven/cling/invoker/LookupContext.java | 2 -- .../java/org/apache/maven/cling/invoker/LookupInvoker.java | 3 +-- .../maven/cling/invoker/mvn/resident/ResidentMavenContext.java | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java index 42dad4162c7b..e5af6e8513d6 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupContext.java @@ -32,7 +32,6 @@ import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.Logger; import org.apache.maven.api.services.Lookup; -import org.apache.maven.api.services.SettingsBuilder; import org.apache.maven.api.settings.Settings; import org.apache.maven.cling.invoker.mvn.ProtoSession; import org.apache.maven.cling.logging.Slf4jConfiguration; @@ -74,7 +73,6 @@ protected LookupContext(InvokerRequest invokerRequest) { public Consumer writer; public ContainerCapsule containerCapsule; public Lookup lookup; - public SettingsBuilder settingsBuilder; public boolean interactive; public Path localRepositoryPath; diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java index 0fa68f0814be..ae229ec7c00f 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java @@ -369,7 +369,6 @@ protected void container(C context) throws Exception { context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(this, context); context.closeables.add(context.containerCapsule); context.lookup = context.containerCapsule.getLookup(); - context.settingsBuilder = context.lookup.lookup(SettingsBuilder.class); // refresh logger in case container got customized by spy org.slf4j.Logger l = context.loggerFactory.getLogger(this.getClass().getName()); @@ -413,7 +412,7 @@ protected void postCommands(C context) throws Exception { } protected void settings(C context) throws Exception { - settings(context, context.settingsBuilder); + settings(context, context.lookup.lookup(SettingsBuilder.class)); } protected void settings(C context, SettingsBuilder settingsBuilder) throws Exception { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java index 7e34b0a449c6..b58efbba9dbd 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java @@ -48,7 +48,6 @@ public ResidentMavenContext copy(InvokerRequest invokerRequest) { shadow.loggerLevel = loggerLevel; shadow.containerCapsule = containerCapsule; shadow.lookup = lookup; - shadow.settingsBuilder = settingsBuilder; shadow.interactive = interactive; shadow.localRepositoryPath = localRepositoryPath; From a30a01aa1a1bdb9939683b8b6f8016cea40ad09e Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 12:29:07 +0100 Subject: [PATCH 06/16] Another prototype --- .../java/org/apache/maven/cling/invoker/mvn/MavenContext.java | 2 -- .../java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java | 4 ++-- .../cling/invoker/mvn/resident/ResidentMavenContext.java | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java index 92a7a5226618..26d9c2b512ce 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenContext.java @@ -20,7 +20,6 @@ import org.apache.maven.Maven; import org.apache.maven.api.cli.InvokerRequest; -import org.apache.maven.api.services.ToolchainsBuilder; import org.apache.maven.api.services.model.ModelProcessor; import org.apache.maven.cling.invoker.LookupContext; import org.apache.maven.eventspy.internal.EventSpyDispatcher; @@ -38,7 +37,6 @@ public MavenContext(InvokerRequest invokerRequest) { public MavenExecutionRequest mavenExecutionRequest; public EventSpyDispatcher eventSpyDispatcher; public MavenExecutionRequestPopulator mavenExecutionRequestPopulator; - public ToolchainsBuilder toolchainsBuilder; public ModelProcessor modelProcessor; public Maven maven; } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java index 8f141c974474..9fdb40c1480b 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java @@ -116,7 +116,6 @@ protected void prepare(C context) throws Exception { protected void lookup(C context) throws Exception { context.eventSpyDispatcher = context.lookup.lookup(EventSpyDispatcher.class); context.mavenExecutionRequestPopulator = context.lookup.lookup(MavenExecutionRequestPopulator.class); - context.toolchainsBuilder = context.lookup.lookup(ToolchainsBuilder.class); context.modelProcessor = context.lookup.lookup(ModelProcessor.class); context.maven = context.lookup.lookup(Maven.class); } @@ -241,7 +240,8 @@ protected void toolchains(C context) throws Exception { context.logger.debug("Reading installation toolchains from '" + installationToolchainsFile + "'"); context.logger.debug("Reading user toolchains from '" + userToolchainsFile + "'"); - ToolchainsBuilderResult toolchainsResult = context.toolchainsBuilder.build(toolchainsRequest); + ToolchainsBuilderResult toolchainsResult = + context.lookup.lookup(ToolchainsBuilder.class).build(toolchainsRequest); context.eventSpyDispatcher.onEvent(toolchainsResult); diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java index b58efbba9dbd..aa1102baa805 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenContext.java @@ -59,7 +59,6 @@ public ResidentMavenContext copy(InvokerRequest invokerRequest) { shadow.mavenExecutionRequest = mavenExecutionRequest; shadow.eventSpyDispatcher = eventSpyDispatcher; shadow.mavenExecutionRequestPopulator = mavenExecutionRequestPopulator; - shadow.toolchainsBuilder = toolchainsBuilder; shadow.modelProcessor = modelProcessor; shadow.maven = maven; From 0504f1b842ba4c3d3289482c70da773072bbd156 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 12:59:28 +0100 Subject: [PATCH 07/16] Add some doco --- .../mvn/forked/ForkedMavenInvoker.java | 2 +- .../invoker/mvn/local/LocalMavenInvoker.java | 4 +--- .../maven/cling/invoker/mvn/package-info.java | 23 +++++++++++++++++++ .../mvn/resident/ResidentMavenInvoker.java | 2 +- .../cling/invoker/mvnenc/package-info.java | 23 +++++++++++++++++++ 5 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/package-info.java create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/package-info.java diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvoker.java index 12b8bf491df8..29ad880a2f68 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvoker.java @@ -32,7 +32,7 @@ import static java.util.Objects.requireNonNull; /** - * Forked invoker implementation, that spawns a subprocess with Maven. + * Forked invoker implementation, that spawns a subprocess with Maven from the installation directory. */ public class ForkedMavenInvoker implements Invoker { @SuppressWarnings("MethodLength") diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/LocalMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/LocalMavenInvoker.java index 3fdc065b76d9..3ac8cc783b46 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/LocalMavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/local/LocalMavenInvoker.java @@ -25,9 +25,7 @@ import org.apache.maven.cling.invoker.mvn.MavenInvoker; /** - * Local resident invoker implementation, similar to "local" but keeps Maven instance resident. This implies, that - * things like environment, system properties, extensions etc. are loaded only once. It is caller duty to ensure - * that subsequent call is right for the resident instance (ie no env change or different extension needed). + * Local Maven invoker implementation, that expects all the Maven to be on classpath. */ public class LocalMavenInvoker extends MavenInvoker { public LocalMavenInvoker(ProtoLookup protoLookup) { diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/package-info.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/package-info.java new file mode 100644 index 000000000000..60eea96850bb --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/package-info.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * This package contains the {@code mvn} tool implementation. + */ +package org.apache.maven.cling.invoker.mvn; diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java index 8e3bd243c628..95132cdcc939 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/resident/ResidentMavenInvoker.java @@ -27,7 +27,7 @@ import org.apache.maven.cling.invoker.mvn.MavenInvoker; /** - * Local resident invoker implementation, similar to "local" but keeps Maven instance resident. This implies, that + * Resident invoker implementation, similar to "local", but keeps Maven instance resident. This implies, that * things like environment, system properties, extensions etc. are loaded only once. It is caller duty to ensure * that subsequent call is right for the resident instance (ie no env change or different extension needed). */ diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/package-info.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/package-info.java new file mode 100644 index 000000000000..69376e787296 --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/package-info.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * This package contains the {@code mvnenc} tool implementation. + */ +package org.apache.maven.cling.invoker.mvnenc; From 891fd436467de906cdb2c08e32313d94f4dae37c Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 16:50:32 +0100 Subject: [PATCH 08/16] Stretch a bit --- .../org/apache/maven/api/cli/Executor.java | 55 +++++ .../maven/api/cli/ExecutorException.java | 69 ++++++ .../apache/maven/api/cli/ExecutorRequest.java | 82 ++++++++ .../apache/maven/api/cli/InvokerRequest.java | 49 +---- .../java/org/apache/maven/api/cli/Parser.java | 25 ++- .../apache/maven/api/cli/ParserRequest.java | 10 +- .../java/org/apache/maven/api/cli/Tools.java | 39 ++++ .../org/apache/maven/cling/MavenCling.java | 2 +- .../org/apache/maven/cling/MavenEncCling.java | 2 +- .../cling/invoker/BaseExecutorRequest.java | 77 +++++++ .../cling/invoker/BaseInvokerRequest.java | 43 +--- .../maven/cling/invoker/BaseParser.java | 40 +++- .../maven/cling/invoker/mvn/MavenParser.java | 20 -- .../mvn/embedded/EmbeddedMavenExecutor.java | 198 ++++++++++++++++++ .../mvn/forked/ForkedMavenExecutor.java | 73 +++++++ .../invoker/mvnenc/EncryptInvokerRequest.java | 8 +- .../cling/invoker/mvnenc/EncryptParser.java | 4 +- .../invoker/mvn/MavenExecutorTestSupport.java | 119 +++++++++++ .../invoker/mvn/MavenInvokerTestSupport.java | 2 +- .../embedded/EmbeddedMavenExecutorTest.java | 55 +++++ 20 files changed, 842 insertions(+), 130 deletions(-) create mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Executor.java create mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorException.java create mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorRequest.java create mode 100644 api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Tools.java create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseExecutorRequest.java create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java create mode 100644 impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenExecutor.java create mode 100644 impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java create mode 100644 impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Executor.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Executor.java new file mode 100644 index 000000000000..84d332c67365 --- /dev/null +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Executor.java @@ -0,0 +1,55 @@ +/* + * 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.api.cli; + +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. + * + * @since 4.0.0 + */ +@Experimental +public interface Executor extends AutoCloseable { + /** + * 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; + + /** + * 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. + * + *

The default implementation does nothing. Subclasses should override this method + * if they need to perform cleanup operations.

+ * + * @throws ExecutorException if an error occurs while closing the {@link Executor} + */ + @Override + default void close() throws ExecutorException {} +} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorException.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorException.java new file mode 100644 index 000000000000..6b67fc4f5338 --- /dev/null +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorException.java @@ -0,0 +1,69 @@ +/* + * 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.api.cli; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Nullable; +import org.apache.maven.api.services.MavenException; + +/** + * 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 MavenException { + /** + * 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); + } + + /** + * Exception for intentional exit: No message or anything will be displayed, just the + * carried exit code will be returned from invoker {@link Invoker#invoke(InvokerRequest)} method. + */ + public static final class ExitException extends ExecutorException { + private final int exitCode; + + public ExitException(int exitCode) { + super("EXIT"); + this.exitCode = exitCode; + } + + public int getExitCode() { + return exitCode; + } + } +} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorRequest.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorRequest.java new file mode 100644 index 000000000000..811fe87686a4 --- /dev/null +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorRequest.java @@ -0,0 +1,82 @@ +/* + * 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.api.cli; + +import java.nio.file.Path; +import java.util.List; +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; + +/** + * 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 were not parsed, they are just passed over + * to executed tool. + * + * @since 4.0.0 + */ +@Immutable +@Experimental +public interface ExecutorRequest { + /** + * The parser request this instance was created from. + */ + @Nonnull + ParserRequest parserRequest(); + + /** + * 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 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 and invokers that spawn a new JVM. + * + * @return an Optional containing the list of extra JVM arguments, or empty if not specified + */ + @Nonnull + Optional> jvmArguments(); +} diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerRequest.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerRequest.java index 229f9b6364ca..ed019663c6bf 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerRequest.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/InvokerRequest.java @@ -33,20 +33,14 @@ import org.apache.maven.api.services.MessageBuilderFactory; /** - * Represents a Maven execution request, encapsulating all necessary information - * for invoking a Maven build or command. + * Represents a Maven invocation request, encapsulating all necessary information + * for invoking a Maven build or command. Arguments are parsed and exposed via methods. * * @since 4.0.0 */ @Immutable @Experimental -public interface InvokerRequest { - /** - * The parser request this instance was created from. - */ - @Nonnull - ParserRequest parserRequest(); - +public interface InvokerRequest extends ExecutorRequest { /** * Shorthand for {@link Logger} to use. */ @@ -68,33 +62,6 @@ default Lookup lookup() { return parserRequest().lookup(); } - /** - * 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 a map of user-defined properties for the Maven execution. * These properties can be set using the -D command-line option. @@ -164,16 +131,6 @@ default Lookup lookup() { @Nonnull Optional> coreExtensions(); - /** - * Returns the list of extra JVM arguments to be passed to the forked Maven process. - * These arguments allow for customization of the JVM environment in which Maven will run. - * This property is used ONLY by invokers that spawn a new JVM and is fully ignored by others. - * - * @return an Optional containing the list of extra JVM arguments, or empty if not specified - */ - @Nonnull - Optional> jvmArguments(); - /** * Returns the options associated with this invocation request. * diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Parser.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Parser.java index 89f1d4278c2b..6b791cbaaecd 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Parser.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Parser.java @@ -24,24 +24,33 @@ import org.apache.maven.api.annotations.Nonnull; /** - * Defines the contract for parsing Maven command-line arguments and creating an InvokerRequest. - * This interface is responsible for interpreting the command-line input and constructing - * the appropriate {@link InvokerRequest} object. + * Defines the contract for parsing Maven command-line arguments and creating an execution or invoker requests. * * @since 4.0.0 */ @Experimental public interface Parser { /** - * Parses the given ParserRequest to create an InvokerRequest. - * This method is responsible for interpreting the contents of the ParserRequest - * and constructing the appropriate InvokerRequest object. + * Parses the given ParserRequest to create an {@link ExecutorRequest}. + * This method does not interpret tool arguments. * * @param parserRequest the request containing all necessary information for parsing - * @return the parsed InvokerRequest + * @return the parsed executor request * @throws ParserException if there's an error during parsing of the request * @throws IOException if there's an I/O error during the parsing process */ @Nonnull - InvokerRequest parse(@Nonnull ParserRequest parserRequest) throws ParserException, IOException; + ExecutorRequest parseExecution(@Nonnull ParserRequest parserRequest) throws ParserException, IOException; + + /** + * Parses the given ParserRequest to create an {@link InvokerRequest}. + * This method does interpret tool arguments. + * + * @param parserRequest the request containing all necessary information for parsing + * @return the parsed invoker request + * @throws ParserException if there's an error during parsing of the request + * @throws IOException if there's an I/O error during the parsing process + */ + @Nonnull + InvokerRequest parseInvocation(@Nonnull ParserRequest parserRequest) throws ParserException, IOException; } diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ParserRequest.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ParserRequest.java index ae5f83ec4b6b..014576b4925d 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ParserRequest.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ParserRequest.java @@ -46,12 +46,6 @@ @Immutable @Experimental public interface ParserRequest { - String MVN_CMD = "mvn"; - String MVN_NAME = "Maven"; - - String MVNENC_CMD = "mvnenc"; - String MVNENC_NAME = "Maven Password Encrypting Tool"; - /** * Returns the Maven command to be executed. This command is used in some invokers (ie forked) but also to * present help to user. @@ -179,7 +173,7 @@ static Builder mvn( @Nonnull static Builder mvn( @Nonnull List args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) { - return builder(MVN_CMD, MVN_NAME, args, logger, messageBuilderFactory); + return builder(Tools.MVN_CMD, Tools.MVN_NAME, args, logger, messageBuilderFactory); } /** @@ -207,7 +201,7 @@ static Builder mvnenc( @Nonnull static Builder mvnenc( @Nonnull List args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) { - return builder(MVNENC_CMD, MVNENC_NAME, args, logger, messageBuilderFactory); + return builder(Tools.MVNENC_CMD, Tools.MVNENC_NAME, args, logger, messageBuilderFactory); } /** diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Tools.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Tools.java new file mode 100644 index 000000000000..b237dc54145b --- /dev/null +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Tools.java @@ -0,0 +1,39 @@ +/* + * 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.api.cli; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Immutable; + +/** + * Represents most common tools supported by CLIng. + * + * @since 4.0.0 + */ +@Immutable +@Experimental +public final class Tools { + private Tools() {} + + public static final String MVN_CMD = "mvn"; + public static final String MVN_NAME = "Maven"; + + public static final String MVNENC_CMD = "mvnenc"; + public static final String MVNENC_NAME = "Maven Password Encrypting Tool"; +} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java index 7a2f646548c8..d4869f2186f3 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenCling.java @@ -68,7 +68,7 @@ protected Invoker createInvoker() { @Override protected InvokerRequest parseArguments(String[] args) throws ParserException, IOException { return new MavenParser() - .parse(ParserRequest.mvn(args, new ProtoLogger(), new JLineMessageBuilderFactory()) + .parseInvocation(ParserRequest.mvn(args, new ProtoLogger(), new JLineMessageBuilderFactory()) .build()); } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java index 66ebe9f1a0bb..b1f2f861badb 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/MavenEncCling.java @@ -68,7 +68,7 @@ protected Invoker createInvoker() { @Override protected InvokerRequest parseArguments(String[] args) throws ParserException, IOException { return new EncryptParser() - .parse(ParserRequest.mvnenc(args, new ProtoLogger(), new JLineMessageBuilderFactory()) + .parseInvocation(ParserRequest.mvnenc(args, new ProtoLogger(), new JLineMessageBuilderFactory()) .build()); } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseExecutorRequest.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseExecutorRequest.java new file mode 100644 index 000000000000..00dbef917702 --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseExecutorRequest.java @@ -0,0 +1,77 @@ +/* + * 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.invoker; + +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; +import org.apache.maven.api.cli.ExecutorRequest; +import org.apache.maven.api.cli.ParserRequest; + +import static java.util.Objects.requireNonNull; + +public class BaseExecutorRequest implements ExecutorRequest { + private final ParserRequest parserRequest; + private final Path cwd; + private final Path installationDirectory; + private final Path userHomeDirectory; + private final List jvmArguments; + + @SuppressWarnings("ParameterNumber") + public BaseExecutorRequest( + @Nonnull ParserRequest parserRequest, + @Nonnull Path cwd, + @Nonnull Path installationDirectory, + @Nonnull Path userHomeDirectory, + @Nullable List jvmArguments) { + this.parserRequest = requireNonNull(parserRequest); + this.cwd = requireNonNull(cwd); + this.installationDirectory = requireNonNull(installationDirectory); + this.userHomeDirectory = requireNonNull(userHomeDirectory); + this.jvmArguments = jvmArguments; + } + + @Override + public ParserRequest parserRequest() { + return parserRequest; + } + + @Override + public Path cwd() { + return cwd; + } + + @Override + public Path installationDirectory() { + return installationDirectory; + } + + @Override + public Path userHomeDirectory() { + return userHomeDirectory; + } + + @Override + public Optional> jvmArguments() { + return Optional.ofNullable(jvmArguments); + } +} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseInvokerRequest.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseInvokerRequest.java index 46530eee8528..25dcf754a766 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseInvokerRequest.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseInvokerRequest.java @@ -33,21 +33,15 @@ import static java.util.Objects.requireNonNull; -public abstract class BaseInvokerRequest implements InvokerRequest { - private final ParserRequest parserRequest; - private final Path cwd; - private final Path installationDirectory; - private final Path userHomeDirectory; +public abstract class BaseInvokerRequest extends BaseExecutorRequest implements InvokerRequest { private final Map userProperties; private final Map systemProperties; private final Path topDirectory; private final Path rootDirectory; - + private final List coreExtensions; private final InputStream in; private final OutputStream out; private final OutputStream err; - private final List coreExtensions; - private final List jvmArguments; @SuppressWarnings("ParameterNumber") public BaseInvokerRequest( @@ -64,40 +58,16 @@ public BaseInvokerRequest( @Nullable OutputStream err, @Nullable List coreExtensions, @Nullable List jvmArguments) { - this.parserRequest = requireNonNull(parserRequest); - this.cwd = requireNonNull(cwd); - this.installationDirectory = requireNonNull(installationDirectory); - this.userHomeDirectory = requireNonNull(userHomeDirectory); + super(parserRequest, cwd, installationDirectory, userHomeDirectory, jvmArguments); this.userProperties = requireNonNull(userProperties); this.systemProperties = requireNonNull(systemProperties); this.topDirectory = requireNonNull(topDirectory); this.rootDirectory = rootDirectory; + this.coreExtensions = coreExtensions; this.in = in; this.out = out; this.err = err; - this.coreExtensions = coreExtensions; - this.jvmArguments = jvmArguments; - } - - @Override - public ParserRequest parserRequest() { - return parserRequest; - } - - @Override - public Path cwd() { - return cwd; - } - - @Override - public Path installationDirectory() { - return installationDirectory; - } - - @Override - public Path userHomeDirectory() { - return userHomeDirectory; } @Override @@ -139,9 +109,4 @@ public Optional err() { public Optional> coreExtensions() { return Optional.ofNullable(coreExtensions); } - - @Override - public Optional> jvmArguments() { - return Optional.ofNullable(jvmArguments); - } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java index 7071b7769c03..853fea00d8be 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java @@ -33,9 +33,11 @@ import java.util.Map; import java.util.Properties; import java.util.function.Function; +import java.util.stream.Collectors; import org.apache.maven.api.Constants; import org.apache.maven.api.annotations.Nullable; +import org.apache.maven.api.cli.ExecutorRequest; import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.Parser; @@ -93,7 +95,26 @@ public Map extraInterpolationSource() { } @Override - public InvokerRequest parse(ParserRequest parserRequest) throws ParserException, IOException { + public ExecutorRequest parseExecution(ParserRequest parserRequest) throws ParserException, IOException { + requireNonNull(parserRequest); + + LocalContext context = new LocalContext(parserRequest); + + // the basics + context.cwd = requireNonNull(getCwd(context)); + context.installationDirectory = requireNonNull(getInstallationDirectory(context)); + context.userHomeDirectory = requireNonNull(getUserHomeDirectory(context)); + + return getExecutionRequest(context); + } + + protected ExecutorRequest getExecutionRequest(LocalContext context) { + return new BaseExecutorRequest( + context.parserRequest, context.cwd, context.installationDirectory, context.userHomeDirectory, null); + } + + @Override + public InvokerRequest parseInvocation(ParserRequest parserRequest) throws ParserException, IOException { requireNonNull(parserRequest); LocalContext context = new LocalContext(parserRequest); @@ -304,4 +325,21 @@ protected List readCoreExtensionsDescriptorFromFile(Path extensio throw new ParserException("Failed to parse extensions file: " + extensionsFile, e); } } + + protected List getJvmArguments(Path rootDirectory) throws ParserException { + if (rootDirectory != null) { + Path jvmConfig = rootDirectory.resolve(".mvn/jvm.config"); + if (Files.exists(jvmConfig)) { + try { + return Files.readAllLines(jvmConfig).stream() + .filter(l -> !l.isBlank() && !l.startsWith("#")) + .flatMap(l -> Arrays.stream(l.split(" "))) + .collect(Collectors.toList()); + } catch (IOException e) { + throw new ParserException("Failed to read JVM configuration file: " + jvmConfig, e); + } + } + } + return null; + } } diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java index 1b9fac64cfc6..944d0a94f942 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenParser.java @@ -19,14 +19,11 @@ package org.apache.maven.cling.invoker.mvn; import java.io.IOException; -import java.io.UncheckedIOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.cli.ParseException; @@ -76,23 +73,6 @@ protected MavenOptions parseArgs(String source, List args) throws Parser } } - protected List getJvmArguments(Path rootDirectory) { - if (rootDirectory != null) { - Path jvmConfig = rootDirectory.resolve(".mvn/jvm.config"); - if (Files.exists(jvmConfig)) { - try { - return Files.readAllLines(jvmConfig).stream() - .filter(l -> !l.isBlank() && !l.startsWith("#")) - .flatMap(l -> Arrays.stream(l.split(" "))) - .collect(Collectors.toList()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - } - return null; - } - @Override protected MavenInvokerRequest getInvokerRequest(LocalContext context) { return new MavenInvokerRequest( diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java new file mode 100644 index 000000000000..d76919fa7f5a --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java @@ -0,0 +1,198 @@ +/* + * 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.invoker.mvn.embedded; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +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.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +import org.apache.maven.api.cli.Executor; +import org.apache.maven.api.cli.ExecutorException; +import org.apache.maven.api.cli.ExecutorRequest; +import org.apache.maven.api.cli.ParserRequest; +import org.apache.maven.cling.invoker.BaseExecutorRequest; + +import static java.util.Objects.requireNonNull; + +/** + * Embedded invoker implementation, that invokes Maven from installation directory within this same JVM but in isolated + * classloader. + */ +public class EmbeddedMavenExecutor implements Executor { + protected static final class Context { + private final Properties properties; + private final URLClassLoader bootClassLoader; + private final Object classWorld; + private final Method mainMethod; + + public Context(Properties properties, URLClassLoader bootClassLoader, Object classWorld, Method mainMethod) { + this.properties = properties; + this.bootClassLoader = bootClassLoader; + this.classWorld = classWorld; + this.mainMethod = mainMethod; + } + } + + private final Properties originalProperties; + private final ClassLoader originalClassLoader; + private final ConcurrentHashMap contexts; + + public EmbeddedMavenExecutor() { + this.originalClassLoader = Thread.currentThread().getContextClassLoader(); + this.contexts = new ConcurrentHashMap<>(); + this.originalProperties = System.getProperties(); + } + + @Override + public int execute(ExecutorRequest executorRequest) throws ExecutorException { + requireNonNull(executorRequest); + validate(executorRequest); + + Path installation = executorRequest.installationDirectory(); + if (!Files.isDirectory(installation)) { + throw new IllegalArgumentException("Installation directory must point to existing directory"); + } + Context context = mayCreate(installation); + + System.setProperties(context.properties); + Thread.currentThread().setContextClassLoader(context.bootClassLoader); + try { + return (int) context.mainMethod.invoke( + null, executorRequest.parserRequest().args().toArray(new String[0]), context.classWorld); + } catch (Exception e) { + throw new ExecutorException("Failed to execute", e); + } finally { + Thread.currentThread().setContextClassLoader(originalClassLoader); + System.setProperties(originalProperties); + } + } + + protected Context mayCreate(Path installation) { + return contexts.computeIfAbsent(installation, k -> { + Path mavenHome = installation.toAbsolutePath().normalize(); + 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"); + } + + Properties properties = System.getProperties(); + properties.put("maven.home", mavenHome.toString()); + properties.put("maven.mainClass", "org.apache.maven.cling.MavenCling"); + properties.put( + "library.jline.path", mavenHome.resolve("lib/jline-native").toString()); + + System.setProperties(properties); + URLClassLoader bootClassLoader = createMavenBootClassLoader(boot, Collections.emptyList()); + Thread.currentThread().setContextClassLoader(bootClassLoader); + try { + Class launcherClass = bootClassLoader.loadClass("org.codehaus.plexus.classworlds.launcher.Launcher"); + Class classWorldClass = bootClassLoader.loadClass("org.codehaus.plexus.classworlds.ClassWorld"); + 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); + Class cliClass = + (Class) launcherClass.getMethod("getMainClass").invoke(launcher); + Method mainMethod = cliClass.getMethod("main", String[].class, classWorldClass); + + return new Context(properties, bootClassLoader, classWorld, mainMethod); + } catch (Exception e) { + throw new ExecutorException("Failed to create executor", e); + } finally { + Thread.currentThread().setContextClassLoader(originalClassLoader); + System.setProperties(originalProperties); + } + }); + } + + @Override + public void close() throws ExecutorException { + try { + ArrayList 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 Exception { + Thread.currentThread().setContextClassLoader(context.bootClassLoader); + try { + try { + context.bootClassLoader.close(); + } finally { + ((Closeable) context.classWorld).close(); + } + } finally { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } + + protected void validate(ExecutorRequest executorRequest) throws ExecutorException {} + + protected URLClassLoader createMavenBootClassLoader(Path boot, List extraClasspath) { + ArrayList urls = new ArrayList<>(extraClasspath); + try (Stream 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()); + } +} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenExecutor.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenExecutor.java new file mode 100644 index 000000000000..b8e25b84dfb4 --- /dev/null +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenExecutor.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.cling.invoker.mvn.forked; + +import java.io.IOException; +import java.util.ArrayList; + +import org.apache.maven.api.cli.Executor; +import org.apache.maven.api.cli.ExecutorException; +import org.apache.maven.api.cli.ExecutorRequest; +import org.apache.maven.internal.impl.model.profile.Os; + +import static java.util.Objects.requireNonNull; + +/** + * Forked executor implementation, that spawns a subprocess with Maven from the installation directory. + */ +public class ForkedMavenExecutor implements Executor { + @Override + public int execute(ExecutorRequest executorRequest) throws ExecutorException { + requireNonNull(executorRequest); + validate(executorRequest); + + ArrayList cmdAndArguments = new ArrayList<>(); + cmdAndArguments.add(executorRequest + .installationDirectory() + .resolve("bin") + .resolve( + Os.IS_WINDOWS + ? executorRequest.parserRequest().command() + ".cmd" + : executorRequest.parserRequest().command()) + .toString()); + + cmdAndArguments.addAll(executorRequest.parserRequest().args()); + + try { + ProcessBuilder pb = new ProcessBuilder() + .directory(executorRequest.cwd().toFile()) + .command(cmdAndArguments); + + if (executorRequest.jvmArguments().isPresent()) { + pb.environment() + .put( + "MAVEN_OPTS", + String.join(" ", executorRequest.jvmArguments().get())); + } + + return pb.start().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 void validate(ExecutorRequest executorRequest) throws ExecutorException {} +} diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvokerRequest.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvokerRequest.java index 425f4d318db5..004e64e4285d 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvokerRequest.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptInvokerRequest.java @@ -25,7 +25,6 @@ import java.util.Map; import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.api.cli.extensions.CoreExtension; import org.apache.maven.api.cli.mvnenc.EncryptOptions; @@ -50,7 +49,8 @@ public EncryptInvokerRequest( OutputStream out, OutputStream err, List coreExtensions, - Options options) { + List jvmArguments, + EncryptOptions options) { super( parserRequest, cwd, @@ -64,8 +64,8 @@ public EncryptInvokerRequest( out, err, coreExtensions, - null); - this.options = (EncryptOptions) requireNonNull(options); + jvmArguments); + this.options = requireNonNull(options); } /** diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptParser.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptParser.java index 07d1a5ad0ce3..f49fa2e852c0 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptParser.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvnenc/EncryptParser.java @@ -24,6 +24,7 @@ import org.apache.commons.cli.ParseException; import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.ParserException; +import org.apache.maven.api.cli.mvnenc.EncryptOptions; import org.apache.maven.cling.invoker.BaseParser; public class EncryptParser extends BaseParser { @@ -42,7 +43,8 @@ protected EncryptInvokerRequest getInvokerRequest(LocalContext context) { context.parserRequest.out(), context.parserRequest.err(), context.extensions, - context.options); + getJvmArguments(context.rootDirectory), + (EncryptOptions) context.options); } @Override diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java new file mode 100644 index 000000000000..b5822ca5d747 --- /dev/null +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java @@ -0,0 +1,119 @@ +/* + * 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.invoker.mvn; + +import org.apache.maven.api.cli.Executor; +import org.apache.maven.api.cli.Invoker; +import org.apache.maven.api.cli.Parser; +import org.apache.maven.api.cli.ParserRequest; +import org.apache.maven.cling.invoker.ProtoLogger; +import org.apache.maven.jline.JLineMessageBuilderFactory; +import org.junit.jupiter.api.Assumptions; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public abstract class MavenExecutorTestSupport { + + protected void execute(Path cwd, Collection goals) throws Exception { + // works only in recent Maven4 + Assumptions.assumeTrue( + Files.isRegularFile(Paths.get(System.getProperty("maven.home")) + .resolve("conf") + .resolve("maven.properties")), + "${maven.home}/conf/maven.properties must be a file"); + + Files.createDirectory(cwd.resolve(".mvn")); + + String pomString = + """ + + + + 4.0.0 + + org.apache.maven.samples + sample + 1.0.0 + + + + + org.junit + junit-bom + 5.11.1 + pom + import + + + + + + + org.junit.jupiter + junit-jupiter-api + test + + + + + """; + Path pom = cwd.resolve("pom.xml").toAbsolutePath(); + Files.writeString(pom, pomString); + + String appJavaString = + """ + package org.apache.maven.samples.sample; + + public class App { + public static void main(String... args) { + System.out.println("Hello World!"); + } + } + """; + Path appJava = cwd.resolve("src/main/java/org/apache/maven/samples/sample/App.java"); + Files.createDirectories(appJava.getParent()); + Files.writeString(appJava, appJavaString); + + Parser parser = createParser(); + try (Executor invoker = createExecutor()) { + for (String goal : goals) { + Path logFile = cwd.resolve(goal + "-build.log").toAbsolutePath(); + int exitCode = invoker.execute(parser.parseExecution(ParserRequest.mvn( + List.of("-l", logFile.toString(), goal), + new ProtoLogger(), + new JLineMessageBuilderFactory()) + .cwd(cwd) + .build())); + String log = Files.readString(logFile); + assertEquals(0, exitCode, log); + } + } + } + + protected abstract Executor createExecutor(); + + protected abstract Parser createParser(); +} diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java index 24ea2f6cb575..dcf7ac539324 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java @@ -100,7 +100,7 @@ public static void main(String... args) { try (Invoker invoker = createInvoker()) { for (String goal : goals) { Path logFile = cwd.resolve(goal + "-build.log").toAbsolutePath(); - int exitCode = invoker.invoke(parser.parse(ParserRequest.mvn( + int exitCode = invoker.invoke(parser.parseInvocation(ParserRequest.mvn( List.of("-l", logFile.toString(), goal), new ProtoLogger(), new JLineMessageBuilderFactory()) diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java new file mode 100644 index 000000000000..4b579d08d31d --- /dev/null +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java @@ -0,0 +1,55 @@ +/* + * 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.invoker.mvn.embedded; + +import org.apache.maven.api.cli.Executor; +import org.apache.maven.api.cli.Parser; +import org.apache.maven.cling.invoker.mvn.MavenExecutorTestSupport; +import org.apache.maven.cling.invoker.mvn.MavenParser; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.CleanupMode; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Path; +import java.util.List; + +/** + * Forked UT: it cannot use jimFS as it runs in child process. + */ +@Disabled( + "The tests reuse properties from the JVM being launched, thus may lead to failures depending on which options are used") +public class EmbeddedMavenExecutorTest extends MavenExecutorTestSupport { + + @Override + protected Executor createExecutor() { + return new EmbeddedMavenExecutor(); + } + + @Override + protected Parser createParser() { + return new MavenParser(); + } + + @Test + void defaultFs(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tempDir) throws Exception { + System.setProperty("maven.home", "/home/cstamas/Tools/maven/apache-maven-4.0.0-beta-6-SNAPSHOT"); + execute(tempDir, List.of("verify")); + } +} From 2ba54424beab227b293230b3bf9311d3c1fb5353 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 17:06:55 +0100 Subject: [PATCH 09/16] Reformat --- .../invoker/mvn/embedded/EmbeddedMavenExecutor.java | 4 ---- .../cling/invoker/mvn/MavenExecutorTestSupport.java | 13 ++++++------- .../mvn/embedded/EmbeddedMavenExecutorTest.java | 6 +++--- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java index d76919fa7f5a..e375c312a9d1 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java @@ -28,9 +28,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; @@ -39,8 +37,6 @@ import org.apache.maven.api.cli.Executor; import org.apache.maven.api.cli.ExecutorException; import org.apache.maven.api.cli.ExecutorRequest; -import org.apache.maven.api.cli.ParserRequest; -import org.apache.maven.cling.invoker.BaseExecutorRequest; import static java.util.Objects.requireNonNull; diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java index b5822ca5d747..3227d4f40b38 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java @@ -18,20 +18,19 @@ */ package org.apache.maven.cling.invoker.mvn; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; + import org.apache.maven.api.cli.Executor; -import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Parser; import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.jline.JLineMessageBuilderFactory; import org.junit.jupiter.api.Assumptions; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.List; - import static org.junit.jupiter.api.Assertions.assertEquals; public abstract class MavenExecutorTestSupport { diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java index 4b579d08d31d..b639e180f6c5 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java @@ -18,6 +18,9 @@ */ package org.apache.maven.cling.invoker.mvn.embedded; +import java.nio.file.Path; +import java.util.List; + import org.apache.maven.api.cli.Executor; import org.apache.maven.api.cli.Parser; import org.apache.maven.cling.invoker.mvn.MavenExecutorTestSupport; @@ -27,9 +30,6 @@ import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDir; -import java.nio.file.Path; -import java.util.List; - /** * Forked UT: it cannot use jimFS as it runs in child process. */ From c5f5949433669a57237f54df9f635986760cd8ca Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 17:40:06 +0100 Subject: [PATCH 10/16] Ignore UTs --- .../mvn/embedded/EmbeddedMavenExecutor.java | 26 +++++++++++++------ .../invoker/mvn/MavenExecutorTestSupport.java | 1 + .../invoker/mvn/MavenInvokerTestSupport.java | 1 + .../mvn/forked/ForkedMavenInvokerTest.java | 3 +++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java index e375c312a9d1..0a2ca9d28202 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java @@ -73,15 +73,11 @@ public EmbeddedMavenExecutor() { public int execute(ExecutorRequest executorRequest) throws ExecutorException { requireNonNull(executorRequest); validate(executorRequest); - - Path installation = executorRequest.installationDirectory(); - if (!Files.isDirectory(installation)) { - throw new IllegalArgumentException("Installation directory must point to existing directory"); - } - Context context = mayCreate(installation); + Context context = mayCreate(executorRequest); System.setProperties(context.properties); - Thread.currentThread().setContextClassLoader(context.bootClassLoader); + Thread.currentThread() + .setContextClassLoader(context.mainMethod.getDeclaringClass().getClassLoader()); try { return (int) context.mainMethod.invoke( null, executorRequest.parserRequest().args().toArray(new String[0]), context.classWorld); @@ -93,7 +89,11 @@ public int execute(ExecutorRequest executorRequest) throws ExecutorException { } } - protected Context mayCreate(Path installation) { + protected Context mayCreate(ExecutorRequest executorRequest) { + Path installation = executorRequest.installationDirectory(); + if (!Files.isDirectory(installation)) { + throw new IllegalArgumentException("Installation directory must point to existing directory"); + } return contexts.computeIfAbsent(installation, k -> { Path mavenHome = installation.toAbsolutePath().normalize(); Path boot = mavenHome.resolve("boot"); @@ -103,6 +103,16 @@ protected Context mayCreate(Path installation) { } Properties properties = System.getProperties(); + properties.put( + "user.dir", + executorRequest.cwd().toAbsolutePath().normalize().toString()); + properties.put( + "user.home", + executorRequest + .userHomeDirectory() + .toAbsolutePath() + .normalize() + .toString()); properties.put("maven.home", mavenHome.toString()); properties.put("maven.mainClass", "org.apache.maven.cling.MavenCling"); properties.put( diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java index 3227d4f40b38..a6b232e63f9f 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java @@ -107,6 +107,7 @@ public static void main(String... args) { .cwd(cwd) .build())); String log = Files.readString(logFile); + System.out.println(log); assertEquals(0, exitCode, log); } } diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java index dcf7ac539324..5ffd7ce0ebfd 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java @@ -107,6 +107,7 @@ public static void main(String... args) { .cwd(cwd) .build())); String log = Files.readString(logFile); + System.out.println(log); assertEquals(0, exitCode, log); } } diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java index 8698f5a78eeb..01ddfe3267c5 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/forked/ForkedMavenInvokerTest.java @@ -25,6 +25,7 @@ import org.apache.maven.api.cli.Parser; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport; import org.apache.maven.cling.invoker.mvn.MavenParser; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDir; @@ -32,6 +33,8 @@ /** * Forked UT: it cannot use jimFS as it runs in child process. */ +@Disabled( + "The tests reuse properties from the JVM being launched, thus may lead to failures depending on which options are used") public class ForkedMavenInvokerTest extends MavenInvokerTestSupport { @Override From 79a9d4a8afa1b6c1f3bc0a460c8014df89f0efc5 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 21:36:45 +0100 Subject: [PATCH 11/16] Support 3.x as well --- .../mvn/embedded/EmbeddedMavenExecutor.java | 84 ++++++++++++++++--- 1 file changed, 71 insertions(+), 13 deletions(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java index 0a2ca9d28202..c7dee23499ee 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java @@ -21,6 +21,8 @@ import java.io.Closeable; import java.io.IOException; import java.io.InputStream; +import java.io.PrintStream; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; @@ -32,6 +34,7 @@ import java.util.List; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import java.util.stream.Stream; import org.apache.maven.api.cli.Executor; @@ -48,14 +51,24 @@ public class EmbeddedMavenExecutor implements Executor { protected static final class Context { private final Properties properties; private final URLClassLoader bootClassLoader; + private final String version; private final Object classWorld; - private final Method mainMethod; + private final ClassLoader tccl; + private final Function exec; - public Context(Properties properties, URLClassLoader bootClassLoader, Object classWorld, Method mainMethod) { + public Context( + Properties properties, + URLClassLoader bootClassLoader, + String version, + Object classWorld, + ClassLoader tccl, + Function exec) { this.properties = properties; this.bootClassLoader = bootClassLoader; + this.version = version; this.classWorld = classWorld; - this.mainMethod = mainMethod; + this.tccl = tccl; + this.exec = exec; } } @@ -76,11 +89,9 @@ public int execute(ExecutorRequest executorRequest) throws ExecutorException { Context context = mayCreate(executorRequest); System.setProperties(context.properties); - Thread.currentThread() - .setContextClassLoader(context.mainMethod.getDeclaringClass().getClassLoader()); + Thread.currentThread().setContextClassLoader(context.tccl); try { - return (int) context.mainMethod.invoke( - null, executorRequest.parserRequest().args().toArray(new String[0]), context.classWorld); + return context.exec.apply(executorRequest); } catch (Exception e) { throw new ExecutorException("Failed to execute", e); } finally { @@ -102,7 +113,8 @@ protected Context mayCreate(ExecutorRequest executorRequest) { throw new IllegalArgumentException("Installation directory does not point to Maven installation"); } - Properties properties = System.getProperties(); + Properties properties = new Properties(); + properties.putAll(System.getProperties()); properties.put( "user.dir", executorRequest.cwd().toAbsolutePath().normalize().toString()); @@ -123,7 +135,6 @@ protected Context mayCreate(ExecutorRequest executorRequest) { Thread.currentThread().setContextClassLoader(bootClassLoader); try { Class launcherClass = bootClassLoader.loadClass("org.codehaus.plexus.classworlds.launcher.Launcher"); - Class classWorldClass = bootClassLoader.loadClass("org.codehaus.plexus.classworlds.ClassWorld"); Object launcher = launcherClass.getDeclaredConstructor().newInstance(); Method configure = launcherClass.getMethod("configure", InputStream.class); try (InputStream inputStream = Files.newInputStream(m2conf)) { @@ -132,9 +143,41 @@ protected Context mayCreate(ExecutorRequest executorRequest) { Object classWorld = launcherClass.getMethod("getWorld").invoke(launcher); Class cliClass = (Class) launcherClass.getMethod("getMainClass").invoke(launcher); - Method mainMethod = cliClass.getMethod("main", String[].class, classWorldClass); + String version = getMavenVersion(cliClass.getClassLoader()); + Function exec; - return new Context(properties, bootClassLoader, classWorld, mainMethod); + if (version.startsWith("3.")) { + // 3.x + 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); + exec = r -> { + try { + return (int) doMain.invoke(mavenCli, new Object[] { + r.parserRequest().args().toArray(new String[0]), + r.cwd().toString(), + null, + null + }); + } catch (Exception e) { + throw new ExecutorException("Failed to execute", e); + } + }; + } else { + // assume 4.x + Method mainMethod = cliClass.getMethod("main", String[].class, classWorld.getClass()); + exec = r -> { + try { + return (int) mainMethod.invoke( + null, r.parserRequest().args().toArray(new String[0]), classWorld); + } catch (Exception e) { + throw new ExecutorException("Failed to execute", e); + } + }; + } + + return new Context(properties, bootClassLoader, version, classWorld, cliClass.getClassLoader(), exec); } catch (Exception e) { throw new ExecutorException("Failed to create executor", e); } finally { @@ -169,9 +212,9 @@ protected void doClose(Context context) throws Exception { Thread.currentThread().setContextClassLoader(context.bootClassLoader); try { try { - context.bootClassLoader.close(); - } finally { ((Closeable) context.classWorld).close(); + } finally { + context.bootClassLoader.close(); } } finally { Thread.currentThread().setContextClassLoader(originalClassLoader); @@ -201,4 +244,19 @@ protected URLClassLoader createMavenBootClassLoader(Path boot, List extraCl return new URLClassLoader( urls.toArray(new URL[0]), ClassLoader.getSystemClassLoader().getParent()); } + + public String getMavenVersion(ClassLoader classLoader) throws IOException { + Properties props = new Properties(); + try (InputStream is = + classLoader.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"; + } + } } From 0dbd0038778c73d1cdc0c32715673140f412a777 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 21:44:43 +0100 Subject: [PATCH 12/16] Add 3.x test --- .../mvn/embedded/EmbeddedMavenExecutor.java | 1 + .../invoker/mvn/MavenExecutorTestSupport.java | 59 +--------------- .../invoker/mvn/MavenInvokerTestSupport.java | 50 +------------- .../cling/invoker/mvn/MavenTestSupport.java | 69 +++++++++++++++++++ .../embedded/EmbeddedMavenExecutorTest.java | 6 ++ 5 files changed, 80 insertions(+), 105 deletions(-) create mode 100644 impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenTestSupport.java diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java index c7dee23499ee..f2c283f1f73f 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java @@ -118,6 +118,7 @@ protected Context mayCreate(ExecutorRequest executorRequest) { properties.put( "user.dir", executorRequest.cwd().toAbsolutePath().normalize().toString()); + properties.put("maven.multiModuleProjectDirectory", executorRequest.cwd().toAbsolutePath().normalize().toString()); properties.put( "user.home", executorRequest diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java index a6b232e63f9f..c3c487dcc1c7 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenExecutorTestSupport.java @@ -20,7 +20,6 @@ import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Collection; import java.util.List; @@ -29,72 +28,18 @@ import org.apache.maven.api.cli.ParserRequest; import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.jline.JLineMessageBuilderFactory; -import org.junit.jupiter.api.Assumptions; import static org.junit.jupiter.api.Assertions.assertEquals; public abstract class MavenExecutorTestSupport { protected void execute(Path cwd, Collection goals) throws Exception { - // works only in recent Maven4 - Assumptions.assumeTrue( - Files.isRegularFile(Paths.get(System.getProperty("maven.home")) - .resolve("conf") - .resolve("maven.properties")), - "${maven.home}/conf/maven.properties must be a file"); - Files.createDirectory(cwd.resolve(".mvn")); - - String pomString = - """ - - - - 4.0.0 - - org.apache.maven.samples - sample - 1.0.0 - - - - - org.junit - junit-bom - 5.11.1 - pom - import - - - - - - - org.junit.jupiter - junit-jupiter-api - test - - - - - """; Path pom = cwd.resolve("pom.xml").toAbsolutePath(); - Files.writeString(pom, pomString); - - String appJavaString = - """ - package org.apache.maven.samples.sample; - - public class App { - public static void main(String... args) { - System.out.println("Hello World!"); - } - } - """; + Files.writeString(pom, MavenTestSupport.POM_STRING); Path appJava = cwd.resolve("src/main/java/org/apache/maven/samples/sample/App.java"); Files.createDirectories(appJava.getParent()); - Files.writeString(appJava, appJavaString); + Files.writeString(appJava, MavenTestSupport.APP_JAVA_STRING); Parser parser = createParser(); try (Executor invoker = createExecutor()) { diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java index 5ffd7ce0ebfd..d3dcf3fc9a20 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenInvokerTestSupport.java @@ -44,57 +44,11 @@ protected void invoke(Path cwd, Collection goals) throws Exception { "${maven.home}/conf/maven.properties must be a file"); Files.createDirectory(cwd.resolve(".mvn")); - - String pomString = - """ - - - - 4.0.0 - - org.apache.maven.samples - sample - 1.0.0 - - - - - org.junit - junit-bom - 5.11.1 - pom - import - - - - - - - org.junit.jupiter - junit-jupiter-api - test - - - - - """; Path pom = cwd.resolve("pom.xml").toAbsolutePath(); - Files.writeString(pom, pomString); - - String appJavaString = - """ - package org.apache.maven.samples.sample; - - public class App { - public static void main(String... args) { - System.out.println("Hello World!"); - } - } - """; + Files.writeString(pom, MavenTestSupport.POM_STRING); Path appJava = cwd.resolve("src/main/java/org/apache/maven/samples/sample/App.java"); Files.createDirectories(appJava.getParent()); - Files.writeString(appJava, appJavaString); + Files.writeString(appJava, MavenTestSupport.APP_JAVA_STRING); Parser parser = createParser(); try (Invoker invoker = createInvoker()) { diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenTestSupport.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenTestSupport.java new file mode 100644 index 000000000000..9c1ebeff36d5 --- /dev/null +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/MavenTestSupport.java @@ -0,0 +1,69 @@ +/* + * 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.invoker.mvn; + +public final class MavenTestSupport { + private MavenTestSupport() {} + + public static final String POM_STRING = + """ + + + + 4.0.0 + + org.apache.maven.samples + sample + 1.0.0 + + + + + org.junit + junit-bom + 5.11.1 + pom + import + + + + + + + org.junit.jupiter + junit-jupiter-api + test + + + + + """; + + 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!"); + } + } + """; +} diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java index b639e180f6c5..7199d43fdd31 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutorTest.java @@ -52,4 +52,10 @@ void defaultFs(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tempDir) throws E System.setProperty("maven.home", "/home/cstamas/Tools/maven/apache-maven-4.0.0-beta-6-SNAPSHOT"); execute(tempDir, List.of("verify")); } + + @Test + void defaultFs3x(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tempDir) throws Exception { + System.setProperty("maven.home", "/home/cstamas/.sdkman/candidates/maven/3.9.9"); + execute(tempDir, List.of("verify")); + } } From 46909eec297a393b26894a635b3c7cef098f9237 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 21:56:06 +0100 Subject: [PATCH 13/16] Adjust javadoc --- .../src/main/java/org/apache/maven/api/cli/Executor.java | 2 +- .../src/main/java/org/apache/maven/api/cli/Invoker.java | 2 +- .../cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Executor.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Executor.java index 84d332c67365..60cd38921a0f 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Executor.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Executor.java @@ -24,7 +24,7 @@ /** * 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. + * to the execution of Maven commands and builds, but it does not construct nor fully parses arguments. * * @since 4.0.0 */ diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Invoker.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Invoker.java index dc26cbcbaf1b..70b54ba20461 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Invoker.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Invoker.java @@ -24,7 +24,7 @@ /** * Defines the contract for a component responsible for invoking a Maven application * using the information provided in an {@link InvokerRequest}. This interface is central - * to the execution of Maven commands and builds. + * to the construction and invocation of Maven commands and builds, and it fully parses arguments. * *

The Invoker is designed to be flexible, allowing for different implementations * that can handle various types of {@link InvokerRequest InvokerRequests}. It also implements diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java index f2c283f1f73f..f8932b6e690b 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java @@ -44,8 +44,10 @@ import static java.util.Objects.requireNonNull; /** - * Embedded invoker implementation, that invokes Maven from installation directory within this same JVM but in isolated - * classloader. + * 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 class world with 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 { protected static final class Context { From c449ed8b6934acbb87a6f5891227e8d94282dbf0 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Tue, 12 Nov 2024 21:56:19 +0100 Subject: [PATCH 14/16] Reformat --- .../cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java index f8932b6e690b..ff34b8c4896e 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/embedded/EmbeddedMavenExecutor.java @@ -120,7 +120,9 @@ protected Context mayCreate(ExecutorRequest executorRequest) { properties.put( "user.dir", executorRequest.cwd().toAbsolutePath().normalize().toString()); - properties.put("maven.multiModuleProjectDirectory", executorRequest.cwd().toAbsolutePath().normalize().toString()); + properties.put( + "maven.multiModuleProjectDirectory", + executorRequest.cwd().toAbsolutePath().normalize().toString()); properties.put( "user.home", executorRequest From b2a8408e2fb95dbc4b0d8aa7536a75a8ddc4d266 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 13 Nov 2024 12:21:22 +0100 Subject: [PATCH 15/16] Force HTTP/1.1 for now on JDK transport We get recently a flood of GOAWAY messages, that JDK HttpClient cannot cope with in reasonable way. --- .mvn/maven.config | 1 + 1 file changed, 1 insertion(+) create mode 100644 .mvn/maven.config diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 000000000000..a4e2970377ca --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1 @@ +-Daether.transport.jdk.httpVersion=HTTP_1_1 \ No newline at end of file From 71dafe53072a7eb7a9b04f48a0a7b22f25f279a9 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 13 Nov 2024 14:50:21 +0100 Subject: [PATCH 16/16] Remove copy-pasta Executor does not have exit exception --- .../apache/maven/api/cli/ExecutorException.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorException.java b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorException.java index 6b67fc4f5338..8ce5bf157dbf 100644 --- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorException.java +++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ExecutorException.java @@ -49,21 +49,4 @@ public ExecutorException(@Nullable String message) { public ExecutorException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } - - /** - * Exception for intentional exit: No message or anything will be displayed, just the - * carried exit code will be returned from invoker {@link Invoker#invoke(InvokerRequest)} method. - */ - public static final class ExitException extends ExecutorException { - private final int exitCode; - - public ExitException(int exitCode) { - super("EXIT"); - this.exitCode = exitCode; - } - - public int getExitCode() { - return exitCode; - } - } }