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