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