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