1 package org.apache.maven.cli;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.text.SimpleDateFormat;
26 import java.util.Arrays;
27 import java.util.Date;
28 import java.util.Iterator;
29 import java.util.Locale;
30 import java.util.Properties;
31 import java.util.StringTokenizer;
32 import java.util.Map.Entry;
33
34 import org.apache.commons.cli.CommandLine;
35 import org.apache.commons.cli.ParseException;
36 import org.apache.maven.Maven;
37 import org.apache.maven.SettingsConfigurationException;
38 import org.apache.maven.artifact.manager.WagonManager;
39 import org.apache.maven.artifact.repository.ArtifactRepository;
40 import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
41 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
42 import org.apache.maven.artifact.repository.DefaultArtifactRepository;
43 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
44 import org.apache.maven.execution.DefaultMavenExecutionRequest;
45 import org.apache.maven.execution.MavenExecutionRequest;
46 import org.apache.maven.execution.ReactorManager;
47 import org.apache.maven.monitor.event.DefaultEventDispatcher;
48 import org.apache.maven.monitor.event.DefaultEventMonitor;
49 import org.apache.maven.monitor.event.EventDispatcher;
50 import org.apache.maven.plugin.Mojo;
51 import org.apache.maven.profiles.DefaultProfileManager;
52 import org.apache.maven.profiles.ProfileManager;
53 import org.apache.maven.reactor.MavenExecutionException;
54 import org.apache.maven.settings.MavenSettingsBuilder;
55 import org.apache.maven.settings.RuntimeInfo;
56 import org.apache.maven.settings.Settings;
57 import org.codehaus.classworlds.ClassWorld;
58 import org.codehaus.plexus.PlexusContainerException;
59 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
60 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
61 import org.codehaus.plexus.embed.Embedder;
62 import org.codehaus.plexus.logging.Logger;
63 import org.codehaus.plexus.logging.LoggerManager;
64 import org.codehaus.plexus.util.IOUtil;
65 import org.codehaus.plexus.util.Os;
66 import org.codehaus.plexus.util.StringUtils;
67 import org.codehaus.plexus.util.cli.CommandLineUtils;
68 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
69 import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
70 import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
71 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
72 import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
73 import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
74
75
76
77
78
79
80 public class MavenCli
81 {
82
83 public static final String OS_NAME = Os.OS_NAME;
84
85
86 public static final String OS_ARCH = Os.OS_ARCH;
87
88
89 public static final String OS_VERSION = Os.OS_VERSION;
90
91 private static Embedder embedder;
92
93
94
95
96 public static void main( String[] args )
97 {
98 ClassWorld classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
99
100 int result = main( args, classWorld );
101
102 System.exit( result );
103 }
104
105
106
107
108 public static int main( String[] args, ClassWorld classWorld )
109 {
110
111
112
113
114 CLIManager cliManager = new CLIManager();
115
116 CommandLine commandLine;
117 try
118 {
119 commandLine = cliManager.parse( args );
120 }
121 catch ( ParseException e )
122 {
123 System.err.println( "Unable to parse command line options: " + e.getMessage() );
124 cliManager.displayHelp();
125 return 1;
126 }
127
128 boolean debug = commandLine.hasOption( CLIManager.DEBUG );
129
130 boolean showErrors = debug || commandLine.hasOption( CLIManager.ERRORS );
131
132 if ( showErrors )
133 {
134 System.out.println( "+ Error stacktraces are turned on." );
135 }
136
137
138
139
140
141 if ( commandLine.hasOption( CLIManager.HELP ) )
142 {
143 cliManager.displayHelp();
144 return 0;
145 }
146
147 if ( commandLine.hasOption( CLIManager.VERSION ) )
148 {
149 showVersion();
150
151 return 0;
152 }
153 else if ( debug || commandLine.hasOption( CLIManager.SHOW_VERSION ) )
154 {
155 showVersion();
156 }
157
158 EventDispatcher eventDispatcher = new DefaultEventDispatcher();
159
160
161
162 String mavenHome = System.getProperty( "maven.home" );
163 if ( mavenHome != null )
164 {
165 System.setProperty( "maven.home", new File( mavenHome ).getAbsolutePath() );
166 }
167
168
169
170
171
172
173 embedder = new Embedder();
174
175 try
176 {
177 embedder.start( classWorld );
178 }
179 catch ( PlexusContainerException e )
180 {
181 showFatalError( "Unable to start the embedded plexus container", e, showErrors );
182
183 return 1;
184 }
185
186
187 try
188 {
189
190
191
192
193
194 Properties executionProperties = new Properties();
195 Properties userProperties = new Properties();
196 populateProperties( commandLine, executionProperties, userProperties );
197
198 Settings settings;
199
200 try
201 {
202 settings = buildSettings( commandLine );
203 }
204 catch ( SettingsConfigurationException e )
205 {
206 showError( "Error reading settings.xml: " + e.getMessage(), e, showErrors );
207
208 return 1;
209 }
210 catch ( ComponentLookupException e )
211 {
212 showFatalError( "Unable to read settings.xml", e, showErrors );
213
214 return 1;
215 }
216
217 DefaultSecDispatcher dispatcher;
218 try
219 {
220 if ( commandLine.hasOption( CLIManager.ENCRYPT_MASTER_PASSWORD ) )
221 {
222 String passwd = commandLine.getOptionValue( CLIManager.ENCRYPT_MASTER_PASSWORD );
223
224 DefaultPlexusCipher cipher = new DefaultPlexusCipher();
225
226 System.out.println( cipher.encryptAndDecorate( passwd,
227 DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) );
228
229 return 0;
230 }
231 else if ( commandLine.hasOption( CLIManager.ENCRYPT_PASSWORD ) )
232 {
233 String passwd = commandLine.getOptionValue( CLIManager.ENCRYPT_PASSWORD );
234
235 dispatcher = (DefaultSecDispatcher) embedder.lookup( SecDispatcher.ROLE );
236 String configurationFile = dispatcher.getConfigurationFile();
237 if ( configurationFile.startsWith( "~" ) )
238 {
239 configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
240 }
241 String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
242 embedder.release( dispatcher );
243
244 String master = null;
245
246 SettingsSecurity sec = SecUtil.read( file, true );
247 if ( sec != null )
248 {
249 master = sec.getMaster();
250 }
251
252 if ( master == null )
253 {
254 System.err.println( "Master password is not set in the setting security file" );
255
256 return 1;
257 }
258
259 DefaultPlexusCipher cipher = new DefaultPlexusCipher();
260 String masterPasswd =
261 cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
262 System.out.println( cipher.encryptAndDecorate( passwd, masterPasswd ) );
263
264 return 0;
265 }
266 }
267 catch ( Exception e )
268 {
269 showFatalError( "Error encrypting password: " + e.getMessage(), e, showErrors );
270
271 return 1;
272 }
273
274 Maven maven = null;
275
276 MavenExecutionRequest request = null;
277
278 LoggerManager loggerManager = null;
279
280 try
281 {
282
283 loggerManager = (LoggerManager) embedder.lookup( LoggerManager.ROLE );
284
285 if ( debug )
286 {
287 loggerManager.setThreshold( Logger.LEVEL_DEBUG );
288 }
289 else if ( commandLine.hasOption( CLIManager.QUIET ) )
290 {
291
292
293 loggerManager.setThreshold( Logger.LEVEL_ERROR );
294
295 }
296
297 ProfileManager profileManager = new DefaultProfileManager( embedder.getContainer(), executionProperties );
298
299 if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) )
300 {
301 String [] profileOptionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES );
302
303 if ( profileOptionValues != null )
304 {
305 for ( int i=0; i < profileOptionValues.length; ++i )
306 {
307 StringTokenizer profileTokens = new StringTokenizer( profileOptionValues[i], "," );
308
309 while ( profileTokens.hasMoreTokens() )
310 {
311 String profileAction = profileTokens.nextToken().trim();
312
313 if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) )
314 {
315 profileManager.explicitlyDeactivate( profileAction.substring( 1 ) );
316 }
317 else if ( profileAction.startsWith( "+" ) )
318 {
319 profileManager.explicitlyActivate( profileAction.substring( 1 ) );
320 }
321 else
322 {
323 profileManager.explicitlyActivate( profileAction );
324 }
325 }
326 }
327 }
328 }
329
330 request = createRequest( commandLine, settings, eventDispatcher, loggerManager, profileManager,
331 executionProperties, userProperties, showErrors );
332
333 setProjectFileOptions( commandLine, request );
334
335 maven =
336 createMavenInstance( settings.isInteractiveMode(),
337 loggerManager.getLoggerForComponent( WagonManager.ROLE ) );
338 }
339 catch ( ComponentLookupException e )
340 {
341 showFatalError( "Unable to configure the Maven application", e, showErrors );
342
343 return 1;
344 }
345 finally
346 {
347 if ( loggerManager != null )
348 {
349 try
350 {
351 embedder.release( loggerManager );
352 }
353 catch ( ComponentLifecycleException e )
354 {
355 showFatalError( "Error releasing logging manager", e, showErrors );
356 }
357 }
358 }
359
360 try
361 {
362 maven.execute( request );
363 }
364 catch ( MavenExecutionException e )
365 {
366 return 1;
367 }
368 }
369 finally
370 {
371 try
372 {
373 embedder.stop();
374 }
375 catch ( Exception e )
376 {
377
378 }
379 }
380
381 return 0;
382 }
383
384 private static Settings buildSettings( CommandLine commandLine )
385 throws ComponentLookupException, SettingsConfigurationException
386 {
387 String userSettingsPath = null;
388
389 if ( commandLine.hasOption( CLIManager.ALTERNATE_USER_SETTINGS ) )
390 {
391 userSettingsPath = commandLine.getOptionValue( CLIManager.ALTERNATE_USER_SETTINGS );
392 }
393
394 if ( commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_SETTINGS ) )
395 {
396 String globalSettingsPath = commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_SETTINGS );
397 System.setProperty( MavenSettingsBuilder.ALT_GLOBAL_SETTINGS_XML_LOCATION, globalSettingsPath );
398 }
399
400 Settings settings = null;
401
402 MavenSettingsBuilder settingsBuilder = (MavenSettingsBuilder) embedder.lookup( MavenSettingsBuilder.ROLE );
403
404 try
405 {
406 if ( userSettingsPath != null )
407 {
408 File userSettingsFile = new File( userSettingsPath );
409
410 if ( userSettingsFile.exists() && !userSettingsFile.isDirectory() )
411 {
412 settings = settingsBuilder.buildSettings( userSettingsFile );
413 }
414 else
415 {
416 System.out.println( "WARNING: Alternate user settings file: " + userSettingsPath +
417 " is invalid. Using default path." );
418 }
419 }
420
421 if ( settings == null )
422 {
423 settings = settingsBuilder.buildSettings();
424 }
425 }
426 catch ( IOException e )
427 {
428 throw new SettingsConfigurationException( "Error reading settings file", e );
429 }
430 catch ( XmlPullParserException e )
431 {
432 throw new SettingsConfigurationException( e.getMessage(), e, e.getLineNumber(),
433 e.getColumnNumber() );
434 }
435
436
437
438 if ( commandLine.hasOption( CLIManager.BATCH_MODE ) )
439 {
440 settings.setInteractiveMode( false );
441 }
442
443 if ( commandLine.hasOption( CLIManager.SUPPRESS_PLUGIN_REGISTRY ) )
444 {
445 settings.setUsePluginRegistry( false );
446 }
447
448
449
450 settings.setRuntimeInfo( createRuntimeInfo( commandLine, settings ) );
451
452 return settings;
453 }
454
455 private static RuntimeInfo createRuntimeInfo( CommandLine commandLine, Settings settings )
456 {
457 RuntimeInfo runtimeInfo = new RuntimeInfo( settings );
458
459 if ( commandLine.hasOption( CLIManager.FORCE_PLUGIN_UPDATES ) ||
460 commandLine.hasOption( CLIManager.FORCE_PLUGIN_UPDATES2 ) )
461 {
462 runtimeInfo.setPluginUpdateOverride( Boolean.TRUE );
463 }
464 else if ( commandLine.hasOption( CLIManager.SUPPRESS_PLUGIN_UPDATES ) )
465 {
466 runtimeInfo.setPluginUpdateOverride( Boolean.FALSE );
467 }
468
469 return runtimeInfo;
470 }
471
472
473 private static void showFatalError( String message, Exception e, boolean show )
474 {
475 System.err.println( "FATAL ERROR: " + message );
476 if ( show )
477 {
478 System.err.println( "Error stacktrace:" );
479
480 e.printStackTrace();
481 }
482 else
483 {
484 System.err.println( "For more information, run with the -e flag" );
485 }
486 }
487
488 private static void showError( String message, Exception e, boolean show )
489 {
490 System.err.println( message );
491 if ( show )
492 {
493 System.err.println( "Error stacktrace:" );
494
495 e.printStackTrace();
496 }
497 }
498
499 private static MavenExecutionRequest createRequest( CommandLine commandLine, Settings settings,
500 EventDispatcher eventDispatcher, LoggerManager loggerManager,
501 ProfileManager profileManager, Properties executionProperties,
502 Properties userProperties, boolean showErrors )
503 throws ComponentLookupException
504 {
505 MavenExecutionRequest request;
506
507 ArtifactRepository localRepository = createLocalRepository( embedder, settings, commandLine );
508
509 File userDir = new File( System.getProperty( "user.dir" ) );
510
511 request = new DefaultMavenExecutionRequest( localRepository, settings, eventDispatcher,
512 commandLine.getArgList(), userDir.getPath(), profileManager,
513 executionProperties, userProperties, showErrors );
514
515
516 Logger logger = loggerManager.getLoggerForComponent( Mojo.ROLE );
517
518 if ( logger != null )
519 {
520 request.addEventMonitor( new DefaultEventMonitor( logger ) );
521 }
522
523 if ( commandLine.hasOption( CLIManager.NON_RECURSIVE ) )
524 {
525 request.setRecursive( false );
526 }
527
528 if ( commandLine.hasOption( CLIManager.FAIL_FAST ) )
529 {
530 request.setFailureBehavior( ReactorManager.FAIL_FAST );
531 }
532 else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) )
533 {
534 request.setFailureBehavior( ReactorManager.FAIL_AT_END );
535 }
536 else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) )
537 {
538 request.setFailureBehavior( ReactorManager.FAIL_NEVER );
539 }
540
541 return request;
542 }
543
544 private static void setProjectFileOptions( CommandLine commandLine, MavenExecutionRequest request )
545 {
546 if ( commandLine.hasOption( CLIManager.REACTOR ) )
547 {
548 request.setReactorActive( true );
549 }
550 else if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) )
551 {
552 request.setPomFile( commandLine.getOptionValue( CLIManager.ALTERNATE_POM_FILE ) );
553 }
554
555 if ( commandLine.hasOption( CLIManager.RESUME_FROM ) )
556 {
557 request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) );
558 }
559
560 if ( commandLine.hasOption( CLIManager.PROJECT_LIST ) )
561 {
562 String projectList = commandLine.getOptionValue( CLIManager.PROJECT_LIST );
563 String[] projects = StringUtils.split( projectList, "," );
564 request.setSelectedProjects( Arrays.asList( projects ) );
565 }
566
567 if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && !commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
568 {
569 request.setMakeBehavior( ReactorManager.MAKE_MODE );
570 }
571 else if ( !commandLine.hasOption( CLIManager.ALSO_MAKE )
572 && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
573 {
574 request.setMakeBehavior( ReactorManager.MAKE_DEPENDENTS_MODE );
575 }
576 if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
577 {
578 request.setMakeBehavior( ReactorManager.MAKE_BOTH_MODE );
579 }
580 }
581
582 private static Maven createMavenInstance( boolean interactive, Logger logger )
583 throws ComponentLookupException
584 {
585
586 WagonManager wagonManager = (WagonManager) embedder.lookup( WagonManager.ROLE );
587 if ( interactive )
588 {
589 wagonManager.setDownloadMonitor( new ConsoleDownloadMonitor( logger ) );
590 }
591 else
592 {
593 wagonManager.setDownloadMonitor( new BatchModeDownloadMonitor( logger ) );
594 }
595
596 wagonManager.setInteractive( interactive );
597
598 return (Maven) embedder.lookup( Maven.ROLE );
599 }
600
601 private static ArtifactRepository createLocalRepository( Embedder embedder, Settings settings,
602 CommandLine commandLine )
603 throws ComponentLookupException
604 {
605
606
607 ArtifactRepositoryLayout repositoryLayout =
608 (ArtifactRepositoryLayout) embedder.lookup( ArtifactRepositoryLayout.ROLE, "default" );
609
610 ArtifactRepositoryFactory artifactRepositoryFactory =
611 (ArtifactRepositoryFactory) embedder.lookup( ArtifactRepositoryFactory.ROLE );
612
613 String url = settings.getLocalRepository();
614
615 if ( !url.startsWith( "file:" ) )
616 {
617 url = "file://" + url;
618 }
619
620 ArtifactRepository localRepository = new DefaultArtifactRepository( "local", url, repositoryLayout );
621
622 boolean snapshotPolicySet = false;
623
624 if ( commandLine.hasOption( CLIManager.OFFLINE ) )
625 {
626 settings.setOffline( true );
627
628 snapshotPolicySet = true;
629 }
630
631 if ( !snapshotPolicySet && commandLine.hasOption( CLIManager.UPDATE_SNAPSHOTS ) )
632 {
633 artifactRepositoryFactory.setGlobalUpdatePolicy( ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS );
634 }
635
636 if ( commandLine.hasOption( CLIManager.CHECKSUM_FAILURE_POLICY ) )
637 {
638 System.out.println( "+ Enabling strict checksum verification on all artifact downloads." );
639
640 artifactRepositoryFactory.setGlobalChecksumPolicy( ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL );
641 }
642 else if ( commandLine.hasOption( CLIManager.CHECKSUM_WARNING_POLICY ) )
643 {
644 System.out.println( "+ Disabling strict checksum verification on all artifact downloads." );
645
646 artifactRepositoryFactory.setGlobalChecksumPolicy( ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN );
647 }
648
649 return localRepository;
650 }
651
652 static Properties getBuildProperties()
653 {
654 Properties properties = new Properties();
655 InputStream resourceAsStream = null;
656 try
657 {
658 resourceAsStream = MavenCli.class.getClassLoader().getResourceAsStream( "org/apache/maven/messages/build.properties" );
659
660 if ( resourceAsStream != null )
661 {
662 properties.load( resourceAsStream );
663 }
664 }
665 catch ( IOException e )
666 {
667 System.err.println( "Unable determine version from JAR file: " + e.getMessage() );
668 }
669 finally
670 {
671 IOUtil.close( resourceAsStream );
672 }
673
674 return properties;
675 }
676
677 private static void showVersion()
678 {
679 Properties properties = getBuildProperties();
680
681 String timestamp = reduce( properties.getProperty( "timestamp" ) );
682 String version = reduce( properties.getProperty( "version" ) );
683 String rev = reduce( properties.getProperty( "buildNumber" ) );
684
685 String msg = "Apache Maven ";
686 msg += ( version != null ? version : "<version unknown>" );
687 if ( rev != null || timestamp != null )
688 {
689 msg += " (";
690 msg += ( rev != null ? "r" + rev : "" );
691 if ( timestamp != null )
692 {
693 SimpleDateFormat fmt = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ssZ" );
694 String ts = fmt.format( new Date( Long.valueOf( timestamp ).longValue() ) );
695 msg += ( rev != null ? "; " : "" ) + ts;
696 }
697 msg += ")";
698 }
699
700 System.out.println( msg );
701
702 System.out.println( "Java version: " + System.getProperty( "java.version", "<unknown java version>" ) );
703
704 System.out.println( "Java home: " + System.getProperty( "java.home", "<unknown java home>" ) );
705
706 System.out.println( "Default locale: " + Locale.getDefault() + ", platform encoding: "
707 + System.getProperty( "file.encoding", "<unknown encoding>" ) );
708
709 System.out.println( "OS name: \"" + Os.OS_NAME + "\" version: \"" + Os.OS_VERSION +
710 "\" arch: \"" + Os.OS_ARCH + "\" Family: \"" + Os.OS_FAMILY + "\"" );
711 }
712
713 private static String reduce( String s )
714 {
715 return ( s != null ? ( s.startsWith( "${" ) && s.endsWith( "}" ) ? null : s ) : null );
716 }
717
718
719
720
721
722 static void populateProperties( CommandLine commandLine, Properties executionProperties, Properties userProperties )
723 {
724
725
726 try
727 {
728 Properties envVars = CommandLineUtils.getSystemEnvVars();
729 Iterator i = envVars.entrySet().iterator();
730 while ( i.hasNext() )
731 {
732 Entry e = (Entry) i.next();
733 executionProperties.setProperty( "env." + e.getKey().toString(), e.getValue().toString() );
734 }
735 }
736 catch ( IOException e )
737 {
738 System.err.println( "Error getting environment vars for profile activation: " + e );
739 }
740
741
742
743
744
745
746
747 if ( commandLine.hasOption( CLIManager.SET_SYSTEM_PROPERTY ) )
748 {
749 String[] defStrs = commandLine.getOptionValues( CLIManager.SET_SYSTEM_PROPERTY );
750
751 if ( defStrs != null )
752 {
753 for ( int i = 0; i < defStrs.length; ++i )
754 {
755 setCliProperty( defStrs[i], userProperties );
756 }
757 }
758
759 executionProperties.putAll( userProperties );
760 }
761
762 executionProperties.putAll( System.getProperties() );
763 }
764
765 private static void setCliProperty( String property, Properties requestProperties )
766 {
767 String name;
768
769 String value;
770
771 int i = property.indexOf( "=" );
772
773 if ( i <= 0 )
774 {
775 name = property.trim();
776
777 value = "true";
778 }
779 else
780 {
781 name = property.substring( 0, i ).trim();
782
783 value = property.substring( i + 1 ).trim();
784 }
785
786 requestProperties.setProperty( name, value );
787
788
789
790
791
792
793 System.setProperty( name, value );
794 }
795 }