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