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