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             // NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups
378             container.setLookupRealm( null );
379 
380             container.setLoggerManager( new MavenLoggerManager( logger ) );
381 
382             customizeContainer( container );
383 
384             if ( cliRequest.classWorld == classWorld )
385             {
386                 this.container = container;
387             }
388         }
389 
390         container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
391 
392         Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
393 
394         eventSpyDispatcher = container.lookup( EventSpyDispatcher.class );
395 
396         DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext();
397         Map<String, Object> data = eventSpyContext.getData();
398         data.put( "plexus", container );
399         data.put( "workingDirectory", cliRequest.workingDirectory );
400         data.put( "systemProperties", cliRequest.systemProperties );
401         data.put( "userProperties", cliRequest.userProperties );
402         data.put( "versionProperties", CLIReportingUtils.getBuildProperties() );
403         eventSpyDispatcher.init( eventSpyContext );
404 
405         // refresh logger in case container got customized by spy
406         logger = container.getLoggerManager().getLoggerForComponent( MavenCli.class.getName(), null );
407 
408         maven = container.lookup( Maven.class );
409 
410         executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
411 
412         modelProcessor = createModelProcessor( container );
413 
414         settingsBuilder = container.lookup( SettingsBuilder.class );
415 
416         dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" );
417     }
418 
419     private PrintStreamLogger setupLogger( CliRequest cliRequest )
420     {
421         PrintStreamLogger logger = new PrintStreamLogger( new PrintStreamLogger.Provider()
422         {
423             public PrintStream getStream()
424             {
425                 return System.out;
426             }
427         } );
428 
429         logger.setThreshold( cliRequest.request.getLoggingLevel() );
430 
431         return logger;
432     }
433 
434     private ClassRealm setupContainerRealm( CliRequest cliRequest )
435         throws Exception
436     {
437         ClassRealm containerRealm = null;
438 
439         String extClassPath = cliRequest.userProperties.getProperty( EXT_CLASS_PATH );
440         if ( extClassPath == null )
441         {
442             extClassPath = cliRequest.systemProperties.getProperty( EXT_CLASS_PATH );
443         }
444 
445         if ( StringUtils.isNotEmpty( extClassPath ) )
446         {
447             String[] jars = StringUtils.split( extClassPath, File.pathSeparator );
448 
449             if ( jars.length > 0 )
450             {
451                 ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" );
452                 if ( coreRealm == null )
453                 {
454                     coreRealm = (ClassRealm) cliRequest.classWorld.getRealms().iterator().next();
455                 }
456 
457                 ClassRealm extRealm = cliRequest.classWorld.newRealm( "maven.ext", null );
458 
459                 logger.debug( "Populating class realm " + extRealm.getId() );
460 
461                 for ( String jar : jars )
462                 {
463                     File file = resolveFile( new File( jar ), cliRequest.workingDirectory );
464 
465                     logger.debug( "  Included " + file );
466 
467                     extRealm.addURL( file.toURI().toURL() );
468                 }
469 
470                 extRealm.setParentRealm( coreRealm );
471 
472                 containerRealm = extRealm;
473             }
474         }
475 
476         return containerRealm;
477     }
478 
479     protected void customizeContainer( PlexusContainer container )
480     {
481     }
482 
483     //
484     // This should probably be a separate tool and not be baked into Maven.
485     //
486     private void encryption( CliRequest cliRequest )
487         throws Exception
488     {
489         if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_MASTER_PASSWORD ) )
490         {
491             String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_MASTER_PASSWORD );
492 
493             DefaultPlexusCipher cipher = new DefaultPlexusCipher();
494 
495             System.out.println( cipher.encryptAndDecorate( passwd, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) );
496 
497             throw new ExitException( 0 );
498         }
499         else if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_PASSWORD ) )
500         {
501             String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_PASSWORD );
502 
503             String configurationFile = dispatcher.getConfigurationFile();
504 
505             if ( configurationFile.startsWith( "~" ) )
506             {
507                 configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
508             }
509 
510             String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
511 
512             String master = null;
513 
514             SettingsSecurity sec = SecUtil.read( file, true );
515             if ( sec != null )
516             {
517                 master = sec.getMaster();
518             }
519 
520             if ( master == null )
521             {
522                 throw new IllegalStateException( "Master password is not set in the setting security file: " + file );
523             }
524 
525             DefaultPlexusCipher cipher = new DefaultPlexusCipher();
526             String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
527             System.out.println( cipher.encryptAndDecorate( passwd, masterPasswd ) );
528 
529             throw new ExitException( 0 );
530         }
531     }
532 
533     private int execute( CliRequest cliRequest )
534     {
535         eventSpyDispatcher.onEvent( cliRequest.request );
536 
537         MavenExecutionResult result = maven.execute( cliRequest.request );
538 
539         eventSpyDispatcher.onEvent( result );
540 
541         eventSpyDispatcher.close();
542 
543         if ( result.hasExceptions() )
544         {
545             ExceptionHandler handler = new DefaultExceptionHandler();
546 
547             Map<String, String> references = new LinkedHashMap<String, String>();
548 
549             MavenProject project = null;
550 
551             for ( Throwable exception : result.getExceptions() )
552             {
553                 ExceptionSummary summary = handler.handleException( exception );
554 
555                 logSummary( summary, references, "", cliRequest.showErrors );
556 
557                 if ( project == null && exception instanceof LifecycleExecutionException )
558                 {
559                     project = ( (LifecycleExecutionException) exception ).getProject();
560                 }
561             }
562 
563             logger.error( "" );
564 
565             if ( !cliRequest.showErrors )
566             {
567                 logger.error( "To see the full stack trace of the errors, re-run Maven with the -e switch." );
568             }
569             if ( !logger.isDebugEnabled() )
570             {
571                 logger.error( "Re-run Maven using the -X switch to enable full debug logging." );
572             }
573 
574             if ( !references.isEmpty() )
575             {
576                 logger.error( "" );
577                 logger.error( "For more information about the errors and possible solutions"
578                               + ", please read the following articles:" );
579 
580                 for ( Map.Entry<String, String> entry : references.entrySet() )
581                 {
582                     logger.error( entry.getValue() + " " + entry.getKey() );
583                 }
584             }
585 
586             if ( project != null && !project.equals( result.getTopologicallySortedProjects().get( 0 ) ) )
587             {
588                 logger.error( "" );
589                 logger.error( "After correcting the problems, you can resume the build with the command" );
590                 logger.error( "  mvn <goals> -rf :" + project.getArtifactId() );
591             }
592 
593             if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) )
594             {
595                 logger.info( "Build failures were ignored." );
596 
597                 return 0;
598             }
599             else
600             {
601                 return 1;
602             }
603         }
604         else
605         {
606             return 0;
607         }
608     }
609 
610     private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent,
611                              boolean showErrors )
612     {
613         String referenceKey = "";
614 
615         if ( StringUtils.isNotEmpty( summary.getReference() ) )
616         {
617             referenceKey = references.get( summary.getReference() );
618             if ( referenceKey == null )
619             {
620                 referenceKey = "[Help " + ( references.size() + 1 ) + "]";
621                 references.put( summary.getReference(), referenceKey );
622             }
623         }
624 
625         String msg = summary.getMessage();
626 
627         if ( StringUtils.isNotEmpty( referenceKey ) )
628         {
629             if ( msg.indexOf( '\n' ) < 0 )
630             {
631                 msg += " -> " + referenceKey;
632             }
633             else
634             {
635                 msg += "\n-> " + referenceKey;
636             }
637         }
638 
639         String[] lines = msg.split( "(\r\n)|(\r)|(\n)" );
640 
641         for ( int i = 0; i < lines.length; i++ )
642         {
643             String line = indent + lines[i].trim();
644 
645             if ( i == lines.length - 1 && ( showErrors || ( summary.getException() instanceof InternalErrorException ) ) )
646             {
647                 logger.error( line, summary.getException() );
648             }
649             else
650             {
651                 logger.error( line );
652             }
653         }
654 
655         indent += "  ";
656 
657         for ( ExceptionSummary child : summary.getChildren() )
658         {
659             logSummary( child, references, indent, showErrors );
660         }
661     }
662 
663     protected ModelProcessor createModelProcessor( PlexusContainer container )
664         throws ComponentLookupException
665     {
666         return container.lookup( ModelProcessor.class );
667     }
668 
669     private void settings( CliRequest cliRequest )
670         throws Exception
671     {
672         File userSettingsFile;
673 
674         if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_SETTINGS ) )
675         {
676             userSettingsFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_USER_SETTINGS ) );
677             userSettingsFile = resolveFile( userSettingsFile, cliRequest.workingDirectory );
678 
679             if ( !userSettingsFile.isFile() )
680             {
681                 throw new FileNotFoundException( "The specified user settings file does not exist: "
682                     + userSettingsFile );
683             }
684         }
685         else
686         {
687             userSettingsFile = DEFAULT_USER_SETTINGS_FILE;
688         }
689 
690         File globalSettingsFile;
691 
692         if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_SETTINGS ) )
693         {
694             globalSettingsFile =
695                 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_SETTINGS ) );
696             globalSettingsFile = resolveFile( globalSettingsFile, cliRequest.workingDirectory );
697 
698             if ( !globalSettingsFile.isFile() )
699             {
700                 throw new FileNotFoundException( "The specified global settings file does not exist: "
701                     + globalSettingsFile );
702             }
703         }
704         else
705         {
706             globalSettingsFile = DEFAULT_GLOBAL_SETTINGS_FILE;
707         }
708 
709         cliRequest.request.setGlobalSettingsFile( globalSettingsFile );
710         cliRequest.request.setUserSettingsFile( userSettingsFile );
711 
712         SettingsBuildingRequest settingsRequest = new DefaultSettingsBuildingRequest();
713         settingsRequest.setGlobalSettingsFile( globalSettingsFile );
714         settingsRequest.setUserSettingsFile( userSettingsFile );
715         settingsRequest.setSystemProperties( cliRequest.systemProperties );
716         settingsRequest.setUserProperties( cliRequest.userProperties );
717 
718         eventSpyDispatcher.onEvent( settingsRequest );
719 
720         logger.debug( "Reading global settings from "
721             + getSettingsLocation( settingsRequest.getGlobalSettingsSource(), settingsRequest.getGlobalSettingsFile() ) );
722         logger.debug( "Reading user settings from "
723             + getSettingsLocation( settingsRequest.getUserSettingsSource(), settingsRequest.getUserSettingsFile() ) );
724 
725         SettingsBuildingResult settingsResult = settingsBuilder.build( settingsRequest );
726 
727         eventSpyDispatcher.onEvent( settingsResult );
728 
729         executionRequestPopulator.populateFromSettings( cliRequest.request, settingsResult.getEffectiveSettings() );
730 
731         if ( !settingsResult.getProblems().isEmpty() && logger.isWarnEnabled() )
732         {
733             logger.warn( "" );
734             logger.warn( "Some problems were encountered while building the effective settings" );
735 
736             for ( SettingsProblem problem : settingsResult.getProblems() )
737             {
738                 logger.warn( problem.getMessage() + " @ " + problem.getLocation() );
739             }
740 
741             logger.warn( "" );
742         }
743     }
744 
745     private Object getSettingsLocation( SettingsSource source, File file )
746     {
747         if ( source != null )
748         {
749             return source.getLocation();
750         }
751         return file;
752     }
753 
754     private MavenExecutionRequest populateRequest( CliRequest cliRequest )
755     {
756         MavenExecutionRequest request = cliRequest.request;
757         CommandLine commandLine = cliRequest.commandLine;
758         String workingDirectory = cliRequest.workingDirectory;
759         boolean quiet = cliRequest.quiet;
760         boolean showErrors = cliRequest.showErrors;
761 
762         String[] deprecatedOptions = { "up", "npu", "cpu", "npr" };
763         for ( String deprecatedOption : deprecatedOptions )
764         {
765             if ( commandLine.hasOption( deprecatedOption ) )
766             {
767                 logger.warn( "Command line option -" + deprecatedOption
768                     + " is deprecated and will be removed in future Maven versions." );
769             }
770         }
771 
772         // ----------------------------------------------------------------------
773         // Now that we have everything that we need we will fire up plexus and
774         // bring the maven component to life for use.
775         // ----------------------------------------------------------------------
776 
777         if ( commandLine.hasOption( CLIManager.BATCH_MODE ) )
778         {
779             request.setInteractiveMode( false );
780         }
781 
782         boolean noSnapshotUpdates = false;
783         if ( commandLine.hasOption( CLIManager.SUPRESS_SNAPSHOT_UPDATES ) )
784         {
785             noSnapshotUpdates = true;
786         }
787 
788         // ----------------------------------------------------------------------
789         //
790         // ----------------------------------------------------------------------
791 
792         @SuppressWarnings("unchecked")
793         List<String> goals = commandLine.getArgList();
794 
795         boolean recursive = true;
796 
797         // this is the default behavior.
798         String reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST;
799 
800         if ( commandLine.hasOption( CLIManager.NON_RECURSIVE ) )
801         {
802             recursive = false;
803         }
804 
805         if ( commandLine.hasOption( CLIManager.FAIL_FAST ) )
806         {
807             reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST;
808         }
809         else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) )
810         {
811             reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_AT_END;
812         }
813         else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) )
814         {
815             reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_NEVER;
816         }
817 
818         if ( commandLine.hasOption( CLIManager.OFFLINE ) )
819         {
820             request.setOffline( true );
821         }
822 
823         boolean updateSnapshots = false;
824 
825         if ( commandLine.hasOption( CLIManager.UPDATE_SNAPSHOTS ) )
826         {
827             updateSnapshots = true;
828         }
829 
830         String globalChecksumPolicy = null;
831 
832         if ( commandLine.hasOption( CLIManager.CHECKSUM_FAILURE_POLICY ) )
833         {
834             globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
835         }
836         else if ( commandLine.hasOption( CLIManager.CHECKSUM_WARNING_POLICY ) )
837         {
838             globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_WARN;
839         }
840 
841         File baseDirectory = new File( workingDirectory, "" ).getAbsoluteFile();
842 
843         // ----------------------------------------------------------------------
844         // Profile Activation
845         // ----------------------------------------------------------------------
846 
847         List<String> activeProfiles = new ArrayList<String>();
848 
849         List<String> inactiveProfiles = new ArrayList<String>();
850 
851         if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) )
852         {
853             String[] profileOptionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES );
854             if ( profileOptionValues != null )
855             {
856                 for ( int i = 0; i < profileOptionValues.length; ++i )
857                 {
858                     StringTokenizer profileTokens = new StringTokenizer( profileOptionValues[i], "," );
859 
860                     while ( profileTokens.hasMoreTokens() )
861                     {
862                         String profileAction = profileTokens.nextToken().trim();
863 
864                         if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) )
865                         {
866                             inactiveProfiles.add( profileAction.substring( 1 ) );
867                         }
868                         else if ( profileAction.startsWith( "+" ) )
869                         {
870                             activeProfiles.add( profileAction.substring( 1 ) );
871                         }
872                         else
873                         {
874                             activeProfiles.add( profileAction );
875                         }
876                     }
877                 }
878             }
879         }
880 
881         TransferListener transferListener;
882 
883         if ( quiet )
884         {
885             transferListener = new QuietMavenTransferListener();
886         }
887         else if ( request.isInteractiveMode() )
888         {
889             transferListener = new ConsoleMavenTransferListener( System.out );
890         }
891         else
892         {
893             transferListener = new BatchModeMavenTransferListener( System.out );
894         }
895 
896         ExecutionListener executionListener = new ExecutionEventLogger( logger );
897         executionListener = eventSpyDispatcher.chainListener( executionListener );
898 
899         String alternatePomFile = null;
900         if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) )
901         {
902             alternatePomFile = commandLine.getOptionValue( CLIManager.ALTERNATE_POM_FILE );
903         }
904 
905         File userToolchainsFile;
906         if ( commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) )
907         {
908             userToolchainsFile = new File( commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) );
909             userToolchainsFile = resolveFile( userToolchainsFile, workingDirectory );
910         }
911         else
912         {
913             userToolchainsFile = MavenCli.DEFAULT_USER_TOOLCHAINS_FILE;
914         }
915 
916         request.setBaseDirectory( baseDirectory ).setGoals( goals )
917             .setSystemProperties( cliRequest.systemProperties )
918             .setUserProperties( cliRequest.userProperties )
919             .setReactorFailureBehavior( reactorFailureBehaviour ) // default: fail fast
920             .setRecursive( recursive ) // default: true
921             .setShowErrors( showErrors ) // default: false
922             .addActiveProfiles( activeProfiles ) // optional
923             .addInactiveProfiles( inactiveProfiles ) // optional
924             .setExecutionListener( executionListener )
925             .setTransferListener( transferListener ) // default: batch mode which goes along with interactive
926             .setUpdateSnapshots( updateSnapshots ) // default: false
927             .setNoSnapshotUpdates( noSnapshotUpdates ) // default: false
928             .setGlobalChecksumPolicy( globalChecksumPolicy ) // default: warn
929             .setUserToolchainsFile( userToolchainsFile );
930 
931         if ( alternatePomFile != null )
932         {
933             File pom = resolveFile( new File( alternatePomFile ), workingDirectory );
934 
935             request.setPom( pom );
936         }
937         else
938         {
939             File pom = modelProcessor.locatePom( baseDirectory );
940 
941             if ( pom.isFile() )
942             {
943                 request.setPom( pom );
944             }
945         }
946 
947         if ( ( request.getPom() != null ) && ( request.getPom().getParentFile() != null ) )
948         {
949             request.setBaseDirectory( request.getPom().getParentFile() );
950         }
951 
952         if ( commandLine.hasOption( CLIManager.RESUME_FROM ) )
953         {
954             request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) );
955         }
956 
957         if ( commandLine.hasOption( CLIManager.PROJECT_LIST ) )
958         {
959             String[] values = commandLine.getOptionValues( CLIManager.PROJECT_LIST );
960             List<String> projects = new ArrayList<String>();
961             for ( int i = 0; i < values.length; i++ )
962             {
963                 String[] tmp = StringUtils.split( values[i], "," );
964                 projects.addAll( Arrays.asList( tmp ) );
965             }
966             request.setSelectedProjects( projects );
967         }
968 
969         if ( commandLine.hasOption( CLIManager.ALSO_MAKE )
970                         && !commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
971         {
972             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM );
973         }
974         else if ( !commandLine.hasOption( CLIManager.ALSO_MAKE )
975                         && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
976         {
977             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM );
978         }
979         else if ( commandLine.hasOption( CLIManager.ALSO_MAKE )
980                         && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
981         {
982             request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_BOTH );
983         }
984 
985         String localRepoProperty = request.getUserProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
986 
987         if ( localRepoProperty == null )
988         {
989             localRepoProperty = request.getSystemProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
990         }
991 
992         if ( localRepoProperty != null )
993         {
994             request.setLocalRepositoryPath( localRepoProperty );
995         }
996 
997         final String threadConfiguration = commandLine.hasOption( CLIManager.THREADS )
998             ? commandLine.getOptionValue( CLIManager.THREADS )
999             : request.getSystemProperties().getProperty(
1000                 MavenCli.THREADS_DEPRECATED ); // TODO: Remove this setting. Note that the int-tests use it
1001 
1002         if ( threadConfiguration != null )
1003         {
1004             request.setPerCoreThreadCount( threadConfiguration.contains( "C" ) );
1005             if ( threadConfiguration.contains( "W" ) )
1006             {
1007                 LifecycleWeaveBuilder.setWeaveMode( request.getUserProperties() );
1008             }
1009             request.setThreadCount( threadConfiguration.replace( "C", "" ).replace( "W", "" ).replace( "auto", "" ) );
1010         }
1011 
1012         request.setCacheNotFound( true );
1013         request.setCacheTransferError( false );
1014 
1015         return request;
1016     }
1017 
1018     static File resolveFile( File file, String workingDirectory )
1019     {
1020         if ( file == null )
1021         {
1022             return null;
1023         }
1024         else if ( file.isAbsolute() )
1025         {
1026             return file;
1027         }
1028         else if ( file.getPath().startsWith( File.separator ) )
1029         {
1030             // drive-relative Windows path
1031             return file.getAbsoluteFile();
1032         }
1033         else
1034         {
1035             return new File( workingDirectory, file.getPath() ).getAbsoluteFile();
1036         }
1037     }
1038 
1039     // ----------------------------------------------------------------------
1040     // System properties handling
1041     // ----------------------------------------------------------------------
1042 
1043     static void populateProperties( CommandLine commandLine, Properties systemProperties, Properties userProperties )
1044     {
1045         EnvironmentUtils.addEnvVars( systemProperties );
1046 
1047         // ----------------------------------------------------------------------
1048         // Options that are set on the command line become system properties
1049         // and therefore are set in the session properties. System properties
1050         // are most dominant.
1051         // ----------------------------------------------------------------------
1052 
1053         if ( commandLine.hasOption( CLIManager.SET_SYSTEM_PROPERTY ) )
1054         {
1055             String[] defStrs = commandLine.getOptionValues( CLIManager.SET_SYSTEM_PROPERTY );
1056 
1057             if ( defStrs != null )
1058             {
1059                 for ( int i = 0; i < defStrs.length; ++i )
1060                 {
1061                     setCliProperty( defStrs[i], userProperties );
1062                 }
1063             }
1064         }
1065 
1066         systemProperties.putAll( System.getProperties() );
1067         
1068         // ----------------------------------------------------------------------
1069         // Properties containing info about the currently running version of Maven
1070         // These override any corresponding properties set on the command line
1071         // ----------------------------------------------------------------------
1072 
1073         Properties buildProperties = CLIReportingUtils.getBuildProperties();
1074 
1075         String mavenVersion = buildProperties.getProperty( CLIReportingUtils.BUILD_VERSION_PROPERTY );
1076         systemProperties.setProperty( "maven.version", mavenVersion );
1077 
1078         String mavenBuildVersion = CLIReportingUtils.createMavenVersionString( buildProperties );
1079         systemProperties.setProperty( "maven.build.version", mavenBuildVersion );
1080     }
1081 
1082     private static void setCliProperty( String property, Properties properties )
1083     {
1084         String name;
1085 
1086         String value;
1087 
1088         int i = property.indexOf( "=" );
1089 
1090         if ( i <= 0 )
1091         {
1092             name = property.trim();
1093 
1094             value = "true";
1095         }
1096         else
1097         {
1098             name = property.substring( 0, i ).trim();
1099 
1100             value = property.substring( i + 1 );
1101         }
1102 
1103         properties.setProperty( name, value );
1104 
1105         // ----------------------------------------------------------------------
1106         // I'm leaving the setting of system properties here as not to break
1107         // the SystemPropertyProfileActivator. This won't harm embedding. jvz.
1108         // ----------------------------------------------------------------------
1109 
1110         System.setProperty( name, value );
1111     }
1112 
1113     static class CliRequest
1114     {
1115         String[] args;
1116         CommandLine commandLine;
1117         ClassWorld classWorld;
1118         String workingDirectory;
1119         boolean debug;
1120         boolean quiet;
1121         boolean showErrors = true;
1122         PrintStream fileStream;
1123         Properties userProperties = new Properties();
1124         Properties systemProperties = new Properties();
1125         MavenExecutionRequest request;
1126 
1127         CliRequest( String[] args, ClassWorld classWorld )
1128         {
1129             this.args = args;
1130             this.classWorld = classWorld;
1131             this.request = new DefaultMavenExecutionRequest();
1132         }
1133     }
1134 
1135     static class ExitException
1136         extends Exception
1137     {
1138 
1139         public int exitCode;
1140 
1141         public ExitException( int exitCode )
1142         {
1143             this.exitCode = exitCode;
1144         }
1145 
1146     }
1147 
1148 }