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.BufferedInputStream; 023import java.io.Console; 024import java.io.File; 025import java.io.FileInputStream; 026import java.io.FileNotFoundException; 027import java.io.FileOutputStream; 028import java.io.IOException; 029import java.io.InputStream; 030import java.io.PrintStream; 031import java.util.ArrayList; 032import java.util.Arrays; 033import java.util.Collections; 034import java.util.HashSet; 035import java.util.LinkedHashMap; 036import java.util.List; 037import java.util.Map; 038import java.util.Map.Entry; 039import java.util.Properties; 040import java.util.Set; 041import java.util.StringTokenizer; 042 043import org.apache.commons.cli.CommandLine; 044import org.apache.commons.cli.ParseException; 045import org.apache.commons.cli.UnrecognizedOptionException; 046import org.apache.maven.BuildAbort; 047import org.apache.maven.InternalErrorException; 048import org.apache.maven.Maven; 049import org.apache.maven.building.FileSource; 050import org.apache.maven.building.Problem; 051import org.apache.maven.building.Source; 052import org.apache.maven.cli.configuration.ConfigurationProcessor; 053import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor; 054import org.apache.maven.cli.event.DefaultEventSpyContext; 055import org.apache.maven.cli.event.ExecutionEventLogger; 056import org.apache.maven.cli.internal.BootstrapCoreExtensionManager; 057import org.apache.maven.cli.internal.extension.model.CoreExtension; 058import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader; 059import org.apache.maven.cli.logging.Slf4jConfiguration; 060import org.apache.maven.cli.logging.Slf4jConfigurationFactory; 061import org.apache.maven.cli.logging.Slf4jLoggerManager; 062import org.apache.maven.cli.logging.Slf4jStdoutLogger; 063import org.apache.maven.cli.transfer.ConsoleMavenTransferListener; 064import org.apache.maven.cli.transfer.QuietMavenTransferListener; 065import org.apache.maven.cli.transfer.Slf4jMavenTransferListener; 066import org.apache.maven.eventspy.internal.EventSpyDispatcher; 067import org.apache.maven.exception.DefaultExceptionHandler; 068import org.apache.maven.exception.ExceptionHandler; 069import org.apache.maven.exception.ExceptionSummary; 070import org.apache.maven.execution.DefaultMavenExecutionRequest; 071import org.apache.maven.execution.ExecutionListener; 072import org.apache.maven.execution.MavenExecutionRequest; 073import org.apache.maven.execution.MavenExecutionRequestPopulationException; 074import org.apache.maven.execution.MavenExecutionRequestPopulator; 075import org.apache.maven.execution.MavenExecutionResult; 076import org.apache.maven.extension.internal.CoreExports; 077import org.apache.maven.extension.internal.CoreExtensionEntry; 078import org.apache.maven.lifecycle.LifecycleExecutionException; 079import org.apache.maven.model.building.ModelProcessor; 080import org.apache.maven.project.MavenProject; 081import org.apache.maven.properties.internal.EnvironmentUtils; 082import org.apache.maven.properties.internal.SystemProperties; 083import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest; 084import org.apache.maven.toolchain.building.ToolchainsBuilder; 085import org.apache.maven.toolchain.building.ToolchainsBuildingResult; 086import org.codehaus.plexus.ContainerConfiguration; 087import org.codehaus.plexus.DefaultContainerConfiguration; 088import org.codehaus.plexus.DefaultPlexusContainer; 089import org.codehaus.plexus.PlexusConstants; 090import org.codehaus.plexus.PlexusContainer; 091import org.codehaus.plexus.classworlds.ClassWorld; 092import org.codehaus.plexus.classworlds.realm.ClassRealm; 093import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; 094import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 095import org.codehaus.plexus.logging.LoggerManager; 096import org.codehaus.plexus.util.IOUtil; 097import org.codehaus.plexus.util.StringUtils; 098import org.codehaus.plexus.util.xml.pull.XmlPullParserException; 099import org.eclipse.aether.transfer.TransferListener; 100import org.slf4j.ILoggerFactory; 101import org.slf4j.Logger; 102import org.slf4j.LoggerFactory; 103import org.sonatype.plexus.components.cipher.DefaultPlexusCipher; 104import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher; 105import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; 106import org.sonatype.plexus.components.sec.dispatcher.SecUtil; 107import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity; 108 109import com.google.common.base.Charsets; 110import com.google.common.io.Files; 111import com.google.inject.AbstractModule; 112 113// TODO: push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs 114 115/** 116 * @author Jason van Zyl 117 * @noinspection UseOfSystemOutOrSystemErr,ACCESS_STATIC_VIA_INSTANCE 118 */ 119public class MavenCli 120{ 121 public static final String LOCAL_REPO_PROPERTY = "maven.repo.local"; 122 123 public static final String THREADS_DEPRECATED = "maven.threads.experimental"; 124 125 public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory"; 126 127 @SuppressWarnings( "checkstyle:constantname" ) 128 public static final String userHome = System.getProperty( "user.home" ); 129 130 @SuppressWarnings( "checkstyle:constantname" ) 131 public static final File userMavenConfigurationHome = new File( userHome, ".m2" ); 132 133 /** 134 * @deprecated use {@link SettingsXmlConfigurationProcessor#DEFAULT_USER_SETTINGS_FILE} 135 */ 136 public static final File DEFAULT_USER_SETTINGS_FILE = SettingsXmlConfigurationProcessor.DEFAULT_USER_SETTINGS_FILE; 137 138 /** 139 * @deprecated use {@link SettingsXmlConfigurationProcessor#DEFAULT_GLOBAL_SETTINGS_FILE} 140 */ 141 public static final File DEFAULT_GLOBAL_SETTINGS_FILE = 142 SettingsXmlConfigurationProcessor.DEFAULT_GLOBAL_SETTINGS_FILE; 143 144 public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File( userMavenConfigurationHome, "toolchains.xml" ); 145 146 public static final File DEFAULT_GLOBAL_TOOLCHAINS_FILE = 147 new File( System.getProperty( "maven.home", System.getProperty( "user.dir", "" ) ), "conf/toolchains.xml" ); 148 149 private static final String EXT_CLASS_PATH = "maven.ext.class.path"; 150 151 private static final String EXTENSIONS_FILENAME = ".mvn/extensions.xml"; 152 153 private ClassWorld classWorld; 154 155 private LoggerManager plexusLoggerManager; 156 157 private ILoggerFactory slf4jLoggerFactory; 158 159 private Logger slf4jLogger; 160 161 private EventSpyDispatcher eventSpyDispatcher; 162 163 private ModelProcessor modelProcessor; 164 165 private Maven maven; 166 167 private MavenExecutionRequestPopulator executionRequestPopulator; 168 169 private ToolchainsBuilder toolchainsBuilder; 170 171 private DefaultSecDispatcher dispatcher; 172 173 private Map<String, ConfigurationProcessor> configurationProcessors; 174 175 public MavenCli() 176 { 177 this( null ); 178 } 179 180 // This supports painless invocation by the Verifier during embedded execution of the core ITs 181 public MavenCli( ClassWorld classWorld ) 182 { 183 this.classWorld = classWorld; 184 } 185 186 public static void main( String[] args ) 187 { 188 int result = main( args, null ); 189 190 System.exit( result ); 191 } 192 193 /** @noinspection ConfusingMainMethod */ 194 public static int main( String[] args, ClassWorld classWorld ) 195 { 196 MavenCli cli = new MavenCli(); 197 return cli.doMain( new CliRequest( args, classWorld ) ); 198 } 199 200 // TODO: need to externalize CliRequest 201 public static int doMain( String[] args, ClassWorld classWorld ) 202 { 203 MavenCli cli = new MavenCli(); 204 return cli.doMain( new CliRequest( args, classWorld ) ); 205 } 206 207 // This supports painless invocation by the Verifier during embedded execution of the core ITs 208 public int doMain( String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr ) 209 { 210 PrintStream oldout = System.out; 211 PrintStream olderr = System.err; 212 213 final Set<String> realms; 214 if ( classWorld != null ) 215 { 216 realms = new HashSet<String>(); 217 for ( ClassRealm realm : classWorld.getRealms() ) 218 { 219 realms.add( realm.getId() ); 220 } 221 } 222 else 223 { 224 realms = Collections.emptySet(); 225 } 226 227 try 228 { 229 if ( stdout != null ) 230 { 231 System.setOut( stdout ); 232 } 233 if ( stderr != null ) 234 { 235 System.setErr( stderr ); 236 } 237 238 CliRequest cliRequest = new CliRequest( args, classWorld ); 239 cliRequest.workingDirectory = workingDirectory; 240 241 return doMain( cliRequest ); 242 } 243 finally 244 { 245 if ( classWorld != null ) 246 { 247 for ( ClassRealm realm : new ArrayList<ClassRealm>( classWorld.getRealms() ) ) 248 { 249 String realmId = realm.getId(); 250 if ( !realms.contains( realmId ) ) 251 { 252 try 253 { 254 classWorld.disposeRealm( realmId ); 255 } 256 catch ( NoSuchRealmException ignored ) 257 { 258 // can't happen 259 } 260 } 261 } 262 } 263 System.setOut( oldout ); 264 System.setErr( olderr ); 265 } 266 } 267 268 // TODO: need to externalize CliRequest 269 public int doMain( CliRequest cliRequest ) 270 { 271 PlexusContainer localContainer = null; 272 try 273 { 274 initialize( cliRequest ); 275 cli( cliRequest ); 276 logging( cliRequest ); 277 version( cliRequest ); 278 properties( cliRequest ); 279 localContainer = container( cliRequest ); 280 commands( cliRequest ); 281 configure( cliRequest ); 282 toolchains( cliRequest ); 283 populateRequest( cliRequest ); 284 encryption( cliRequest ); 285 repository( cliRequest ); 286 return execute( cliRequest ); 287 } 288 catch ( ExitException e ) 289 { 290 return e.exitCode; 291 } 292 catch ( UnrecognizedOptionException e ) 293 { 294 // pure user error, suppress stack trace 295 return 1; 296 } 297 catch ( BuildAbort e ) 298 { 299 CLIReportingUtils.showError( slf4jLogger, "ABORTED", e, cliRequest.showErrors ); 300 301 return 2; 302 } 303 catch ( Exception e ) 304 { 305 CLIReportingUtils.showError( slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors ); 306 307 return 1; 308 } 309 finally 310 { 311 if ( localContainer != null ) 312 { 313 localContainer.dispose(); 314 } 315 } 316 } 317 318 void initialize( CliRequest cliRequest ) 319 throws ExitException 320 { 321 if ( cliRequest.workingDirectory == null ) 322 { 323 cliRequest.workingDirectory = System.getProperty( "user.dir" ); 324 } 325 326 if ( cliRequest.multiModuleProjectDirectory == null ) 327 { 328 String basedirProperty = System.getProperty( MULTIMODULE_PROJECT_DIRECTORY ); 329 if ( basedirProperty == null ) 330 { 331 System.err.format( "-D%s system propery is not set." 332 + " Check $M2_HOME environment variable and mvn script match.", MULTIMODULE_PROJECT_DIRECTORY ); 333 throw new ExitException( 1 ); 334 } 335 File basedir = basedirProperty != null ? new File( basedirProperty ) : new File( "" ); 336 try 337 { 338 cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile(); 339 } 340 catch ( IOException e ) 341 { 342 cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile(); 343 } 344 } 345 346 // 347 // Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative 348 // Windows paths. 349 // 350 String mavenHome = System.getProperty( "maven.home" ); 351 352 if ( mavenHome != null ) 353 { 354 System.setProperty( "maven.home", new File( mavenHome ).getAbsolutePath() ); 355 } 356 } 357 358 void cli( CliRequest cliRequest ) 359 throws Exception 360 { 361 // 362 // Parsing errors can happen during the processing of the arguments and we prefer not having to check if 363 // the logger is null and construct this so we can use an SLF4J logger everywhere. 364 // 365 slf4jLogger = new Slf4jStdoutLogger(); 366 367 CLIManager cliManager = new CLIManager(); 368 369 List<String> args = new ArrayList<String>(); 370 371 try 372 { 373 File configFile = new File( cliRequest.multiModuleProjectDirectory, ".mvn/maven.config" ); 374 375 if ( configFile.isFile() ) 376 { 377 for ( String arg : Files.toString( configFile, Charsets.UTF_8 ).split( "\\s+" ) ) 378 { 379 args.add( arg ); 380 } 381 382 CommandLine config = cliManager.parse( args.toArray( new String[args.size()] ) ); 383 List<?> unrecongized = config.getArgList(); 384 if ( !unrecongized.isEmpty() ) 385 { 386 throw new ParseException( "Unrecognized maven.config entries: " + unrecongized ); 387 } 388 } 389 } 390 catch ( ParseException e ) 391 { 392 System.err.println( "Unable to parse maven.config: " + e.getMessage() ); 393 cliManager.displayHelp( System.out ); 394 throw e; 395 } 396 397 try 398 { 399 args.addAll( 0, Arrays.asList( cliRequest.args ) ); 400 cliRequest.commandLine = cliManager.parse( args.toArray( new String[args.size()] ) ); 401 } 402 catch ( ParseException e ) 403 { 404 System.err.println( "Unable to parse command line options: " + e.getMessage() ); 405 cliManager.displayHelp( System.out ); 406 throw e; 407 } 408 409 if ( cliRequest.commandLine.hasOption( CLIManager.HELP ) ) 410 { 411 cliManager.displayHelp( System.out ); 412 throw new ExitException( 0 ); 413 } 414 415 if ( cliRequest.commandLine.hasOption( CLIManager.VERSION ) ) 416 { 417 System.out.println( CLIReportingUtils.showVersion() ); 418 throw new ExitException( 0 ); 419 } 420 } 421 422 /** 423 * configure logging 424 */ 425 private void logging( CliRequest cliRequest ) 426 { 427 cliRequest.debug = cliRequest.commandLine.hasOption( CLIManager.DEBUG ); 428 cliRequest.quiet = !cliRequest.debug && cliRequest.commandLine.hasOption( CLIManager.QUIET ); 429 cliRequest.showErrors = cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.ERRORS ); 430 431 slf4jLoggerFactory = LoggerFactory.getILoggerFactory(); 432 Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration( slf4jLoggerFactory ); 433 434 if ( cliRequest.debug ) 435 { 436 cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_DEBUG ); 437 slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.DEBUG ); 438 } 439 else if ( cliRequest.quiet ) 440 { 441 cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_ERROR ); 442 slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.ERROR ); 443 } 444 // else fall back to default log level specified in conf 445 // see http://jira.codehaus.org/browse/MNG-2570 446 447 if ( cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) ) 448 { 449 File logFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.LOG_FILE ) ); 450 logFile = resolveFile( logFile, cliRequest.workingDirectory ); 451 452 // redirect stdout and stderr to file 453 try 454 { 455 PrintStream ps = new PrintStream( new FileOutputStream( logFile ) ); 456 System.setOut( ps ); 457 System.setErr( ps ); 458 } 459 catch ( FileNotFoundException e ) 460 { 461 // 462 // Ignore 463 // 464 } 465 } 466 467 slf4jConfiguration.activate(); 468 469 plexusLoggerManager = new Slf4jLoggerManager(); 470 slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() ); 471 } 472 473 private void version( CliRequest cliRequest ) 474 { 475 if ( cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.SHOW_VERSION ) ) 476 { 477 System.out.println( CLIReportingUtils.showVersion() ); 478 } 479 } 480 481 private void commands( CliRequest cliRequest ) 482 { 483 if ( cliRequest.showErrors ) 484 { 485 slf4jLogger.info( "Error stacktraces are turned on." ); 486 } 487 488 if ( MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals( cliRequest.request.getGlobalChecksumPolicy() ) ) 489 { 490 slf4jLogger.info( "Disabling strict checksum verification on all artifact downloads." ); 491 } 492 else if ( MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals( cliRequest.request.getGlobalChecksumPolicy() ) ) 493 { 494 slf4jLogger.info( "Enabling strict checksum verification on all artifact downloads." ); 495 } 496 } 497 498 private void properties( CliRequest cliRequest ) 499 { 500 populateProperties( cliRequest.commandLine, cliRequest.systemProperties, cliRequest.userProperties ); 501 } 502 503 private PlexusContainer container( CliRequest cliRequest ) 504 throws Exception 505 { 506 if ( cliRequest.classWorld == null ) 507 { 508 cliRequest.classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() ); 509 } 510 511 ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" ); 512 if ( coreRealm == null ) 513 { 514 coreRealm = cliRequest.classWorld.getRealms().iterator().next(); 515 } 516 517 List<File> extClassPath = parseExtClasspath( cliRequest ); 518 519 CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom( coreRealm ); 520 List<CoreExtensionEntry> extensions = 521 loadCoreExtensions( cliRequest, coreRealm, coreEntry.getExportedArtifacts() ); 522 523 ClassRealm containerRealm = setupContainerRealm( cliRequest.classWorld, coreRealm, extClassPath, extensions ); 524 525 ContainerConfiguration cc = new DefaultContainerConfiguration() 526 .setClassWorld( cliRequest.classWorld ) 527 .setRealm( containerRealm ) 528 .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) 529 .setAutoWiring( true ) 530 .setName( "maven" ); 531 532 Set<String> exportedArtifacts = new HashSet<String>( coreEntry.getExportedArtifacts() ); 533 Set<String> exportedPackages = new HashSet<String>( coreEntry.getExportedPackages() ); 534 for ( CoreExtensionEntry extension : extensions ) 535 { 536 exportedArtifacts.addAll( extension.getExportedArtifacts() ); 537 exportedPackages.addAll( extension.getExportedPackages() ); 538 } 539 540 final CoreExports exports = new CoreExports( containerRealm, exportedArtifacts, exportedPackages ); 541 542 DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule() 543 { 544 @Override 545 protected void configure() 546 { 547 bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory ); 548 bind( CoreExports.class ).toInstance( exports ); 549 } 550 } ); 551 552 // NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups 553 container.setLookupRealm( null ); 554 555 container.setLoggerManager( plexusLoggerManager ); 556 557 for ( CoreExtensionEntry extension : extensions ) 558 { 559 container.discoverComponents( extension.getClassRealm() ); 560 } 561 562 customizeContainer( container ); 563 564 container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() ); 565 566 Thread.currentThread().setContextClassLoader( container.getContainerRealm() ); 567 568 eventSpyDispatcher = container.lookup( EventSpyDispatcher.class ); 569 570 DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext(); 571 Map<String, Object> data = eventSpyContext.getData(); 572 data.put( "plexus", container ); 573 data.put( "workingDirectory", cliRequest.workingDirectory ); 574 data.put( "systemProperties", cliRequest.systemProperties ); 575 data.put( "userProperties", cliRequest.userProperties ); 576 data.put( "versionProperties", CLIReportingUtils.getBuildProperties() ); 577 eventSpyDispatcher.init( eventSpyContext ); 578 579 // refresh logger in case container got customized by spy 580 slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() ); 581 582 maven = container.lookup( Maven.class ); 583 584 executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class ); 585 586 modelProcessor = createModelProcessor( container ); 587 588 configurationProcessors = container.lookupMap( ConfigurationProcessor.class ); 589 590 toolchainsBuilder = container.lookup( ToolchainsBuilder.class ); 591 592 dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" ); 593 594 return container; 595 } 596 597 private List<CoreExtensionEntry> loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm, 598 Set<String> providedArtifacts ) 599 { 600 if ( cliRequest.multiModuleProjectDirectory == null ) 601 { 602 return Collections.emptyList(); 603 } 604 605 File extensionsFile = new File( cliRequest.multiModuleProjectDirectory, EXTENSIONS_FILENAME ); 606 if ( !extensionsFile.isFile() ) 607 { 608 return Collections.emptyList(); 609 } 610 611 try 612 { 613 List<CoreExtension> extensions = readCoreExtensionsDescriptor( extensionsFile ); 614 if ( extensions.isEmpty() ) 615 { 616 return Collections.emptyList(); 617 } 618 619 ContainerConfiguration cc = new DefaultContainerConfiguration() // 620 .setClassWorld( cliRequest.classWorld ) // 621 .setRealm( containerRealm ) // 622 .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) // 623 .setAutoWiring( true ) // 624 .setName( "maven" ); 625 626 DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule() 627 { 628 @Override 629 protected void configure() 630 { 631 bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory ); 632 } 633 } ); 634 635 try 636 { 637 container.setLookupRealm( null ); 638 639 container.setLoggerManager( plexusLoggerManager ); 640 641 container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() ); 642 643 Thread.currentThread().setContextClassLoader( container.getContainerRealm() ); 644 645 executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class ); 646 647 configurationProcessors = container.lookupMap( ConfigurationProcessor.class ); 648 649 configure( cliRequest ); 650 651 MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request ); 652 653 request = populateRequest( cliRequest, request ); 654 655 request = executionRequestPopulator.populateDefaults( request ); 656 657 BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class ); 658 659 return resolver.loadCoreExtensions( request, providedArtifacts, extensions ); 660 } 661 finally 662 { 663 executionRequestPopulator = null; 664 container.dispose(); 665 } 666 } 667 catch ( RuntimeException e ) 668 { 669 // runtime exceptions are most likely bugs in maven, let them bubble up to the user 670 throw e; 671 } 672 catch ( Exception e ) 673 { 674 slf4jLogger.warn( "Failed to read extensions descriptor " + extensionsFile + ": " + e.getMessage() ); 675 } 676 return Collections.emptyList(); 677 } 678 679 private List<CoreExtension> readCoreExtensionsDescriptor( File extensionsFile ) 680 throws IOException, XmlPullParserException 681 { 682 CoreExtensionsXpp3Reader parser = new CoreExtensionsXpp3Reader(); 683 InputStream is = null; 684 try 685 { 686 is = new BufferedInputStream( new FileInputStream( extensionsFile ) ); 687 return parser.read( is ).getExtensions(); 688 } 689 finally 690 { 691 IOUtil.close( is ); 692 } 693 } 694 695 private ClassRealm setupContainerRealm( ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath, 696 List<CoreExtensionEntry> extensions ) 697 throws Exception 698 { 699 if ( !extClassPath.isEmpty() || !extensions.isEmpty() ) 700 { 701 ClassRealm extRealm = classWorld.newRealm( "maven.ext", null ); 702 703 extRealm.setParentRealm( coreRealm ); 704 705 slf4jLogger.debug( "Populating class realm " + extRealm.getId() ); 706 707 for ( File file : extClassPath ) 708 { 709 slf4jLogger.debug( " Included " + file ); 710 711 extRealm.addURL( file.toURI().toURL() ); 712 } 713 714 for ( CoreExtensionEntry entry : reverse( extensions ) ) 715 { 716 Set<String> exportedPackages = entry.getExportedPackages(); 717 ClassRealm realm = entry.getClassRealm(); 718 for ( String exportedPackage : exportedPackages ) 719 { 720 extRealm.importFrom( realm, exportedPackage ); 721 } 722 if ( exportedPackages.isEmpty() ) 723 { 724 // sisu uses realm imports to establish component visibility 725 extRealm.importFrom( realm, realm.getId() ); 726 } 727 } 728 729 return extRealm; 730 } 731 732 return coreRealm; 733 } 734 735 private static <T> List<T> reverse( List<T> list ) 736 { 737 List<T> copy = new ArrayList<T>( list ); 738 Collections.reverse( copy ); 739 return copy; 740 } 741 742 private List<File> parseExtClasspath( CliRequest cliRequest ) 743 { 744 String extClassPath = cliRequest.userProperties.getProperty( EXT_CLASS_PATH ); 745 if ( extClassPath == null ) 746 { 747 extClassPath = cliRequest.systemProperties.getProperty( EXT_CLASS_PATH ); 748 } 749 750 List<File> jars = new ArrayList<File>(); 751 752 if ( StringUtils.isNotEmpty( extClassPath ) ) 753 { 754 for ( String jar : StringUtils.split( extClassPath, File.pathSeparator ) ) 755 { 756 File file = resolveFile( new File( jar ), cliRequest.workingDirectory ); 757 758 slf4jLogger.debug( " Included " + file ); 759 760 jars.add( file ); 761 } 762 } 763 764 return jars; 765 } 766 767 // 768 // This should probably be a separate tool and not be baked into Maven. 769 // 770 private void encryption( CliRequest cliRequest ) 771 throws Exception 772 { 773 if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_MASTER_PASSWORD ) ) 774 { 775 String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_MASTER_PASSWORD ); 776 777 if ( passwd == null ) 778 { 779 Console cons = System.console(); 780 char[] password = ( cons == null ) ? null : cons.readPassword( "Master password: " ); 781 if ( password != null ) 782 { 783 // Cipher uses Strings 784 passwd = String.copyValueOf( password ); 785 786 // Sun/Oracle advises to empty the char array 787 java.util.Arrays.fill( password, ' ' ); 788 } 789 } 790 791 DefaultPlexusCipher cipher = new DefaultPlexusCipher(); 792 793 System.out.println( cipher.encryptAndDecorate( passwd, 794 DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) ); 795 796 throw new ExitException( 0 ); 797 } 798 else if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_PASSWORD ) ) 799 { 800 String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_PASSWORD ); 801 802 if ( passwd == null ) 803 { 804 Console cons = System.console(); 805 char[] password = ( cons == null ) ? null : cons.readPassword( "Password: " ); 806 if ( password != null ) 807 { 808 // Cipher uses Strings 809 passwd = String.copyValueOf( password ); 810 811 // Sun/Oracle advises to empty the char array 812 java.util.Arrays.fill( password, ' ' ); 813 } 814 } 815 816 String configurationFile = dispatcher.getConfigurationFile(); 817 818 if ( configurationFile.startsWith( "~" ) ) 819 { 820 configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 ); 821 } 822 823 String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile ); 824 825 String master = null; 826 827 SettingsSecurity sec = SecUtil.read( file, true ); 828 if ( sec != null ) 829 { 830 master = sec.getMaster(); 831 } 832 833 if ( master == null ) 834 { 835 throw new IllegalStateException( "Master password is not set in the setting security file: " + file ); 836 } 837 838 DefaultPlexusCipher cipher = new DefaultPlexusCipher(); 839 String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ); 840 System.out.println( cipher.encryptAndDecorate( passwd, masterPasswd ) ); 841 842 throw new ExitException( 0 ); 843 } 844 } 845 846 private void repository( CliRequest cliRequest ) 847 throws Exception 848 { 849 if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_LOCAL_REPOSITORY ) 850 || Boolean.getBoolean( "maven.legacyLocalRepo" ) ) 851 { 852 cliRequest.request.setUseLegacyLocalRepository( true ); 853 } 854 } 855 856 private int execute( CliRequest cliRequest ) throws MavenExecutionRequestPopulationException 857 { 858 MavenExecutionRequest request = executionRequestPopulator.populateDefaults( cliRequest.request ); 859 860 eventSpyDispatcher.onEvent( request ); 861 862 MavenExecutionResult result = maven.execute( request ); 863 864 eventSpyDispatcher.onEvent( result ); 865 866 eventSpyDispatcher.close(); 867 868 if ( result.hasExceptions() ) 869 { 870 ExceptionHandler handler = new DefaultExceptionHandler(); 871 872 Map<String, String> references = new LinkedHashMap<String, String>(); 873 874 MavenProject project = null; 875 876 for ( Throwable exception : result.getExceptions() ) 877 { 878 ExceptionSummary summary = handler.handleException( exception ); 879 880 logSummary( summary, references, "", cliRequest.showErrors ); 881 882 if ( project == null && exception instanceof LifecycleExecutionException ) 883 { 884 project = ( (LifecycleExecutionException) exception ).getProject(); 885 } 886 } 887 888 slf4jLogger.error( "" ); 889 890 if ( !cliRequest.showErrors ) 891 { 892 slf4jLogger.error( "To see the full stack trace of the errors, re-run Maven with the -e switch." ); 893 } 894 if ( !slf4jLogger.isDebugEnabled() ) 895 { 896 slf4jLogger.error( "Re-run Maven using the -X switch to enable full debug logging." ); 897 } 898 899 if ( !references.isEmpty() ) 900 { 901 slf4jLogger.error( "" ); 902 slf4jLogger.error( "For more information about the errors and possible solutions" 903 + ", please read the following articles:" ); 904 905 for ( Map.Entry<String, String> entry : references.entrySet() ) 906 { 907 slf4jLogger.error( entry.getValue() + " " + entry.getKey() ); 908 } 909 } 910 911 if ( project != null && !project.equals( result.getTopologicallySortedProjects().get( 0 ) ) ) 912 { 913 slf4jLogger.error( "" ); 914 slf4jLogger.error( "After correcting the problems, you can resume the build with the command" ); 915 slf4jLogger.error( " mvn <goals> -rf :" + project.getArtifactId() ); 916 } 917 918 if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) ) 919 { 920 slf4jLogger.info( "Build failures were ignored." ); 921 922 return 0; 923 } 924 else 925 { 926 return 1; 927 } 928 } 929 else 930 { 931 return 0; 932 } 933 } 934 935 private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent, 936 boolean showErrors ) 937 { 938 String referenceKey = ""; 939 940 if ( StringUtils.isNotEmpty( summary.getReference() ) ) 941 { 942 referenceKey = references.get( summary.getReference() ); 943 if ( referenceKey == null ) 944 { 945 referenceKey = "[Help " + ( references.size() + 1 ) + "]"; 946 references.put( summary.getReference(), referenceKey ); 947 } 948 } 949 950 String msg = summary.getMessage(); 951 952 if ( StringUtils.isNotEmpty( referenceKey ) ) 953 { 954 if ( msg.indexOf( '\n' ) < 0 ) 955 { 956 msg += " -> " + referenceKey; 957 } 958 else 959 { 960 msg += "\n-> " + referenceKey; 961 } 962 } 963 964 String[] lines = msg.split( "(\r\n)|(\r)|(\n)" ); 965 966 for ( int i = 0; i < lines.length; i++ ) 967 { 968 String line = indent + lines[i].trim(); 969 970 if ( ( i == lines.length - 1 ) 971 && ( showErrors || ( summary.getException() instanceof InternalErrorException ) ) ) 972 { 973 slf4jLogger.error( line, summary.getException() ); 974 } 975 else 976 { 977 slf4jLogger.error( line ); 978 } 979 } 980 981 indent += " "; 982 983 for ( ExceptionSummary child : summary.getChildren() ) 984 { 985 logSummary( child, references, indent, showErrors ); 986 } 987 } 988 989 @SuppressWarnings( "checkstyle:methodlength" ) 990 private void configure( CliRequest cliRequest ) 991 throws Exception 992 { 993 // 994 // This is not ideal but there are events specifically for configuration from the CLI which I don't 995 // believe are really valid but there are ITs which assert the right events are published so this 996 // needs to be supported so the EventSpyDispatcher needs to be put in the CliRequest so that 997 // it can be accessed by configuration processors. 998 // 999 cliRequest.request.setEventSpyDispatcher( eventSpyDispatcher ); 1000 1001 // 1002 // We expect at most 2 implementations to be available. The SettingsXmlConfigurationProcessor implementation 1003 // is always available in the core and likely always will be, but we may have another ConfigurationProcessor 1004 // present supplied by the user. The rule is that we only allow the execution of one ConfigurationProcessor. 1005 // If there is more than one then we execute the one supplied by the user, otherwise we execute the 1006 // the default SettingsXmlConfigurationProcessor. 1007 // 1008 int userSuppliedConfigurationProcessorCount = configurationProcessors.size() - 1; 1009 1010 if ( userSuppliedConfigurationProcessorCount == 0 ) 1011 { 1012 // 1013 // Our settings.xml source is historically how we have configured Maven from the CLI so we are going to 1014 // have to honour its existence forever. So let's run it. 1015 // 1016 configurationProcessors.get( SettingsXmlConfigurationProcessor.HINT ).process( cliRequest ); 1017 } 1018 else if ( userSuppliedConfigurationProcessorCount == 1 ) 1019 { 1020 // 1021 // Run the user supplied ConfigurationProcessor 1022 // 1023 for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() ) 1024 { 1025 String hint = entry.getKey(); 1026 if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) ) 1027 { 1028 ConfigurationProcessor configurationProcessor = entry.getValue(); 1029 configurationProcessor.process( cliRequest ); 1030 } 1031 } 1032 } 1033 else if ( userSuppliedConfigurationProcessorCount > 1 ) 1034 { 1035 // 1036 // There are too many ConfigurationProcessors so we don't know which one to run so report the error. 1037 // 1038 StringBuffer sb = new StringBuffer( 1039 String.format( "\nThere can only be one user supplied ConfigurationProcessor, there are %s:\n\n", 1040 userSuppliedConfigurationProcessorCount ) ); 1041 for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() ) 1042 { 1043 String hint = entry.getKey(); 1044 if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) ) 1045 { 1046 ConfigurationProcessor configurationProcessor = entry.getValue(); 1047 sb.append( String.format( "%s\n", configurationProcessor.getClass().getName() ) ); 1048 } 1049 } 1050 sb.append( String.format( "\n" ) ); 1051 throw new Exception( sb.toString() ); 1052 } 1053 } 1054 1055 @SuppressWarnings( "checkstyle:methodlength" ) 1056 private void toolchains( CliRequest cliRequest ) 1057 throws Exception 1058 { 1059 File userToolchainsFile; 1060 1061 if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ) 1062 { 1063 userToolchainsFile = 1064 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ); 1065 userToolchainsFile = resolveFile( userToolchainsFile, cliRequest.workingDirectory ); 1066 1067 if ( !userToolchainsFile.isFile() ) 1068 { 1069 throw new FileNotFoundException( "The specified user toolchains file does not exist: " 1070 + userToolchainsFile ); 1071 } 1072 } 1073 else 1074 { 1075 userToolchainsFile = DEFAULT_USER_TOOLCHAINS_FILE; 1076 } 1077 1078 File globalToolchainsFile; 1079 1080 if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) ) 1081 { 1082 globalToolchainsFile = 1083 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) ); 1084 globalToolchainsFile = resolveFile( globalToolchainsFile, cliRequest.workingDirectory ); 1085 1086 if ( !globalToolchainsFile.isFile() ) 1087 { 1088 throw new FileNotFoundException( "The specified global toolchains file does not exist: " 1089 + globalToolchainsFile ); 1090 } 1091 } 1092 else 1093 { 1094 globalToolchainsFile = DEFAULT_GLOBAL_TOOLCHAINS_FILE; 1095 } 1096 1097 cliRequest.request.setGlobalToolchainsFile( globalToolchainsFile ); 1098 cliRequest.request.setUserToolchainsFile( userToolchainsFile ); 1099 1100 DefaultToolchainsBuildingRequest toolchainsRequest = new DefaultToolchainsBuildingRequest(); 1101 if ( globalToolchainsFile.isFile() ) 1102 { 1103 toolchainsRequest.setGlobalToolchainsSource( new FileSource( globalToolchainsFile ) ); 1104 } 1105 if ( userToolchainsFile.isFile() ) 1106 { 1107 toolchainsRequest.setUserToolchainsSource( new FileSource( userToolchainsFile ) ); 1108 } 1109 1110 eventSpyDispatcher.onEvent( toolchainsRequest ); 1111 1112 slf4jLogger.debug( "Reading global toolchains from " 1113 + getLocation( toolchainsRequest.getGlobalToolchainsSource(), globalToolchainsFile ) ); 1114 slf4jLogger.debug( "Reading user toolchains from " 1115 + getLocation( toolchainsRequest.getUserToolchainsSource(), userToolchainsFile ) ); 1116 1117 ToolchainsBuildingResult toolchainsResult = toolchainsBuilder.build( toolchainsRequest ); 1118 1119 eventSpyDispatcher.onEvent( toolchainsRequest ); 1120 1121 executionRequestPopulator.populateFromToolchains( cliRequest.request, 1122 toolchainsResult.getEffectiveToolchains() ); 1123 1124 if ( !toolchainsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled() ) 1125 { 1126 slf4jLogger.warn( "" ); 1127 slf4jLogger.warn( "Some problems were encountered while building the effective toolchains" ); 1128 1129 for ( Problem problem : toolchainsResult.getProblems() ) 1130 { 1131 slf4jLogger.warn( problem.getMessage() + " @ " + problem.getLocation() ); 1132 } 1133 1134 slf4jLogger.warn( "" ); 1135 } 1136 } 1137 1138 private Object getLocation( Source source, File defaultLocation ) 1139 { 1140 if ( source != null ) 1141 { 1142 return source.getLocation(); 1143 } 1144 return defaultLocation; 1145 } 1146 1147 private MavenExecutionRequest populateRequest( CliRequest cliRequest ) 1148 { 1149 return populateRequest( cliRequest, cliRequest.request ); 1150 } 1151 1152 private MavenExecutionRequest populateRequest( CliRequest cliRequest, MavenExecutionRequest request ) 1153 { 1154 CommandLine commandLine = cliRequest.commandLine; 1155 String workingDirectory = cliRequest.workingDirectory; 1156 boolean quiet = cliRequest.quiet; 1157 boolean showErrors = cliRequest.showErrors; 1158 1159 String[] deprecatedOptions = { "up", "npu", "cpu", "npr" }; 1160 for ( String deprecatedOption : deprecatedOptions ) 1161 { 1162 if ( commandLine.hasOption( deprecatedOption ) ) 1163 { 1164 slf4jLogger.warn( "Command line option -" + deprecatedOption 1165 + " is deprecated and will be removed in future Maven versions." ); 1166 } 1167 } 1168 1169 // ---------------------------------------------------------------------- 1170 // Now that we have everything that we need we will fire up plexus and 1171 // bring the maven component to life for use. 1172 // ---------------------------------------------------------------------- 1173 1174 if ( commandLine.hasOption( CLIManager.BATCH_MODE ) ) 1175 { 1176 request.setInteractiveMode( false ); 1177 } 1178 1179 boolean noSnapshotUpdates = false; 1180 if ( commandLine.hasOption( CLIManager.SUPRESS_SNAPSHOT_UPDATES ) ) 1181 { 1182 noSnapshotUpdates = true; 1183 } 1184 1185 // ---------------------------------------------------------------------- 1186 // 1187 // ---------------------------------------------------------------------- 1188 1189 @SuppressWarnings( "unchecked" ) 1190 List<String> goals = commandLine.getArgList(); 1191 1192 boolean recursive = true; 1193 1194 // this is the default behavior. 1195 String reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST; 1196 1197 if ( commandLine.hasOption( CLIManager.NON_RECURSIVE ) ) 1198 { 1199 recursive = false; 1200 } 1201 1202 if ( commandLine.hasOption( CLIManager.FAIL_FAST ) ) 1203 { 1204 reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST; 1205 } 1206 else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) ) 1207 { 1208 reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_AT_END; 1209 } 1210 else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) ) 1211 { 1212 reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_NEVER; 1213 } 1214 1215 if ( commandLine.hasOption( CLIManager.OFFLINE ) ) 1216 { 1217 request.setOffline( true ); 1218 } 1219 1220 boolean updateSnapshots = false; 1221 1222 if ( commandLine.hasOption( CLIManager.UPDATE_SNAPSHOTS ) ) 1223 { 1224 updateSnapshots = true; 1225 } 1226 1227 String globalChecksumPolicy = null; 1228 1229 if ( commandLine.hasOption( CLIManager.CHECKSUM_FAILURE_POLICY ) ) 1230 { 1231 globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_FAIL; 1232 } 1233 else if ( commandLine.hasOption( CLIManager.CHECKSUM_WARNING_POLICY ) ) 1234 { 1235 globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_WARN; 1236 } 1237 1238 File baseDirectory = new File( workingDirectory, "" ).getAbsoluteFile(); 1239 1240 // ---------------------------------------------------------------------- 1241 // Profile Activation 1242 // ---------------------------------------------------------------------- 1243 1244 List<String> activeProfiles = new ArrayList<String>(); 1245 1246 List<String> inactiveProfiles = new ArrayList<String>(); 1247 1248 if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) ) 1249 { 1250 String[] profileOptionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES ); 1251 if ( profileOptionValues != null ) 1252 { 1253 for ( String profileOptionValue : profileOptionValues ) 1254 { 1255 StringTokenizer profileTokens = new StringTokenizer( profileOptionValue, "," ); 1256 1257 while ( profileTokens.hasMoreTokens() ) 1258 { 1259 String profileAction = profileTokens.nextToken().trim(); 1260 1261 if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) ) 1262 { 1263 inactiveProfiles.add( profileAction.substring( 1 ) ); 1264 } 1265 else if ( profileAction.startsWith( "+" ) ) 1266 { 1267 activeProfiles.add( profileAction.substring( 1 ) ); 1268 } 1269 else 1270 { 1271 activeProfiles.add( profileAction ); 1272 } 1273 } 1274 } 1275 } 1276 } 1277 1278 TransferListener transferListener; 1279 1280 if ( quiet ) 1281 { 1282 transferListener = new QuietMavenTransferListener(); 1283 } 1284 else if ( request.isInteractiveMode() && !cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) ) 1285 { 1286 // 1287 // If we're logging to a file then we don't want the console transfer listener as it will spew 1288 // download progress all over the place 1289 // 1290 transferListener = getConsoleTransferListener(); 1291 } 1292 else 1293 { 1294 transferListener = getBatchTransferListener(); 1295 } 1296 1297 ExecutionListener executionListener = new ExecutionEventLogger(); 1298 if ( eventSpyDispatcher != null ) 1299 { 1300 executionListener = eventSpyDispatcher.chainListener( executionListener ); 1301 } 1302 1303 String alternatePomFile = null; 1304 if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) ) 1305 { 1306 alternatePomFile = commandLine.getOptionValue( CLIManager.ALTERNATE_POM_FILE ); 1307 } 1308 1309 File userToolchainsFile; 1310 if ( commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ) 1311 { 1312 userToolchainsFile = new File( commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ); 1313 userToolchainsFile = resolveFile( userToolchainsFile, workingDirectory ); 1314 } 1315 else 1316 { 1317 userToolchainsFile = MavenCli.DEFAULT_USER_TOOLCHAINS_FILE; 1318 } 1319 1320 request.setBaseDirectory( baseDirectory ).setGoals( goals ) 1321 .setSystemProperties( cliRequest.systemProperties ) 1322 .setUserProperties( cliRequest.userProperties ) 1323 .setReactorFailureBehavior( reactorFailureBehaviour ) // default: fail fast 1324 .setRecursive( recursive ) // default: true 1325 .setShowErrors( showErrors ) // default: false 1326 .addActiveProfiles( activeProfiles ) // optional 1327 .addInactiveProfiles( inactiveProfiles ) // optional 1328 .setExecutionListener( executionListener ) 1329 .setTransferListener( transferListener ) // default: batch mode which goes along with interactive 1330 .setUpdateSnapshots( updateSnapshots ) // default: false 1331 .setNoSnapshotUpdates( noSnapshotUpdates ) // default: false 1332 .setGlobalChecksumPolicy( globalChecksumPolicy ) // default: warn 1333 .setMultiModuleProjectDirectory( cliRequest.multiModuleProjectDirectory ); 1334 1335 if ( alternatePomFile != null ) 1336 { 1337 File pom = resolveFile( new File( alternatePomFile ), workingDirectory ); 1338 if ( pom.isDirectory() ) 1339 { 1340 pom = new File( pom, "pom.xml" ); 1341 } 1342 1343 request.setPom( pom ); 1344 } 1345 else if ( modelProcessor != null ) 1346 { 1347 File pom = modelProcessor.locatePom( baseDirectory ); 1348 1349 if ( pom.isFile() ) 1350 { 1351 request.setPom( pom ); 1352 } 1353 } 1354 1355 if ( ( request.getPom() != null ) && ( request.getPom().getParentFile() != null ) ) 1356 { 1357 request.setBaseDirectory( request.getPom().getParentFile() ); 1358 } 1359 1360 if ( commandLine.hasOption( CLIManager.RESUME_FROM ) ) 1361 { 1362 request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) ); 1363 } 1364 1365 if ( commandLine.hasOption( CLIManager.PROJECT_LIST ) ) 1366 { 1367 String[] projectOptionValues = commandLine.getOptionValues( CLIManager.PROJECT_LIST ); 1368 1369 List<String> inclProjects = new ArrayList<String>(); 1370 List<String> exclProjects = new ArrayList<String>(); 1371 1372 if ( projectOptionValues != null ) 1373 { 1374 for ( String projectOptionValue : projectOptionValues ) 1375 { 1376 StringTokenizer projectTokens = new StringTokenizer( projectOptionValue, "," ); 1377 1378 while ( projectTokens.hasMoreTokens() ) 1379 { 1380 String projectAction = projectTokens.nextToken().trim(); 1381 1382 if ( projectAction.startsWith( "-" ) || projectAction.startsWith( "!" ) ) 1383 { 1384 exclProjects.add( projectAction.substring( 1 ) ); 1385 } 1386 else if ( projectAction.startsWith( "+" ) ) 1387 { 1388 inclProjects.add( projectAction.substring( 1 ) ); 1389 } 1390 else 1391 { 1392 inclProjects.add( projectAction ); 1393 } 1394 } 1395 } 1396 } 1397 1398 request.setSelectedProjects( inclProjects ); 1399 request.setExcludedProjects( exclProjects ); 1400 } 1401 1402 if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) 1403 && !commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) ) 1404 { 1405 request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM ); 1406 } 1407 else if ( !commandLine.hasOption( CLIManager.ALSO_MAKE ) 1408 && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) ) 1409 { 1410 request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM ); 1411 } 1412 else if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) 1413 && commandLine.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) ) 1414 { 1415 request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_BOTH ); 1416 } 1417 1418 String localRepoProperty = request.getUserProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY ); 1419 1420 if ( localRepoProperty == null ) 1421 { 1422 localRepoProperty = request.getSystemProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY ); 1423 } 1424 1425 if ( localRepoProperty != null ) 1426 { 1427 request.setLocalRepositoryPath( localRepoProperty ); 1428 } 1429 1430 request.setCacheNotFound( true ); 1431 request.setCacheTransferError( false ); 1432 1433 // 1434 // Builder, concurrency and parallelism 1435 // 1436 // We preserve the existing methods for builder selection which is to look for various inputs in the threading 1437 // configuration. We don't have an easy way to allow a pluggable builder to provide its own configuration 1438 // parameters but this is sufficient for now. Ultimately we want components like Builders to provide a way to 1439 // extend the command line to accept its own configuration parameters. 1440 // 1441 final String threadConfiguration = commandLine.hasOption( CLIManager.THREADS ) 1442 ? commandLine.getOptionValue( CLIManager.THREADS ) 1443 : request.getSystemProperties().getProperty( 1444 MavenCli.THREADS_DEPRECATED ); // TODO: Remove this setting. Note that the int-tests use it 1445 1446 if ( threadConfiguration != null ) 1447 { 1448 // 1449 // Default to the standard multithreaded builder 1450 // 1451 request.setBuilderId( "multithreaded" ); 1452 1453 if ( threadConfiguration.contains( "C" ) ) 1454 { 1455 request.setDegreeOfConcurrency( calculateDegreeOfConcurrencyWithCoreMultiplier( threadConfiguration ) ); 1456 } 1457 else 1458 { 1459 request.setDegreeOfConcurrency( Integer.valueOf( threadConfiguration ) ); 1460 } 1461 } 1462 1463 // 1464 // Allow the builder to be overriden by the user if requested. The builders are now pluggable. 1465 // 1466 if ( commandLine.hasOption( CLIManager.BUILDER ) ) 1467 { 1468 request.setBuilderId( commandLine.getOptionValue( CLIManager.BUILDER ) ); 1469 } 1470 1471 return request; 1472 } 1473 1474 int calculateDegreeOfConcurrencyWithCoreMultiplier( String threadConfiguration ) 1475 { 1476 int procs = Runtime.getRuntime().availableProcessors(); 1477 return (int) ( Float.valueOf( threadConfiguration.replace( "C", "" ) ) * procs ); 1478 } 1479 1480 static File resolveFile( File file, String workingDirectory ) 1481 { 1482 if ( file == null ) 1483 { 1484 return null; 1485 } 1486 else if ( file.isAbsolute() ) 1487 { 1488 return file; 1489 } 1490 else if ( file.getPath().startsWith( File.separator ) ) 1491 { 1492 // drive-relative Windows path 1493 return file.getAbsoluteFile(); 1494 } 1495 else 1496 { 1497 return new File( workingDirectory, file.getPath() ).getAbsoluteFile(); 1498 } 1499 } 1500 1501 // ---------------------------------------------------------------------- 1502 // System properties handling 1503 // ---------------------------------------------------------------------- 1504 1505 static void populateProperties( CommandLine commandLine, Properties systemProperties, Properties userProperties ) 1506 { 1507 EnvironmentUtils.addEnvVars( systemProperties ); 1508 1509 // ---------------------------------------------------------------------- 1510 // Options that are set on the command line become system properties 1511 // and therefore are set in the session properties. System properties 1512 // are most dominant. 1513 // ---------------------------------------------------------------------- 1514 1515 if ( commandLine.hasOption( CLIManager.SET_SYSTEM_PROPERTY ) ) 1516 { 1517 String[] defStrs = commandLine.getOptionValues( CLIManager.SET_SYSTEM_PROPERTY ); 1518 1519 if ( defStrs != null ) 1520 { 1521 for ( String defStr : defStrs ) 1522 { 1523 setCliProperty( defStr, userProperties ); 1524 } 1525 } 1526 } 1527 1528 SystemProperties.addSystemProperties( systemProperties ); 1529 1530 // ---------------------------------------------------------------------- 1531 // Properties containing info about the currently running version of Maven 1532 // These override any corresponding properties set on the command line 1533 // ---------------------------------------------------------------------- 1534 1535 Properties buildProperties = CLIReportingUtils.getBuildProperties(); 1536 1537 String mavenVersion = buildProperties.getProperty( CLIReportingUtils.BUILD_VERSION_PROPERTY ); 1538 systemProperties.setProperty( "maven.version", mavenVersion ); 1539 1540 String mavenBuildVersion = CLIReportingUtils.createMavenVersionString( buildProperties ); 1541 systemProperties.setProperty( "maven.build.version", mavenBuildVersion ); 1542 } 1543 1544 private static void setCliProperty( String property, Properties properties ) 1545 { 1546 String name; 1547 1548 String value; 1549 1550 int i = property.indexOf( "=" ); 1551 1552 if ( i <= 0 ) 1553 { 1554 name = property.trim(); 1555 1556 value = "true"; 1557 } 1558 else 1559 { 1560 name = property.substring( 0, i ).trim(); 1561 1562 value = property.substring( i + 1 ); 1563 } 1564 1565 properties.setProperty( name, value ); 1566 1567 // ---------------------------------------------------------------------- 1568 // I'm leaving the setting of system properties here as not to break 1569 // the SystemPropertyProfileActivator. This won't harm embedding. jvz. 1570 // ---------------------------------------------------------------------- 1571 1572 System.setProperty( name, value ); 1573 } 1574 1575 static class ExitException 1576 extends Exception 1577 { 1578 @SuppressWarnings( "checkstyle:visibilitymodifier" ) 1579 public int exitCode; 1580 1581 public ExitException( int exitCode ) 1582 { 1583 this.exitCode = exitCode; 1584 } 1585 } 1586 1587 // 1588 // Customizations available via the CLI 1589 // 1590 1591 protected TransferListener getConsoleTransferListener() 1592 { 1593 return new ConsoleMavenTransferListener( System.out ); 1594 } 1595 1596 protected TransferListener getBatchTransferListener() 1597 { 1598 return new Slf4jMavenTransferListener(); 1599 } 1600 1601 protected void customizeContainer( PlexusContainer container ) 1602 { 1603 } 1604 1605 protected ModelProcessor createModelProcessor( PlexusContainer container ) 1606 throws ComponentLookupException 1607 { 1608 return container.lookup( ModelProcessor.class ); 1609 } 1610}