View Javadoc
1   package org.apache.maven.cli;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import com.google.inject.AbstractModule;
23  import org.apache.commons.cli.CommandLine;
24  import org.apache.commons.cli.Option;
25  import org.apache.commons.cli.ParseException;
26  import org.apache.commons.cli.UnrecognizedOptionException;
27  import org.apache.maven.BuildAbort;
28  import org.apache.maven.InternalErrorException;
29  import org.apache.maven.Maven;
30  import org.apache.maven.building.FileSource;
31  import org.apache.maven.building.Problem;
32  import org.apache.maven.building.Source;
33  import org.apache.maven.cli.configuration.ConfigurationProcessor;
34  import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor;
35  import org.apache.maven.cli.event.DefaultEventSpyContext;
36  import org.apache.maven.cli.event.ExecutionEventLogger;
37  import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
38  import org.apache.maven.cli.internal.extension.model.CoreExtension;
39  import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader;
40  import org.apache.maven.cli.logging.Slf4jConfiguration;
41  import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
42  import org.apache.maven.cli.logging.Slf4jLoggerManager;
43  import org.apache.maven.cli.logging.Slf4jStdoutLogger;
44  import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
45  import org.apache.maven.cli.transfer.QuietMavenTransferListener;
46  import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
47  import org.apache.maven.eventspy.internal.EventSpyDispatcher;
48  import org.apache.maven.exception.DefaultExceptionHandler;
49  import org.apache.maven.exception.ExceptionHandler;
50  import org.apache.maven.exception.ExceptionSummary;
51  import org.apache.maven.execution.DefaultMavenExecutionRequest;
52  import org.apache.maven.execution.ExecutionListener;
53  import org.apache.maven.execution.MavenExecutionRequest;
54  import org.apache.maven.execution.MavenExecutionRequestPopulationException;
55  import org.apache.maven.execution.MavenExecutionRequestPopulator;
56  import org.apache.maven.execution.MavenExecutionResult;
57  import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
58  import org.apache.maven.extension.internal.CoreExports;
59  import org.apache.maven.extension.internal.CoreExtensionEntry;
60  import org.apache.maven.lifecycle.LifecycleExecutionException;
61  import org.apache.maven.model.building.ModelProcessor;
62  import org.apache.maven.project.MavenProject;
63  import org.apache.maven.properties.internal.EnvironmentUtils;
64  import org.apache.maven.properties.internal.SystemProperties;
65  import org.apache.maven.session.scope.internal.SessionScopeModule;
66  import org.apache.maven.shared.utils.logging.MessageBuilder;
67  import org.apache.maven.shared.utils.logging.MessageUtils;
68  import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest;
69  import org.apache.maven.toolchain.building.ToolchainsBuilder;
70  import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
71  import org.codehaus.plexus.ContainerConfiguration;
72  import org.codehaus.plexus.DefaultContainerConfiguration;
73  import org.codehaus.plexus.DefaultPlexusContainer;
74  import org.codehaus.plexus.PlexusConstants;
75  import org.codehaus.plexus.PlexusContainer;
76  import org.codehaus.plexus.classworlds.ClassWorld;
77  import org.codehaus.plexus.classworlds.realm.ClassRealm;
78  import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
79  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
80  import org.codehaus.plexus.logging.LoggerManager;
81  import org.codehaus.plexus.util.StringUtils;
82  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
83  import org.eclipse.aether.transfer.TransferListener;
84  import org.slf4j.ILoggerFactory;
85  import org.slf4j.Logger;
86  import org.slf4j.LoggerFactory;
87  import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
88  import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
89  import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
90  import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
91  import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
92  
93  import java.io.BufferedInputStream;
94  import java.io.Console;
95  import java.io.File;
96  import java.io.FileInputStream;
97  import java.io.FileNotFoundException;
98  import java.io.FileOutputStream;
99  import java.io.IOException;
100 import java.io.InputStream;
101 import java.io.PrintStream;
102 import java.nio.file.Files;
103 import java.util.ArrayList;
104 import java.util.Collections;
105 import java.util.HashSet;
106 import java.util.LinkedHashMap;
107 import java.util.List;
108 import java.util.Map;
109 import java.util.Map.Entry;
110 import java.util.Properties;
111 import java.util.Set;
112 import java.util.StringTokenizer;
113 import java.util.regex.Matcher;
114 import java.util.regex.Pattern;
115 
116 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
117 
118 // TODO push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs
119 
120 /**
121  * @author Jason van Zyl
122  */
123 public class MavenCli
124 {
125     public static final String LOCAL_REPO_PROPERTY = "maven.repo.local";
126 
127     public static final String THREADS_DEPRECATED = "maven.threads.experimental";
128 
129     public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory";
130 
131     public static final String USER_HOME = System.getProperty( "user.home" );
132 
133     public static final File USER_MAVEN_CONFIGURATION_HOME = new File( USER_HOME, ".m2" );
134 
135     public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File( USER_MAVEN_CONFIGURATION_HOME, "toolchains.xml" );
136 
137     public static final File DEFAULT_GLOBAL_TOOLCHAINS_FILE =
138         new File( System.getProperty( "maven.conf" ), "toolchains.xml" );
139 
140     private static final String EXT_CLASS_PATH = "maven.ext.class.path";
141 
142     private static final String EXTENSIONS_FILENAME = ".mvn/extensions.xml";
143 
144     private static final String MVN_MAVEN_CONFIG = ".mvn/maven.config";
145 
146     public static final String STYLE_COLOR_PROPERTY = "style.color";
147 
148     private ClassWorld classWorld;
149 
150     private LoggerManager plexusLoggerManager;
151 
152     private ILoggerFactory slf4jLoggerFactory;
153 
154     private Logger slf4jLogger;
155 
156     private EventSpyDispatcher eventSpyDispatcher;
157 
158     private ModelProcessor modelProcessor;
159 
160     private Maven maven;
161 
162     private MavenExecutionRequestPopulator executionRequestPopulator;
163 
164     private ToolchainsBuilder toolchainsBuilder;
165 
166     private DefaultSecDispatcher dispatcher;
167 
168     private Map<String, ConfigurationProcessor> configurationProcessors;
169 
170     public MavenCli()
171     {
172         this( null );
173     }
174 
175     // This supports painless invocation by the Verifier during embedded execution of the core ITs
176     public MavenCli( ClassWorld classWorld )
177     {
178         this.classWorld = classWorld;
179     }
180 
181     public static void main( String[] args )
182     {
183         int result = main( args, null );
184 
185         System.exit( result );
186     }
187 
188     public static int main( String[] args, ClassWorld classWorld )
189     {
190         MavenCli cli = new MavenCli();
191 
192         MessageUtils.systemInstall();
193         MessageUtils.registerShutdownHook();
194         int result = cli.doMain( new CliRequest( args, classWorld ) );
195         MessageUtils.systemUninstall();
196 
197         return result;
198     }
199 
200     // TODO need to externalize CliRequest
201     public static int doMain( String[] args, ClassWorld classWorld )
202     {
203         MavenCli cli = new MavenCli();
204         return cli.doMain( new CliRequest( args, classWorld ) );
205     }
206 
207     /**
208      * This supports painless invocation by the Verifier during embedded execution of the core ITs.
209      * See <a href="http://maven.apache.org/shared/maven-verifier/xref/org/apache/maven/it/Embedded3xLauncher.html">
210      * <code>Embedded3xLauncher</code> in <code>maven-verifier</code></a>
211      */
212     public int doMain( String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr )
213     {
214         PrintStream oldout = System.out;
215         PrintStream olderr = System.err;
216 
217         final Set<String> realms;
218         if ( classWorld != null )
219         {
220             realms = new HashSet<>();
221             for ( ClassRealm realm : classWorld.getRealms() )
222             {
223                 realms.add( realm.getId() );
224             }
225         }
226         else
227         {
228             realms = Collections.emptySet();
229         }
230 
231         try
232         {
233             if ( stdout != null )
234             {
235                 System.setOut( stdout );
236             }
237             if ( stderr != null )
238             {
239                 System.setErr( stderr );
240             }
241 
242             CliRequest cliRequest = new CliRequest( args, classWorld );
243             cliRequest.workingDirectory = workingDirectory;
244 
245             return doMain( cliRequest );
246         }
247         finally
248         {
249             if ( classWorld != null )
250             {
251                 for ( ClassRealm realm : new ArrayList<>( classWorld.getRealms() ) )
252                 {
253                     String realmId = realm.getId();
254                     if ( !realms.contains( realmId ) )
255                     {
256                         try
257                         {
258                             classWorld.disposeRealm( realmId );
259                         }
260                         catch ( NoSuchRealmException ignored )
261                         {
262                             // can't happen
263                         }
264                     }
265                 }
266             }
267             System.setOut( oldout );
268             System.setErr( olderr );
269         }
270     }
271 
272     // TODO need to externalize CliRequest
273     public int doMain( CliRequest cliRequest )
274     {
275         PlexusContainer localContainer = null;
276         try
277         {
278             initialize( cliRequest );
279             cli( cliRequest );
280             properties( cliRequest );
281             logging( cliRequest );
282             version( cliRequest );
283             localContainer = container( cliRequest );
284             commands( cliRequest );
285             configure( cliRequest );
286             toolchains( cliRequest );
287             populateRequest( cliRequest );
288             encryption( cliRequest );
289             repository( cliRequest );
290             return execute( cliRequest );
291         }
292         catch ( ExitException e )
293         {
294             return e.exitCode;
295         }
296         catch ( UnrecognizedOptionException e )
297         {
298             // pure user error, suppress stack trace
299             return 1;
300         }
301         catch ( BuildAbort e )
302         {
303             CLIReportingUtils.showError( slf4jLogger, "ABORTED", e, cliRequest.showErrors );
304 
305             return 2;
306         }
307         catch ( Exception e )
308         {
309             CLIReportingUtils.showError( slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors );
310 
311             return 1;
312         }
313         finally
314         {
315             if ( localContainer != null )
316             {
317                 localContainer.dispose();
318             }
319         }
320     }
321 
322     void initialize( CliRequest cliRequest )
323         throws ExitException
324     {
325         if ( cliRequest.workingDirectory == null )
326         {
327             cliRequest.workingDirectory = System.getProperty( "user.dir" );
328         }
329 
330         if ( cliRequest.multiModuleProjectDirectory == null )
331         {
332             String basedirProperty = System.getProperty( MULTIMODULE_PROJECT_DIRECTORY );
333             if ( basedirProperty == null )
334             {
335                 System.err.format(
336                     "-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY );
337                 throw new ExitException( 1 );
338             }
339             File basedir = basedirProperty != null ? new File( basedirProperty ) : new File( "" );
340             try
341             {
342                 cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile();
343             }
344             catch ( IOException e )
345             {
346                 cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile();
347             }
348         }
349 
350         //
351         // Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative
352         // Windows paths.
353         //
354         String mavenHome = System.getProperty( "maven.home" );
355 
356         if ( mavenHome != null )
357         {
358             System.setProperty( "maven.home", new File( mavenHome ).getAbsolutePath() );
359         }
360     }
361 
362     void cli( CliRequest cliRequest )
363         throws Exception
364     {
365         //
366         // Parsing errors can happen during the processing of the arguments and we prefer not having to check if
367         // the logger is null and construct this so we can use an SLF4J logger everywhere.
368         //
369         slf4jLogger = new Slf4jStdoutLogger();
370 
371         CLIManager cliManager = new CLIManager();
372 
373         List<String> args = new ArrayList<>();
374         CommandLine mavenConfig = null;
375         try
376         {
377             File configFile = new File( cliRequest.multiModuleProjectDirectory, MVN_MAVEN_CONFIG );
378 
379             if ( configFile.isFile() )
380             {
381                 for ( String arg : new String( Files.readAllBytes( configFile.toPath() ) ).split( "\\s+" ) )
382                 {
383                     if ( !arg.isEmpty() )
384                     {
385                         args.add( arg );
386                     }
387                 }
388 
389                 mavenConfig = cliManager.parse( args.toArray( new String[args.size()] ) );
390                 List<?> unrecongized = mavenConfig.getArgList();
391                 if ( !unrecongized.isEmpty() )
392                 {
393                     throw new ParseException( "Unrecognized maven.config entries: " + unrecongized );
394                 }
395             }
396         }
397         catch ( ParseException e )
398         {
399             System.err.println( "Unable to parse maven.config: " + e.getMessage() );
400             cliManager.displayHelp( System.out );
401             throw e;
402         }
403 
404         try
405         {
406             if ( mavenConfig == null )
407             {
408                 cliRequest.commandLine = cliManager.parse( cliRequest.args );
409             }
410             else
411             {
412                 cliRequest.commandLine = cliMerge( cliManager.parse( cliRequest.args ), mavenConfig );
413             }
414         }
415         catch ( ParseException e )
416         {
417             System.err.println( "Unable to parse command line options: " + e.getMessage() );
418             cliManager.displayHelp( System.out );
419             throw e;
420         }
421 
422         if ( cliRequest.commandLine.hasOption( CLIManager.HELP ) )
423         {
424             cliManager.displayHelp( System.out );
425             throw new ExitException( 0 );
426         }
427 
428         if ( cliRequest.commandLine.hasOption( CLIManager.VERSION ) )
429         {
430             System.out.println( CLIReportingUtils.showVersion() );
431             throw new ExitException( 0 );
432         }
433     }
434 
435     private CommandLine cliMerge( CommandLine mavenArgs, CommandLine mavenConfig )
436     {
437         CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
438         
439         // the args are easy, cli first then config file
440         for ( String arg : mavenArgs.getArgs() )
441         {
442             commandLineBuilder.addArg( arg );
443         }
444         for ( String arg : mavenConfig.getArgs() )
445         {
446             commandLineBuilder.addArg( arg );
447         }
448         
449         // now add all options, except for -D with cli first then config file
450         List<Option> setPropertyOptions = new ArrayList<>();
451         for ( Option opt : mavenArgs.getOptions() )
452         {
453             if ( String.valueOf( CLIManager.SET_SYSTEM_PROPERTY ).equals( opt.getOpt() ) )
454             {
455                 setPropertyOptions.add( opt );
456             }
457             else
458             {
459                 commandLineBuilder.addOption( opt );
460             }
461         }
462         for ( Option opt : mavenConfig.getOptions() )
463         {
464             commandLineBuilder.addOption( opt );
465         }
466         // finally add the CLI system properties
467         for ( Option opt : setPropertyOptions )
468         {
469             commandLineBuilder.addOption( opt );
470         }
471         return commandLineBuilder.build();
472     }
473 
474     /**
475      * configure logging
476      */
477     void logging( CliRequest cliRequest )
478     {
479         // LOG LEVEL
480         cliRequest.debug = cliRequest.commandLine.hasOption( CLIManager.DEBUG );
481         cliRequest.quiet = !cliRequest.debug && cliRequest.commandLine.hasOption( CLIManager.QUIET );
482         cliRequest.showErrors = cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.ERRORS );
483 
484         slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
485         Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration( slf4jLoggerFactory );
486 
487         if ( cliRequest.debug )
488         {
489             cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_DEBUG );
490             slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.DEBUG );
491         }
492         else if ( cliRequest.quiet )
493         {
494             cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_ERROR );
495             slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.ERROR );
496         }
497         // else fall back to default log level specified in conf
498         // see https://issues.apache.org/jira/browse/MNG-2570
499 
500         // LOG COLOR
501         String styleColor = cliRequest.getUserProperties().getProperty( STYLE_COLOR_PROPERTY, "auto" );
502         if ( "always".equals( styleColor ) )
503         {
504             MessageUtils.setColorEnabled( true );
505         }
506         else if ( "never".equals( styleColor ) )
507         {
508             MessageUtils.setColorEnabled( false );
509         }
510         else if ( !"auto".equals( styleColor ) )
511         {
512             throw new IllegalArgumentException( "Invalid color configuration option [" + styleColor
513                 + "]. Supported values are (auto|always|never)." );
514         }
515         else if ( cliRequest.commandLine.hasOption( CLIManager.BATCH_MODE )
516             || cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
517         {
518             MessageUtils.setColorEnabled( false );
519         }
520         
521         // LOG STREAMS
522         if ( cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
523         {
524             File logFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.LOG_FILE ) );
525             logFile = resolveFile( logFile, cliRequest.workingDirectory );
526 
527             // redirect stdout and stderr to file
528             try
529             {
530                 PrintStream ps = new PrintStream( new FileOutputStream( logFile ) );
531                 System.setOut( ps );
532                 System.setErr( ps );
533             }
534             catch ( FileNotFoundException e )
535             {
536                 //
537                 // Ignore
538                 //
539             }
540         }
541 
542         slf4jConfiguration.activate();
543 
544         plexusLoggerManager = new Slf4jLoggerManager();
545         slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
546     }
547 
548     private void version( CliRequest cliRequest )
549     {
550         if ( cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.SHOW_VERSION ) )
551         {
552             System.out.println( CLIReportingUtils.showVersion() );
553         }
554     }
555 
556     private void commands( CliRequest cliRequest )
557     {
558         if ( cliRequest.showErrors )
559         {
560             slf4jLogger.info( "Error stacktraces are turned on." );
561         }
562 
563         if ( MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
564         {
565             slf4jLogger.info( "Disabling strict checksum verification on all artifact downloads." );
566         }
567         else if ( MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
568         {
569             slf4jLogger.info( "Enabling strict checksum verification on all artifact downloads." );
570         }
571 
572         if ( slf4jLogger.isDebugEnabled() )
573         {
574             slf4jLogger.debug( "Message scheme: " + ( MessageUtils.isColorEnabled() ? "color" : "plain" ) );
575             if ( MessageUtils.isColorEnabled() )
576             {
577                 MessageBuilder buff = MessageUtils.buffer();
578                 buff.a( "Message styles: " );
579                 buff.a( MessageUtils.level().debug( "debug" ) ).a( ' ' );
580                 buff.a( MessageUtils.level().info( "info" ) ).a( ' ' );
581                 buff.a( MessageUtils.level().warning( "warning" ) ).a( ' ' );
582                 buff.a( MessageUtils.level().error( "error" ) ).a( ' ' );
583 
584                 buff.success( "success" ).a( ' ' );
585                 buff.failure( "failure" ).a( ' ' );
586                 buff.strong( "strong" ).a( ' ' );
587                 buff.mojo( "mojo" ).a( ' ' );
588                 buff.project( "project" );
589                 slf4jLogger.debug( buff.toString() );
590             }
591         }
592     }
593 
594     //Needed to make this method package visible to make writing a unit test possible
595     //Maybe it's better to move some of those methods to separate class (SoC).
596     void properties( CliRequest cliRequest )
597     {
598         populateProperties( cliRequest.commandLine, cliRequest.systemProperties, cliRequest.userProperties );
599     }
600 
601     private PlexusContainer container( CliRequest cliRequest )
602         throws Exception
603     {
604         if ( cliRequest.classWorld == null )
605         {
606             cliRequest.classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
607         }
608 
609         ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" );
610         if ( coreRealm == null )
611         {
612             coreRealm = cliRequest.classWorld.getRealms().iterator().next();
613         }
614 
615         List<File> extClassPath = parseExtClasspath( cliRequest );
616 
617         CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom( coreRealm );
618         List<CoreExtensionEntry> extensions =
619             loadCoreExtensions( cliRequest, coreRealm, coreEntry.getExportedArtifacts() );
620 
621         ClassRealm containerRealm = setupContainerRealm( cliRequest.classWorld, coreRealm, extClassPath, extensions );
622 
623         ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld( cliRequest.classWorld )
624             .setRealm( containerRealm ).setClassPathScanning( PlexusConstants.SCANNING_INDEX ).setAutoWiring( true )
625             .setJSR250Lifecycle( true ).setName( "maven" );
626 
627         Set<String> exportedArtifacts = new HashSet<>( coreEntry.getExportedArtifacts() );
628         Set<String> exportedPackages = new HashSet<>( coreEntry.getExportedPackages() );
629         for ( CoreExtensionEntry extension : extensions )
630         {
631             exportedArtifacts.addAll( extension.getExportedArtifacts() );
632             exportedPackages.addAll( extension.getExportedPackages() );
633         }
634 
635         final CoreExports exports = new CoreExports( containerRealm, exportedArtifacts, exportedPackages );
636 
637         DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
638         {
639             @Override
640             protected void configure()
641             {
642                 bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
643                 bind( CoreExports.class ).toInstance( exports );
644             }
645         } );
646 
647         // NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups
648         container.setLookupRealm( null );
649         Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
650 
651         container.setLoggerManager( plexusLoggerManager );
652 
653         for ( CoreExtensionEntry extension : extensions )
654         {
655             container.discoverComponents( extension.getClassRealm(), new SessionScopeModule( container ),
656                                           new MojoExecutionScopeModule( container ) );
657         }
658 
659         customizeContainer( container );
660 
661         container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
662 
663         eventSpyDispatcher = container.lookup( EventSpyDispatcher.class );
664 
665         DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext();
666         Map<String, Object> data = eventSpyContext.getData();
667         data.put( "plexus", container );
668         data.put( "workingDirectory", cliRequest.workingDirectory );
669         data.put( "systemProperties", cliRequest.systemProperties );
670         data.put( "userProperties", cliRequest.userProperties );
671         data.put( "versionProperties", CLIReportingUtils.getBuildProperties() );
672         eventSpyDispatcher.init( eventSpyContext );
673 
674         // refresh logger in case container got customized by spy
675         slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
676 
677         maven = container.lookup( Maven.class );
678 
679         executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
680 
681         modelProcessor = createModelProcessor( container );
682 
683         configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
684 
685         toolchainsBuilder = container.lookup( ToolchainsBuilder.class );
686 
687         dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" );
688 
689         return container;
690     }
691 
692     private List<CoreExtensionEntry> loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm,
693                                                          Set<String> providedArtifacts )
694     {
695         if ( cliRequest.multiModuleProjectDirectory == null )
696         {
697             return Collections.emptyList();
698         }
699 
700         File extensionsFile = new File( cliRequest.multiModuleProjectDirectory, EXTENSIONS_FILENAME );
701         if ( !extensionsFile.isFile() )
702         {
703             return Collections.emptyList();
704         }
705 
706         try
707         {
708             List<CoreExtension> extensions = readCoreExtensionsDescriptor( extensionsFile );
709             if ( extensions.isEmpty() )
710             {
711                 return Collections.emptyList();
712             }
713 
714             ContainerConfiguration cc = new DefaultContainerConfiguration() //
715                 .setClassWorld( cliRequest.classWorld ) //
716                 .setRealm( containerRealm ) //
717                 .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) //
718                 .setAutoWiring( true ) //
719                 .setJSR250Lifecycle( true ) //
720                 .setName( "maven" );
721 
722             DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
723             {
724                 @Override
725                 protected void configure()
726                 {
727                     bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
728                 }
729             } );
730 
731             try
732             {
733                 container.setLookupRealm( null );
734 
735                 container.setLoggerManager( plexusLoggerManager );
736 
737                 container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
738 
739                 Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
740 
741                 executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
742 
743                 configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
744 
745                 configure( cliRequest );
746 
747                 MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request );
748 
749                 request = populateRequest( cliRequest, request );
750 
751                 request = executionRequestPopulator.populateDefaults( request );
752 
753                 BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class );
754 
755                 return resolver.loadCoreExtensions( request, providedArtifacts, extensions );
756             }
757             finally
758             {
759                 executionRequestPopulator = null;
760                 container.dispose();
761             }
762         }
763         catch ( RuntimeException e )
764         {
765             // runtime exceptions are most likely bugs in maven, let them bubble up to the user
766             throw e;
767         }
768         catch ( Exception e )
769         {
770             slf4jLogger.warn( "Failed to read extensions descriptor " + extensionsFile + ": " + e.getMessage() );
771         }
772         return Collections.emptyList();
773     }
774 
775     private List<CoreExtension> readCoreExtensionsDescriptor( File extensionsFile )
776         throws IOException, XmlPullParserException
777     {
778         CoreExtensionsXpp3Reader parser = new CoreExtensionsXpp3Reader();
779 
780         try ( InputStream is = new BufferedInputStream( new FileInputStream( extensionsFile ) ) )
781         {
782 
783             return parser.read( is ).getExtensions();
784         }
785 
786     }
787 
788     private ClassRealm setupContainerRealm( ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath,
789                                             List<CoreExtensionEntry> extensions )
790         throws Exception
791     {
792         if ( !extClassPath.isEmpty() || !extensions.isEmpty() )
793         {
794             ClassRealm extRealm = classWorld.newRealm( "maven.ext", null );
795 
796             extRealm.setParentRealm( coreRealm );
797 
798             slf4jLogger.debug( "Populating class realm " + extRealm.getId() );
799 
800             for ( File file : extClassPath )
801             {
802                 slf4jLogger.debug( "  Included " + file );
803 
804                 extRealm.addURL( file.toURI().toURL() );
805             }
806 
807             for ( CoreExtensionEntry entry : reverse( extensions ) )
808             {
809                 Set<String> exportedPackages = entry.getExportedPackages();
810                 ClassRealm realm = entry.getClassRealm();
811                 for ( String exportedPackage : exportedPackages )
812                 {
813                     extRealm.importFrom( realm, exportedPackage );
814                 }
815                 if ( exportedPackages.isEmpty() )
816                 {
817                     // sisu uses realm imports to establish component visibility
818                     extRealm.importFrom( realm, realm.getId() );
819                 }
820             }
821 
822             return extRealm;
823         }
824 
825         return coreRealm;
826     }
827 
828     private static <T> List<T> reverse( List<T> list )
829     {
830         List<T> copy = new ArrayList<>( list );
831         Collections.reverse( copy );
832         return copy;
833     }
834 
835     private List<File> parseExtClasspath( CliRequest cliRequest )
836     {
837         String extClassPath = cliRequest.userProperties.getProperty( EXT_CLASS_PATH );
838         if ( extClassPath == null )
839         {
840             extClassPath = cliRequest.systemProperties.getProperty( EXT_CLASS_PATH );
841         }
842 
843         List<File> jars = new ArrayList<>();
844 
845         if ( StringUtils.isNotEmpty( extClassPath ) )
846         {
847             for ( String jar : StringUtils.split( extClassPath, File.pathSeparator ) )
848             {
849                 File file = resolveFile( new File( jar ), cliRequest.workingDirectory );
850 
851                 slf4jLogger.debug( "  Included " + file );
852 
853                 jars.add( file );
854             }
855         }
856 
857         return jars;
858     }
859 
860     //
861     // This should probably be a separate tool and not be baked into Maven.
862     //
863     private void encryption( CliRequest cliRequest )
864         throws Exception
865     {
866         if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_MASTER_PASSWORD ) )
867         {
868             String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_MASTER_PASSWORD );
869 
870             if ( passwd == null )
871             {
872                 Console cons = System.console();
873                 char[] password = ( cons == null ) ? null : cons.readPassword( "Master password: " );
874                 if ( password != null )
875                 {
876                     // Cipher uses Strings
877                     passwd = String.copyValueOf( password );
878 
879                     // Sun/Oracle advises to empty the char array
880                     java.util.Arrays.fill( password, ' ' );
881                 }
882             }
883 
884             DefaultPlexusCipher cipher = new DefaultPlexusCipher();
885 
886             System.out.println(
887                 cipher.encryptAndDecorate( passwd, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) );
888 
889             throw new ExitException( 0 );
890         }
891         else if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_PASSWORD ) )
892         {
893             String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_PASSWORD );
894 
895             if ( passwd == null )
896             {
897                 Console cons = System.console();
898                 char[] password = ( cons == null ) ? null : cons.readPassword( "Password: " );
899                 if ( password != null )
900                 {
901                     // Cipher uses Strings
902                     passwd = String.copyValueOf( password );
903 
904                     // Sun/Oracle advises to empty the char array
905                     java.util.Arrays.fill( password, ' ' );
906                 }
907             }
908 
909             String configurationFile = dispatcher.getConfigurationFile();
910 
911             if ( configurationFile.startsWith( "~" ) )
912             {
913                 configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
914             }
915 
916             String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
917 
918             String master = null;
919 
920             SettingsSecurity sec = SecUtil.read( file, true );
921             if ( sec != null )
922             {
923                 master = sec.getMaster();
924             }
925 
926             if ( master == null )
927             {
928                 throw new IllegalStateException( "Master password is not set in the setting security file: " + file );
929             }
930 
931             DefaultPlexusCipher cipher = new DefaultPlexusCipher();
932             String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
933             System.out.println( cipher.encryptAndDecorate( passwd, masterPasswd ) );
934 
935             throw new ExitException( 0 );
936         }
937     }
938 
939     private void repository( CliRequest cliRequest )
940         throws Exception
941     {
942         if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_LOCAL_REPOSITORY ) || Boolean.getBoolean(
943             "maven.legacyLocalRepo" ) )
944         {
945             cliRequest.request.setUseLegacyLocalRepository( true );
946         }
947     }
948 
949     private int execute( CliRequest cliRequest )
950         throws MavenExecutionRequestPopulationException
951     {
952         MavenExecutionRequest request = executionRequestPopulator.populateDefaults( cliRequest.request );
953 
954         eventSpyDispatcher.onEvent( request );
955 
956         MavenExecutionResult result = maven.execute( request );
957 
958         eventSpyDispatcher.onEvent( result );
959 
960         eventSpyDispatcher.close();
961 
962         if ( result.hasExceptions() )
963         {
964             ExceptionHandler handler = new DefaultExceptionHandler();
965 
966             Map<String, String> references = new LinkedHashMap<>();
967 
968             MavenProject project = null;
969 
970             for ( Throwable exception : result.getExceptions() )
971             {
972                 ExceptionSummary summary = handler.handleException( exception );
973 
974                 logSummary( summary, references, "", cliRequest.showErrors );
975 
976                 if ( project == null && exception instanceof LifecycleExecutionException )
977                 {
978                     project = ( (LifecycleExecutionException) exception ).getProject();
979                 }
980             }
981 
982             slf4jLogger.error( "" );
983 
984             if ( !cliRequest.showErrors )
985             {
986                 slf4jLogger.error( "To see the full stack trace of the errors, re-run Maven with the "
987                     + buffer().strong( "-e" ) + " switch." );
988             }
989             if ( !slf4jLogger.isDebugEnabled() )
990             {
991                 slf4jLogger.error( "Re-run Maven using the " + buffer().strong( "-X" )
992                     + " switch to enable full debug logging." );
993             }
994 
995             if ( !references.isEmpty() )
996             {
997                 slf4jLogger.error( "" );
998                 slf4jLogger.error( "For more information about the errors and possible solutions"
999                                        + ", please read the following articles:" );
1000 
1001                 for ( Map.Entry<String, String> entry : references.entrySet() )
1002                 {
1003                     slf4jLogger.error( buffer().strong( entry.getValue() ) + " " + entry.getKey() );
1004                 }
1005             }
1006 
1007             if ( project != null && !project.equals( result.getTopologicallySortedProjects().get( 0 ) ) )
1008             {
1009                 slf4jLogger.error( "" );
1010                 slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
1011                 slf4jLogger.error( buffer().a( "  " ).strong( "mvn <goals> -rf :"
1012                                 + project.getArtifactId() ).toString() );
1013             }
1014 
1015             if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) )
1016             {
1017                 slf4jLogger.info( "Build failures were ignored." );
1018 
1019                 return 0;
1020             }
1021             else
1022             {
1023                 return 1;
1024             }
1025         }
1026         else
1027         {
1028             return 0;
1029         }
1030     }
1031 
1032     private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent,
1033                              boolean showErrors )
1034     {
1035         String referenceKey = "";
1036 
1037         if ( StringUtils.isNotEmpty( summary.getReference() ) )
1038         {
1039             referenceKey = references.get( summary.getReference() );
1040             if ( referenceKey == null )
1041             {
1042                 referenceKey = "[Help " + ( references.size() + 1 ) + "]";
1043                 references.put( summary.getReference(), referenceKey );
1044             }
1045         }
1046 
1047         String msg = summary.getMessage();
1048 
1049         if ( StringUtils.isNotEmpty( referenceKey ) )
1050         {
1051             if ( msg.indexOf( '\n' ) < 0 )
1052             {
1053                 msg += " -> " + buffer().strong( referenceKey );
1054             }
1055             else
1056             {
1057                 msg += "\n-> " + buffer().strong( referenceKey );
1058             }
1059         }
1060 
1061         String[] lines = msg.split( "(\r\n)|(\r)|(\n)" );
1062         String currentColor = "";
1063 
1064         for ( int i = 0; i < lines.length; i++ )
1065         {
1066             // add eventual current color inherited from previous line 
1067             String line = currentColor + lines[i];
1068 
1069             // look for last ANSI escape sequence to check if nextColor
1070             Matcher matcher = LAST_ANSI_SEQUENCE.matcher( line );
1071             String nextColor = "";
1072             if ( matcher.find() )
1073             {
1074                 nextColor = matcher.group( 1 );
1075                 if ( ANSI_RESET.equals( nextColor ) )
1076                 {
1077                     // last ANSI escape code is reset: no next color
1078                     nextColor = "";
1079                 }
1080             }
1081 
1082             // effective line, with indent and reset if end is colored
1083             line = indent + line + ( "".equals( nextColor ) ? "" : ANSI_RESET );
1084 
1085             if ( ( i == lines.length - 1 ) && ( showErrors
1086                 || ( summary.getException() instanceof InternalErrorException ) ) )
1087             {
1088                 slf4jLogger.error( line, summary.getException() );
1089             }
1090             else
1091             {
1092                 slf4jLogger.error( line );
1093             }
1094 
1095             currentColor = nextColor;
1096         }
1097 
1098         indent += "  ";
1099 
1100         for ( ExceptionSummary child : summary.getChildren() )
1101         {
1102             logSummary( child, references, indent, showErrors );
1103         }
1104     }
1105 
1106     private static final Pattern LAST_ANSI_SEQUENCE = Pattern.compile( "(\u001B\\[[;\\d]*[ -/]*[@-~])[^\u001B]*$" );
1107 
1108     private static final String ANSI_RESET = "\u001B\u005Bm";
1109 
1110     private void configure( CliRequest cliRequest )
1111         throws Exception
1112     {
1113         //
1114         // This is not ideal but there are events specifically for configuration from the CLI which I don't
1115         // believe are really valid but there are ITs which assert the right events are published so this
1116         // needs to be supported so the EventSpyDispatcher needs to be put in the CliRequest so that
1117         // it can be accessed by configuration processors.
1118         //
1119         cliRequest.request.setEventSpyDispatcher( eventSpyDispatcher );
1120 
1121         //
1122         // We expect at most 2 implementations to be available. The SettingsXmlConfigurationProcessor implementation
1123         // is always available in the core and likely always will be, but we may have another ConfigurationProcessor
1124         // present supplied by the user. The rule is that we only allow the execution of one ConfigurationProcessor.
1125         // If there is more than one then we execute the one supplied by the user, otherwise we execute the
1126         // the default SettingsXmlConfigurationProcessor.
1127         //
1128         int userSuppliedConfigurationProcessorCount = configurationProcessors.size() - 1;
1129 
1130         if ( userSuppliedConfigurationProcessorCount == 0 )
1131         {
1132             //
1133             // Our settings.xml source is historically how we have configured Maven from the CLI so we are going to
1134             // have to honour its existence forever. So let's run it.
1135             //
1136             configurationProcessors.get( SettingsXmlConfigurationProcessor.HINT ).process( cliRequest );
1137         }
1138         else if ( userSuppliedConfigurationProcessorCount == 1 )
1139         {
1140             //
1141             // Run the user supplied ConfigurationProcessor
1142             //
1143             for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() )
1144             {
1145                 String hint = entry.getKey();
1146                 if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) )
1147                 {
1148                     ConfigurationProcessor configurationProcessor = entry.getValue();
1149                     configurationProcessor.process( cliRequest );
1150                 }
1151             }
1152         }
1153         else if ( userSuppliedConfigurationProcessorCount > 1 )
1154         {
1155             //
1156             // There are too many ConfigurationProcessors so we don't know which one to run so report the error.
1157             //
1158             StringBuilder sb = new StringBuilder(
1159                 String.format( "\nThere can only be one user supplied ConfigurationProcessor, there are %s:\n\n",
1160                                userSuppliedConfigurationProcessorCount ) );
1161             for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() )
1162             {
1163                 String hint = entry.getKey();
1164                 if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) )
1165                 {
1166                     ConfigurationProcessor configurationProcessor = entry.getValue();
1167                     sb.append( String.format( "%s\n", configurationProcessor.getClass().getName() ) );
1168                 }
1169             }
1170             sb.append( String.format( "\n" ) );
1171             throw new Exception( sb.toString() );
1172         }
1173     }
1174 
1175     private void toolchains( CliRequest cliRequest )
1176         throws Exception
1177     {
1178         File userToolchainsFile;
1179 
1180         if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) )
1181         {
1182             userToolchainsFile =
1183                 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) );
1184             userToolchainsFile = resolveFile( userToolchainsFile, cliRequest.workingDirectory );
1185 
1186             if ( !userToolchainsFile.isFile() )
1187             {
1188                 throw new FileNotFoundException(
1189                     "The specified user toolchains file does not exist: " + userToolchainsFile );
1190             }
1191         }
1192         else
1193         {
1194             userToolchainsFile = DEFAULT_USER_TOOLCHAINS_FILE;
1195         }
1196 
1197         File globalToolchainsFile;
1198 
1199         if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) )
1200         {
1201             globalToolchainsFile =
1202                 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) );
1203             globalToolchainsFile = resolveFile( globalToolchainsFile, cliRequest.workingDirectory );
1204 
1205             if ( !globalToolchainsFile.isFile() )
1206             {
1207                 throw new FileNotFoundException(
1208                     "The specified global toolchains file does not exist: " + globalToolchainsFile );
1209             }
1210         }
1211         else
1212         {
1213             globalToolchainsFile = DEFAULT_GLOBAL_TOOLCHAINS_FILE;
1214         }
1215 
1216         cliRequest.request.setGlobalToolchainsFile( globalToolchainsFile );
1217         cliRequest.request.setUserToolchainsFile( userToolchainsFile );
1218 
1219         DefaultToolchainsBuildingRequest toolchainsRequest = new DefaultToolchainsBuildingRequest();
1220         if ( globalToolchainsFile.isFile() )
1221         {
1222             toolchainsRequest.setGlobalToolchainsSource( new FileSource( globalToolchainsFile ) );
1223         }
1224         if ( userToolchainsFile.isFile() )
1225         {
1226             toolchainsRequest.setUserToolchainsSource( new FileSource( userToolchainsFile ) );
1227         }
1228 
1229         eventSpyDispatcher.onEvent( toolchainsRequest );
1230 
1231         slf4jLogger.debug(
1232             "Reading global toolchains from " + getLocation( toolchainsRequest.getGlobalToolchainsSource(),
1233                                                              globalToolchainsFile ) );
1234         slf4jLogger.debug( "Reading user toolchains from " + getLocation( toolchainsRequest.getUserToolchainsSource(),
1235                                                                           userToolchainsFile ) );
1236 
1237         ToolchainsBuildingResult toolchainsResult = toolchainsBuilder.build( toolchainsRequest );
1238 
1239         eventSpyDispatcher.onEvent( toolchainsRequest );
1240 
1241         executionRequestPopulator.populateFromToolchains( cliRequest.request,
1242                                                           toolchainsResult.getEffectiveToolchains() );
1243 
1244         if ( !toolchainsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled() )
1245         {
1246             slf4jLogger.warn( "" );
1247             slf4jLogger.warn( "Some problems were encountered while building the effective toolchains" );
1248 
1249             for ( Problem problem : toolchainsResult.getProblems() )
1250             {
1251                 slf4jLogger.warn( problem.getMessage() + " @ " + problem.getLocation() );
1252             }
1253 
1254             slf4jLogger.warn( "" );
1255         }
1256     }
1257 
1258     private Object getLocation( Source source, File defaultLocation )
1259     {
1260         if ( source != null )
1261         {
1262             return source.getLocation();
1263         }
1264         return defaultLocation;
1265     }
1266 
1267     private MavenExecutionRequest populateRequest( CliRequest cliRequest )
1268     {
1269         return populateRequest( cliRequest, cliRequest.request );
1270     }
1271 
1272     @SuppressWarnings( "checkstyle:methodlength" )
1273     private MavenExecutionRequest populateRequest( CliRequest cliRequest, MavenExecutionRequest request )
1274     {
1275         CommandLine commandLine = cliRequest.commandLine;
1276         String workingDirectory = cliRequest.workingDirectory;
1277         boolean quiet = cliRequest.quiet;
1278         boolean showErrors = cliRequest.showErrors;
1279 
1280         String[] deprecatedOptions = { "up", "npu", "cpu", "npr" };
1281         for ( String deprecatedOption : deprecatedOptions )
1282         {
1283             if ( commandLine.hasOption( deprecatedOption ) )
1284             {
1285                 slf4jLogger.warn( "Command line option -" + deprecatedOption
1286                                       + " is deprecated and will be removed in future Maven versions." );
1287             }
1288         }
1289 
1290         // ----------------------------------------------------------------------
1291         // Now that we have everything that we need we will fire up plexus and
1292         // bring the maven component to life for use.
1293         // ----------------------------------------------------------------------
1294 
1295         if ( commandLine.hasOption( CLIManager.BATCH_MODE ) )
1296         {
1297             request.setInteractiveMode( false );
1298         }
1299 
1300         boolean noSnapshotUpdates = false;
1301         if ( commandLine.hasOption( CLIManager.SUPRESS_SNAPSHOT_UPDATES ) )
1302         {
1303             noSnapshotUpdates = true;
1304         }
1305 
1306         // ----------------------------------------------------------------------
1307         //
1308         // ----------------------------------------------------------------------
1309 
1310         List<String> goals = commandLine.getArgList();
1311 
1312         boolean recursive = true;
1313 
1314         // this is the default behavior.
1315         String reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST;
1316 
1317         if ( commandLine.hasOption( CLIManager.NON_RECURSIVE ) )
1318         {
1319             recursive = false;
1320         }
1321 
1322         if ( commandLine.hasOption( CLIManager.FAIL_FAST ) )
1323         {
1324             reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST;
1325         }
1326         else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) )
1327         {
1328             reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_AT_END;
1329         }
1330         else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) )
1331         {
1332             reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_NEVER;
1333         }
1334 
1335         if ( commandLine.hasOption( CLIManager.OFFLINE ) )
1336         {
1337             request.setOffline( true );
1338         }
1339 
1340         boolean updateSnapshots = false;
1341 
1342         if ( commandLine.hasOption( CLIManager.UPDATE_SNAPSHOTS ) )
1343         {
1344             updateSnapshots = true;
1345         }
1346 
1347         String globalChecksumPolicy = null;
1348 
1349         if ( commandLine.hasOption( CLIManager.CHECKSUM_FAILURE_POLICY ) )
1350         {
1351             globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
1352         }
1353         else if ( commandLine.hasOption( CLIManager.CHECKSUM_WARNING_POLICY ) )
1354         {
1355             globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_WARN;
1356         }
1357 
1358         File baseDirectory = new File( workingDirectory, "" ).getAbsoluteFile();
1359 
1360         // ----------------------------------------------------------------------
1361         // Profile Activation
1362         // ----------------------------------------------------------------------
1363 
1364         List<String> activeProfiles = new ArrayList<>();
1365 
1366         List<String> inactiveProfiles = new ArrayList<>();
1367 
1368         if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) )
1369         {
1370             String[] profileOptionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES );
1371             if ( profileOptionValues != null )
1372             {
1373                 for ( String profileOptionValue : profileOptionValues )
1374                 {
1375                     StringTokenizer profileTokens = new StringTokenizer( profileOptionValue, "," );
1376 
1377                     while ( profileTokens.hasMoreTokens() )
1378                     {
1379                         String profileAction = profileTokens.nextToken().trim();
1380 
1381                         if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) )
1382                         {
1383                             inactiveProfiles.add( profileAction.substring( 1 ) );
1384                         }
1385                         else if ( profileAction.startsWith( "+" ) )
1386                         {
1387                             activeProfiles.add( profileAction.substring( 1 ) );
1388                         }
1389                         else
1390                         {
1391                             activeProfiles.add( profileAction );
1392                         }
1393                     }
1394                 }
1395             }
1396         }
1397 
1398         TransferListener transferListener;
1399 
1400         if ( quiet )
1401         {
1402             transferListener = new QuietMavenTransferListener();
1403         }
1404         else if ( request.isInteractiveMode() && !cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
1405         {
1406             //
1407             // If we're logging to a file then we don't want the console transfer listener as it will spew
1408             // download progress all over the place
1409             //
1410             transferListener = getConsoleTransferListener( cliRequest.commandLine.hasOption( CLIManager.DEBUG ) );
1411         }
1412         else
1413         {
1414             transferListener = getBatchTransferListener();
1415         }
1416 
1417         ExecutionListener executionListener = new ExecutionEventLogger();
1418         if ( eventSpyDispatcher != null )
1419         {
1420             executionListener = eventSpyDispatcher.chainListener( executionListener );
1421         }
1422 
1423         String alternatePomFile = null;
1424         if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) )
1425         {
1426             alternatePomFile = commandLine.getOptionValue( CLIManager.ALTERNATE_POM_FILE );
1427         }
1428 
1429         request.setBaseDirectory( baseDirectory ).setGoals( goals ).setSystemProperties(
1430             cliRequest.systemProperties ).setUserProperties( cliRequest.userProperties ).setReactorFailureBehavior(
1431             reactorFailureBehaviour ) // default: fail fast
1432             .setRecursive( recursive ) // default: true
1433             .setShowErrors( showErrors ) // default: false
1434             .addActiveProfiles( activeProfiles ) // optional
1435             .addInactiveProfiles( inactiveProfiles ) // optional
1436             .setExecutionListener( executionListener ).setTransferListener(
1437             transferListener ) // default: batch mode which goes along with interactive
1438             .setUpdateSnapshots( updateSnapshots ) // default: false
1439             .setNoSnapshotUpdates( noSnapshotUpdates ) // default: false
1440             .setGlobalChecksumPolicy( globalChecksumPolicy ) // default: warn
1441             .setMultiModuleProjectDirectory( cliRequest.multiModuleProjectDirectory );
1442 
1443         if ( alternatePomFile != null )
1444         {
1445             File pom = resolveFile( new File( alternatePomFile ), workingDirectory );
1446             if ( pom.isDirectory() )
1447             {
1448                 pom = new File( pom, "pom.xml" );
1449             }
1450 
1451             request.setPom( pom );
1452         }
1453         else if ( modelProcessor != null )
1454         {
1455             File pom = modelProcessor.locatePom( baseDirectory );
1456 
1457             if ( pom.isFile() )
1458             {
1459                 request.setPom( pom );
1460             }
1461         }
1462 
1463         if ( ( request.getPom() != null ) && ( request.getPom().getParentFile() != null ) )
1464         {
1465             request.setBaseDirectory( request.getPom().getParentFile() );
1466         }
1467 
1468         if ( commandLine.hasOption( CLIManager.RESUME_FROM ) )
1469         {
1470             request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) );
1471         }
1472 
1473         if ( commandLine.hasOption( CLIManager.PROJECT_LIST ) )
1474         {
1475             String[] projectOptionValues = commandLine.getOptionValues( CLIManager.PROJECT_LIST );
1476 
1477             List<String> inclProjects = new ArrayList<>();
1478             List<String> exclProjects = new ArrayList<>();
1479 
1480             if ( projectOptionValues != null )
1481             {
1482                 for ( String projectOptionValue : projectOptionValues )
1483                 {
1484                     StringTokenizer projectTokens = new StringTokenizer( projectOptionValue, "," );
1485 
1486                     while ( projectTokens.hasMoreTokens() )
1487                     {
1488                         String projectAction = projectTokens.nextToken().trim();
1489 
1490                         if ( projectAction.startsWith( "-" ) || projectAction.startsWith( "!" ) )
1491                         {
1492                             exclProjects.add( projectAction.substring( 1 ) );
1493                         }
1494                         else if ( projectAction.startsWith( "+" ) )
1495                         {
1496                             inclProjects.add( projectAction.substring( 1 ) );
1497                         }
1498                         else
1499                         {
1500                             inclProjects.add( projectAction );
1501                         }
1502                     }
1503                 }
1504             }
1505 
1506             request.setSelectedProjects( inclProjects );
1507             request.setExcludedProjects( exclProjects );
1508         }
1509 
1510         if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && !commandLine.hasOption(
1511             CLIManager.ALSO_MAKE_DEPENDENTS ) )
1512         {
1513             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM );
1514         }
1515         else if ( !commandLine.hasOption( CLIManager.ALSO_MAKE ) && commandLine.hasOption(
1516             CLIManager.ALSO_MAKE_DEPENDENTS ) )
1517         {
1518             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM );
1519         }
1520         else if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && commandLine.hasOption(
1521             CLIManager.ALSO_MAKE_DEPENDENTS ) )
1522         {
1523             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_BOTH );
1524         }
1525 
1526         String localRepoProperty = request.getUserProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
1527 
1528         if ( localRepoProperty == null )
1529         {
1530             localRepoProperty = request.getSystemProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
1531         }
1532 
1533         if ( localRepoProperty != null )
1534         {
1535             request.setLocalRepositoryPath( localRepoProperty );
1536         }
1537 
1538         request.setCacheNotFound( true );
1539         request.setCacheTransferError( false );
1540 
1541         //
1542         // Builder, concurrency and parallelism
1543         //
1544         // We preserve the existing methods for builder selection which is to look for various inputs in the threading
1545         // configuration. We don't have an easy way to allow a pluggable builder to provide its own configuration
1546         // parameters but this is sufficient for now. Ultimately we want components like Builders to provide a way to
1547         // extend the command line to accept its own configuration parameters.
1548         //
1549         final String threadConfiguration = commandLine.hasOption( CLIManager.THREADS )
1550             ? commandLine.getOptionValue( CLIManager.THREADS )
1551             : request.getSystemProperties().getProperty(
1552                 MavenCli.THREADS_DEPRECATED ); // TODO Remove this setting. Note that the int-tests use it
1553 
1554         if ( threadConfiguration != null )
1555         {
1556             //
1557             // Default to the standard multithreaded builder
1558             //
1559             request.setBuilderId( "multithreaded" );
1560 
1561             if ( threadConfiguration.contains( "C" ) )
1562             {
1563                 request.setDegreeOfConcurrency( calculateDegreeOfConcurrencyWithCoreMultiplier( threadConfiguration ) );
1564             }
1565             else
1566             {
1567                 request.setDegreeOfConcurrency( Integer.valueOf( threadConfiguration ) );
1568             }
1569         }
1570 
1571         //
1572         // Allow the builder to be overridden by the user if requested. The builders are now pluggable.
1573         //
1574         if ( commandLine.hasOption( CLIManager.BUILDER ) )
1575         {
1576             request.setBuilderId( commandLine.getOptionValue( CLIManager.BUILDER ) );
1577         }
1578 
1579         return request;
1580     }
1581 
1582     int calculateDegreeOfConcurrencyWithCoreMultiplier( String threadConfiguration )
1583     {
1584         int procs = Runtime.getRuntime().availableProcessors();
1585         return (int) ( Float.valueOf( threadConfiguration.replace( "C", "" ) ) * procs );
1586     }
1587 
1588     static File resolveFile( File file, String workingDirectory )
1589     {
1590         if ( file == null )
1591         {
1592             return null;
1593         }
1594         else if ( file.isAbsolute() )
1595         {
1596             return file;
1597         }
1598         else if ( file.getPath().startsWith( File.separator ) )
1599         {
1600             // drive-relative Windows path
1601             return file.getAbsoluteFile();
1602         }
1603         else
1604         {
1605             return new File( workingDirectory, file.getPath() ).getAbsoluteFile();
1606         }
1607     }
1608 
1609     // ----------------------------------------------------------------------
1610     // System properties handling
1611     // ----------------------------------------------------------------------
1612 
1613     static void populateProperties( CommandLine commandLine, Properties systemProperties, Properties userProperties )
1614     {
1615         EnvironmentUtils.addEnvVars( systemProperties );
1616 
1617         // ----------------------------------------------------------------------
1618         // Options that are set on the command line become system properties
1619         // and therefore are set in the session properties. System properties
1620         // are most dominant.
1621         // ----------------------------------------------------------------------
1622 
1623         if ( commandLine.hasOption( CLIManager.SET_SYSTEM_PROPERTY ) )
1624         {
1625             String[] defStrs = commandLine.getOptionValues( CLIManager.SET_SYSTEM_PROPERTY );
1626             
1627             if ( defStrs != null )
1628             {
1629                 for ( String defStr : defStrs )
1630                 {
1631                     setCliProperty( defStr, userProperties );
1632                 }
1633             }
1634         }
1635 
1636         SystemProperties.addSystemProperties( systemProperties );
1637 
1638         // ----------------------------------------------------------------------
1639         // Properties containing info about the currently running version of Maven
1640         // These override any corresponding properties set on the command line
1641         // ----------------------------------------------------------------------
1642 
1643         Properties buildProperties = CLIReportingUtils.getBuildProperties();
1644 
1645         String mavenVersion = buildProperties.getProperty( CLIReportingUtils.BUILD_VERSION_PROPERTY );
1646         systemProperties.setProperty( "maven.version", mavenVersion );
1647 
1648         String mavenBuildVersion = CLIReportingUtils.createMavenVersionString( buildProperties );
1649         systemProperties.setProperty( "maven.build.version", mavenBuildVersion );
1650     }
1651 
1652     private static void setCliProperty( String property, Properties properties )
1653     {
1654         String name;
1655 
1656         String value;
1657 
1658         int i = property.indexOf( '=' );
1659 
1660         if ( i <= 0 )
1661         {
1662             name = property.trim();
1663 
1664             value = "true";
1665         }
1666         else
1667         {
1668             name = property.substring( 0, i ).trim();
1669 
1670             value = property.substring( i + 1 );
1671         }
1672 
1673         properties.setProperty( name, value );
1674 
1675         // ----------------------------------------------------------------------
1676         // I'm leaving the setting of system properties here as not to break
1677         // the SystemPropertyProfileActivator. This won't harm embedding. jvz.
1678         // ----------------------------------------------------------------------
1679 
1680         System.setProperty( name, value );
1681     }
1682 
1683     static class ExitException
1684         extends Exception
1685     {
1686         int exitCode;
1687 
1688         ExitException( int exitCode )
1689         {
1690             this.exitCode = exitCode;
1691         }
1692     }
1693 
1694     //
1695     // Customizations available via the CLI
1696     //
1697 
1698     protected TransferListener getConsoleTransferListener( boolean printResourceNames )
1699     {
1700         return new ConsoleMavenTransferListener( System.out, printResourceNames );
1701     }
1702 
1703     protected TransferListener getBatchTransferListener()
1704     {
1705         return new Slf4jMavenTransferListener();
1706     }
1707 
1708     protected void customizeContainer( PlexusContainer container )
1709     {
1710     }
1711 
1712     protected ModelProcessor createModelProcessor( PlexusContainer container )
1713         throws ComponentLookupException
1714     {
1715         return container.lookup( ModelProcessor.class );
1716     }
1717 }