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.File;
23  import java.io.FileNotFoundException;
24  import java.io.FileOutputStream;
25  import java.io.PrintStream;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.LinkedHashMap;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Properties;
32  import java.util.StringTokenizer;
33  
34  import org.apache.commons.cli.CommandLine;
35  import org.apache.commons.cli.ParseException;
36  import org.apache.commons.cli.UnrecognizedOptionException;
37  import org.apache.maven.BuildAbort;
38  import org.apache.maven.InternalErrorException;
39  import org.apache.maven.Maven;
40  import org.apache.maven.cli.event.DefaultEventSpyContext;
41  import org.apache.maven.cli.event.ExecutionEventLogger;
42  import org.apache.maven.cli.logging.Slf4jConfiguration;
43  import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
44  import org.apache.maven.cli.logging.Slf4jLoggerManager;
45  import org.apache.maven.cli.logging.Slf4jStdoutLogger;
46  import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
47  import org.apache.maven.cli.transfer.QuietMavenTransferListener;
48  import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
49  import org.apache.maven.eventspy.internal.EventSpyDispatcher;
50  import org.apache.maven.exception.DefaultExceptionHandler;
51  import org.apache.maven.exception.ExceptionHandler;
52  import org.apache.maven.exception.ExceptionSummary;
53  import org.apache.maven.execution.DefaultMavenExecutionRequest;
54  import org.apache.maven.execution.ExecutionListener;
55  import org.apache.maven.execution.MavenExecutionRequest;
56  import org.apache.maven.execution.MavenExecutionRequestPopulator;
57  import org.apache.maven.execution.MavenExecutionResult;
58  import org.apache.maven.lifecycle.LifecycleExecutionException;
59  import org.apache.maven.lifecycle.internal.LifecycleWeaveBuilder;
60  import org.apache.maven.model.building.ModelProcessor;
61  import org.apache.maven.project.MavenProject;
62  import org.apache.maven.properties.internal.EnvironmentUtils;
63  import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
64  import org.apache.maven.settings.building.SettingsBuilder;
65  import org.apache.maven.settings.building.SettingsBuildingRequest;
66  import org.apache.maven.settings.building.SettingsBuildingResult;
67  import org.apache.maven.settings.building.SettingsProblem;
68  import org.apache.maven.settings.building.SettingsSource;
69  import org.codehaus.plexus.ContainerConfiguration;
70  import org.codehaus.plexus.DefaultContainerConfiguration;
71  import org.codehaus.plexus.DefaultPlexusContainer;
72  import org.codehaus.plexus.PlexusConstants;
73  import org.codehaus.plexus.PlexusContainer;
74  import org.codehaus.plexus.classworlds.ClassWorld;
75  import org.codehaus.plexus.classworlds.realm.ClassRealm;
76  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
77  import org.codehaus.plexus.logging.LoggerManager;
78  import org.codehaus.plexus.util.StringUtils;
79  import org.eclipse.aether.transfer.TransferListener;
80  import org.slf4j.ILoggerFactory;
81  import org.slf4j.Logger;
82  import org.slf4j.LoggerFactory;
83  import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
84  import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
85  import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
86  import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
87  import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
88  
89  import com.google.inject.AbstractModule;
90  
91  // TODO: push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs
92  
93  /**
94   * @author Jason van Zyl
95   * @noinspection UseOfSystemOutOrSystemErr,ACCESS_STATIC_VIA_INSTANCE
96   */
97  public class MavenCli
98  {
99      public static final String LOCAL_REPO_PROPERTY = "maven.repo.local";
100 
101     public static final String THREADS_DEPRECATED = "maven.threads.experimental";
102 
103     public static final String userHome = System.getProperty( "user.home" );
104 
105     public static final File userMavenConfigurationHome = new File( userHome, ".m2" );
106 
107     public static final File DEFAULT_USER_SETTINGS_FILE = new File( userMavenConfigurationHome, "settings.xml" );
108 
109     public static final File DEFAULT_GLOBAL_SETTINGS_FILE =
110         new File( System.getProperty( "maven.home", System.getProperty( "user.dir", "" ) ), "conf/settings.xml" );
111 
112     public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File( userMavenConfigurationHome, "toolchains.xml" );
113 
114     private static final String EXT_CLASS_PATH = "maven.ext.class.path";
115 
116     private ClassWorld classWorld;
117 
118     private LoggerManager plexusLoggerManager;
119 
120     private ILoggerFactory slf4jLoggerFactory;
121     
122     private Logger slf4jLogger;
123     
124     private EventSpyDispatcher eventSpyDispatcher;
125 
126     private ModelProcessor modelProcessor;
127 
128     private Maven maven;
129 
130     private MavenExecutionRequestPopulator executionRequestPopulator;
131 
132     private SettingsBuilder settingsBuilder;
133 
134     private DefaultSecDispatcher dispatcher;
135 
136     public MavenCli()
137     {
138         this( null );
139     }
140 
141     // This supports painless invocation by the Verifier during embedded execution of the core ITs
142     public MavenCli( ClassWorld classWorld )
143     {
144         this.classWorld = classWorld;
145     }
146 
147     public static void main( String[] args )
148     {
149         int result = main( args, null );
150 
151         System.exit( result );
152     }
153 
154     /** @noinspection ConfusingMainMethod */
155     public static int main( String[] args, ClassWorld classWorld )
156     {
157         MavenCli cli = new MavenCli();
158         return cli.doMain( new CliRequest( args, classWorld ) );
159     }
160 
161     // TODO: need to externalize CliRequest
162     public static int doMain( String[] args, ClassWorld classWorld )
163     {
164         MavenCli cli = new MavenCli();
165         return cli.doMain( new CliRequest( args, classWorld ) );
166     }
167 
168     // This supports painless invocation by the Verifier during embedded execution of the core ITs
169     public int doMain( String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr )
170     {
171         PrintStream oldout = System.out;
172         PrintStream olderr = System.err;
173 
174         try
175         {
176             if ( stdout != null )
177             {
178                 System.setOut( stdout );
179             }
180             if ( stderr != null )
181             {
182                 System.setErr( stderr );
183             }
184 
185             CliRequest cliRequest = new CliRequest( args, classWorld );
186             cliRequest.workingDirectory = workingDirectory;
187 
188             return doMain( cliRequest );
189         }
190         finally
191         {
192             System.setOut( oldout );
193             System.setErr( olderr );
194         }
195     }
196 
197     // TODO: need to externalize CliRequest
198     public int doMain( CliRequest cliRequest )
199     {
200         PlexusContainer localContainer = null;
201         try
202         {
203             initialize( cliRequest );
204             cli( cliRequest );
205             logging( cliRequest );
206             version( cliRequest );
207             properties( cliRequest );
208             localContainer = container( cliRequest );
209             commands( cliRequest );
210             settings( cliRequest );
211             populateRequest( cliRequest );
212             encryption( cliRequest );
213             repository( cliRequest );
214             return execute( cliRequest );
215         }
216         catch ( ExitException e )
217         {
218             return e.exitCode;
219         }
220         catch ( UnrecognizedOptionException e )
221         {
222             // pure user error, suppress stack trace
223             return 1;
224         }
225         catch ( BuildAbort e )
226         {
227             CLIReportingUtils.showError( slf4jLogger, "ABORTED", e, cliRequest.showErrors );
228 
229             return 2;
230         }
231         catch ( Exception e )
232         {
233             CLIReportingUtils.showError( slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors );
234 
235             return 1;
236         }
237         finally
238         {
239             if ( localContainer != null )
240             {
241                 localContainer.dispose();
242             }
243         }
244     }
245 
246     private void initialize( CliRequest cliRequest )
247     {
248         if ( cliRequest.workingDirectory == null )
249         {
250             cliRequest.workingDirectory = System.getProperty( "user.dir" );
251         }
252 
253         //
254         // Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative
255         // Windows paths.
256         //
257         String mavenHome = System.getProperty( "maven.home" );
258 
259         if ( mavenHome != null )
260         {
261             System.setProperty( "maven.home", new File( mavenHome ).getAbsolutePath() );
262         }
263     }
264 
265     private void cli( CliRequest cliRequest )
266         throws Exception
267     {
268         //
269         // Parsing errors can happen during the processing of the arguments and we prefer not having to check if the logger is null
270         // and construct this so we can use an SLF4J logger everywhere.
271         //
272         slf4jLogger = new Slf4jStdoutLogger();
273 
274         CLIManager cliManager = new CLIManager();
275 
276         try
277         {
278             cliRequest.commandLine = cliManager.parse( cliRequest.args );
279         }
280         catch ( ParseException e )
281         {
282             System.err.println( "Unable to parse command line options: " + e.getMessage() );
283             cliManager.displayHelp( System.out );
284             throw e;
285         }
286 
287         if ( cliRequest.commandLine.hasOption( CLIManager.HELP ) )
288         {
289             cliManager.displayHelp( System.out );
290             throw new ExitException( 0 );
291         }
292 
293         if ( cliRequest.commandLine.hasOption( CLIManager.VERSION ) )
294         {
295             System.out.println( CLIReportingUtils.showVersion() );
296             throw new ExitException( 0 );
297         }
298     }    
299 
300     /**
301      * configure logging
302      */
303     private void logging( CliRequest cliRequest )
304     {
305         cliRequest.debug = cliRequest.commandLine.hasOption( CLIManager.DEBUG );
306         cliRequest.quiet = !cliRequest.debug && cliRequest.commandLine.hasOption( CLIManager.QUIET );
307         cliRequest.showErrors = cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.ERRORS );
308 
309         slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
310         Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration( slf4jLoggerFactory );
311 
312         if ( cliRequest.debug )
313         {
314             cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_DEBUG );
315             slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.DEBUG );
316         }
317         else if ( cliRequest.quiet )
318         {
319             cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_ERROR );
320             slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.ERROR );
321         }
322         else
323         {
324             cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_INFO );
325             slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.INFO );
326         }
327 
328         if ( cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
329         {
330             File logFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.LOG_FILE ) );
331             logFile = resolveFile( logFile, cliRequest.workingDirectory );
332 
333             // redirect stdout and stderr to file
334             try
335             {
336                 PrintStream ps = new PrintStream( new FileOutputStream( logFile ) );
337                 System.setOut( ps );
338                 System.setErr( ps );
339             }
340             catch ( FileNotFoundException e )
341             {
342                 //
343                 // Ignore
344                 //
345             }
346         }
347 
348         slf4jConfiguration.activate();
349 
350         plexusLoggerManager = new Slf4jLoggerManager();
351         slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
352     }
353 
354     private void version( CliRequest cliRequest )
355     {
356         if ( cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.SHOW_VERSION ) )
357         {
358             System.out.println( CLIReportingUtils.showVersion() );
359         }
360     }
361 
362     private void commands( CliRequest cliRequest )
363     {
364         if ( cliRequest.showErrors )
365         {
366             slf4jLogger.info( "Error stacktraces are turned on." );
367         }
368 
369         if ( MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
370         {
371             slf4jLogger.info( "Disabling strict checksum verification on all artifact downloads." );
372         }
373         else if ( MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
374         {
375             slf4jLogger.info( "Enabling strict checksum verification on all artifact downloads." );
376         }
377     }
378 
379     private void properties( CliRequest cliRequest )
380     {
381         populateProperties( cliRequest.commandLine, cliRequest.systemProperties, cliRequest.userProperties );
382     }
383 
384     private PlexusContainer container( CliRequest cliRequest )
385         throws Exception
386     {
387         if ( cliRequest.classWorld == null )
388         {
389             cliRequest.classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
390         }
391 
392         DefaultPlexusContainer container = null;
393 
394         ContainerConfiguration cc = new DefaultContainerConfiguration()
395             .setClassWorld( cliRequest.classWorld )
396             .setRealm( setupContainerRealm( cliRequest ) )
397             .setClassPathScanning( PlexusConstants.SCANNING_INDEX )
398             .setAutoWiring( true )
399             .setName( "maven" );
400 
401         container = new DefaultPlexusContainer( cc, new AbstractModule()
402         {
403             protected void configure()
404             {
405                 bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
406             }
407         } );
408 
409         // NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups
410         container.setLookupRealm( null );
411 
412         container.setLoggerManager( plexusLoggerManager );
413 
414         customizeContainer( container );
415 
416         container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
417 
418         Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
419 
420         eventSpyDispatcher = container.lookup( EventSpyDispatcher.class );
421 
422         DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext();
423         Map<String, Object> data = eventSpyContext.getData();
424         data.put( "plexus", container );
425         data.put( "workingDirectory", cliRequest.workingDirectory );
426         data.put( "systemProperties", cliRequest.systemProperties );
427         data.put( "userProperties", cliRequest.userProperties );
428         data.put( "versionProperties", CLIReportingUtils.getBuildProperties() );
429         eventSpyDispatcher.init( eventSpyContext );
430 
431         // refresh logger in case container got customized by spy
432         slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
433 
434         maven = container.lookup( Maven.class );
435 
436         executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
437 
438         modelProcessor = createModelProcessor( container );
439 
440         settingsBuilder = container.lookup( SettingsBuilder.class );
441 
442         dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" );
443 
444         return container;
445     }
446 
447     private ClassRealm setupContainerRealm( CliRequest cliRequest )
448         throws Exception
449     {
450         ClassRealm containerRealm = null;
451 
452         String extClassPath = cliRequest.userProperties.getProperty( EXT_CLASS_PATH );
453         if ( extClassPath == null )
454         {
455             extClassPath = cliRequest.systemProperties.getProperty( EXT_CLASS_PATH );
456         }
457 
458         if ( StringUtils.isNotEmpty( extClassPath ) )
459         {
460             String[] jars = StringUtils.split( extClassPath, File.pathSeparator );
461 
462             if ( jars.length > 0 )
463             {
464                 ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" );
465                 if ( coreRealm == null )
466                 {
467                     coreRealm = (ClassRealm) cliRequest.classWorld.getRealms().iterator().next();
468                 }
469 
470                 ClassRealm extRealm = cliRequest.classWorld.newRealm( "maven.ext", null );
471 
472                 slf4jLogger.debug( "Populating class realm " + extRealm.getId() );
473 
474                 for ( String jar : jars )
475                 {
476                     File file = resolveFile( new File( jar ), cliRequest.workingDirectory );
477 
478                     slf4jLogger.debug( "  Included " + file );
479 
480                     extRealm.addURL( file.toURI().toURL() );
481                 }
482 
483                 extRealm.setParentRealm( coreRealm );
484 
485                 containerRealm = extRealm;
486             }
487         }
488 
489         return containerRealm;
490     }
491 
492     //
493     // This should probably be a separate tool and not be baked into Maven.
494     //
495     private void encryption( CliRequest cliRequest )
496         throws Exception
497     {
498         if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_MASTER_PASSWORD ) )
499         {
500             String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_MASTER_PASSWORD );
501 
502             DefaultPlexusCipher cipher = new DefaultPlexusCipher();
503 
504             System.out.println( cipher.encryptAndDecorate( passwd, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) );
505 
506             throw new ExitException( 0 );
507         }
508         else if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_PASSWORD ) )
509         {
510             String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_PASSWORD );
511 
512             String configurationFile = dispatcher.getConfigurationFile();
513 
514             if ( configurationFile.startsWith( "~" ) )
515             {
516                 configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
517             }
518 
519             String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
520 
521             String master = null;
522 
523             SettingsSecurity sec = SecUtil.read( file, true );
524             if ( sec != null )
525             {
526                 master = sec.getMaster();
527             }
528 
529             if ( master == null )
530             {
531                 throw new IllegalStateException( "Master password is not set in the setting security file: " + file );
532             }
533 
534             DefaultPlexusCipher cipher = new DefaultPlexusCipher();
535             String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
536             System.out.println( cipher.encryptAndDecorate( passwd, masterPasswd ) );
537 
538             throw new ExitException( 0 );
539         }
540     }
541 
542     private void repository( CliRequest cliRequest )
543         throws Exception
544     {
545         if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_LOCAL_REPOSITORY ) || Boolean.getBoolean( "maven.legacyLocalRepo" ) )
546         {
547            cliRequest.request.setUseLegacyLocalRepository( true );
548         }
549     }
550 
551     private int execute( CliRequest cliRequest )
552     {
553         eventSpyDispatcher.onEvent( cliRequest.request );
554 
555         MavenExecutionResult result = maven.execute( cliRequest.request );
556 
557         eventSpyDispatcher.onEvent( result );
558 
559         eventSpyDispatcher.close();
560 
561         if ( result.hasExceptions() )
562         {
563             ExceptionHandler handler = new DefaultExceptionHandler();
564 
565             Map<String, String> references = new LinkedHashMap<String, String>();
566 
567             MavenProject project = null;
568 
569             for ( Throwable exception : result.getExceptions() )
570             {
571                 ExceptionSummary summary = handler.handleException( exception );
572 
573                 logSummary( summary, references, "", cliRequest.showErrors );
574 
575                 if ( project == null && exception instanceof LifecycleExecutionException )
576                 {
577                     project = ( (LifecycleExecutionException) exception ).getProject();
578                 }
579             }
580 
581             slf4jLogger.error( "" );
582 
583             if ( !cliRequest.showErrors )
584             {
585                 slf4jLogger.error( "To see the full stack trace of the errors, re-run Maven with the -e switch." );
586             }
587             if ( !slf4jLogger.isDebugEnabled() )
588             {
589                 slf4jLogger.error( "Re-run Maven using the -X switch to enable full debug logging." );
590             }
591 
592             if ( !references.isEmpty() )
593             {
594                 slf4jLogger.error( "" );
595                 slf4jLogger.error( "For more information about the errors and possible solutions"
596                               + ", please read the following articles:" );
597 
598                 for ( Map.Entry<String, String> entry : references.entrySet() )
599                 {
600                     slf4jLogger.error( entry.getValue() + " " + entry.getKey() );
601                 }
602             }
603 
604             if ( project != null && !project.equals( result.getTopologicallySortedProjects().get( 0 ) ) )
605             {
606                 slf4jLogger.error( "" );
607                 slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
608                 slf4jLogger.error( "  mvn <goals> -rf :" + project.getArtifactId() );
609             }
610 
611             if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) )
612             {
613                 slf4jLogger.info( "Build failures were ignored." );
614 
615                 return 0;
616             }
617             else
618             {
619                 return 1;
620             }
621         }
622         else
623         {
624             return 0;
625         }
626     }
627 
628     private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent,
629                              boolean showErrors )
630     {
631         String referenceKey = "";
632 
633         if ( StringUtils.isNotEmpty( summary.getReference() ) )
634         {
635             referenceKey = references.get( summary.getReference() );
636             if ( referenceKey == null )
637             {
638                 referenceKey = "[Help " + ( references.size() + 1 ) + "]";
639                 references.put( summary.getReference(), referenceKey );
640             }
641         }
642 
643         String msg = summary.getMessage();
644 
645         if ( StringUtils.isNotEmpty( referenceKey ) )
646         {
647             if ( msg.indexOf( '\n' ) < 0 )
648             {
649                 msg += " -> " + referenceKey;
650             }
651             else
652             {
653                 msg += "\n-> " + referenceKey;
654             }
655         }
656 
657         String[] lines = msg.split( "(\r\n)|(\r)|(\n)" );
658 
659         for ( int i = 0; i < lines.length; i++ )
660         {
661             String line = indent + lines[i].trim();
662 
663             if ( i == lines.length - 1 && ( showErrors || ( summary.getException() instanceof InternalErrorException ) ) )
664             {
665                 slf4jLogger.error( line, summary.getException() );
666             }
667             else
668             {
669                 slf4jLogger.error( line );
670             }
671         }
672 
673         indent += "  ";
674 
675         for ( ExceptionSummary child : summary.getChildren() )
676         {
677             logSummary( child, references, indent, showErrors );
678         }
679     }
680 
681     private void settings( CliRequest cliRequest )
682         throws Exception
683     {
684         File userSettingsFile;
685 
686         if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_SETTINGS ) )
687         {
688             userSettingsFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_USER_SETTINGS ) );
689             userSettingsFile = resolveFile( userSettingsFile, cliRequest.workingDirectory );
690 
691             if ( !userSettingsFile.isFile() )
692             {
693                 throw new FileNotFoundException( "The specified user settings file does not exist: "
694                     + userSettingsFile );
695             }
696         }
697         else
698         {
699             userSettingsFile = DEFAULT_USER_SETTINGS_FILE;
700         }
701 
702         File globalSettingsFile;
703 
704         if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_SETTINGS ) )
705         {
706             globalSettingsFile =
707                 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_SETTINGS ) );
708             globalSettingsFile = resolveFile( globalSettingsFile, cliRequest.workingDirectory );
709 
710             if ( !globalSettingsFile.isFile() )
711             {
712                 throw new FileNotFoundException( "The specified global settings file does not exist: "
713                     + globalSettingsFile );
714             }
715         }
716         else
717         {
718             globalSettingsFile = DEFAULT_GLOBAL_SETTINGS_FILE;
719         }
720 
721         cliRequest.request.setGlobalSettingsFile( globalSettingsFile );
722         cliRequest.request.setUserSettingsFile( userSettingsFile );
723 
724         SettingsBuildingRequest settingsRequest = new DefaultSettingsBuildingRequest();
725         settingsRequest.setGlobalSettingsFile( globalSettingsFile );
726         settingsRequest.setUserSettingsFile( userSettingsFile );
727         settingsRequest.setSystemProperties( cliRequest.systemProperties );
728         settingsRequest.setUserProperties( cliRequest.userProperties );
729 
730         eventSpyDispatcher.onEvent( settingsRequest );
731 
732         slf4jLogger.debug( "Reading global settings from "
733             + getSettingsLocation( settingsRequest.getGlobalSettingsSource(), settingsRequest.getGlobalSettingsFile() ) );
734         slf4jLogger.debug( "Reading user settings from "
735             + getSettingsLocation( settingsRequest.getUserSettingsSource(), settingsRequest.getUserSettingsFile() ) );
736 
737         SettingsBuildingResult settingsResult = settingsBuilder.build( settingsRequest );
738 
739         eventSpyDispatcher.onEvent( settingsResult );
740 
741         executionRequestPopulator.populateFromSettings( cliRequest.request, settingsResult.getEffectiveSettings() );
742 
743         if ( !settingsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled() )
744         {
745             slf4jLogger.warn( "" );
746             slf4jLogger.warn( "Some problems were encountered while building the effective settings" );
747 
748             for ( SettingsProblem problem : settingsResult.getProblems() )
749             {
750                 slf4jLogger.warn( problem.getMessage() + " @ " + problem.getLocation() );
751             }
752 
753             slf4jLogger.warn( "" );
754         }
755     }
756 
757     private Object getSettingsLocation( SettingsSource source, File file )
758     {
759         if ( source != null )
760         {
761             return source.getLocation();
762         }
763         return file;
764     }
765 
766     private MavenExecutionRequest populateRequest( CliRequest cliRequest )
767     {
768         MavenExecutionRequest request = cliRequest.request;
769         CommandLine commandLine = cliRequest.commandLine;
770         String workingDirectory = cliRequest.workingDirectory;
771         boolean quiet = cliRequest.quiet;
772         boolean showErrors = cliRequest.showErrors;
773 
774         String[] deprecatedOptions = { "up", "npu", "cpu", "npr" };
775         for ( String deprecatedOption : deprecatedOptions )
776         {
777             if ( commandLine.hasOption( deprecatedOption ) )
778             {
779                 slf4jLogger.warn( "Command line option -" + deprecatedOption
780                     + " is deprecated and will be removed in future Maven versions." );
781             }
782         }
783 
784         // ----------------------------------------------------------------------
785         // Now that we have everything that we need we will fire up plexus and
786         // bring the maven component to life for use.
787         // ----------------------------------------------------------------------
788 
789         if ( commandLine.hasOption( CLIManager.BATCH_MODE ) )
790         {
791             request.setInteractiveMode( false );
792         }
793 
794         boolean noSnapshotUpdates = false;
795         if ( commandLine.hasOption( CLIManager.SUPRESS_SNAPSHOT_UPDATES ) )
796         {
797             noSnapshotUpdates = true;
798         }
799 
800         // ----------------------------------------------------------------------
801         //
802         // ----------------------------------------------------------------------
803 
804         @SuppressWarnings( "unchecked" )
805         List<String> goals = commandLine.getArgList();
806 
807         boolean recursive = true;
808 
809         // this is the default behavior.
810         String reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST;
811 
812         if ( commandLine.hasOption( CLIManager.NON_RECURSIVE ) )
813         {
814             recursive = false;
815         }
816 
817         if ( commandLine.hasOption( CLIManager.FAIL_FAST ) )
818         {
819             reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST;
820         }
821         else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) )
822         {
823             reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_AT_END;
824         }
825         else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) )
826         {
827             reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_NEVER;
828         }
829 
830         if ( commandLine.hasOption( CLIManager.OFFLINE ) )
831         {
832             request.setOffline( true );
833         }
834 
835         boolean updateSnapshots = false;
836 
837         if ( commandLine.hasOption( CLIManager.UPDATE_SNAPSHOTS ) )
838         {
839             updateSnapshots = true;
840         }
841 
842         String globalChecksumPolicy = null;
843 
844         if ( commandLine.hasOption( CLIManager.CHECKSUM_FAILURE_POLICY ) )
845         {
846             globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
847         }
848         else if ( commandLine.hasOption( CLIManager.CHECKSUM_WARNING_POLICY ) )
849         {
850             globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_WARN;
851         }
852 
853         File baseDirectory = new File( workingDirectory, "" ).getAbsoluteFile();
854 
855         // ----------------------------------------------------------------------
856         // Profile Activation
857         // ----------------------------------------------------------------------
858 
859         List<String> activeProfiles = new ArrayList<String>();
860 
861         List<String> inactiveProfiles = new ArrayList<String>();
862 
863         if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) )
864         {
865             String[] profileOptionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES );
866             if ( profileOptionValues != null )
867             {
868                 for ( String profileOptionValue : profileOptionValues )
869                 {
870                     StringTokenizer profileTokens = new StringTokenizer( profileOptionValue, "," );
871 
872                     while ( profileTokens.hasMoreTokens() )
873                     {
874                         String profileAction = profileTokens.nextToken().trim();
875 
876                         if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) )
877                         {
878                             inactiveProfiles.add( profileAction.substring( 1 ) );
879                         }
880                         else if ( profileAction.startsWith( "+" ) )
881                         {
882                             activeProfiles.add( profileAction.substring( 1 ) );
883                         }
884                         else
885                         {
886                             activeProfiles.add( profileAction );
887                         }
888                     }
889                 }
890             }
891         }
892 
893         TransferListener transferListener;
894 
895         if ( quiet )
896         {
897             transferListener = new QuietMavenTransferListener();
898         }        
899         else if ( request.isInteractiveMode() && !cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
900         {
901             //
902             // If we're logging to a file then we don't want the console transfer listener as it will spew
903             // download progress all over the place
904             //
905             transferListener = getConsoleTransferListener();
906         }
907         else
908         {
909             transferListener = getBatchTransferListener();
910         }
911 
912         ExecutionListener executionListener = new ExecutionEventLogger();
913         executionListener = eventSpyDispatcher.chainListener( executionListener );
914 
915         String alternatePomFile = null;
916         if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) )
917         {
918             alternatePomFile = commandLine.getOptionValue( CLIManager.ALTERNATE_POM_FILE );
919         }
920 
921         File userToolchainsFile;
922         if ( commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) )
923         {
924             userToolchainsFile = new File( commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) );
925             userToolchainsFile = resolveFile( userToolchainsFile, workingDirectory );
926         }
927         else
928         {
929             userToolchainsFile = MavenCli.DEFAULT_USER_TOOLCHAINS_FILE;
930         }
931 
932         request.setBaseDirectory( baseDirectory ).setGoals( goals )
933             .setSystemProperties( cliRequest.systemProperties )
934             .setUserProperties( cliRequest.userProperties )
935             .setReactorFailureBehavior( reactorFailureBehaviour ) // default: fail fast
936             .setRecursive( recursive ) // default: true
937             .setShowErrors( showErrors ) // default: false
938             .addActiveProfiles( activeProfiles ) // optional
939             .addInactiveProfiles( inactiveProfiles ) // optional
940             .setExecutionListener( executionListener )
941             .setTransferListener( transferListener ) // default: batch mode which goes along with interactive
942             .setUpdateSnapshots( updateSnapshots ) // default: false
943             .setNoSnapshotUpdates( noSnapshotUpdates ) // default: false
944             .setGlobalChecksumPolicy( globalChecksumPolicy ) // default: warn
945             .setUserToolchainsFile( userToolchainsFile );
946 
947         if ( alternatePomFile != null )
948         {
949             File pom = resolveFile( new File( alternatePomFile ), workingDirectory );
950             if ( pom.isDirectory() )
951             {
952                 pom = new File( pom, "pom.xml" );
953             }
954 
955             request.setPom( pom );
956         }
957         else
958         {
959             File pom = modelProcessor.locatePom( baseDirectory );
960 
961             if ( pom.isFile() )
962             {
963                 request.setPom( pom );
964             }
965         }
966 
967         if ( ( request.getPom() != null ) && ( request.getPom().getParentFile() != null ) )
968         {
969             request.setBaseDirectory( request.getPom().getParentFile() );
970         }
971 
972         if ( commandLine.hasOption( CLIManager.RESUME_FROM ) )
973         {
974             request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) );
975         }
976 
977         if ( commandLine.hasOption( CLIManager.PROJECT_LIST ) )
978         {
979             String[] values = commandLine.getOptionValues( CLIManager.PROJECT_LIST );
980             List<String> projects = new ArrayList<String>();
981             for ( String value : values )
982             {
983                 String[] tmp = StringUtils.split( value, "," );
984                 projects.addAll( Arrays.asList( tmp ) );
985             }
986             request.setSelectedProjects( projects );
987         }
988 
989         if ( commandLine.hasOption( CLIManager.ALSO_MAKE )
990                         && !commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
991         {
992             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM );
993         }
994         else if ( !commandLine.hasOption( CLIManager.ALSO_MAKE )
995                         && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
996         {
997             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM );
998         }
999         else if ( commandLine.hasOption( CLIManager.ALSO_MAKE )
1000                         && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
1001         {
1002             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_BOTH );
1003         }
1004 
1005         String localRepoProperty = request.getUserProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
1006 
1007         if ( localRepoProperty == null )
1008         {
1009             localRepoProperty = request.getSystemProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
1010         }
1011 
1012         if ( localRepoProperty != null )
1013         {
1014             request.setLocalRepositoryPath( localRepoProperty );
1015         }
1016 
1017         final String threadConfiguration = commandLine.hasOption( CLIManager.THREADS )
1018             ? commandLine.getOptionValue( CLIManager.THREADS )
1019             : request.getSystemProperties().getProperty(
1020                 MavenCli.THREADS_DEPRECATED ); // TODO: Remove this setting. Note that the int-tests use it
1021 
1022         if ( threadConfiguration != null )
1023         {
1024             request.setPerCoreThreadCount( threadConfiguration.contains( "C" ) );
1025             if ( threadConfiguration.contains( "W" ) )
1026             {
1027                 LifecycleWeaveBuilder.setWeaveMode( request.getUserProperties() );
1028             }
1029             request.setThreadCount( threadConfiguration.replace( "C", "" ).replace( "W", "" ).replace( "auto", "" ) );
1030         }
1031 
1032         request.setCacheNotFound( true );
1033         request.setCacheTransferError( false );
1034 
1035         return request;
1036     }
1037 
1038     static File resolveFile( File file, String workingDirectory )
1039     {
1040         if ( file == null )
1041         {
1042             return null;
1043         }
1044         else if ( file.isAbsolute() )
1045         {
1046             return file;
1047         }
1048         else if ( file.getPath().startsWith( File.separator ) )
1049         {
1050             // drive-relative Windows path
1051             return file.getAbsoluteFile();
1052         }
1053         else
1054         {
1055             return new File( workingDirectory, file.getPath() ).getAbsoluteFile();
1056         }
1057     }
1058 
1059     // ----------------------------------------------------------------------
1060     // System properties handling
1061     // ----------------------------------------------------------------------
1062 
1063     static void populateProperties( CommandLine commandLine, Properties systemProperties, Properties userProperties )
1064     {
1065         EnvironmentUtils.addEnvVars( systemProperties );
1066 
1067         // ----------------------------------------------------------------------
1068         // Options that are set on the command line become system properties
1069         // and therefore are set in the session properties. System properties
1070         // are most dominant.
1071         // ----------------------------------------------------------------------
1072 
1073         if ( commandLine.hasOption( CLIManager.SET_SYSTEM_PROPERTY ) )
1074         {
1075             String[] defStrs = commandLine.getOptionValues( CLIManager.SET_SYSTEM_PROPERTY );
1076 
1077             if ( defStrs != null )
1078             {
1079                 for ( String defStr : defStrs )
1080                 {
1081                     setCliProperty( defStr, userProperties );
1082                 }
1083             }
1084         }
1085 
1086         systemProperties.putAll( System.getProperties() );
1087         
1088         // ----------------------------------------------------------------------
1089         // Properties containing info about the currently running version of Maven
1090         // These override any corresponding properties set on the command line
1091         // ----------------------------------------------------------------------
1092 
1093         Properties buildProperties = CLIReportingUtils.getBuildProperties();
1094 
1095         String mavenVersion = buildProperties.getProperty( CLIReportingUtils.BUILD_VERSION_PROPERTY );
1096         systemProperties.setProperty( "maven.version", mavenVersion );
1097 
1098         String mavenBuildVersion = CLIReportingUtils.createMavenVersionString( buildProperties );
1099         systemProperties.setProperty( "maven.build.version", mavenBuildVersion );
1100     }
1101 
1102     private static void setCliProperty( String property, Properties properties )
1103     {
1104         String name;
1105 
1106         String value;
1107 
1108         int i = property.indexOf( "=" );
1109 
1110         if ( i <= 0 )
1111         {
1112             name = property.trim();
1113 
1114             value = "true";
1115         }
1116         else
1117         {
1118             name = property.substring( 0, i ).trim();
1119 
1120             value = property.substring( i + 1 );
1121         }
1122 
1123         properties.setProperty( name, value );
1124 
1125         // ----------------------------------------------------------------------
1126         // I'm leaving the setting of system properties here as not to break
1127         // the SystemPropertyProfileActivator. This won't harm embedding. jvz.
1128         // ----------------------------------------------------------------------
1129 
1130         System.setProperty( name, value );
1131     }
1132 
1133     static class CliRequest
1134     {
1135         String[] args;
1136         CommandLine commandLine;
1137         ClassWorld classWorld;
1138         String workingDirectory;
1139         boolean debug;
1140         boolean quiet;
1141         boolean showErrors = true;
1142         Properties userProperties = new Properties();
1143         Properties systemProperties = new Properties();
1144         MavenExecutionRequest request;
1145 
1146         CliRequest( String[] args, ClassWorld classWorld )
1147         {
1148             this.args = args;
1149             this.classWorld = classWorld;
1150             this.request = new DefaultMavenExecutionRequest();
1151         }
1152     }
1153 
1154     static class ExitException
1155         extends Exception
1156     {
1157 
1158         public int exitCode;
1159 
1160         public ExitException( int exitCode )
1161         {
1162             this.exitCode = exitCode;
1163         }
1164 
1165     }
1166     
1167     //
1168     // Customizations available via the CLI
1169     //
1170     
1171     protected TransferListener getConsoleTransferListener() 
1172     {
1173         return new ConsoleMavenTransferListener( System.out );
1174     }
1175     
1176     protected TransferListener getBatchTransferListener()
1177     {
1178         return new Slf4jMavenTransferListener();
1179     }
1180     
1181     protected void customizeContainer( PlexusContainer container )
1182     {
1183     }
1184 
1185     protected ModelProcessor createModelProcessor( PlexusContainer container )
1186         throws ComponentLookupException
1187     {
1188         return container.lookup( ModelProcessor.class );
1189     }        
1190 }