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