blob: 7afe07385c81956383717ab7dea08c005b77163f [file] [log] [blame]
package org.apache.maven.cli;
/*
* 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.
*/
import com.google.inject.AbstractModule;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.apache.maven.BuildAbort;
import org.apache.maven.InternalErrorException;
import org.apache.maven.Maven;
import org.apache.maven.building.FileSource;
import org.apache.maven.building.Problem;
import org.apache.maven.building.Source;
import org.apache.maven.cli.configuration.ConfigurationProcessor;
import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor;
import org.apache.maven.cli.event.DefaultEventSpyContext;
import org.apache.maven.cli.event.ExecutionEventLogger;
import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
import org.apache.maven.cli.internal.extension.model.CoreExtension;
import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader;
import org.apache.maven.cli.logging.Slf4jConfiguration;
import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
import org.apache.maven.cli.logging.Slf4jLoggerManager;
import org.apache.maven.cli.logging.Slf4jStdoutLogger;
import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
import org.apache.maven.cli.transfer.QuietMavenTransferListener;
import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.exception.DefaultExceptionHandler;
import org.apache.maven.exception.ExceptionHandler;
import org.apache.maven.exception.ExceptionSummary;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.ExecutionListener;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionRequestPopulationException;
import org.apache.maven.execution.MavenExecutionRequestPopulator;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.extension.internal.CoreExtensionEntry;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.logwrapper.LogLevelRecorder;
import org.apache.maven.logwrapper.MavenSlf4jWrapperFactory;
import org.apache.maven.model.building.ModelProcessor;
import org.apache.maven.project.MavenProject;
import org.apache.maven.properties.internal.EnvironmentUtils;
import org.apache.maven.properties.internal.SystemProperties;
import org.apache.maven.session.scope.internal.SessionScopeModule;
import org.apache.maven.shared.utils.logging.MessageBuilder;
import org.apache.maven.shared.utils.logging.MessageUtils;
import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest;
import org.apache.maven.toolchain.building.ToolchainsBuilder;
import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
import org.codehaus.plexus.ContainerConfiguration;
import org.codehaus.plexus.DefaultContainerConfiguration;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusConstants;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.logging.LoggerManager;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.eclipse.aether.transfer.TransferListener;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
import java.io.BufferedInputStream;
import java.io.Console;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.util.Comparator.comparing;
import static org.apache.maven.cli.ResolveFile.resolveFile;
import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
// TODO push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs
/**
* @author Jason van Zyl
*/
public class MavenCli
{
public static final String LOCAL_REPO_PROPERTY = "maven.repo.local";
public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory";
public static final String USER_HOME = System.getProperty( "user.home" );
public static final File USER_MAVEN_CONFIGURATION_HOME = new File( USER_HOME, ".m2" );
public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File( USER_MAVEN_CONFIGURATION_HOME, "toolchains.xml" );
public static final File DEFAULT_GLOBAL_TOOLCHAINS_FILE =
new File( System.getProperty( "maven.conf" ), "toolchains.xml" );
private static final String EXT_CLASS_PATH = "maven.ext.class.path";
private static final String EXTENSIONS_FILENAME = ".mvn/extensions.xml";
private static final String MVN_MAVEN_CONFIG = ".mvn/maven.config";
public static final String STYLE_COLOR_PROPERTY = "style.color";
private ClassWorld classWorld;
private LoggerManager plexusLoggerManager;
private ILoggerFactory slf4jLoggerFactory;
private Logger slf4jLogger;
private EventSpyDispatcher eventSpyDispatcher;
private ModelProcessor modelProcessor;
private Maven maven;
private MavenExecutionRequestPopulator executionRequestPopulator;
private ToolchainsBuilder toolchainsBuilder;
private DefaultSecDispatcher dispatcher;
private Map<String, ConfigurationProcessor> configurationProcessors;
public MavenCli()
{
this( null );
}
// This supports painless invocation by the Verifier during embedded execution of the core ITs
public MavenCli( ClassWorld classWorld )
{
this.classWorld = classWorld;
}
public static void main( String[] args )
{
int result = main( args, null );
System.exit( result );
}
public static int main( String[] args, ClassWorld classWorld )
{
MavenCli cli = new MavenCli();
MessageUtils.systemInstall();
MessageUtils.registerShutdownHook();
int result = cli.doMain( new CliRequest( args, classWorld ) );
MessageUtils.systemUninstall();
return result;
}
// TODO need to externalize CliRequest
public static int doMain( String[] args, ClassWorld classWorld )
{
MavenCli cli = new MavenCli();
return cli.doMain( new CliRequest( args, classWorld ) );
}
/**
* This supports painless invocation by the Verifier during embedded execution of the core ITs.
* See <a href="http://maven.apache.org/shared/maven-verifier/xref/org/apache/maven/it/Embedded3xLauncher.html">
* <code>Embedded3xLauncher</code> in <code>maven-verifier</code></a>
*/
public int doMain( String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr )
{
PrintStream oldout = System.out;
PrintStream olderr = System.err;
final Set<String> realms;
if ( classWorld != null )
{
realms = new HashSet<>();
for ( ClassRealm realm : classWorld.getRealms() )
{
realms.add( realm.getId() );
}
}
else
{
realms = Collections.emptySet();
}
try
{
if ( stdout != null )
{
System.setOut( stdout );
}
if ( stderr != null )
{
System.setErr( stderr );
}
CliRequest cliRequest = new CliRequest( args, classWorld );
cliRequest.workingDirectory = workingDirectory;
return doMain( cliRequest );
}
finally
{
if ( classWorld != null )
{
for ( ClassRealm realm : new ArrayList<>( classWorld.getRealms() ) )
{
String realmId = realm.getId();
if ( !realms.contains( realmId ) )
{
try
{
classWorld.disposeRealm( realmId );
}
catch ( NoSuchRealmException ignored )
{
// can't happen
}
}
}
}
System.setOut( oldout );
System.setErr( olderr );
}
}
// TODO need to externalize CliRequest
public int doMain( CliRequest cliRequest )
{
PlexusContainer localContainer = null;
try
{
initialize( cliRequest );
cli( cliRequest );
properties( cliRequest );
logging( cliRequest );
version( cliRequest );
localContainer = container( cliRequest );
commands( cliRequest );
configure( cliRequest );
toolchains( cliRequest );
populateRequest( cliRequest );
encryption( cliRequest );
repository( cliRequest );
return execute( cliRequest );
}
catch ( ExitException e )
{
return e.exitCode;
}
catch ( UnrecognizedOptionException e )
{
// pure user error, suppress stack trace
return 1;
}
catch ( BuildAbort e )
{
CLIReportingUtils.showError( slf4jLogger, "ABORTED", e, cliRequest.showErrors );
return 2;
}
catch ( Exception e )
{
CLIReportingUtils.showError( slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors );
return 1;
}
finally
{
if ( localContainer != null )
{
localContainer.dispose();
}
}
}
void initialize( CliRequest cliRequest )
throws ExitException
{
if ( cliRequest.workingDirectory == null )
{
cliRequest.workingDirectory = System.getProperty( "user.dir" );
}
if ( cliRequest.multiModuleProjectDirectory == null )
{
String basedirProperty = System.getProperty( MULTIMODULE_PROJECT_DIRECTORY );
if ( basedirProperty == null )
{
System.err.format(
"-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY );
throw new ExitException( 1 );
}
File basedir = new File( basedirProperty );
try
{
cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile();
}
catch ( IOException e )
{
cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile();
}
}
//
// Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative
// Windows paths.
//
String mavenHome = System.getProperty( "maven.home" );
if ( mavenHome != null )
{
System.setProperty( "maven.home", new File( mavenHome ).getAbsolutePath() );
}
}
void cli( CliRequest cliRequest )
throws Exception
{
//
// Parsing errors can happen during the processing of the arguments and we prefer not having to check if
// the logger is null and construct this so we can use an SLF4J logger everywhere.
//
slf4jLogger = new Slf4jStdoutLogger();
CLIManager cliManager = new CLIManager();
List<String> args = new ArrayList<>();
CommandLine mavenConfig = null;
try
{
File configFile = new File( cliRequest.multiModuleProjectDirectory, MVN_MAVEN_CONFIG );
if ( configFile.isFile() )
{
for ( String arg : new String( Files.readAllBytes( configFile.toPath() ) ).split( "\\s+" ) )
{
if ( !arg.isEmpty() )
{
args.add( arg );
}
}
mavenConfig = cliManager.parse( args.toArray( new String[0] ) );
List<?> unrecongized = mavenConfig.getArgList();
if ( !unrecongized.isEmpty() )
{
throw new ParseException( "Unrecognized maven.config entries: " + unrecongized );
}
}
}
catch ( ParseException e )
{
System.err.println( "Unable to parse maven.config: " + e.getMessage() );
cliManager.displayHelp( System.out );
throw e;
}
try
{
if ( mavenConfig == null )
{
cliRequest.commandLine = cliManager.parse( cliRequest.args );
}
else
{
cliRequest.commandLine = cliMerge( cliManager.parse( cliRequest.args ), mavenConfig );
}
}
catch ( ParseException e )
{
System.err.println( "Unable to parse command line options: " + e.getMessage() );
cliManager.displayHelp( System.out );
throw e;
}
if ( cliRequest.commandLine.hasOption( CLIManager.HELP ) )
{
cliManager.displayHelp( System.out );
throw new ExitException( 0 );
}
if ( cliRequest.commandLine.hasOption( CLIManager.VERSION ) )
{
System.out.println( CLIReportingUtils.showVersion() );
throw new ExitException( 0 );
}
}
private CommandLine cliMerge( CommandLine mavenArgs, CommandLine mavenConfig )
{
CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
// the args are easy, cli first then config file
for ( String arg : mavenArgs.getArgs() )
{
commandLineBuilder.addArg( arg );
}
for ( String arg : mavenConfig.getArgs() )
{
commandLineBuilder.addArg( arg );
}
// now add all options, except for -D with cli first then config file
List<Option> setPropertyOptions = new ArrayList<>();
for ( Option opt : mavenArgs.getOptions() )
{
if ( String.valueOf( CLIManager.SET_SYSTEM_PROPERTY ).equals( opt.getOpt() ) )
{
setPropertyOptions.add( opt );
}
else
{
commandLineBuilder.addOption( opt );
}
}
for ( Option opt : mavenConfig.getOptions() )
{
commandLineBuilder.addOption( opt );
}
// finally add the CLI system properties
for ( Option opt : setPropertyOptions )
{
commandLineBuilder.addOption( opt );
}
return commandLineBuilder.build();
}
/**
* configure logging
*/
void logging( CliRequest cliRequest )
{
// LOG LEVEL
cliRequest.debug = cliRequest.commandLine.hasOption( CLIManager.DEBUG );
cliRequest.quiet = !cliRequest.debug && cliRequest.commandLine.hasOption( CLIManager.QUIET );
cliRequest.showErrors = cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.ERRORS );
slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration( slf4jLoggerFactory );
if ( cliRequest.debug )
{
cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_DEBUG );
slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.DEBUG );
}
else if ( cliRequest.quiet )
{
cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_ERROR );
slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.ERROR );
}
// else fall back to default log level specified in conf
// see https://issues.apache.org/jira/browse/MNG-2570
// LOG COLOR
String styleColor = cliRequest.getUserProperties().getProperty( STYLE_COLOR_PROPERTY, "auto" );
if ( "always".equals( styleColor ) )
{
MessageUtils.setColorEnabled( true );
}
else if ( "never".equals( styleColor ) )
{
MessageUtils.setColorEnabled( false );
}
else if ( !"auto".equals( styleColor ) )
{
throw new IllegalArgumentException( "Invalid color configuration option [" + styleColor
+ "]. Supported values are (auto|always|never)." );
}
else if ( cliRequest.commandLine.hasOption( CLIManager.BATCH_MODE )
|| cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
{
MessageUtils.setColorEnabled( false );
}
// LOG STREAMS
if ( cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
{
File logFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.LOG_FILE ) );
logFile = resolveFile( logFile, cliRequest.workingDirectory );
// redirect stdout and stderr to file
try
{
PrintStream ps = new PrintStream( new FileOutputStream( logFile ) );
System.setOut( ps );
System.setErr( ps );
}
catch ( FileNotFoundException e )
{
//
// Ignore
//
}
}
slf4jConfiguration.activate();
plexusLoggerManager = new Slf4jLoggerManager();
slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
if ( cliRequest.commandLine.hasOption( CLIManager.FAIL_ON_SEVERITY ) )
{
String logLevelThreshold = cliRequest.commandLine.getOptionValue( CLIManager.FAIL_ON_SEVERITY );
if ( slf4jLoggerFactory instanceof MavenSlf4jWrapperFactory )
{
LogLevelRecorder logLevelRecorder = new LogLevelRecorder( logLevelThreshold );
( (MavenSlf4jWrapperFactory) slf4jLoggerFactory ).setLogLevelRecorder( logLevelRecorder );
slf4jLogger.info( "Enabled to break the build on log level {}.", logLevelThreshold );
}
else
{
slf4jLogger.warn( "Expected LoggerFactory to be of type '{}', but found '{}' instead. "
+ "The --fail-on-severity flag will not take effect.",
MavenSlf4jWrapperFactory.class.getName(), slf4jLoggerFactory.getClass().getName() );
}
}
}
private void version( CliRequest cliRequest )
{
if ( cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.SHOW_VERSION ) )
{
System.out.println( CLIReportingUtils.showVersion() );
}
}
private void commands( CliRequest cliRequest )
{
if ( cliRequest.showErrors )
{
slf4jLogger.info( "Error stacktraces are turned on." );
}
if ( MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
{
slf4jLogger.info( "Disabling strict checksum verification on all artifact downloads." );
}
else if ( MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
{
slf4jLogger.info( "Enabling strict checksum verification on all artifact downloads." );
}
if ( slf4jLogger.isDebugEnabled() )
{
slf4jLogger.debug( "Message scheme: {}", ( MessageUtils.isColorEnabled() ? "color" : "plain" ) );
if ( MessageUtils.isColorEnabled() )
{
MessageBuilder buff = MessageUtils.buffer();
buff.a( "Message styles: " );
buff.a( MessageUtils.level().debug( "debug" ) ).a( ' ' );
buff.a( MessageUtils.level().info( "info" ) ).a( ' ' );
buff.a( MessageUtils.level().warning( "warning" ) ).a( ' ' );
buff.a( MessageUtils.level().error( "error" ) ).a( ' ' );
buff.success( "success" ).a( ' ' );
buff.failure( "failure" ).a( ' ' );
buff.strong( "strong" ).a( ' ' );
buff.mojo( "mojo" ).a( ' ' );
buff.project( "project" );
slf4jLogger.debug( buff.toString() );
}
}
}
//Needed to make this method package visible to make writing a unit test possible
//Maybe it's better to move some of those methods to separate class (SoC).
void properties( CliRequest cliRequest )
{
populateProperties( cliRequest.commandLine, cliRequest.systemProperties, cliRequest.userProperties );
}
PlexusContainer container( CliRequest cliRequest )
throws Exception
{
if ( cliRequest.classWorld == null )
{
cliRequest.classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
}
ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" );
if ( coreRealm == null )
{
coreRealm = cliRequest.classWorld.getRealms().iterator().next();
}
List<File> extClassPath = parseExtClasspath( cliRequest );
CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom( coreRealm );
List<CoreExtensionEntry> extensions =
loadCoreExtensions( cliRequest, coreRealm, coreEntry.getExportedArtifacts() );
ClassRealm containerRealm = setupContainerRealm( cliRequest.classWorld, coreRealm, extClassPath, extensions );
ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld( cliRequest.classWorld )
.setRealm( containerRealm ).setClassPathScanning( PlexusConstants.SCANNING_INDEX ).setAutoWiring( true )
.setJSR250Lifecycle( true ).setName( "maven" );
Set<String> exportedArtifacts = new HashSet<>( coreEntry.getExportedArtifacts() );
Set<String> exportedPackages = new HashSet<>( coreEntry.getExportedPackages() );
for ( CoreExtensionEntry extension : extensions )
{
exportedArtifacts.addAll( extension.getExportedArtifacts() );
exportedPackages.addAll( extension.getExportedPackages() );
}
final CoreExports exports = new CoreExports( containerRealm, exportedArtifacts, exportedPackages );
DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
{
@Override
protected void configure()
{
bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
bind( CoreExports.class ).toInstance( exports );
}
} );
// NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups
container.setLookupRealm( null );
Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
container.setLoggerManager( plexusLoggerManager );
for ( CoreExtensionEntry extension : extensions )
{
container.discoverComponents( extension.getClassRealm(), new SessionScopeModule( container ),
new MojoExecutionScopeModule( container ) );
}
customizeContainer( container );
container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
eventSpyDispatcher = container.lookup( EventSpyDispatcher.class );
DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext();
Map<String, Object> data = eventSpyContext.getData();
data.put( "plexus", container );
data.put( "workingDirectory", cliRequest.workingDirectory );
data.put( "systemProperties", cliRequest.systemProperties );
data.put( "userProperties", cliRequest.userProperties );
data.put( "versionProperties", CLIReportingUtils.getBuildProperties() );
eventSpyDispatcher.init( eventSpyContext );
// refresh logger in case container got customized by spy
slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
maven = container.lookup( Maven.class );
executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
modelProcessor = createModelProcessor( container );
configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
toolchainsBuilder = container.lookup( ToolchainsBuilder.class );
dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" );
return container;
}
private List<CoreExtensionEntry> loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm,
Set<String> providedArtifacts )
{
if ( cliRequest.multiModuleProjectDirectory == null )
{
return Collections.emptyList();
}
File extensionsFile = new File( cliRequest.multiModuleProjectDirectory, EXTENSIONS_FILENAME );
if ( !extensionsFile.isFile() )
{
return Collections.emptyList();
}
try
{
List<CoreExtension> extensions = readCoreExtensionsDescriptor( extensionsFile );
if ( extensions.isEmpty() )
{
return Collections.emptyList();
}
ContainerConfiguration cc = new DefaultContainerConfiguration() //
.setClassWorld( cliRequest.classWorld ) //
.setRealm( containerRealm ) //
.setClassPathScanning( PlexusConstants.SCANNING_INDEX ) //
.setAutoWiring( true ) //
.setJSR250Lifecycle( true ) //
.setName( "maven" );
DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
{
@Override
protected void configure()
{
bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
}
} );
try
{
container.setLookupRealm( null );
container.setLoggerManager( plexusLoggerManager );
container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
configure( cliRequest );
MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request );
populateRequest( cliRequest, request );
request = executionRequestPopulator.populateDefaults( request );
BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class );
return Collections.unmodifiableList( resolver.loadCoreExtensions( request, providedArtifacts,
extensions ) );
}
finally
{
executionRequestPopulator = null;
container.dispose();
}
}
catch ( RuntimeException e )
{
// runtime exceptions are most likely bugs in maven, let them bubble up to the user
throw e;
}
catch ( Exception e )
{
slf4jLogger.warn( "Failed to read extensions descriptor from '{}'", extensionsFile, e );
}
return Collections.emptyList();
}
private List<CoreExtension> readCoreExtensionsDescriptor( File extensionsFile )
throws IOException, XmlPullParserException
{
CoreExtensionsXpp3Reader parser = new CoreExtensionsXpp3Reader();
try ( InputStream is = new BufferedInputStream( new FileInputStream( extensionsFile ) ) )
{
return parser.read( is ).getExtensions();
}
}
private ClassRealm setupContainerRealm( ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath,
List<CoreExtensionEntry> extensions )
throws Exception
{
if ( !extClassPath.isEmpty() || !extensions.isEmpty() )
{
ClassRealm extRealm = classWorld.newRealm( "maven.ext", null );
extRealm.setParentRealm( coreRealm );
slf4jLogger.debug( "Populating class realm '{}'", extRealm.getId() );
for ( File file : extClassPath )
{
slf4jLogger.debug( " included '{}'", file );
extRealm.addURL( file.toURI().toURL() );
}
for ( CoreExtensionEntry entry : reverse( extensions ) )
{
Set<String> exportedPackages = entry.getExportedPackages();
ClassRealm realm = entry.getClassRealm();
for ( String exportedPackage : exportedPackages )
{
extRealm.importFrom( realm, exportedPackage );
}
if ( exportedPackages.isEmpty() )
{
// sisu uses realm imports to establish component visibility
extRealm.importFrom( realm, realm.getId() );
}
}
return extRealm;
}
return coreRealm;
}
private static <T> List<T> reverse( List<T> list )
{
List<T> copy = new ArrayList<>( list );
Collections.reverse( copy );
return copy;
}
private List<File> parseExtClasspath( CliRequest cliRequest )
{
String extClassPath = cliRequest.userProperties.getProperty( EXT_CLASS_PATH );
if ( extClassPath == null )
{
extClassPath = cliRequest.systemProperties.getProperty( EXT_CLASS_PATH );
}
List<File> jars = new ArrayList<>();
if ( StringUtils.isNotEmpty( extClassPath ) )
{
for ( String jar : StringUtils.split( extClassPath, File.pathSeparator ) )
{
File file = resolveFile( new File( jar ), cliRequest.workingDirectory );
slf4jLogger.debug( " included '{}'", file );
jars.add( file );
}
}
return jars;
}
//
// This should probably be a separate tool and not be baked into Maven.
//
private void encryption( CliRequest cliRequest )
throws Exception
{
if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_MASTER_PASSWORD ) )
{
String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_MASTER_PASSWORD );
if ( passwd == null )
{
Console cons = System.console();
char[] password = ( cons == null ) ? null : cons.readPassword( "Master password: " );
if ( password != null )
{
// Cipher uses Strings
passwd = String.copyValueOf( password );
// Sun/Oracle advises to empty the char array
java.util.Arrays.fill( password, ' ' );
}
}
DefaultPlexusCipher cipher = new DefaultPlexusCipher();
System.out.println(
cipher.encryptAndDecorate( passwd, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) );
throw new ExitException( 0 );
}
else if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_PASSWORD ) )
{
String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_PASSWORD );
if ( passwd == null )
{
Console cons = System.console();
char[] password = ( cons == null ) ? null : cons.readPassword( "Password: " );
if ( password != null )
{
// Cipher uses Strings
passwd = String.copyValueOf( password );
// Sun/Oracle advises to empty the char array
java.util.Arrays.fill( password, ' ' );
}
}
String configurationFile = dispatcher.getConfigurationFile();
if ( configurationFile.startsWith( "~" ) )
{
configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
}
String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
String master = null;
SettingsSecurity sec = SecUtil.read( file, true );
if ( sec != null )
{
master = sec.getMaster();
}
if ( master == null )
{
throw new IllegalStateException( "Master password is not set in the setting security file: " + file );
}
DefaultPlexusCipher cipher = new DefaultPlexusCipher();
String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
System.out.println( cipher.encryptAndDecorate( passwd, masterPasswd ) );
throw new ExitException( 0 );
}
}
private void repository( CliRequest cliRequest )
throws Exception
{
if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_LOCAL_REPOSITORY ) || Boolean.getBoolean(
"maven.legacyLocalRepo" ) )
{
cliRequest.request.setUseLegacyLocalRepository( true );
}
}
private int execute( CliRequest cliRequest )
throws MavenExecutionRequestPopulationException
{
MavenExecutionRequest request = executionRequestPopulator.populateDefaults( cliRequest.request );
eventSpyDispatcher.onEvent( request );
MavenExecutionResult result = maven.execute( request );
eventSpyDispatcher.onEvent( result );
eventSpyDispatcher.close();
if ( result.hasExceptions() )
{
ExceptionHandler handler = new DefaultExceptionHandler();
Map<String, String> references = new LinkedHashMap<>();
List<MavenProject> failedProjects = new ArrayList<>();
for ( Throwable exception : result.getExceptions() )
{
ExceptionSummary summary = handler.handleException( exception );
logSummary( summary, references, "", cliRequest.showErrors );
if ( exception instanceof LifecycleExecutionException )
{
failedProjects.add ( ( (LifecycleExecutionException) exception ).getProject() );
}
}
slf4jLogger.error( "" );
if ( !cliRequest.showErrors )
{
slf4jLogger.error( "To see the full stack trace of the errors, re-run Maven with the '{}' switch.",
buffer().strong( "-e" ) );
}
if ( !slf4jLogger.isDebugEnabled() )
{
slf4jLogger.error( "Re-run Maven using the '{}' switch to enable full debug logging.",
buffer().strong( "-X" ) );
}
if ( !references.isEmpty() )
{
slf4jLogger.error( "" );
slf4jLogger.error( "For more information about the errors and possible solutions"
+ ", please read the following articles:" );
for ( Map.Entry<String, String> entry : references.entrySet() )
{
slf4jLogger.error( "{} {}", buffer().strong( entry.getValue() ), entry.getKey() );
}
}
if ( result.canResume() )
{
logBuildResumeHint( "mvn <args> -r" );
}
else if ( !failedProjects.isEmpty() )
{
List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
// Sort the failedProjects list in the topologically sorted order.
failedProjects.sort( comparing( sortedProjects::indexOf ) );
MavenProject firstFailedProject = failedProjects.get( 0 );
if ( !firstFailedProject.equals( sortedProjects.get( 0 ) ) )
{
String resumeFromSelector = getResumeFromSelector( sortedProjects, firstFailedProject );
logBuildResumeHint( "mvn <args> -rf " + resumeFromSelector );
}
}
if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) )
{
slf4jLogger.info( "Build failures were ignored." );
return 0;
}
else
{
return 1;
}
}
else
{
return 0;
}
}
private void logBuildResumeHint( String resumeBuildHint )
{
slf4jLogger.error( "" );
slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
slf4jLogger.error( buffer().a( " " ).strong( resumeBuildHint ).toString() );
}
/**
* A helper method to determine the value to resume the build with {@code -rf} taking into account the edge case
* where multiple modules in the reactor have the same artifactId.
* <p>
* {@code -rf :artifactId} will pick up the first module which matches, but when multiple modules in the reactor
* have the same artifactId, effective failed module might be later in build reactor.
* This means that developer will either have to type groupId or wait for build execution of all modules which
* were fine, but they are still before one which reported errors.
* <p>Then the returned value is {@code groupId:artifactId} when there is a name clash and
* {@code :artifactId} if there is no conflict.
* This method is made package-private for testing purposes.
*
* @param mavenProjects Maven projects which are part of build execution.
* @param firstFailedProject The first project which has failed.
* @return Value for -rf flag to resume build exactly from place where it failed ({@code :artifactId} in general
* and {@code groupId:artifactId} when there is a name clash).
*/
String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject firstFailedProject )
{
boolean hasOverlappingArtifactId = mavenProjects.stream()
.filter( project -> firstFailedProject.getArtifactId().equals( project.getArtifactId() ) )
.count() > 1;
if ( hasOverlappingArtifactId )
{
return firstFailedProject.getGroupId() + ":" + firstFailedProject.getArtifactId();
}
return ":" + firstFailedProject.getArtifactId();
}
private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent,
boolean showErrors )
{
String referenceKey = "";
if ( StringUtils.isNotEmpty( summary.getReference() ) )
{
referenceKey = references.get( summary.getReference() );
if ( referenceKey == null )
{
referenceKey = "[Help " + ( references.size() + 1 ) + "]";
references.put( summary.getReference(), referenceKey );
}
}
String msg = summary.getMessage();
if ( StringUtils.isNotEmpty( referenceKey ) )
{
if ( msg.indexOf( '\n' ) < 0 )
{
msg += " -> " + buffer().strong( referenceKey );
}
else
{
msg += "\n-> " + buffer().strong( referenceKey );
}
}
String[] lines = msg.split( "(\r\n)|(\r)|(\n)" );
String currentColor = "";
for ( int i = 0; i < lines.length; i++ )
{
// add eventual current color inherited from previous line
String line = currentColor + lines[i];
// look for last ANSI escape sequence to check if nextColor
Matcher matcher = LAST_ANSI_SEQUENCE.matcher( line );
String nextColor = "";
if ( matcher.find() )
{
nextColor = matcher.group( 1 );
if ( ANSI_RESET.equals( nextColor ) )
{
// last ANSI escape code is reset: no next color
nextColor = "";
}
}
// effective line, with indent and reset if end is colored
line = indent + line + ( "".equals( nextColor ) ? "" : ANSI_RESET );
if ( ( i == lines.length - 1 ) && ( showErrors
|| ( summary.getException() instanceof InternalErrorException ) ) )
{
slf4jLogger.error( line, summary.getException() );
}
else
{
slf4jLogger.error( line );
}
currentColor = nextColor;
}
indent += " ";
for ( ExceptionSummary child : summary.getChildren() )
{
logSummary( child, references, indent, showErrors );
}
}
private static final Pattern LAST_ANSI_SEQUENCE = Pattern.compile( "(\u001B\\[[;\\d]*[ -/]*[@-~])[^\u001B]*$" );
private static final String ANSI_RESET = "\u001B\u005Bm";
private void configure( CliRequest cliRequest )
throws Exception
{
//
// This is not ideal but there are events specifically for configuration from the CLI which I don't
// believe are really valid but there are ITs which assert the right events are published so this
// needs to be supported so the EventSpyDispatcher needs to be put in the CliRequest so that
// it can be accessed by configuration processors.
//
cliRequest.request.setEventSpyDispatcher( eventSpyDispatcher );
//
// We expect at most 2 implementations to be available. The SettingsXmlConfigurationProcessor implementation
// is always available in the core and likely always will be, but we may have another ConfigurationProcessor
// present supplied by the user. The rule is that we only allow the execution of one ConfigurationProcessor.
// If there is more than one then we execute the one supplied by the user, otherwise we execute the
// the default SettingsXmlConfigurationProcessor.
//
int userSuppliedConfigurationProcessorCount = configurationProcessors.size() - 1;
if ( userSuppliedConfigurationProcessorCount == 0 )
{
//
// Our settings.xml source is historically how we have configured Maven from the CLI so we are going to
// have to honour its existence forever. So let's run it.
//
configurationProcessors.get( SettingsXmlConfigurationProcessor.HINT ).process( cliRequest );
}
else if ( userSuppliedConfigurationProcessorCount == 1 )
{
//
// Run the user supplied ConfigurationProcessor
//
for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() )
{
String hint = entry.getKey();
if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) )
{
ConfigurationProcessor configurationProcessor = entry.getValue();
configurationProcessor.process( cliRequest );
}
}
}
else if ( userSuppliedConfigurationProcessorCount > 1 )
{
//
// There are too many ConfigurationProcessors so we don't know which one to run so report the error.
//
StringBuilder sb = new StringBuilder(
String.format( "%nThere can only be one user supplied ConfigurationProcessor, there are %s:%n%n",
userSuppliedConfigurationProcessorCount ) );
for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() )
{
String hint = entry.getKey();
if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) )
{
ConfigurationProcessor configurationProcessor = entry.getValue();
sb.append( String.format( "%s%n", configurationProcessor.getClass().getName() ) );
}
}
throw new Exception( sb.toString() );
}
}
void toolchains( CliRequest cliRequest )
throws Exception
{
File userToolchainsFile;
if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) )
{
userToolchainsFile =
new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) );
userToolchainsFile = resolveFile( userToolchainsFile, cliRequest.workingDirectory );
if ( !userToolchainsFile.isFile() )
{
throw new FileNotFoundException(
"The specified user toolchains file does not exist: " + userToolchainsFile );
}
}
else
{
userToolchainsFile = DEFAULT_USER_TOOLCHAINS_FILE;
}
File globalToolchainsFile;
if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) )
{
globalToolchainsFile =
new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) );
globalToolchainsFile = resolveFile( globalToolchainsFile, cliRequest.workingDirectory );
if ( !globalToolchainsFile.isFile() )
{
throw new FileNotFoundException(
"The specified global toolchains file does not exist: " + globalToolchainsFile );
}
}
else
{
globalToolchainsFile = DEFAULT_GLOBAL_TOOLCHAINS_FILE;
}
cliRequest.request.setGlobalToolchainsFile( globalToolchainsFile );
cliRequest.request.setUserToolchainsFile( userToolchainsFile );
DefaultToolchainsBuildingRequest toolchainsRequest = new DefaultToolchainsBuildingRequest();
if ( globalToolchainsFile.isFile() )
{
toolchainsRequest.setGlobalToolchainsSource( new FileSource( globalToolchainsFile ) );
}
if ( userToolchainsFile.isFile() )
{
toolchainsRequest.setUserToolchainsSource( new FileSource( userToolchainsFile ) );
}
eventSpyDispatcher.onEvent( toolchainsRequest );
slf4jLogger.debug( "Reading global toolchains from '{}'",
getLocation( toolchainsRequest.getGlobalToolchainsSource(), globalToolchainsFile ) );
slf4jLogger.debug( "Reading user toolchains from '{}'",
getLocation( toolchainsRequest.getUserToolchainsSource(), userToolchainsFile ) );
ToolchainsBuildingResult toolchainsResult = toolchainsBuilder.build( toolchainsRequest );
eventSpyDispatcher.onEvent( toolchainsResult );
executionRequestPopulator.populateFromToolchains( cliRequest.request,
toolchainsResult.getEffectiveToolchains() );
if ( !toolchainsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled() )
{
slf4jLogger.warn( "" );
slf4jLogger.warn( "Some problems were encountered while building the effective toolchains" );
for ( Problem problem : toolchainsResult.getProblems() )
{
slf4jLogger.warn( "{} @ {}", problem.getMessage(), problem.getLocation() );
}
slf4jLogger.warn( "" );
}
}
private Object getLocation( Source source, File defaultLocation )
{
if ( source != null )
{
return source.getLocation();
}
return defaultLocation;
}
protected MavenExecutionRequest populateRequest( CliRequest cliRequest )
{
return populateRequest( cliRequest, cliRequest.request );
}
private MavenExecutionRequest populateRequest( CliRequest cliRequest, MavenExecutionRequest request )
{
slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
CommandLine commandLine = cliRequest.commandLine;
String workingDirectory = cliRequest.workingDirectory;
boolean quiet = cliRequest.quiet;
request.setShowErrors( cliRequest.showErrors ); // default: false
File baseDirectory = new File( workingDirectory, "" ).getAbsoluteFile();
disableOnPresentOption( commandLine, CLIManager.BATCH_MODE, request::setInteractiveMode );
enableOnPresentOption( commandLine, CLIManager.SUPRESS_SNAPSHOT_UPDATES, request::setNoSnapshotUpdates );
request.setGoals( commandLine.getArgList() );
request.setReactorFailureBehavior( determineReactorFailureBehaviour ( commandLine ) );
disableOnPresentOption( commandLine, CLIManager.NON_RECURSIVE, request::setRecursive );
enableOnPresentOption( commandLine, CLIManager.OFFLINE, request::setOffline );
enableOnPresentOption( commandLine, CLIManager.UPDATE_SNAPSHOTS, request::setUpdateSnapshots );
request.setGlobalChecksumPolicy( determineGlobalCheckPolicy( commandLine ) );
request.setBaseDirectory( baseDirectory );
request.setSystemProperties( cliRequest.systemProperties );
request.setUserProperties( cliRequest.userProperties );
request.setMultiModuleProjectDirectory( cliRequest.multiModuleProjectDirectory );
request.setPom( determinePom( commandLine, workingDirectory, baseDirectory ) );
request.setTransferListener( determineTransferListener( quiet, commandLine, request ) );
request.setExecutionListener( determineExecutionListener() );
if ( ( request.getPom() != null ) && ( request.getPom().getParentFile() != null ) )
{
request.setBaseDirectory( request.getPom().getParentFile() );
}
request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) );
enableOnPresentOption( commandLine, CLIManager.RESUME, request::setResume );
request.setMakeBehavior( determineMakeBehavior( commandLine ) );
request.setCacheNotFound( true );
request.setCacheTransferError( false );
final ProjectActivation projectActivation = determineProjectActivation( commandLine );
request.setSelectedProjects( projectActivation.activeProjects );
request.setExcludedProjects( projectActivation.inactiveProjects );
final ProfileActivation profileActivation = determineProfileActivation( commandLine );
request.addActiveProfiles( profileActivation.activeProfiles );
request.addInactiveProfiles( profileActivation.inactiveProfiles );
final String localRepositoryPath = determineLocalRepositoryPath( request );
if ( localRepositoryPath != null )
{
request.setLocalRepositoryPath( localRepositoryPath );
}
//
// Builder, concurrency and parallelism
//
// We preserve the existing methods for builder selection which is to look for various inputs in the threading
// configuration. We don't have an easy way to allow a pluggable builder to provide its own configuration
// parameters but this is sufficient for now. Ultimately we want components like Builders to provide a way to
// extend the command line to accept its own configuration parameters.
//
final String threadConfiguration = commandLine.getOptionValue( CLIManager.THREADS );
if ( threadConfiguration != null )
{
//
// Default to the standard multithreaded builder
//
request.setBuilderId( "multithreaded" );
if ( threadConfiguration.contains( "C" ) )
{
request.setDegreeOfConcurrency( calculateDegreeOfConcurrencyWithCoreMultiplier( threadConfiguration ) );
}
else
{
request.setDegreeOfConcurrency( Integer.parseInt( threadConfiguration ) );
}
}
//
// Allow the builder to be overridden by the user if requested. The builders are now pluggable.
//
request.setBuilderId( commandLine.getOptionValue( CLIManager.BUILDER, request.getBuilderId() ) );
return request;
}
private String determineLocalRepositoryPath( final MavenExecutionRequest request )
{
String userDefinedLocalRepo = request.getUserProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
if ( userDefinedLocalRepo != null )
{
return userDefinedLocalRepo;
}
return request.getSystemProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
}
private File determinePom( final CommandLine commandLine, final String workingDirectory, final File baseDirectory )
{
String alternatePomFile = null;
if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) )
{
alternatePomFile = commandLine.getOptionValue( CLIManager.ALTERNATE_POM_FILE );
}
if ( alternatePomFile != null )
{
File pom = resolveFile( new File( alternatePomFile ), workingDirectory );
if ( pom.isDirectory() )
{
pom = new File( pom, "pom.xml" );
}
return pom;
}
else if ( modelProcessor != null )
{
File pom = modelProcessor.locatePom( baseDirectory );
if ( pom.isFile() )
{
return pom;
}
}
return null;
}
// Visible for testing
static ProjectActivation determineProjectActivation ( final CommandLine commandLine )
{
final ProjectActivation projectActivation = new ProjectActivation();
if ( commandLine.hasOption( CLIManager.PROJECT_LIST ) )
{
String[] projectOptionValues = commandLine.getOptionValues( CLIManager.PROJECT_LIST );
if ( projectOptionValues != null )
{
for ( String projectOptionValue : projectOptionValues )
{
StringTokenizer projectTokens = new StringTokenizer( projectOptionValue, "," );
while ( projectTokens.hasMoreTokens() )
{
String projectAction = projectTokens.nextToken().trim();
if ( projectAction.startsWith( "-" ) || projectAction.startsWith( "!" ) )
{
projectActivation.deactivate( projectAction.substring( 1 ) );
}
else if ( projectAction.startsWith( "+" ) )
{
projectActivation.activate( projectAction.substring( 1 ) );
}
else
{
projectActivation.activate( projectAction );
}
}
}
}
}
return projectActivation;
}
// Visible for testing
static ProfileActivation determineProfileActivation( final CommandLine commandLine )
{
final ProfileActivation result = new ProfileActivation();
if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) )
{
String[] profileOptionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES );
if ( profileOptionValues != null )
{
for ( String profileOptionValue : profileOptionValues )
{
StringTokenizer profileTokens = new StringTokenizer( profileOptionValue, "," );
while ( profileTokens.hasMoreTokens() )
{
String profileAction = profileTokens.nextToken().trim();
if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) )
{
result.deactivate( profileAction.substring( 1 ) );
}
else if ( profileAction.startsWith( "+" ) )
{
result.activate( profileAction.substring( 1 ) );
}
else
{
result.activate( profileAction );
}
}
}
}
}
return result;
}
private ExecutionListener determineExecutionListener()
{
ExecutionListener executionListener = new ExecutionEventLogger();
if ( eventSpyDispatcher != null )
{
return eventSpyDispatcher.chainListener( executionListener );
}
else
{
return executionListener;
}
}
private String determineReactorFailureBehaviour( final CommandLine commandLine )
{
if ( commandLine.hasOption( CLIManager.FAIL_FAST ) )
{
return MavenExecutionRequest.REACTOR_FAIL_FAST;
}
else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) )
{
return MavenExecutionRequest.REACTOR_FAIL_AT_END;
}
else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) )
{
return MavenExecutionRequest.REACTOR_FAIL_NEVER;
}
else
{
// this is the default behavior.
return MavenExecutionRequest.REACTOR_FAIL_FAST;
}
}
private TransferListener determineTransferListener( final boolean quiet,
final CommandLine commandLine,
final MavenExecutionRequest request )
{
if ( quiet || commandLine.hasOption( CLIManager.NO_TRANSFER_PROGRESS ) )
{
return new QuietMavenTransferListener();
}
else if ( request.isInteractiveMode() && !commandLine.hasOption( CLIManager.LOG_FILE ) )
{
//
// If we're logging to a file then we don't want the console transfer listener as it will spew
// download progress all over the place
//
return getConsoleTransferListener( commandLine.hasOption( CLIManager.DEBUG ) );
}
else
{
// default: batch mode which goes along with interactive
return getBatchTransferListener();
}
}
private String determineMakeBehavior( final CommandLine cl )
{
if ( cl.hasOption( CLIManager.ALSO_MAKE ) && !cl.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
{
return MavenExecutionRequest.REACTOR_MAKE_UPSTREAM;
}
else if ( !cl.hasOption( CLIManager.ALSO_MAKE ) && cl.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
{
return MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM;
}
else if ( cl.hasOption( CLIManager.ALSO_MAKE ) && cl.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
{
return MavenExecutionRequest.REACTOR_MAKE_BOTH;
}
else
{
return null;
}
}
private String determineGlobalCheckPolicy( final CommandLine commandLine )
{
if ( commandLine.hasOption( CLIManager.CHECKSUM_FAILURE_POLICY ) )
{
return MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
}
else if ( commandLine.hasOption( CLIManager.CHECKSUM_WARNING_POLICY ) )
{
return MavenExecutionRequest.CHECKSUM_POLICY_WARN;
}
else
{
return null;
}
}
private void disableOnPresentOption( final CommandLine commandLine,
final String option,
final Consumer<Boolean> setting )
{
if ( commandLine.hasOption( option ) )
{
setting.accept( false );
}
}
private void disableOnPresentOption( final CommandLine commandLine,
final char option,
final Consumer<Boolean> setting )
{
disableOnPresentOption( commandLine, String.valueOf( option ), setting );
}
private void enableOnPresentOption( final CommandLine commandLine,
final String option,
final Consumer<Boolean> setting )
{
if ( commandLine.hasOption( option ) )
{
setting.accept( true );
}
}
private void enableOnPresentOption( final CommandLine commandLine,
final char option,
final Consumer<Boolean> setting )
{
enableOnPresentOption( commandLine, String.valueOf( option ), setting );
}
private void enableOnAbsentOption( final CommandLine commandLine,
final char option,
final Consumer<Boolean> setting )
{
if ( !commandLine.hasOption( option ) )
{
setting.accept( true );
}
}
int calculateDegreeOfConcurrencyWithCoreMultiplier( String threadConfiguration )
{
int procs = Runtime.getRuntime().availableProcessors();
return (int) ( Float.parseFloat( threadConfiguration.replace( "C", "" ) ) * procs );
}
// ----------------------------------------------------------------------
// System properties handling
// ----------------------------------------------------------------------
static void populateProperties( CommandLine commandLine, Properties systemProperties, Properties userProperties )
{
EnvironmentUtils.addEnvVars( systemProperties );
// ----------------------------------------------------------------------
// Options that are set on the command line become system properties
// and therefore are set in the session properties. System properties
// are most dominant.
// ----------------------------------------------------------------------
if ( commandLine.hasOption( CLIManager.SET_SYSTEM_PROPERTY ) )
{
String[] defStrs = commandLine.getOptionValues( CLIManager.SET_SYSTEM_PROPERTY );
if ( defStrs != null )
{
for ( String defStr : defStrs )
{
setCliProperty( defStr, userProperties );
}
}
}
SystemProperties.addSystemProperties( systemProperties );
// ----------------------------------------------------------------------
// Properties containing info about the currently running version of Maven
// These override any corresponding properties set on the command line
// ----------------------------------------------------------------------
Properties buildProperties = CLIReportingUtils.getBuildProperties();
String mavenVersion = buildProperties.getProperty( CLIReportingUtils.BUILD_VERSION_PROPERTY );
systemProperties.setProperty( "maven.version", mavenVersion );
String mavenBuildVersion = CLIReportingUtils.createMavenVersionString( buildProperties );
systemProperties.setProperty( "maven.build.version", mavenBuildVersion );
}
private static void setCliProperty( String property, Properties properties )
{
String name;
String value;
int i = property.indexOf( '=' );
if ( i <= 0 )
{
name = property.trim();
value = "true";
}
else
{
name = property.substring( 0, i ).trim();
value = property.substring( i + 1 );
}
properties.setProperty( name, value );
// ----------------------------------------------------------------------
// I'm leaving the setting of system properties here as not to break
// the SystemPropertyProfileActivator. This won't harm embedding. jvz.
// ----------------------------------------------------------------------
System.setProperty( name, value );
}
static class ExitException
extends Exception
{
int exitCode;
ExitException( int exitCode )
{
this.exitCode = exitCode;
}
}
//
// Customizations available via the CLI
//
protected TransferListener getConsoleTransferListener( boolean printResourceNames )
{
return new ConsoleMavenTransferListener( System.out, printResourceNames );
}
protected TransferListener getBatchTransferListener()
{
return new Slf4jMavenTransferListener();
}
protected void customizeContainer( PlexusContainer container )
{
}
protected ModelProcessor createModelProcessor( PlexusContainer container )
throws ComponentLookupException
{
return container.lookup( ModelProcessor.class );
}
// Visible for testing
static class ProfileActivation
{
final List<String> activeProfiles = new ArrayList<>();
final List<String> inactiveProfiles = new ArrayList<>();
public void deactivate( final String profile )
{
inactiveProfiles.add( profile );
}
public void activate( final String profile )
{
activeProfiles.add( profile );
}
}
// Visible for testing
static class ProjectActivation
{
List<String> activeProjects;
List<String> inactiveProjects;
public void deactivate( final String project )
{
if ( inactiveProjects == null )
{
inactiveProjects = new ArrayList<>();
}
inactiveProjects.add( project );
}
public void activate( final String project )
{
if ( activeProjects == null )
{
activeProjects = new ArrayList<>();
}
activeProjects.add( project );
}
}
}