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