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