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