[MNG-8283] Maven CLIng smaller bugfixes and improvements (#1772)

This PR adopts CLIng for use in mvnd, and adds several improvements to CLIng overall.

Major topics:
* ability to pass in per-request Lookup for customization
* makes parser request creation a bit friendlier
* removes a log of redundancy (same stuff copied over)
* ability to alter rootDirectory detection in parsers
* resident invoker bugfix
* adds UTs for 3 invoker implementations

---

https://issues.apache.org/jira/browse/MNG-8283
This commit is contained in:
Tamas Cservenak 2024-10-04 14:23:10 +02:00 committed by GitHub
parent 1f1a0f9a72
commit 533790bb4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 863 additions and 500 deletions

View File

@ -26,8 +26,10 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Immutable;
import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.cli.extensions.CoreExtension; 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.MessageBuilderFactory;
/** /**
@ -38,15 +40,35 @@ import org.apache.maven.api.services.MessageBuilderFactory;
* *
* @since 4.0.0 * @since 4.0.0
*/ */
@Immutable
@Experimental @Experimental
public interface InvokerRequest<O extends Options> { public interface InvokerRequest<O extends Options> {
/** /**
* Returns the command to be executed. * The parser request this instance was created from.
*
* @return the command string
*/ */
@Nonnull @Nonnull
String command(); ParserRequest parserRequest();
/**
* Shorthand for {@link Logger} to use.
*/
default Logger logger() {
return parserRequest().logger();
}
/**
* Shorthand for {@link MessageBuilderFactory}.
*/
default MessageBuilderFactory messageBuilderFactory() {
return parserRequest().messageBuilderFactory();
}
/**
* Shorthand for {@link Lookup}.
*/
default Lookup lookup() {
return parserRequest().lookup();
}
/** /**
* Returns the current working directory for the Maven execution. * Returns the current working directory for the Maven execution.
@ -93,24 +115,6 @@ public interface InvokerRequest<O extends Options> {
@Nonnull @Nonnull
Map<String, String> systemProperties(); Map<String, String> systemProperties();
/**
* Returns the logger to be used during the early phases of Maven execution,
* before the main Maven logger is initialized.
*
* @return the early-phase logger
*/
@Nonnull
Logger logger();
/**
* Returns the factory for creating message builders.
* Message builders are used for constructing formatted log messages.
*
* @return the message builder factory
*/
@Nonnull
MessageBuilderFactory messageBuilderFactory();
/** /**
* Returns the top-level directory of the Maven invocation. * Returns the top-level directory of the Maven invocation.
* This is typically the directory containing the POM file being executed. * This is typically the directory containing the POM file being executed.

View File

@ -196,12 +196,12 @@ public interface Options {
* *
* @param printWriter the PrintWriter to use for output * @param printWriter the PrintWriter to use for output
*/ */
default void warnAboutDeprecatedOptions(@Nonnull PrintWriter printWriter) {} default void warnAboutDeprecatedOptions(@Nonnull ParserRequest request, @Nonnull PrintWriter printWriter) {}
/** /**
* Displays help information for these options. * Displays help information for these options.
* *
* @param printWriter the PrintWriter to use for output * @param printWriter the PrintWriter to use for output
*/ */
void displayHelp(@Nonnull String command, @Nonnull PrintWriter printWriter); void displayHelp(@Nonnull ParserRequest request, @Nonnull PrintWriter printWriter);
} }

View File

@ -36,10 +36,10 @@ import org.apache.maven.api.services.MessageBuilderFactory;
@Experimental @Experimental
public interface Parser<R extends InvokerRequest<? extends Options>> { public interface Parser<R extends InvokerRequest<? extends Options>> {
/** /**
* Parses the given command and arguments to create an InvokerRequest. * Parses the given Maven arguments to create an InvokerRequest.
* This is a convenience method that internally creates a ParserRequest. * This is a convenience method that internally creates a ParserRequest using
* {@link ParserRequest#mvn(String[], Logger, MessageBuilderFactory)}.
* *
* @param command the Maven command to execute
* @param args the command-line arguments * @param args the command-line arguments
* @param logger the logger to use during parsing * @param logger the logger to use during parsing
* @param messageBuilderFactory the factory for creating message builders * @param messageBuilderFactory the factory for creating message builders
@ -48,14 +48,9 @@ public interface Parser<R extends InvokerRequest<? extends Options>> {
* @throws IOException if there's an I/O error during the parsing process * @throws IOException if there's an I/O error during the parsing process
*/ */
@Nonnull @Nonnull
default R parse( default R mvn(@Nonnull String[] args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory)
@Nonnull String command,
@Nonnull String[] args,
@Nonnull Logger logger,
@Nonnull MessageBuilderFactory messageBuilderFactory)
throws ParserException, IOException { throws ParserException, IOException {
return parse(ParserRequest.builder(command, args, logger, messageBuilderFactory) return parse(ParserRequest.mvn(args, logger, messageBuilderFactory).build());
.build());
} }
/** /**

View File

@ -21,10 +21,17 @@ package org.apache.maven.api.cli;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Immutable;
import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.services.Lookup;
import org.apache.maven.api.services.LookupException;
import org.apache.maven.api.services.MessageBuilderFactory; import org.apache.maven.api.services.MessageBuilderFactory;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -36,16 +43,31 @@ import static java.util.Objects.requireNonNull;
* *
* @since 4.0.0 * @since 4.0.0
*/ */
@Immutable
@Experimental @Experimental
public interface ParserRequest { 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. * Returns the Maven command to be executed. This command is used in some invokers (ie forked) but also to
* present help to user.
* *
* @return the command string * @return the command string
*/ */
@Nonnull @Nonnull
String command(); String command();
/**
* Returns the Maven command name (ie "Maven"). This string is used in some invokers to complete error messages.
*
* @return the command (human) name
*/
String commandName();
/** /**
* Returns the logger to be used during the parsing process. * Returns the logger to be used during the parsing process.
* *
@ -65,10 +87,18 @@ public interface ParserRequest {
/** /**
* Returns the command-line arguments to be parsed. * Returns the command-line arguments to be parsed.
* *
* @return an array of argument strings * @return a list of argument strings
*/ */
@Nonnull @Nonnull
String[] args(); List<String> args();
/**
* Per-request {@link Lookup} for customization.
*
* @return a lookup possibly with custom components
*/
@Nonnull
Lookup lookup();
/** /**
* Returns the current working directory for the Maven execution. * Returns the current working directory for the Maven execution.
@ -124,10 +154,67 @@ public interface ParserRequest {
@Nullable @Nullable
OutputStream err(); OutputStream err();
/**
* Creates a new Builder instance for constructing a Maven ParserRequest.
*
* @param args the command-line arguments
* @param logger the logger to be used during parsing
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvn(
@Nonnull String[] args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return mvn(Arrays.asList(args), logger, messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven ParserRequest.
*
* @param args the command-line arguments
* @param logger the logger to be used during parsing
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvn(
@Nonnull List<String> args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return builder(MVN_CMD, MVN_NAME, args, logger, messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven Encrypting Tool ParserRequest.
*
* @param args the command-line arguments
* @param logger the logger to be used during parsing
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvnenc(
@Nonnull String[] args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return mvnenc(Arrays.asList(args), logger, messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven Encrypting Tool ParserRequest.
*
* @param args the command-line arguments
* @param logger the logger to be used during parsing
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvnenc(
@Nonnull List<String> args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return builder(MVNENC_CMD, MVNENC_NAME, args, logger, messageBuilderFactory);
}
/** /**
* Creates a new Builder instance for constructing a ParserRequest. * Creates a new Builder instance for constructing a ParserRequest.
* *
* @param command the Maven command to be executed * @param command the Maven command to be executed
* @param commandName the Maven command Name to be executed
* @param args the command-line arguments * @param args the command-line arguments
* @param logger the logger to be used during parsing * @param logger the logger to be used during parsing
* @param messageBuilderFactory the factory for creating message builders * @param messageBuilderFactory the factory for creating message builders
@ -136,17 +223,20 @@ public interface ParserRequest {
@Nonnull @Nonnull
static Builder builder( static Builder builder(
@Nonnull String command, @Nonnull String command,
@Nonnull String[] args, @Nonnull String commandName,
@Nonnull List<String> args,
@Nonnull Logger logger, @Nonnull Logger logger,
@Nonnull MessageBuilderFactory messageBuilderFactory) { @Nonnull MessageBuilderFactory messageBuilderFactory) {
return new Builder(command, args, logger, messageBuilderFactory); return new Builder(command, commandName, args, logger, messageBuilderFactory);
} }
class Builder { class Builder {
private final String command; private final String command;
private final String[] args; private final String commandName;
private final List<String> args;
private final Logger logger; private final Logger logger;
private final MessageBuilderFactory messageBuilderFactory; private final MessageBuilderFactory messageBuilderFactory;
private Lookup lookup = EMPTY_LOOKUP;
private Path cwd; private Path cwd;
private Path mavenHome; private Path mavenHome;
private Path userHome; private Path userHome;
@ -154,13 +244,24 @@ public interface ParserRequest {
private OutputStream out; private OutputStream out;
private OutputStream err; private OutputStream err;
private Builder(String command, String[] args, Logger logger, MessageBuilderFactory messageBuilderFactory) { private Builder(
this.command = requireNonNull(command, "appName"); String command,
String commandName,
List<String> args,
Logger logger,
MessageBuilderFactory messageBuilderFactory) {
this.command = requireNonNull(command, "command");
this.commandName = requireNonNull(commandName, "commandName");
this.args = requireNonNull(args, "args"); this.args = requireNonNull(args, "args");
this.logger = requireNonNull(logger, "logger"); this.logger = requireNonNull(logger, "logger");
this.messageBuilderFactory = requireNonNull(messageBuilderFactory, "messageBuilderFactory"); this.messageBuilderFactory = requireNonNull(messageBuilderFactory, "messageBuilderFactory");
} }
public Builder lookup(@Nonnull Lookup lookup) {
this.lookup = requireNonNull(lookup);
return this;
}
public Builder cwd(Path cwd) { public Builder cwd(Path cwd) {
this.cwd = cwd; this.cwd = cwd;
return this; return this;
@ -193,15 +294,28 @@ public interface ParserRequest {
public ParserRequest build() { public ParserRequest build() {
return new ParserRequestImpl( return new ParserRequestImpl(
command, args, logger, messageBuilderFactory, cwd, mavenHome, userHome, in, out, err); command,
commandName,
args,
logger,
messageBuilderFactory,
lookup,
cwd,
mavenHome,
userHome,
in,
out,
err);
} }
@SuppressWarnings("ParameterNumber") @SuppressWarnings("ParameterNumber")
private static class ParserRequestImpl implements ParserRequest { private static class ParserRequestImpl implements ParserRequest {
private final String command; private final String command;
private final String commandName;
private final Logger logger; private final Logger logger;
private final MessageBuilderFactory messageBuilderFactory; private final MessageBuilderFactory messageBuilderFactory;
private final String[] args; private final List<String> args;
private final Lookup lookup;
private final Path cwd; private final Path cwd;
private final Path mavenHome; private final Path mavenHome;
private final Path userHome; private final Path userHome;
@ -211,19 +325,23 @@ public interface ParserRequest {
private ParserRequestImpl( private ParserRequestImpl(
String command, String command,
String[] args, String commandName,
List<String> args,
Logger logger, Logger logger,
MessageBuilderFactory messageBuilderFactory, MessageBuilderFactory messageBuilderFactory,
Lookup lookup,
Path cwd, Path cwd,
Path mavenHome, Path mavenHome,
Path userHome, Path userHome,
InputStream in, InputStream in,
OutputStream out, OutputStream out,
OutputStream err) { OutputStream err) {
this.command = requireNonNull(command, "appName"); this.command = requireNonNull(command, "command");
this.args = requireNonNull(args, "args"); this.commandName = requireNonNull(commandName, "commandName");
this.args = List.copyOf(requireNonNull(args, "args"));
this.logger = requireNonNull(logger, "logger"); this.logger = requireNonNull(logger, "logger");
this.messageBuilderFactory = requireNonNull(messageBuilderFactory, "messageBuilderFactory"); this.messageBuilderFactory = requireNonNull(messageBuilderFactory, "messageBuilderFactory");
this.lookup = requireNonNull(lookup, "lookup");
this.cwd = cwd; this.cwd = cwd;
this.mavenHome = mavenHome; this.mavenHome = mavenHome;
this.userHome = userHome; this.userHome = userHome;
@ -237,6 +355,11 @@ public interface ParserRequest {
return command; return command;
} }
@Override
public String commandName() {
return commandName;
}
@Override @Override
public Logger logger() { public Logger logger() {
return logger; return logger;
@ -248,10 +371,15 @@ public interface ParserRequest {
} }
@Override @Override
public String[] args() { public List<String> args() {
return args; return args;
} }
@Override
public Lookup lookup() {
return lookup;
}
@Override @Override
public Path cwd() { public Path cwd() {
return cwd; return cwd;
@ -282,5 +410,37 @@ public interface ParserRequest {
return err; return err;
} }
} }
private static final Lookup EMPTY_LOOKUP = new Lookup() {
@Override
public <T> T lookup(Class<T> type) {
throw new LookupException("empty lookup");
}
@Override
public <T> T lookup(Class<T> type, String name) {
throw new LookupException("empty lookup");
}
@Override
public <T> Optional<T> lookupOptional(Class<T> type) {
return Optional.empty();
}
@Override
public <T> Optional<T> lookupOptional(Class<T> type, String name) {
return Optional.empty();
}
@Override
public <T> List<T> lookupList(Class<T> type) {
return List.of();
}
@Override
public <T> Map<String, T> lookupMap(Class<T> type) {
return Map.of();
}
};
} }
} }

View File

@ -23,13 +23,8 @@ import java.io.IOException;
import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Invoker;
import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerException;
import org.apache.maven.api.cli.InvokerRequest; 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.Options;
import org.apache.maven.api.cli.Parser;
import org.apache.maven.api.cli.ParserException; import org.apache.maven.api.cli.ParserException;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.apache.maven.cling.invoker.ProtoLogger;
import org.apache.maven.jline.JLineMessageBuilderFactory;
import org.apache.maven.jline.MessageUtils; import org.apache.maven.jline.MessageUtils;
import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.ClassWorld;
@ -44,26 +39,24 @@ import static java.util.Objects.requireNonNull;
public abstract class ClingSupport<O extends Options, R extends InvokerRequest<O>> { public abstract class ClingSupport<O extends Options, R extends InvokerRequest<O>> {
static final String CORE_CLASS_REALM_ID = "plexus.core"; static final String CORE_CLASS_REALM_ID = "plexus.core";
protected final String command;
protected final ClassWorld classWorld; protected final ClassWorld classWorld;
protected final boolean classWorldManaged; protected final boolean classWorldManaged;
/** /**
* Ctor that creates "managed" ClassWorld. This constructor is not used in "normal" circumstances. * Ctor that creates "managed" ClassWorld. This constructor is not used in "normal" circumstances.
*/ */
public ClingSupport(String command) { public ClingSupport() {
this(command, new ClassWorld(CORE_CLASS_REALM_ID, Thread.currentThread().getContextClassLoader()), true); this(new ClassWorld(CORE_CLASS_REALM_ID, Thread.currentThread().getContextClassLoader()), true);
} }
/** /**
* Ctor to be used when running in ClassWorlds Launcher. * Ctor to be used when running in ClassWorlds Launcher.
*/ */
public ClingSupport(String command, ClassWorld classWorld) { public ClingSupport(ClassWorld classWorld) {
this(command, classWorld, false); this(classWorld, false);
} }
protected ClingSupport(String command, ClassWorld classWorld, boolean classWorldManaged) { private ClingSupport(ClassWorld classWorld, boolean classWorldManaged) {
this.command = requireNonNull(command, "command");
this.classWorld = requireNonNull(classWorld); this.classWorld = requireNonNull(classWorld);
this.classWorldManaged = classWorldManaged; this.classWorldManaged = classWorldManaged;
} }
@ -75,7 +68,7 @@ public abstract class ClingSupport<O extends Options, R extends InvokerRequest<O
MessageUtils.systemInstall(); MessageUtils.systemInstall();
MessageUtils.registerShutdownHook(); MessageUtils.registerShutdownHook();
try (Invoker<R> invoker = createInvoker()) { try (Invoker<R> invoker = createInvoker()) {
return invoker.invoke(createParser().parse(command, args, createLogger(), createMessageBuilderFactory())); return invoker.invoke(parseArguments(args));
} catch (ParserException e) { } catch (ParserException e) {
System.err.println(e.getMessage()); System.err.println(e.getMessage());
return 1; return 1;
@ -94,13 +87,5 @@ public abstract class ClingSupport<O extends Options, R extends InvokerRequest<O
protected abstract Invoker<R> createInvoker(); protected abstract Invoker<R> createInvoker();
protected abstract Parser<R> createParser(); protected abstract R parseArguments(String[] args) throws ParserException, IOException;
protected Logger createLogger() {
return new ProtoLogger();
}
protected MessageBuilderFactory createMessageBuilderFactory() {
return new JLineMessageBuilderFactory();
}
} }

View File

@ -21,26 +21,26 @@ package org.apache.maven.cling;
import java.io.IOException; import java.io.IOException;
import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Invoker;
import org.apache.maven.api.cli.Parser; import org.apache.maven.api.cli.ParserException;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.cling.invoker.ProtoLogger;
import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.ProtoLookup;
import org.apache.maven.cling.invoker.mvn.local.DefaultLocalMavenInvoker; import org.apache.maven.cling.invoker.mvn.local.DefaultLocalMavenInvoker;
import org.apache.maven.cling.invoker.mvn.local.DefaultLocalMavenParser; import org.apache.maven.cling.invoker.mvn.local.DefaultLocalMavenParser;
import org.apache.maven.jline.JLineMessageBuilderFactory;
import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.ClassWorld;
/** /**
* Maven CLI "new-gen". * Maven CLI "new-gen".
*/ */
public class MavenCling extends ClingSupport<MavenOptions, MavenInvokerRequest<MavenOptions>> { public class MavenCling extends ClingSupport<MavenOptions, MavenInvokerRequest<MavenOptions>> {
public static final String NAME = "mvn";
/** /**
* "Normal" Java entry point. Note: Maven uses ClassWorld Launcher and this entry point is NOT used under normal * "Normal" Java entry point. Note: Maven uses ClassWorld Launcher and this entry point is NOT used under normal
* circumstances. * circumstances.
*/ */
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
int exitCode = new MavenCling(NAME).run(args); int exitCode = new MavenCling().run(args);
System.exit(exitCode); System.exit(exitCode);
} }
@ -48,15 +48,15 @@ public class MavenCling extends ClingSupport<MavenOptions, MavenInvokerRequest<M
* ClassWorld Launcher "enhanced" entry point: returning exitCode and accepts Class World. * ClassWorld Launcher "enhanced" entry point: returning exitCode and accepts Class World.
*/ */
public static int main(String[] args, ClassWorld world) throws IOException { public static int main(String[] args, ClassWorld world) throws IOException {
return new MavenCling(NAME, world).run(args); return new MavenCling(world).run(args);
} }
public MavenCling(String command) { public MavenCling() {
super(command); super();
} }
public MavenCling(String command, ClassWorld classWorld) { public MavenCling(ClassWorld classWorld) {
super(command, classWorld); super(classWorld);
} }
@Override @Override
@ -66,7 +66,7 @@ public class MavenCling extends ClingSupport<MavenOptions, MavenInvokerRequest<M
} }
@Override @Override
protected Parser<MavenInvokerRequest<MavenOptions>> createParser() { protected MavenInvokerRequest<MavenOptions> parseArguments(String[] args) throws ParserException, IOException {
return new DefaultLocalMavenParser(); return new DefaultLocalMavenParser().mvn(args, new ProtoLogger(), new JLineMessageBuilderFactory());
} }
} }

