This is an automated email from the ASF dual-hosted git repository. michaelo pushed a commit to branch maven-3.9.x in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/maven-3.9.x by this push: new e1e4f5bda [MNG-7511] Ensure the degreeOfConcurrency is a positive number in MavenExecutionRequest e1e4f5bda is described below commit e1e4f5bda02535f718785189082f4197037774f3 Author: Josef Cacek <josef.ca...@gmail.com> AuthorDate: Tue Jul 12 20:15:25 2022 +0200 [MNG-7511] Ensure the degreeOfConcurrency is a positive number in MavenExecutionRequest This closes #767 --- .../maven/lifecycle/internal/LifecycleStarter.java | 2 +- .../multithreaded/MultiThreadedBuilder.java | 2 +- .../main/java/org/apache/maven/cli/CLIManager.java | 2 +- .../main/java/org/apache/maven/cli/MavenCli.java | 68 +++++++++++++++++----- .../java/org/apache/maven/cli/MavenCliTest.java | 58 ++++++++++++------ 5 files changed, 96 insertions(+), 36 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java index cee807392..9bd74328b 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java @@ -119,7 +119,7 @@ public class LifecycleStarter } int degreeOfConcurrency = session.getRequest().getDegreeOfConcurrency(); - if ( degreeOfConcurrency >= 2 ) + if ( degreeOfConcurrency > 1 ) { logger.info( "" ); logger.info( String.format( "Using the %s implementation with a thread count of %d", diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java index 1be0e42ea..c2f9c5b6a 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java @@ -80,7 +80,7 @@ public class MultiThreadedBuilder throws ExecutionException, InterruptedException { int nThreads = Math.min( session.getRequest().getDegreeOfConcurrency(), session.getProjects().size() ); - boolean parallel = nThreads >= 2; + boolean parallel = nThreads > 1; // Propagate the parallel flag to the root session and all of the cloned sessions in each project segment session.setParallel( parallel ); for ( ProjectSegment segment : projectBuilds ) diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java index 2ad542457..8a8b04d9c 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java @@ -141,7 +141,7 @@ public class CLIManager options.addOption( Option.builder( Character.toString( SHOW_VERSION ) ).longOpt( "show-version" ).desc( "Display version information WITHOUT stopping build" ).build() ); options.addOption( Option.builder( ENCRYPT_MASTER_PASSWORD ).longOpt( "encrypt-master-password" ).hasArg().optionalArg( true ).desc( "Encrypt master security password" ).build() ); options.addOption( Option.builder( ENCRYPT_PASSWORD ).longOpt( "encrypt-password" ).hasArg().optionalArg( true ).desc( "Encrypt server password" ).build() ); - options.addOption( Option.builder( THREADS ).longOpt( "threads" ).hasArg().desc( "Thread count, for instance 2.0C where C is core multiplied" ).build() ); + options.addOption( Option.builder( THREADS ).longOpt( "threads" ).hasArg().desc( "Thread count, for instance 4 (int) or 2C/2.5C (int/float) where C is core multiplied" ).build() ); options.addOption( Option.builder( LEGACY_LOCAL_REPOSITORY ).longOpt( "legacy-local-repository" ).desc( "Use Maven 2 Legacy Local Repository behaviour, ie no use of _remote.repositories. Can also be activated by using -Dmaven.legacyLocalRepo=true" ).build() ); options.addOption( Option.builder( BUILDER ).longOpt( "builder" ).hasArg().desc( "The id of the build strategy to use" ).build() ); options.addOption( Option.builder( NO_TRANSFER_PROGRESS ).longOpt( "no-transfer-progress" ).desc( "Do not display transfer progress when downloading or uploading" ).build() ); diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java index ed695ebbf..6aded69b7 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java @@ -24,6 +24,7 @@ import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.UnrecognizedOptionException; +import org.apache.commons.lang3.math.NumberUtils; import org.apache.maven.BuildAbort; import org.apache.maven.InternalErrorException; import org.apache.maven.Maven; @@ -1584,18 +1585,11 @@ public class MavenCli if ( threadConfiguration != null ) { - // - // Default to the standard multithreaded builder - // - request.setBuilderId( "multithreaded" ); - - if ( threadConfiguration.contains( "C" ) ) - { - request.setDegreeOfConcurrency( calculateDegreeOfConcurrencyWithCoreMultiplier( threadConfiguration ) ); - } - else + int degreeOfConcurrency = calculateDegreeOfConcurrency( threadConfiguration ); + if ( degreeOfConcurrency > 1 ) { - request.setDegreeOfConcurrency( Integer.parseInt( threadConfiguration ) ); + request.setBuilderId( "multithreaded" ); + request.setDegreeOfConcurrency( degreeOfConcurrency ); } } @@ -1610,10 +1604,56 @@ public class MavenCli return request; } - int calculateDegreeOfConcurrencyWithCoreMultiplier( String threadConfiguration ) + int calculateDegreeOfConcurrency( String threadConfiguration ) { - int procs = Runtime.getRuntime().availableProcessors(); - return (int) ( Float.parseFloat( threadConfiguration.replace( "C", "" ) ) * procs ); + if ( threadConfiguration.endsWith( "C" ) ) + { + threadConfiguration = threadConfiguration.substring( 0, threadConfiguration.length() - 1 ); + + if ( !NumberUtils.isParsable( threadConfiguration ) ) + { + throw new IllegalArgumentException( "Invalid threads core multiplier value: '" + threadConfiguration + + "C'. Supported are int and float values ending with C." ); + } + + float coreMultiplier = Float.parseFloat( threadConfiguration ); + + if ( coreMultiplier <= 0.0f ) + { + throw new IllegalArgumentException( "Invalid threads core multiplier value: '" + threadConfiguration + + "C'. Value must be positive." ); + } + + int procs = Runtime.getRuntime().availableProcessors(); + int threads = (int) ( coreMultiplier * procs ); + return threads == 0 ? 1 : threads; + } + else + { + if ( !NumberUtils.isParsable( threadConfiguration ) ) + { + throw new IllegalArgumentException( "Invalid threads value: '" + threadConfiguration + + "'. Supported are int values." ); + } + + try + { + int threads = Integer.parseInt( threadConfiguration ); + + if ( threads <= 0 ) + { + throw new IllegalArgumentException( "Invalid threads value: '" + threadConfiguration + + "'. Value must be positive." ); + } + + return threads; + } + catch ( NumberFormatException e ) + { + throw new IllegalArgumentException( "Invalid threads value: '" + threadConfiguration + + "'. Supported are integer values." ); + } + } } // ---------------------------------------------------------------------- diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java index 7a96bbe5e..ff197c206 100644 --- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java +++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java @@ -21,6 +21,7 @@ package org.apache.maven.cli; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; @@ -33,8 +34,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.PrintStream; import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; import org.apache.commons.cli.ParseException; import org.apache.maven.Maven; @@ -46,11 +45,12 @@ import org.codehaus.plexus.PlexusContainer; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.function.ThrowingRunnable; import org.mockito.InOrder; public class MavenCliTest { - private MavenCli cli; + MavenCli cli; private String origBasedir; @@ -76,23 +76,27 @@ public class MavenCliTest } @Test - public void testCalculateDegreeOfConcurrencyWithCoreMultiplier() + public void testCalculateDegreeOfConcurrency() { - int cores = Runtime.getRuntime().availableProcessors(); - // -T2.2C - assertEquals( (int) ( cores * 2.2 ), cli.calculateDegreeOfConcurrencyWithCoreMultiplier( "C2.2" ) ); - // -TC2.2 - assertEquals( (int) ( cores * 2.2 ), cli.calculateDegreeOfConcurrencyWithCoreMultiplier( "2.2C" ) ); - - try - { - cli.calculateDegreeOfConcurrencyWithCoreMultiplier( "CXXX" ); - fail( "Should have failed with a NumberFormatException" ); - } - catch ( NumberFormatException e ) - { - // carry on - } + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "0" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "-1" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "0x4" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "1.0" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "1." ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "AA" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "C" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "C2.2C" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "C2.2" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "2C2" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "CXXX" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "XXXC" ) ); + + int cpus = Runtime.getRuntime().availableProcessors(); + assertEquals( (int) ( cpus * 2.2 ), cli.calculateDegreeOfConcurrency( "2.2C" ) ); + assertEquals( 1, cli.calculateDegreeOfConcurrency( "0.0001C" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "2.C" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "-2.2C" ) ); + assertThrows( IllegalArgumentException.class, new ConcurrencyCalculator( "0C" ) ); } @Test @@ -371,4 +375,20 @@ public class MavenCliTest assertEquals( MessageUtils.stripAnsiCodes( versionOut ), versionOut ); } + class ConcurrencyCalculator implements ThrowingRunnable + { + + private final String value; + + public ConcurrencyCalculator( String value ) + { + this.value = value; + } + + @Override + public void run() throws Throwable + { + cli.calculateDegreeOfConcurrency( value ); + } + } }