mirror of https://github.com/apache/maven.git
[MNG-8437] mvnsh (#1982)
Maven shell Changes: * (unrelated) contains fix for property handling in embedded executor and in lookup invoker * pulled `-o` (offline) option to "generic" Options from MavenOptions * introduce mvnsh (scripts, options, CLIng main class) * simplified invokers (only one context needed for maven now) * invokers made "reentrant", it all depends HOW context is created Related PRs: * mvnd changes https://github.com/apache/maven-mvnd/pull/1228 --- https://issues.apache.org/jira/browse/MNG-8437
This commit is contained in:
parent
d9dcac85d9
commit
49825e6dba
|
@ -86,6 +86,7 @@ under the License.
|
|||
<includes>
|
||||
<include>mvn</include>
|
||||
<include>mvnenc</include>
|
||||
<include>mvnsh</include>
|
||||
<include>mvnDebug</include>
|
||||
<include>mvnencDebug</include>
|
||||
<!-- This is so that CI systems can periodically run the profiler -->
|
||||
|
|
|
@ -207,6 +207,9 @@ handle_args() {
|
|||
--enc)
|
||||
MAVEN_MAIN_CLASS="org.apache.maven.cling.MavenEncCling"
|
||||
;;
|
||||
--shell)
|
||||
MAVEN_MAIN_CLASS="org.apache.maven.cling.MavenShellCling"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -200,6 +200,8 @@ if "%~1"=="--debug" (
|
|||
set "MAVEN_OPTS=-agentpath:%YJPLIB%=onexit=snapshot,onexit=memory,tracing,onlylocal %MAVEN_OPTS%"
|
||||
) else if "%~1"=="--enc" (
|
||||
set "MAVEN_MAIN_CLASS=org.apache.maven.cling.MavenEncCling"
|
||||
) else if "%~1"=="--shell" (
|
||||
set "MAVEN_MAIN_CLASS=org.apache.maven.cling.MavenShellCling"
|
||||
)
|
||||
exit /b 0
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/sh
|
||||
|
||||
# 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.
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Apache Maven Encrypt Script
|
||||
#
|
||||
# Environment Variable Prerequisites
|
||||
#
|
||||
# JAVA_HOME (Optional) Points to a Java installation.
|
||||
# MAVEN_OPTS (Optional) Java runtime options used when Maven is executed.
|
||||
# MAVEN_SKIP_RC (Optional) Flag to disable loading of mavenrc files.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
"`dirname "$0"`/mvn" --shell "$@"
|
|
@ -0,0 +1,39 @@
|
|||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
|
||||
@REM -----------------------------------------------------------------------------
|
||||
@REM Apache Maven Encrypt Script
|
||||
@REM
|
||||
@REM Environment Variable Prerequisites
|
||||
@REM
|
||||
@REM JAVA_HOME (Optional) Points to a Java installation.
|
||||
@REM MAVEN_BATCH_ECHO (Optional) Set to 'on' to enable the echoing of the batch commands.
|
||||
@REM MAVEN_BATCH_PAUSE (Optional) set to 'on' to wait for a key stroke before ending.
|
||||
@REM MAVEN_OPTS (Optional) Java runtime options used when Maven is executed.
|
||||
@REM MAVEN_SKIP_RC (Optional) Flag to disable loading of mavenrc files.
|
||||
@REM -----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%"=="on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@setlocal
|
||||
|
||||
@call "%~dp0"mvn.cmd --shell %*
|
|
@ -182,6 +182,14 @@ public interface Options {
|
|||
@Nonnull
|
||||
Optional<String> color();
|
||||
|
||||
/**
|
||||
* Indicates whether Maven should operate in offline mode.
|
||||
*
|
||||
* @return an {@link Optional} containing true if offline mode is enabled, false if disabled, or empty if not specified
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<Boolean> offline();
|
||||
|
||||
/**
|
||||
* Indicates whether to show help information.
|
||||
*
|
||||
|
|
|
@ -205,6 +205,34 @@ public interface ParserRequest {
|
|||
return builder(Tools.MVNENC_CMD, Tools.MVNENC_NAME, args, logger, messageBuilderFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Builder instance for constructing a Maven Shell 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 mvnsh(
|
||||
@Nonnull String[] args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
|
||||
return mvnsh(Arrays.asList(args), logger, messageBuilderFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Builder instance for constructing a Maven Shell 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 mvnsh(
|
||||
@Nonnull List<String> args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
|
||||
return builder(Tools.MVNSHELL_CMD, Tools.MVNSHELL_NAME, args, logger, messageBuilderFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Builder instance for constructing a ParserRequest.
|
||||
*
|
||||
|
|
|
@ -36,4 +36,7 @@ public final class Tools {
|
|||
|
||||
public static final String MVNENC_CMD = "mvnenc";
|
||||
public static final String MVNENC_NAME = "Maven Password Encrypting Tool";
|
||||
|
||||
public static final String MVNSHELL_CMD = "mvnsh";
|
||||
public static final String MVNSHELL_NAME = "Maven Shell Tool";
|
||||
}
|
||||
|
|
|
@ -48,14 +48,6 @@ public interface MavenOptions extends Options {
|
|||
@Nonnull
|
||||
Optional<String> alternatePomFile();
|
||||
|
||||
/**
|
||||
* Indicates whether Maven should operate in offline mode.
|
||||
*
|
||||
* @return an {@link Optional} containing true if offline mode is enabled, false if disabled, or empty if not specified
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<Boolean> offline();
|
||||
|
||||
/**
|
||||
* Indicates whether Maven should operate in non-recursive mode (i.e., not build child modules).
|
||||
*
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.api.cli.mvnsh;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.api.annotations.Experimental;
|
||||
import org.apache.maven.api.annotations.Nonnull;
|
||||
import org.apache.maven.api.cli.Options;
|
||||
|
||||
/**
|
||||
* Defines the options specific to the Maven Shell tool.
|
||||
* This interface extends the general {@link Options} interface, adding shell-specific configuration options.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Experimental
|
||||
public interface ShellOptions extends Options {
|
||||
/**
|
||||
* Returns a new instance of ShellOptions with values interpolated using the given properties.
|
||||
*
|
||||
* @param properties a collection of property maps to use for interpolation
|
||||
* @return a new EncryptOptions instance with interpolated values
|
||||
*/
|
||||
@Nonnull
|
||||
ShellOptions interpolate(Collection<Map<String, String>> properties);
|
||||
}
|
|
@ -26,8 +26,8 @@ import org.apache.maven.api.cli.ParserException;
|
|||
import org.apache.maven.api.cli.ParserRequest;
|
||||
import org.apache.maven.cling.invoker.ProtoLogger;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenInvoker;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenParser;
|
||||
import org.apache.maven.cling.invoker.mvn.local.LocalMavenInvoker;
|
||||
import org.apache.maven.jline.JLineMessageBuilderFactory;
|
||||
import org.codehaus.plexus.classworlds.ClassWorld;
|
||||
|
||||
|
@ -61,7 +61,7 @@ public class MavenCling extends ClingSupport {
|
|||
|
||||
@Override
|
||||
protected Invoker createInvoker() {
|
||||
return new LocalMavenInvoker(
|
||||
return new MavenInvoker(
|
||||
ProtoLookup.builder().addMapping(ClassWorld.class, classWorld).build());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.maven.api.cli.Invoker;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.api.cli.ParserException;
|
||||
import org.apache.maven.api.cli.ParserRequest;
|
||||
import org.apache.maven.cling.invoker.ProtoLogger;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.cling.invoker.mvnsh.ShellInvoker;
|
||||
import org.apache.maven.cling.invoker.mvnsh.ShellParser;
|
||||
import org.apache.maven.jline.JLineMessageBuilderFactory;
|
||||
import org.codehaus.plexus.classworlds.ClassWorld;
|
||||
|
||||
/**
|
||||
* Maven shell.
|
||||
*/
|
||||
public class MavenShellCling extends ClingSupport {
|
||||
/**
|
||||
* "Normal" Java entry point. Note: Maven uses ClassWorld Launcher and this entry point is NOT used under normal
|
||||
* circumstances.
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
int exitCode = new MavenShellCling().run(args);
|
||||
System.exit(exitCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* ClassWorld Launcher "enhanced" entry point: returning exitCode and accepts Class World.
|
||||
*/
|
||||
public static int main(String[] args, ClassWorld world) throws IOException {
|
||||
return new MavenShellCling(world).run(args);
|
||||
}
|
||||
|
||||
public MavenShellCling() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MavenShellCling(ClassWorld classWorld) {
|
||||
super(classWorld);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Invoker createInvoker() {
|
||||
return new ShellInvoker(
|
||||
ProtoLookup.builder().addMapping(ClassWorld.class, classWorld).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InvokerRequest parseArguments(String[] args) throws ParserException, IOException {
|
||||
return new ShellParser()
|
||||
.parseInvocation(ParserRequest.mvnsh(args, new ProtoLogger(), new JLineMessageBuilderFactory())
|
||||
.build());
|
||||
}
|
||||
}
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.apache.maven.cling.extensions;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -33,7 +30,10 @@ import java.util.stream.Collectors;
|
|||
import org.apache.maven.RepositoryUtils;
|
||||
import org.apache.maven.api.Service;
|
||||
import org.apache.maven.api.Session;
|
||||
import org.apache.maven.api.annotations.Nullable;
|
||||
import org.apache.maven.api.cli.extensions.CoreExtension;
|
||||
import org.apache.maven.api.di.Inject;
|
||||
import org.apache.maven.api.di.Named;
|
||||
import org.apache.maven.api.model.Plugin;
|
||||
import org.apache.maven.api.services.ArtifactCoordinatesFactory;
|
||||
import org.apache.maven.api.services.ArtifactManager;
|
||||
|
@ -80,7 +80,6 @@ import org.eclipse.aether.resolution.ArtifactResult;
|
|||
import org.eclipse.aether.resolution.DependencyResult;
|
||||
import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
|
||||
import org.eclipse.aether.util.version.GenericVersionScheme;
|
||||
import org.eclipse.sisu.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
|
@ -202,6 +202,14 @@ public abstract class CommonsCliOptions implements Options {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Boolean> offline() {
|
||||
if (commandLine.hasOption(CLIManager.OFFLINE)) {
|
||||
return Optional.of(Boolean.TRUE);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Boolean> help() {
|
||||
if (commandLine.hasOption(CLIManager.HELP)) {
|
||||
|
@ -267,11 +275,13 @@ public abstract class CommonsCliOptions implements Options {
|
|||
public static final String LOG_FILE = "l";
|
||||
public static final String RAW_STREAMS = "raw-streams";
|
||||
public static final String COLOR = "color";
|
||||
public static final String OFFLINE = "o";
|
||||
public static final String HELP = "h";
|
||||
|
||||
// parameters handled by script
|
||||
public static final String DEBUG = "debug";
|
||||
public static final String ENC = "enc";
|
||||
public static final String SHELL = "shell";
|
||||
public static final String YJP = "yjp";
|
||||
|
||||
// deprecated ones
|
||||
|
@ -378,6 +388,10 @@ public abstract class CommonsCliOptions implements Options {
|
|||
.optionalArg(true)
|
||||
.desc("Defines the color mode of the output. Supported are 'auto', 'always', 'never'.")
|
||||
.build());
|
||||
options.addOption(Option.builder(OFFLINE)
|
||||
.longOpt("offline")
|
||||
.desc("Work offline")
|
||||
.build());
|
||||
|
||||
// Parameters handled by script
|
||||
options.addOption(Option.builder()
|
||||
|
@ -388,6 +402,10 @@ public abstract class CommonsCliOptions implements Options {
|
|||
.longOpt(ENC)
|
||||
.desc("Launch the Maven Encryption tool (script option).")
|
||||
.build());
|
||||
options.addOption(Option.builder()
|
||||
.longOpt(SHELL)
|
||||
.desc("Launch the Maven Shell tool (script option).")
|
||||
.build());
|
||||
options.addOption(Option.builder()
|
||||
.longOpt(YJP)
|
||||
.desc("Launch the JVM with Yourkit profiler (script option).")
|
||||
|
|
|
@ -132,6 +132,11 @@ public abstract class LayeredOptions<O extends Options> implements Options {
|
|||
return returnFirstPresentOrEmpty(Options::color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Boolean> offline() {
|
||||
return returnFirstPresentOrEmpty(Options::offline);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Boolean> help() {
|
||||
return returnFirstPresentOrEmpty(Options::help);
|
||||
|
|
|
@ -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.eventspy.internal.EventSpyDispatcher;
|
||||
import org.apache.maven.logging.BuildEventListener;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.slf4j.ILoggerFactory;
|
||||
|
@ -47,14 +48,20 @@ public class LookupContext implements AutoCloseable {
|
|||
public final Function<String, Path> cwdResolver;
|
||||
public final Function<String, Path> installationResolver;
|
||||
public final Function<String, Path> userResolver;
|
||||
public final boolean containerCapsuleManaged;
|
||||
|
||||
protected LookupContext(InvokerRequest invokerRequest) {
|
||||
public LookupContext(InvokerRequest invokerRequest) {
|
||||
this(invokerRequest, true);
|
||||
}
|
||||
|
||||
public LookupContext(InvokerRequest invokerRequest, boolean containerCapsuleManaged) {
|
||||
this.invokerRequest = requireNonNull(invokerRequest);
|
||||
this.cwdResolver = s -> invokerRequest.cwd().resolve(s).normalize().toAbsolutePath();
|
||||
this.installationResolver = s ->
|
||||
invokerRequest.installationDirectory().resolve(s).normalize().toAbsolutePath();
|
||||
this.userResolver =
|
||||
s -> invokerRequest.userHomeDirectory().resolve(s).normalize().toAbsolutePath();
|
||||
this.containerCapsuleManaged = containerCapsuleManaged;
|
||||
this.logger = invokerRequest.parserRequest().logger();
|
||||
|
||||
Map<String, String> user = new HashMap<>(invokerRequest.userProperties());
|
||||
|
@ -84,8 +91,10 @@ public class LookupContext implements AutoCloseable {
|
|||
public Boolean coloredOutput;
|
||||
public Terminal terminal;
|
||||
public Consumer<String> writer;
|
||||
|
||||
public ContainerCapsule containerCapsule;
|
||||
public Lookup lookup;
|
||||
public EventSpyDispatcher eventSpyDispatcher;
|
||||
|
||||
public BuildEventListener buildEventListener;
|
||||
|
||||
|
@ -93,7 +102,6 @@ public class LookupContext implements AutoCloseable {
|
|||
public Path installationSettingsPath;
|
||||
public Path projectSettingsPath;
|
||||
public Path userSettingsPath;
|
||||
|
||||
public boolean interactive;
|
||||
public Path localRepositoryPath;
|
||||
public Settings effectiveSettings;
|
||||
|
@ -124,11 +132,18 @@ public class LookupContext implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
protected void closeContainer() {
|
||||
public final void closeContainer() {
|
||||
if (containerCapsuleManaged) {
|
||||
doCloseContainer();
|
||||
}
|
||||
}
|
||||
|
||||
public void doCloseContainer() {
|
||||
if (containerCapsule != null) {
|
||||
try {
|
||||
containerCapsule.close();
|
||||
} finally {
|
||||
eventSpyDispatcher = null;
|
||||
lookup = null;
|
||||
containerCapsule = null;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.PrintWriter;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -34,6 +35,7 @@ import java.util.function.Function;
|
|||
|
||||
import org.apache.maven.api.Constants;
|
||||
import org.apache.maven.api.ProtoSession;
|
||||
import org.apache.maven.api.annotations.Nullable;
|
||||
import org.apache.maven.api.cli.Invoker;
|
||||
import org.apache.maven.api.cli.InvokerException;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
|
@ -65,6 +67,7 @@ import org.apache.maven.cling.invoker.spi.PropertyContributorsHolder;
|
|||
import org.apache.maven.cling.logging.Slf4jConfiguration;
|
||||
import org.apache.maven.cling.logging.Slf4jConfigurationFactory;
|
||||
import org.apache.maven.cling.utils.CLIReportingUtils;
|
||||
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
|
||||
import org.apache.maven.execution.MavenExecutionRequest;
|
||||
import org.apache.maven.internal.impl.SettingsUtilsV4;
|
||||
import org.apache.maven.jline.FastTerminal;
|
||||
|
@ -75,6 +78,7 @@ 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.codehaus.plexus.PlexusContainer;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.terminal.TerminalBuilder;
|
||||
import org.jline.terminal.impl.AbstractPosixTerminal;
|
||||
|
@ -92,19 +96,27 @@ import static org.apache.maven.cling.invoker.Utils.toProperties;
|
|||
* @param <C> The context type.
|
||||
*/
|
||||
public abstract class LookupInvoker<C extends LookupContext> implements Invoker {
|
||||
protected final ProtoLookup protoLookup;
|
||||
protected final Lookup protoLookup;
|
||||
|
||||
public LookupInvoker(ProtoLookup protoLookup) {
|
||||
@Nullable
|
||||
protected final Consumer<LookupContext> contextConsumer;
|
||||
|
||||
public LookupInvoker(Lookup protoLookup, @Nullable Consumer<LookupContext> contextConsumer) {
|
||||
this.protoLookup = requireNonNull(protoLookup);
|
||||
this.contextConsumer = contextConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int invoke(InvokerRequest invokerRequest) throws InvokerException {
|
||||
requireNonNull(invokerRequest);
|
||||
|
||||
Properties oldProps = (Properties) System.getProperties().clone();
|
||||
Properties oldProps = new Properties();
|
||||
oldProps.putAll(System.getProperties());
|
||||
ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
|
||||
try (C context = createContext(invokerRequest)) {
|
||||
if (contextConsumer != null) {
|
||||
contextConsumer.accept(context);
|
||||
}
|
||||
try {
|
||||
if (context.containerCapsule != null
|
||||
&& context.containerCapsule.currentThreadClassLoader().isPresent()) {
|
||||
|
@ -128,8 +140,6 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
|||
protected int doInvoke(C context) throws Exception {
|
||||
pushCoreProperties(context);
|
||||
pushUserProperties(context);
|
||||
validate(context);
|
||||
prepare(context);
|
||||
configureLogging(context);
|
||||
createTerminal(context);
|
||||
activateLogging(context);
|
||||
|
@ -192,10 +202,6 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
|||
}
|
||||
}
|
||||
|
||||
protected void validate(C context) throws Exception {}
|
||||
|
||||
protected void prepare(C context) throws Exception {}
|
||||
|
||||
protected void configureLogging(C context) throws Exception {
|
||||
// LOG COLOR
|
||||
Options mavenOptions = context.invokerRequest.options();
|
||||
|
@ -251,33 +257,40 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
|||
}
|
||||
|
||||
protected void createTerminal(C context) {
|
||||
MessageUtils.systemInstall(
|
||||
builder -> {
|
||||
builder.streams(
|
||||
context.invokerRequest.in().orElse(null),
|
||||
context.invokerRequest.out().orElse(null));
|
||||
builder.systemOutput(TerminalBuilder.SystemOutput.ForcedSysOut);
|
||||
// The exec builder suffers from https://github.com/jline/jline3/issues/1098
|
||||
// We could re-enable it when fixed to provide support for non-standard architectures,
|
||||
// for which JLine does not provide any native library.
|
||||
builder.exec(false);
|
||||
if (context.coloredOutput != null) {
|
||||
builder.color(context.coloredOutput);
|
||||
}
|
||||
},
|
||||
terminal -> doConfigureWithTerminal(context, terminal));
|
||||
if (context.terminal == null) {
|
||||
MessageUtils.systemInstall(
|
||||
builder -> {
|
||||
builder.streams(
|
||||
context.invokerRequest.in().orElse(null),
|
||||
context.invokerRequest.out().orElse(null));
|
||||
builder.systemOutput(TerminalBuilder.SystemOutput.ForcedSysOut);
|
||||
// The exec builder suffers from https://github.com/jline/jline3/issues/1098
|
||||
// We could re-enable it when fixed to provide support for non-standard architectures,
|
||||
// for which JLine does not provide any native library.
|
||||
builder.exec(false);
|
||||
if (context.coloredOutput != null) {
|
||||
builder.color(context.coloredOutput);
|
||||
}
|
||||
},
|
||||
terminal -> doConfigureWithTerminal(context, terminal));
|
||||
|
||||
context.terminal = MessageUtils.getTerminal();
|
||||
// JLine is quite slow to start due to the native library unpacking and loading
|
||||
// so boot it asynchronously
|
||||
context.closeables.add(MessageUtils::systemUninstall);
|
||||
MessageUtils.registerShutdownHook(); // safety belt
|
||||
if (context.coloredOutput != null) {
|
||||
MessageUtils.setColorEnabled(context.coloredOutput);
|
||||
context.terminal = MessageUtils.getTerminal();
|
||||
// JLine is quite slow to start due to the native library unpacking and loading
|
||||
// so boot it asynchronously
|
||||
context.closeables.add(MessageUtils::systemUninstall);
|
||||
MessageUtils.registerShutdownHook(); // safety belt
|
||||
if (context.coloredOutput != null) {
|
||||
MessageUtils.setColorEnabled(context.coloredOutput);
|
||||
}
|
||||
} else {
|
||||
if (context.coloredOutput != null) {
|
||||
MessageUtils.setColorEnabled(context.coloredOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void doConfigureWithTerminal(C context, Terminal terminal) {
|
||||
context.terminal = terminal;
|
||||
Options options = context.invokerRequest.options();
|
||||
if (options.rawStreams().isEmpty() || !options.rawStreams().get()) {
|
||||
MavenSimpleLogger stdout = (MavenSimpleLogger) context.loggerFactory.getLogger("stdout");
|
||||
|
@ -406,15 +419,13 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
|||
}
|
||||
|
||||
protected void container(C context) throws Exception {
|
||||
context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(this, context);
|
||||
context.closeables.add(context::closeContainer);
|
||||
context.lookup = context.containerCapsule.getLookup();
|
||||
|
||||
// refresh logger in case container got customized by spy
|
||||
org.slf4j.Logger l = context.loggerFactory.getLogger(this.getClass().getName());
|
||||
context.logger = (level, message, error) -> l.atLevel(org.slf4j.event.Level.valueOf(level.name()))
|
||||
.setCause(error)
|
||||
.log(message);
|
||||
if (context.lookup == null) {
|
||||
context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(this, context);
|
||||
context.closeables.add(context::closeContainer);
|
||||
context.lookup = context.containerCapsule.getLookup();
|
||||
} else {
|
||||
context.containerCapsule.updateLogging(context);
|
||||
}
|
||||
}
|
||||
|
||||
protected ContainerCapsuleFactory<C> createContainerCapsuleFactory() {
|
||||
|
@ -434,9 +445,22 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
|||
context.protoSession = protoSession;
|
||||
}
|
||||
|
||||
protected void lookup(C context) throws Exception {}
|
||||
protected void lookup(C context) throws Exception {
|
||||
if (context.eventSpyDispatcher == null) {
|
||||
context.eventSpyDispatcher = context.lookup.lookup(EventSpyDispatcher.class);
|
||||
}
|
||||
}
|
||||
|
||||
protected void init(C context) throws Exception {}
|
||||
protected void init(C context) throws Exception {
|
||||
InvokerRequest invokerRequest = context.invokerRequest;
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("plexus", context.lookup.lookup(PlexusContainer.class));
|
||||
data.put("workingDirectory", invokerRequest.cwd().toString());
|
||||
data.put("systemProperties", toProperties(context.protoSession.getSystemProperties()));
|
||||
data.put("userProperties", toProperties(context.protoSession.getUserProperties()));
|
||||
data.put("versionProperties", CLIReportingUtils.getBuildProperties());
|
||||
context.eventSpyDispatcher.init(() -> data);
|
||||
}
|
||||
|
||||
protected void postCommands(C context) throws Exception {
|
||||
InvokerRequest invokerRequest = context.invokerRequest;
|
||||
|
@ -465,7 +489,9 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
|||
}
|
||||
|
||||
protected void settings(C context) throws Exception {
|
||||
settings(context, true, context.lookup.lookup(SettingsBuilder.class));
|
||||
if (context.effectiveSettings == null) {
|
||||
settings(context, true, context.lookup.lookup(SettingsBuilder.class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -553,6 +579,9 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
|||
.build();
|
||||
|
||||
customizeSettingsRequest(context, settingsRequest);
|
||||
if (context.eventSpyDispatcher != null) {
|
||||
context.eventSpyDispatcher.onEvent(settingsRequest);
|
||||
}
|
||||
|
||||
context.logger.debug("Reading installation settings from '" + installationSettingsFile + "'");
|
||||
context.logger.debug("Reading project settings from '" + projectSettingsFile + "'");
|
||||
|
@ -560,6 +589,9 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
|||
|
||||
SettingsBuilderResult settingsResult = settingsBuilder.build(settingsRequest);
|
||||
customizeSettingsResult(context, settingsResult);
|
||||
if (context.eventSpyDispatcher != null) {
|
||||
context.eventSpyDispatcher.onEvent(settingsResult);
|
||||
}
|
||||
|
||||
context.effectiveSettings = settingsResult.getEffectiveSettings();
|
||||
context.interactive = mayDisableInteractiveMode(context, context.effectiveSettings.isInteractiveMode());
|
||||
|
|
|
@ -79,14 +79,6 @@ public class CommonsCliMavenOptions extends CommonsCliOptions implements MavenOp
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Boolean> offline() {
|
||||
if (commandLine.hasOption(CLIManager.OFFLINE)) {
|
||||
return Optional.of(Boolean.TRUE);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Boolean> nonRecursive() {
|
||||
if (commandLine.hasOption(CLIManager.NON_RECURSIVE)) {
|
||||
|
@ -263,7 +255,6 @@ public class CommonsCliMavenOptions extends CommonsCliOptions implements MavenOp
|
|||
|
||||
protected static class CLIManager extends CommonsCliOptions.CLIManager {
|
||||
public static final String ALTERNATE_POM_FILE = "f";
|
||||
public static final String OFFLINE = "o";
|
||||
public static final String NON_RECURSIVE = "N";
|
||||
public static final String UPDATE_SNAPSHOTS = "U";
|
||||
public static final String ACTIVATE_PROFILES = "P";
|
||||
|
@ -293,10 +284,6 @@ public class CommonsCliMavenOptions extends CommonsCliOptions implements MavenOp
|
|||
.hasArg()
|
||||
.desc("Force the use of an alternate POM file (or directory with pom.xml)")
|
||||
.build());
|
||||
options.addOption(Option.builder(OFFLINE)
|
||||
.longOpt("offline")
|
||||
.desc("Work offline")
|
||||
.build());
|
||||
options.addOption(Option.builder(NON_RECURSIVE)
|
||||
.longOpt("non-recursive")
|
||||
.desc(
|
||||
|
|
|
@ -54,11 +54,6 @@ public class LayeredMavenOptions<O extends MavenOptions> extends LayeredOptions<
|
|||
return returnFirstPresentOrEmpty(MavenOptions::alternatePomFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Boolean> offline() {
|
||||
return returnFirstPresentOrEmpty(MavenOptions::offline);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Boolean> nonRecursive() {
|
||||
return returnFirstPresentOrEmpty(MavenOptions::nonRecursive);
|
||||
|
|
|
@ -21,21 +21,25 @@ package org.apache.maven.cling.invoker.mvn;
|
|||
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;
|
||||
|
||||
@SuppressWarnings("VisibilityModifier")
|
||||
public class MavenContext extends LookupContext {
|
||||
public MavenContext(InvokerRequest invokerRequest) {
|
||||
super(invokerRequest);
|
||||
this(invokerRequest, true);
|
||||
}
|
||||
|
||||
public MavenContext(InvokerRequest invokerRequest, boolean containerCapsuleManaged) {
|
||||
super(invokerRequest, containerCapsuleManaged);
|
||||
}
|
||||
|
||||
public EventSpyDispatcher eventSpyDispatcher;
|
||||
public Maven maven;
|
||||
|
||||
@Override
|
||||
protected void closeContainer() {
|
||||
eventSpyDispatcher = null;
|
||||
maven = null;
|
||||
super.closeContainer();
|
||||
public void doCloseContainer() {
|
||||
try {
|
||||
super.doCloseContainer();
|
||||
} finally {
|
||||
maven = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,10 @@ import java.io.FileNotFoundException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
|
@ -33,28 +33,26 @@ import org.apache.maven.InternalErrorException;
|
|||
import org.apache.maven.Maven;
|
||||
import org.apache.maven.api.Constants;
|
||||
import org.apache.maven.api.MonotonicClock;
|
||||
import org.apache.maven.api.annotations.Nullable;
|
||||
import org.apache.maven.api.cli.InvokerException;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.api.cli.Logger;
|
||||
import org.apache.maven.api.cli.mvn.MavenOptions;
|
||||
import org.apache.maven.api.services.BuilderProblem;
|
||||
import org.apache.maven.api.services.Lookup;
|
||||
import org.apache.maven.api.services.SettingsBuilderRequest;
|
||||
import org.apache.maven.api.services.SettingsBuilderResult;
|
||||
import org.apache.maven.api.services.Source;
|
||||
import org.apache.maven.api.services.ToolchainsBuilder;
|
||||
import org.apache.maven.api.services.ToolchainsBuilderRequest;
|
||||
import org.apache.maven.api.services.ToolchainsBuilderResult;
|
||||
import org.apache.maven.api.services.model.ModelProcessor;
|
||||
import org.apache.maven.cling.event.ExecutionEventLogger;
|
||||
import org.apache.maven.cling.invoker.LookupContext;
|
||||
import org.apache.maven.cling.invoker.LookupInvoker;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.cling.invoker.Utils;
|
||||
import org.apache.maven.cling.transfer.ConsoleMavenTransferListener;
|
||||
import org.apache.maven.cling.transfer.QuietMavenTransferListener;
|
||||
import org.apache.maven.cling.transfer.SimplexTransferListener;
|
||||
import org.apache.maven.cling.transfer.Slf4jMavenTransferListener;
|
||||
import org.apache.maven.cling.utils.CLIReportingUtils;
|
||||
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
|
||||
import org.apache.maven.exception.DefaultExceptionHandler;
|
||||
import org.apache.maven.exception.ExceptionHandler;
|
||||
import org.apache.maven.exception.ExceptionSummary;
|
||||
|
@ -70,25 +68,30 @@ import org.apache.maven.lifecycle.LifecycleExecutionException;
|
|||
import org.apache.maven.logging.LoggingExecutionListener;
|
||||
import org.apache.maven.logging.MavenTransferListener;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.codehaus.plexus.PlexusContainer;
|
||||
import org.eclipse.aether.DefaultRepositoryCache;
|
||||
import org.eclipse.aether.transfer.TransferListener;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static org.apache.maven.cling.invoker.Utils.toProperties;
|
||||
|
||||
/**
|
||||
* The "local" Maven invoker, that expects whole Maven on classpath and invokes it.
|
||||
*
|
||||
* @param <C> The context type.
|
||||
* The Maven invoker, that expects whole Maven on classpath and invokes it.
|
||||
*/
|
||||
public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker<C> {
|
||||
public MavenInvoker(ProtoLookup protoLookup) {
|
||||
super(protoLookup);
|
||||
public class MavenInvoker extends LookupInvoker<MavenContext> {
|
||||
public MavenInvoker(Lookup protoLookup) {
|
||||
this(protoLookup, null);
|
||||
}
|
||||
|
||||
public MavenInvoker(Lookup protoLookup, @Nullable Consumer<LookupContext> contextConsumer) {
|
||||
super(protoLookup, contextConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int execute(C context) throws Exception {
|
||||
protected MavenContext createContext(InvokerRequest invokerRequest) throws InvokerException {
|
||||
return new MavenContext(invokerRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int execute(MavenContext context) throws Exception {
|
||||
MavenExecutionRequest request = prepareMavenExecutionRequest();
|
||||
toolchains(context, request);
|
||||
populateRequest(context, context.lookup, request);
|
||||
|
@ -113,26 +116,15 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void lookup(C context) throws Exception {
|
||||
context.eventSpyDispatcher = context.lookup.lookup(EventSpyDispatcher.class);
|
||||
context.maven = context.lookup.lookup(Maven.class);
|
||||
protected void lookup(MavenContext context) throws Exception {
|
||||
if (context.maven == null) {
|
||||
super.lookup(context);
|
||||
context.maven = context.lookup.lookup(Maven.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(C context) throws Exception {
|
||||
super.init(context);
|
||||
InvokerRequest invokerRequest = context.invokerRequest;
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("plexus", context.lookup.lookup(PlexusContainer.class));
|
||||
data.put("workingDirectory", invokerRequest.cwd().toString());
|
||||
data.put("systemProperties", toProperties(context.protoSession.getSystemProperties()));
|
||||
data.put("userProperties", toProperties(context.protoSession.getUserProperties()));
|
||||
data.put("versionProperties", CLIReportingUtils.getBuildProperties());
|
||||
context.eventSpyDispatcher.init(() -> data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postCommands(C context) throws Exception {
|
||||
protected void postCommands(MavenContext context) throws Exception {
|
||||
super.postCommands(context);
|
||||
|
||||
InvokerRequest invokerRequest = context.invokerRequest;
|
||||
|
@ -145,21 +137,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeSettingsRequest(C context, SettingsBuilderRequest settingsBuilderRequest) throws Exception {
|
||||
if (context.eventSpyDispatcher != null) {
|
||||
context.eventSpyDispatcher.onEvent(settingsBuilderRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeSettingsResult(C context, SettingsBuilderResult settingsBuilderResult) throws Exception {
|
||||
if (context.eventSpyDispatcher != null) {
|
||||
context.eventSpyDispatcher.onEvent(settingsBuilderResult);
|
||||
}
|
||||
}
|
||||
|
||||
protected void toolchains(C context, MavenExecutionRequest request) throws Exception {
|
||||
protected void toolchains(MavenContext context, MavenExecutionRequest request) throws Exception {
|
||||
Path userToolchainsFile = null;
|
||||
if (context.invokerRequest.options().altUserToolchains().isPresent()) {
|
||||
userToolchainsFile = context.cwdResolver.apply(
|
||||
|
@ -240,7 +218,8 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void populateRequest(C context, Lookup lookup, MavenExecutionRequest request) throws Exception {
|
||||
protected void populateRequest(MavenContext context, Lookup lookup, MavenExecutionRequest request)
|
||||
throws Exception {
|
||||
super.populateRequest(context, lookup, request);
|
||||
if (context.invokerRequest.rootDirectory().isEmpty()) {
|
||||
// maven requires this to be set; so default it (and see below at POM)
|
||||
|
@ -322,7 +301,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
protected Path determinePom(C context, Lookup lookup) {
|
||||
protected Path determinePom(MavenContext context, Lookup lookup) {
|
||||
Path current = context.invokerRequest.cwd();
|
||||
MavenOptions options = (MavenOptions) context.invokerRequest.options();
|
||||
if (options.alternatePomFile().isPresent()) {
|
||||
|
@ -337,7 +316,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
protected String determineReactorFailureBehaviour(C context) {
|
||||
protected String determineReactorFailureBehaviour(MavenContext context) {
|
||||
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||
if (mavenOptions.failFast().isPresent()) {
|
||||
return MavenExecutionRequest.REACTOR_FAIL_FAST;
|
||||
|
@ -350,7 +329,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
protected String determineGlobalChecksumPolicy(C context) {
|
||||
protected String determineGlobalChecksumPolicy(MavenContext context) {
|
||||
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||
if (mavenOptions.strictChecksums().orElse(false)) {
|
||||
return MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
|
||||
|
@ -361,7 +340,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
protected ExecutionListener determineExecutionListener(C context) {
|
||||
protected ExecutionListener determineExecutionListener(MavenContext context) {
|
||||
ExecutionListener listener = new ExecutionEventLogger(context.invokerRequest.messageBuilderFactory());
|
||||
if (context.eventSpyDispatcher != null) {
|
||||
listener = context.eventSpyDispatcher.chainListener(listener);
|
||||
|
@ -369,7 +348,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
return new LoggingExecutionListener(listener, determineBuildEventListener(context));
|
||||
}
|
||||
|
||||
protected TransferListener determineTransferListener(C context, boolean noTransferProgress) {
|
||||
protected TransferListener determineTransferListener(MavenContext context, boolean noTransferProgress) {
|
||||
boolean quiet = context.invokerRequest.options().quiet().orElse(false);
|
||||
boolean logFile = context.invokerRequest.options().logFile().isPresent();
|
||||
boolean runningOnCI = isRunningOnCI(context);
|
||||
|
@ -390,7 +369,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
return new MavenTransferListener(delegate, determineBuildEventListener(context));
|
||||
}
|
||||
|
||||
protected String determineMakeBehavior(C context) {
|
||||
protected String determineMakeBehavior(MavenContext context) {
|
||||
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||
if (mavenOptions.alsoMake().isPresent()
|
||||
&& mavenOptions.alsoMakeDependents().isEmpty()) {
|
||||
|
@ -406,7 +385,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
protected void performProjectActivation(C context, ProjectActivation projectActivation) {
|
||||
protected void performProjectActivation(MavenContext context, ProjectActivation projectActivation) {
|
||||
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||
if (mavenOptions.projects().isPresent()
|
||||
&& !mavenOptions.projects().get().isEmpty()) {
|
||||
|
@ -434,7 +413,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
protected void performProfileActivation(C context, ProfileActivation profileActivation) {
|
||||
protected void performProfileActivation(MavenContext context, ProfileActivation profileActivation) {
|
||||
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||
if (mavenOptions.activatedProfiles().isPresent()
|
||||
&& !mavenOptions.activatedProfiles().get().isEmpty()) {
|
||||
|
@ -462,7 +441,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
protected int doExecute(C context, MavenExecutionRequest request) throws Exception {
|
||||
protected int doExecute(MavenContext context, MavenExecutionRequest request) throws Exception {
|
||||
context.eventSpyDispatcher.onEvent(request);
|
||||
|
||||
MavenExecutionResult result;
|
||||
|
@ -534,7 +513,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
}
|
||||
}
|
||||
|
||||
protected void logBuildResumeHint(C context, String resumeBuildHint) {
|
||||
protected void logBuildResumeHint(MavenContext context, String resumeBuildHint) {
|
||||
context.logger.error("");
|
||||
context.logger.error("After correcting the problems, you can resume the build with the command");
|
||||
context.logger.error(
|
||||
|
@ -577,7 +556,8 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
|||
|
||||
protected static final String ANSI_RESET = "\u001B\u005Bm";
|
||||
|
||||
protected void logSummary(C context, ExceptionSummary summary, Map<String, String> references, String indent) {
|
||||
protected void logSummary(
|
||||
MavenContext context, ExceptionSummary summary, Map<String, String> references, String indent) {
|
||||
String referenceKey = "";
|
||||
|
||||
if (summary.getReference() != null && !summary.getReference().isEmpty()) {
|
||||
|
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.cling.invoker.mvn.forked;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.api.cli.Invoker;
|
||||
import org.apache.maven.api.cli.InvokerException;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.api.cli.mvn.MavenOptions;
|
||||
import org.apache.maven.internal.impl.model.profile.Os;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* Forked invoker implementation, that spawns a subprocess with Maven from the installation directory.
|
||||
*/
|
||||
public class ForkedMavenInvoker implements Invoker {
|
||||
@SuppressWarnings("MethodLength")
|
||||
@Override
|
||||
public int invoke(InvokerRequest invokerRequest) throws InvokerException {
|
||||
requireNonNull(invokerRequest);
|
||||
validate(invokerRequest);
|
||||
|
||||
ArrayList<String> cmdAndArguments = new ArrayList<>();
|
||||
cmdAndArguments.add(invokerRequest
|
||||
.installationDirectory()
|
||||
.resolve("bin")
|
||||
.resolve(
|
||||
Os.IS_WINDOWS
|
||||
? invokerRequest.parserRequest().command() + ".cmd"
|
||||
: invokerRequest.parserRequest().command())
|
||||
.toString());
|
||||
|
||||
MavenOptions mavenOptions = (MavenOptions) invokerRequest.options();
|
||||
if (mavenOptions.userProperties().isPresent()) {
|
||||
for (Map.Entry<String, String> entry :
|
||||
mavenOptions.userProperties().get().entrySet()) {
|
||||
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()) {
|
||||
cmdAndArguments.add("--file");
|
||||
cmdAndArguments.add(mavenOptions.alternatePomFile().get());
|
||||
}
|
||||
if (mavenOptions.offline().orElse(false)) {
|
||||
cmdAndArguments.add("--offline");
|
||||
}
|
||||
if (mavenOptions.nonRecursive().orElse(false)) {
|
||||
cmdAndArguments.add("--non-recursive");
|
||||
}
|
||||
if (mavenOptions.updateSnapshots().orElse(false)) {
|
||||
cmdAndArguments.add("--update-snapshots");
|
||||
}
|
||||
if (mavenOptions.activatedProfiles().isPresent()) {
|
||||
cmdAndArguments.add("--activate-profiles");
|
||||
cmdAndArguments.add(
|
||||
String.join(",", mavenOptions.activatedProfiles().get()));
|
||||
}
|
||||
if (mavenOptions.suppressSnapshotUpdates().orElse(false)) {
|
||||
cmdAndArguments.add("--no-snapshot-updates");
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
// last the goals
|
||||
cmdAndArguments.addAll(mavenOptions.goals().orElse(Collections.emptyList()));
|
||||
|
||||
try {
|
||||
ProcessBuilder pb = new ProcessBuilder()
|
||||
.directory(invokerRequest.cwd().toFile())
|
||||
.command(cmdAndArguments);
|
||||
|
||||
if (invokerRequest.jvmArguments().isPresent()) {
|
||||
pb.environment()
|
||||
.put(
|
||||
"MAVEN_OPTS",
|
||||
String.join(" ", invokerRequest.jvmArguments().get()));
|
||||
}
|
||||
|
||||
return pb.start().waitFor();
|
||||
} catch (IOException e) {
|
||||
invokerRequest.logger().error("IO problem while executing command: " + cmdAndArguments, e);
|
||||
return 127;
|
||||
} catch (InterruptedException e) {
|
||||
invokerRequest.logger().error("Interrupted while executing command: " + cmdAndArguments, e);
|
||||
return 127;
|
||||
}
|
||||
}
|
||||
|
||||
protected void validate(InvokerRequest invokerRequest) throws InvokerException {}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.cling.invoker.mvn.resident;
|
||||
|
||||
import org.apache.maven.api.cli.InvokerException;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenContext;
|
||||
|
||||
public class ResidentMavenContext extends MavenContext {
|
||||
|
||||
protected ResidentMavenContext(InvokerRequest invokerRequest) {
|
||||
super(invokerRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void closeContainer() {
|
||||
// we are resident; we do not shut down here
|
||||
}
|
||||
|
||||
public void shutDown() throws InvokerException {
|
||||
super.closeContainer();
|
||||
}
|
||||
|
||||
public ResidentMavenContext copy(InvokerRequest invokerRequest) {
|
||||
if (invokerRequest == this.invokerRequest) {
|
||||
return this;
|
||||
}
|
||||
ResidentMavenContext shadow = new ResidentMavenContext(invokerRequest);
|
||||
|
||||
// we carry over only "resident" things
|
||||
shadow.containerCapsule = containerCapsule;
|
||||
shadow.lookup = lookup;
|
||||
shadow.eventSpyDispatcher = eventSpyDispatcher;
|
||||
shadow.maven = maven;
|
||||
|
||||
return shadow;
|
||||
}
|
||||
}
|
|
@ -23,29 +23,32 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
import org.apache.maven.api.cli.InvokerException;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.api.services.Lookup;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenContext;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenInvoker;
|
||||
|
||||
/**
|
||||
* Resident invoker implementation, similar to "local", but keeps Maven instance resident. This implies, that
|
||||
* Resident invoker implementation, specialization of Maven Invoker, but keeps Maven instance resident. This implies, that
|
||||
* things like environment, system properties, extensions etc. are loaded only once. It is caller duty to ensure
|
||||
* that subsequent call is right for the resident instance (ie no env change or different extension needed).
|
||||
* This implementation "pre-populates" MavenContext with pre-existing stuff (except for very first call)
|
||||
* and does not let DI container to be closed.
|
||||
*/
|
||||
public class ResidentMavenInvoker extends MavenInvoker<ResidentMavenContext> {
|
||||
public class ResidentMavenInvoker extends MavenInvoker {
|
||||
|
||||
private final ConcurrentHashMap<String, ResidentMavenContext> residentContext;
|
||||
private final ConcurrentHashMap<String, MavenContext> residentContext;
|
||||
|
||||
public ResidentMavenInvoker(ProtoLookup protoLookup) {
|
||||
super(protoLookup);
|
||||
public ResidentMavenInvoker(Lookup protoLookup) {
|
||||
super(protoLookup, null);
|
||||
this.residentContext = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws InvokerException {
|
||||
ArrayList<InvokerException> exceptions = new ArrayList<>();
|
||||
for (ResidentMavenContext context : residentContext.values()) {
|
||||
for (MavenContext context : residentContext.values()) {
|
||||
try {
|
||||
context.shutDown();
|
||||
context.doCloseContainer();
|
||||
} catch (InvokerException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
|
@ -58,31 +61,25 @@ public class ResidentMavenInvoker extends MavenInvoker<ResidentMavenContext> {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ResidentMavenContext createContext(InvokerRequest invokerRequest) {
|
||||
return residentContext
|
||||
.computeIfAbsent(getContextId(invokerRequest), k -> new ResidentMavenContext(invokerRequest))
|
||||
.copy(invokerRequest);
|
||||
}
|
||||
|
||||
protected String getContextId(InvokerRequest invokerRequest) {
|
||||
protected MavenContext createContext(InvokerRequest invokerRequest) {
|
||||
// TODO: in a moment Maven stop pushing user properties to system properties (and maybe something more)
|
||||
// and allow multiple instances per JVM, this may become a pool?
|
||||
return "resident";
|
||||
// and allow multiple instances per JVM, this may become a pool? derive key based in invokerRequest?
|
||||
MavenContext result = residentContext.computeIfAbsent("resident", k -> new MavenContext(invokerRequest, false));
|
||||
return copyIfDifferent(result, invokerRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void container(ResidentMavenContext context) throws Exception {
|
||||
if (context.containerCapsule == null) {
|
||||
super.container(context);
|
||||
} else {
|
||||
context.containerCapsule.updateLogging(context);
|
||||
protected MavenContext copyIfDifferent(MavenContext mavenContext, InvokerRequest invokerRequest) {
|
||||
if (invokerRequest == mavenContext.invokerRequest) {
|
||||
return mavenContext;
|
||||
}
|
||||
}
|
||||
MavenContext shadow = new MavenContext(invokerRequest, false);
|
||||
|
||||
@Override
|
||||
protected void lookup(ResidentMavenContext context) throws Exception {
|
||||
if (context.maven == null) {
|
||||
super.lookup(context);
|
||||
}
|
||||
// we carry over only "resident" things
|
||||
shadow.containerCapsule = mavenContext.containerCapsule;
|
||||
shadow.lookup = mavenContext.lookup;
|
||||
shadow.eventSpyDispatcher = mavenContext.eventSpyDispatcher;
|
||||
shadow.maven = mavenContext.maven;
|
||||
|
||||
return shadow;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,12 @@ import org.jline.utils.AttributedStyle;
|
|||
|
||||
@SuppressWarnings("VisibilityModifier")
|
||||
public class EncryptContext extends LookupContext {
|
||||
protected EncryptContext(InvokerRequest invokerRequest) {
|
||||
super(invokerRequest);
|
||||
public EncryptContext(InvokerRequest invokerRequest) {
|
||||
this(invokerRequest, true);
|
||||
}
|
||||
|
||||
public EncryptContext(InvokerRequest invokerRequest, boolean containerCapsuleManaged) {
|
||||
super(invokerRequest, containerCapsuleManaged);
|
||||
}
|
||||
|
||||
public Map<String, Goal> goals;
|
||||
|
|
|
@ -20,11 +20,14 @@ package org.apache.maven.cling.invoker.mvnenc;
|
|||
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.maven.api.annotations.Nullable;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.api.cli.mvnenc.EncryptOptions;
|
||||
import org.apache.maven.api.services.Lookup;
|
||||
import org.apache.maven.cling.invoker.LookupContext;
|
||||
import org.apache.maven.cling.invoker.LookupInvoker;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.cling.utils.CLIReportingUtils;
|
||||
import org.jline.reader.LineReaderBuilder;
|
||||
import org.jline.reader.UserInterruptException;
|
||||
|
@ -37,13 +40,17 @@ import org.jline.utils.Colors;
|
|||
*/
|
||||
public class EncryptInvoker extends LookupInvoker<EncryptContext> {
|
||||
|
||||
public EncryptInvoker(ProtoLookup protoLookup) {
|
||||
super(protoLookup);
|
||||
public static final int OK = 0; // OK
|
||||
public static final int ERROR = 1; // "generic" error
|
||||
public static final int BAD_OPERATION = 2; // bad user input or alike
|
||||
public static final int CANCELED = 3; // user canceled
|
||||
|
||||
public EncryptInvoker(Lookup protoLookup) {
|
||||
this(protoLookup, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int execute(EncryptContext context) throws Exception {
|
||||
return doExecute(context);
|
||||
public EncryptInvoker(Lookup protoLookup, @Nullable Consumer<LookupContext> contextConsumer) {
|
||||
super(protoLookup, contextConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,16 +59,15 @@ public class EncryptInvoker extends LookupInvoker<EncryptContext> {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void lookup(EncryptContext context) {
|
||||
context.goals = context.lookup.lookupMap(Goal.class);
|
||||
protected void lookup(EncryptContext context) throws Exception {
|
||||
if (context.goals == null) {
|
||||
super.lookup(context);
|
||||
context.goals = context.lookup.lookupMap(Goal.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static final int OK = 0; // OK
|
||||
public static final int ERROR = 1; // "generic" error
|
||||
public static final int BAD_OPERATION = 2; // bad user input or alike
|
||||
public static final int CANCELED = 3; // user canceled
|
||||
|
||||
protected int doExecute(EncryptContext context) throws Exception {
|
||||
@Override
|
||||
protected int execute(EncryptContext context) throws Exception {
|
||||
try {
|
||||
context.header = new ArrayList<>();
|
||||
context.style = new AttributedStyle();
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
*/
|
||||
package org.apache.maven.cling.invoker.mvnenc.goals;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.maven.api.di.Inject;
|
||||
import org.apache.maven.api.di.Named;
|
||||
import org.apache.maven.api.di.Singleton;
|
||||
import org.apache.maven.api.services.MessageBuilderFactory;
|
||||
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
||||
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
*/
|
||||
package org.apache.maven.cling.invoker.mvnenc.goals;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.maven.api.di.Inject;
|
||||
import org.apache.maven.api.di.Named;
|
||||
import org.apache.maven.api.di.Singleton;
|
||||
import org.apache.maven.api.services.MessageBuilderFactory;
|
||||
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
||||
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
*/
|
||||
package org.apache.maven.cling.invoker.mvnenc.goals;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.maven.api.di.Inject;
|
||||
import org.apache.maven.api.di.Named;
|
||||
import org.apache.maven.api.di.Singleton;
|
||||
import org.apache.maven.api.services.MessageBuilderFactory;
|
||||
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
||||
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
||||
|
|
|
@ -18,15 +18,17 @@
|
|||
*/
|
||||
package org.apache.maven.cling.invoker.mvnenc.goals;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import java.io.IOError;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.maven.api.cli.mvnenc.EncryptOptions;
|
||||
import org.apache.maven.api.di.Inject;
|
||||
import org.apache.maven.api.di.Named;
|
||||
import org.apache.maven.api.di.Singleton;
|
||||
import org.apache.maven.api.services.MessageBuilderFactory;
|
||||
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
||||
import org.codehaus.plexus.components.secdispatcher.DispatcherMeta;
|
||||
|
@ -40,14 +42,12 @@ import org.jline.consoleui.prompt.ConsolePrompt;
|
|||
import org.jline.consoleui.prompt.PromptResultItemIF;
|
||||
import org.jline.consoleui.prompt.builder.ListPromptBuilder;
|
||||
import org.jline.consoleui.prompt.builder.PromptBuilder;
|
||||
import org.jline.reader.Candidate;
|
||||
import org.jline.reader.Completer;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.ParsedLine;
|
||||
import org.jline.reader.UserInterruptException;
|
||||
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.CANCELED;
|
||||
import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK;
|
||||
|
||||
/**
|
||||
|
@ -63,6 +63,7 @@ public class Init extends InteractiveGoalSupport {
|
|||
super(messageBuilderFactory, secDispatcher);
|
||||
}
|
||||
|
||||
@SuppressWarnings("MethodLength")
|
||||
@Override
|
||||
public int doExecute(EncryptContext context) throws Exception {
|
||||
EncryptOptions options = (EncryptOptions) context.invokerRequest.options();
|
||||
|
@ -87,125 +88,128 @@ public class Init extends InteractiveGoalSupport {
|
|||
promptConfig = new ConsolePrompt.UiConfig("❯", "◯ ", "◉ ", "◯ ");
|
||||
}
|
||||
promptConfig.setCancellableFirstPrompt(true);
|
||||
ConsolePrompt prompt = new ConsolePrompt(context.reader, context.terminal, promptConfig);
|
||||
|
||||
SettingsSecurity config = secDispatcher.readConfiguration(true);
|
||||
|
||||
// reset config
|
||||
config.setDefaultDispatcher(null);
|
||||
config.getConfigurations().clear();
|
||||
|
||||
Map<String, PromptResultItemIF> result = prompt.prompt(
|
||||
context.header, dispatcherPrompt(prompt.getPromptBuilder()).build());
|
||||
if (result == null) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
if (NONE.equals(result.get("defaultDispatcher").getResult())) {
|
||||
context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory
|
||||
.builder()
|
||||
.warning(
|
||||
"Maven4 SecDispatcher disabled; Maven3 fallback may still work, use `mvnenc diag` to check")
|
||||
.build());
|
||||
secDispatcher.writeConfiguration(config);
|
||||
return OK;
|
||||
}
|
||||
config.setDefaultDispatcher(result.get("defaultDispatcher").getResult());
|
||||
try (ConsolePrompt prompt = new ConsolePrompt(context.reader, context.terminal, promptConfig)) {
|
||||
Map<String, PromptResultItemIF> dispatcherResult = new HashMap<>();
|
||||
Map<String, PromptResultItemIF> dispatcherConfigResult = new HashMap<>();
|
||||
Map<String, PromptResultItemIF> confirmChoice = new HashMap<>();
|
||||
|
||||
DispatcherMeta meta = secDispatcher.availableDispatchers().stream()
|
||||
.filter(d -> Objects.equals(config.getDefaultDispatcher(), d.name()))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
if (!meta.fields().isEmpty()) {
|
||||
result = prompt.prompt(
|
||||
context.header,
|
||||
configureDispatcher(context, meta, prompt.getPromptBuilder())
|
||||
.build());
|
||||
if (result == null) {
|
||||
prompt.prompt(
|
||||
context.header, dispatcherPrompt(prompt.getPromptBuilder()).build(), dispatcherResult);
|
||||
if (dispatcherResult.isEmpty()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
if (NONE.equals(dispatcherResult.get("defaultDispatcher").getResult())) {
|
||||
context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory
|
||||
.builder()
|
||||
.warning(
|
||||
"Maven4 SecDispatcher disabled; Maven3 fallback may still work, use `mvnenc diag` to check")
|
||||
.build());
|
||||
} else {
|
||||
config.setDefaultDispatcher(
|
||||
dispatcherResult.get("defaultDispatcher").getResult());
|
||||
|
||||
List<Map.Entry<String, PromptResultItemIF>> editables = result.entrySet().stream()
|
||||
.filter(e -> e.getValue().getResult().contains("$"))
|
||||
.toList();
|
||||
if (!editables.isEmpty()) {
|
||||
context.addInHeader("");
|
||||
context.addInHeader("Please customize the editable value:");
|
||||
Map<String, PromptResultItemIF> editMap;
|
||||
for (Map.Entry<String, PromptResultItemIF> editable : editables) {
|
||||
String template = editable.getValue().getResult();
|
||||
String prefix = template.substring(0, template.indexOf("$"));
|
||||
editMap = prompt.prompt(
|
||||
DispatcherMeta meta = secDispatcher.availableDispatchers().stream()
|
||||
.filter(d -> Objects.equals(config.getDefaultDispatcher(), d.name()))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
if (!meta.fields().isEmpty()) {
|
||||
prompt.prompt(
|
||||
context.header,
|
||||
prompt.getPromptBuilder()
|
||||
.createInputPrompt()
|
||||
.name("edit")
|
||||
.message(template)
|
||||
.addCompleter(new Completer() {
|
||||
@Override
|
||||
public void complete(
|
||||
LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
||||
if (!line.line().startsWith(prefix)) {
|
||||
candidates.add(
|
||||
new Candidate(prefix, prefix, null, null, null, null, false));
|
||||
}
|
||||
}
|
||||
})
|
||||
.addPrompt()
|
||||
.build());
|
||||
if (editMap == null) {
|
||||
configureDispatcher(context, meta, prompt.getPromptBuilder())
|
||||
.build(),
|
||||
dispatcherConfigResult);
|
||||
if (dispatcherConfigResult.isEmpty()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
result.put(editable.getKey(), editMap.get("edit"));
|
||||
|
||||
List<Map.Entry<String, PromptResultItemIF>> editables = dispatcherConfigResult.entrySet().stream()
|
||||
.filter(e -> e.getValue().getResult().contains("$"))
|
||||
.toList();
|
||||
if (!editables.isEmpty()) {
|
||||
context.addInHeader("");
|
||||
context.addInHeader("Please customize the editable value:");
|
||||
Map<String, PromptResultItemIF> editMap = new HashMap<>(editables.size());
|
||||
for (Map.Entry<String, PromptResultItemIF> editable : editables) {
|
||||
String template = editable.getValue().getResult();
|
||||
prompt.prompt(
|
||||
context.header,
|
||||
prompt.getPromptBuilder()
|
||||
.createInputPrompt()
|
||||
.name("edit")
|
||||
.message(template)
|
||||
.addPrompt()
|
||||
.build(),
|
||||
editMap);
|
||||
if (editMap.isEmpty()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
dispatcherConfigResult.put(editable.getKey(), editMap.get("edit"));
|
||||
}
|
||||
}
|
||||
|
||||
Config dispatcherConfig = new Config();
|
||||
dispatcherConfig.setName(meta.name());
|
||||
for (DispatcherMeta.Field field : meta.fields()) {
|
||||
ConfigProperty property = new ConfigProperty();
|
||||
property.setName(field.getKey());
|
||||
property.setValue(
|
||||
dispatcherConfigResult.get(field.getKey()).getResult());
|
||||
dispatcherConfig.addProperty(property);
|
||||
}
|
||||
if (!dispatcherConfig.getProperties().isEmpty()) {
|
||||
config.addConfiguration(dispatcherConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Config dispatcherConfig = new Config();
|
||||
dispatcherConfig.setName(meta.name());
|
||||
for (DispatcherMeta.Field field : meta.fields()) {
|
||||
ConfigProperty property = new ConfigProperty();
|
||||
property.setName(field.getKey());
|
||||
property.setValue(result.get(field.getKey()).getResult());
|
||||
dispatcherConfig.addProperty(property);
|
||||
}
|
||||
if (!dispatcherConfig.getProperties().isEmpty()) {
|
||||
config.addConfiguration(dispatcherConfig);
|
||||
}
|
||||
}
|
||||
|
||||
if (yes) {
|
||||
secDispatcher.writeConfiguration(config);
|
||||
} else {
|
||||
context.addInHeader("");
|
||||
context.addInHeader("Values set:");
|
||||
context.addInHeader("defaultDispatcher=" + config.getDefaultDispatcher());
|
||||
for (Config c : config.getConfigurations()) {
|
||||
context.addInHeader(" dispatcherName=" + c.getName());
|
||||
for (ConfigProperty cp : c.getProperties()) {
|
||||
context.addInHeader(" " + cp.getName() + "=" + cp.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
result = prompt.prompt(
|
||||
context.header, confirmPrompt(prompt.getPromptBuilder()).build());
|
||||
ConfirmResult confirm = (ConfirmResult) result.get("confirm");
|
||||
if (confirm.getConfirmed() == ConfirmChoice.ConfirmationValue.YES) {
|
||||
context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory
|
||||
.builder()
|
||||
.info("Writing out the configuration...")
|
||||
.build());
|
||||
if (yes) {
|
||||
secDispatcher.writeConfiguration(config);
|
||||
} else {
|
||||
context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory
|
||||
.builder()
|
||||
.warning("Values not accepted; not saving configuration.")
|
||||
.build());
|
||||
return BAD_OPERATION;
|
||||
context.addInHeader("");
|
||||
context.addInHeader("Values set:");
|
||||
context.addInHeader("defaultDispatcher=" + config.getDefaultDispatcher());
|
||||
for (Config c : config.getConfigurations()) {
|
||||
context.addInHeader(" dispatcherName=" + c.getName());
|
||||
for (ConfigProperty cp : c.getProperties()) {
|
||||
context.addInHeader(" " + cp.getName() + "=" + cp.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
prompt.prompt(
|
||||
context.header, confirmPrompt(prompt.getPromptBuilder()).build(), confirmChoice);
|
||||
ConfirmResult confirm = (ConfirmResult) confirmChoice.get("confirm");
|
||||
if (confirm.getConfirmed() == ConfirmChoice.ConfirmationValue.YES) {
|
||||
context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory
|
||||
.builder()
|
||||
.info("Writing out the configuration...")
|
||||
.build());
|
||||
secDispatcher.writeConfiguration(config);
|
||||
} else {
|
||||
context.terminal
|
||||
.writer()
|
||||
.println(messageBuilderFactory
|
||||
.builder()
|
||||
.warning("Values not accepted; not saving configuration.")
|
||||
.build());
|
||||
return CANCELED;
|
||||
}
|
||||
}
|
||||
} catch (IOError e) {
|
||||
// TODO: this should be handled properly in jline3!
|
||||
if (e.getCause() instanceof InterruptedIOException) {
|
||||
throw new UserInterruptException(e.getCause());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.mvnsh;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.maven.api.cli.Options;
|
||||
import org.apache.maven.api.cli.mvnsh.ShellOptions;
|
||||
import org.apache.maven.cling.invoker.CommonsCliOptions;
|
||||
import org.codehaus.plexus.interpolation.BasicInterpolator;
|
||||
import org.codehaus.plexus.interpolation.InterpolationException;
|
||||
|
||||
import static org.apache.maven.cling.invoker.Utils.createInterpolator;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ShellOptions} (base + shell).
|
||||
*/
|
||||
public class CommonsCliShellOptions extends CommonsCliOptions implements ShellOptions {
|
||||
public static CommonsCliShellOptions parse(String[] args) throws ParseException {
|
||||
CLIManager cliManager = new CLIManager();
|
||||
return new CommonsCliShellOptions(Options.SOURCE_CLI, cliManager, cliManager.parse(args));
|
||||
}
|
||||
|
||||
protected CommonsCliShellOptions(String source, CLIManager cliManager, CommandLine commandLine) {
|
||||
super(source, cliManager, commandLine);
|
||||
}
|
||||
|
||||
private static CommonsCliShellOptions interpolate(
|
||||
CommonsCliShellOptions options, Collection<Map<String, String>> properties) {
|
||||
try {
|
||||
// now that we have properties, interpolate all arguments
|
||||
BasicInterpolator interpolator = createInterpolator(properties);
|
||||
CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
|
||||
commandLineBuilder.setDeprecatedHandler(o -> {});
|
||||
for (Option option : options.commandLine.getOptions()) {
|
||||
if (!CLIManager.USER_PROPERTY.equals(option.getOpt())) {
|
||||
List<String> values = option.getValuesList();
|
||||
for (ListIterator<String> it = values.listIterator(); it.hasNext(); ) {
|
||||
it.set(interpolator.interpolate(it.next()));
|
||||
}
|
||||
}
|
||||
commandLineBuilder.addOption(option);
|
||||
}
|
||||
for (String arg : options.commandLine.getArgList()) {
|
||||
commandLineBuilder.addArg(interpolator.interpolate(arg));
|
||||
}
|
||||
return new CommonsCliShellOptions(
|
||||
options.source, (CLIManager) options.cliManager, commandLineBuilder.build());
|
||||
} catch (InterpolationException e) {
|
||||
throw new IllegalArgumentException("Could not interpolate CommonsCliOptions", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellOptions interpolate(Collection<Map<String, String>> properties) {
|
||||
return interpolate(this, properties);
|
||||
}
|
||||
|
||||
protected static class CLIManager extends CommonsCliOptions.CLIManager {
|
||||
@Override
|
||||
protected String commandLineSyntax(String command) {
|
||||
return command + " [options]";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.mvnsh;
|
||||
|
||||
import org.apache.maven.cling.invoker.LookupContext;
|
||||
import org.jline.console.CommandRegistry;
|
||||
|
||||
public interface ShellCommandRegistryFactory {
|
||||
CommandRegistry createShellCommandRegistry(LookupContext context);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.mvnsh;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jline.console.CommandRegistry;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class ShellCommandRegistryHolder implements AutoCloseable {
|
||||
private final List<CommandRegistry> commandRegistries;
|
||||
|
||||
public ShellCommandRegistryHolder() {
|
||||
this.commandRegistries = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addCommandRegistry(CommandRegistry commandRegistry) {
|
||||
requireNonNull(commandRegistry, "commandRegistry");
|
||||
this.commandRegistries.add(commandRegistry);
|
||||
}
|
||||
|
||||
public CommandRegistry[] getCommandRegistries() {
|
||||
return commandRegistries.toArray(new CommandRegistry[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
ArrayList<Exception> exceptions = new ArrayList<>();
|
||||
for (CommandRegistry commandRegistry : commandRegistries) {
|
||||
if (commandRegistry instanceof AutoCloseable closeable) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (Exception e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!exceptions.isEmpty()) {
|
||||
IllegalStateException ex = new IllegalStateException("Could not close commandRegistries");
|
||||
exceptions.forEach(ex::addSuppressed);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* 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.mvnsh;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.api.services.Lookup;
|
||||
import org.apache.maven.cling.invoker.LookupContext;
|
||||
import org.apache.maven.cling.invoker.LookupInvoker;
|
||||
import org.apache.maven.cling.utils.CLIReportingUtils;
|
||||
import org.jline.builtins.ConfigurationPath;
|
||||
import org.jline.console.impl.Builtins;
|
||||
import org.jline.console.impl.SimpleSystemRegistryImpl;
|
||||
import org.jline.console.impl.SystemRegistryImpl;
|
||||
import org.jline.keymap.KeyMap;
|
||||
import org.jline.reader.Binding;
|
||||
import org.jline.reader.EndOfFileException;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.LineReaderBuilder;
|
||||
import org.jline.reader.MaskingCallback;
|
||||
import org.jline.reader.Parser;
|
||||
import org.jline.reader.Reference;
|
||||
import org.jline.reader.UserInterruptException;
|
||||
import org.jline.reader.impl.DefaultHighlighter;
|
||||
import org.jline.reader.impl.DefaultParser;
|
||||
import org.jline.reader.impl.history.DefaultHistory;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
import org.jline.utils.InfoCmp;
|
||||
import org.jline.widget.TailTipWidgets;
|
||||
|
||||
/**
|
||||
* mvnsh invoker implementation.
|
||||
*/
|
||||
public class ShellInvoker extends LookupInvoker<LookupContext> {
|
||||
|
||||
public ShellInvoker(Lookup protoLookup) {
|
||||
super(protoLookup, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LookupContext createContext(InvokerRequest invokerRequest) {
|
||||
return new LookupContext(invokerRequest);
|
||||
}
|
||||
|
||||
public static final int OK = 0; // OK
|
||||
public static final int ERROR = 1; // "generic" error
|
||||
|
||||
@Override
|
||||
protected int execute(LookupContext context) throws Exception {
|
||||
// set up JLine built-in commands
|
||||
ConfigurationPath configPath =
|
||||
new ConfigurationPath(context.invokerRequest.cwd(), context.invokerRequest.cwd());
|
||||
Builtins builtins = new Builtins(context.invokerRequest::cwd, configPath, null);
|
||||
builtins.rename(Builtins.Command.TTOP, "top");
|
||||
builtins.alias("zle", "widget");
|
||||
builtins.alias("bindkey", "keymap");
|
||||
|
||||
ShellCommandRegistryHolder holder = new ShellCommandRegistryHolder();
|
||||
holder.addCommandRegistry(builtins);
|
||||
|
||||
// gather commands
|
||||
Map<String, ShellCommandRegistryFactory> factories =
|
||||
context.lookup.lookupMap(ShellCommandRegistryFactory.class);
|
||||
for (Map.Entry<String, ShellCommandRegistryFactory> entry : factories.entrySet()) {
|
||||
holder.addCommandRegistry(entry.getValue().createShellCommandRegistry(context));
|
||||
}
|
||||
|
||||
Parser parser = new DefaultParser();
|
||||
|
||||
String banner =
|
||||
"""
|
||||
|
||||
░▒▓██████████████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░░▒▓███████▓▒░ ░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░\s
|
||||
░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░\s
|
||||
░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░\s
|
||||
░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓██████▓▒░ ░▒▓████████▓▒░\s
|
||||
░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░\s
|
||||
░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░\s
|
||||
░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓██▓▒░ ░▒▓█▓▒░░▒▓█▓▒░░▒▓███████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░""";
|
||||
context.writer.accept(banner);
|
||||
if (!context.invokerRequest.options().showVersion().orElse(false)) {
|
||||
context.writer.accept(CLIReportingUtils.showVersionMinimal());
|
||||
}
|
||||
context.writer.accept("");
|
||||
|
||||
try (holder) {
|
||||
SimpleSystemRegistryImpl systemRegistry =
|
||||
new SimpleSystemRegistryImpl(parser, context.terminal, context.invokerRequest::cwd, configPath);
|
||||
systemRegistry.setCommandRegistries(holder.getCommandRegistries());
|
||||
|
||||
Path history = context.userResolver.apply(".mvnsh_history");
|
||||
LineReader reader = LineReaderBuilder.builder()
|
||||
.terminal(context.terminal)
|
||||
.history(new DefaultHistory())
|
||||
.highlighter(new ReplHighlighter())
|
||||
.completer(systemRegistry.completer())
|
||||
.parser(parser)
|
||||
.variable(LineReader.LIST_MAX, 50) // max tab completion candidates
|
||||
.variable(LineReader.HISTORY_FILE, history)
|
||||
.variable(LineReader.OTHERS_GROUP_NAME, "Others")
|
||||
.variable(LineReader.COMPLETION_STYLE_GROUP, "fg:blue,bold")
|
||||
.variable("HELP_COLORS", "ti=1;34:co=38:ar=3:op=33:de=90")
|
||||
.option(LineReader.Option.GROUP_PERSIST, true)
|
||||
.build();
|
||||
builtins.setLineReader(reader);
|
||||
systemRegistry.setLineReader(reader);
|
||||
new TailTipWidgets(reader, systemRegistry::commandDescription, 5, TailTipWidgets.TipType.COMPLETER);
|
||||
KeyMap<Binding> keyMap = reader.getKeyMaps().get("main");
|
||||
keyMap.bind(new Reference("tailtip-toggle"), KeyMap.alt("s"));
|
||||
|
||||
String prompt = "mvnsh> ";
|
||||
String rightPrompt = null;
|
||||
|
||||
// start the shell and process input until the user quits with Ctrl-D
|
||||
String line;
|
||||
while (true) {
|
||||
try {
|
||||
systemRegistry.cleanUp();
|
||||
line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null);
|
||||
systemRegistry.execute(line);
|
||||
} catch (UserInterruptException e) {
|
||||
// Ignore
|
||||
// return CANCELED;
|
||||
} catch (EndOfFileException e) {
|
||||
return OK;
|
||||
} catch (SystemRegistryImpl.UnknownCommandException e) {
|
||||
context.writer.accept(context.invokerRequest
|
||||
.messageBuilderFactory()
|
||||
.builder()
|
||||
.error(e.getMessage())
|
||||
.build());
|
||||
} catch (Exception e) {
|
||||
systemRegistry.trace(e);
|
||||
context.writer.accept(context.invokerRequest
|
||||
.messageBuilderFactory()
|
||||
.builder()
|
||||
.error("Error:" + e.getMessage())
|
||||
.build());
|
||||
if (context.invokerRequest.options().showErrors().orElse(false)) {
|
||||
e.printStackTrace(context.terminal.writer());
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReplHighlighter extends DefaultHighlighter {
|
||||
@Override
|
||||
protected void commandStyle(LineReader reader, AttributedStringBuilder sb, boolean enable) {
|
||||
if (enable) {
|
||||
if (reader.getTerminal().getNumericCapability(InfoCmp.Capability.max_colors) >= 256) {
|
||||
sb.style(AttributedStyle.DEFAULT.bold().foreground(69));
|
||||
} else {
|
||||
sb.style(AttributedStyle.DEFAULT.foreground(AttributedStyle.CYAN));
|
||||
}
|
||||
} else {
|
||||
sb.style(AttributedStyle.DEFAULT.boldOff().foregroundOff());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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.mvnsh;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.api.annotations.Nonnull;
|
||||
import org.apache.maven.api.cli.ParserRequest;
|
||||
import org.apache.maven.api.cli.extensions.CoreExtension;
|
||||
import org.apache.maven.api.cli.mvnsh.ShellOptions;
|
||||
import org.apache.maven.cling.invoker.BaseInvokerRequest;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class ShellInvokerRequest extends BaseInvokerRequest {
|
||||
private final ShellOptions options;
|
||||
|
||||
@SuppressWarnings("ParameterNumber")
|
||||
public ShellInvokerRequest(
|
||||
ParserRequest parserRequest,
|
||||
Path cwd,
|
||||
Path installationDirectory,
|
||||
Path userHomeDirectory,
|
||||
Map<String, String> userProperties,
|
||||
Map<String, String> systemProperties,
|
||||
Path topDirectory,
|
||||
Path rootDirectory,
|
||||
InputStream in,
|
||||
OutputStream out,
|
||||
OutputStream err,
|
||||
List<CoreExtension> coreExtensions,
|
||||
List<String> jvmArguments,
|
||||
ShellOptions options) {
|
||||
super(
|
||||
parserRequest,
|
||||
cwd,
|
||||
installationDirectory,
|
||||
userHomeDirectory,
|
||||
userProperties,
|
||||
systemProperties,
|
||||
topDirectory,
|
||||
rootDirectory,
|
||||
in,
|
||||
out,
|
||||
err,
|
||||
coreExtensions,
|
||||
jvmArguments);
|
||||
this.options = requireNonNull(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* The mandatory Shell options.
|
||||
*/
|
||||
@Nonnull
|
||||
public ShellOptions options() {
|
||||
return options;
|
||||
}
|
||||
}
|
|
@ -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.mvnsh;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.maven.api.cli.Options;
|
||||
import org.apache.maven.api.cli.ParserException;
|
||||
import org.apache.maven.api.cli.mvnsh.ShellOptions;
|
||||
import org.apache.maven.cling.invoker.BaseParser;
|
||||
|
||||
public class ShellParser extends BaseParser {
|
||||
@Override
|
||||
protected ShellInvokerRequest getInvokerRequest(LocalContext context) {
|
||||
return new ShellInvokerRequest(
|
||||
context.parserRequest,
|
||||
context.cwd,
|
||||
context.installationDirectory,
|
||||
context.userHomeDirectory,
|
||||
context.userProperties,
|
||||
context.systemProperties,
|
||||
context.topDirectory,
|
||||
context.rootDirectory,
|
||||
context.parserRequest.in(),
|
||||
context.parserRequest.out(),
|
||||
context.parserRequest.err(),
|
||||
context.extensions,
|
||||
getJvmArguments(context.rootDirectory),
|
||||
(ShellOptions) context.options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Options> parseCliOptions(LocalContext context) throws ParserException {
|
||||
return Collections.singletonList(parseShellCliOptions(context.parserRequest.args()));
|
||||
}
|
||||
|
||||
protected CommonsCliShellOptions parseShellCliOptions(List<String> args) throws ParserException {
|
||||
try {
|
||||
return CommonsCliShellOptions.parse(args.toArray(new String[0]));
|
||||
} catch (ParseException e) {
|
||||
throw new ParserException("Failed to parse command line options: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Options assembleOptions(List<Options> parsedOptions) {
|
||||
// nothing to assemble, we deal with CLI only
|
||||
return parsedOptions.get(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* 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.mvnsh.builtin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.maven.api.cli.ParserRequest;
|
||||
import org.apache.maven.api.di.Named;
|
||||
import org.apache.maven.api.di.Singleton;
|
||||
import org.apache.maven.cling.invoker.LookupContext;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenInvoker;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenParser;
|
||||
import org.apache.maven.cling.invoker.mvnenc.EncryptInvoker;
|
||||
import org.apache.maven.cling.invoker.mvnenc.EncryptParser;
|
||||
import org.apache.maven.cling.invoker.mvnsh.ShellCommandRegistryFactory;
|
||||
import org.jline.builtins.Completers;
|
||||
import org.jline.builtins.Options;
|
||||
import org.jline.console.CmdDesc;
|
||||
import org.jline.console.CommandInput;
|
||||
import org.jline.console.CommandMethods;
|
||||
import org.jline.console.CommandRegistry;
|
||||
import org.jline.console.impl.AbstractCommandRegistry;
|
||||
import org.jline.reader.Completer;
|
||||
import org.jline.reader.impl.completer.ArgumentCompleter;
|
||||
import org.jline.reader.impl.completer.NullCompleter;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.jline.console.impl.JlineCommandRegistry.compileCommandOptions;
|
||||
|
||||
@Named("builtin")
|
||||
@Singleton
|
||||
public class BuiltinShellCommandRegistryFactory implements ShellCommandRegistryFactory {
|
||||
public CommandRegistry createShellCommandRegistry(LookupContext context) {
|
||||
return new BuiltinShellCommandRegistry(context);
|
||||
}
|
||||
|
||||
private static class BuiltinShellCommandRegistry extends AbstractCommandRegistry implements AutoCloseable {
|
||||
public enum Command {
|
||||
MVN,
|
||||
MVNENC
|
||||
}
|
||||
|
||||
private final LookupContext shellContext;
|
||||
private final MavenInvoker shellMavenInvoker;
|
||||
private final MavenParser mavenParser;
|
||||
private final EncryptInvoker shellEncryptInvoker;
|
||||
private final EncryptParser encryptParser;
|
||||
|
||||
private BuiltinShellCommandRegistry(LookupContext shellContext) {
|
||||
this.shellContext = requireNonNull(shellContext, "shellContext");
|
||||
this.shellMavenInvoker = new MavenInvoker(shellContext.invokerRequest.lookup(), contextCopier());
|
||||
this.mavenParser = new MavenParser();
|
||||
this.shellEncryptInvoker = new EncryptInvoker(shellContext.invokerRequest.lookup(), contextCopier());
|
||||
this.encryptParser = new EncryptParser();
|
||||
Set<Command> commands = new HashSet<>(EnumSet.allOf(Command.class));
|
||||
Map<Command, String> commandName = new HashMap<>();
|
||||
Map<Command, CommandMethods> commandExecute = new HashMap<>();
|
||||
for (Command c : commands) {
|
||||
commandName.put(c, c.name().toLowerCase());
|
||||
}
|
||||
commandExecute.put(Command.MVN, new CommandMethods(this::mvn, this::mvnCompleter));
|
||||
commandExecute.put(Command.MVNENC, new CommandMethods(this::mvnenc, this::mvnencCompleter));
|
||||
registerCommands(commandName, commandExecute);
|
||||
}
|
||||
|
||||
private Consumer<LookupContext> contextCopier() {
|
||||
return result -> {
|
||||
result.logger = shellContext.logger;
|
||||
result.loggerFactory = shellContext.loggerFactory;
|
||||
result.slf4jConfiguration = shellContext.slf4jConfiguration;
|
||||
result.loggerLevel = shellContext.loggerLevel;
|
||||
result.coloredOutput = shellContext.coloredOutput;
|
||||
result.terminal = shellContext.terminal;
|
||||
result.writer = shellContext.writer;
|
||||
|
||||
result.installationSettingsPath = shellContext.installationSettingsPath;
|
||||
result.projectSettingsPath = shellContext.projectSettingsPath;
|
||||
result.userSettingsPath = shellContext.userSettingsPath;
|
||||
result.interactive = shellContext.interactive;
|
||||
result.localRepositoryPath = shellContext.localRepositoryPath;
|
||||
result.effectiveSettings = shellContext.effectiveSettings;
|
||||
|
||||
result.containerCapsule = shellContext.containerCapsule;
|
||||
result.lookup = shellContext.lookup;
|
||||
result.eventSpyDispatcher = shellContext.eventSpyDispatcher;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
shellMavenInvoker.close();
|
||||
shellEncryptInvoker.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> commandInfo(String command) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CmdDesc commandDescription(List<String> args) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "Builtin Maven Shell commands";
|
||||
}
|
||||
|
||||
private List<Completers.OptDesc> commandOptions(String command) {
|
||||
try {
|
||||
invoke(new CommandSession(), command, "--help");
|
||||
} catch (Options.HelpException e) {
|
||||
return compileCommandOptions(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void mvn(CommandInput input) {
|
||||
try {
|
||||
shellMavenInvoker.invoke(mavenParser.parseInvocation(ParserRequest.mvn(
|
||||
input.args(),
|
||||
shellContext.invokerRequest.logger(),
|
||||
shellContext.invokerRequest.messageBuilderFactory())
|
||||
.build()));
|
||||
} catch (Exception e) {
|
||||
saveException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Completer> mvnCompleter(String name) {
|
||||
List<Completer> completers = new ArrayList<>();
|
||||
completers.add(new ArgumentCompleter(
|
||||
NullCompleter.INSTANCE,
|
||||
new Completers.OptionCompleter(
|
||||
new Completers.FilesCompleter(shellContext.invokerRequest::cwd), this::commandOptions, 1)));
|
||||
return completers;
|
||||
}
|
||||
|
||||
private void mvnenc(CommandInput input) {
|
||||
try {
|
||||
shellEncryptInvoker.invoke(encryptParser.parseInvocation(ParserRequest.mvnenc(
|
||||
input.args(),
|
||||
shellContext.invokerRequest.logger(),
|
||||
shellContext.invokerRequest.messageBuilderFactory())
|
||||
.build()));
|
||||
} catch (Exception e) {
|
||||
saveException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Completer> mvnencCompleter(String name) {
|
||||
List<Completer> completers = new ArrayList<>();
|
||||
completers.add(new ArgumentCompleter(
|
||||
NullCompleter.INSTANCE,
|
||||
new Completers.OptionCompleter(
|
||||
new Completers.FilesCompleter(shellContext.invokerRequest::cwd), this::commandOptions, 1)));
|
||||
return completers;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,24 +16,8 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.cling.invoker.mvn.local;
|
||||
|
||||
import org.apache.maven.api.cli.InvokerException;
|
||||
import org.apache.maven.api.cli.InvokerRequest;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenContext;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenInvoker;
|
||||
|
||||
/**
|
||||
* Local Maven invoker implementation, that expects all the Maven to be on classpath.
|
||||
* This package contains the {@code mvnsh} tool implementation.
|
||||
*/
|
||||
public class LocalMavenInvoker extends MavenInvoker<MavenContext> {
|
||||
public LocalMavenInvoker(ProtoLookup protoLookup) {
|
||||
super(protoLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MavenContext createContext(InvokerRequest invokerRequest) throws InvokerException {
|
||||
return new MavenContext(invokerRequest);
|
||||
}
|
||||
}
|
||||
package org.apache.maven.cling.invoker.mvnsh;
|
|
@ -20,5 +20,17 @@
|
|||
/**
|
||||
* This package contain support (mostly abstract) classes, that implement "base" of CLIng.
|
||||
* In packages below you find actual implementations.
|
||||
*
|
||||
* Hierarchy:
|
||||
* <ul>
|
||||
* <li>{@link org.apache.maven.cling.invoker.LookupInvoker} is the "basis", the common ground of all Maven Tools</li>
|
||||
* <li>extended by {@link org.apache.maven.cling.invoker.mvn.MavenInvoker} is the "mvn Tool"</li>
|
||||
* <li>extended by {@link org.apache.maven.cling.invoker.mvnenc.EncryptInvoker} is the "mvnenc Tool"</li>
|
||||
* <li>extended by {@link org.apache.maven.cling.invoker.mvnsh.ShellInvoker} is the "mvnsh Tool"</li>
|
||||
* </ul>
|
||||
*
|
||||
* There is one specialization of {@link org.apache.maven.cling.invoker.mvn.MavenInvoker}, the "resident"
|
||||
* {@link org.apache.maven.cling.invoker.mvn.resident.ResidentMavenInvoker}. The difference is that this invoker
|
||||
* will on close "clean up" (tear down) the instance. All invokers are re-entrant.
|
||||
*/
|
||||
package org.apache.maven.cling.invoker;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.cling.invoker.mvn.local;
|
||||
package org.apache.maven.cling.invoker.mvn;
|
||||
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Path;
|
||||
|
@ -27,8 +27,6 @@ import com.google.common.jimfs.Jimfs;
|
|||
import org.apache.maven.api.cli.Invoker;
|
||||
import org.apache.maven.api.cli.Parser;
|
||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenInvokerTestSupport;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenParser;
|
||||
import org.codehaus.plexus.classworlds.ClassWorld;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Order;
|
||||
|
@ -40,10 +38,10 @@ import org.junit.jupiter.api.io.TempDir;
|
|||
* Local UT.
|
||||
*/
|
||||
@Order(200)
|
||||
public class LocalMavenInvokerTest extends MavenInvokerTestSupport {
|
||||
public class MavenInvokerTest extends MavenInvokerTestSupport {
|
||||
@Override
|
||||
protected Invoker createInvoker() {
|
||||
return new LocalMavenInvoker(ProtoLookup.builder()
|
||||
return new MavenInvoker(ProtoLookup.builder()
|
||||
.addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader()))
|
||||
.build());
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.maven.cling.invoker.mvn.forked;
|
||||
|
||||
import java.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.cling.invoker.mvn.MavenInvokerTestSupport;
|
||||
import org.apache.maven.cling.invoker.mvn.MavenParser;
|
||||
import org.junit.jupiter.api.Order;
|
||||
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.
|
||||
*/
|
||||
@Order(300)
|
||||
public class ForkedMavenInvokerTest extends MavenInvokerTestSupport {
|
||||
|
||||
@Override
|
||||
protected Invoker createInvoker() {
|
||||
return new ForkedMavenInvoker();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parser createParser() {
|
||||
return new MavenParser();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultFs(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tempDir) throws Exception {
|
||||
invoke(tempDir, Arrays.asList("clean", "verify"));
|
||||
}
|
||||
}
|
|
@ -126,7 +126,8 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
this.originalStderr = System.err;
|
||||
this.originalClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
this.contexts = new ConcurrentHashMap<>();
|
||||
this.originalProperties = System.getProperties();
|
||||
this.originalProperties = new Properties();
|
||||
this.originalProperties.putAll(System.getProperties());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -261,7 +262,6 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
Class<?>[] parameterTypes = {String[].class, String.class, PrintStream.class, PrintStream.class};
|
||||
Method doMain = cliClass.getMethod("doMain", parameterTypes);
|
||||
exec = r -> {
|
||||
System.setProperties(null);
|
||||
System.setProperties(prepareProperties(r));
|
||||
try {
|
||||
return (int) doMain.invoke(mavenCli, new Object[] {
|
||||
|
@ -278,7 +278,6 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
Field ansiConsoleInstalled = ansiConsole.getDeclaredField("installed");
|
||||
ansiConsoleInstalled.setAccessible(true);
|
||||
exec = r -> {
|
||||
System.setProperties(null);
|
||||
System.setProperties(prepareProperties(r));
|
||||
try {
|
||||
try {
|
||||
|
@ -310,8 +309,10 @@ public class EmbeddedMavenExecutor implements Executor {
|
|||
}
|
||||
|
||||
protected Properties prepareProperties(ExecutorRequest request) {
|
||||
System.setProperties(null); // this "inits" them!
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.putAll(System.getProperties());
|
||||
properties.putAll(System.getProperties()); // get mandatory/expected init-ed above
|
||||
|
||||
properties.setProperty("user.dir", request.cwd().toString());
|
||||
properties.setProperty("user.home", request.userHomeDirectory().toString());
|
||||
|
|
|
@ -52,6 +52,10 @@ under the License.
|
|||
<groupId>org.jline</groupId>
|
||||
<artifactId>jline-builtins</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jline</groupId>
|
||||
<artifactId>jline-console</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jline</groupId>
|
||||
<artifactId>jline-console-ui</artifactId>
|
||||
|
|
5
pom.xml
5
pom.xml
|
@ -452,6 +452,11 @@ under the License.
|
|||
<artifactId>jline-builtins</artifactId>
|
||||
<version>${jlineVersion}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jline</groupId>
|
||||
<artifactId>jline-console</artifactId>
|
||||
<version>${jlineVersion}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jline</groupId>
|
||||
<artifactId>jline-console-ui</artifactId>
|
||||
|
|
Loading…
Reference in New Issue