View File

@ -21,26 +21,27 @@ package org.apache.maven.cling;
import java.io.IOException; import java.io.IOException;
import org.apache.maven.api.cli.Invoker; import org.apache.maven.api.cli.Invoker;
import org.apache.maven.api.cli.Parser; 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.EncryptInvokerRequest;
import org.apache.maven.api.cli.mvnenc.EncryptOptions; 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.ProtoLookup;
import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker; import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker;
import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptParser; import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptParser;
import org.apache.maven.jline.JLineMessageBuilderFactory;
import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.ClassWorld;
/** /**
* Maven encrypt CLI "new-gen". * Maven encrypt CLI "new-gen".
*/ */
public class MavenEncCling extends ClingSupport<EncryptOptions, EncryptInvokerRequest> { public class MavenEncCling extends ClingSupport<EncryptOptions, EncryptInvokerRequest> {
public static final String NAME = "mvnenc";
/** /**
* "Normal" Java entry point. Note: Maven uses ClassWorld Launcher and this entry point is NOT used under normal * "Normal" Java entry point. Note: Maven uses ClassWorld Launcher and this entry point is NOT used under normal
* circumstances. * circumstances.
*/ */
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
int exitCode = new MavenEncCling(NAME).run(args); int exitCode = new MavenEncCling().run(args);
System.exit(exitCode); System.exit(exitCode);
} }
@ -48,15 +49,15 @@ public class MavenEncCling extends ClingSupport<EncryptOptions, EncryptInvokerRe
* ClassWorld Launcher "enhanced" entry point: returning exitCode and accepts Class World. * ClassWorld Launcher "enhanced" entry point: returning exitCode and accepts Class World.
*/ */
public static int main(String[] args, ClassWorld world) throws IOException { public static int main(String[] args, ClassWorld world) throws IOException {
return new MavenEncCling(NAME, world).run(args); return new MavenEncCling(world).run(args);
} }
public MavenEncCling(String command) { public MavenEncCling() {
super(command); super();
} }
public MavenEncCling(String command, ClassWorld classWorld) { public MavenEncCling(ClassWorld classWorld) {
super(command, classWorld); super(classWorld);
} }
@Override @Override
@ -66,7 +67,9 @@ public class MavenEncCling extends ClingSupport<EncryptOptions, EncryptInvokerRe
} }
@Override @Override
protected Parser<EncryptInvokerRequest> createParser() { protected EncryptInvokerRequest parseArguments(String[] args) throws ParserException, IOException {
return new DefaultEncryptParser(); return new DefaultEncryptParser()
.parse(ParserRequest.mvnenc(args, new ProtoLogger(), new JLineMessageBuilderFactory())
.build());
} }
} }

View File

