Skip to content

Commit

Permalink
[MNG-8375] CLIng diet (#1897)
Browse files Browse the repository at this point in the history
First part was to "reverse" MavenCli into CLIng, that also became a huge and complex beast. Now, sanitization comes, tearing down unneeded stuff. CLIng should be simple and straightforward.

Now the **invoker** fully parses args, creates Maven instance (ie. local, using Maven components on classpath) and invokes Maven. The new **executor** in turn does NOT fully parses args and is logical equivalent of maven-invoker.

Changes:
* radically simplify CLIng existing classes (and especially API - the fact we have "local", "resident" etc invoker is actually implementation detail).
* introduce "executor", a "lower level" tool that does not parse args (and is logical equivalent of maven-invoker) and support Maven 4.x and Maven 3.x.

---

https://issues.apache.org/jira/browse/MNG-8375
  • Loading branch information
cstamas authored Nov 13, 2024
1 parent c7effeb commit a67d274
Show file tree
Hide file tree
Showing 67 changed files with 1,580 additions and 1,365 deletions.
1 change: 1 addition & 0 deletions .mvn/maven.config
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-Daether.transport.jdk.httpVersion=HTTP_1_1
Original file line number Diff line number Diff line change
@@ -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, but it does not construct nor fully parses arguments.
*
* @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.
*
* <p>The default implementation does nothing. Subclasses should override this method
* if they need to perform cleanup operations.</p>
*
* @throws ExecutorException if an error occurs while closing the {@link Executor}
*/
@Override
default void close() throws ExecutorException {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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);
}
}
Original file line number Diff line number Diff line change
@@ -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<List<String>> jvmArguments();
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,16 @@
/**
* 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.
*
* <p>The Invoker is designed to be flexible, allowing for different implementations
* that can handle various types of {@link InvokerRequest InvokerRequests}. It also implements
* {@link AutoCloseable} to ensure proper resource management.</p>
*
* @param <R> The specific type of {@link InvokerRequest} this {@code Invoker} can handle, extending {@link InvokerRequest}
*
* @since 4.0.0
*/
@Experimental
public interface Invoker<R extends InvokerRequest<? extends Options>> 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
Expand All @@ -45,7 +43,7 @@ public interface Invoker<R extends InvokerRequest<? extends Options>> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +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.
*
* @param <O> the type of {@link Options} used for this request, extending the base {@link Options} interface
* 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<O extends Options> {
/**
* The parser request this instance was created from.
*/
@Nonnull
ParserRequest parserRequest();

public interface InvokerRequest extends ExecutorRequest {
/**
* Shorthand for {@link Logger} to use.
*/
Expand All @@ -70,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.
Expand Down Expand Up @@ -172,5 +137,5 @@ default Lookup lookup() {
* @return the options object
*/
@Nonnull
O options();
Options options();
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,47 +22,35 @@

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 <R> the type of {@link InvokerRequest} produced by this parser, extending {@link InvokerRequest}
* Defines the contract for parsing Maven command-line arguments and creating an execution or invoker requests.
*
* @since 4.0.0
*/
@Experimental
public interface Parser<R extends InvokerRequest<? extends Options>> {
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)}.
* Parses the given ParserRequest to create an {@link ExecutorRequest}.
* This method does not interpret tool arguments.
*
* @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
* @param parserRequest the request containing all necessary information for parsing
* @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
default R mvn(@Nonnull String[] args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory)
throws ParserException, IOException {
return parse(ParserRequest.mvn(args, logger, messageBuilderFactory).build());
}
ExecutorRequest parseExecution(@Nonnull ParserRequest parserRequest) throws ParserException, IOException;

/**
* 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 InvokerRequest}.
* This method does interpret tool arguments.
*
* @param parserRequest the request containing all necessary information for parsing
* @return the parsed InvokerRequest
* @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
R parse(@Nonnull ParserRequest parserRequest) throws ParserException, IOException;
InvokerRequest parseInvocation(@Nonnull ParserRequest parserRequest) throws ParserException, IOException;
}
Loading

0 comments on commit a67d274

Please sign in to comment.