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 com.google.common.base.Charsets; 023import com.google.common.io.Files; 024import com.google.inject.AbstractModule; 025import org.apache.commons.cli.CommandLine; 026import org.apache.commons.cli.ParseException; 027import org.apache.commons.cli.UnrecognizedOptionException; 028import org.apache.maven.BuildAbort; 029import org.apache.maven.InternalErrorException; 030import org.apache.maven.Maven; 031import org.apache.maven.building.FileSource; 032import org.apache.maven.building.Problem; 033import org.apache.maven.building.Source; 034import org.apache.maven.cli.configuration.ConfigurationProcessor; 035import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor; 036import org.apache.maven.cli.event.DefaultEventSpyContext; 037import org.apache.maven.cli.event.ExecutionEventLogger; 038import org.apache.maven.cli.internal.BootstrapCoreExtensionManager; 039import org.apache.maven.cli.internal.extension.model.CoreExtension; 040import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader; 041import org.apache.maven.cli.logging.Slf4jConfiguration; 042import org.apache.maven.cli.logging.Slf4jConfigurationFactory; 043import org.apache.maven.cli.logging.Slf4jLoggerManager; 044import org.apache.maven.cli.logging.Slf4jStdoutLogger; 045import org.apache.maven.cli.transfer.ConsoleMavenTransferListener; 046import org.apache.maven.cli.transfer.QuietMavenTransferListener; 047import org.apache.maven.cli.transfer.Slf4jMavenTransferListener; 048import org.apache.maven.eventspy.internal.EventSpyDispatcher; 049import org.apache.maven.exception.DefaultExceptionHandler; 050import org.apache.maven.exception.ExceptionHandler; 051import org.apache.maven.exception.ExceptionSummary; 052import org.apache.maven.execution.DefaultMavenExecutionRequest; 053import org.apache.maven.execution.ExecutionListener; 054import org.apache.maven.execution.MavenExecutionRequest; 055import org.apache.maven.execution.MavenExecutionRequestPopulationException; 056import org.apache.maven.execution.MavenExecutionRequestPopulator; 057import org.apache.maven.execution.MavenExecutionResult; 058import org.apache.maven.extension.internal.CoreExports; 059import org.apache.maven.extension.internal.CoreExtensionEntry; 060import org.apache.maven.lifecycle.LifecycleExecutionException; 061import org.apache.maven.model.building.ModelProcessor; 062import org.apache.maven.project.MavenProject; 063import org.apache.maven.properties.internal.EnvironmentUtils; 064import org.apache.maven.properties.internal.SystemProperties; 065import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest; 066import org.apache.maven.toolchain.building.ToolchainsBuilder; 067import org.apache.maven.toolchain.building.ToolchainsBuildingResult; 068import org.codehaus.plexus.ContainerConfiguration; 069import org.codehaus.plexus.DefaultContainerConfiguration; 070import org.codehaus.plexus.DefaultPlexusContainer; 071import org.codehaus.plexus.PlexusConstants; 072import org.codehaus.plexus.PlexusContainer; 073import org.codehaus.plexus.classworlds.ClassWorld; 074import org.codehaus.plexus.classworlds.realm.ClassRealm; 075import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; 076import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 077import org.codehaus.plexus.logging.LoggerManager; 078import org.codehaus.plexus.util.StringUtils; 079import org.codehaus.plexus.util.xml.pull.XmlPullParserException; 080import org.eclipse.aether.transfer.TransferListener; 081import org.slf4j.ILoggerFactory; 082import org.slf4j.Logger; 083import org.slf4j.LoggerFactory; 084import org.sonatype.plexus.components.cipher.DefaultPlexusCipher; 085import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher; 086import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; 087import org.sonatype.plexus.components.sec.dispatcher.SecUtil; 088import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity; 089 090import java.io.BufferedInputStream; 091import java.io.Console; 092import java.io.File; 093import java.io.FileInputStream; 094import java.io.FileNotFoundException; 095import java.io.FileOutputStream; 096import java.io.IOException; 097import java.io.InputStream; 098import java.io.PrintStream; 099import java.util.ArrayList; 100import java.util.Arrays; 101import java.util.Collections; 102import java.util.HashSet; 103import java.util.LinkedHashMap; 104import java.util.List; 105import java.util.Map; 106import java.util.Map.Entry; 107import java.util.Properties; 108import java.util.Set; 109import java.util.StringTokenizer; 110 111// TODO: push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs 112 113/** 114 * @author Jason van Zyl 115 * @noinspection UseOfSystemOutOrSystemErr, ACCESS_STATIC_VIA_INSTANCE 116 */ 117public class MavenCli 118{ 119 public static final String LOCAL_REPO_PROPERTY = "maven.repo.local"; 120 121 public static final String THREADS_DEPRECATED = "maven.threads.experimental"; 122 123 public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory"; 124 125 @SuppressWarnings( "checkstyle:constantname" ) 126 public static final String userHome = System.getProperty( "user.home" ); 127 128 @SuppressWarnings( "checkstyle:constantname" ) 129 public static final File userMavenConfigurationHome = new File( userHome, ".m2" ); 130 131 /** 132 * @deprecated use {@link SettingsXmlConfigurationProcessor#DEFAULT_USER_SETTINGS_FILE} 133 */ 134 public static final File DEFAULT_USER_SETTINGS_FILE = SettingsXmlConfigurationProcessor.DEFAULT_USER_SETTINGS_FILE; 135 136 /** 137 * @deprecated use {@link SettingsXmlConfigurationProcessor#DEFAULT_GLOBAL_SETTINGS_FILE} 138 */ 139 public static final File DEFAULT_GLOBAL_SETTINGS_FILE = 140 SettingsXmlConfigurationProcessor.DEFAULT_GLOBAL_SETTINGS_FILE; 141 142 public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File( userMavenConfigurationHome, "toolchains.xml" ); 143 144 public static final File DEFAULT_GLOBAL_TOOLCHAINS_FILE = 145 new File( System.getProperty( "maven.home", System.getProperty( "user.dir", "" ) ), "conf/toolchains.xml" ); 146 147 private static final String EXT_CLASS_PATH = "maven.ext.class.path"; 148 149 private static final String EXTENSIONS_FILENAME = ".mvn/extensions.xml"; 150 151 private static final String MVN_MAVEN_CONFIG = ".mvn/maven.config"; 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 /** 194 * @noinspection ConfusingMainMethod 195 */ 196 public static int main( String[] args, ClassWorld classWorld ) 197 { 198 MavenCli cli = new MavenCli(); 199 return cli.doMain( new CliRequest( args, classWorld ) ); 200 } 201 202 // TODO: need to externalize CliRequest 203 public static int doMain( String[] args, ClassWorld classWorld ) 204 { 205 MavenCli cli = new MavenCli(); 206 return cli.doMain( new CliRequest( args, classWorld ) ); 207 } 208 209 // This supports painless invocation by the Verifier during embedded execution of the core ITs 210 public int doMain( String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr ) 211 { 212 PrintStream oldout = System.out; 213 PrintStream olderr = System.err; 214 215 final Set<String> realms; 216 if ( classWorld != null ) 217 { 218 realms = new HashSet<>(); 219 for ( ClassRealm realm : classWorld.getRealms() ) 220 { 221 realms.add( realm.getId() ); 222 } 223 } 224 else 225 { 226 realms = Collections.emptySet(); 227 } 228 229 try 230 { 231 if ( stdout != null ) 232 { 233 System.setOut( stdout ); 234 } 235 if ( stderr != null ) 236 { 237 System.setErr( stderr ); 238 } 239 240 CliRequest cliRequest = new CliRequest( args, classWorld ); 241 cliRequest.workingDirectory = workingDirectory; 242 243 return doMain( cliRequest ); 244 } 245 finally 246 { 247 if ( classWorld != null ) 248 { 249 for ( ClassRealm realm : new ArrayList<>( classWorld.getRealms() ) ) 250 { 251 String realmId = realm.getId(); 252 if ( !realms.contains( realmId ) ) 253 { 254 try 255 { 256 classWorld.disposeRealm( realmId ); 257 } 258 catch ( NoSuchRealmException ignored ) 259 { 260 // can't happen 261 } 262 } 263 } 264 } 265 System.setOut( oldout ); 266 System.setErr( olderr ); 267 } 268 } 269 270 // TODO: need to externalize CliRequest 271 public int doMain( CliRequest cliRequest ) 272 { 273 PlexusContainer localContainer = null; 274 try 275 { 276 initialize( cliRequest ); 277 cli( cliRequest ); 278 logging( cliRequest ); 279 version( cliRequest ); 280 properties( cliRequest ); 281 localContainer = container( cliRequest ); 282 commands( cliRequest ); 283 configure( cliRequest ); 284 toolchains( cliRequest ); 285 populateRequest( cliRequest ); 286 encryption( cliRequest ); 287 repository( cliRequest ); 288 return execute( cliRequest ); 289 } 290 catch ( ExitException e ) 291 { 292 return e.exitCode; 293 } 294 catch ( UnrecognizedOptionException e ) 295 { 296 // pure user error, suppress stack trace 297 return 1; 298 } 299 catch ( BuildAbort e ) 300 { 301 CLIReportingUtils.showError( slf4jLogger, "ABORTED", e, cliRequest.showErrors ); 302 303 return 2; 304 } 305 catch ( Exception e ) 306 { 307 CLIReportingUtils.showError( slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors ); 308 309 return 1; 310 } 311 finally 312 { 313 if ( localContainer != null ) 314 { 315 localContainer.dispose(); 316 } 317 } 318 } 319 320 void initialize( CliRequest cliRequest ) 321 throws ExitException 322 { 323 if ( cliRequest.workingDirectory == null ) 324 { 325 cliRequest.workingDirectory = System.getProperty( "user.dir" ); 326 } 327 328 if ( cliRequest.multiModuleProjectDirectory == null ) 329 { 330 String basedirProperty = System.getProperty( MULTIMODULE_PROJECT_DIRECTORY ); 331 if ( basedirProperty == null ) 332 { 333 System.err.format( 334 "-D%s system property is not set." + " Check $M2_HOME environment variable and mvn script match.", 335 MULTIMODULE_PROJECT_DIRECTORY ); 336 throw new ExitException( 1 ); 337 } 338 File basedir = basedirProperty != null ? new File( basedirProperty ) : new File( "" ); 339 try 340 { 341 cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile(); 342 } 343 catch ( IOException e ) 344 { 345 cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile(); 346 } 347 } 348 349 // 350 // Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative 351 // Windows paths. 352 // 353 String mavenHome = System.getProperty( "maven.home" ); 354 355 if ( mavenHome != null ) 356 { 357 System.setProperty( "maven.home", new File( mavenHome ).getAbsolutePath() ); 358 } 359 } 360 361 void cli( CliRequest cliRequest ) 362 throws Exception 363 { 364 // 365 // Parsing errors can happen during the processing of the arguments and we prefer not having to check if 366 // the logger is null and construct this so we can use an SLF4J logger everywhere. 367 // 368 slf4jLogger = new Slf4jStdoutLogger(); 369 370 CLIManager cliManager = new CLIManager(); 371 372 List<String> args = new ArrayList<>(); 373 374 try 375 { 376 File configFile = new File( cliRequest.multiModuleProjectDirectory, MVN_MAVEN_CONFIG ); 377 378 if ( configFile.isFile() ) 379 { 380 for ( String arg : Files.toString( configFile, Charsets.UTF_8 ).split( "\\s+" ) ) 381 { 382 if ( !arg.isEmpty() ) 383 { 384 args.add( arg ); 385 } 386 } 387 388 CommandLine config = cliManager.parse( args.toArray( new String[args.size()] ) ); 389 List<?> unrecongized = config.getArgList(); 390 if ( !unrecongized.isEmpty() ) 391 { 392 throw new ParseException( "Unrecognized maven.config entries: " + unrecongized ); 393 } 394 } 395 } 396 catch ( ParseException e ) 397 { 398 System.err.println( "Unable to parse maven.config: " + e.getMessage() ); 399 cliManager.displayHelp( System.out ); 400 throw e; 401 } 402 403 try 404 { 405 args.addAll( 0, Arrays.asList( cliRequest.args ) ); 406 cliRequest.commandLine = cliManager.parse( args.toArray( new String[args.size()] ) ); 407 } 408 catch ( ParseException e ) 409 { 410 System.err.println( "Unable to parse command line options: " + e.getMessage() ); 411 cliManager.displayHelp( System.out ); 412 throw e; 413 } 414 415 if ( cliRequest.commandLine.hasOption( CLIManager.HELP ) ) 416 { 417 cliManager.displayHelp( System.out ); 418 throw new ExitException( 0 ); 419 } 420 421 if ( cliRequest.commandLine.hasOption( CLIManager.VERSION ) ) 422 { 423 System.out.println( CLIReportingUtils.showVersion() ); 424 throw new ExitException( 0 ); 425 } 426 } 427 428 /** 429 * configure logging 430 */ 431 private void logging( CliRequest cliRequest ) 432 { 433 cliRequest.debug = cliRequest.commandLine.hasOption( CLIManager.DEBUG ); 434 cliRequest.quiet = !cliRequest.debug && cliRequest.commandLine.hasOption( CLIManager.QUIET ); 435 cliRequest.showErrors = cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.ERRORS ); 436 437 slf4jLoggerFactory = LoggerFactory.getILoggerFactory(); 438 Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration( slf4jLoggerFactory ); 439 440 if ( cliRequest.debug ) 441 { 442 cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_DEBUG ); 443 slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.DEBUG ); 444 } 445 else if ( cliRequest.quiet ) 446 { 447 cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_ERROR ); 448 slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.ERROR ); 449 } 450 // else fall back to default log level specified in conf 451 // see https://issues.apache.org/jira/browse/MNG-2570 452 453 if ( cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) ) 454 { 455 File logFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.LOG_FILE ) ); 456 logFile = resolveFile( logFile, cliRequest.workingDirectory ); 457 458 // redirect stdout and stderr to file 459 try 460 { 461 PrintStream ps = new PrintStream( new FileOutputStream( logFile ) ); 462 System.setOut( ps ); 463 System.setErr( ps ); 464 } 465 catch ( FileNotFoundException e ) 466 { 467 // 468 // Ignore 469 // 470 } 471 } 472 473 slf4jConfiguration.activate(); 474 475 plexusLoggerManager = new Slf4jLoggerManager(); 476 slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() ); 477 } 478 479 private void version( CliRequest cliRequest ) 480 { 481 if ( cliRequest.debug || cliRequest.commandLine.hasOption( CLIManager.SHOW_VERSION ) ) 482 { 483 System.out.println( CLIReportingUtils.showVersion() ); 484 } 485 } 486 487 private void commands( CliRequest cliRequest ) 488 { 489 if ( cliRequest.showErrors ) 490 { 491 slf4jLogger.info( "Error stacktraces are turned on." ); 492 } 493 494 if ( MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals( cliRequest.request.getGlobalChecksumPolicy() ) ) 495 { 496 slf4jLogger.info( "Disabling strict checksum verification on all artifact downloads." ); 497 } 498 else if ( MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals( cliRequest.request.getGlobalChecksumPolicy() ) ) 499 { 500 slf4jLogger.info( "Enabling strict checksum verification on all artifact downloads." ); 501 } 502 } 503 504 private void properties( CliRequest cliRequest ) 505 { 506 populateProperties( cliRequest.commandLine, cliRequest.systemProperties, cliRequest.userProperties ); 507 } 508 509 private PlexusContainer container( CliRequest cliRequest ) 510 throws Exception 511 { 512 if ( cliRequest.classWorld == null ) 513 { 514 cliRequest.classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() ); 515 } 516 517 ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" ); 518 if ( coreRealm == null ) 519 { 520 coreRealm = cliRequest.classWorld.getRealms().iterator().next(); 521 } 522 523 List<File> extClassPath = parseExtClasspath( cliRequest ); 524 525 CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom( coreRealm ); 526 List<CoreExtensionEntry> extensions = 527 loadCoreExtensions( cliRequest, coreRealm, coreEntry.getExportedArtifacts() ); 528 529 ClassRealm containerRealm = setupContainerRealm( cliRequest.classWorld, coreRealm, extClassPath, extensions ); 530 531 ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld( cliRequest.classWorld ).setRealm( 532 containerRealm ).setClassPathScanning( PlexusConstants.SCANNING_INDEX ).setAutoWiring( true ).setName( 533 "maven" ); 534 535 Set<String> exportedArtifacts = new HashSet<>( coreEntry.getExportedArtifacts() ); 536 Set<String> exportedPackages = new HashSet<>( coreEntry.getExportedPackages() ); 537 for ( CoreExtensionEntry extension : extensions ) 538 { 539 exportedArtifacts.addAll( extension.getExportedArtifacts() ); 540 exportedPackages.addAll( extension.getExportedPackages() ); 541 } 542 543 final CoreExports exports = new CoreExports( containerRealm, exportedArtifacts, exportedPackages ); 544 545 DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule() 546 { 547 @Override 548 protected void configure() 549 { 550 bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory ); 551 bind( CoreExports.class ).toInstance( exports ); 552 } 553 } ); 554 555 // NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups 556 container.setLookupRealm( null ); 557 558 container.setLoggerManager( plexusLoggerManager ); 559 560 for ( CoreExtensionEntry extension : extensions ) 561 { 562 container.discoverComponents( extension.getClassRealm() ); 563 } 564 565 customizeContainer( container ); 566 567 container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() ); 568 569 Thread.currentThread().setContextClassLoader( container.getContainerRealm() ); 570 571 eventSpyDispatcher = container.lookup( EventSpyDispatcher.class ); 572 573 DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext(); 574 Map<String, Object> data = eventSpyContext.getData(); 575 data.put( "plexus", container ); 576 data.put( "workingDirectory", cliRequest.workingDirectory ); 577 data.put( "systemProperties", cliRequest.systemProperties ); 578 data.put( "userProperties", cliRequest.userProperties ); 579 data.put( "versionProperties", CLIReportingUtils.getBuildProperties() ); 580 eventSpyDispatcher.init( eventSpyContext ); 581 582 // refresh logger in case container got customized by spy 583 slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() ); 584 585 maven = container.lookup( Maven.class ); 586 587 executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class ); 588 589 modelProcessor = createModelProcessor( container ); 590 591 configurationProcessors = container.lookupMap( ConfigurationProcessor.class ); 592 593 toolchainsBuilder = container.lookup( ToolchainsBuilder.class ); 594 595 dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" ); 596 597 return container; 598 } 599 600 private List<CoreExtensionEntry> loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm, 601 Set<String> providedArtifacts ) 602 { 603 if ( cliRequest.multiModuleProjectDirectory == null ) 604 { 605 return Collections.emptyList(); 606 } 607 608 File extensionsFile = new File( cliRequest.multiModuleProjectDirectory, EXTENSIONS_FILENAME ); 609 if ( !extensionsFile.isFile() ) 610 { 611 return Collections.emptyList(); 612 } 613 614 try 615 { 616 List<CoreExtension> extensions = readCoreExtensionsDescriptor( extensionsFile ); 617 if ( extensions.isEmpty() ) 618 { 619 return Collections.emptyList(); 620 } 621 622 ContainerConfiguration cc = new DefaultContainerConfiguration() // 623 .setClassWorld( cliRequest.classWorld ) // 624 .setRealm( containerRealm ) // 625 .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) // 626 .setAutoWiring( true ) // 627 .setName( "maven" ); 628 629 DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule() 630 { 631 @Override 632 protected void configure() 633 { 634 bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory ); 635 } 636 } ); 637 638 try 639 { 640 container.setLookupRealm( null ); 641 642 container.setLoggerManager( plexusLoggerManager ); 643 644 container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() ); 645 646 Thread.currentThread().setContextClassLoader( container.getContainerRealm() ); 647 648 executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class ); 649 650 configurationProcessors = container.lookupMap( ConfigurationProcessor.class ); 651 652 configure( cliRequest ); 653 654 MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request ); 655 656 request = populateRequest( cliRequest, request ); 657 658 request = executionRequestPopulator.populateDefaults( request ); 659 660 BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class ); 661 662 return resolver.loadCoreExtensions( request, providedArtifacts, extensions ); 663 } 664 finally 665 { 666 executionRequestPopulator = null; 667 container.dispose(); 668 } 669 } 670 catch ( RuntimeException e ) 671 { 672 // runtime exceptions are most likely bugs in maven, let them bubble up to the user 673 throw e; 674 } 675 catch ( Exception e ) 676 { 677 slf4jLogger.warn( "Failed to read extensions descriptor " + extensionsFile + ": " + e.getMessage() ); 678 } 679 return Collections.emptyList(); 680 } 681 682 private List<CoreExtension> readCoreExtensionsDescriptor( File extensionsFile ) 683 throws IOException, XmlPullParserException 684 { 685 CoreExtensionsXpp3Reader parser = new CoreExtensionsXpp3Reader(); 686 687 try ( InputStream is = new BufferedInputStream( new FileInputStream( extensionsFile ) ) ) 688 { 689 690 return parser.read( is ).getExtensions(); 691 } 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<>( 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<>(); 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( 794 cipher.encryptAndDecorate( passwd, 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 ) || Boolean.getBoolean( 850 "maven.legacyLocalRepo" ) ) 851 { 852 cliRequest.request.setUseLegacyLocalRepository( true ); 853 } 854 } 855 856 private int execute( CliRequest cliRequest ) 857 throws MavenExecutionRequestPopulationException 858 { 859 MavenExecutionRequest request = executionRequestPopulator.populateDefaults( cliRequest.request ); 860 861 eventSpyDispatcher.onEvent( request ); 862 863 MavenExecutionResult result = maven.execute( request ); 864 865 eventSpyDispatcher.onEvent( result ); 866 867 eventSpyDispatcher.close(); 868 869 if ( result.hasExceptions() ) 870 { 871 ExceptionHandler handler = new DefaultExceptionHandler(); 872 873 Map<String, String> references = new LinkedHashMap<>(); 874 875 MavenProject project = null; 876 877 for ( Throwable exception : result.getExceptions() ) 878 { 879 ExceptionSummary summary = handler.handleException( exception ); 880 881 logSummary( summary, references, "", cliRequest.showErrors ); 882 883 if ( project == null && exception instanceof LifecycleExecutionException ) 884 { 885 project = ( (LifecycleExecutionException) exception ).getProject(); 886 } 887 } 888 889 slf4jLogger.error( "" ); 890 891 if ( !cliRequest.showErrors ) 892 { 893 slf4jLogger.error( "To see the full stack trace of the errors, re-run Maven with the -e switch." ); 894 } 895 if ( !slf4jLogger.isDebugEnabled() ) 896 { 897 slf4jLogger.error( "Re-run Maven using the -X switch to enable full debug logging." ); 898 } 899 900 if ( !references.isEmpty() ) 901 { 902 slf4jLogger.error( "" ); 903 slf4jLogger.error( "For more information about the errors and possible solutions" 904 + ", please read the following articles:" ); 905 906 for ( Map.Entry<String, String> entry : references.entrySet() ) 907 { 908 slf4jLogger.error( entry.getValue() + " " + entry.getKey() ); 909 } 910 } 911 912 if ( project != null && !project.equals( result.getTopologicallySortedProjects().get( 0 ) ) ) 913 { 914 slf4jLogger.error( "" ); 915 slf4jLogger.error( "After correcting the problems, you can resume the build with the command" ); 916 slf4jLogger.error( " mvn <goals> -rf :" + project.getArtifactId() ); 917 } 918 919 if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) ) 920 { 921 slf4jLogger.info( "Build failures were ignored." ); 922 923 return 0; 924 } 925 else 926 { 927 return 1; 928 } 929 } 930 else 931 { 932 return 0; 933 } 934 } 935 936 private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent, 937 boolean showErrors ) 938 { 939 String referenceKey = ""; 940 941 if ( StringUtils.isNotEmpty( summary.getReference() ) ) 942 { 943 referenceKey = references.get( summary.getReference() ); 944 if ( referenceKey == null ) 945 { 946 referenceKey = "[Help " + ( references.size() + 1 ) + "]"; 947 references.put( summary.getReference(), referenceKey ); 948 } 949 } 950 951 String msg = summary.getMessage(); 952 953 if ( StringUtils.isNotEmpty( referenceKey ) ) 954 { 955 if ( msg.indexOf( '\n' ) < 0 ) 956 { 957 msg += " -> " + referenceKey; 958 } 959 else 960 { 961 msg += "\n-> " + referenceKey; 962 } 963 } 964 965 String[] lines = msg.split( "(\r\n)|(\r)|(\n)" ); 966 967 for ( int i = 0; i < lines.length; i++ ) 968 { 969 String line = indent + lines[i].trim(); 970 971 if ( ( i == lines.length - 1 ) && ( showErrors 972 || ( summary.getException() instanceof InternalErrorException ) ) ) 973 { 974 slf4jLogger.error( line, summary.getException() ); 975 } 976 else 977 { 978 slf4jLogger.error( line ); 979 } 980 } 981 982 indent += " "; 983 984 for ( ExceptionSummary child : summary.getChildren() ) 985 { 986 logSummary( child, references, indent, showErrors ); 987 } 988 } 989 990 @SuppressWarnings( "checkstyle:methodlength" ) 991 private void configure( CliRequest cliRequest ) 992 throws Exception 993 { 994 // 995 // This is not ideal but there are events specifically for configuration from the CLI which I don't 996 // believe are really valid but there are ITs which assert the right events are published so this 997 // needs to be supported so the EventSpyDispatcher needs to be put in the CliRequest so that 998 // it can be accessed by configuration processors. 999 // 1000 cliRequest.request.setEventSpyDispatcher( eventSpyDispatcher ); 1001 1002 // 1003 // We expect at most 2 implementations to be available. The SettingsXmlConfigurationProcessor implementation 1004 // is always available in the core and likely always will be, but we may have another ConfigurationProcessor 1005 // present supplied by the user. The rule is that we only allow the execution of one ConfigurationProcessor. 1006 // If there is more than one then we execute the one supplied by the user, otherwise we execute the 1007 // the default SettingsXmlConfigurationProcessor. 1008 // 1009 int userSuppliedConfigurationProcessorCount = configurationProcessors.size() - 1; 1010 1011 if ( userSuppliedConfigurationProcessorCount == 0 ) 1012 { 1013 // 1014 // Our settings.xml source is historically how we have configured Maven from the CLI so we are going to 1015 // have to honour its existence forever. So let's run it. 1016 // 1017 configurationProcessors.get( SettingsXmlConfigurationProcessor.HINT ).process( cliRequest ); 1018 } 1019 else if ( userSuppliedConfigurationProcessorCount == 1 ) 1020 { 1021 // 1022 // Run the user supplied ConfigurationProcessor 1023 // 1024 for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() ) 1025 { 1026 String hint = entry.getKey(); 1027 if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) ) 1028 { 1029 ConfigurationProcessor configurationProcessor = entry.getValue(); 1030 configurationProcessor.process( cliRequest ); 1031 } 1032 } 1033 } 1034 else if ( userSuppliedConfigurationProcessorCount > 1 ) 1035 { 1036 // 1037 // There are too many ConfigurationProcessors so we don't know which one to run so report the error. 1038 // 1039 StringBuilder sb = new StringBuilder( 1040 String.format( "\nThere can only be one user supplied ConfigurationProcessor, there are %s:\n\n", 1041 userSuppliedConfigurationProcessorCount ) ); 1042 for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() ) 1043 { 1044 String hint = entry.getKey(); 1045 if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) ) 1046 { 1047 ConfigurationProcessor configurationProcessor = entry.getValue(); 1048 sb.append( String.format( "%s\n", configurationProcessor.getClass().getName() ) ); 1049 } 1050 } 1051 sb.append( String.format( "\n" ) ); 1052 throw new Exception( sb.toString() ); 1053 } 1054 } 1055 1056 @SuppressWarnings( "checkstyle:methodlength" ) 1057 private void toolchains( CliRequest cliRequest ) 1058 throws Exception 1059 { 1060 File userToolchainsFile; 1061 1062 if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ) 1063 { 1064 userToolchainsFile = 1065 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ); 1066 userToolchainsFile = resolveFile( userToolchainsFile, cliRequest.workingDirectory ); 1067 1068 if ( !userToolchainsFile.isFile() ) 1069 { 1070 throw new FileNotFoundException( 1071 "The specified user toolchains file does not exist: " + userToolchainsFile ); 1072 } 1073 } 1074 else 1075 { 1076 userToolchainsFile = DEFAULT_USER_TOOLCHAINS_FILE; 1077 } 1078 1079 File globalToolchainsFile; 1080 1081 if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) ) 1082 { 1083 globalToolchainsFile = 1084 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) ); 1085 globalToolchainsFile = resolveFile( globalToolchainsFile, cliRequest.workingDirectory ); 1086 1087 if ( !globalToolchainsFile.isFile() ) 1088 { 1089 throw new FileNotFoundException( 1090 "The specified global toolchains file does not exist: " + globalToolchainsFile ); 1091 } 1092 } 1093 else 1094 { 1095 globalToolchainsFile = DEFAULT_GLOBAL_TOOLCHAINS_FILE; 1096 } 1097 1098 cliRequest.request.setGlobalToolchainsFile( globalToolchainsFile ); 1099 cliRequest.request.setUserToolchainsFile( userToolchainsFile ); 1100 1101 DefaultToolchainsBuildingRequest toolchainsRequest = new DefaultToolchainsBuildingRequest(); 1102 if ( globalToolchainsFile.isFile() ) 1103 { 1104 toolchainsRequest.setGlobalToolchainsSource( new FileSource( globalToolchainsFile ) ); 1105 } 1106 if ( userToolchainsFile.isFile() ) 1107 { 1108 toolchainsRequest.setUserToolchainsSource( new FileSource( userToolchainsFile ) ); 1109 } 1110 1111 eventSpyDispatcher.onEvent( toolchainsRequest ); 1112 1113 slf4jLogger.debug( 1114 "Reading global toolchains from " + getLocation( toolchainsRequest.getGlobalToolchainsSource(), 1115 globalToolchainsFile ) ); 1116 slf4jLogger.debug( "Reading user toolchains from " + getLocation( toolchainsRequest.getUserToolchainsSource(), 1117 userToolchainsFile ) ); 1118 1119 ToolchainsBuildingResult toolchainsResult = toolchainsBuilder.build( toolchainsRequest ); 1120 1121 eventSpyDispatcher.onEvent( toolchainsRequest ); 1122 1123 executionRequestPopulator.populateFromToolchains( cliRequest.request, 1124 toolchainsResult.getEffectiveToolchains() ); 1125 1126 if ( !toolchainsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled() ) 1127 { 1128 slf4jLogger.warn( "" ); 1129 slf4jLogger.warn( "Some problems were encountered while building the effective toolchains" ); 1130 1131 for ( Problem problem : toolchainsResult.getProblems() ) 1132 { 1133 slf4jLogger.warn( problem.getMessage() + " @ " + problem.getLocation() ); 1134 } 1135 1136 slf4jLogger.warn( "" ); 1137 } 1138 } 1139 1140 private Object getLocation( Source source, File defaultLocation ) 1141 { 1142 if ( source != null ) 1143 { 1144 return source.getLocation(); 1145 } 1146 return defaultLocation; 1147 } 1148 1149 private MavenExecutionRequest populateRequest( CliRequest cliRequest ) 1150 { 1151 return populateRequest( cliRequest, cliRequest.request ); 1152 } 1153 1154 private MavenExecutionRequest populateRequest( CliRequest cliRequest, MavenExecutionRequest request ) 1155 { 1156 CommandLine commandLine = cliRequest.commandLine; 1157 String workingDirectory = cliRequest.workingDirectory; 1158 boolean quiet = cliRequest.quiet; 1159 boolean showErrors = cliRequest.showErrors; 1160 1161 String[] deprecatedOptions = { "up", "npu", "cpu", "npr" }; 1162 for ( String deprecatedOption : deprecatedOptions ) 1163 { 1164 if ( commandLine.hasOption( deprecatedOption ) ) 1165 { 1166 slf4jLogger.warn( "Command line option -" + deprecatedOption 1167 + " is deprecated and will be removed in future Maven versions." ); 1168 } 1169 } 1170 1171 // ---------------------------------------------------------------------- 1172 // Now that we have everything that we need we will fire up plexus and 1173 // bring the maven component to life for use. 1174 // ---------------------------------------------------------------------- 1175 1176 if ( commandLine.hasOption( CLIManager.BATCH_MODE ) ) 1177 { 1178 request.setInteractiveMode( false ); 1179 } 1180 1181 boolean noSnapshotUpdates = false; 1182 if ( commandLine.hasOption( CLIManager.SUPRESS_SNAPSHOT_UPDATES ) ) 1183 { 1184 noSnapshotUpdates = true; 1185 } 1186 1187 // ---------------------------------------------------------------------- 1188 // 1189 // ---------------------------------------------------------------------- 1190 1191 @SuppressWarnings( "unchecked" ) List<String> goals = commandLine.getArgList(); 1192 1193 boolean recursive = true; 1194 1195 // this is the default behavior. 1196 String reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST; 1197 1198 if ( commandLine.hasOption( CLIManager.NON_RECURSIVE ) ) 1199 { 1200 recursive = false; 1201 } 1202 1203 if ( commandLine.hasOption( CLIManager.FAIL_FAST ) ) 1204 { 1205 reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_FAST; 1206 } 1207 else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) ) 1208 { 1209 reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_AT_END; 1210 } 1211 else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) ) 1212 { 1213 reactorFailureBehaviour = MavenExecutionRequest.REACTOR_FAIL_NEVER; 1214 } 1215 1216 if ( commandLine.hasOption( CLIManager.OFFLINE ) ) 1217 { 1218 request.setOffline( true ); 1219 } 1220 1221 boolean updateSnapshots = false; 1222 1223 if ( commandLine.hasOption( CLIManager.UPDATE_SNAPSHOTS ) ) 1224 { 1225 updateSnapshots = true; 1226 } 1227 1228 String globalChecksumPolicy = null; 1229 1230 if ( commandLine.hasOption( CLIManager.CHECKSUM_FAILURE_POLICY ) ) 1231 { 1232 globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_FAIL; 1233 } 1234 else if ( commandLine.hasOption( CLIManager.CHECKSUM_WARNING_POLICY ) ) 1235 { 1236 globalChecksumPolicy = MavenExecutionRequest.CHECKSUM_POLICY_WARN; 1237 } 1238 1239 File baseDirectory = new File( workingDirectory, "" ).getAbsoluteFile(); 1240 1241 // ---------------------------------------------------------------------- 1242 // Profile Activation 1243 // ---------------------------------------------------------------------- 1244 1245 List<String> activeProfiles = new ArrayList<>(); 1246 1247 List<String> inactiveProfiles = new ArrayList<>(); 1248 1249 if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) ) 1250 { 1251 String[] profileOptionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES ); 1252 if ( profileOptionValues != null ) 1253 { 1254 for ( String profileOptionValue : profileOptionValues ) 1255 { 1256 StringTokenizer profileTokens = new StringTokenizer( profileOptionValue, "," ); 1257 1258 while ( profileTokens.hasMoreTokens() ) 1259 { 1260 String profileAction = profileTokens.nextToken().trim(); 1261 1262 if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) ) 1263 { 1264 inactiveProfiles.add( profileAction.substring( 1 ) ); 1265 } 1266 else if ( profileAction.startsWith( "+" ) ) 1267 { 1268 activeProfiles.add( profileAction.substring( 1 ) ); 1269 } 1270 else 1271 { 1272 activeProfiles.add( profileAction ); 1273 } 1274 } 1275 } 1276 } 1277 } 1278 1279 TransferListener transferListener; 1280 1281 if ( quiet ) 1282 { 1283 transferListener = new QuietMavenTransferListener(); 1284 } 1285 else if ( request.isInteractiveMode() && !cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) ) 1286 { 1287 // 1288 // If we're logging to a file then we don't want the console transfer listener as it will spew 1289 // download progress all over the place 1290 // 1291 transferListener = getConsoleTransferListener(); 1292 } 1293 else 1294 { 1295 transferListener = getBatchTransferListener(); 1296 } 1297 1298 ExecutionListener executionListener = new ExecutionEventLogger(); 1299 if ( eventSpyDispatcher != null ) 1300 { 1301 executionListener = eventSpyDispatcher.chainListener( executionListener ); 1302 } 1303 1304 String alternatePomFile = null; 1305 if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) ) 1306 { 1307 alternatePomFile = commandLine.getOptionValue( CLIManager.ALTERNATE_POM_FILE ); 1308 } 1309 1310 File userToolchainsFile; 1311 if ( commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ) 1312 { 1313 userToolchainsFile = new File( commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) ); 1314 userToolchainsFile = resolveFile( userToolchainsFile, workingDirectory ); 1315 } 1316 else 1317 { 1318 userToolchainsFile = MavenCli.DEFAULT_USER_TOOLCHAINS_FILE; 1319 } 1320 1321 request.setBaseDirectory( baseDirectory ).setGoals( goals ).setSystemProperties( 1322 cliRequest.systemProperties ).setUserProperties( cliRequest.userProperties ).setReactorFailureBehavior( 1323 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 ).setTransferListener( 1329 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<>(); 1370 List<String> exclProjects = new ArrayList<>(); 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 ) && !commandLine.hasOption( 1403 CLIManager.ALSO_MAKE_DEPENDENTS ) ) 1404 { 1405 request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_UPSTREAM ); 1406 } 1407 else if ( !commandLine.hasOption( CLIManager.ALSO_MAKE ) && commandLine.hasOption( 1408 CLIManager.ALSO_MAKE_DEPENDENTS ) ) 1409 { 1410 request.setMakeBehavior( MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM ); 1411 } 1412 else if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) && commandLine.hasOption( 1413 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}