1 package org.apache.maven.cli;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import com.google.inject.AbstractModule;
23 import org.apache.commons.cli.CommandLine;
24 import org.apache.commons.cli.Option;
25 import org.apache.commons.cli.ParseException;
26 import org.apache.commons.cli.UnrecognizedOptionException;
27 import org.apache.commons.lang3.math.NumberUtils;
28 import org.apache.maven.BuildAbort;
29 import org.apache.maven.InternalErrorException;
30 import org.apache.maven.Maven;
31 import org.apache.maven.building.FileSource;
32 import org.apache.maven.building.Problem;
33 import org.apache.maven.building.Source;
34 import org.apache.maven.cli.configuration.ConfigurationProcessor;
35 import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor;
36 import org.apache.maven.cli.event.DefaultEventSpyContext;
37 import org.apache.maven.cli.event.ExecutionEventLogger;
38 import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
39 import org.apache.maven.cli.internal.extension.model.CoreExtension;
40 import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader;
41 import org.apache.maven.cli.logging.Slf4jConfiguration;
42 import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
43 import org.apache.maven.cli.logging.Slf4jLoggerManager;
44 import org.apache.maven.cli.logging.Slf4jStdoutLogger;
45 import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
46 import org.apache.maven.cli.transfer.QuietMavenTransferListener;
47 import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
48 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
49 import org.apache.maven.exception.DefaultExceptionHandler;
50 import org.apache.maven.exception.ExceptionHandler;
51 import org.apache.maven.exception.ExceptionSummary;
52 import org.apache.maven.execution.DefaultMavenExecutionRequest;
53 import org.apache.maven.execution.ExecutionListener;
54 import org.apache.maven.execution.MavenExecutionRequest;
55 import org.apache.maven.execution.MavenExecutionRequestPopulationException;
56 import org.apache.maven.execution.MavenExecutionRequestPopulator;
57 import org.apache.maven.execution.MavenExecutionResult;
58 import org.apache.maven.execution.ProfileActivation;
59 import org.apache.maven.execution.ProjectActivation;
60 import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
61 import org.apache.maven.extension.internal.CoreExports;
62 import org.apache.maven.extension.internal.CoreExtensionEntry;
63 import org.apache.maven.lifecycle.LifecycleExecutionException;
64 import org.apache.maven.logwrapper.LogLevelRecorder;
65 import org.apache.maven.logwrapper.MavenSlf4jWrapperFactory;
66 import org.apache.maven.model.building.ModelProcessor;
67 import org.apache.maven.project.MavenProject;
68 import org.apache.maven.properties.internal.EnvironmentUtils;
69 import org.apache.maven.properties.internal.SystemProperties;
70 import org.apache.maven.session.scope.internal.SessionScopeModule;
71 import org.apache.maven.shared.utils.logging.MessageBuilder;
72 import org.apache.maven.shared.utils.logging.MessageUtils;
73 import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest;
74 import org.apache.maven.toolchain.building.ToolchainsBuilder;
75 import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
76 import org.codehaus.plexus.ContainerConfiguration;
77 import org.codehaus.plexus.DefaultContainerConfiguration;
78 import org.codehaus.plexus.DefaultPlexusContainer;
79 import org.codehaus.plexus.PlexusConstants;
80 import org.codehaus.plexus.PlexusContainer;
81 import org.codehaus.plexus.classworlds.ClassWorld;
82 import org.codehaus.plexus.classworlds.realm.ClassRealm;
83 import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
84 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
85 import org.codehaus.plexus.logging.LoggerManager;
86 import org.codehaus.plexus.util.StringUtils;
87 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
88 import org.eclipse.aether.DefaultRepositoryCache;
89 import org.eclipse.aether.transfer.TransferListener;
90 import org.slf4j.ILoggerFactory;
91 import org.slf4j.Logger;
92 import org.slf4j.LoggerFactory;
93 import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
94 import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
95 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
96 import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
97 import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
98
99 import java.io.BufferedInputStream;
100 import java.io.Console;
101 import java.io.File;
102 import java.io.FileInputStream;
103 import java.io.FileNotFoundException;
104 import java.io.FileOutputStream;
105 import java.io.IOException;
106 import java.io.InputStream;
107 import java.io.PrintStream;
108 import java.nio.charset.Charset;
109 import java.nio.file.Files;
110 import java.util.ArrayList;
111 import java.util.Collections;
112 import java.util.HashSet;
113 import java.util.LinkedHashMap;
114 import java.util.List;
115 import java.util.Map;
116 import java.util.Map.Entry;
117 import java.util.Properties;
118 import java.util.Set;
119 import java.util.function.Consumer;
120 import java.util.regex.Matcher;
121 import java.util.regex.Pattern;
122
123 import static java.util.Comparator.comparing;
124 import static org.apache.maven.cli.CLIManager.COLOR;
125 import static org.apache.maven.cli.ResolveFile.resolveFile;
126 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
127
128
129
130
131
132
133 public class MavenCli
134 {
135 public static final String LOCAL_REPO_PROPERTY = "maven.repo.local";
136
137 public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory";
138
139 public static final String USER_HOME = System.getProperty( "user.home" );
140
141 public static final File USER_MAVEN_CONFIGURATION_HOME = new File( USER_HOME, ".m2" );
142
143 public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File( USER_MAVEN_CONFIGURATION_HOME, "toolchains.xml" );
144
145 public static final File DEFAULT_GLOBAL_TOOLCHAINS_FILE =
146 new File( System.getProperty( "maven.conf" ), "toolchains.xml" );
147
148 private static final String EXT_CLASS_PATH = "maven.ext.class.path";
149
150 private static final String EXTENSIONS_FILENAME = ".mvn/extensions.xml";
151
152 private static final String MVN_MAVEN_CONFIG = ".mvn/maven.config";
153
154 public static final String STYLE_COLOR_PROPERTY = "style.color";
155
156 private ClassWorld classWorld;
157
158 private LoggerManager plexusLoggerManager;
159
160 private ILoggerFactory slf4jLoggerFactory;
161
162 private Logger slf4jLogger;
163
164 private EventSpyDispatcher eventSpyDispatcher;
165
166 private ModelProcessor modelProcessor;
167
168 private Maven maven;
169
170 private MavenExecutionRequestPopulator executionRequestPopulator;
171
172 private ToolchainsBuilder toolchainsBuilder;
173
174 private DefaultSecDispatcher dispatcher;
175
176 private Map<String, ConfigurationProcessor> configurationProcessors;
177
178 private CLIManager cliManager;
179
180 public MavenCli()
181 {
182 this( null );
183 }
184
185
186 public MavenCli( ClassWorld classWorld )
187 {
188 this.classWorld = classWorld;
189 }
190
191 public static void main( String[] args )
192 {
193 int result = main( args, null );
194
195 System.exit( result );
196 }
197
198 public static int main( String[] args, ClassWorld classWorld )
199 {
200 MavenCli cli = new MavenCli();
201
202 MessageUtils.systemInstall();
203 MessageUtils.registerShutdownHook();
204 int result = cli.doMain( new CliRequest( args, classWorld ) );
205 MessageUtils.systemUninstall();
206
207 return result;
208 }
209
210
211 public static int doMain( String[] args, ClassWorld classWorld )
212 {
213 MavenCli cli = new MavenCli();
214 return cli.doMain( new CliRequest( args, classWorld ) );
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228 public int doMain( String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr )
229 {
230 PrintStream oldout = System.out;
231 PrintStream olderr = System.err;
232
233 final Set<String> realms;
234 if ( classWorld != null )
235 {
236 realms = new HashSet<>();
237 for ( ClassRealm realm : classWorld.getRealms() )
238 {
239 realms.add( realm.getId() );
240 }
241 }
242 else
243 {
244 realms = Collections.emptySet();
245 }
246
247 try
248 {
249 if ( stdout != null )
250 {
251 System.setOut( stdout );
252 }
253 if ( stderr != null )
254 {
255 System.setErr( stderr );
256 }
257
258 CliRequest cliRequest = new CliRequest( args, classWorld );
259 cliRequest.workingDirectory = workingDirectory;
260
261 return doMain( cliRequest );
262 }
263 finally
264 {
265 if ( classWorld != null )
266 {
267 for ( ClassRealm realm : new ArrayList<>( classWorld.getRealms() ) )
268 {
269 String realmId = realm.getId();
270 if ( !realms.contains( realmId ) )
271 {
272 try
273 {
274 classWorld.disposeRealm( realmId );
275 }
276 catch ( NoSuchRealmException ignored )
277 {
278
279 }
280 }
281 }
282 }
283 System.setOut( oldout );
284 System.setErr( olderr );
285 }
286 }
287
288
289 public int doMain( CliRequest cliRequest )
290 {
291 PlexusContainer localContainer = null;
292 try
293 {
294 initialize( cliRequest );
295 cli( cliRequest );
296 properties( cliRequest );
297 logging( cliRequest );
298 informativeCommands( cliRequest );
299 version( cliRequest );
300 localContainer = container( cliRequest );
301 commands( cliRequest );
302 configure( cliRequest );
303 toolchains( cliRequest );
304 populateRequest( cliRequest );
305 encryption( cliRequest );
306 repository( cliRequest );
307 return execute( cliRequest );
308 }
309 catch ( ExitException e )
310 {
311 return e.exitCode;
312 }
313 catch ( UnrecognizedOptionException e )
314 {
315
316 return 1;
317 }
318 catch ( BuildAbort e )
319 {
320 CLIReportingUtils.showError( slf4jLogger, "ABORTED", e, cliRequest.showErrors );
321
322 return 2;
323 }
324 catch ( Exception e )
325 {
326 CLIReportingUtils.showError( slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors );
327
328 return 1;
329 }
330 finally
331 {
332 if ( localContainer != null )
333 {
334 localContainer.dispose();
335 }
336 }
337 }
338
339 void initialize( CliRequest cliRequest )
340 throws ExitException
341 {
342 if ( cliRequest.workingDirectory == null )
343 {
344 cliRequest.workingDirectory = System.getProperty( "user.dir" );
345 }
346
347 if ( cliRequest.multiModuleProjectDirectory == null )
348 {
349 String basedirProperty = System.getProperty( MULTIMODULE_PROJECT_DIRECTORY );
350 if ( basedirProperty == null )
351 {
352 System.err.format(
353 "-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY );
354 throw new ExitException( 1 );
355 }
356 File basedir = new File( basedirProperty );
357 try
358 {
359 cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile();
360 }
361 catch ( IOException e )
362 {
363 cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile();
364 }
365 }
366
367
368
369
370
371 String mavenHome = System.getProperty( "maven.home" );
372
373 if ( mavenHome != null )
374 {
375 System.setProperty( "maven.home", new File( mavenHome ).getAbsolutePath() );
376 }
377 }
378
379 void cli( CliRequest cliRequest )
380 throws Exception
381 {
382
383
384
385
386 slf4jLogger = new Slf4jStdoutLogger();
387
388 cliManager = new CLIManager();
389
390 List<String> args = new ArrayList<>();
391 CommandLine mavenConfig = null;
392 try
393 {
394 File configFile = new File( cliRequest.multiModuleProjectDirectory, MVN_MAVEN_CONFIG );
395
396 if ( configFile.isFile() )
397 {
398 for ( String arg : Files.readAllLines( configFile.toPath(), Charset.defaultCharset() ) )
399 {
400 if ( !arg.isEmpty() )
401 {
402 args.add( arg );
403 }
404 }
405
406 mavenConfig = cliManager.parse( args.toArray( new String[0] ) );
407 List<?> unrecognized = mavenConfig.getArgList();
408 if ( !unrecognized.isEmpty() )
409 {
410 throw new ParseException( "Unrecognized maven.config entries: " + unrecognized );
411 }
412 }
413 }
414 catch ( ParseException e )
415 {
416 System.err.println( "Unable to parse maven.config: " + e.getMessage() );
417 cliManager.displayHelp( System.out );
418 throw e;
419 }
420
421 try
422 {
423 if ( mavenConfig == null )
424 {
425 cliRequest.commandLine = cliManager.parse( cliRequest.args );
426 }
427 else
428 {
429 cliRequest.commandLine = cliMerge( cliManager.parse( cliRequest.args ), mavenConfig );
430 }
431 }
432 catch ( ParseException e )
433 {
434 System.err.println( "Unable to parse command line options: " + e.getMessage() );
435 cliManager.displayHelp( System.out );
436 throw e;
437 }
438 }
439
440 private void informativeCommands( CliRequest cliRequest ) throws ExitException
441 {
442 if ( cliRequest.commandLine.hasOption( CLIManager.HELP ) )
443 {
444 cliManager.displayHelp( System.out );
445 throw new ExitException( 0 );
446 }
447
448 if ( cliRequest.commandLine.hasOption( CLIManager.VERSION ) )
449 {
450 if ( cliRequest.commandLine.hasOption( CLIManager.QUIET ) )
451 {
452 System.out.println( CLIReportingUtils.showVersionMinimal() );
453 }
454 else
455 {
456 System.out.println( CLIReportingUtils.showVersion() );
457 }
458 throw new ExitException( 0 );
459 }
460 }
461
462 private CommandLine cliMerge( CommandLine mavenArgs, CommandLine mavenConfig )
463 {
464 CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
465
466
467 for ( String arg : mavenArgs.getArgs() )
468 {
469 commandLineBuilder.addArg( arg );
470 }
471 for ( String arg : mavenConfig.getArgs() )
472 {
473 commandLineBuilder.addArg( arg );
474 }
475
476
477 List<Option> setPropertyOptions = new ArrayList<>();
478 for ( Option opt : mavenArgs.getOptions() )
479 {
480 if ( String.valueOf( CLIManager.SET_SYSTEM_PROPERTY ).equals( opt.getOpt() ) )
481 {
482 setPropertyOptions.add( opt );
483 }
484 else
485 {
486 commandLineBuilder.addOption( opt );
487 }
488 }
489 for ( Option opt : mavenConfig.getOptions() )
490 {
491 commandLineBuilder.addOption( opt );
492 }
493
494 for ( Option opt : setPropertyOptions )
495 {
496 commandLineBuilder.addOption( opt );
497 }
498 return commandLineBuilder.build();
499 }
500
501
502
503
504 void logging( CliRequest cliRequest )
505 {
506
507 cliRequest.verbose = cliRequest.commandLine.hasOption( CLIManager.VERBOSE )
508 || cliRequest.commandLine.hasOption( CLIManager.DEBUG );
509 cliRequest.quiet = !cliRequest.verbose && cliRequest.commandLine.hasOption( CLIManager.QUIET );
510 cliRequest.showErrors = cliRequest.verbose || cliRequest.commandLine.hasOption( CLIManager.ERRORS );
511
512 slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
513 Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration( slf4jLoggerFactory );
514
515 if ( cliRequest.verbose )
516 {
517 cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_DEBUG );
518 slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.DEBUG );
519 }
520 else if ( cliRequest.quiet )
521 {
522 cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_ERROR );
523 slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.ERROR );
524 }
525
526
527
528
529 String styleColor = cliRequest.getUserProperties().getProperty( STYLE_COLOR_PROPERTY, "auto" );
530 styleColor = cliRequest.commandLine.getOptionValue( COLOR, styleColor );
531 if ( "always".equals( styleColor ) || "yes".equals( styleColor ) || "force".equals( styleColor ) )
532 {
533 MessageUtils.setColorEnabled( true );
534 }
535 else if ( "never".equals( styleColor ) || "no".equals( styleColor ) || "none".equals( styleColor ) )
536 {
537 MessageUtils.setColorEnabled( false );
538 }
539 else if ( !"auto".equals( styleColor ) && !"tty".equals( styleColor ) && !"if-tty".equals( styleColor ) )
540 {
541 throw new IllegalArgumentException( "Invalid color configuration value '" + styleColor
542 + "'. Supported are 'auto', 'always', 'never'." );
543 }
544 else if ( cliRequest.commandLine.hasOption( CLIManager.BATCH_MODE )
545 || cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
546 {
547 MessageUtils.setColorEnabled( false );
548 }
549
550
551 if ( cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
552 {
553 File logFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.LOG_FILE ) );
554 logFile = resolveFile( logFile, cliRequest.workingDirectory );
555
556
557 try
558 {
559 PrintStream ps = new PrintStream( new FileOutputStream( logFile ) );
560 System.setOut( ps );
561 System.setErr( ps );
562 }
563 catch ( FileNotFoundException e )
564 {
565
566
567
568 }
569 }
570
571 slf4jConfiguration.activate();
572
573 plexusLoggerManager = new Slf4jLoggerManager();
574 slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
575
576 if ( cliRequest.commandLine.hasOption( CLIManager.FAIL_ON_SEVERITY ) )
577 {
578 String logLevelThreshold = cliRequest.commandLine.getOptionValue( CLIManager.FAIL_ON_SEVERITY );
579
580 if ( slf4jLoggerFactory instanceof MavenSlf4jWrapperFactory )
581 {
582 LogLevelRecorder logLevelRecorder = new LogLevelRecorder( logLevelThreshold );
583 ( (MavenSlf4jWrapperFactory) slf4jLoggerFactory ).setLogLevelRecorder( logLevelRecorder );
584 slf4jLogger.info( "Enabled to break the build on log level {}.", logLevelThreshold );
585 }
586 else
587 {
588 slf4jLogger.warn( "Expected LoggerFactory to be of type '{}', but found '{}' instead. "
589 + "The --fail-on-severity flag will not take effect.",
590 MavenSlf4jWrapperFactory.class.getName(), slf4jLoggerFactory.getClass().getName() );
591 }
592 }
593
594 if ( cliRequest.commandLine.hasOption( CLIManager.DEBUG ) )
595 {
596 slf4jLogger.warn( "The option '--debug' is deprecated and may be repurposed as Java debug"
597 + " in a future version. Use -X/--verbose instead." );
598 }
599 }
600
601 private void version( CliRequest cliRequest )
602 {
603 if ( cliRequest.verbose || cliRequest.commandLine.hasOption( CLIManager.SHOW_VERSION ) )
604 {
605 System.out.println( CLIReportingUtils.showVersion() );
606 }
607 }
608
609 private void commands( CliRequest cliRequest )
610 {
611 if ( cliRequest.showErrors )
612 {
613 slf4jLogger.info( "Error stacktraces are turned on." );
614 }
615
616 if ( MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
617 {
618 slf4jLogger.info( "Disabling strict checksum verification on all artifact downloads." );
619 }
620 else if ( MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
621 {
622 slf4jLogger.info( "Enabling strict checksum verification on all artifact downloads." );
623 }
624
625 if ( slf4jLogger.isDebugEnabled() )
626 {
627 slf4jLogger.debug( "Message scheme: {}", ( MessageUtils.isColorEnabled() ? "color" : "plain" ) );
628 if ( MessageUtils.isColorEnabled() )
629 {
630 MessageBuilder buff = MessageUtils.buffer();
631 buff.a( "Message styles: " );
632 buff.a( MessageUtils.level().debug( "debug" ) ).a( ' ' );
633 buff.a( MessageUtils.level().info( "info" ) ).a( ' ' );
634 buff.a( MessageUtils.level().warning( "warning" ) ).a( ' ' );
635 buff.a( MessageUtils.level().error( "error" ) ).a( ' ' );
636
637 buff.success( "success" ).a( ' ' );
638 buff.failure( "failure" ).a( ' ' );
639 buff.strong( "strong" ).a( ' ' );
640 buff.mojo( "mojo" ).a( ' ' );
641 buff.project( "project" );
642 slf4jLogger.debug( buff.toString() );
643 }
644 }
645 }
646
647
648
649 void properties( CliRequest cliRequest )
650 {
651 populateProperties( cliRequest.commandLine, cliRequest.systemProperties, cliRequest.userProperties );
652 }
653
654 PlexusContainer container( CliRequest cliRequest )
655 throws Exception
656 {
657 if ( cliRequest.classWorld == null )
658 {
659 cliRequest.classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
660 }
661
662 ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" );
663 if ( coreRealm == null )
664 {
665 coreRealm = cliRequest.classWorld.getRealms().iterator().next();
666 }
667
668 List<File> extClassPath = parseExtClasspath( cliRequest );
669
670 CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom( coreRealm );
671 List<CoreExtensionEntry> extensions =
672 loadCoreExtensions( cliRequest, coreRealm, coreEntry.getExportedArtifacts() );
673
674 ClassRealm containerRealm = setupContainerRealm( cliRequest.classWorld, coreRealm, extClassPath, extensions );
675
676 ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld( cliRequest.classWorld )
677 .setRealm( containerRealm ).setClassPathScanning( PlexusConstants.SCANNING_INDEX ).setAutoWiring( true )
678 .setJSR250Lifecycle( true ).setName( "maven" );
679
680 Set<String> exportedArtifacts = new HashSet<>( coreEntry.getExportedArtifacts() );
681 Set<String> exportedPackages = new HashSet<>( coreEntry.getExportedPackages() );
682 for ( CoreExtensionEntry extension : extensions )
683 {
684 exportedArtifacts.addAll( extension.getExportedArtifacts() );
685 exportedPackages.addAll( extension.getExportedPackages() );
686 }
687
688 final CoreExports exports = new CoreExports( containerRealm, exportedArtifacts, exportedPackages );
689
690 DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
691 {
692 @Override
693 protected void configure()
694 {
695 bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
696 bind( CoreExports.class ).toInstance( exports );
697 }
698 } );
699
700
701 container.setLookupRealm( null );
702 Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
703
704 container.setLoggerManager( plexusLoggerManager );
705
706 for ( CoreExtensionEntry extension : extensions )
707 {
708 container.discoverComponents( extension.getClassRealm(), new SessionScopeModule( container ),
709 new MojoExecutionScopeModule( container ) );
710 }
711
712 customizeContainer( container );
713
714 container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
715
716 eventSpyDispatcher = container.lookup( EventSpyDispatcher.class );
717
718 DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext();
719 Map<String, Object> data = eventSpyContext.getData();
720 data.put( "plexus", container );
721 data.put( "workingDirectory", cliRequest.workingDirectory );
722 data.put( "systemProperties", cliRequest.systemProperties );
723 data.put( "userProperties", cliRequest.userProperties );
724 data.put( "versionProperties", CLIReportingUtils.getBuildProperties() );
725 eventSpyDispatcher.init( eventSpyContext );
726
727
728 slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
729
730 maven = container.lookup( Maven.class );
731
732 executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
733
734 modelProcessor = createModelProcessor( container );
735
736 configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
737
738 toolchainsBuilder = container.lookup( ToolchainsBuilder.class );
739
740 dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" );
741
742 return container;
743 }
744
745 private List<CoreExtensionEntry> loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm,
746 Set<String> providedArtifacts )
747 throws Exception
748 {
749 if ( cliRequest.multiModuleProjectDirectory == null )
750 {
751 return Collections.emptyList();
752 }
753
754 File extensionsFile = new File( cliRequest.multiModuleProjectDirectory, EXTENSIONS_FILENAME );
755 if ( !extensionsFile.isFile() )
756 {
757 return Collections.emptyList();
758 }
759
760 List<CoreExtension> extensions = readCoreExtensionsDescriptor( extensionsFile );
761 if ( extensions.isEmpty() )
762 {
763 return Collections.emptyList();
764 }
765
766 ContainerConfiguration cc = new DefaultContainerConfiguration()
767 .setClassWorld( cliRequest.classWorld )
768 .setRealm( containerRealm )
769 .setClassPathScanning( PlexusConstants.SCANNING_INDEX )
770 .setAutoWiring( true )
771 .setJSR250Lifecycle( true )
772 .setName( "maven" );
773
774 DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
775 {
776 @Override
777 protected void configure()
778 {
779 bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
780 }
781 } );
782
783 try
784 {
785 container.setLookupRealm( null );
786
787 container.setLoggerManager( plexusLoggerManager );
788
789 container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
790
791 Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
792
793 executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
794
795 configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
796
797 configure( cliRequest );
798
799 MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request );
800
801 populateRequest( cliRequest, request );
802
803 request = executionRequestPopulator.populateDefaults( request );
804
805 BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class );
806
807 return Collections.unmodifiableList( resolver.loadCoreExtensions( request, providedArtifacts,
808 extensions ) );
809
810 }
811 finally
812 {
813 executionRequestPopulator = null;
814 container.dispose();
815 }
816 }
817
818 private List<CoreExtension> readCoreExtensionsDescriptor( File extensionsFile )
819 throws IOException, XmlPullParserException
820 {
821 CoreExtensionsXpp3Reader parser = new CoreExtensionsXpp3Reader();
822
823 try ( InputStream is = new BufferedInputStream( new FileInputStream( extensionsFile ) ) )
824 {
825
826 return parser.read( is ).getExtensions();
827 }
828
829 }
830
831 private ClassRealm setupContainerRealm( ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath,
832 List<CoreExtensionEntry> extensions )
833 throws Exception
834 {
835 if ( !extClassPath.isEmpty() || !extensions.isEmpty() )
836 {
837 ClassRealm extRealm = classWorld.newRealm( "maven.ext", null );
838
839 extRealm.setParentRealm( coreRealm );
840
841 slf4jLogger.debug( "Populating class realm '{}'", extRealm.getId() );
842
843 for ( File file : extClassPath )
844 {
845 slf4jLogger.debug( " included '{}'", file );
846
847 extRealm.addURL( file.toURI().toURL() );
848 }
849
850 for ( CoreExtensionEntry entry : reverse( extensions ) )
851 {
852 Set<String> exportedPackages = entry.getExportedPackages();
853 ClassRealm realm = entry.getClassRealm();
854 for ( String exportedPackage : exportedPackages )
855 {
856 extRealm.importFrom( realm, exportedPackage );
857 }
858 if ( exportedPackages.isEmpty() )
859 {
860
861 extRealm.importFrom( realm, realm.getId() );
862 }
863 }
864
865 return extRealm;
866 }
867
868 return coreRealm;
869 }
870
871 private static <T> List<T> reverse( List<T> list )
872 {
873 List<T> copy = new ArrayList<>( list );
874 Collections.reverse( copy );
875 return copy;
876 }
877
878 private List<File> parseExtClasspath( CliRequest cliRequest )
879 {
880 String extClassPath = cliRequest.userProperties.getProperty( EXT_CLASS_PATH );
881 if ( extClassPath == null )
882 {
883 extClassPath = cliRequest.systemProperties.getProperty( EXT_CLASS_PATH );
884 }
885
886 List<File> jars = new ArrayList<>();
887
888 if ( StringUtils.isNotEmpty( extClassPath ) )
889 {
890 for ( String jar : StringUtils.split( extClassPath, File.pathSeparator ) )
891 {
892 File file = resolveFile( new File( jar ), cliRequest.workingDirectory );
893
894 slf4jLogger.debug( " included '{}'", file );
895
896 jars.add( file );
897 }
898 }
899
900 return jars;
901 }
902
903
904
905
906 private void encryption( CliRequest cliRequest )
907 throws Exception
908 {
909 if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_MASTER_PASSWORD ) )
910 {
911 String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_MASTER_PASSWORD );
912
913 if ( passwd == null )
914 {
915 Console cons = System.console();
916 char[] password = ( cons == null ) ? null : cons.readPassword( "Master password: " );
917 if ( password != null )
918 {
919
920 passwd = String.copyValueOf( password );
921
922
923 java.util.Arrays.fill( password, ' ' );
924 }
925 }
926
927 DefaultPlexusCipher cipher = new DefaultPlexusCipher();
928
929 System.out.println(
930 cipher.encryptAndDecorate( passwd, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) );
931
932 throw new ExitException( 0 );
933 }
934 else if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_PASSWORD ) )
935 {
936 String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_PASSWORD );
937
938 if ( passwd == null )
939 {
940 Console cons = System.console();
941 char[] password = ( cons == null ) ? null : cons.readPassword( "Password: " );
942 if ( password != null )
943 {
944
945 passwd = String.copyValueOf( password );
946
947
948 java.util.Arrays.fill( password, ' ' );
949 }
950 }
951
952 String configurationFile = dispatcher.getConfigurationFile();
953
954 if ( configurationFile.startsWith( "~" ) )
955 {
956 configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
957 }
958
959 String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
960
961 String master = null;
962
963 SettingsSecurity sec = SecUtil.read( file, true );
964 if ( sec != null )
965 {
966 master = sec.getMaster();
967 }
968
969 if ( master == null )
970 {
971 throw new IllegalStateException( "Master password is not set in the setting security file: " + file );
972 }
973
974 DefaultPlexusCipher cipher = new DefaultPlexusCipher();
975 String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
976 System.out.println( cipher.encryptAndDecorate( passwd, masterPasswd ) );
977
978 throw new ExitException( 0 );
979 }
980 }
981
982 private void repository( CliRequest cliRequest )
983 throws Exception
984 {
985 if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_LOCAL_REPOSITORY ) || Boolean.getBoolean(
986 "maven.legacyLocalRepo" ) )
987 {
988 cliRequest.request.setUseLegacyLocalRepository( true );
989 }
990 }
991
992 private int execute( CliRequest cliRequest )
993 throws MavenExecutionRequestPopulationException
994 {
995 MavenExecutionRequest request = executionRequestPopulator.populateDefaults( cliRequest.request );
996
997 if ( cliRequest.request.getRepositoryCache() == null )
998 {
999 cliRequest.request.setRepositoryCache( new DefaultRepositoryCache() );
1000 }
1001
1002 eventSpyDispatcher.onEvent( request );
1003
1004 MavenExecutionResult result = maven.execute( request );
1005
1006 eventSpyDispatcher.onEvent( result );
1007
1008 eventSpyDispatcher.close();
1009
1010 if ( result.hasExceptions() )
1011 {
1012 ExceptionHandler handler = new DefaultExceptionHandler();
1013
1014 Map<String, String> references = new LinkedHashMap<>();
1015
1016 List<MavenProject> failedProjects = new ArrayList<>();
1017
1018 for ( Throwable exception : result.getExceptions() )
1019 {
1020 ExceptionSummary summary = handler.handleException( exception );
1021
1022 logSummary( summary, references, "", cliRequest.showErrors );
1023
1024 if ( exception instanceof LifecycleExecutionException )
1025 {
1026 failedProjects.add ( ( (LifecycleExecutionException) exception ).getProject() );
1027 }
1028 }
1029
1030 slf4jLogger.error( "" );
1031
1032 if ( !cliRequest.showErrors )
1033 {
1034 slf4jLogger.error( "To see the full stack trace of the errors, re-run Maven with the '{}' switch",
1035 buffer().strong( "-e" ) );
1036 }
1037 if ( !slf4jLogger.isDebugEnabled() )
1038 {
1039 slf4jLogger.error( "Re-run Maven using the '{}' switch to enable verbose output",
1040 buffer().strong( "-X" ) );
1041 }
1042
1043 if ( !references.isEmpty() )
1044 {
1045 slf4jLogger.error( "" );
1046 slf4jLogger.error( "For more information about the errors and possible solutions"
1047 + ", please read the following articles:" );
1048
1049 for ( Map.Entry<String, String> entry : references.entrySet() )
1050 {
1051 slf4jLogger.error( "{} {}", buffer().strong( entry.getValue() ), entry.getKey() );
1052 }
1053 }
1054
1055 if ( result.canResume() )
1056 {
1057 logBuildResumeHint( "mvn [args] -r" );
1058 }
1059 else if ( !failedProjects.isEmpty() )
1060 {
1061 List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
1062
1063
1064 failedProjects.sort( comparing( sortedProjects::indexOf ) );
1065
1066 MavenProject firstFailedProject = failedProjects.get( 0 );
1067 if ( !firstFailedProject.equals( sortedProjects.get( 0 ) ) )
1068 {
1069 String resumeFromSelector = getResumeFromSelector( sortedProjects, firstFailedProject );
1070 logBuildResumeHint( "mvn [args] -rf " + resumeFromSelector );
1071 }
1072 }
1073
1074 if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) )
1075 {
1076 slf4jLogger.info( "Build failures were ignored." );
1077
1078 return 0;
1079 }
1080 else
1081 {
1082 return 1;
1083 }
1084 }
1085 else
1086 {
1087 return 0;
1088 }
1089 }
1090
1091 private void logBuildResumeHint( String resumeBuildHint )
1092 {
1093 slf4jLogger.error( "" );
1094 slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
1095 slf4jLogger.error( buffer().a( " " ).strong( resumeBuildHint ).toString() );
1096 }
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115 String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject firstFailedProject )
1116 {
1117 boolean hasOverlappingArtifactId = mavenProjects.stream()
1118 .filter( project -> firstFailedProject.getArtifactId().equals( project.getArtifactId() ) )
1119 .count() > 1;
1120
1121 if ( hasOverlappingArtifactId )
1122 {
1123 return firstFailedProject.getGroupId() + ":" + firstFailedProject.getArtifactId();
1124 }
1125
1126 return ":" + firstFailedProject.getArtifactId();
1127 }
1128
1129 private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent,
1130 boolean showErrors )
1131 {
1132 String referenceKey = "";
1133
1134 if ( StringUtils.isNotEmpty( summary.getReference() ) )
1135 {
1136 referenceKey = references.get( summary.getReference() );
1137 if ( referenceKey == null )
1138 {
1139 referenceKey = "[Help " + ( references.size() + 1 ) + "]";
1140 references.put( summary.getReference(), referenceKey );
1141 }
1142 }
1143
1144 String msg = summary.getMessage();
1145
1146 if ( StringUtils.isNotEmpty( referenceKey ) )
1147 {
1148 if ( msg.indexOf( '\n' ) < 0 )
1149 {
1150 msg += " -> " + buffer().strong( referenceKey );
1151 }
1152 else
1153 {
1154 msg += "\n-> " + buffer().strong( referenceKey );
1155 }
1156 }
1157
1158 String[] lines = msg.split( "(\r\n)|(\r)|(\n)" );
1159 String currentColor = "";
1160
1161 for ( int i = 0; i < lines.length; i++ )
1162 {
1163
1164 String line = currentColor + lines[i];
1165
1166
1167 Matcher matcher = LAST_ANSI_SEQUENCE.matcher( line );
1168 String nextColor = "";
1169 if ( matcher.find() )
1170 {
1171 nextColor = matcher.group( 1 );
1172 if ( ANSI_RESET.equals( nextColor ) )
1173 {
1174
1175 nextColor = "";
1176 }
1177 }
1178
1179
1180 line = indent + line + ( "".equals( nextColor ) ? "" : ANSI_RESET );
1181
1182 if ( ( i == lines.length - 1 ) && ( showErrors
1183 || ( summary.getException() instanceof InternalErrorException ) ) )
1184 {
1185 slf4jLogger.error( line, summary.getException() );
1186 }
1187 else
1188 {
1189 slf4jLogger.error( line );
1190 }
1191
1192 currentColor = nextColor;
1193 }
1194
1195 indent += " ";
1196
1197 for ( ExceptionSummary child : summary.getChildren() )
1198 {
1199 logSummary( child, references, indent, showErrors );
1200 }
1201 }
1202
1203 private static final Pattern LAST_ANSI_SEQUENCE = Pattern.compile( "(\u001B\\[[;\\d]*[ -/]*[@-~])[^\u001B]*$" );
1204
1205 private static final String ANSI_RESET = "\u001B\u005Bm";
1206
1207 private void configure( CliRequest cliRequest )
1208 throws Exception
1209 {
1210
1211
1212
1213
1214
1215
1216 cliRequest.request.setEventSpyDispatcher( eventSpyDispatcher );
1217
1218
1219
1220
1221
1222
1223
1224
1225 int userSuppliedConfigurationProcessorCount = configurationProcessors.size() - 1;
1226
1227 if ( userSuppliedConfigurationProcessorCount == 0 )
1228 {
1229
1230
1231
1232
1233 configurationProcessors.get( SettingsXmlConfigurationProcessor.HINT ).process( cliRequest );
1234 }
1235 else if ( userSuppliedConfigurationProcessorCount == 1 )
1236 {
1237
1238
1239
1240 for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() )
1241 {
1242 String hint = entry.getKey();
1243 if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) )
1244 {
1245 ConfigurationProcessor configurationProcessor = entry.getValue();
1246 configurationProcessor.process( cliRequest );
1247 }
1248 }
1249 }
1250 else if ( userSuppliedConfigurationProcessorCount > 1 )
1251 {
1252
1253
1254
1255 StringBuilder sb = new StringBuilder(
1256 String.format( "%nThere can only be one user supplied ConfigurationProcessor, there are %s:%n%n",
1257 userSuppliedConfigurationProcessorCount ) );
1258 for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() )
1259 {
1260 String hint = entry.getKey();
1261 if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) )
1262 {
1263 ConfigurationProcessor configurationProcessor = entry.getValue();
1264 sb.append( String.format( "%s%n", configurationProcessor.getClass().getName() ) );
1265 }
1266 }
1267 throw new Exception( sb.toString() );
1268 }
1269 }
1270
1271 void toolchains( CliRequest cliRequest )
1272 throws Exception
1273 {
1274 File userToolchainsFile;
1275
1276 if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) )
1277 {
1278 userToolchainsFile =
1279 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) );
1280 userToolchainsFile = resolveFile( userToolchainsFile, cliRequest.workingDirectory );
1281
1282 if ( !userToolchainsFile.isFile() )
1283 {
1284 throw new FileNotFoundException(
1285 "The specified user toolchains file does not exist: " + userToolchainsFile );
1286 }
1287 }
1288 else
1289 {
1290 userToolchainsFile = DEFAULT_USER_TOOLCHAINS_FILE;
1291 }
1292
1293 File globalToolchainsFile;
1294
1295 if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) )
1296 {
1297 globalToolchainsFile =
1298 new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) );
1299 globalToolchainsFile = resolveFile( globalToolchainsFile, cliRequest.workingDirectory );
1300
1301 if ( !globalToolchainsFile.isFile() )
1302 {
1303 throw new FileNotFoundException(
1304 "The specified global toolchains file does not exist: " + globalToolchainsFile );
1305 }
1306 }
1307 else
1308 {
1309 globalToolchainsFile = DEFAULT_GLOBAL_TOOLCHAINS_FILE;
1310 }
1311
1312 cliRequest.request.setGlobalToolchainsFile( globalToolchainsFile );
1313 cliRequest.request.setUserToolchainsFile( userToolchainsFile );
1314
1315 DefaultToolchainsBuildingRequest toolchainsRequest = new DefaultToolchainsBuildingRequest();
1316 if ( globalToolchainsFile.isFile() )
1317 {
1318 toolchainsRequest.setGlobalToolchainsSource( new FileSource( globalToolchainsFile ) );
1319 }
1320 if ( userToolchainsFile.isFile() )
1321 {
1322 toolchainsRequest.setUserToolchainsSource( new FileSource( userToolchainsFile ) );
1323 }
1324
1325 eventSpyDispatcher.onEvent( toolchainsRequest );
1326
1327 slf4jLogger.debug( "Reading global toolchains from '{}'",
1328 getLocation( toolchainsRequest.getGlobalToolchainsSource(), globalToolchainsFile ) );
1329 slf4jLogger.debug( "Reading user toolchains from '{}'",
1330 getLocation( toolchainsRequest.getUserToolchainsSource(), userToolchainsFile ) );
1331
1332 ToolchainsBuildingResult toolchainsResult = toolchainsBuilder.build( toolchainsRequest );
1333
1334 eventSpyDispatcher.onEvent( toolchainsResult );
1335
1336 executionRequestPopulator.populateFromToolchains( cliRequest.request,
1337 toolchainsResult.getEffectiveToolchains() );
1338
1339 if ( !toolchainsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled() )
1340 {
1341 slf4jLogger.warn( "" );
1342 slf4jLogger.warn( "Some problems were encountered while building the effective toolchains" );
1343
1344 for ( Problem problem : toolchainsResult.getProblems() )
1345 {
1346 slf4jLogger.warn( "{} @ {}", problem.getMessage(), problem.getLocation() );
1347 }
1348
1349 slf4jLogger.warn( "" );
1350 }
1351 }
1352
1353 private Object getLocation( Source source, File defaultLocation )
1354 {
1355 if ( source != null )
1356 {
1357 return source.getLocation();
1358 }
1359 return defaultLocation;
1360 }
1361
1362 protected MavenExecutionRequest populateRequest( CliRequest cliRequest )
1363 {
1364 return populateRequest( cliRequest, cliRequest.request );
1365 }
1366
1367 private MavenExecutionRequest populateRequest( CliRequest cliRequest, MavenExecutionRequest request )
1368 {
1369 slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
1370 CommandLine commandLine = cliRequest.commandLine;
1371 String workingDirectory = cliRequest.workingDirectory;
1372 boolean quiet = cliRequest.quiet;
1373 boolean verbose = cliRequest.verbose;
1374 request.setShowErrors( cliRequest.showErrors );
1375 File baseDirectory = new File( workingDirectory, "" ).getAbsoluteFile();
1376
1377 disableOnPresentOption( commandLine, CLIManager.BATCH_MODE, request::setInteractiveMode );
1378 enableOnPresentOption( commandLine, CLIManager.SUPPRESS_SNAPSHOT_UPDATES, request::setNoSnapshotUpdates );
1379 request.setGoals( commandLine.getArgList() );
1380 request.setReactorFailureBehavior( determineReactorFailureBehaviour ( commandLine ) );
1381 disableOnPresentOption( commandLine, CLIManager.NON_RECURSIVE, request::setRecursive );
1382 enableOnPresentOption( commandLine, CLIManager.OFFLINE, request::setOffline );
1383 enableOnPresentOption( commandLine, CLIManager.UPDATE_SNAPSHOTS, request::setUpdateSnapshots );
1384 request.setGlobalChecksumPolicy( determineGlobalCheckPolicy( commandLine ) );
1385 request.setBaseDirectory( baseDirectory );
1386 request.setSystemProperties( cliRequest.systemProperties );
1387 request.setUserProperties( cliRequest.userProperties );
1388 request.setMultiModuleProjectDirectory( cliRequest.multiModuleProjectDirectory );
1389 request.setPom( determinePom( commandLine, workingDirectory, baseDirectory ) );
1390 request.setTransferListener( determineTransferListener( quiet, verbose, commandLine, request ) );
1391 request.setExecutionListener( determineExecutionListener() );
1392
1393 if ( ( request.getPom() != null ) && ( request.getPom().getParentFile() != null ) )
1394 {
1395 request.setBaseDirectory( request.getPom().getParentFile() );
1396 }
1397
1398 request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) );
1399 enableOnPresentOption( commandLine, CLIManager.RESUME, request::setResume );
1400 request.setMakeBehavior( determineMakeBehavior( commandLine ) );
1401 request.setCacheNotFound( true );
1402 request.setCacheTransferError( false );
1403
1404 performProjectActivation( commandLine, request.getProjectActivation() );
1405 performProfileActivation( commandLine, request.getProfileActivation() );
1406
1407 final String localRepositoryPath = determineLocalRepositoryPath( request );
1408 if ( localRepositoryPath != null )
1409 {
1410 request.setLocalRepositoryPath( localRepositoryPath );
1411 }
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421 final String threadConfiguration = commandLine.getOptionValue( CLIManager.THREADS );
1422
1423 if ( threadConfiguration != null )
1424 {
1425 int degreeOfConcurrency = calculateDegreeOfConcurrency( threadConfiguration );
1426 if ( degreeOfConcurrency > 1 )
1427 {
1428 request.setBuilderId( "multithreaded" );
1429 request.setDegreeOfConcurrency( degreeOfConcurrency );
1430 }
1431 }
1432
1433
1434
1435
1436 request.setBuilderId( commandLine.getOptionValue( CLIManager.BUILDER, request.getBuilderId() ) );
1437
1438 return request;
1439 }
1440
1441 private String determineLocalRepositoryPath( final MavenExecutionRequest request )
1442 {
1443 String userDefinedLocalRepo = request.getUserProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
1444 if ( userDefinedLocalRepo != null )
1445 {
1446 return userDefinedLocalRepo;
1447 }
1448
1449 return request.getSystemProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
1450 }
1451
1452 private File determinePom( final CommandLine commandLine, final String workingDirectory, final File baseDirectory )
1453 {
1454 String alternatePomFile = null;
1455 if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) )
1456 {
1457 alternatePomFile = commandLine.getOptionValue( CLIManager.ALTERNATE_POM_FILE );
1458 }
1459
1460 if ( alternatePomFile != null )
1461 {
1462 File pom = resolveFile( new File( alternatePomFile ), workingDirectory );
1463 if ( pom.isDirectory() )
1464 {
1465 pom = new File( pom, "pom.xml" );
1466 }
1467
1468 return pom;
1469 }
1470 else if ( modelProcessor != null )
1471 {
1472 File pom = modelProcessor.locatePom( baseDirectory );
1473
1474 if ( pom.isFile() )
1475 {
1476 return pom;
1477 }
1478 }
1479
1480 return null;
1481 }
1482
1483
1484 static void performProjectActivation( final CommandLine commandLine, final ProjectActivation projectActivation )
1485 {
1486 if ( commandLine.hasOption( CLIManager.PROJECT_LIST ) )
1487 {
1488 final String[] optionValues = commandLine.getOptionValues( CLIManager.PROJECT_LIST );
1489
1490 if ( optionValues == null || optionValues.length == 0 )
1491 {
1492 return;
1493 }
1494
1495 for ( final String optionValue : optionValues )
1496 {
1497 for ( String token : optionValue.split( "," ) )
1498 {
1499 String selector = token.trim();
1500 boolean active = true;
1501 if ( selector.charAt( 0 ) == '-' || selector.charAt( 0 ) == '!' )
1502 {
1503 active = false;
1504 selector = selector.substring( 1 );
1505 }
1506 else if ( token.charAt( 0 ) == '+' )
1507 {
1508 selector = selector.substring( 1 );
1509 }
1510
1511 boolean optional = selector.charAt( 0 ) == '?';
1512 selector = selector.substring( optional ? 1 : 0 );
1513
1514 projectActivation.addProjectActivation( selector, active, optional );
1515 }
1516 }
1517 }
1518 }
1519
1520
1521 static void performProfileActivation( final CommandLine commandLine, final ProfileActivation profileActivation )
1522 {
1523 if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) )
1524 {
1525 final String[] optionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES );
1526
1527 if ( optionValues == null || optionValues.length == 0 )
1528 {
1529 return;
1530 }
1531
1532 for ( final String optionValue : optionValues )
1533 {
1534 for ( String token : optionValue.split( "," ) )
1535 {
1536 String profileId = token.trim();
1537 boolean active = true;
1538 if ( profileId.charAt( 0 ) == '-' || profileId.charAt( 0 ) == '!' )
1539 {
1540 active = false;
1541 profileId = profileId.substring( 1 );
1542 }
1543 else if ( token.charAt( 0 ) == '+' )
1544 {
1545 profileId = profileId.substring( 1 );
1546 }
1547
1548 boolean optional = profileId.charAt( 0 ) == '?';
1549 profileId = profileId.substring( optional ? 1 : 0 );
1550
1551 profileActivation.addProfileActivation( profileId, active, optional );
1552 }
1553 }
1554 }
1555 }
1556
1557 private ExecutionListener determineExecutionListener()
1558 {
1559 ExecutionListener executionListener = new ExecutionEventLogger();
1560 if ( eventSpyDispatcher != null )
1561 {
1562 return eventSpyDispatcher.chainListener( executionListener );
1563 }
1564 else
1565 {
1566 return executionListener;
1567 }
1568 }
1569
1570 private String determineReactorFailureBehaviour( final CommandLine commandLine )
1571 {
1572 if ( commandLine.hasOption( CLIManager.FAIL_FAST ) )
1573 {
1574 return MavenExecutionRequest.REACTOR_FAIL_FAST;
1575 }
1576 else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) )
1577 {
1578 return MavenExecutionRequest.REACTOR_FAIL_AT_END;
1579 }
1580 else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) )
1581 {
1582 return MavenExecutionRequest.REACTOR_FAIL_NEVER;
1583 }
1584 else
1585 {
1586
1587 return MavenExecutionRequest.REACTOR_FAIL_FAST;
1588 }
1589 }
1590
1591 private TransferListener determineTransferListener( final boolean quiet,
1592 final boolean verbose,
1593 final CommandLine commandLine,
1594 final MavenExecutionRequest request )
1595 {
1596 if ( quiet || commandLine.hasOption( CLIManager.NO_TRANSFER_PROGRESS ) )
1597 {
1598 return new QuietMavenTransferListener();
1599 }
1600 else if ( request.isInteractiveMode() && !commandLine.hasOption( CLIManager.LOG_FILE ) )
1601 {
1602
1603
1604
1605
1606 return getConsoleTransferListener( verbose );
1607 }
1608 else
1609 {
1610
1611 return getBatchTransferListener();
1612 }
1613 }
1614
1615 private String determineMakeBehavior( final CommandLine cl )
1616 {
1617 if ( cl.hasOption( CLIManager.ALSO_MAKE ) && !cl.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
1618 {
1619 return MavenExecutionRequest.REACTOR_MAKE_UPSTREAM;
1620 }
1621 else if ( !cl.hasOption( CLIManager.ALSO_MAKE ) && cl.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
1622 {
1623 return MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM;
1624 }
1625 else if ( cl.hasOption( CLIManager.ALSO_MAKE ) && cl.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
1626 {
1627 return MavenExecutionRequest.REACTOR_MAKE_BOTH;
1628 }
1629 else
1630 {
1631 return null;
1632 }
1633 }
1634
1635 private String determineGlobalCheckPolicy( final CommandLine commandLine )
1636 {
1637 if ( commandLine.hasOption( CLIManager.CHECKSUM_FAILURE_POLICY ) )
1638 {
1639 return MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
1640 }
1641 else if ( commandLine.hasOption( CLIManager.CHECKSUM_WARNING_POLICY ) )
1642 {
1643 return MavenExecutionRequest.CHECKSUM_POLICY_WARN;
1644 }
1645 else
1646 {
1647 return null;
1648 }
1649 }
1650
1651 private void disableOnPresentOption( final CommandLine commandLine,
1652 final String option,
1653 final Consumer<Boolean> setting )
1654 {
1655 if ( commandLine.hasOption( option ) )
1656 {
1657 setting.accept( false );
1658 }
1659 }
1660
1661 private void disableOnPresentOption( final CommandLine commandLine,
1662 final char option,
1663 final Consumer<Boolean> setting )
1664 {
1665 disableOnPresentOption( commandLine, String.valueOf( option ), setting );
1666 }
1667
1668 private void enableOnPresentOption( final CommandLine commandLine,
1669 final String option,
1670 final Consumer<Boolean> setting )
1671 {
1672 if ( commandLine.hasOption( option ) )
1673 {
1674 setting.accept( true );
1675 }
1676 }
1677
1678 private void enableOnPresentOption( final CommandLine commandLine,
1679 final char option,
1680 final Consumer<Boolean> setting )
1681 {
1682 enableOnPresentOption( commandLine, String.valueOf( option ), setting );
1683 }
1684
1685 private void enableOnAbsentOption( final CommandLine commandLine,
1686 final char option,
1687 final Consumer<Boolean> setting )
1688 {
1689 if ( !commandLine.hasOption( option ) )
1690 {
1691 setting.accept( true );
1692 }
1693 }
1694
1695 int calculateDegreeOfConcurrency( String threadConfiguration )
1696 {
1697 if ( threadConfiguration.endsWith( "C" ) )
1698 {
1699 threadConfiguration = threadConfiguration.substring( 0, threadConfiguration.length() - 1 );
1700
1701 if ( !NumberUtils.isParsable( threadConfiguration ) )
1702 {
1703 throw new IllegalArgumentException( "Invalid threads core multiplier value: '" + threadConfiguration
1704 + "C'. Supported are int and float values ending with C." );
1705 }
1706
1707 float coreMultiplier = Float.parseFloat( threadConfiguration );
1708
1709 if ( coreMultiplier <= 0.0f )
1710 {
1711 throw new IllegalArgumentException( "Invalid threads core multiplier value: '" + threadConfiguration
1712 + "C'. Value must be positive." );
1713 }
1714
1715 int procs = Runtime.getRuntime().availableProcessors();
1716 int threads = (int) ( coreMultiplier * procs );
1717 return threads == 0 ? 1 : threads;
1718 }
1719 else
1720 {
1721 if ( !NumberUtils.isParsable( threadConfiguration ) )
1722 {
1723 throw new IllegalArgumentException( "Invalid threads value: '" + threadConfiguration
1724 + "'. Supported are int values." );
1725 }
1726
1727 try
1728 {
1729 int threads = Integer.parseInt( threadConfiguration );
1730
1731 if ( threads <= 0 )
1732 {
1733 throw new IllegalArgumentException( "Invalid threads value: '" + threadConfiguration
1734 + "'. Value must be positive." );
1735 }
1736
1737 return threads;
1738 }
1739 catch ( NumberFormatException e )
1740 {
1741 throw new IllegalArgumentException( "Invalid threads value: '" + threadConfiguration
1742 + "'. Supported are integer values." );
1743 }
1744 }
1745 }
1746
1747
1748
1749
1750
1751 static void populateProperties( CommandLine commandLine, Properties systemProperties, Properties userProperties )
1752 {
1753 EnvironmentUtils.addEnvVars( systemProperties );
1754
1755
1756
1757
1758
1759
1760
1761 final Properties userSpecifiedProperties = commandLine.getOptionProperties(
1762 String.valueOf( CLIManager.SET_SYSTEM_PROPERTY ) );
1763 userSpecifiedProperties.forEach(
1764 ( prop, value ) -> setCliProperty( (String) prop, (String) value, userProperties )
1765 );
1766
1767 SystemProperties.addSystemProperties( systemProperties );
1768
1769
1770
1771
1772
1773
1774 Properties buildProperties = CLIReportingUtils.getBuildProperties();
1775
1776 String mavenVersion = buildProperties.getProperty( CLIReportingUtils.BUILD_VERSION_PROPERTY );
1777 systemProperties.setProperty( "maven.version", mavenVersion );
1778
1779 String mavenBuildVersion = CLIReportingUtils.createMavenVersionString( buildProperties );
1780 systemProperties.setProperty( "maven.build.version", mavenBuildVersion );
1781 }
1782
1783 private static void setCliProperty( String name, String value, Properties properties )
1784 {
1785 properties.setProperty( name, value );
1786
1787
1788
1789
1790
1791
1792 System.setProperty( name, value );
1793 }
1794
1795 static class ExitException
1796 extends Exception
1797 {
1798 int exitCode;
1799
1800 ExitException( int exitCode )
1801 {
1802 this.exitCode = exitCode;
1803 }
1804 }
1805
1806
1807
1808
1809
1810 protected TransferListener getConsoleTransferListener( boolean printResourceNames )
1811 {
1812 return new ConsoleMavenTransferListener( System.out, printResourceNames );
1813 }
1814
1815 protected TransferListener getBatchTransferListener()
1816 {
1817 return new Slf4jMavenTransferListener();
1818 }
1819
1820 protected void customizeContainer( PlexusContainer container )
1821 {
1822 }
1823
1824 protected ModelProcessor createModelProcessor( PlexusContainer container )
1825 throws ComponentLookupException
1826 {
1827 return container.lookup( ModelProcessor.class );
1828 }
1829 }