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>
|
<includes>
|
||||||
<include>mvn</include>
|
<include>mvn</include>
|
||||||
<include>mvnenc</include>
|
<include>mvnenc</include>
|
||||||
|
<include>mvnsh</include>
|
||||||
<include>mvnDebug</include>
|
<include>mvnDebug</include>
|
||||||
<include>mvnencDebug</include>
|
<include>mvnencDebug</include>
|
||||||
<!-- This is so that CI systems can periodically run the profiler -->
|
<!-- This is so that CI systems can periodically run the profiler -->
|
||||||
|
|
|
@ -207,6 +207,9 @@ handle_args() {
|
||||||
--enc)
|
--enc)
|
||||||
MAVEN_MAIN_CLASS="org.apache.maven.cling.MavenEncCling"
|
MAVEN_MAIN_CLASS="org.apache.maven.cling.MavenEncCling"
|
||||||
;;
|
;;
|
||||||
|
--shell)
|
||||||
|
MAVEN_MAIN_CLASS="org.apache.maven.cling.MavenShellCling"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -200,6 +200,8 @@ if "%~1"=="--debug" (
|
||||||
set "MAVEN_OPTS=-agentpath:%YJPLIB%=onexit=snapshot,onexit=memory,tracing,onlylocal %MAVEN_OPTS%"
|
set "MAVEN_OPTS=-agentpath:%YJPLIB%=onexit=snapshot,onexit=memory,tracing,onlylocal %MAVEN_OPTS%"
|
||||||
) else if "%~1"=="--enc" (
|
) else if "%~1"=="--enc" (
|
||||||
set "MAVEN_MAIN_CLASS=org.apache.maven.cling.MavenEncCling"
|
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
|
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
|
@Nonnull
|
||||||
Optional<String> color();
|
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.
|
* Indicates whether to show help information.
|
||||||
*
|
*
|
||||||
|
|
|
@ -205,6 +205,34 @@ public interface ParserRequest {
|
||||||
return builder(Tools.MVNENC_CMD, Tools.MVNENC_NAME, args, logger, messageBuilderFactory);
|
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.
|
* 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_CMD = "mvnenc";
|
||||||
public static final String MVNENC_NAME = "Maven Password Encrypting Tool";
|
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
|
@Nonnull
|
||||||
Optional<String> alternatePomFile();
|
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).
|
* 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.api.cli.ParserRequest;
|
||||||
import org.apache.maven.cling.invoker.ProtoLogger;
|
import org.apache.maven.cling.invoker.ProtoLogger;
|
||||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
import org.apache.maven.cling.invoker.ProtoLookup;
|
||||||
|
import org.apache.maven.cling.invoker.mvn.MavenInvoker;
|
||||||
import org.apache.maven.cling.invoker.mvn.MavenParser;
|
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.apache.maven.jline.JLineMessageBuilderFactory;
|
||||||
import org.codehaus.plexus.classworlds.ClassWorld;
|
import org.codehaus.plexus.classworlds.ClassWorld;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ public class MavenCling extends ClingSupport {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Invoker createInvoker() {
|
protected Invoker createInvoker() {
|
||||||
return new LocalMavenInvoker(
|
return new MavenInvoker(
|
||||||
ProtoLookup.builder().addMapping(ClassWorld.class, classWorld).build());
|
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;
|
package org.apache.maven.cling.extensions;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -33,7 +30,10 @@ import java.util.stream.Collectors;
|
||||||
import org.apache.maven.RepositoryUtils;
|
import org.apache.maven.RepositoryUtils;
|
||||||
import org.apache.maven.api.Service;
|
import org.apache.maven.api.Service;
|
||||||
import org.apache.maven.api.Session;
|
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.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.model.Plugin;
|
||||||
import org.apache.maven.api.services.ArtifactCoordinatesFactory;
|
import org.apache.maven.api.services.ArtifactCoordinatesFactory;
|
||||||
import org.apache.maven.api.services.ArtifactManager;
|
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.resolution.DependencyResult;
|
||||||
import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
|
import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
|
||||||
import org.eclipse.aether.util.version.GenericVersionScheme;
|
import org.eclipse.aether.util.version.GenericVersionScheme;
|
||||||
import org.eclipse.sisu.Nullable;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,14 @@ public abstract class CommonsCliOptions implements Options {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Boolean> offline() {
|
||||||
|
if (commandLine.hasOption(CLIManager.OFFLINE)) {
|
||||||
|
return Optional.of(Boolean.TRUE);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Boolean> help() {
|
public Optional<Boolean> help() {
|
||||||
if (commandLine.hasOption(CLIManager.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 LOG_FILE = "l";
|
||||||
public static final String RAW_STREAMS = "raw-streams";
|
public static final String RAW_STREAMS = "raw-streams";
|
||||||
public static final String COLOR = "color";
|
public static final String COLOR = "color";
|
||||||
|
public static final String OFFLINE = "o";
|
||||||
public static final String HELP = "h";
|
public static final String HELP = "h";
|
||||||
|
|
||||||
// parameters handled by script
|
// parameters handled by script
|
||||||
public static final String DEBUG = "debug";
|
public static final String DEBUG = "debug";
|
||||||
public static final String ENC = "enc";
|
public static final String ENC = "enc";
|
||||||
|
public static final String SHELL = "shell";
|
||||||
public static final String YJP = "yjp";
|
public static final String YJP = "yjp";
|
||||||
|
|
||||||
// deprecated ones
|
// deprecated ones
|
||||||
|
@ -378,6 +388,10 @@ public abstract class CommonsCliOptions implements Options {
|
||||||
.optionalArg(true)
|
.optionalArg(true)
|
||||||
.desc("Defines the color mode of the output. Supported are 'auto', 'always', 'never'.")
|
.desc("Defines the color mode of the output. Supported are 'auto', 'always', 'never'.")
|
||||||
.build());
|
.build());
|
||||||
|
options.addOption(Option.builder(OFFLINE)
|
||||||
|
.longOpt("offline")
|
||||||
|
.desc("Work offline")
|
||||||
|
.build());
|
||||||
|
|
||||||
// Parameters handled by script
|
// Parameters handled by script
|
||||||
options.addOption(Option.builder()
|
options.addOption(Option.builder()
|
||||||
|
@ -388,6 +402,10 @@ public abstract class CommonsCliOptions implements Options {
|
||||||
.longOpt(ENC)
|
.longOpt(ENC)
|
||||||
.desc("Launch the Maven Encryption tool (script option).")
|
.desc("Launch the Maven Encryption tool (script option).")
|
||||||
.build());
|
.build());
|
||||||
|
options.addOption(Option.builder()
|
||||||
|
.longOpt(SHELL)
|
||||||
|
.desc("Launch the Maven Shell tool (script option).")
|
||||||
|
.build());
|
||||||
options.addOption(Option.builder()
|
options.addOption(Option.builder()
|
||||||
.longOpt(YJP)
|
.longOpt(YJP)
|
||||||
.desc("Launch the JVM with Yourkit profiler (script option).")
|
.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);
|
return returnFirstPresentOrEmpty(Options::color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Boolean> offline() {
|
||||||
|
return returnFirstPresentOrEmpty(Options::offline);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Boolean> help() {
|
public Optional<Boolean> help() {
|
||||||
return returnFirstPresentOrEmpty(Options::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.services.Lookup;
|
||||||
import org.apache.maven.api.settings.Settings;
|
import org.apache.maven.api.settings.Settings;
|
||||||
import org.apache.maven.cling.logging.Slf4jConfiguration;
|
import org.apache.maven.cling.logging.Slf4jConfiguration;
|
||||||
|
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
|
||||||
import org.apache.maven.logging.BuildEventListener;
|
import org.apache.maven.logging.BuildEventListener;
|
||||||
import org.jline.terminal.Terminal;
|
import org.jline.terminal.Terminal;
|
||||||
import org.slf4j.ILoggerFactory;
|
import org.slf4j.ILoggerFactory;
|
||||||
|
@ -47,14 +48,20 @@ public class LookupContext implements AutoCloseable {
|
||||||
public final Function<String, Path> cwdResolver;
|
public final Function<String, Path> cwdResolver;
|
||||||
public final Function<String, Path> installationResolver;
|
public final Function<String, Path> installationResolver;
|
||||||
public final Function<String, Path> userResolver;
|
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.invokerRequest = requireNonNull(invokerRequest);
|
||||||
this.cwdResolver = s -> invokerRequest.cwd().resolve(s).normalize().toAbsolutePath();
|
this.cwdResolver = s -> invokerRequest.cwd().resolve(s).normalize().toAbsolutePath();
|
||||||
this.installationResolver = s ->
|
this.installationResolver = s ->
|
||||||
invokerRequest.installationDirectory().resolve(s).normalize().toAbsolutePath();
|
invokerRequest.installationDirectory().resolve(s).normalize().toAbsolutePath();
|
||||||
this.userResolver =
|
this.userResolver =
|
||||||
s -> invokerRequest.userHomeDirectory().resolve(s).normalize().toAbsolutePath();
|
s -> invokerRequest.userHomeDirectory().resolve(s).normalize().toAbsolutePath();
|
||||||
|
this.containerCapsuleManaged = containerCapsuleManaged;
|
||||||
this.logger = invokerRequest.parserRequest().logger();
|
this.logger = invokerRequest.parserRequest().logger();
|
||||||
|
|
||||||
Map<String, String> user = new HashMap<>(invokerRequest.userProperties());
|
Map<String, String> user = new HashMap<>(invokerRequest.userProperties());
|
||||||
|
@ -84,8 +91,10 @@ public class LookupContext implements AutoCloseable {
|
||||||
public Boolean coloredOutput;
|
public Boolean coloredOutput;
|
||||||
public Terminal terminal;
|
public Terminal terminal;
|
||||||
public Consumer<String> writer;
|
public Consumer<String> writer;
|
||||||
|
|
||||||
public ContainerCapsule containerCapsule;
|
public ContainerCapsule containerCapsule;
|
||||||
public Lookup lookup;
|
public Lookup lookup;
|
||||||
|
public EventSpyDispatcher eventSpyDispatcher;
|
||||||
|
|
||||||
public BuildEventListener buildEventListener;
|
public BuildEventListener buildEventListener;
|
||||||
|
|
||||||
|
@ -93,7 +102,6 @@ public class LookupContext implements AutoCloseable {
|
||||||
public Path installationSettingsPath;
|
public Path installationSettingsPath;
|
||||||
public Path projectSettingsPath;
|
public Path projectSettingsPath;
|
||||||
public Path userSettingsPath;
|
public Path userSettingsPath;
|
||||||
|
|
||||||
public boolean interactive;
|
public boolean interactive;
|
||||||
public Path localRepositoryPath;
|
public Path localRepositoryPath;
|
||||||
public Settings effectiveSettings;
|
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) {
|
if (containerCapsule != null) {
|
||||||
try {
|
try {
|
||||||
containerCapsule.close();
|
containerCapsule.close();
|
||||||
} finally {
|
} finally {
|
||||||
|
eventSpyDispatcher = null;
|
||||||
lookup = null;
|
lookup = null;
|
||||||
containerCapsule = null;
|
containerCapsule = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.io.PrintWriter;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -34,6 +35,7 @@ import java.util.function.Function;
|
||||||
|
|
||||||
import org.apache.maven.api.Constants;
|
import org.apache.maven.api.Constants;
|
||||||
import org.apache.maven.api.ProtoSession;
|
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.Invoker;
|
||||||
import org.apache.maven.api.cli.InvokerException;
|
import org.apache.maven.api.cli.InvokerException;
|
||||||
import org.apache.maven.api.cli.InvokerRequest;
|
import org.apache.maven.api.cli.InvokerRequest;
|
||||||
|
@ -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.Slf4jConfiguration;
|
||||||
import org.apache.maven.cling.logging.Slf4jConfigurationFactory;
|
import org.apache.maven.cling.logging.Slf4jConfigurationFactory;
|
||||||
import org.apache.maven.cling.utils.CLIReportingUtils;
|
import org.apache.maven.cling.utils.CLIReportingUtils;
|
||||||
|
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
|
||||||
import org.apache.maven.execution.MavenExecutionRequest;
|
import org.apache.maven.execution.MavenExecutionRequest;
|
||||||
import org.apache.maven.internal.impl.SettingsUtilsV4;
|
import org.apache.maven.internal.impl.SettingsUtilsV4;
|
||||||
import org.apache.maven.jline.FastTerminal;
|
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.SimpleBuildEventListener;
|
||||||
import org.apache.maven.logging.api.LogLevelRecorder;
|
import org.apache.maven.logging.api.LogLevelRecorder;
|
||||||
import org.apache.maven.slf4j.MavenSimpleLogger;
|
import org.apache.maven.slf4j.MavenSimpleLogger;
|
||||||
|
import org.codehaus.plexus.PlexusContainer;
|
||||||
import org.jline.terminal.Terminal;
|
import org.jline.terminal.Terminal;
|
||||||
import org.jline.terminal.TerminalBuilder;
|
import org.jline.terminal.TerminalBuilder;
|
||||||
import org.jline.terminal.impl.AbstractPosixTerminal;
|
import org.jline.terminal.impl.AbstractPosixTerminal;
|
||||||
|
@ -92,19 +96,27 @@ import static org.apache.maven.cling.invoker.Utils.toProperties;
|
||||||
* @param <C> The context type.
|
* @param <C> The context type.
|
||||||
*/
|
*/
|
||||||
public abstract class LookupInvoker<C extends LookupContext> implements Invoker {
|
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.protoLookup = requireNonNull(protoLookup);
|
||||||
|
this.contextConsumer = contextConsumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int invoke(InvokerRequest invokerRequest) throws InvokerException {
|
public int invoke(InvokerRequest invokerRequest) throws InvokerException {
|
||||||
requireNonNull(invokerRequest);
|
requireNonNull(invokerRequest);
|
||||||
|
|
||||||
Properties oldProps = (Properties) System.getProperties().clone();
|
Properties oldProps = new Properties();
|
||||||
|
oldProps.putAll(System.getProperties());
|
||||||
ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
|
ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
|
||||||
try (C context = createContext(invokerRequest)) {
|
try (C context = createContext(invokerRequest)) {
|
||||||
|
if (contextConsumer != null) {
|
||||||
|
contextConsumer.accept(context);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (context.containerCapsule != null
|
if (context.containerCapsule != null
|
||||||
&& context.containerCapsule.currentThreadClassLoader().isPresent()) {
|
&& context.containerCapsule.currentThreadClassLoader().isPresent()) {
|
||||||
|
@ -128,8 +140,6 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
||||||
protected int doInvoke(C context) throws Exception {
|
protected int doInvoke(C context) throws Exception {
|
||||||
pushCoreProperties(context);
|
pushCoreProperties(context);
|
||||||
pushUserProperties(context);
|
pushUserProperties(context);
|
||||||
validate(context);
|
|
||||||
prepare(context);
|
|
||||||
configureLogging(context);
|
configureLogging(context);
|
||||||
createTerminal(context);
|
createTerminal(context);
|
||||||
activateLogging(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 {
|
protected void configureLogging(C context) throws Exception {
|
||||||
// LOG COLOR
|
// LOG COLOR
|
||||||
Options mavenOptions = context.invokerRequest.options();
|
Options mavenOptions = context.invokerRequest.options();
|
||||||
|
@ -251,33 +257,40 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createTerminal(C context) {
|
protected void createTerminal(C context) {
|
||||||
MessageUtils.systemInstall(
|
if (context.terminal == null) {
|
||||||
builder -> {
|
MessageUtils.systemInstall(
|
||||||
builder.streams(
|
builder -> {
|
||||||
context.invokerRequest.in().orElse(null),
|
builder.streams(
|
||||||
context.invokerRequest.out().orElse(null));
|
context.invokerRequest.in().orElse(null),
|
||||||
builder.systemOutput(TerminalBuilder.SystemOutput.ForcedSysOut);
|
context.invokerRequest.out().orElse(null));
|
||||||
// The exec builder suffers from https://github.com/jline/jline3/issues/1098
|
builder.systemOutput(TerminalBuilder.SystemOutput.ForcedSysOut);
|
||||||
// We could re-enable it when fixed to provide support for non-standard architectures,
|
// The exec builder suffers from https://github.com/jline/jline3/issues/1098
|
||||||
// for which JLine does not provide any native library.
|
// We could re-enable it when fixed to provide support for non-standard architectures,
|
||||||
builder.exec(false);
|
// for which JLine does not provide any native library.
|
||||||
if (context.coloredOutput != null) {
|
builder.exec(false);
|
||||||
builder.color(context.coloredOutput);
|
if (context.coloredOutput != null) {
|
||||||
}
|
builder.color(context.coloredOutput);
|
||||||
},
|
}
|
||||||
terminal -> doConfigureWithTerminal(context, terminal));
|
},
|
||||||
|
terminal -> doConfigureWithTerminal(context, terminal));
|
||||||
|
|
||||||
context.terminal = MessageUtils.getTerminal();
|
context.terminal = MessageUtils.getTerminal();
|
||||||
// JLine is quite slow to start due to the native library unpacking and loading
|
// JLine is quite slow to start due to the native library unpacking and loading
|
||||||
// so boot it asynchronously
|
// so boot it asynchronously
|
||||||
context.closeables.add(MessageUtils::systemUninstall);
|
context.closeables.add(MessageUtils::systemUninstall);
|
||||||
MessageUtils.registerShutdownHook(); // safety belt
|
MessageUtils.registerShutdownHook(); // safety belt
|
||||||
if (context.coloredOutput != null) {
|
if (context.coloredOutput != null) {
|
||||||
MessageUtils.setColorEnabled(context.coloredOutput);
|
MessageUtils.setColorEnabled(context.coloredOutput);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (context.coloredOutput != null) {
|
||||||
|
MessageUtils.setColorEnabled(context.coloredOutput);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doConfigureWithTerminal(C context, Terminal terminal) {
|
protected void doConfigureWithTerminal(C context, Terminal terminal) {
|
||||||
|
context.terminal = terminal;
|
||||||
Options options = context.invokerRequest.options();
|
Options options = context.invokerRequest.options();
|
||||||
if (options.rawStreams().isEmpty() || !options.rawStreams().get()) {
|
if (options.rawStreams().isEmpty() || !options.rawStreams().get()) {
|
||||||
MavenSimpleLogger stdout = (MavenSimpleLogger) context.loggerFactory.getLogger("stdout");
|
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 {
|
protected void container(C context) throws Exception {
|
||||||
context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(this, context);
|
if (context.lookup == null) {
|
||||||
context.closeables.add(context::closeContainer);
|
context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(this, context);
|
||||||
context.lookup = context.containerCapsule.getLookup();
|
context.closeables.add(context::closeContainer);
|
||||||
|
context.lookup = context.containerCapsule.getLookup();
|
||||||
// refresh logger in case container got customized by spy
|
} else {
|
||||||
org.slf4j.Logger l = context.loggerFactory.getLogger(this.getClass().getName());
|
context.containerCapsule.updateLogging(context);
|
||||||
context.logger = (level, message, error) -> l.atLevel(org.slf4j.event.Level.valueOf(level.name()))
|
}
|
||||||
.setCause(error)
|
|
||||||
.log(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ContainerCapsuleFactory<C> createContainerCapsuleFactory() {
|
protected ContainerCapsuleFactory<C> createContainerCapsuleFactory() {
|
||||||
|
@ -434,9 +445,22 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
||||||
context.protoSession = protoSession;
|
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 {
|
protected void postCommands(C context) throws Exception {
|
||||||
InvokerRequest invokerRequest = context.invokerRequest;
|
InvokerRequest invokerRequest = context.invokerRequest;
|
||||||
|
@ -465,7 +489,9 @@ public abstract class LookupInvoker<C extends LookupContext> implements Invoker
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void settings(C context) throws Exception {
|
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();
|
.build();
|
||||||
|
|
||||||
customizeSettingsRequest(context, settingsRequest);
|
customizeSettingsRequest(context, settingsRequest);
|
||||||
|
if (context.eventSpyDispatcher != null) {
|
||||||
|
context.eventSpyDispatcher.onEvent(settingsRequest);
|
||||||
|
}
|
||||||
|
|
||||||
context.logger.debug("Reading installation settings from '" + installationSettingsFile + "'");
|
context.logger.debug("Reading installation settings from '" + installationSettingsFile + "'");
|
||||||
context.logger.debug("Reading project settings from '" + projectSettingsFile + "'");
|
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);
|
SettingsBuilderResult settingsResult = settingsBuilder.build(settingsRequest);
|
||||||
customizeSettingsResult(context, settingsResult);
|
customizeSettingsResult(context, settingsResult);
|
||||||
|
if (context.eventSpyDispatcher != null) {
|
||||||
|
context.eventSpyDispatcher.onEvent(settingsResult);
|
||||||
|
}
|
||||||
|
|
||||||
context.effectiveSettings = settingsResult.getEffectiveSettings();
|
context.effectiveSettings = settingsResult.getEffectiveSettings();
|
||||||
context.interactive = mayDisableInteractiveMode(context, context.effectiveSettings.isInteractiveMode());
|
context.interactive = mayDisableInteractiveMode(context, context.effectiveSettings.isInteractiveMode());
|
||||||
|
|
|
@ -79,14 +79,6 @@ public class CommonsCliMavenOptions extends CommonsCliOptions implements MavenOp
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Boolean> offline() {
|
|
||||||
if (commandLine.hasOption(CLIManager.OFFLINE)) {
|
|
||||||
return Optional.of(Boolean.TRUE);
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Boolean> nonRecursive() {
|
public Optional<Boolean> nonRecursive() {
|
||||||
if (commandLine.hasOption(CLIManager.NON_RECURSIVE)) {
|
if (commandLine.hasOption(CLIManager.NON_RECURSIVE)) {
|
||||||
|
@ -263,7 +255,6 @@ public class CommonsCliMavenOptions extends CommonsCliOptions implements MavenOp
|
||||||
|
|
||||||
protected static class CLIManager extends CommonsCliOptions.CLIManager {
|
protected static class CLIManager extends CommonsCliOptions.CLIManager {
|
||||||
public static final String ALTERNATE_POM_FILE = "f";
|
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 NON_RECURSIVE = "N";
|
||||||
public static final String UPDATE_SNAPSHOTS = "U";
|
public static final String UPDATE_SNAPSHOTS = "U";
|
||||||
public static final String ACTIVATE_PROFILES = "P";
|
public static final String ACTIVATE_PROFILES = "P";
|
||||||
|
@ -293,10 +284,6 @@ public class CommonsCliMavenOptions extends CommonsCliOptions implements MavenOp
|
||||||
.hasArg()
|
.hasArg()
|
||||||
.desc("Force the use of an alternate POM file (or directory with pom.xml)")
|
.desc("Force the use of an alternate POM file (or directory with pom.xml)")
|
||||||
.build());
|
.build());
|
||||||
options.addOption(Option.builder(OFFLINE)
|
|
||||||
.longOpt("offline")
|
|
||||||
.desc("Work offline")
|
|
||||||
.build());
|
|
||||||
options.addOption(Option.builder(NON_RECURSIVE)
|
options.addOption(Option.builder(NON_RECURSIVE)
|
||||||
.longOpt("non-recursive")
|
.longOpt("non-recursive")
|
||||||
.desc(
|
.desc(
|
||||||
|
|
|
@ -54,11 +54,6 @@ public class LayeredMavenOptions<O extends MavenOptions> extends LayeredOptions<
|
||||||
return returnFirstPresentOrEmpty(MavenOptions::alternatePomFile);
|
return returnFirstPresentOrEmpty(MavenOptions::alternatePomFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Boolean> offline() {
|
|
||||||
return returnFirstPresentOrEmpty(MavenOptions::offline);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Boolean> nonRecursive() {
|
public Optional<Boolean> nonRecursive() {
|
||||||
return returnFirstPresentOrEmpty(MavenOptions::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.Maven;
|
||||||
import org.apache.maven.api.cli.InvokerRequest;
|
import org.apache.maven.api.cli.InvokerRequest;
|
||||||
import org.apache.maven.cling.invoker.LookupContext;
|
import org.apache.maven.cling.invoker.LookupContext;
|
||||||
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
|
|
||||||
|
|
||||||
@SuppressWarnings("VisibilityModifier")
|
@SuppressWarnings("VisibilityModifier")
|
||||||
public class MavenContext extends LookupContext {
|
public class MavenContext extends LookupContext {
|
||||||
public MavenContext(InvokerRequest invokerRequest) {
|
public MavenContext(InvokerRequest invokerRequest) {
|
||||||
super(invokerRequest);
|
this(invokerRequest, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MavenContext(InvokerRequest invokerRequest, boolean containerCapsuleManaged) {
|
||||||
|
super(invokerRequest, containerCapsuleManaged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventSpyDispatcher eventSpyDispatcher;
|
|
||||||
public Maven maven;
|
public Maven maven;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void closeContainer() {
|
public void doCloseContainer() {
|
||||||
eventSpyDispatcher = null;
|
try {
|
||||||
maven = null;
|
super.doCloseContainer();
|
||||||
super.closeContainer();
|
} finally {
|
||||||
|
maven = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,10 @@ import java.io.FileNotFoundException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -33,28 +33,26 @@ import org.apache.maven.InternalErrorException;
|
||||||
import org.apache.maven.Maven;
|
import org.apache.maven.Maven;
|
||||||
import org.apache.maven.api.Constants;
|
import org.apache.maven.api.Constants;
|
||||||
import org.apache.maven.api.MonotonicClock;
|
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.InvokerRequest;
|
||||||
import org.apache.maven.api.cli.Logger;
|
import org.apache.maven.api.cli.Logger;
|
||||||
import org.apache.maven.api.cli.mvn.MavenOptions;
|
import org.apache.maven.api.cli.mvn.MavenOptions;
|
||||||
import org.apache.maven.api.services.BuilderProblem;
|
import org.apache.maven.api.services.BuilderProblem;
|
||||||
import org.apache.maven.api.services.Lookup;
|
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.Source;
|
||||||
import org.apache.maven.api.services.ToolchainsBuilder;
|
import org.apache.maven.api.services.ToolchainsBuilder;
|
||||||
import org.apache.maven.api.services.ToolchainsBuilderRequest;
|
import org.apache.maven.api.services.ToolchainsBuilderRequest;
|
||||||
import org.apache.maven.api.services.ToolchainsBuilderResult;
|
import org.apache.maven.api.services.ToolchainsBuilderResult;
|
||||||
import org.apache.maven.api.services.model.ModelProcessor;
|
import org.apache.maven.api.services.model.ModelProcessor;
|
||||||
import org.apache.maven.cling.event.ExecutionEventLogger;
|
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.LookupInvoker;
|
||||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
|
||||||
import org.apache.maven.cling.invoker.Utils;
|
import org.apache.maven.cling.invoker.Utils;
|
||||||
import org.apache.maven.cling.transfer.ConsoleMavenTransferListener;
|
import org.apache.maven.cling.transfer.ConsoleMavenTransferListener;
|
||||||
import org.apache.maven.cling.transfer.QuietMavenTransferListener;
|
import org.apache.maven.cling.transfer.QuietMavenTransferListener;
|
||||||
import org.apache.maven.cling.transfer.SimplexTransferListener;
|
import org.apache.maven.cling.transfer.SimplexTransferListener;
|
||||||
import org.apache.maven.cling.transfer.Slf4jMavenTransferListener;
|
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.DefaultExceptionHandler;
|
||||||
import org.apache.maven.exception.ExceptionHandler;
|
import org.apache.maven.exception.ExceptionHandler;
|
||||||
import org.apache.maven.exception.ExceptionSummary;
|
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.LoggingExecutionListener;
|
||||||
import org.apache.maven.logging.MavenTransferListener;
|
import org.apache.maven.logging.MavenTransferListener;
|
||||||
import org.apache.maven.project.MavenProject;
|
import org.apache.maven.project.MavenProject;
|
||||||
import org.codehaus.plexus.PlexusContainer;
|
|
||||||
import org.eclipse.aether.DefaultRepositoryCache;
|
import org.eclipse.aether.DefaultRepositoryCache;
|
||||||
import org.eclipse.aether.transfer.TransferListener;
|
import org.eclipse.aether.transfer.TransferListener;
|
||||||
|
|
||||||
import static java.util.Comparator.comparing;
|
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.
|
* The Maven invoker, that expects whole Maven on classpath and invokes it.
|
||||||
*
|
|
||||||
* @param <C> The context type.
|
|
||||||
*/
|
*/
|
||||||
public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker<C> {
|
public class MavenInvoker extends LookupInvoker<MavenContext> {
|
||||||
public MavenInvoker(ProtoLookup protoLookup) {
|
public MavenInvoker(Lookup protoLookup) {
|
||||||
super(protoLookup);
|
this(protoLookup, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MavenInvoker(Lookup protoLookup, @Nullable Consumer<LookupContext> contextConsumer) {
|
||||||
|
super(protoLookup, contextConsumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
MavenExecutionRequest request = prepareMavenExecutionRequest();
|
||||||
toolchains(context, request);
|
toolchains(context, request);
|
||||||
populateRequest(context, context.lookup, request);
|
populateRequest(context, context.lookup, request);
|
||||||
|
@ -113,26 +116,15 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void lookup(C context) throws Exception {
|
protected void lookup(MavenContext context) throws Exception {
|
||||||
context.eventSpyDispatcher = context.lookup.lookup(EventSpyDispatcher.class);
|
if (context.maven == null) {
|
||||||
context.maven = context.lookup.lookup(Maven.class);
|
super.lookup(context);
|
||||||
|
context.maven = context.lookup.lookup(Maven.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init(C context) throws Exception {
|
protected void postCommands(MavenContext 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 {
|
|
||||||
super.postCommands(context);
|
super.postCommands(context);
|
||||||
|
|
||||||
InvokerRequest invokerRequest = context.invokerRequest;
|
InvokerRequest invokerRequest = context.invokerRequest;
|
||||||
|
@ -145,21 +137,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected void toolchains(MavenContext context, MavenExecutionRequest request) throws Exception {
|
||||||
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 {
|
|
||||||
Path userToolchainsFile = null;
|
Path userToolchainsFile = null;
|
||||||
if (context.invokerRequest.options().altUserToolchains().isPresent()) {
|
if (context.invokerRequest.options().altUserToolchains().isPresent()) {
|
||||||
userToolchainsFile = context.cwdResolver.apply(
|
userToolchainsFile = context.cwdResolver.apply(
|
||||||
|
@ -240,7 +218,8 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
super.populateRequest(context, lookup, request);
|
||||||
if (context.invokerRequest.rootDirectory().isEmpty()) {
|
if (context.invokerRequest.rootDirectory().isEmpty()) {
|
||||||
// maven requires this to be set; so default it (and see below at POM)
|
// 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();
|
Path current = context.invokerRequest.cwd();
|
||||||
MavenOptions options = (MavenOptions) context.invokerRequest.options();
|
MavenOptions options = (MavenOptions) context.invokerRequest.options();
|
||||||
if (options.alternatePomFile().isPresent()) {
|
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();
|
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||||
if (mavenOptions.failFast().isPresent()) {
|
if (mavenOptions.failFast().isPresent()) {
|
||||||
return MavenExecutionRequest.REACTOR_FAIL_FAST;
|
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();
|
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||||
if (mavenOptions.strictChecksums().orElse(false)) {
|
if (mavenOptions.strictChecksums().orElse(false)) {
|
||||||
return MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
|
return MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
|
||||||
|
@ -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());
|
ExecutionListener listener = new ExecutionEventLogger(context.invokerRequest.messageBuilderFactory());
|
||||||
if (context.eventSpyDispatcher != null) {
|
if (context.eventSpyDispatcher != null) {
|
||||||
listener = context.eventSpyDispatcher.chainListener(listener);
|
listener = context.eventSpyDispatcher.chainListener(listener);
|
||||||
|
@ -369,7 +348,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
||||||
return new LoggingExecutionListener(listener, determineBuildEventListener(context));
|
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 quiet = context.invokerRequest.options().quiet().orElse(false);
|
||||||
boolean logFile = context.invokerRequest.options().logFile().isPresent();
|
boolean logFile = context.invokerRequest.options().logFile().isPresent();
|
||||||
boolean runningOnCI = isRunningOnCI(context);
|
boolean runningOnCI = isRunningOnCI(context);
|
||||||
|
@ -390,7 +369,7 @@ public abstract class MavenInvoker<C extends MavenContext> extends LookupInvoker
|
||||||
return new MavenTransferListener(delegate, determineBuildEventListener(context));
|
return new MavenTransferListener(delegate, determineBuildEventListener(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String determineMakeBehavior(C context) {
|
protected String determineMakeBehavior(MavenContext context) {
|
||||||
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||||
if (mavenOptions.alsoMake().isPresent()
|
if (mavenOptions.alsoMake().isPresent()
|
||||||
&& mavenOptions.alsoMakeDependents().isEmpty()) {
|
&& 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();
|
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||||
if (mavenOptions.projects().isPresent()
|
if (mavenOptions.projects().isPresent()
|
||||||
&& !mavenOptions.projects().get().isEmpty()) {
|
&& !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();
|
MavenOptions mavenOptions = (MavenOptions) context.invokerRequest.options();
|
||||||
if (mavenOptions.activatedProfiles().isPresent()
|
if (mavenOptions.activatedProfiles().isPresent()
|
||||||
&& !mavenOptions.activatedProfiles().get().isEmpty()) {
|
&& !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);
|
context.eventSpyDispatcher.onEvent(request);
|
||||||
|
|
||||||
MavenExecutionResult result;
|
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("");
|
||||||
context.logger.error("After correcting the problems, you can resume the build with the command");
|
context.logger.error("After correcting the problems, you can resume the build with the command");
|
||||||
context.logger.error(
|
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 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 = "";
|
String referenceKey = "";
|
||||||
|
|
||||||
if (summary.getReference() != null && !summary.getReference().isEmpty()) {
|
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.InvokerException;
|
||||||
import org.apache.maven.api.cli.InvokerRequest;
|
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;
|
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
|
* 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).
|
* 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) {
|
public ResidentMavenInvoker(Lookup protoLookup) {
|
||||||
super(protoLookup);
|
super(protoLookup, null);
|
||||||
this.residentContext = new ConcurrentHashMap<>();
|
this.residentContext = new ConcurrentHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws InvokerException {
|
public void close() throws InvokerException {
|
||||||
ArrayList<InvokerException> exceptions = new ArrayList<>();
|
ArrayList<InvokerException> exceptions = new ArrayList<>();
|
||||||
for (ResidentMavenContext context : residentContext.values()) {
|
for (MavenContext context : residentContext.values()) {
|
||||||
try {
|
try {
|
||||||
context.shutDown();
|
context.doCloseContainer();
|
||||||
} catch (InvokerException e) {
|
} catch (InvokerException e) {
|
||||||
exceptions.add(e);
|
exceptions.add(e);
|
||||||
}
|
}
|
||||||
|
@ -58,31 +61,25 @@ public class ResidentMavenInvoker extends MavenInvoker<ResidentMavenContext> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResidentMavenContext createContext(InvokerRequest invokerRequest) {
|
protected MavenContext createContext(InvokerRequest invokerRequest) {
|
||||||
return residentContext
|
|
||||||
.computeIfAbsent(getContextId(invokerRequest), k -> new ResidentMavenContext(invokerRequest))
|
|
||||||
.copy(invokerRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getContextId(InvokerRequest invokerRequest) {
|
|
||||||
// TODO: in a moment Maven stop pushing user properties to system properties (and maybe something more)
|
// 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?
|
// and allow multiple instances per JVM, this may become a pool? derive key based in invokerRequest?
|
||||||
return "resident";
|
MavenContext result = residentContext.computeIfAbsent("resident", k -> new MavenContext(invokerRequest, false));
|
||||||
|
return copyIfDifferent(result, invokerRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected MavenContext copyIfDifferent(MavenContext mavenContext, InvokerRequest invokerRequest) {
|
||||||
protected void container(ResidentMavenContext context) throws Exception {
|
if (invokerRequest == mavenContext.invokerRequest) {
|
||||||
if (context.containerCapsule == null) {
|
return mavenContext;
|
||||||
super.container(context);
|
|
||||||
} else {
|
|
||||||
context.containerCapsule.updateLogging(context);
|
|
||||||
}
|
}
|
||||||
}
|
MavenContext shadow = new MavenContext(invokerRequest, false);
|
||||||
|
|
||||||
@Override
|
// we carry over only "resident" things
|
||||||
protected void lookup(ResidentMavenContext context) throws Exception {
|
shadow.containerCapsule = mavenContext.containerCapsule;
|
||||||
if (context.maven == null) {
|
shadow.lookup = mavenContext.lookup;
|
||||||
super.lookup(context);
|
shadow.eventSpyDispatcher = mavenContext.eventSpyDispatcher;
|
||||||
}
|
shadow.maven = mavenContext.maven;
|
||||||
|
|
||||||
|
return shadow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,12 @@ import org.jline.utils.AttributedStyle;
|
||||||
|
|
||||||
@SuppressWarnings("VisibilityModifier")
|
@SuppressWarnings("VisibilityModifier")
|
||||||
public class EncryptContext extends LookupContext {
|
public class EncryptContext extends LookupContext {
|
||||||
protected EncryptContext(InvokerRequest invokerRequest) {
|
public EncryptContext(InvokerRequest invokerRequest) {
|
||||||
super(invokerRequest);
|
this(invokerRequest, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EncryptContext(InvokerRequest invokerRequest, boolean containerCapsuleManaged) {
|
||||||
|
super(invokerRequest, containerCapsuleManaged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Goal> goals;
|
public Map<String, Goal> goals;
|
||||||
|
|
|
@ -20,11 +20,14 @@ package org.apache.maven.cling.invoker.mvnenc;
|
||||||
|
|
||||||
import java.io.InterruptedIOException;
|
import java.io.InterruptedIOException;
|
||||||
import java.util.ArrayList;
|
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.InvokerRequest;
|
||||||
import org.apache.maven.api.cli.mvnenc.EncryptOptions;
|
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.LookupInvoker;
|
||||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
|
||||||
import org.apache.maven.cling.utils.CLIReportingUtils;
|
import org.apache.maven.cling.utils.CLIReportingUtils;
|
||||||
import org.jline.reader.LineReaderBuilder;
|
import org.jline.reader.LineReaderBuilder;
|
||||||
import org.jline.reader.UserInterruptException;
|
import org.jline.reader.UserInterruptException;
|
||||||
|
@ -37,13 +40,17 @@ import org.jline.utils.Colors;
|
||||||
*/
|
*/
|
||||||
public class EncryptInvoker extends LookupInvoker<EncryptContext> {
|
public class EncryptInvoker extends LookupInvoker<EncryptContext> {
|
||||||
|
|
||||||
public EncryptInvoker(ProtoLookup protoLookup) {
|
public static final int OK = 0; // OK
|
||||||
super(protoLookup);
|
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
|
public EncryptInvoker(Lookup protoLookup, @Nullable Consumer<LookupContext> contextConsumer) {
|
||||||
protected int execute(EncryptContext context) throws Exception {
|
super(protoLookup, contextConsumer);
|
||||||
return doExecute(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,16 +59,15 @@ public class EncryptInvoker extends LookupInvoker<EncryptContext> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void lookup(EncryptContext context) {
|
protected void lookup(EncryptContext context) throws Exception {
|
||||||
context.goals = context.lookup.lookupMap(Goal.class);
|
if (context.goals == null) {
|
||||||
|
super.lookup(context);
|
||||||
|
context.goals = context.lookup.lookupMap(Goal.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int OK = 0; // OK
|
@Override
|
||||||
public static final int ERROR = 1; // "generic" error
|
protected int execute(EncryptContext context) throws Exception {
|
||||||
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 {
|
|
||||||
try {
|
try {
|
||||||
context.header = new ArrayList<>();
|
context.header = new ArrayList<>();
|
||||||
context.style = new AttributedStyle();
|
context.style = new AttributedStyle();
|
||||||
|
|
|
@ -18,10 +18,9 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.maven.cling.invoker.mvnenc.goals;
|
package org.apache.maven.cling.invoker.mvnenc.goals;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import org.apache.maven.api.di.Inject;
|
||||||
import javax.inject.Named;
|
import org.apache.maven.api.di.Named;
|
||||||
import javax.inject.Singleton;
|
import org.apache.maven.api.di.Singleton;
|
||||||
|
|
||||||
import org.apache.maven.api.services.MessageBuilderFactory;
|
import org.apache.maven.api.services.MessageBuilderFactory;
|
||||||
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
||||||
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
||||||
|
|
|
@ -18,10 +18,9 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.maven.cling.invoker.mvnenc.goals;
|
package org.apache.maven.cling.invoker.mvnenc.goals;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import org.apache.maven.api.di.Inject;
|
||||||
import javax.inject.Named;
|
import org.apache.maven.api.di.Named;
|
||||||
import javax.inject.Singleton;
|
import org.apache.maven.api.di.Singleton;
|
||||||
|
|
||||||
import org.apache.maven.api.services.MessageBuilderFactory;
|
import org.apache.maven.api.services.MessageBuilderFactory;
|
||||||
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
||||||
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
||||||
|
|
|
@ -18,10 +18,9 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.maven.cling.invoker.mvnenc.goals;
|
package org.apache.maven.cling.invoker.mvnenc.goals;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import org.apache.maven.api.di.Inject;
|
||||||
import javax.inject.Named;
|
import org.apache.maven.api.di.Named;
|
||||||
import javax.inject.Singleton;
|
import org.apache.maven.api.di.Singleton;
|
||||||
|
|
||||||
import org.apache.maven.api.services.MessageBuilderFactory;
|
import org.apache.maven.api.services.MessageBuilderFactory;
|
||||||
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
||||||
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
|
||||||
|
|
|
@ -18,15 +18,17 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.maven.cling.invoker.mvnenc.goals;
|
package org.apache.maven.cling.invoker.mvnenc.goals;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import java.io.IOError;
|
||||||
import javax.inject.Named;
|
import java.io.InterruptedIOException;
|
||||||
import javax.inject.Singleton;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.apache.maven.api.cli.mvnenc.EncryptOptions;
|
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.api.services.MessageBuilderFactory;
|
||||||
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
import org.apache.maven.cling.invoker.mvnenc.EncryptContext;
|
||||||
import org.codehaus.plexus.components.secdispatcher.DispatcherMeta;
|
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.PromptResultItemIF;
|
||||||
import org.jline.consoleui.prompt.builder.ListPromptBuilder;
|
import org.jline.consoleui.prompt.builder.ListPromptBuilder;
|
||||||
import org.jline.consoleui.prompt.builder.PromptBuilder;
|
import org.jline.consoleui.prompt.builder.PromptBuilder;
|
||||||
import org.jline.reader.Candidate;
|
import org.jline.reader.UserInterruptException;
|
||||||
import org.jline.reader.Completer;
|
|
||||||
import org.jline.reader.LineReader;
|
|
||||||
import org.jline.reader.ParsedLine;
|
|
||||||
import org.jline.utils.Colors;
|
import org.jline.utils.Colors;
|
||||||
import org.jline.utils.OSUtils;
|
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.BAD_OPERATION;
|
||||||
|
import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.CANCELED;
|
||||||
import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK;
|
import static org.apache.maven.cling.invoker.mvnenc.EncryptInvoker.OK;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,6 +63,7 @@ public class Init extends InteractiveGoalSupport {
|
||||||
super(messageBuilderFactory, secDispatcher);
|
super(messageBuilderFactory, secDispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("MethodLength")
|
||||||
@Override
|
@Override
|
||||||
public int doExecute(EncryptContext context) throws Exception {
|
public int doExecute(EncryptContext context) throws Exception {
|
||||||
EncryptOptions options = (EncryptOptions) context.invokerRequest.options();
|
EncryptOptions options = (EncryptOptions) context.invokerRequest.options();
|
||||||
|
@ -87,125 +88,128 @@ public class Init extends InteractiveGoalSupport {
|
||||||
promptConfig = new ConsolePrompt.UiConfig("❯", "◯ ", "◉ ", "◯ ");
|
promptConfig = new ConsolePrompt.UiConfig("❯", "◯ ", "◉ ", "◯ ");
|
||||||
}
|
}
|
||||||
promptConfig.setCancellableFirstPrompt(true);
|
promptConfig.setCancellableFirstPrompt(true);
|
||||||
ConsolePrompt prompt = new ConsolePrompt(context.reader, context.terminal, promptConfig);
|
|
||||||
|
|
||||||
SettingsSecurity config = secDispatcher.readConfiguration(true);
|
SettingsSecurity config = secDispatcher.readConfiguration(true);
|
||||||
|
|
||||||
// reset config
|
// reset config
|
||||||
config.setDefaultDispatcher(null);
|
config.setDefaultDispatcher(null);
|
||||||
config.getConfigurations().clear();
|
config.getConfigurations().clear();
|
||||||
|
|
||||||
Map<String, PromptResultItemIF> result = prompt.prompt(
|
try (ConsolePrompt prompt = new ConsolePrompt(context.reader, context.terminal, promptConfig)) {
|
||||||
context.header, dispatcherPrompt(prompt.getPromptBuilder()).build());
|
Map<String, PromptResultItemIF> dispatcherResult = new HashMap<>();
|
||||||
if (result == null) {
|
Map<String, PromptResultItemIF> dispatcherConfigResult = new HashMap<>();
|
||||||
throw new InterruptedException();
|
Map<String, PromptResultItemIF> confirmChoice = new HashMap<>();
|
||||||
}
|
|
||||||
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());
|
|
||||||
|
|
||||||
DispatcherMeta meta = secDispatcher.availableDispatchers().stream()
|
prompt.prompt(
|
||||||
.filter(d -> Objects.equals(config.getDefaultDispatcher(), d.name()))
|
context.header, dispatcherPrompt(prompt.getPromptBuilder()).build(), dispatcherResult);
|
||||||
.findFirst()
|
if (dispatcherResult.isEmpty()) {
|
||||||
.orElseThrow();
|
|
||||||
if (!meta.fields().isEmpty()) {
|
|
||||||
result = prompt.prompt(
|
|
||||||
context.header,
|
|
||||||
configureDispatcher(context, meta, prompt.getPromptBuilder())
|
|
||||||
.build());
|
|
||||||
if (result == null) {
|
|
||||||
throw new InterruptedException();
|
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()
|
DispatcherMeta meta = secDispatcher.availableDispatchers().stream()
|
||||||
.filter(e -> e.getValue().getResult().contains("$"))
|
.filter(d -> Objects.equals(config.getDefaultDispatcher(), d.name()))
|
||||||
.toList();
|
.findFirst()
|
||||||
if (!editables.isEmpty()) {
|
.orElseThrow();
|
||||||
context.addInHeader("");
|
if (!meta.fields().isEmpty()) {
|
||||||
context.addInHeader("Please customize the editable value:");
|
prompt.prompt(
|
||||||
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(
|
|
||||||
context.header,
|
context.header,
|
||||||
prompt.getPromptBuilder()
|
configureDispatcher(context, meta, prompt.getPromptBuilder())
|
||||||
.createInputPrompt()
|
.build(),
|
||||||
.name("edit")
|
dispatcherConfigResult);
|
||||||
.message(template)
|
if (dispatcherConfigResult.isEmpty()) {
|
||||||
.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) {
|
|
||||||
throw new InterruptedException();
|
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();
|
if (yes) {
|
||||||
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());
|
|
||||||
secDispatcher.writeConfiguration(config);
|
secDispatcher.writeConfiguration(config);
|
||||||
} else {
|
} else {
|
||||||
context.terminal
|
context.addInHeader("");
|
||||||
.writer()
|
context.addInHeader("Values set:");
|
||||||
.println(messageBuilderFactory
|
context.addInHeader("defaultDispatcher=" + config.getDefaultDispatcher());
|
||||||
.builder()
|
for (Config c : config.getConfigurations()) {
|
||||||
.warning("Values not accepted; not saving configuration.")
|
context.addInHeader(" dispatcherName=" + c.getName());
|
||||||
.build());
|
for (ConfigProperty cp : c.getProperties()) {
|
||||||
return BAD_OPERATION;
|
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
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* 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> {
|
package org.apache.maven.cling.invoker.mvnsh;
|
||||||
public LocalMavenInvoker(ProtoLookup protoLookup) {
|
|
||||||
super(protoLookup);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected MavenContext createContext(InvokerRequest invokerRequest) throws InvokerException {
|
|
||||||
return new MavenContext(invokerRequest);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,5 +20,17 @@
|
||||||
/**
|
/**
|
||||||
* This package contain support (mostly abstract) classes, that implement "base" of CLIng.
|
* This package contain support (mostly abstract) classes, that implement "base" of CLIng.
|
||||||
* In packages below you find actual implementations.
|
* 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;
|
package org.apache.maven.cling.invoker;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* 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.FileSystem;
|
||||||
import java.nio.file.Path;
|
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.Invoker;
|
||||||
import org.apache.maven.api.cli.Parser;
|
import org.apache.maven.api.cli.Parser;
|
||||||
import org.apache.maven.cling.invoker.ProtoLookup;
|
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.codehaus.plexus.classworlds.ClassWorld;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Order;
|
import org.junit.jupiter.api.Order;
|
||||||
|
@ -40,10 +38,10 @@ import org.junit.jupiter.api.io.TempDir;
|
||||||
* Local UT.
|
* Local UT.
|
||||||
*/
|
*/
|
||||||
@Order(200)
|
@Order(200)
|
||||||
public class LocalMavenInvokerTest extends MavenInvokerTestSupport {
|
public class MavenInvokerTest extends MavenInvokerTestSupport {
|
||||||
@Override
|
@Override
|
||||||
protected Invoker createInvoker() {
|
protected Invoker createInvoker() {
|
||||||
return new LocalMavenInvoker(ProtoLookup.builder()
|
return new MavenInvoker(ProtoLookup.builder()
|
||||||
.addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader()))
|
.addMapping(ClassWorld.class, new ClassWorld("plexus.core", ClassLoader.getSystemClassLoader()))
|
||||||
.build());
|
.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.originalStderr = System.err;
|
||||||
this.originalClassLoader = Thread.currentThread().getContextClassLoader();
|
this.originalClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
this.contexts = new ConcurrentHashMap<>();
|
this.contexts = new ConcurrentHashMap<>();
|
||||||
this.originalProperties = System.getProperties();
|
this.originalProperties = new Properties();
|
||||||
|
this.originalProperties.putAll(System.getProperties());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -261,7 +262,6 @@ public class EmbeddedMavenExecutor implements Executor {
|
||||||
Class<?>[] parameterTypes = {String[].class, String.class, PrintStream.class, PrintStream.class};
|
Class<?>[] parameterTypes = {String[].class, String.class, PrintStream.class, PrintStream.class};
|
||||||
Method doMain = cliClass.getMethod("doMain", parameterTypes);
|
Method doMain = cliClass.getMethod("doMain", parameterTypes);
|
||||||
exec = r -> {
|
exec = r -> {
|
||||||
System.setProperties(null);
|
|
||||||
System.setProperties(prepareProperties(r));
|
System.setProperties(prepareProperties(r));
|
||||||
try {
|
try {
|
||||||
return (int) doMain.invoke(mavenCli, new Object[] {
|
return (int) doMain.invoke(mavenCli, new Object[] {
|
||||||
|
@ -278,7 +278,6 @@ public class EmbeddedMavenExecutor implements Executor {
|
||||||
Field ansiConsoleInstalled = ansiConsole.getDeclaredField("installed");
|
Field ansiConsoleInstalled = ansiConsole.getDeclaredField("installed");
|
||||||
ansiConsoleInstalled.setAccessible(true);
|
ansiConsoleInstalled.setAccessible(true);
|
||||||
exec = r -> {
|
exec = r -> {
|
||||||
System.setProperties(null);
|
|
||||||
System.setProperties(prepareProperties(r));
|
System.setProperties(prepareProperties(r));
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
|
@ -310,8 +309,10 @@ public class EmbeddedMavenExecutor implements Executor {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Properties prepareProperties(ExecutorRequest request) {
|
protected Properties prepareProperties(ExecutorRequest request) {
|
||||||
|
System.setProperties(null); // this "inits" them!
|
||||||
|
|
||||||
Properties properties = new Properties();
|
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.dir", request.cwd().toString());
|
||||||
properties.setProperty("user.home", request.userHomeDirectory().toString());
|
properties.setProperty("user.home", request.userHomeDirectory().toString());
|
||||||
|
|
|
@ -52,6 +52,10 @@ under the License.
|
||||||
<groupId>org.jline</groupId>
|
<groupId>org.jline</groupId>
|
||||||
<artifactId>jline-builtins</artifactId>
|
<artifactId>jline-builtins</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jline</groupId>
|
||||||
|
<artifactId>jline-console</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jline</groupId>
|
<groupId>org.jline</groupId>
|
||||||
<artifactId>jline-console-ui</artifactId>
|
<artifactId>jline-console-ui</artifactId>
|
||||||
|
|
5
pom.xml
5
pom.xml
|
@ -452,6 +452,11 @@ under the License.
|
||||||
<artifactId>jline-builtins</artifactId>
|
<artifactId>jline-builtins</artifactId>
|
||||||
<version>${jlineVersion}</version>
|
<version>${jlineVersion}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jline</groupId>
|
||||||
|
<artifactId>jline-console</artifactId>
|
||||||
|
<version>${jlineVersion}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jline</groupId>
|
<groupId>org.jline</groupId>
|
||||||
<artifactId>jline-console-ui</artifactId>
|
<artifactId>jline-console-ui</artifactId>
|
||||||
|
|
Loading…
Reference in New Issue