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