mirror of https://github.com/apache/maven.git
[MNG-8421] Move all of logging setup to LookupInvoker; mvnenc IT (#1964)
Currently mvnenc is unable to log to file (-l) as logging setup is incomplete, move all of this logic to LookupInvoker. Also, create prompt in mvnenc only when needed. Finally, implement needed changes to support mvnenc ITs and add mvnenc IT. Other changes: * get rid of `distributionFileName` dirty hack, is remnant from old ITs * fix CI re removal of that above and use of site that is brain-dead --- https://issues.apache.org/jira/browse/MNG-8421
This commit is contained in:
parent
9c77221cbc
commit
5b7a6de55a
|
@ -56,7 +56,7 @@ jobs:
|
|||
|
||||
- name: Build Maven distributions
|
||||
shell: bash
|
||||
run: ./mvnw verify -e -B -V -DdistributionFileName=apache-maven -Dmaven.repo.local=$HOME/.m2/repository/cached
|
||||
run: ./mvnw verify -e -B -V -Dmaven.repo.local=$HOME/.m2/repository/cached
|
||||
|
||||
- name: List contents of target directory
|
||||
shell: bash
|
||||
|
@ -117,9 +117,14 @@ jobs:
|
|||
run: |
|
||||
mkdir -p maven-local
|
||||
if [ "${{ runner.os }}" = "Windows" ]; then
|
||||
unzip maven-dist/apache-maven-bin.zip -d maven-local
|
||||
unzip maven-dist/apache-maven-*-bin.zip -d maven-local
|
||||
# Get the name of the extracted directory
|
||||
MAVEN_DIR=$(ls maven-local)
|
||||
# Move contents up one level
|
||||
mv "maven-local/$MAVEN_DIR"/* maven-local/
|
||||
rm -r "maven-local/$MAVEN_DIR"
|
||||
else
|
||||
tar xzf maven-dist/apache-maven-bin.tar.gz -C maven-local --strip-components 1
|
||||
tar xzf maven-dist/apache-maven-*-bin.tar.gz -C maven-local --strip-components 1
|
||||
fi
|
||||
echo "MAVEN_HOME=$PWD/maven-local" >> $GITHUB_ENV
|
||||
echo "$PWD/maven-local/bin" >> $GITHUB_PATH
|
||||
|
@ -133,9 +138,13 @@ jobs:
|
|||
maven-${{ runner.os }}-full-
|
||||
maven-${{ runner.os }}-
|
||||
|
||||
- name: Build with downloaded Maven
|
||||
shell: bash
|
||||
run: mvn verify -e -B -V -Dmaven.repo.local=$HOME/.m2/repository/cached
|
||||
|
||||
- name: Build site with downloaded Maven
|
||||
shell: bash
|
||||
run: mvn verify site -e -B -V -Preporting -Dmaven.repo.local=$HOME/.m2/repository/cached
|
||||
run: mvn site -e -B -V -Preporting -Dmaven.repo.local=$HOME/.m2/repository/cached
|
||||
|
||||
integration-tests:
|
||||
needs: initial-build
|
||||
|
@ -172,14 +181,14 @@ jobs:
|
|||
run: |
|
||||
mkdir -p maven-local
|
||||
if [ "${{ runner.os }}" = "Windows" ]; then
|
||||
unzip maven-dist/apache-maven-bin.zip -d maven-local
|
||||
unzip maven-dist/apache-maven-*-bin.zip -d maven-local
|
||||
# Get the name of the extracted directory
|
||||
MAVEN_DIR=$(ls maven-local)
|
||||
# Move contents up one level
|
||||
mv "maven-local/$MAVEN_DIR"/* maven-local/
|
||||
rm -r "maven-local/$MAVEN_DIR"
|
||||
else
|
||||
tar xzf maven-dist/apache-maven-bin.tar.gz -C maven-local --strip-components 1
|
||||
tar xzf maven-dist/apache-maven-*-bin.tar.gz -C maven-local --strip-components 1
|
||||
fi
|
||||
echo "MAVEN_HOME=$PWD/maven-local" >> $GITHUB_ENV
|
||||
echo "$PWD/maven-local/bin" >> $GITHUB_PATH
|
||||
|
|
|
@ -32,10 +32,6 @@ under the License.
|
|||
<name>Apache Maven Distribution</name>
|
||||
<description>The Apache Maven distribution, source and binary, in zip and tar.gz formats.</description>
|
||||
|
||||
<properties>
|
||||
<distributionFileName>${distributionId}-${project.version}</distributionFileName>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
|
@ -162,7 +158,6 @@ under the License.
|
|||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
<finalName>${distributionFileName}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.maven.api.cli.Logger;
|
|||
import org.apache.maven.api.services.Lookup;
|
||||
import org.apache.maven.api.settings.Settings;
|
||||
import org.apache.maven.cling.logging.Slf4jConfiguration;
|
||||
import org.apache.maven.logging.BuildEventListener;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.slf4j.ILoggerFactory;
|
||||
|
||||
|
@ -86,6 +87,8 @@ public class LookupContext implements AutoCloseable {
|
|||
public ContainerCapsule containerCapsule;
|
||||
public Lookup lookup;
|
||||
|
||||
public BuildEventListener buildEventListener;
|
||||
|
||||
// paths user can override from CLI, and we need to set on MavenExReq
|
||||
public Path installationSettingsPath;
|
||||
public Path projectSettingsPath;
|
||||
|
|
|
@ -69,7 +69,10 @@ import org.apache.maven.execution.MavenExecutionRequest;
|
|||
import org.apache.maven.internal.impl.SettingsUtilsV4;
|
||||
import org.apache.maven.jline.FastTerminal;
|
||||
import org.apache.maven.jline.MessageUtils;
|
||||
import org.apache.maven.logging.BuildEventListener;
|
||||
import org.apache.maven.logging.LoggingOutputStream;
|
||||
import org.apache.maven.logging.ProjectBuildLogAppender;
|
||||
import org.apache.maven.logging.SimpleBuildEventListener;
|
||||
import org.apache.maven.logging.api.LogLevelRecorder;
|
||||
import org.apache.maven.slf4j.MavenSimpleLogger;
|
||||
import org.jline.terminal.Terminal;
|
||||
|
@ -228,6 +231,23 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
|||
context.slf4jConfiguration.setRootLoggerLevel(context.loggerLevel);
|
||||
// else fall back to default log level specified in conf
|
||||
// see https://issues.apache.org/jira/browse/MNG-2570
|
||||
|
||||
// Create the build log appender; also sets MavenSimpleLogger sink
|
||||
ProjectBuildLogAppender projectBuildLogAppender =
|
||||
new ProjectBuildLogAppender(determineBuildEventListener(context));
|
||||
context.closeables.add(projectBuildLogAppender);
|
||||
}
|
||||
|
||||
protected BuildEventListener determineBuildEventListener(C context) {
|
||||
if (context.buildEventListener == null) {
|
||||
context.buildEventListener = doDetermineBuildEventListener(context);
|
||||
}
|
||||
return context.buildEventListener;
|
||||
}
|
||||
|
||||
protected BuildEventListener doDetermineBuildEventListener(C context) {
|
||||
Consumer<String> writer = determineWriter(context);
|
||||
return new SimpleBuildEventListener(writer);
|
||||
}
|
||||
|
||||
protected void createTerminal(C context) {
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.apache.maven.Maven;
|
|||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.cling.invoker.LookupContext;
|
||||
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
|
||||
import org.apache.maven.logging.BuildEventListener;
|
||||
|
||||
@SuppressWarnings("VisibilityModifier")
|
||||
public class MavenContext extends LookupContext {
|
||||
|
@ -30,7 +29,6 @@ public class MavenContext extends LookupContext {
|
|||
super(invokerRequest);
|
||||
}
|
||||
|
||||
public BuildEventListener buildEventListener;
|
||||
public EventSpyDispatcher eventSpyDispatcher;
|
||||
public Maven maven;
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.util.HashMap;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -68,11 +67,8 @@ import org.apache.maven.execution.ProfileActivation;
|
|||
import org.apache.maven.execution.ProjectActivation;
|
||||
import org.apache.maven.jline.MessageUtils;
|
||||
import org.apache.maven.lifecycle.LifecycleExecutionException;
|
||||
import org.apache.maven.logging.BuildEventListener;
|
||||
import org.apache.maven.logging.LoggingExecutionListener;
|
||||
import org.apache.maven.logging.MavenTransferListener;
|
||||
import org.apache.maven.logging.ProjectBuildLogAppender;
|
||||
import org.apache.maven.logging.SimpleBuildEventListener;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.PlexusContainer;
|
||||
import org.eclipse.aether.DefaultRepositoryCache;
|
||||
|
@ -149,27 +145,6 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureLogging(C context) throws Exception {
|
||||
super.configureLogging(context);
|
||||
// Create the build log appender
|
||||
ProjectBuildLogAppender projectBuildLogAppender =
|
||||
new ProjectBuildLogAppender(determineBuildEventListener(context));
|
||||
context.closeables.add(projectBuildLogAppender);
|
||||
}
|
||||
|
||||
protected BuildEventListener determineBuildEventListener(C context) {
|
||||
if (context.buildEventListener == null) {
|
||||
context.buildEventListener = doDetermineBuildEventListener(context);
|
||||
}
|
||||
return context.buildEventListener;
|
||||
}
|
||||
|
||||
protected BuildEventListener doDetermineBuildEventListener(C context) {
|
||||
Consumer<String> writer = determineWriter(context);
|
||||
return new SimpleBuildEventListener(writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeSettingsRequest(C context, SettingsBuilderRequest settingsBuilderRequest) throws Exception {
|
||||
if (context.eventSpyDispatcher != null) {
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.util.Map;
|
|||
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.cling.invoker.LookupContext;
|
||||
import org.jline.consoleui.prompt.ConsolePrompt;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
|
@ -40,7 +39,6 @@ public class EncryptContext extends LookupContext {
|
|||
public List<AttributedString> header;
|
||||
public AttributedStyle style;
|
||||
public LineReader reader;
|
||||
public ConsolePrompt prompt;
|
||||
|
||||
public void addInHeader(String text) {
|
||||
addInHeader(AttributedStyle.DEFAULT, text);
|
||||
|
|
|
@ -26,13 +26,11 @@ import org.apache.maven.api.cli.mvnenc.EncryptOptions;
|
|||
import org.apache.maven.cling.invoker.LookupInvoker;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.cling.utils.CLIReportingUtils;
|
||||
import org.jline.consoleui.prompt.ConsolePrompt;
|
||||
import org.jline.reader.LineReaderBuilder;
|
||||
import org.jline.reader.UserInterruptException;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
import org.jline.utils.Colors;
|
||||
import org.jline.utils.OSUtils;
|
||||
|
||||
/**
|
||||
* mvnenc invoker implementation.
|
||||
|
@ -76,17 +74,9 @@ public class EncryptInvoker extends LookupInvoker<EncryptContext> {
|
|||
|
||||
Thread executeThread = Thread.currentThread();
|
||||
context.terminal.handle(Terminal.Signal.INT, signal -> executeThread.interrupt());
|
||||
ConsolePrompt.UiConfig config;
|
||||
if (OSUtils.IS_WINDOWS) {
|
||||
config = new ConsolePrompt.UiConfig(">", "( )", "(x)", "( )");
|
||||
} else {
|
||||
config = new ConsolePrompt.UiConfig("❯", "◯ ", "◉ ", "◯ ");
|
||||
}
|
||||
config.setCancellableFirstPrompt(true);
|
||||
|
||||
context.reader =
|
||||
LineReaderBuilder.builder().terminal(context.terminal).build();
|
||||
context.prompt = new ConsolePrompt(context.reader, context.terminal, config);
|
||||
|
||||
EncryptOptions options = (EncryptOptions) context.invokerRequest.options();
|
||||
if (options.goals().isEmpty() || options.goals().get().size() != 1) {
|
||||
|
@ -102,14 +92,13 @@ public class EncryptInvoker extends LookupInvoker<EncryptContext> {
|
|||
|
||||
return goal.execute(context);
|
||||
} catch (InterruptedException | InterruptedIOException | UserInterruptException e) {
|
||||
context.terminal.writer().println("Goal canceled by user.");
|
||||
context.logger.error("Goal canceled by user.");
|
||||
return CANCELED;
|
||||
} catch (Exception e) {
|
||||
if (context.invokerRequest.options().showErrors().orElse(false)) {
|
||||
context.terminal.writer().println(e.getMessage());
|
||||
e.printStackTrace(context.terminal.writer());
|
||||
context.logger.error(e.getMessage(), e);
|
||||
} else {
|
||||
context.terminal.writer().println(e.getMessage());
|
||||
context.logger.error(e.getMessage());
|
||||
}
|
||||
return ERROR;
|
||||
} finally {
|
||||
|
@ -118,9 +107,9 @@ public class EncryptInvoker extends LookupInvoker<EncryptContext> {
|
|||
}
|
||||
|
||||
protected int badGoalsErrorMessage(String message, EncryptContext context) {
|
||||
context.terminal.writer().println(message);
|
||||
context.terminal.writer().println("Supported goals are: " + String.join(", ", context.goals.keySet()));
|
||||
context.terminal.writer().println("Use -h to display help.");
|
||||
context.logger.error(message);
|
||||
context.logger.error("Supported goals are: " + String.join(", ", context.goals.keySet()));
|
||||
context.logger.error("Use -h to display help.");
|
||||
return BAD_OPERATION;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,12 +39,10 @@ public abstract class ConfiguredGoalSupport extends GoalSupport {
|
|||
@Override
|
||||
public int execute(EncryptContext context) throws Exception {
|
||||
if (!validateConfiguration(context)) {
|
||||
context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory
|
||||
.builder()
|
||||
.error("Maven Encryption is not configured, run `mvnenc init` first.")
|
||||
.build());
|
||||
context.logger.error(messageBuilderFactory
|
||||
.builder()
|
||||
.error("Maven Encryption is not configured, run `mvnenc init` first.")
|
||||
.build());
|
||||
return ERROR;
|
||||
}
|
||||
return doExecute(context);
|
||||
|
@ -59,36 +57,32 @@ public abstract class ConfiguredGoalSupport extends GoalSupport {
|
|||
}
|
||||
|
||||
protected void dumpResponse(EncryptContext context, String indent, SecDispatcher.ValidationResponse response) {
|
||||
context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory
|
||||
.builder()
|
||||
.format(
|
||||
response.isValid()
|
||||
? messageBuilderFactory
|
||||
.builder()
|
||||
.success("%sConfiguration validation of %s: %s")
|
||||
.build()
|
||||
: messageBuilderFactory
|
||||
.builder()
|
||||
.failure("%sConfiguration validation of %s: %s")
|
||||
.build(),
|
||||
indent,
|
||||
response.getSource(),
|
||||
response.isValid() ? "VALID" : "INVALID"));
|
||||
context.logger.info(messageBuilderFactory
|
||||
.builder()
|
||||
.format(
|
||||
response.isValid()
|
||||
? messageBuilderFactory
|
||||
.builder()
|
||||
.success("%sConfiguration validation of %s: %s")
|
||||
.build()
|
||||
: messageBuilderFactory
|
||||
.builder()
|
||||
.failure("%sConfiguration validation of %s: %s")
|
||||
.build(),
|
||||
indent,
|
||||
response.getSource(),
|
||||
response.isValid() ? "VALID" : "INVALID")
|
||||
.build());
|
||||
for (Map.Entry<SecDispatcher.ValidationResponse.Level, List<String>> entry :
|
||||
response.getReport().entrySet()) {
|
||||
Consumer<String> consumer = s -> context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory.builder().info(s).build());
|
||||
Consumer<String> consumer = s ->
|
||||
context.logger.info(messageBuilderFactory.builder().info(s).build());
|
||||
if (entry.getKey() == SecDispatcher.ValidationResponse.Level.ERROR) {
|
||||
consumer = s -> context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory.builder().error(s).build());
|
||||
consumer = s -> context.logger.error(
|
||||
messageBuilderFactory.builder().error(s).build());
|
||||
} else if (entry.getKey() == SecDispatcher.ValidationResponse.Level.WARNING) {
|
||||
consumer = s -> context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory.builder().warning(s).build());
|
||||
consumer = s -> context.logger.warn(
|
||||
messageBuilderFactory.builder().warning(s).build());
|
||||
}
|
||||
for (String line : entry.getValue()) {
|
||||
consumer.accept(indent + " " + line);
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
|||
import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK;
|
||||
|
||||
/**
|
||||
* The "diag" goal.
|
||||
* The "diag" goal. It should always run, despite it overrides configured goal support.
|
||||
*/
|
||||
@Singleton
|
||||
@Named("diag")
|
||||
|
@ -40,8 +40,13 @@ public class Diag extends ConfiguredGoalSupport {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int doExecute(EncryptContext context) {
|
||||
public int execute(EncryptContext context) {
|
||||
dumpResponse(context, "", secDispatcher.validateConfiguration());
|
||||
return OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doExecute(EncryptContext context) throws Exception {
|
||||
throw new IllegalStateException("Cannot reach here");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.jline.reader.Completer;
|
|||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.ParsedLine;
|
||||
import org.jline.utils.Colors;
|
||||
import org.jline.utils.OSUtils;
|
||||
|
||||
import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.BAD_OPERATION;
|
||||
import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK;
|
||||
|
@ -64,26 +65,30 @@ public class Init extends InteractiveGoalSupport {
|
|||
|
||||
@Override
|
||||
public int doExecute(EncryptContext context) throws Exception {
|
||||
context.addInHeader(context.style.italic().bold().foreground(Colors.rgbColor("yellow")), "goal: init");
|
||||
context.addInHeader("");
|
||||
|
||||
ConsolePrompt prompt = context.prompt;
|
||||
|
||||
EncryptOptions options = (EncryptOptions) context.invokerRequest.options();
|
||||
boolean force = options.force().orElse(false);
|
||||
boolean yes = options.yes().orElse(false);
|
||||
|
||||
if (configExists() && !force) {
|
||||
context.terminal
|
||||
.writer()
|
||||
.println(
|
||||
messageBuilderFactory
|
||||
.builder()
|
||||
.error(
|
||||
"Error: configuration exist. Use --force if you want to reset existing configuration."));
|
||||
context.logger.error(messageBuilderFactory
|
||||
.builder()
|
||||
.error("Error: configuration exist. Use --force if you want to reset existing configuration.")
|
||||
.build());
|
||||
return BAD_OPERATION;
|
||||
}
|
||||
|
||||
context.addInHeader(context.style.italic().bold().foreground(Colors.rgbColor("yellow")), "goal: init");
|
||||
context.addInHeader("");
|
||||
|
||||
ConsolePrompt.UiConfig promptConfig;
|
||||
if (OSUtils.IS_WINDOWS) {
|
||||
promptConfig = new ConsolePrompt.UiConfig(">", "( )", "(x)", "( )");
|
||||
} else {
|
||||
promptConfig = new ConsolePrompt.UiConfig("❯", "◯ ", "◉ ", "◯ ");
|
||||
}
|
||||
promptConfig.setCancellableFirstPrompt(true);
|
||||
ConsolePrompt prompt = new ConsolePrompt(context.reader, context.terminal, promptConfig);
|
||||
|
||||
SettingsSecurity config = secDispatcher.readConfiguration(true);
|
||||
|
||||
// reset config
|
||||
|
|
|
@ -35,7 +35,7 @@ under the License.
|
|||
|
||||
<properties>
|
||||
<maven3version>3.9.9</maven3version>
|
||||
<maven4version>4.0.0-rc-1</maven4version>
|
||||
<maven4version>${project.version}</maven4version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -55,6 +55,14 @@ under the License.
|
|||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>apache-maven</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>bin</classifier>
|
||||
<type>zip</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -64,7 +72,17 @@ under the License.
|
|||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-maven-distros</id>
|
||||
<id>prepare-maven4-distro</id>
|
||||
<goals>
|
||||
<goal>unpack-dependencies</goal>
|
||||
</goals>
|
||||
<phase>generate-test-resources</phase>
|
||||
<configuration>
|
||||
<includeArtifactIds>apache-maven</includeArtifactIds>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>prepare-maven3-distro</id>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
|
@ -78,13 +96,6 @@ under the License.
|
|||
<classifier>bin</classifier>
|
||||
<type>zip</type>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>apache-maven</artifactId>
|
||||
<version>${maven4version}</version>
|
||||
<classifier>bin</classifier>
|
||||
<type>zip</type>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
@ -54,6 +55,9 @@ import static java.util.Objects.requireNonNull;
|
|||
* long as instance of this class is not closed. Subsequent execution requests over same installation home are cached.
|
||||
*/
|
||||
public class EmbeddedMavenExecutor implements Executor {
|
||||
protected static final Map<String, String> MAIN_CLASSES =
|
||||
Map.of("mvn", "org.apache.maven.cling.MavenCling", "mvnenc", "org.apache.maven.cling.MavenEncCling");
|
||||
|
||||
protected static final class Context {
|
||||
private final URLClassLoader bootClassLoader;
|
||||
private final String version;
|
||||
|
@ -62,7 +66,7 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
private final ClassLoader tccl;
|
||||
private final Function<ExecutorRequest, Integer> exec;
|
||||
|
||||
public Context(
|
||||
private Context(
|
||||
URLClassLoader bootClassLoader,
|
||||
String version,
|
||||
Object classWorld,
|
||||
|
@ -78,13 +82,38 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
}
|
||||
}
|
||||
|
||||
protected static class Key {
|
||||
private final Path installationDirectory;
|
||||
private final String command;
|
||||
|
||||
private Key(Path installationDirectory, String command) {
|
||||
this.installationDirectory = installationDirectory;
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Key key = (Key) o;
|
||||
return Objects.equals(installationDirectory, key.installationDirectory)
|
||||
&& Objects.equals(command, key.command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(installationDirectory, command);
|
||||
}
|
||||
}
|
||||
|
||||
protected final boolean cacheContexts;
|
||||
protected final AtomicBoolean closed;
|
||||
protected final PrintStream originalStdout;
|
||||
protected final PrintStream originalStderr;
|
||||
protected final Properties originalProperties;
|
||||
protected final ClassLoader originalClassLoader;
|
||||
protected final ConcurrentHashMap<Path, Context> contexts;
|
||||
protected final ConcurrentHashMap<Key, Context> contexts;
|
||||
|
||||
public EmbeddedMavenExecutor() {
|
||||
this(true);
|
||||
|
@ -163,8 +192,10 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
|
||||
protected Context mayCreate(ExecutorRequest executorRequest) {
|
||||
Path mavenHome = ExecutorRequest.getCanonicalPath(executorRequest.installationDirectory());
|
||||
String command = executorRequest.command();
|
||||
Key key = new Key(mavenHome, command);
|
||||
if (cacheContexts) {
|
||||
return contexts.computeIfAbsent(mavenHome, k -> doCreate(mavenHome, executorRequest));
|
||||
return contexts.computeIfAbsent(key, k -> doCreate(mavenHome, executorRequest));
|
||||
} else {
|
||||
return doCreate(mavenHome, executorRequest);
|
||||
}
|
||||
|
@ -172,9 +203,9 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
|
||||
protected Context doCreate(Path mavenHome, ExecutorRequest executorRequest) {
|
||||
if (!Files.isDirectory(mavenHome)) {
|
||||
throw new IllegalArgumentException("Installation directory must point to existing directory");
|
||||
throw new IllegalArgumentException("Installation directory must point to existing directory: " + mavenHome);
|
||||
}
|
||||
if (!Objects.equals(executorRequest.command(), ExecutorRequest.MVN)) {
|
||||
if (!MAIN_CLASSES.containsKey(executorRequest.command())) {
|
||||
throw new IllegalArgumentException(
|
||||
getClass().getSimpleName() + " does not support command " + executorRequest.command());
|
||||
}
|
||||
|
@ -187,7 +218,8 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
Path boot = mavenHome.resolve("boot");
|
||||
Path m2conf = mavenHome.resolve("bin/m2.conf");
|
||||
if (!Files.isDirectory(boot) || !Files.isRegularFile(m2conf)) {
|
||||
throw new IllegalArgumentException("Installation directory does not point to Maven installation");
|
||||
throw new IllegalArgumentException(
|
||||
"Installation directory does not point to Maven installation: " + mavenHome);
|
||||
}
|
||||
|
||||
Properties properties = prepareProperties(executorRequest);
|
||||
|
@ -220,6 +252,10 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
|
||||
if (version.startsWith("3.")) {
|
||||
// 3.x
|
||||
if (!ExecutorRequest.MVN.equals(executorRequest.command())) {
|
||||
throw new IllegalArgumentException(getClass().getSimpleName() + "w/ mvn3 does not support command "
|
||||
+ executorRequest.command());
|
||||
}
|
||||
Constructor<?> newMavenCli = cliClass.getConstructor(classWorld.getClass());
|
||||
Object mavenCli = newMavenCli.newInstance(classWorld);
|
||||
Class<?>[] parameterTypes = {String[].class, String.class, PrintStream.class, PrintStream.class};
|
||||
|
@ -284,7 +320,8 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
properties.setProperty("maven.home", mavenHome.toString());
|
||||
properties.setProperty(
|
||||
"maven.multiModuleProjectDirectory", request.cwd().toString());
|
||||
properties.setProperty("maven.mainClass", "org.apache.maven.cling.MavenCling");
|
||||
String mainClass = requireNonNull(MAIN_CLASSES.get(request.command()), "mainClass");
|
||||
properties.setProperty("maven.mainClass", mainClass);
|
||||
properties.setProperty(
|
||||
"library.jline.path", mavenHome.resolve("lib/jline-native").toString());
|
||||
// TODO: is this needed?
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.nio.file.Path;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.maven.api.annotations.Nullable;
|
||||
|
@ -112,8 +111,7 @@ public class HelperImpl implements ExecutorHelper {
|
|||
}
|
||||
|
||||
private Executor getExecutorByRequest(ExecutorRequest request) {
|
||||
if (Objects.equals(request.command(), ExecutorRequest.MVN)
|
||||
&& request.environmentVariables().orElse(Collections.emptyMap()).isEmpty()
|
||||
if (request.environmentVariables().orElse(Collections.emptyMap()).isEmpty()
|
||||
&& request.jvmArguments().orElse(Collections.emptyList()).isEmpty()) {
|
||||
return getExecutor(Mode.EMBEDDED, request);
|
||||
} else {
|
||||
|
|
|
@ -35,6 +35,25 @@ import org.junit.jupiter.api.io.TempDir;
|
|||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public abstract class MavenExecutorTestSupport {
|
||||
@Test
|
||||
void mvnenc(
|
||||
@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path cwd,
|
||||
@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path userHome)
|
||||
throws Exception {
|
||||
String logfile = "m4.log";
|
||||
execute(
|
||||
cwd.resolve(logfile),
|
||||
List.of(mvn4ExecutorRequestBuilder()
|
||||
.command("mvnenc")
|
||||
.cwd(cwd)
|
||||
.userHomeDirectory(userHome)
|
||||
.argument("diag")
|
||||
.argument("-l")
|
||||
.argument(logfile)
|
||||
.build()));
|
||||
System.out.println(Files.readString(cwd.resolve(logfile)));
|
||||
}
|
||||
|
||||
@Disabled("JUnit on Windows fails to clean up as mvn3 seems does not close log file properly")
|
||||
@Test
|
||||
void dump3(
|
||||
|
|
|
@ -715,7 +715,7 @@ under the License.
|
|||
<unzip dest="${mavenHome}" src="${project.build.directory}/maven-bin.zip">
|
||||
<globmapper from="apache-maven-${mavenVersion}/*" handledirsep="true" to="*" />
|
||||
</unzip>
|
||||
<chmod dir="${mavenHome}/bin" includes="mvn,mvnDebug" perm="ugo+rx" />
|
||||
<chmod dir="${mavenHome}/bin" includes="mvn,mvnDebug,mvnenc" perm="ugo+rx" />
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -758,7 +758,7 @@ under the License.
|
|||
<unzip dest="${mavenHome}" src="${mavenDistro}">
|
||||
<regexpmapper from="^([^/]+)/(.*)$" handledirsep="true" to="\2" />
|
||||
</unzip>
|
||||
<chmod dir="${mavenHome}/bin" includes="mvn,mvnDebug" perm="ugo+rx" />
|
||||
<chmod dir="${mavenHome}/bin" includes="mvn,mvnDebug,mvnenc" perm="ugo+rx" />
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.it;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* This is a test set for <a href="https://issues.apache.org/jira/browse/MNG-8421">MNG-8421</a>.
|
||||
*/
|
||||
class MavenITmng8421MavenEncryptionTest extends AbstractMavenIntegrationTestCase {
|
||||
|
||||
MavenITmng8421MavenEncryptionTest() {
|
||||
super("[4.0.0-rc-2-SNAPSHOT,)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that empty home causes diag output as expected.
|
||||
*/
|
||||
@Test
|
||||
void testEmptyHome() throws Exception {
|
||||
Path basedir = extractResources("/mng-8421").getAbsoluteFile().toPath();
|
||||
|
||||
Path home = basedir.resolve("home1");
|
||||
|
||||
Verifier verifier = newVerifier(basedir.toString());
|
||||
verifier.setLogFileName("home1.txt");
|
||||
verifier.setUserHomeDirectory(home);
|
||||
verifier.setExecutable("mvnenc");
|
||||
verifier.addCliArgument("diag");
|
||||
verifier.execute();
|
||||
verifier.verifyTextInLog("[ERROR]");
|
||||
verifier.verifyTextInLog("No configuration file found");
|
||||
verifier.verifyTextInLog("settings-security4.xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that set-upo home causes diag output as expected.
|
||||
*/
|
||||
@Test
|
||||
void testSetupHome() throws Exception {
|
||||
Path basedir = extractResources("/mng-8421").getAbsoluteFile().toPath();
|
||||
|
||||
Path home = basedir.resolve("home2");
|
||||
|
||||
Verifier verifier = newVerifier(basedir.toString());
|
||||
verifier.setLogFileName("home2.txt");
|
||||
verifier.setUserHomeDirectory(home);
|
||||
verifier.setExecutable("mvnenc");
|
||||
verifier.addCliArgument("diag");
|
||||
verifier.execute();
|
||||
verifier.verifyErrorFreeLog();
|
||||
verifier.verifyTextInLog("[INFO] Configuration validation of MavenSecDispatcher: VALID");
|
||||
verifier.verifyTextInLog("[WARNING] Configured environment variable not exist");
|
||||
}
|
||||
}
|
|
@ -100,6 +100,7 @@ public class TestSuiteOrdering implements ClassOrderer {
|
|||
* the tests are to finishing. Newer tests are also more likely to fail, so this is
|
||||
* a fail fast technique as well.
|
||||
*/
|
||||
suite.addTestSuite(MavenITmng8421MavenEncryptionTest.class);
|
||||
suite.addTestSuite(MavenITmng8400CanonicalMavenHomeTest.class);
|
||||
suite.addTestSuite(MavenITmng8385PropertyContributoSPITest.class);
|
||||
suite.addTestSuite(MavenITmng8383UnknownTypeDependenciesTest.class);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
This is an empty home
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<settingsSecurity>
|
||||
<!-- created with Maven 3.9.9: "masterpassword" -->
|
||||
<master>{biSS3+PaKIMH9acY9wBZjfuzSTrkkrXjgDa7jWvW+ew=}</master>
|
||||
</settingsSecurity>
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<settingsSecurity xmlns="http://codehaus-plexus.github.io/plexus-sec-dispatcher/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://codehaus-plexus.github.io/plexus-sec-dispatcher/4.0.0 https://codehaus-plexus.github.io/xsd/plexus-sec-dispatcher-4.0.0.xsd">
|
||||
<modelVersion>4.0</modelVersion>
|
||||
<defaultDispatcher>master</defaultDispatcher>
|
||||
<configurations>
|
||||
<configuration>
|
||||
<name>master</name>
|
||||
<properties>
|
||||
<property>
|
||||
<name>source</name>
|
||||
<value>env:MAVEN_MASTER_PASSWORD</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>cipher</name>
|
||||
<value>AES/GCM/NoPadding</value>
|
||||
</property>
|
||||
</properties>
|
||||
</configuration>
|
||||
</configurations>
|
||||
</settingsSecurity>
|
|
@ -0,0 +1 @@
|
|||
This is fully setup home
|
|
@ -92,7 +92,7 @@ public class Verifier {
|
|||
|
||||
private final Path tempBasedir; // empty basedir for queries
|
||||
|
||||
private final Path userHomeDirectory;
|
||||
private Path userHomeDirectory;
|
||||
|
||||
private final List<String> defaultCliArguments;
|
||||
|
||||
|
@ -102,6 +102,8 @@ public class Verifier {
|
|||
|
||||
private final List<String> cliArguments = new ArrayList<>();
|
||||
|
||||
private String executable = ExecutorRequest.MVN;
|
||||
|
||||
private boolean autoClean = true;
|
||||
|
||||
private boolean forkJvm = false;
|
||||
|
@ -144,8 +146,16 @@ public class Verifier {
|
|||
}
|
||||
}
|
||||
|
||||
public void setUserHomeDirectory(Path userHomeDirectory) {
|
||||
this.userHomeDirectory = requireNonNull(userHomeDirectory);
|
||||
}
|
||||
|
||||
public String getExecutable() {
|
||||
return ExecutorRequest.MVN;
|
||||
return executable;
|
||||
}
|
||||
|
||||
public void setExecutable(String executable) {
|
||||
this.executable = requireNonNull(executable);
|
||||
}
|
||||
|
||||
public void execute() throws VerificationException {
|
||||
|
@ -221,6 +231,7 @@ public class Verifier {
|
|||
try {
|
||||
ExecutorRequest.Builder builder = executorHelper
|
||||
.executorRequest()
|
||||
.command(executable)
|
||||
.cwd(basedir)
|
||||
.userHomeDirectory(userHomeDirectory)
|
||||
.arguments(args);
|
||||
|
|
Loading…
Reference in New Issue