@ -28,22 +28,19 @@ import java.util.Optional;
import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.cli.InvokerRequest; 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.Options;
import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.extensions.CoreExtension; import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.services.MessageBuilderFactory;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
public abstract class BaseInvokerRequest<T extends Options> implements InvokerRequest<T> { public abstract class BaseInvokerRequest<T extends Options> implements InvokerRequest<T> {
private final String command; private final ParserRequest parserRequest;
private final Path cwd; private final Path cwd;
private final Path installationDirectory; private final Path installationDirectory;
private final Path userHomeDirectory; private final Path userHomeDirectory;
private final Map<String, String> userProperties; private final Map<String, String> userProperties;
private final Map<String, String> systemProperties; private final Map<String, String> systemProperties;
private final Logger logger;
private final MessageBuilderFactory messageBuilderFactory;
private final Path topDirectory; private final Path topDirectory;
private final Path rootDirectory; private final Path rootDirectory;
@ -54,28 +51,24 @@ public abstract class BaseInvokerRequest<T extends Options> implements InvokerRe
@SuppressWarnings("ParameterNumber") @SuppressWarnings("ParameterNumber")
public BaseInvokerRequest( public BaseInvokerRequest(
@Nonnull String command, @Nonnull ParserRequest parserRequest,
@Nonnull Path cwd, @Nonnull Path cwd,
@Nonnull Path installationDirectory, @Nonnull Path installationDirectory,
@Nonnull Path userHomeDirectory, @Nonnull Path userHomeDirectory,
@Nonnull Map<String, String> userProperties, @Nonnull Map<String, String> userProperties,
@Nonnull Map<String, String> systemProperties, @Nonnull Map<String, String> systemProperties,
@Nonnull Logger logger,
@Nonnull MessageBuilderFactory messageBuilderFactory,
@Nonnull Path topDirectory, @Nonnull Path topDirectory,
@Nullable Path rootDirectory, @Nullable Path rootDirectory,
@Nullable InputStream in, @Nullable InputStream in,
@Nullable OutputStream out, @Nullable OutputStream out,
@Nullable OutputStream err, @Nullable OutputStream err,
@Nullable List<CoreExtension> coreExtensions) { @Nullable List<CoreExtension> coreExtensions) {
this.command = requireNonNull(command); this.parserRequest = requireNonNull(parserRequest);
this.cwd = requireNonNull(cwd); this.cwd = requireNonNull(cwd);
this.installationDirectory = requireNonNull(installationDirectory); this.installationDirectory = requireNonNull(installationDirectory);
this.userHomeDirectory = requireNonNull(userHomeDirectory); this.userHomeDirectory = requireNonNull(userHomeDirectory);
this.userProperties = requireNonNull(userProperties); this.userProperties = requireNonNull(userProperties);
this.systemProperties = requireNonNull(systemProperties); this.systemProperties = requireNonNull(systemProperties);
this.logger = requireNonNull(logger);
this.messageBuilderFactory = requireNonNull(messageBuilderFactory);
this.topDirectory = requireNonNull(topDirectory); this.topDirectory = requireNonNull(topDirectory);
this.rootDirectory = rootDirectory; this.rootDirectory = rootDirectory;
@ -86,8 +79,8 @@ public abstract class BaseInvokerRequest<T extends Options> implements InvokerRe
} }
@Override @Override
public String command() { public ParserRequest parserRequest() {
return command; return parserRequest;
} }
@Override @Override
@ -115,16 +108,6 @@ public abstract class BaseInvokerRequest<T extends Options> implements InvokerRe
return systemProperties; return systemProperties;
} }
@Override
public Logger logger() {
return logger;
}
@Override
public MessageBuilderFactory messageBuilderFactory() {
return messageBuilderFactory;
}
@Override @Override
public Path topDirectory() { public Path topDirectory() {
return topDirectory; return topDirectory;

View File

@ -23,10 +23,9 @@ import javax.xml.stream.XMLStreamException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -39,7 +38,6 @@ import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import org.apache.maven.api.Constants; import org.apache.maven.api.Constants;
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.InvokerRequest;
import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.Parser; import org.apache.maven.api.cli.Parser;
@ -69,41 +67,20 @@ public abstract class BaseParser<O extends Options, R extends InvokerRequest<O>>
// the basics // the basics
HashMap<String, String> overrides = new HashMap<>(); HashMap<String, String> overrides = new HashMap<>();
FileSystem fileSystem = requireNonNull(getFileSystem(parserRequest)); Path cwd = requireNonNull(getCwd(parserRequest, overrides));
Path cwd = requireNonNull(getCwd(parserRequest, fileSystem, overrides)); Path installationDirectory = requireNonNull(getInstallationDirectory(parserRequest, overrides));
Path installationDirectory = requireNonNull(getInstallationDirectory(parserRequest, fileSystem, overrides)); Path userHomeDirectory = requireNonNull(getUserHomeDirectory(parserRequest, overrides));
Path userHomeDirectory = requireNonNull(getUserHomeDirectory(parserRequest, fileSystem, overrides));
// top/root // top/root
Path topDirectory = getCanonicalPath(requireNonNull(getTopDirectory(parserRequest, cwd))); Path topDirectory = requireNonNull(getTopDirectory(parserRequest, cwd));
RootLocator rootLocator = Path rootDirectory = requireNonNull(getRootDirectory(parserRequest, cwd, topDirectory));
ServiceLoader.load(RootLocator.class).iterator().next();
@Nullable Path rootDirectory = rootLocator.findRoot(topDirectory);
// TODO: multiModuleProjectDirectory vs rootDirectory?
// fallback if no root? otherwise make sure they are same?
Path mmpd = System.getProperty("maven.multiModuleProjectDirectory") == null
? null
: getCanonicalPath(cwd.resolve(requireNonNull(
System.getProperty("maven.multiModuleProjectDirectory"),
"maven.multiModuleProjectDirectory is not set")));
if (rootDirectory == null) {
parserRequest.logger().warn(rootLocator.getNoRootMessage());
rootDirectory = requireNonNull(
mmpd, "maven.multiModuleProjectDirectory is not set and rootDirectory was not discovered");
} else {
rootDirectory = getCanonicalPath(rootDirectory);
if (mmpd != null && !Objects.equals(rootDirectory, mmpd)) {
parserRequest.logger().warn("Project root directory and multiModuleProjectDirectory are not aligned");
}
}
// options // options
List<O> parsedOptions = parseCliOptions(rootDirectory, parserRequest.args()); List<O> parsedOptions = parseCliOptions(rootDirectory, parserRequest.args());
// warn about deprecated options // warn about deprecated options
parsedOptions.forEach(o -> o.warnAboutDeprecatedOptions( parsedOptions.forEach(o -> o.warnAboutDeprecatedOptions(
new PrintWriter(parserRequest.out() != null ? parserRequest.out() : System.out, true))); parserRequest, new PrintWriter(parserRequest.out() != null ? parserRequest.out() : System.out, true)));
// assemble options if needed // assemble options if needed
O options = assembleOptions(parsedOptions); O options = assembleOptions(parsedOptions);
@ -113,7 +90,8 @@ public abstract class BaseParser<O extends Options, R extends InvokerRequest<O>>
Map<String, String> paths = new HashMap<>(); Map<String, String> paths = new HashMap<>();
paths.put("session.topDirectory", topDirectory.toString()); paths.put("session.topDirectory", topDirectory.toString());
paths.put("session.rootDirectory", rootDirectory.toString()); paths.put("session.rootDirectory", rootDirectory.toString());
Map<String, String> userProperties = populateUserProperties(systemProperties, fileSystem, paths, options); Map<String, String> userProperties =
populateUserProperties(systemProperties, installationDirectory, paths, options);
// options: interpolate // options: interpolate
Options interpolatedOptions = options.interpolate(Arrays.asList(paths, systemProperties, userProperties)); Options interpolatedOptions = options.interpolate(Arrays.asList(paths, systemProperties, userProperties));
@ -121,13 +99,13 @@ public abstract class BaseParser<O extends Options, R extends InvokerRequest<O>>
// core extensions // core extensions
ArrayList<CoreExtension> extensions = new ArrayList<>(); ArrayList<CoreExtension> extensions = new ArrayList<>();
String installationExtensionsFile = userProperties.get(Constants.MAVEN_INSTALLATION_EXTENSIONS); String installationExtensionsFile = userProperties.get(Constants.MAVEN_INSTALLATION_EXTENSIONS);
extensions.addAll(readCoreExtensionsDescriptor(installationExtensionsFile, fileSystem)); extensions.addAll(readCoreExtensionsDescriptor(installationExtensionsFile, installationDirectory));
String projectExtensionsFile = userProperties.get(Constants.MAVEN_PROJECT_EXTENSIONS); String projectExtensionsFile = userProperties.get(Constants.MAVEN_PROJECT_EXTENSIONS);
extensions.addAll(readCoreExtensionsDescriptor(projectExtensionsFile, fileSystem)); extensions.addAll(readCoreExtensionsDescriptor(projectExtensionsFile, cwd));
String userExtensionsFile = userProperties.get(Constants.MAVEN_USER_EXTENSIONS); String userExtensionsFile = userProperties.get(Constants.MAVEN_USER_EXTENSIONS);
extensions.addAll(readCoreExtensionsDescriptor(userExtensionsFile, fileSystem)); extensions.addAll(readCoreExtensionsDescriptor(userExtensionsFile, userHomeDirectory));
return getInvokerRequest( return getInvokerRequest(
parserRequest, parserRequest,
@ -155,23 +133,18 @@ public abstract class BaseParser<O extends Options, R extends InvokerRequest<O>>
ArrayList<CoreExtension> extensions, ArrayList<CoreExtension> extensions,
Options options); Options options);
protected FileSystem getFileSystem(ParserRequest parserRequest) throws ParserException, IOException { protected Path getCwd(ParserRequest parserRequest, Map<String, String> overrides) throws ParserException {
return parserRequest.cwd() != null ? parserRequest.cwd().getFileSystem() : FileSystems.getDefault();
}
protected Path getCwd(ParserRequest parserRequest, FileSystem fileSystem, Map<String, String> overrides)
throws ParserException {
if (parserRequest.cwd() != null) { if (parserRequest.cwd() != null) {
Path result = getCanonicalPath(parserRequest.cwd()); Path result = getCanonicalPath(parserRequest.cwd());
overrides.put("user.dir", result.toString()); overrides.put("user.dir", result.toString());
return result; return result;
} else { } else {
return getCanonicalPath(fileSystem.getPath(System.getProperty("user.dir"))); return getCanonicalPath(Paths.get(System.getProperty("user.dir")));
} }
} }
protected Path getInstallationDirectory( protected Path getInstallationDirectory(ParserRequest parserRequest, Map<String, String> overrides)
ParserRequest parserRequest, FileSystem fileSystem, Map<String, String> overrides) throws ParserException { throws ParserException {
Path result; Path result;
if (parserRequest.mavenHome() != null) { if (parserRequest.mavenHome() != null) {
result = getCanonicalPath(parserRequest.mavenHome()); result = getCanonicalPath(parserRequest.mavenHome());
@ -181,21 +154,21 @@ public abstract class BaseParser<O extends Options, R extends InvokerRequest<O>>
if (mavenHome == null) { if (mavenHome == null) {
throw new ParserException("local mode requires " + Constants.MAVEN_HOME + " Java System Property set"); throw new ParserException("local mode requires " + Constants.MAVEN_HOME + " Java System Property set");
} }
result = getCanonicalPath(fileSystem.getPath(mavenHome)); result = getCanonicalPath(Paths.get(mavenHome));
} }
// TODO: we still do this but would be cool if this becomes unneeded // TODO: we still do this but would be cool if this becomes unneeded
System.setProperty(Constants.MAVEN_HOME, result.toString()); System.setProperty(Constants.MAVEN_HOME, result.toString());
return result; return result;
} }
protected Path getUserHomeDirectory( protected Path getUserHomeDirectory(ParserRequest parserRequest, Map<String, String> overrides)
ParserRequest parserRequest, FileSystem fileSystem, Map<String, String> overrides) throws ParserException { throws ParserException {
if (parserRequest.userHome() != null) { if (parserRequest.userHome() != null) {
Path result = getCanonicalPath(parserRequest.userHome()); Path result = getCanonicalPath(parserRequest.userHome());
overrides.put("user.home", result.toString()); overrides.put("user.home", result.toString());
return result; return result;
} else { } else {
return getCanonicalPath(fileSystem.getPath(System.getProperty("user.home"))); return getCanonicalPath(Paths.get(System.getProperty("user.home")));
} }
} }
@ -226,7 +199,32 @@ public abstract class BaseParser<O extends Options, R extends InvokerRequest<O>>
isAltFile = arg.equals("-f") || arg.equals("--file"); isAltFile = arg.equals("-f") || arg.equals("--file");
} }
} }
return topDirectory; return getCanonicalPath(topDirectory);
}
protected Path getRootDirectory(ParserRequest parserRequest, Path cwd, Path topDirectory) throws ParserException {
RootLocator rootLocator =
ServiceLoader.load(RootLocator.class).iterator().next();
Path rootDirectory = rootLocator.findRoot(topDirectory);
// TODO: multiModuleProjectDirectory vs rootDirectory?
// fallback if no root? otherwise make sure they are same?
Path mmpd = System.getProperty("maven.multiModuleProjectDirectory") == null
? null
: getCanonicalPath(cwd.resolve(requireNonNull(
System.getProperty("maven.multiModuleProjectDirectory"),
"maven.multiModuleProjectDirectory is not set")));
if (rootDirectory == null) {
parserRequest.logger().warn(rootLocator.getNoRootMessage());
rootDirectory = requireNonNull(
mmpd, "maven.multiModuleProjectDirectory is not set and rootDirectory was not discovered");
} else {
rootDirectory = getCanonicalPath(rootDirectory);
if (mmpd != null && !Objects.equals(rootDirectory, mmpd)) {
parserRequest.logger().warn("Project root directory and multiModuleProjectDirectory are not aligned");
}
}
return getCanonicalPath(rootDirectory);
} }
protected Map<String, String> populateSystemProperties(Map<String, String> overrides) throws ParserException { protected Map<String, String> populateSystemProperties(Map<String, String> overrides) throws ParserException {
@ -260,7 +258,10 @@ public abstract class BaseParser<O extends Options, R extends InvokerRequest<O>>
} }
protected Map<String, String> populateUserProperties( protected Map<String, String> populateUserProperties(
Map<String, String> systemProperties, FileSystem fileSystem, Map<String, String> paths, Options options) Map<String, String> systemProperties,
Path installationDirectory,
Map<String, String> paths,
Options options)
throws ParserException, IOException { throws ParserException, IOException {
Properties userProperties = new Properties(); Properties userProperties = new Properties();
@ -281,13 +282,15 @@ public abstract class BaseParser<O extends Options, R extends InvokerRequest<O>>
Path mavenConf; Path mavenConf;
if (systemProperties.get(MAVEN_INSTALLATION_CONF) != null) { if (systemProperties.get(MAVEN_INSTALLATION_CONF) != null) {
mavenConf = fileSystem.getPath(systemProperties.get(MAVEN_INSTALLATION_CONF)); mavenConf = installationDirectory.resolve(systemProperties.get(MAVEN_INSTALLATION_CONF));
} else if (systemProperties.get("maven.conf") != null) { } else if (systemProperties.get("maven.conf") != null) {
mavenConf = fileSystem.getPath(systemProperties.get("maven.conf")); mavenConf = installationDirectory.resolve(systemProperties.get("maven.conf"));
} else if (systemProperties.get(MAVEN_HOME) != null) { } else if (systemProperties.get(MAVEN_HOME) != null) {
mavenConf = fileSystem.getPath(systemProperties.get(MAVEN_HOME), "conf"); mavenConf = installationDirectory
.resolve(systemProperties.get(MAVEN_HOME))
.resolve("conf");
} else { } else {
mavenConf = fileSystem.getPath(""); mavenConf = installationDirectory.resolve("");
} }
Path propertiesFile = mavenConf.resolve("maven.properties"); Path propertiesFile = mavenConf.resolve("maven.properties");
MavenPropertiesLoader.loadProperties(userProperties, propertiesFile, callback, false); MavenPropertiesLoader.loadProperties(userProperties, propertiesFile, callback, false);
@ -304,15 +307,16 @@ public abstract class BaseParser<O extends Options, R extends InvokerRequest<O>>
return toMap(userProperties); return toMap(userProperties);
} }
protected abstract List<O> parseCliOptions(Path rootDirectory, String[] args) throws ParserException, IOException; protected abstract List<O> parseCliOptions(Path rootDirectory, List<String> args)
throws ParserException, IOException;
protected abstract O assembleOptions(List<O> parsedOptions); protected abstract O assembleOptions(List<O> parsedOptions);
protected List<CoreExtension> readCoreExtensionsDescriptor(String extensionsFile, FileSystem fileSystem) protected List<CoreExtension> readCoreExtensionsDescriptor(String extensionsFile, Path cwd)
throws ParserException, IOException { throws ParserException, IOException {
try { try {
if (extensionsFile != null) { if (extensionsFile != null) {
Path extensionsPath = fileSystem.getPath(extensionsFile); Path extensionsPath = cwd.resolve(extensionsFile);
if (Files.exists(extensionsPath)) { if (Files.exists(extensionsPath)) {
try (InputStream is = Files.newInputStream(extensionsPath)) { try (InputStream is = Files.newInputStream(extensionsPath)) {
return new CoreExtensionsStaxReader().read(is, true).getExtensions(); return new CoreExtensionsStaxReader().read(is, true).getExtensions();

View File

@ -31,6 +31,7 @@ import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option; import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.cli.CleanArgument; import org.apache.maven.cli.CleanArgument;
import org.apache.maven.jline.MessageUtils; import org.apache.maven.jline.MessageUtils;
@ -201,7 +202,7 @@ public abstract class CommonsCliOptions implements Options {
} }
@Override @Override
public void warnAboutDeprecatedOptions(PrintWriter printWriter) { public void warnAboutDeprecatedOptions(ParserRequest request, PrintWriter printWriter) {
if (cliManager.getUsedDeprecatedOptions().isEmpty()) { if (cliManager.getUsedDeprecatedOptions().isEmpty()) {
return; return;
} }
@ -217,15 +218,18 @@ public abstract class CommonsCliOptions implements Options {
sb.append("and will be removed in a future version"); sb.append("and will be removed in a future version");
} }
if (option.getDeprecated().getSince() != null) { if (option.getDeprecated().getSince() != null) {
sb.append("since Maven ").append(option.getDeprecated().getSince()); sb.append("since ")
.append(request.commandName())
.append(" ")
.append(option.getDeprecated().getSince());
} }
printWriter.println(sb); printWriter.println(sb);
} }
} }
@Override @Override
public void displayHelp(String command, PrintWriter printStream) { public void displayHelp(ParserRequest request, PrintWriter printStream) {
cliManager.displayHelp(command, printStream); cliManager.displayHelp(request.command(), printStream);
} }
protected static class CLIManager { protected static class CLIManager {

View File

@ -27,6 +27,7 @@ import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import org.apache.maven.api.cli.Options; import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.ParserRequest;
/** /**
* Options that are "layered" by precedence order. * Options that are "layered" by precedence order.
@ -132,11 +133,11 @@ public abstract class LayeredOptions<O extends Options> implements Options {
} }
@Override @Override
public void warnAboutDeprecatedOptions(PrintWriter printWriter) {} public void warnAboutDeprecatedOptions(ParserRequest request, PrintWriter printWriter) {}
@Override @Override
public void displayHelp(String command, PrintWriter printWriter) { public void displayHelp(ParserRequest request, PrintWriter printWriter) {
options.get(0).displayHelp(command, printWriter); options.get(0).displayHelp(request, printWriter);
} }
protected <T> Optional<T> returnFirstPresentOrEmpty(Function<O, Optional<T>> getter) { protected <T> Optional<T> returnFirstPresentOrEmpty(Function<O, Optional<T>> getter) {

View File

@ -95,6 +95,8 @@ public abstract class LookupInvoker<
public final ProtoLookup protoLookup; public final ProtoLookup protoLookup;
public final R invokerRequest; public final R invokerRequest;
public final Function<String, Path> cwdResolver; public final Function<String, Path> cwdResolver;
public final Function<String, Path> installationResolver;
public final Function<String, Path> userResolver;
public final InputStream stdIn; public final InputStream stdIn;
public final PrintWriter stdOut; public final PrintWriter stdOut;
public final PrintWriter stdErr; public final PrintWriter stdErr;
@ -104,10 +106,17 @@ public abstract class LookupInvoker<
this.protoLookup = invoker.protoLookup; this.protoLookup = invoker.protoLookup;
this.invokerRequest = requireNonNull(invokerRequest); this.invokerRequest = requireNonNull(invokerRequest);
this.cwdResolver = s -> invokerRequest.cwd().resolve(s).normalize().toAbsolutePath(); 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.stdIn = invokerRequest.in().orElse(System.in); this.stdIn = invokerRequest.in().orElse(System.in);
this.stdOut = new PrintWriter(invokerRequest.out().orElse(System.out), true); this.stdOut = new PrintWriter(invokerRequest.out().orElse(System.out), true);
this.stdErr = new PrintWriter(invokerRequest.err().orElse(System.err), true); this.stdErr = new PrintWriter(invokerRequest.err().orElse(System.err), true);
this.logger = invokerRequest.logger(); this.logger = invokerRequest.parserRequest().logger();
} }
public Logger logger; public Logger logger;
@ -149,7 +158,7 @@ public abstract class LookupInvoker<
logging(context); logging(context);
if (invokerRequest.options().help().isPresent()) { if (invokerRequest.options().help().isPresent()) {
invokerRequest.options().displayHelp(context.invokerRequest.command(), context.stdOut); invokerRequest.options().displayHelp(context.invokerRequest.parserRequest(), context.stdOut);
return 0; return 0;
} }
if (invokerRequest.options().showVersionAndExit().isPresent()) { if (invokerRequest.options().showVersionAndExit().isPresent()) {
@ -178,9 +187,11 @@ public abstract class LookupInvoker<
throws InvokerException { throws InvokerException {
boolean showStackTrace = context.invokerRequest.options().showErrors().orElse(false); boolean showStackTrace = context.invokerRequest.options().showErrors().orElse(false);
if (showStackTrace) { if (showStackTrace) {
context.logger.error("Error executing Maven.", e); context.logger.error(
"Error executing " + context.invokerRequest.parserRequest().commandName() + ".", e);
} else { } else {
context.logger.error("Error executing Maven."); context.logger.error(
"Error executing " + context.invokerRequest.parserRequest().commandName() + ".");
context.logger.error(e.getMessage()); context.logger.error(e.getMessage());
for (Throwable cause = e.getCause(); cause != null && cause != cause.getCause(); cause = cause.getCause()) { for (Throwable cause = e.getCause(); cause != null && cause != cause.getCause(); cause = cause.getCause()) {
context.logger.error("Caused by: " + cause.getMessage()); context.logger.error("Caused by: " + cause.getMessage());
@ -338,7 +349,7 @@ public abstract class LookupInvoker<
} else { } else {
String userSettingsFileStr = context.invokerRequest.userProperties().get(Constants.MAVEN_USER_SETTINGS); String userSettingsFileStr = context.invokerRequest.userProperties().get(Constants.MAVEN_USER_SETTINGS);
if (userSettingsFileStr != null) { if (userSettingsFileStr != null) {
userSettingsFile = context.cwdResolver.apply(userSettingsFileStr); userSettingsFile = context.userResolver.apply(userSettingsFileStr);
} }
} }
@ -374,7 +385,7 @@ public abstract class LookupInvoker<
String installationSettingsFileStr = String installationSettingsFileStr =
context.invokerRequest.userProperties().get(Constants.MAVEN_INSTALLATION_SETTINGS); context.invokerRequest.userProperties().get(Constants.MAVEN_INSTALLATION_SETTINGS);
if (installationSettingsFileStr != null) { if (installationSettingsFileStr != null) {
installationSettingsFile = context.cwdResolver.apply(installationSettingsFileStr); installationSettingsFile = context.installationResolver.apply(installationSettingsFileStr);
} }
} }
@ -463,18 +474,18 @@ public abstract class LookupInvoker<
+ "usually located at ${session.rootDirectory}/.mvn/maven.properties."); + "usually located at ${session.rootDirectory}/.mvn/maven.properties.");
} }
} }
if (userDefinedLocalRepo != null) {
return context.cwdResolver.apply(userDefinedLocalRepo);
}
// settings // settings
if (userDefinedLocalRepo == null) {
userDefinedLocalRepo = context.effectiveSettings.getLocalRepository(); userDefinedLocalRepo = context.effectiveSettings.getLocalRepository();
if (userDefinedLocalRepo != null) {
return context.userResolver.apply(userDefinedLocalRepo);
} }
// defaults // defaults
if (userDefinedLocalRepo == null) { return context.userResolver
userDefinedLocalRepo = context.cwdResolver
.apply(context.invokerRequest.userProperties().get(Constants.MAVEN_USER_CONF)) .apply(context.invokerRequest.userProperties().get(Constants.MAVEN_USER_CONF))
.resolve("repository") .resolve("repository");
.toString();
}
return context.cwdResolver.apply(userDefinedLocalRepo);
} }
protected void populateRequest(C context, MavenExecutionRequest request) throws Exception { protected void populateRequest(C context, MavenExecutionRequest request) throws Exception {

View File

@ -105,7 +105,7 @@ public abstract class DefaultMavenInvoker<
} }
@Override @Override
protected void prepare(C localContext) throws Exception { protected void prepare(C context) throws Exception {
// explicitly fill in "defaults"? // explicitly fill in "defaults"?
DefaultMavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest(); DefaultMavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest();
mavenExecutionRequest.setRepositoryCache(new DefaultRepositoryCache()); mavenExecutionRequest.setRepositoryCache(new DefaultRepositoryCache());
@ -120,7 +120,7 @@ public abstract class DefaultMavenInvoker<
mavenExecutionRequest.setDegreeOfConcurrency(1); mavenExecutionRequest.setDegreeOfConcurrency(1);
mavenExecutionRequest.setBuilderId("singlethreaded"); mavenExecutionRequest.setBuilderId("singlethreaded");
localContext.mavenExecutionRequest = mavenExecutionRequest; context.mavenExecutionRequest = mavenExecutionRequest;
} }
@Override @Override
@ -146,11 +146,11 @@ public abstract class DefaultMavenInvoker<
} }
@Override @Override
protected void postCommands(C localContext) throws Exception { protected void postCommands(C context) throws Exception {
super.postCommands(localContext); super.postCommands(context);
R invokerRequest = localContext.invokerRequest; R invokerRequest = context.invokerRequest;
Logger logger = localContext.logger; Logger logger = context.logger;
if (invokerRequest.options().relaxedChecksums().orElse(false)) { if (invokerRequest.options().relaxedChecksums().orElse(false)) {
logger.info("Disabling strict checksum verification on all artifact downloads."); logger.info("Disabling strict checksum verification on all artifact downloads.");
} else if (invokerRequest.options().strictChecksums().orElse(false)) { } else if (invokerRequest.options().strictChecksums().orElse(false)) {
@ -172,12 +172,12 @@ public abstract class DefaultMavenInvoker<
} }
} }
protected void toolchains(C localContext) throws Exception { protected void toolchains(C context) throws Exception {
Path userToolchainsFile = null; Path userToolchainsFile = null;
if (localContext.invokerRequest.options().altUserToolchains().isPresent()) { if (context.invokerRequest.options().altUserToolchains().isPresent()) {
userToolchainsFile = localContext.cwdResolver.apply( userToolchainsFile = context.cwdResolver.apply(
localContext.invokerRequest.options().altUserToolchains().get()); context.invokerRequest.options().altUserToolchains().get());
if (!Files.isRegularFile(userToolchainsFile)) { if (!Files.isRegularFile(userToolchainsFile)) {
throw new FileNotFoundException( throw new FileNotFoundException(
@ -185,20 +185,17 @@ public abstract class DefaultMavenInvoker<
} }
} else { } else {
String userToolchainsFileStr = String userToolchainsFileStr =
localContext.invokerRequest.userProperties().get(Constants.MAVEN_USER_TOOLCHAINS); context.invokerRequest.userProperties().get(Constants.MAVEN_USER_TOOLCHAINS);
if (userToolchainsFileStr != null) { if (userToolchainsFileStr != null) {
userToolchainsFile = localContext.cwdResolver.apply(userToolchainsFileStr); userToolchainsFile = context.cwdResolver.apply(userToolchainsFileStr);
} }
} }
Path installationToolchainsFile = null; Path installationToolchainsFile = null;
if (localContext.invokerRequest.options().altInstallationToolchains().isPresent()) { if (context.invokerRequest.options().altInstallationToolchains().isPresent()) {
installationToolchainsFile = localContext.cwdResolver.apply(localContext installationToolchainsFile = context.cwdResolver.apply(
.invokerRequest context.invokerRequest.options().altInstallationToolchains().get());
.options()
.altInstallationToolchains()
.get());
if (!Files.isRegularFile(installationToolchainsFile)) { if (!Files.isRegularFile(installationToolchainsFile)) {
throw new FileNotFoundException( throw new FileNotFoundException(
@ -206,15 +203,15 @@ public abstract class DefaultMavenInvoker<
} }
} else { } else {
String installationToolchainsFileStr = String installationToolchainsFileStr =
localContext.invokerRequest.userProperties().get(Constants.MAVEN_INSTALLATION_TOOLCHAINS); context.invokerRequest.userProperties().get(Constants.MAVEN_INSTALLATION_TOOLCHAINS);
if (installationToolchainsFileStr != null) { if (installationToolchainsFileStr != null) {
installationToolchainsFile = localContext.cwdResolver.apply(installationToolchainsFileStr); installationToolchainsFile = context.cwdResolver.apply(installationToolchainsFileStr);
} }
} }
localContext.mavenExecutionRequest.setInstallationToolchainsFile( context.mavenExecutionRequest.setInstallationToolchainsFile(
installationToolchainsFile != null ? installationToolchainsFile.toFile() : null); installationToolchainsFile != null ? installationToolchainsFile.toFile() : null);
localContext.mavenExecutionRequest.setUserToolchainsFile( context.mavenExecutionRequest.setUserToolchainsFile(
userToolchainsFile != null ? userToolchainsFile.toFile() : null); userToolchainsFile != null ? userToolchainsFile.toFile() : null);
DefaultToolchainsBuildingRequest toolchainsRequest = new DefaultToolchainsBuildingRequest(); DefaultToolchainsBuildingRequest toolchainsRequest = new DefaultToolchainsBuildingRequest();
@ -225,35 +222,35 @@ public abstract class DefaultMavenInvoker<
toolchainsRequest.setUserToolchainsSource(new FileSource(userToolchainsFile)); toolchainsRequest.setUserToolchainsSource(new FileSource(userToolchainsFile));
} }
localContext.eventSpyDispatcher.onEvent(toolchainsRequest); context.eventSpyDispatcher.onEvent(toolchainsRequest);
localContext.logger.debug("Reading installation toolchains from '" context.logger.debug("Reading installation toolchains from '"
+ (toolchainsRequest.getGlobalToolchainsSource() != null + (toolchainsRequest.getGlobalToolchainsSource() != null
? toolchainsRequest.getGlobalToolchainsSource().getLocation() ? toolchainsRequest.getGlobalToolchainsSource().getLocation()
: installationToolchainsFile) : installationToolchainsFile)
+ "'"); + "'");
localContext.logger.debug("Reading user toolchains from '" context.logger.debug("Reading user toolchains from '"
+ (toolchainsRequest.getUserToolchainsSource() != null + (toolchainsRequest.getUserToolchainsSource() != null
? toolchainsRequest.getUserToolchainsSource().getLocation() ? toolchainsRequest.getUserToolchainsSource().getLocation()
: userToolchainsFile) : userToolchainsFile)
+ "'"); + "'");
ToolchainsBuildingResult toolchainsResult = localContext.toolchainsBuilder.build(toolchainsRequest); ToolchainsBuildingResult toolchainsResult = context.toolchainsBuilder.build(toolchainsRequest);
localContext.eventSpyDispatcher.onEvent(toolchainsResult); context.eventSpyDispatcher.onEvent(toolchainsResult);
localContext.mavenExecutionRequestPopulator.populateFromToolchains( context.mavenExecutionRequestPopulator.populateFromToolchains(
localContext.mavenExecutionRequest, toolchainsResult.getEffectiveToolchains()); context.mavenExecutionRequest, toolchainsResult.getEffectiveToolchains());
if (!toolchainsResult.getProblems().isEmpty()) { if (!toolchainsResult.getProblems().isEmpty()) {
localContext.logger.warn(""); context.logger.warn("");
localContext.logger.warn("Some problems were encountered while building the effective toolchains"); context.logger.warn("Some problems were encountered while building the effective toolchains");
for (Problem problem : toolchainsResult.getProblems()) { for (Problem problem : toolchainsResult.getProblems()) {
localContext.logger.warn(problem.getMessage() + " @ " + problem.getLocation()); context.logger.warn(problem.getMessage() + " @ " + problem.getLocation());
} }
localContext.logger.warn(""); context.logger.warn("");
} }
} }
@ -325,21 +322,21 @@ public abstract class DefaultMavenInvoker<
} }
} }
protected Path determinePom(C localContext) { protected Path determinePom(C context) {
Path current = localContext.invokerRequest.cwd(); Path current = context.invokerRequest.cwd();
if (localContext.invokerRequest.options().alternatePomFile().isPresent()) { if (context.invokerRequest.options().alternatePomFile().isPresent()) {
current = localContext.cwdResolver.apply( current = context.cwdResolver.apply(
localContext.invokerRequest.options().alternatePomFile().get()); context.invokerRequest.options().alternatePomFile().get());
} }
if (localContext.modelProcessor != null) { if (context.modelProcessor != null) {
return localContext.modelProcessor.locateExistingPom(current); return context.modelProcessor.locateExistingPom(current);
} else { } else {
return Files.isRegularFile(current) ? current : null; return Files.isRegularFile(current) ? current : null;
} }
} }
protected String determineReactorFailureBehaviour(C localContext) { protected String determineReactorFailureBehaviour(C context) {
MavenOptions mavenOptions = localContext.invokerRequest.options(); MavenOptions mavenOptions = context.invokerRequest.options();
if (mavenOptions.failFast().isPresent()) { if (mavenOptions.failFast().isPresent()) {
return MavenExecutionRequest.REACTOR_FAIL_FAST; return MavenExecutionRequest.REACTOR_FAIL_FAST;
} else if (mavenOptions.failAtEnd().isPresent()) { } else if (mavenOptions.failAtEnd().isPresent()) {
@ -351,8 +348,8 @@ public abstract class DefaultMavenInvoker<
} }
} }
protected String determineGlobalChecksumPolicy(C localContext) { protected String determineGlobalChecksumPolicy(C context) {
MavenOptions mavenOptions = localContext.invokerRequest.options(); MavenOptions mavenOptions = context.invokerRequest.options();
if (mavenOptions.strictChecksums().orElse(false)) { if (mavenOptions.strictChecksums().orElse(false)) {
return MavenExecutionRequest.CHECKSUM_POLICY_FAIL; return MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
} else if (mavenOptions.relaxedChecksums().orElse(false)) { } else if (mavenOptions.relaxedChecksums().orElse(false)) {
@ -362,18 +359,17 @@ public abstract class DefaultMavenInvoker<
} }
} }
protected ExecutionListener determineExecutionListener(C localContext) { protected ExecutionListener determineExecutionListener(C context) {
ExecutionListener executionListener = ExecutionListener executionListener = new ExecutionEventLogger(context.invokerRequest.messageBuilderFactory());
new ExecutionEventLogger(localContext.invokerRequest.messageBuilderFactory()); if (context.eventSpyDispatcher != null) {
if (localContext.eventSpyDispatcher != null) { return context.eventSpyDispatcher.chainListener(executionListener);
return localContext.eventSpyDispatcher.chainListener(executionListener);
} else { } else {
return executionListener; return executionListener;
} }
} }
protected String determineMakeBehavior(C localContext) { protected String determineMakeBehavior(C context) {
MavenOptions mavenOptions = localContext.invokerRequest.options(); MavenOptions mavenOptions = context.invokerRequest.options();
if (mavenOptions.alsoMake().isPresent() if (mavenOptions.alsoMake().isPresent()
&& mavenOptions.alsoMakeDependents().isEmpty()) { && mavenOptions.alsoMakeDependents().isEmpty()) {
return MavenExecutionRequest.REACTOR_MAKE_UPSTREAM; return MavenExecutionRequest.REACTOR_MAKE_UPSTREAM;
@ -388,8 +384,8 @@ public abstract class DefaultMavenInvoker<
} }
} }
protected void performProjectActivation(C localContext, ProjectActivation projectActivation) { protected void performProjectActivation(C context, ProjectActivation projectActivation) {
MavenOptions mavenOptions = localContext.invokerRequest.options(); MavenOptions mavenOptions = context.invokerRequest.options();
if (mavenOptions.projects().isPresent() if (mavenOptions.projects().isPresent()
&& !mavenOptions.projects().get().isEmpty()) { && !mavenOptions.projects().get().isEmpty()) {
List<String> optionValues = mavenOptions.projects().get(); List<String> optionValues = mavenOptions.projects().get();
@ -416,8 +412,8 @@ public abstract class DefaultMavenInvoker<
} }
} }
protected void performProfileActivation(C localContext, ProfileActivation profileActivation) { protected void performProfileActivation(C context, ProfileActivation profileActivation) {
MavenOptions mavenOptions = localContext.invokerRequest.options(); MavenOptions mavenOptions = context.invokerRequest.options();
if (mavenOptions.activatedProfiles().isPresent() if (mavenOptions.activatedProfiles().isPresent()
&& !mavenOptions.activatedProfiles().get().isEmpty()) { && !mavenOptions.activatedProfiles().get().isEmpty()) {
List<String> optionValues = mavenOptions.activatedProfiles().get(); List<String> optionValues = mavenOptions.activatedProfiles().get();
@ -444,62 +440,61 @@ public abstract class DefaultMavenInvoker<
} }
} }
protected int doExecute(C localContext) throws Exception { protected int doExecute(C context) throws Exception {
MavenExecutionRequest request = localContext.mavenExecutionRequest; MavenExecutionRequest request = context.mavenExecutionRequest;
// why? No way to disable caching? // why? No way to disable caching?
if (localContext.mavenExecutionRequest.getRepositoryCache() == null) { if (context.mavenExecutionRequest.getRepositoryCache() == null) {
localContext.mavenExecutionRequest.setRepositoryCache(new DefaultRepositoryCache()); context.mavenExecutionRequest.setRepositoryCache(new DefaultRepositoryCache());
} }
localContext.eventSpyDispatcher.onEvent(request); context.eventSpyDispatcher.onEvent(request);
MavenExecutionResult result = localContext.maven.execute(request); MavenExecutionResult result;
try {
localContext.eventSpyDispatcher.onEvent(result); result = context.maven.execute(request);
context.eventSpyDispatcher.onEvent(result);
localContext.eventSpyDispatcher.close(); } finally {
context.eventSpyDispatcher.close();
}
if (result.hasExceptions()) { if (result.hasExceptions()) {
ExceptionHandler handler = new DefaultExceptionHandler(); ExceptionHandler handler = new DefaultExceptionHandler();
Map<String, String> references = new LinkedHashMap<>(); Map<String, String> references = new LinkedHashMap<>();
List<MavenProject> failedProjects = new ArrayList<>(); List<MavenProject> failedProjects = new ArrayList<>();
for (Throwable exception : result.getExceptions()) { for (Throwable exception : result.getExceptions()) {
ExceptionSummary summary = handler.handleException(exception); ExceptionSummary summary = handler.handleException(exception);
logSummary(context, summary, references, "");
logSummary(localContext, summary, references, "");
if (exception instanceof LifecycleExecutionException) { if (exception instanceof LifecycleExecutionException) {
failedProjects.add(((LifecycleExecutionException) exception).getProject()); failedProjects.add(((LifecycleExecutionException) exception).getProject());
} }
} }
localContext.logger.error(""); context.logger.error("");
if (!localContext.invokerRequest.options().showErrors().orElse(false)) { if (!context.invokerRequest.options().showErrors().orElse(false)) {
localContext.logger.error("To see the full stack trace of the errors, re-run Maven with the '" context.logger.error("To see the full stack trace of the errors, re-run Maven with the '"
+ MessageUtils.builder().strong("-e") + "' switch"); + MessageUtils.builder().strong("-e") + "' switch");
} }
if (!localContext.invokerRequest.options().verbose().orElse(false)) { if (!context.invokerRequest.options().verbose().orElse(false)) {
localContext.logger.error("Re-run Maven using the '" context.logger.error("Re-run Maven using the '"
+ MessageUtils.builder().strong("-X") + "' switch to enable verbose output"); + MessageUtils.builder().strong("-X") + "' switch to enable verbose output");
} }
if (!references.isEmpty()) { if (!references.isEmpty()) {
localContext.logger.error(""); context.logger.error("");
localContext.logger.error("For more information about the errors and possible solutions" context.logger.error("For more information about the errors and possible solutions"
+ ", please read the following articles:"); + ", please read the following articles:");
for (Map.Entry<String, String> entry : references.entrySet()) { for (Map.Entry<String, String> entry : references.entrySet()) {
localContext.logger.error(MessageUtils.builder().strong(entry.getValue()) + " " + entry.getKey()); context.logger.error(MessageUtils.builder().strong(entry.getValue()) + " " + entry.getKey());
} }
} }
if (result.canResume()) { if (result.canResume()) {
logBuildResumeHint(localContext, "mvn [args] -r"); logBuildResumeHint(context, "mvn [args] -r");
} else if (!failedProjects.isEmpty()) { } else if (!failedProjects.isEmpty()) {
List<MavenProject> sortedProjects = result.getTopologicallySortedProjects(); List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
@ -509,12 +504,12 @@ public abstract class DefaultMavenInvoker<
MavenProject firstFailedProject = failedProjects.get(0); MavenProject firstFailedProject = failedProjects.get(0);
if (!firstFailedProject.equals(sortedProjects.get(0))) { if (!firstFailedProject.equals(sortedProjects.get(0))) {
String resumeFromSelector = getResumeFromSelector(sortedProjects, firstFailedProject); String resumeFromSelector = getResumeFromSelector(sortedProjects, firstFailedProject);
logBuildResumeHint(localContext, "mvn [args] -rf " + resumeFromSelector); logBuildResumeHint(context, "mvn [args] -rf " + resumeFromSelector);
} }
} }
if (localContext.invokerRequest.options().failNever().orElse(false)) { if (context.invokerRequest.options().failNever().orElse(false)) {
localContext.logger.info("Build failures were ignored."); context.logger.info("Build failures were ignored.");
return 0; return 0;
} else { } else {
return 1; return 1;
@ -524,10 +519,10 @@ public abstract class DefaultMavenInvoker<
} }
} }
protected void logBuildResumeHint(C localContext, String resumeBuildHint) { protected void logBuildResumeHint(C context, String resumeBuildHint) {
localContext.logger.error(""); context.logger.error("");
localContext.logger.error("After correcting the problems, you can resume the build with the command"); context.logger.error("After correcting the problems, you can resume the build with the command");
localContext.logger.error( context.logger.error(
MessageUtils.builder().a(" ").strong(resumeBuildHint).toString()); MessageUtils.builder().a(" ").strong(resumeBuildHint).toString());
} }
@ -567,7 +562,7 @@ public abstract class DefaultMavenInvoker<
protected static final String ANSI_RESET = "\u001B\u005Bm"; protected static final String ANSI_RESET = "\u001B\u005Bm";
protected void logSummary(C localContext, ExceptionSummary summary, Map<String, String> references, String indent) { protected void logSummary(C context, ExceptionSummary summary, Map<String, String> references, String indent) {
String referenceKey = ""; String referenceKey = "";
if (summary.getReference() != null && !summary.getReference().isEmpty()) { if (summary.getReference() != null && !summary.getReference().isEmpty()) {
@ -607,11 +602,11 @@ public abstract class DefaultMavenInvoker<
line = indent + line + ("".equals(nextColor) ? "" : ANSI_RESET); line = indent + line + ("".equals(nextColor) ? "" : ANSI_RESET);
if ((i == lines.length - 1) if ((i == lines.length - 1)
&& (localContext.invokerRequest.options().showErrors().orElse(false) && (context.invokerRequest.options().showErrors().orElse(false)
|| (summary.getException() instanceof InternalErrorException))) { || (summary.getException() instanceof InternalErrorException))) {
localContext.logger.error(line, summary.getException()); context.logger.error(line, summary.getException());
} else { } else {
localContext.logger.error(line); context.logger.error(line);
} }
currentColor = nextColor; currentColor = nextColor;
@ -620,7 +615,7 @@ public abstract class DefaultMavenInvoker<
indent += " "; indent += " ";
for (ExceptionSummary child : summary.getChildren()) { for (ExceptionSummary child : summary.getChildren()) {
logSummary(localContext, child, references, indent); logSummary(context, child, references, indent);
} }
} }
} }

View File

@ -25,11 +25,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.cli.Logger; import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.extensions.CoreExtension; import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.cli.mvn.MavenInvokerRequest; import org.apache.maven.api.cli.mvn.MavenInvokerRequest;
import org.apache.maven.api.cli.mvn.MavenOptions; import org.apache.maven.api.cli.mvn.MavenOptions;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.apache.maven.cling.invoker.BaseInvokerRequest; import org.apache.maven.cling.invoker.BaseInvokerRequest;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -45,14 +44,12 @@ public class DefaultMavenInvokerRequest<O extends MavenOptions> extends BaseInvo
@SuppressWarnings("ParameterNumber") @SuppressWarnings("ParameterNumber")
public DefaultMavenInvokerRequest( public DefaultMavenInvokerRequest(
String command, ParserRequest parserRequest,
Path cwd, Path cwd,
Path installationDirectory, Path installationDirectory,
Path userHomeDirectory, Path userHomeDirectory,
Map<String, String> userProperties, Map<String, String> userProperties,
Map<String, String> systemProperties, Map<String, String> systemProperties,
Logger logger,
MessageBuilderFactory messageBuilderFactory,
Path topDirectory, Path topDirectory,
Path rootDirectory, Path rootDirectory,
InputStream in, InputStream in,
@ -61,14 +58,12 @@ public class DefaultMavenInvokerRequest<O extends MavenOptions> extends BaseInvo
List<CoreExtension> coreExtensions, List<CoreExtension> coreExtensions,
O options) { O options) {
super( super(
command, parserRequest,
cwd, cwd,
installationDirectory, installationDirectory,
userHomeDirectory, userHomeDirectory,
userProperties, userProperties,
systemProperties, systemProperties,
logger,
messageBuilderFactory,
topDirectory, topDirectory,
rootDirectory, rootDirectory,
in, in,

View File

@ -53,7 +53,7 @@ public abstract class DefaultMavenParser<O extends MavenOptions, R extends Maven
Options options); Options options);
@Override @Override
protected List<O> parseCliOptions(Path rootDirectory, String[] args) throws ParserException, IOException { protected List<O> parseCliOptions(Path rootDirectory, List<String> args) throws ParserException, IOException {
ArrayList<O> result = new ArrayList<>(); ArrayList<O> result = new ArrayList<>();
// CLI args // CLI args
result.add(parseMavenCliOptions(args)); result.add(parseMavenCliOptions(args));
@ -65,14 +65,14 @@ public abstract class DefaultMavenParser<O extends MavenOptions, R extends Maven
return result; return result;
} }
protected O parseMavenCliOptions(String[] args) throws ParserException { protected O parseMavenCliOptions(List<String> args) throws ParserException {
return parseArgs(Options.SOURCE_CLI, args); return parseArgs(Options.SOURCE_CLI, args);
} }
protected O parseMavenConfigOptions(Path configFile) throws ParserException, IOException { protected O parseMavenConfigOptions(Path configFile) throws ParserException, IOException {
try (Stream<String> lines = Files.lines(configFile, Charset.defaultCharset())) { try (Stream<String> lines = Files.lines(configFile, Charset.defaultCharset())) {
String[] args = List<String> args =
lines.filter(arg -> !arg.isEmpty() && !arg.startsWith("#")).toArray(String[]::new); lines.filter(arg -> !arg.isEmpty() && !arg.startsWith("#")).toList();
O options = parseArgs("maven.config", args); O options = parseArgs("maven.config", args);
if (options.goals().isPresent()) { if (options.goals().isPresent()) {
// This file can only contain options, not args (goals or phases) // This file can only contain options, not args (goals or phases)
@ -83,5 +83,5 @@ public abstract class DefaultMavenParser<O extends MavenOptions, R extends Maven
} }
} }
protected abstract O parseArgs(String source, String[] args) throws ParserException; protected abstract O parseArgs(String source, List<String> args) throws ParserException;
} }

View File

@ -35,6 +35,7 @@ import static java.util.Objects.requireNonNull;
* Forked invoker implementation, it spawns a subprocess with Maven. * Forked invoker implementation, it spawns a subprocess with Maven.
*/ */
public class DefaultForkedMavenInvoker implements ForkedMavenInvoker { public class DefaultForkedMavenInvoker implements ForkedMavenInvoker {
@SuppressWarnings("MethodLength")
@Override @Override
public int invoke(ForkedMavenInvokerRequest invokerRequest) throws InvokerException { public int invoke(ForkedMavenInvokerRequest invokerRequest) throws InvokerException {
requireNonNull(invokerRequest); requireNonNull(invokerRequest);
@ -44,7 +45,10 @@ public class DefaultForkedMavenInvoker implements ForkedMavenInvoker {
cmdAndArguments.add(invokerRequest cmdAndArguments.add(invokerRequest
.installationDirectory() .installationDirectory()
.resolve("bin") .resolve("bin")
.resolve(Os.IS_WINDOWS ? invokerRequest.command() + ".cmd" : invokerRequest.command()) .resolve(
Os.IS_WINDOWS
? invokerRequest.parserRequest().command() + ".cmd"
: invokerRequest.parserRequest().command())
.toString()); .toString());
MavenOptions mavenOptions = invokerRequest.options(); MavenOptions mavenOptions = invokerRequest.options();
@ -54,42 +58,138 @@ public class DefaultForkedMavenInvoker implements ForkedMavenInvoker {
cmdAndArguments.add("-D" + entry.getKey() + "=" + entry.getValue()); cmdAndArguments.add("-D" + entry.getKey() + "=" + entry.getValue());
} }
} }
if (mavenOptions.showVersionAndExit().orElse(false)) {
cmdAndArguments.add("--version");
}
if (mavenOptions.showVersion().orElse(false)) {
cmdAndArguments.add("--show-version");
}
if (mavenOptions.quiet().orElse(false)) {
cmdAndArguments.add("--quiet");
}
if (mavenOptions.verbose().orElse(false)) {
cmdAndArguments.add("--verbose");
}
if (mavenOptions.showErrors().orElse(false)) {
cmdAndArguments.add("--errors");
}
if (mavenOptions.failOnSeverity().isPresent()) {
cmdAndArguments.add("--fail-on-severity");
cmdAndArguments.add(mavenOptions.failOnSeverity().get());
}
if (mavenOptions.nonInteractive().orElse(false)) {
cmdAndArguments.add("--non-interactive");
}
if (mavenOptions.forceInteractive().orElse(false)) {
cmdAndArguments.add("--force-interactive");
}
if (mavenOptions.altUserSettings().isPresent()) {
cmdAndArguments.add("--settings");
cmdAndArguments.add(mavenOptions.altUserSettings().get());
}
if (mavenOptions.altProjectSettings().isPresent()) {
cmdAndArguments.add("--project-settings");
cmdAndArguments.add(mavenOptions.altProjectSettings().get());
}
if (mavenOptions.altInstallationSettings().isPresent()) {
cmdAndArguments.add("--install-settings");
cmdAndArguments.add(mavenOptions.altInstallationSettings().get());
}
if (mavenOptions.altUserToolchains().isPresent()) {
cmdAndArguments.add("--toolchains");
cmdAndArguments.add(mavenOptions.altUserToolchains().get());
}
if (mavenOptions.altInstallationToolchains().isPresent()) {
cmdAndArguments.add("--install-toolchains");
cmdAndArguments.add(mavenOptions.altInstallationToolchains().get());
}
if (mavenOptions.logFile().isPresent()) {
cmdAndArguments.add("--log-file");
cmdAndArguments.add(mavenOptions.logFile().get());
}
if (mavenOptions.color().isPresent()) {
cmdAndArguments.add("--color");
cmdAndArguments.add(mavenOptions.color().get());
}
if (mavenOptions.help().orElse(false)) {
cmdAndArguments.add("--help");
}
if (mavenOptions.alternatePomFile().isPresent()) { if (mavenOptions.alternatePomFile().isPresent()) {
cmdAndArguments.add("-f"); cmdAndArguments.add("--file");
cmdAndArguments.add(mavenOptions.alternatePomFile().get()); cmdAndArguments.add(mavenOptions.alternatePomFile().get());
} }
if (mavenOptions.offline().orElse(false)) { if (mavenOptions.offline().orElse(false)) {
cmdAndArguments.add("-o"); cmdAndArguments.add("--offline");
}
if (mavenOptions.showVersionAndExit().orElse(false)) {
cmdAndArguments.add("-v");
}
if (mavenOptions.showVersion().orElse(false)) {
cmdAndArguments.add("-V");
}
if (mavenOptions.quiet().orElse(false)) {
cmdAndArguments.add("-q");
}
if (mavenOptions.verbose().orElse(false)) {
cmdAndArguments.add("-X");
}
if (mavenOptions.showErrors().orElse(false)) {
cmdAndArguments.add("-e");
} }
if (mavenOptions.nonRecursive().orElse(false)) { if (mavenOptions.nonRecursive().orElse(false)) {
cmdAndArguments.add("-N"); cmdAndArguments.add("--non-recursive");
} }
if (mavenOptions.updateSnapshots().orElse(false)) { if (mavenOptions.updateSnapshots().orElse(false)) {
cmdAndArguments.add("-U"); cmdAndArguments.add("--update-snapshots");
} }
if (mavenOptions.nonInteractive().orElse(false)) { if (mavenOptions.activatedProfiles().isPresent()) {
cmdAndArguments.add("-B"); cmdAndArguments.add("--activate-profiles");
cmdAndArguments.add(
String.join(",", mavenOptions.activatedProfiles().get()));
} }
if (mavenOptions.logFile().isPresent()) { if (mavenOptions.suppressSnapshotUpdates().orElse(false)) {
cmdAndArguments.add("-l"); cmdAndArguments.add("--no-snapshot-updates");
cmdAndArguments.add(mavenOptions.logFile().get()); }
if (mavenOptions.strictChecksums().orElse(false)) {
cmdAndArguments.add("--strict-checksums");
}
if (mavenOptions.relaxedChecksums().orElse(false)) {
cmdAndArguments.add("--lax-checksums");
}
if (mavenOptions.failFast().orElse(false)) {
cmdAndArguments.add("--fail-fast");
}
if (mavenOptions.failAtEnd().orElse(false)) {
cmdAndArguments.add("--fail-at-end");
}
if (mavenOptions.failNever().orElse(false)) {
cmdAndArguments.add("--fail-never");
}
if (mavenOptions.resume().orElse(false)) {
cmdAndArguments.add("--resume");
}
if (mavenOptions.resumeFrom().isPresent()) {
cmdAndArguments.add("--resume-from");
cmdAndArguments.add(mavenOptions.resumeFrom().get());
}
if (mavenOptions.projects().isPresent()) {
cmdAndArguments.add("--projects");
cmdAndArguments.add(String.join(",", mavenOptions.projects().get()));
}
if (mavenOptions.alsoMake().orElse(false)) {
cmdAndArguments.add("--also-make");
}
if (mavenOptions.alsoMakeDependents().orElse(false)) {
cmdAndArguments.add("--also-make-dependents");
}
if (mavenOptions.threads().isPresent()) {
cmdAndArguments.add("--threads");
cmdAndArguments.add(mavenOptions.threads().get());
}
if (mavenOptions.builder().isPresent()) {
cmdAndArguments.add("--builder");
cmdAndArguments.add(mavenOptions.builder().get());
}
if (mavenOptions.noTransferProgress().orElse(false)) {
cmdAndArguments.add("--no-transfer-progress");
}
if (mavenOptions.cacheArtifactNotFound().isPresent()) {
cmdAndArguments.add("--cache-artifact-not-found");
cmdAndArguments.add(mavenOptions.cacheArtifactNotFound().get().toString());
}
if (mavenOptions.strictArtifactDescriptorPolicy().isPresent()) {
cmdAndArguments.add("--strict-artifact-descriptor-policy");
cmdAndArguments.add(
mavenOptions.strictArtifactDescriptorPolicy().get().toString());
}
if (mavenOptions.ignoreTransitiveRepositories().isPresent()) {
cmdAndArguments.add("--ignore-transitive-repositories");
} }
// TODO: etc
// last the goals // last the goals
cmdAndArguments.addAll(mavenOptions.goals().orElse(Collections.emptyList())); cmdAndArguments.addAll(mavenOptions.goals().orElse(Collections.emptyList()));

View File

@ -25,11 +25,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import org.apache.maven.api.cli.Logger; import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.extensions.CoreExtension; import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.cli.mvn.MavenOptions; 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.ForkedMavenInvokerRequest;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.apache.maven.cling.invoker.mvn.DefaultMavenInvokerRequest; import org.apache.maven.cling.invoker.mvn.DefaultMavenInvokerRequest;
/** /**
@ -41,14 +40,12 @@ public class DefaultForkedMavenInvokerRequest extends DefaultMavenInvokerRequest
@SuppressWarnings("ParameterNumber") @SuppressWarnings("ParameterNumber")
public DefaultForkedMavenInvokerRequest( public DefaultForkedMavenInvokerRequest(
String command, ParserRequest parserRequest,
Path cwd, Path cwd,
Path installationDirectory, Path installationDirectory,
Path userHomeDirectory, Path userHomeDirectory,
Map<String, String> userProperties, Map<String, String> userProperties,
Map<String, String> systemProperties, Map<String, String> systemProperties,
Logger logger,
MessageBuilderFactory messageBuilderFactory,
Path topDirectory, Path topDirectory,
Path rootDirectory, Path rootDirectory,
InputStream in, InputStream in,
@ -58,14 +55,12 @@ public class DefaultForkedMavenInvokerRequest extends DefaultMavenInvokerRequest
List<String> jvmArguments, List<String> jvmArguments,
MavenOptions options) { MavenOptions options) {
super( super(
command, parserRequest,
cwd, cwd,
installationDirectory, installationDirectory,
userHomeDirectory, userHomeDirectory,
userProperties, userProperties,
systemProperties, systemProperties,
logger,
messageBuilderFactory,
topDirectory, topDirectory,
rootDirectory, rootDirectory,
in, in,
@ -78,6 +73,6 @@ public class DefaultForkedMavenInvokerRequest extends DefaultMavenInvokerRequest
@Override @Override
public Optional<List<String>> jvmArguments() { public Optional<List<String>> jvmArguments() {
return Optional.of(jvmArguments); return Optional.ofNullable(jvmArguments);
} }
} }

View File

@ -20,7 +20,6 @@ package org.apache.maven.cling.invoker.mvn.forked;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -53,14 +52,12 @@ public class DefaultForkedMavenParser extends DefaultMavenParser<MavenOptions, F
ArrayList<CoreExtension> extensions, ArrayList<CoreExtension> extensions,
Options options) { Options options) {
return new DefaultForkedMavenInvokerRequest( return new DefaultForkedMavenInvokerRequest(
parserRequest.command(), parserRequest,
cwd, cwd,
installationDirectory, installationDirectory,
userHomeDirectory, userHomeDirectory,
userProperties, userProperties,
systemProperties, systemProperties,
parserRequest.logger(),
parserRequest.messageBuilderFactory(),
topDirectory, topDirectory,
rootDirectory, rootDirectory,
parserRequest.in(), parserRequest.in(),
@ -74,15 +71,15 @@ public class DefaultForkedMavenParser extends DefaultMavenParser<MavenOptions, F
protected List<String> getJvmArguments(Path rootDirectory) { protected List<String> getJvmArguments(Path rootDirectory) {
if (rootDirectory != null) { if (rootDirectory != null) {
// TODO: do this // TODO: do this
return Collections.emptyList(); return null;
} }
return null; return null;
} }
@Override @Override
protected MavenOptions parseArgs(String source, String[] args) throws ParserException { protected MavenOptions parseArgs(String source, List<String> args) throws ParserException {
try { try {
return CommonsCliMavenOptions.parse(source, args); return CommonsCliMavenOptions.parse(source, args.toArray(new String[0]));
} catch (ParseException e) { } catch (ParseException e) {
throw new ParserException("Failed to parse source " + source, e.getCause()); throw new ParserException("Failed to parse source " + source, e.getCause());
} }

View File

@ -52,14 +52,12 @@ public class DefaultLocalMavenParser extends DefaultMavenParser<MavenOptions, Ma
ArrayList<CoreExtension> extensions, ArrayList<CoreExtension> extensions,
Options options) { Options options) {
return new DefaultMavenInvokerRequest<>( return new DefaultMavenInvokerRequest<>(
parserRequest.command(), parserRequest,
cwd, cwd,
installationDirectory, installationDirectory,
userHomeDirectory, userHomeDirectory,
userProperties, userProperties,
systemProperties, systemProperties,
parserRequest.logger(),
parserRequest.messageBuilderFactory(),
topDirectory, topDirectory,
rootDirectory, rootDirectory,
parserRequest.in(), parserRequest.in(),
@ -70,9 +68,9 @@ public class DefaultLocalMavenParser extends DefaultMavenParser<MavenOptions, Ma
} }
@Override @Override
protected MavenOptions parseArgs(String source, String[] args) throws ParserException { protected MavenOptions parseArgs(String source, List<String> args) throws ParserException {
try { try {
return CommonsCliMavenOptions.parse(source, args); return CommonsCliMavenOptions.parse(source, args.toArray(new String[0]));
} catch (ParseException e) { } catch (ParseException e) {
throw new ParserException("Failed to parse source " + source, e.getCause()); throw new ParserException("Failed to parse source " + source, e.getCause());
} }

View File

@ -54,7 +54,7 @@ public class DefaultResidentMavenInvoker
super.close(); super.close();
} }
public LocalContext createShadow() { public LocalContext copy(ResidentMavenInvokerRequest invokerRequest) {
LocalContext shadow = new LocalContext((DefaultResidentMavenInvoker) invoker, invokerRequest); LocalContext shadow = new LocalContext((DefaultResidentMavenInvoker) invoker, invokerRequest);
shadow.logger = logger; shadow.logger = logger;
@ -122,10 +122,12 @@ public class DefaultResidentMavenInvoker
throw new InvokerException("Failed to init master context", e); throw new InvokerException("Failed to init master context", e);
} }
}) })
.createShadow(); .copy(invokerRequest);
} }
protected String getContextId(ResidentMavenInvokerRequest invokerRequest) { protected String getContextId(ResidentMavenInvokerRequest 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"; return "resident";
} }

View File

@ -25,11 +25,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import org.apache.maven.api.cli.Logger; import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.extensions.CoreExtension; import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvokerRequest; import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvokerRequest;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenOptions; import org.apache.maven.api.cli.mvn.resident.ResidentMavenOptions;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.apache.maven.cling.invoker.mvn.DefaultMavenInvokerRequest; import org.apache.maven.cling.invoker.mvn.DefaultMavenInvokerRequest;
/** /**
@ -41,14 +40,12 @@ public class DefaultResidentMavenInvokerRequest extends DefaultMavenInvokerReque
@SuppressWarnings("ParameterNumber") @SuppressWarnings("ParameterNumber")
public DefaultResidentMavenInvokerRequest( public DefaultResidentMavenInvokerRequest(
String command, ParserRequest parserRequest,
Path cwd, Path cwd,
Path installationDirectory, Path installationDirectory,
Path userHomeDirectory, Path userHomeDirectory,
Map<String, String> userProperties, Map<String, String> userProperties,
Map<String, String> systemProperties, Map<String, String> systemProperties,
Logger logger,
MessageBuilderFactory messageBuilderFactory,
Path topDirectory, Path topDirectory,
Path rootDirectory, Path rootDirectory,
InputStream in, InputStream in,
@ -58,14 +55,12 @@ public class DefaultResidentMavenInvokerRequest extends DefaultMavenInvokerReque
List<String> jvmArguments, List<String> jvmArguments,
ResidentMavenOptions options) { ResidentMavenOptions options) {
super( super(
command, parserRequest,
cwd, cwd,
installationDirectory, installationDirectory,
userHomeDirectory, userHomeDirectory,
userProperties, userProperties,
systemProperties, systemProperties,
logger,
messageBuilderFactory,
topDirectory, topDirectory,
rootDirectory, rootDirectory,
in, in,

View File

@ -51,14 +51,12 @@ public class DefaultResidentMavenParser extends DefaultMavenParser<ResidentMaven
ArrayList<CoreExtension> extensions, ArrayList<CoreExtension> extensions,
Options options) { Options options) {
return new DefaultResidentMavenInvokerRequest( return new DefaultResidentMavenInvokerRequest(
parserRequest.command(), parserRequest,
cwd, cwd,
installationDirectory, installationDirectory,
userHomeDirectory, userHomeDirectory,
userProperties, userProperties,
systemProperties, systemProperties,
parserRequest.logger(),
parserRequest.messageBuilderFactory(),
topDirectory, topDirectory,
rootDirectory, rootDirectory,
parserRequest.in(), parserRequest.in(),
@ -78,9 +76,9 @@ public class DefaultResidentMavenParser extends DefaultMavenParser<ResidentMaven
} }
@Override @Override
protected ResidentMavenOptions parseArgs(String source, String[] args) throws ParserException { protected ResidentMavenOptions parseArgs(String source, List<String> args) throws ParserException {
try { try {
return CommonsCliResidentMavenOptions.parse(source, args); return CommonsCliResidentMavenOptions.parse(source, args.toArray(new String[0]));
} catch (ParseException e) { } catch (ParseException e) {
throw new ParserException("Failed to parse source " + source, e.getCause()); throw new ParserException("Failed to parse source " + source, e.getCause());
} }

View File

@ -25,12 +25,11 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.cli.Logger;
import org.apache.maven.api.cli.Options; 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.extensions.CoreExtension;
import org.apache.maven.api.cli.mvnenc.EncryptInvokerRequest; import org.apache.maven.api.cli.mvnenc.EncryptInvokerRequest;
import org.apache.maven.api.cli.mvnenc.EncryptOptions; import org.apache.maven.api.cli.mvnenc.EncryptOptions;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.apache.maven.cling.invoker.BaseInvokerRequest; import org.apache.maven.cling.invoker.BaseInvokerRequest;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -40,14 +39,12 @@ public class DefaultEncryptInvokerRequest extends BaseInvokerRequest<EncryptOpti
@SuppressWarnings("ParameterNumber") @SuppressWarnings("ParameterNumber")
public DefaultEncryptInvokerRequest( public DefaultEncryptInvokerRequest(
String command, ParserRequest parserRequest,
Path cwd, Path cwd,
Path installationDirectory, Path installationDirectory,
Path userHomeDirectory, Path userHomeDirectory,
Map<String, String> userProperties, Map<String, String> userProperties,
Map<String, String> systemProperties, Map<String, String> systemProperties,
Logger logger,
MessageBuilderFactory messageBuilderFactory,
Path topDirectory, Path topDirectory,
Path rootDirectory, Path rootDirectory,
InputStream in, InputStream in,
@ -56,14 +53,12 @@ public class DefaultEncryptInvokerRequest extends BaseInvokerRequest<EncryptOpti
List<CoreExtension> coreExtensions, List<CoreExtension> coreExtensions,
Options options) { Options options) {
super( super(
command, parserRequest,
cwd, cwd,
installationDirectory, installationDirectory,
userHomeDirectory, userHomeDirectory,
userProperties, userProperties,
systemProperties, systemProperties,
logger,
messageBuilderFactory,
topDirectory, topDirectory,
rootDirectory, rootDirectory,
in, in,

View File

@ -49,14 +49,12 @@ public class DefaultEncryptParser extends BaseParser<EncryptOptions, EncryptInvo
ArrayList<CoreExtension> extensions, ArrayList<CoreExtension> extensions,
Options options) { Options options) {
return new DefaultEncryptInvokerRequest( return new DefaultEncryptInvokerRequest(
parserRequest.command(), parserRequest,
cwd, cwd,
installationDirectory, installationDirectory,
userHomeDirectory, userHomeDirectory,
userProperties, userProperties,
systemProperties, systemProperties,
parserRequest.logger(),
parserRequest.messageBuilderFactory(),
topDirectory, topDirectory,
rootDirectory, rootDirectory,
parserRequest.in(), parserRequest.in(),
@ -67,13 +65,13 @@ public class DefaultEncryptParser extends BaseParser<EncryptOptions, EncryptInvo
} }
@Override @Override
protected List<EncryptOptions> parseCliOptions(Path rootDirectory, String[] args) throws ParserException { protected List<EncryptOptions> parseCliOptions(Path rootDirectory, List<String> args) throws ParserException {
return Collections.singletonList(parseEncryptCliOptions(args)); return Collections.singletonList(parseEncryptCliOptions(args));
} }
protected CommonsCliEncryptOptions parseEncryptCliOptions(String[] args) throws ParserException { protected CommonsCliEncryptOptions parseEncryptCliOptions(List<String> args) throws ParserException {
try { try {
return CommonsCliEncryptOptions.parse(args); return CommonsCliEncryptOptions.parse(args.toArray(new String[0]));
} catch (ParseException e) { } catch (ParseException e) {
throw new ParserException("Failed to parse command line options: " + e.getMessage(), e); throw new ParserException("Failed to parse command line options: " + e.getMessage(), e);
} }

View File

@ -1,50 +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.forked;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.maven.cling.invoker.ProtoLogger;
import org.apache.maven.cling.invoker.mvn.forked.DefaultForkedMavenInvoker;
import org.apache.maven.cling.invoker.mvn.forked.DefaultForkedMavenParser;
import org.apache.maven.jline.JLineMessageBuilderFactory;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@Disabled("Works ONLY with Maven4!")
public class DefaultForkedMavenInvokerTest {
@Test
void smoke(@TempDir Path tempDir) throws Exception {
try (DefaultForkedMavenInvoker invoker = new DefaultForkedMavenInvoker()) {
Files.createDirectory(tempDir.resolve(".mvn"));
Path log = tempDir.resolve("build.log").toAbsolutePath();
int exitcode = invoker.invoke(new DefaultForkedMavenParser()
.parse(
"mvn",
new String[] {"-l", log.toString(), "clean"},
new ProtoLogger(),
new JLineMessageBuilderFactory()));
System.out.println("exit code: " + exitcode);
System.out.println("log:");
System.out.println(Files.readString(log));
}
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.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.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;
import org.junit.jupiter.api.Assumptions;
import static org.junit.jupiter.api.Assertions.assertEquals;
public abstract class MavenInvokerTestSupport<O extends MavenOptions, R extends MavenInvokerRequest<O>> {
protected void invoke(Path cwd, Collection<String> goals) throws Exception {
// works only in recent Maven4
Assumptions.assumeTrue(Files.isRegularFile(
Paths.get(System.getProperty("maven.home")).resolve("conf").resolve("maven.properties")));
Files.createDirectory(cwd.resolve(".mvn"));
String pomString =
"""
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.maven.samples</groupId>
<artifactId>sample</artifactId>
<version>1.0.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
""";
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<R> parser = createParser();
try (Invoker<R> invoker = createInvoker()) {
for (String goal : goals) {
Path logFile = cwd.resolve(goal + "-build.log").toAbsolutePath();
int exitCode = invoker.invoke(parser.parse(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 Invoker<R> createInvoker();
protected abstract Parser<R> createParser();
}

View File

@ -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.cling.invoker.mvn.forked;
import java.nio.file.Path;
import java.util.Arrays;
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;
import org.junit.jupiter.api.io.TempDir;
/**
* Forked UT: it cannot use jimFS as it runs in child process.
*/
public class DefaultForkedMavenInvokerTest extends MavenInvokerTestSupport<MavenOptions, ForkedMavenInvokerRequest> {
@Override
protected Invoker<ForkedMavenInvokerRequest> createInvoker() {
return new DefaultForkedMavenInvoker();
}
@Override
protected Parser<ForkedMavenInvokerRequest> createParser() {
return new DefaultForkedMavenParser();
}
@Test
void defaultFs(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tempDir) throws Exception {
invoke(tempDir, Arrays.asList("clean", "verify"));
}
}

View File

@ -0,0 +1,68 @@
/*
* 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 java.nio.file.FileSystem;
import java.nio.file.Path;
import java.util.Arrays;
import com.google.common.jimfs.Configuration;
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.MavenInvokerTestSupport;
import org.codehaus.plexus.classworlds.ClassWorld;
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;
/**
* Local UT.
*/
public class DefaultLocalMavenInvokerTest
extends MavenInvokerTestSupport<MavenOptions, MavenInvokerRequest<MavenOptions>> {
@Override
protected Invoker<MavenInvokerRequest<MavenOptions>> createInvoker() {
return new DefaultLocalMavenInvoker(ProtoLookup.builder()
.addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader()))
.build());
}
@Override
protected Parser<MavenInvokerRequest<MavenOptions>> createParser() {
return new DefaultLocalMavenParser();
}
@Test
void defaultFs(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tempDir) throws Exception {
invoke(tempDir, Arrays.asList("clean", "verify"));
}
@Disabled("Until we move off fully from File")
@Test
void jimFs() throws Exception {
try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
invoke(fs.getPath("/"), Arrays.asList("clean", "verify"));
}
}
}

View File

@ -18,94 +18,52 @@
*/ */
package org.apache.maven.cling.invoker.mvn.resident; package org.apache.maven.cling.invoker.mvn.resident;
import java.nio.file.Files; import java.nio.file.FileSystem;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays;
import org.apache.maven.api.cli.ParserRequest; import com.google.common.jimfs.Configuration;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenParser; import com.google.common.jimfs.Jimfs;
import org.apache.maven.cling.invoker.ProtoLogger; import org.apache.maven.api.cli.Invoker;
import org.apache.maven.api.cli.Parser;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenInvokerRequest;
import org.apache.maven.api.cli.mvn.resident.ResidentMavenOptions;
import org.apache.maven.cling.invoker.ProtoLookup; import org.apache.maven.cling.invoker.ProtoLookup;
import org.apache.maven.jline.JLineMessageBuilderFactory; import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport;
import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.ClassWorld;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.CleanupMode;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
@Disabled("Works ONLY with Maven4!") /**
public class DefaultResidentMavenInvokerTest { * Resident UT.
*/
public class DefaultResidentMavenInvokerTest
extends MavenInvokerTestSupport<ResidentMavenOptions, ResidentMavenInvokerRequest> {
@Override
protected Invoker<ResidentMavenInvokerRequest> createInvoker() {
return new DefaultResidentMavenInvoker(ProtoLookup.builder()
.addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader()))
.build());
}
@Override
protected Parser<ResidentMavenInvokerRequest> createParser() {
return new DefaultResidentMavenParser();
}
@Test @Test
void smoke(@TempDir Path tempDir) throws Exception { void defaultFs(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tempDir) throws Exception {
try (ClassWorld classWorld = invoke(tempDir, Arrays.asList("clean", "verify"));
new ClassWorld("plexus.core", Thread.currentThread().getContextClassLoader()); }
DefaultResidentMavenInvoker invoker = new DefaultResidentMavenInvoker(ProtoLookup.builder()
.addMapping(ClassWorld.class, classWorld)
.build())) {
ResidentMavenParser parser = new DefaultResidentMavenParser();
Files.createDirectory(tempDir.resolve(".mvn"));
Path log = tempDir.resolve("build.log").toAbsolutePath();
String pomString = @Disabled("Until we move off fully from File")
""" @Test
<?xml version="1.0" encoding="UTF-8"?> void jimFs() throws Exception {
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" try (FileSystem fs = Jimfs.newFileSystem(Configuration.unix())) {
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd"> invoke(fs.getPath("/"), Arrays.asList("clean", "verify"));
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.maven.samples</groupId>
<artifactId>resident-invoker</artifactId>
<version>1.0.0</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
</dependency>
</dependencies>
</project>
""";
Path pom = tempDir.resolve("pom.xml").toAbsolutePath();
Files.writeString(pom, pomString);
int exitCode;
exitCode = invoker.invoke(parser.parse(ParserRequest.builder(
"mvn",
new String[] {"-l", log.toString(), "clean"},
new ProtoLogger(),
new JLineMessageBuilderFactory())
.cwd(tempDir)
.build()));
System.out.println("1st exit code: " + exitCode);
System.out.println("log:");
System.out.println(Files.readString(log));
exitCode = invoker.invoke(parser.parse(ParserRequest.builder(
"mvn",
new String[] {"-l", log.toString(), "clean"},
new ProtoLogger(),
new JLineMessageBuilderFactory())
.cwd(tempDir)
.build()));
System.out.println("2nd exit code: " + exitCode);
System.out.println("log:");
System.out.println(Files.readString(log));
} }
} }
} }