ParserRequest.java
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.api.cli;
import java.io.InputStream;
import java.io.OutputStream;
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.Immutable;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.cli.logging.AccumulatingLogger;
import org.apache.maven.api.services.Lookup;
import org.apache.maven.api.services.LookupException;
import org.apache.maven.api.services.MessageBuilderFactory;
import static java.util.Objects.requireNonNull;
/**
* Represents a request to parse Maven command-line arguments.
* This interface encapsulates all the necessary information needed to parse
* Maven commands and arguments into an {@link InvokerRequest}.
*
* @since 4.0.0
*/
@Immutable
@Experimental
public interface ParserRequest {
/**
* 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
*/
@Nonnull
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
*/
@Nonnull
String commandName();
/**
* Returns the logger to be used during the parsing process.
*
* @return the logger instance
*/
@Nonnull
Logger logger();
/**
* Returns the factory for creating message builders.
*
* @return the message builder factory
*/
@Nonnull
MessageBuilderFactory messageBuilderFactory();
/**
* Returns the command-line arguments to be parsed.
*
* @return a list of argument strings
*/
@Nonnull
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.
* If not explicitly set, this value will be detected during parsing.
*
* @return the current working directory path, or null if not set
*/
@Nullable
Path cwd();
/**
* Returns the Maven home directory.
* If not explicitly set, this value will be detected during parsing.
*
* @return the Maven home directory path, or null if not set
*/
@Nullable
Path mavenHome();
/**
* Returns the user's home directory.
* If not explicitly set, this value will be detected during parsing.
*
* @return the user's home directory path, or null if not set
*/
@Nullable
Path userHome();
/**
* Returns the input stream to be used for the Maven execution.
* If not set, {@link System#in} will be used by default.
*
* @return the input stream, or null if not set
*/
@Nullable
InputStream stdIn();
/**
* Returns the output stream to be used for the Maven execution.
* If not set, {@link System#out} will be used by default.
*
* @return the output stream, or null if not set
*/
@Nullable
OutputStream stdOut();
/**
* Returns the error stream to be used for the Maven execution.
* If not set, {@link System#err} will be used by default.
*
* @return the error stream, or null if not set
*/
@Nullable
OutputStream stdErr();
/**
* Returns {@code true} if this call happens in "embedded" mode, for example by another application that
* embeds Maven. When running in "embedded" mode, Maven will not try to grab system terminal and will use
* provided {@link #stdIn()} or {@link InputStream#nullInputStream()} as standard in stream.
*/
boolean embedded();
/**
* Creates a new Builder instance for constructing a Maven ParserRequest.
*
* @param args the command-line arguments
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvn(@Nonnull String[] args, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return mvn(Arrays.asList(args), messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven ParserRequest.
*
* @param args the command-line arguments
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvn(@Nonnull List<String> args, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return builder(Tools.MVN_CMD, Tools.MVN_NAME, args, messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven Encrypting Tool ParserRequest.
*
* @param args the command-line arguments
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvnenc(@Nonnull String[] args, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return mvnenc(Arrays.asList(args), messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven Encrypting Tool ParserRequest.
*
* @param args the command-line arguments
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvnenc(@Nonnull List<String> args, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return builder(Tools.MVNENC_CMD, Tools.MVNENC_NAME, args, messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven Shell Tool ParserRequest.
*
* @param args the command-line arguments
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvnsh(@Nonnull String[] args, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return mvnsh(Arrays.asList(args), messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven Shell Tool ParserRequest.
*
* @param args the command-line arguments
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvnsh(@Nonnull List<String> args, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return builder(Tools.MVNSHELL_CMD, Tools.MVNSHELL_NAME, args, messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven Upgrade Tool ParserRequest.
*
* @param args the command-line arguments
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvnup(@Nonnull String[] args, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return mvnup(Arrays.asList(args), messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a Maven Upgrade Tool ParserRequest.
*
* @param args the command-line arguments
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder mvnup(@Nonnull List<String> args, @Nonnull MessageBuilderFactory messageBuilderFactory) {
return builder(Tools.MVNUP_CMD, Tools.MVNUP_NAME, args, messageBuilderFactory);
}
/**
* Creates a new Builder instance for constructing a ParserRequest.
*
* @param command the Maven command to be executed
* @param commandName the Maven command Name to be executed
* @param args the command-line arguments
* @param messageBuilderFactory the factory for creating message builders
* @return a new Builder instance
*/
@Nonnull
static Builder builder(
@Nonnull String command,
@Nonnull String commandName,
@Nonnull List<String> args,
@Nonnull MessageBuilderFactory messageBuilderFactory) {
return new Builder(command, commandName, args, messageBuilderFactory);
}
class Builder {
private final String command;
private final String commandName;
private final List<String> args;
private final MessageBuilderFactory messageBuilderFactory;
private final Logger logger;
private Lookup lookup = EMPTY_LOOKUP;
private Path cwd;
private Path mavenHome;
private Path userHome;
private InputStream stdIn;
private OutputStream stdOut;
private OutputStream stdErr;
private boolean embedded = false;
private Builder(
String command, String commandName, List<String> args, MessageBuilderFactory messageBuilderFactory) {
this.command = requireNonNull(command, "command");
this.commandName = requireNonNull(commandName, "commandName");
this.args = requireNonNull(args, "args");
this.messageBuilderFactory = requireNonNull(messageBuilderFactory, "messageBuilderFactory");
this.logger = new AccumulatingLogger();
}
public Builder lookup(@Nonnull Lookup lookup) {
this.lookup = requireNonNull(lookup);
return this;
}
public Builder cwd(Path cwd) {
this.cwd = cwd;
return this;
}
public Builder mavenHome(Path mavenHome) {
this.mavenHome = mavenHome;
return this;
}
public Builder userHome(Path userHome) {
this.userHome = userHome;
return this;
}
public Builder stdIn(InputStream stdIn) {
this.stdIn = stdIn;
return this;
}
public Builder stdOut(OutputStream stdOut) {
this.stdOut = stdOut;
return this;
}
public Builder stdErr(OutputStream stdErr) {
this.stdErr = stdErr;
return this;
}
public Builder embedded(boolean embedded) {
this.embedded = embedded;
return this;
}
public ParserRequest build() {
return new ParserRequestImpl(
command,
commandName,
List.copyOf(args),
lookup.lookupOptional(Logger.class).orElse(logger),
messageBuilderFactory,
lookup,
cwd,
mavenHome,
userHome,
stdIn,
stdOut,
stdErr,
embedded);
}
@SuppressWarnings("ParameterNumber")
private static class ParserRequestImpl implements ParserRequest {
private final String command;
private final String commandName;
private final Logger logger;
private final MessageBuilderFactory messageBuilderFactory;
private final List<String> args;
private final Lookup lookup;
private final Path cwd;
private final Path mavenHome;
private final Path userHome;
private final InputStream stdIn;
private final OutputStream stdOut;
private final OutputStream stdErr;
private final boolean embedded;
private ParserRequestImpl(
String command,
String commandName,
List<String> args,
Logger logger,
MessageBuilderFactory messageBuilderFactory,
Lookup lookup,
Path cwd,
Path mavenHome,
Path userHome,
InputStream stdIn,
OutputStream stdOut,
OutputStream stdErr,
boolean embedded) {
this.command = requireNonNull(command, "command");
this.commandName = requireNonNull(commandName, "commandName");
this.args = List.copyOf(requireNonNull(args, "args"));
this.logger = requireNonNull(logger, "logger");
this.messageBuilderFactory = requireNonNull(messageBuilderFactory, "messageBuilderFactory");
this.lookup = requireNonNull(lookup, "lookup");
this.cwd = cwd;
this.mavenHome = mavenHome;
this.userHome = userHome;
this.stdIn = stdIn;
this.stdOut = stdOut;
this.stdErr = stdErr;
this.embedded = embedded;
}
@Override
public String command() {
return command;
}
@Override
public String commandName() {
return commandName;
}
@Override
public Logger logger() {
return logger;
}
@Override
public MessageBuilderFactory messageBuilderFactory() {
return messageBuilderFactory;
}
@Override
public List<String> args() {
return args;
}
@Override
public Lookup lookup() {
return lookup;
}
@Override
public Path cwd() {
return cwd;
}
@Override
public Path mavenHome() {
return mavenHome;
}
@Override
public Path userHome() {
return userHome;
}
@Override
public InputStream stdIn() {
return stdIn;
}
@Override
public OutputStream stdOut() {
return stdOut;
}
@Override
public OutputStream stdErr() {
return stdErr;
}
@Override
public boolean embedded() {
return embedded;
}
}
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();
}
};
}
}