diff --git a/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java b/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java index 286b47866469..99e500c34c85 100644 --- a/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java +++ b/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java @@ -28,6 +28,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -149,6 +150,7 @@ public class MavenCommandLineExecutor extends AbstractMavenExecutor { private static final RequestProcessor UPDATE_INDEX_RP = new RequestProcessor(RunUtils.class.getName(), 5); private static final String ICON_MAVEN_PROJECT = "org/netbeans/modules/maven/resources/Maven2Icon.gif"; // NOI18N + /** * Execute maven build in NetBeans execution engine. * Most callers should rather use {@link #run} as this variant does no (non-late-bound) prerequisite checks. @@ -855,6 +857,11 @@ boolean isMaven2() { return version != null && version.startsWith("2"); } + private boolean isMavenDaemon() { + File mvnHome = EmbedderFactory.getEffectiveMavenHome(); + return MavenSettings.isMavenDaemon(Paths.get(mvnHome.getPath())); + } + private void injectEventSpy(final BeanRunConfig clonedConfig) { //TEMP String mavenPath = clonedConfig.getProperties().get(CosChecker.MAVENEXTCLASSPATH); @@ -878,16 +885,48 @@ private void injectEventSpy(final BeanRunConfig clonedConfig) { } private boolean isMultiThreaded(BeanRunConfig clonedConfig) { - String list = MavenSettings.getDefault().getDefaultOptions(); - for (String s : clonedConfig.getGoals()) { - list = list + " " + s; - } + + List params = new ArrayList<>(); + params.addAll(Arrays.asList(MavenSettings.getDefault().getDefaultOptions().split(" "))); + params.addAll(clonedConfig.getGoals()); if (clonedConfig.getPreExecution() != null) { - for (String s : clonedConfig.getPreExecution().getGoals()) { - list = list + " " + s; + params.addAll(clonedConfig.getPreExecution().getGoals()); + } + + return isMavenDaemon() ? isMultiThreadedMvnd(params) + : isMultiThreadedMaven(params); + } + + // mvnd is MT by default + static boolean isMultiThreadedMvnd(List params) { + for (int i = 0; i < params.size(); i++) { + String p = params.get(i); + if (p.equals("-1") || p.equals("--serial") || p.equals("-Dmvnd.serial")) { // "behave like standard maven" mode + return false; + } + if (i + 1 < params.size() && (p.equals("-T") || p.equals("--threads"))) { + if (params.get(i+1).equals("1")) { + return false; + } + } + try { + if (p.startsWith("-Dmvnd.threads=") && Integer.parseInt(p.substring(15)) == 1) { + return false; + } + } catch (NumberFormatException ignored) {} + } + return true; + } + + // mvn is ST by default + static boolean isMultiThreadedMaven(List params) { + for (int i = 0; i < params.size() - 1; i++) { + String p = params.get(i); + if ((p.equals("-T") || p.equals("--threads")) && !params.get(i+1).equals("1")) { + return true; } } - return list.contains("-T") || list.contains("--threads"); + return false; } private File guessBestMaven(RunConfig clonedConfig, InputOutput ioput) { diff --git a/java/maven/src/org/netbeans/modules/maven/execute/cmd/ShellConstructor.java b/java/maven/src/org/netbeans/modules/maven/execute/cmd/ShellConstructor.java index d1d661585f5a..5433e7f413aa 100644 --- a/java/maven/src/org/netbeans/modules/maven/execute/cmd/ShellConstructor.java +++ b/java/maven/src/org/netbeans/modules/maven/execute/cmd/ShellConstructor.java @@ -20,7 +20,6 @@ package org.netbeans.modules.maven.execute.cmd; import java.io.File; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -44,8 +43,7 @@ public ShellConstructor(@NonNull File mavenHome) { public List construct() { // use mvnd if its the home of a daemon - String mavenDaemonSuffixDetection = Utilities.isWindows() ? ".exe" : ""; - String ex = Files.exists(Paths.get(mavenHome.getPath(), "bin", "mvnd" + mavenDaemonSuffixDetection)) ? "mvnd" : "mvn"; //NOI18N + String ex = MavenSettings.isMavenDaemon(Paths.get(mavenHome.getPath())) ? "mvnd" : "mvn"; //NOI18N List command = new ArrayList<>(); diff --git a/java/maven/src/org/netbeans/modules/maven/options/MavenSettings.java b/java/maven/src/org/netbeans/modules/maven/options/MavenSettings.java index bda5cbabf209..850fd7670843 100644 --- a/java/maven/src/org/netbeans/modules/maven/options/MavenSettings.java +++ b/java/maven/src/org/netbeans/modules/maven/options/MavenSettings.java @@ -31,12 +31,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Properties; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.maven.execution.MavenExecutionRequest; @@ -48,6 +50,7 @@ import org.openide.filesystems.URLMapper; import org.openide.util.NbBundle; import org.openide.util.NbPreferences; +import org.openide.util.Utilities; import org.openide.util.WeakSet; /** @@ -87,6 +90,8 @@ public final class MavenSettings { private static final String PROP_USE_REGISTRY = "usePluginRegistry"; //NOI18N public static final String PROP_NETWORK_PROXY = "networkProxy"; + private static final Pattern MAVEN_CORE_JAR_PATTERN = Pattern.compile("maven-core-(\\d+\\.\\d+\\.\\d+)\\.jar"); // NOI18N + private static final MavenSettings INSTANCE = new MavenSettings(); private final Set listeners = new WeakSet<>(); @@ -471,7 +476,6 @@ public void setBinaryDownloadStrategy(DownloadStrategy ds) { } public static @CheckForNull String getCommandLineMavenVersion(File mavenHome) { - Path lib = Paths.get(mavenHome.getPath(), "lib"); // mvn layout // NOI18N if (!Files.exists(lib)) { lib = Paths.get(mavenHome.getPath(), "mvn", "lib"); // mvnd layout // NOI18N @@ -480,6 +484,20 @@ public void setBinaryDownloadStrategy(DownloadStrategy ds) { } } + // try to resolve maven version by checking maven-core jar name + try (Stream mavenCoreVersions = Files.list(lib) + .map(file -> file.getFileName().toString()) + .filter(file -> file.startsWith("maven-core")) // NOI18N + .map(file -> MAVEN_CORE_JAR_PATTERN.matcher(file)) + .filter(matcher -> matcher.matches()) + .map(matcher -> matcher.group(1))) { + Optional mavenCoreVersion = mavenCoreVersions.findFirst(); + if (mavenCoreVersion.isPresent()) { + return mavenCoreVersion.get(); + } + } catch (IOException ignored) {} + + // try to resolve maven version by parsing pom.properties try { try (Stream jars = Files.list(lib).filter(file -> file.toString().endsWith(".jar"))) { // NOI18N for (Path jar : jars.collect(Collectors.toList())) { @@ -500,6 +518,12 @@ public void setBinaryDownloadStrategy(DownloadStrategy ds) { return null; } + public static boolean isMavenDaemon(Path mavenHome) { + String mvndExecutableName = Utilities.isWindows() ? "mvnd.exe" : "mvnd"; + + return Files.exists(mavenHome.resolve("bin").resolve(mvndExecutableName)); + } + private static List searchMavenRuntimes(String[] paths, boolean stopOnFirstValid) { List runtimes = new ArrayList<>(); for (String path : paths) { diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenCommandParametersAnalyzerTest.java b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenCommandParametersAnalyzerTest.java new file mode 100644 index 000000000000..e7f7ef49477d --- /dev/null +++ b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenCommandParametersAnalyzerTest.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.maven.execute; + +import java.util.Arrays; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +import org.junit.Test; + +/** + * + * @author Benjamin Asbach (asbachb.netbeans@impl.it) + */ +public class MavenCommandParametersAnalyzerTest { + + @Test + public void defaultIsSingleThreaded() { + assertFalse(isMultiThreadedMaven("")); + } + + @Test + public void validateMultiThreaded1() { + assertTrue(isMultiThreadedMaven("-T 10")); + } + + @Test + public void validateMultiThreaded2() { + assertTrue(isMultiThreadedMaven("-T 2")); + } + + @Test + public void validateMultiThreaded3() { + assertTrue(isMultiThreadedMaven("-Dmaven.test.skip=true -T 10")); + } + + @Test + public void validateMultiThreaded4() { + assertTrue(isMultiThreadedMaven("-Dmaven.test.skip=true -T 2")); + } + + @Test + public void validateMultiThreaded5() { + assertTrue(isMultiThreadedMaven("-Dmaven.test.skip=true -T 10 -Dmaven.test.skip=true ")); + } + + @Test + public void validateMultiThreaded6() { + assertTrue(isMultiThreadedMaven("-Dmaven.test.skip=true -T 2 -Dmaven.test.skip=true ")); + } + + @Test + public void validateMultiThreaded7() { + assertTrue(isMultiThreadedMaven("-T 10 -Dmaven.test.skip=true")); + } + + @Test + public void validateMultiThreaded8() { + assertTrue(isMultiThreadedMaven("-T 2 -Dmaven.test.skip=true")); + } + + @Test + public void validateMultiThreaded9() { + assertTrue(isMultiThreadedMaven("--threads 10")); + } + + @Test + public void validateMultiThreaded10() { + assertTrue(isMultiThreadedMaven("--threads 2")); + } + + @Test + public void validateMultiThreaded11() { + assertTrue(isMultiThreadedMaven("-Dmaven.test.skip=true --threads 10")); + } + + @Test + public void validateMultiThreaded12() { + assertTrue(isMultiThreadedMaven("-Dmaven.test.skip=true --threads 2")); + } + + @Test + public void validateMultiThreaded13() { + assertTrue(isMultiThreadedMaven("-Dmaven.test.skip=true --threads 10 -Dmaven.test.skip=true ")); + } + + @Test + public void validateMultiThreaded14() { + assertTrue(isMultiThreadedMaven("-Dmaven.test.skip=true --threads 2 -Dmaven.test.skip=true ")); + } + + @Test + public void validateMultiThreaded15() { + assertTrue(isMultiThreadedMaven("--threads 10 -Dmaven.test.skip=true")); + } + + @Test + public void validateMultiThreaded16() { + assertTrue(isMultiThreadedMaven("--threads 2 -Dmaven.test.skip=true")); + } + + @Test + public void validateSingleThreaded1() { + assertFalse(isMultiThreadedMaven("--threads 1")); + } + + @Test + public void validateSingleThreaded2() { + assertFalse(isMultiThreadedMaven("-T 1")); + } + + private boolean isMultiThreadedMaven(String params) { + return MavenCommandLineExecutor.isMultiThreadedMaven(Arrays.asList(params.split(" "))); + } +} diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenDaemonCommandParametersAnalyzerTest.java b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenDaemonCommandParametersAnalyzerTest.java new file mode 100644 index 000000000000..edeeb9c933e3 --- /dev/null +++ b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenDaemonCommandParametersAnalyzerTest.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.maven.execute; + +import java.util.Arrays; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +import org.junit.Test; + +/** + * + * @author Benjamin Asbach (asbachb.netbeans@impl.it) + */ +public class MavenDaemonCommandParametersAnalyzerTest { + + @Test + public void defaultIsSingleThreaded() { + assertTrue(checkisMultiThreadedMvnd("")); + } + + @Test + public void validateMultiThreaded1() { + assertTrue(checkisMultiThreadedMvnd("-T 10")); + } + + @Test + public void validateMultiThreaded3() { + assertTrue(checkisMultiThreadedMvnd("-Dmaven.test.skip=true -T 10")); + } + + @Test + public void validateMultiThreaded5() { + assertTrue(checkisMultiThreadedMvnd("-Dmaven.test.skip=true -T 10 -Dmaven.test.skip=true ")); + } + + @Test + public void validateMultiThreaded7() { + assertTrue(checkisMultiThreadedMvnd("-T 10 -Dmaven.test.skip=true")); + } + + + @Test + public void validateMultiThreaded2() { + assertTrue(checkisMultiThreadedMvnd("-T 2")); + } + + @Test + public void validateMultiThreaded4() { + assertTrue(checkisMultiThreadedMvnd("-Dmaven.test.skip=true -T 2")); + } + + @Test + public void validateMultiThreaded6() { + assertTrue(checkisMultiThreadedMvnd("-Dmaven.test.skip=true -T 2 -Dmaven.test.skip=true ")); + } + + @Test + public void validateMultiThreaded8() { + assertTrue(checkisMultiThreadedMvnd("-T 2 -Dmaven.test.skip=true")); + } + + + @Test + public void validateMultiThreaded9() { + assertTrue(checkisMultiThreadedMvnd("--threads 10")); + } + + @Test + public void validateMultiThreaded11() { + assertTrue(checkisMultiThreadedMvnd("-Dmaven.test.skip=true --threads 10")); + } + + @Test + public void validateMultiThreaded13() { + assertTrue(checkisMultiThreadedMvnd("-Dmaven.test.skip=true --threads 10 -Dmaven.test.skip=true ")); + } + + @Test + public void validateMultiThreaded15() { + assertTrue(checkisMultiThreadedMvnd("--threads 10 -Dmaven.test.skip=true")); + } + + @Test + public void validateMultiThreaded10() { + assertTrue(checkisMultiThreadedMvnd("--threads 2")); + } + + @Test + public void validateMultiThreaded12() { + assertTrue(checkisMultiThreadedMvnd("-Dmaven.test.skip=true --threads 2")); + } + + @Test + public void validateMultiThreaded14() { + assertTrue(checkisMultiThreadedMvnd("-Dmaven.test.skip=true --threads 2 -Dmaven.test.skip=true ")); + } + + @Test + public void validateMultiThreaded16() { + assertTrue(checkisMultiThreadedMvnd("--threads 2 -Dmaven.test.skip=true")); + } + + @Test + public void validateMultiThreaded17() { + assertTrue(checkisMultiThreadedMvnd("-Dmvnd.threads=2 -Dmaven.test.skip=true")); + } + + @Test + public void validateSingleThreaded1() { + assertFalse(checkisMultiThreadedMvnd("--threads 1")); + } + + @Test + public void validateSingleThreaded3() { + assertFalse(checkisMultiThreadedMvnd("-Dmaven.test.skip=true --threads 1")); + } + + @Test + public void validateSingleThreaded5() { + assertFalse(checkisMultiThreadedMvnd("--threads 1 -Dmaven.test.skip=true")); + } + + @Test + public void validateSingleThreaded2() { + assertFalse(checkisMultiThreadedMvnd("-T 1")); + } + + @Test + public void validateSingleThreaded4() { + assertFalse(checkisMultiThreadedMvnd("-Dmaven.test.skip=true -T 1")); + } + + @Test + public void validateSingleThreaded6() { + assertFalse(checkisMultiThreadedMvnd("-T 1 -Dmaven.test.skip=true")); + } + + @Test + public void validateSingleThreaded7() { + assertFalse(checkisMultiThreadedMvnd("-Dmvnd.threads=1")); + } + + @Test + public void validateSingleThreaded8() { + assertTrue(checkisMultiThreadedMvnd("-Dmvnd.threads=foo -Dmaven.test.skip=true")); + } + + private boolean checkisMultiThreadedMvnd(String params) { + return MavenCommandLineExecutor.isMultiThreadedMvnd(Arrays.asList(params.split(" "))); + } +}