Let -h/--help display also mvnd specific options #243

This commit is contained in:
Peter Palaga
2020-12-08 09:59:05 +01:00
parent 234f59ecb1
commit 3a4d86bc64
15 changed files with 843 additions and 182 deletions

103
build-plugin/pom.xml Normal file
View File

@@ -0,0 +1,103 @@
<!--
Copyright 2019 the original author or authors.
Licensed 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.
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mvndaemon.mvnd</groupId>
<artifactId>mvnd</artifactId>
<version>0.1.2-SNAPSHOT</version>
</parent>
<artifactId>mvnd-build-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>Maven Daemon - Documentation Maven Plugin</name>
<properties>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<roaster.version>2.22.2.Final</roaster.version>
<maven.plugin-tools.version>3.6.0</maven.plugin-tools.version>
<maven-plugin-plugin.version>${maven.plugin-tools.version}</maven-plugin-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>${maven.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>${maven.plugin-tools.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.forge.roaster</groupId>
<artifactId>roaster-jdt</artifactId>
<version>${roaster.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>${maven-plugin-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<configuration>
<goalPrefix>mvnd-build</goalPrefix>
<mojoDependencies>
<dep>org.apache.maven:maven-plugin-api</dep>
</mojoDependencies>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,184 @@
/*
* Copyright 2019 the original author or authors.
*
* Licensed 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.mvndaemon.mvnd.plugin.doc;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import javax.security.sasl.SaslClientFactory;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster.model.source.EnumConstantSource;
import org.jboss.forge.roaster.model.source.JavaDocSource;
import org.jboss.forge.roaster.model.source.JavaEnumSource;
/**
* Extracts JavaDoc blocks from enum entries and stores them into a properties file.
*/
@Mojo(name = "doc", defaultPhase = LifecyclePhase.NONE, threadSafe = true, requiresProject = true, requiresDependencyResolution = ResolutionScope.NONE)
public class DocMojo extends AbstractMojo {
/**
* The current project's <code>${basedir}</code>
*/
@Parameter(readonly = true, defaultValue = "${project.basedir}")
File baseDir;
/** A list of fully qualified enum names to process */
@Parameter(defaultValue = "org.mvndaemon.mvnd.common.Environment,org.mvndaemon.mvnd.common.OptionType")
String[] enums;
/** If {@code true} the execution of this mojo will be skipped altogether; otherwise this mojo will be executed. */
@Parameter(defaultValue = "false", property = "mvnd.build.doc.skip")
boolean skip;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
final Log log = getLog();
if (skip) {
log.info(getClass().getSimpleName() + " skipped per skip parameter");
return;
}
final Path basePath = baseDir.toPath();
for (String enumClassName : enums) {
extractEnumJavaDoc(basePath, enumClassName);
}
}
static void extractEnumJavaDoc(Path basePath, String enumClassName) throws MojoFailureException {
final String classRelPath = enumClassName.replace('.', '/');
final Path enumClassLocation = basePath.resolve("src/main/java")
.resolve(classRelPath + ".java");
final Path propsPath = basePath.resolve("target/classes/" + classRelPath + ".javadoc.properties");
try {
Files.createDirectories(propsPath.getParent());
} catch (IOException e) {
throw new IllegalStateException("Could not create " + propsPath.getParent(), e);
}
if (!Files.isRegularFile(enumClassLocation)) {
throw new IllegalStateException(enumClassLocation + " does not exist: ");
}
try {
final JavaEnumSource source = Roaster.parse(JavaEnumSource.class, enumClassLocation.toFile());
final Properties optionsProperties = new SortedProperties();
for (EnumConstantSource enumConst : source.getEnumConstants()) {
final JavaDocSource<EnumConstantSource> javaDoc = enumConst.getJavaDoc();
final String javadocText = javaDoc.getText();
optionsProperties.setProperty(enumConst.getName(), javadocText);
}
optionsProperties.store(Files.newOutputStream(propsPath), null);
} catch (IOException e) {
throw new MojoFailureException("Could not parse " + enumClassLocation, e);
}
}
/**
* A {@link Properties} with a binarily reproducible {@code store()} operation.
*/
static class SortedProperties extends Properties {
private static final long serialVersionUID = 5983297690254771479L;
@Override
public synchronized Enumeration<Object> keys() {
final Iterator<Object> it = new TreeSet<>(keySet()).iterator();
return new Enumeration<Object>() {
public boolean hasMoreElements() {
return it.hasNext();
}
public Object nextElement() {
return (SaslClientFactory) it.next();
}
};
}
public Set<Map.Entry<Object, Object>> entrySet() {
Comparator<Map.Entry<Object, Object>> comparator = Comparator.comparing(e -> (Comparable) e.getKey());
final Set<Map.Entry<Object, Object>> result = new TreeSet<>(comparator);
result.addAll(super.entrySet());
return result;
}
@Override
public void store(Writer writer, String comments)
throws IOException {
super.store(new SkipFirstLineBufferedWriter(writer), null);
}
@Override
public void store(OutputStream out, String comments)
throws IOException {
this.store(new OutputStreamWriter(out, "8859_1"), comments);
}
static class SkipFirstLineBufferedWriter extends BufferedWriter {
private boolean firstLine = true;
public SkipFirstLineBufferedWriter(Writer out) {
super(out);
}
@Override
public void newLine() throws IOException {
if (firstLine) {
firstLine = false;
} else {
write('\n');
}
}
@Override
public void write(String s, int off, int len) throws IOException {
if (!firstLine) {
super.write(s, off, len);
}
}
@Override
public void write(char cbuf[], int off, int len) throws IOException {
if (!firstLine) {
super.write(cbuf, off, len);
}
}
}
}
}

View File

@@ -327,13 +327,13 @@ public class DaemonConnector {
args.add("-Xmx" + maxHeapSize);
}
args.add(Environment.MVND_HOME.asCommandLineProperty(mvndHome.toString()));
args.add(Environment.LOGBACK_CONFIGURATION_FILE
.asCommandLineProperty(parameters.logbackConfigurationPath().toString()));
args.add(Environment.MVND_UID.asCommandLineProperty(uid));
args.add(Environment.MVND_DAEMON_STORAGE.asCommandLineProperty(parameters.daemonStorage().toString()));
args.add(Environment.MVND_REGISTRY.asCommandLineProperty(parameters.registry().toString()));
args.addAll(parameters.getDaemonCommandLineProperties());
Environment.MVND_HOME.appendAsCommandLineOption(args::add, mvndHome.toString());
Environment.LOGBACK_CONFIGURATION_FILE
.appendAsCommandLineOption(args::add, parameters.logbackConfigurationPath().toString());
Environment.MVND_UID.appendAsCommandLineOption(args::add, uid);
Environment.MVND_DAEMON_STORAGE.appendAsCommandLineOption(args::add, parameters.daemonStorage().toString());
Environment.MVND_REGISTRY.appendAsCommandLineOption(args::add, parameters.registry().toString());
parameters.discriminatingCommandLineOptions(args::add);
args.add(MavenDaemon.class.getName());
command = String.join(" ", args);

View File

@@ -31,10 +31,12 @@ import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntUnaryOperator;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.maven.cli.internal.extension.model.CoreExtension;
import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader;
import org.codehaus.plexus.util.StringUtils;
@@ -71,24 +73,28 @@ public class DaemonParameters {
}
public List<String> getDaemonOpts() {
return Arrays.stream(Environment.values())
.filter(Environment::isDiscriminating)
.map(v -> v.asDaemonOpt(property(v).orFail().asString()))
return discriminatingValues()
.map(envValue -> envValue.envKey.asDaemonOpt(envValue.asString()))
.collect(Collectors.toList());
}
public Map<String, String> getDaemonOptsMap() {
return Arrays.stream(Environment.values())
.filter(Environment::isDiscriminating)
.collect(Collectors.toMap(Environment::getProperty,
v -> property(v).orFail().asString()));
return discriminatingValues()
.collect(Collectors.toMap(
envValue -> envValue.envKey.getProperty(),
EnvValue::asString));
}
public List<String> getDaemonCommandLineProperties() {
Stream<EnvValue> discriminatingValues() {
return Arrays.stream(Environment.values())
.filter(Environment::isDiscriminating)
.map(v -> v.asCommandLineProperty(property(v).orFail().asString()))
.collect(Collectors.toList());
.map(env -> property(env))
.filter(EnvValue::isSet);
}
public void discriminatingCommandLineOptions(Consumer<String> args) {
discriminatingValues()
.forEach(envValue -> envValue.envKey.appendAsCommandLineOption(args, envValue.asString()));
}
public Path mvndHome() {
@@ -350,7 +356,7 @@ public class DaemonParameters {
throw new RuntimeException("Unable to parse core extensions", e);
}
} else {
return env.getDef();
return env.getDefault();
}
}
@@ -506,7 +512,7 @@ public class DaemonParameters {
}
public EnvValue orDefault() {
return orDefault(envKey::getDef);
return orDefault(envKey::getDefault);
}
public EnvValue orDefault(Supplier<String> defaultSupplier) {
@@ -516,28 +522,32 @@ public class DaemonParameters {
public EnvValue orFail() {
return new EnvValue(this, envKey, new ValueSource(sb -> sb, () -> {
final StringBuilder sb = new StringBuilder("Could not get value for ")
.append(Environment.class.getSimpleName())
.append(".").append(envKey.name()).append(" from any of the following sources: ");
/*
* Compose the description functions to invert the order thus getting the resolution order in the
* message
*/
Function<StringBuilder, StringBuilder> description = (s -> s);
EnvValue val = this;
while (val != null) {
description = description.compose(val.valueSource.descriptionFunction);
val = val.previous;
if (val != null) {
description = description.compose(s -> s.append(", "));
}
}
description.apply(sb);
throw new IllegalStateException(sb.toString());
throw couldNotgetValue();
}));
}
IllegalStateException couldNotgetValue() {
EnvValue val = this;
final StringBuilder sb = new StringBuilder("Could not get value for ")
.append(Environment.class.getSimpleName())
.append(".").append(envKey.name()).append(" from any of the following sources: ");
/*
* Compose the description functions to invert the order thus getting the resolution order in the
* message
*/
Function<StringBuilder, StringBuilder> description = (s -> s);
while (val != null) {
description = description.compose(val.valueSource.descriptionFunction);
val = val.previous;
if (val != null) {
description = description.compose(s -> s.append(", "));
}
}
description.apply(sb);
return new IllegalStateException(sb.toString());
}
String get() {
if (previous != null) {
final String result = previous.get();
@@ -591,5 +601,15 @@ public class DaemonParameters {
return TimeUtils.toDuration(get());
}
public boolean isSet() {
if (get() != null) {
return true;
} else if (envKey.isOptional()) {
return false;
} else {
throw couldNotgetValue();
}
}
}
}

View File

@@ -82,6 +82,19 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.mvndaemon.mvnd</groupId>
<artifactId>mvnd-build-maven-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<goals>
<goal>doc</goal>
</goals>
<phase>generate-resources</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.takari.maven.plugins</groupId>
<artifactId>takari-lifecycle-plugin</artifactId>

View File

@@ -15,13 +15,21 @@
*/
package org.mvndaemon.mvnd.common;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
@@ -29,7 +37,7 @@ import java.util.stream.Stream;
*
* Duration properties such as {@link #MVND_IDLE_TIMEOUT}, {@link #MVND_KEEP_ALIVE},
* {@link #MVND_EXPIRATION_CHECK_DELAY} or {@link #MVND_LOG_PURGE_PERIOD} are expressed
* in a human readable format such as {@code 2h30m}, {@code 600ms} or {@code 10 seconds}.
* in a human readable format such as <code>2h30m</code>, <code>600ms</code> or <code>10 seconds</code>.
* The available units are <i>d/day/days</i>, <i>h/hour/hours</i>, <i>m/min/minute/minutes</i>,
* <i>s/sec/second/seconds</i> and <i>ms/millis/msec/milliseconds</i>.
*/
@@ -40,139 +48,150 @@ public enum Environment {
//
/**
* The location of the logback configuration file
* The location of the Logback configuration file the daemon should use to configure its logging.
*/
LOGBACK_CONFIGURATION_FILE("logback.configurationFile", null, null, false),
LOGBACK_CONFIGURATION_FILE("logback.configurationFile", null, null, OptionType.PATH, Flags.NONE),
//
// System properties
//
/** java home directory */
JAVA_HOME("java.home", "JAVA_HOME", null, false),
/** mvnd home directory */
MVND_HOME("mvnd.home", "MVND_HOME", null, false),
/** user home directory */
USER_HOME("user.home", null, null, false),
/** user current dir */
USER_DIR("user.dir", null, null, false),
/** Java home for starting the daemon */
JAVA_HOME("java.home", "JAVA_HOME", null, OptionType.PATH, Flags.NONE),
/**
* The daemon installation directory. The client normally sets this according to where its <code>mvnd</code>
* executable is located
*/
MVND_HOME("mvnd.home", "MVND_HOME", null, OptionType.PATH, Flags.NONE),
/** The user home directory */
USER_HOME("user.home", null, null, OptionType.PATH, Flags.NONE),
/** The current working directory */
USER_DIR("user.dir", null, null, OptionType.PATH, Flags.NONE),
//
// Maven properties
//
/** path to the maven local repository */
MAVEN_REPO_LOCAL("maven.repo.local", null, null, false),
/** location of the maven settings file */
MAVEN_SETTINGS("maven.settings", null, null, false, new String[] { "--settings", "-s" }),
/** root directory of a multi module project */
MAVEN_MULTIMODULE_PROJECT_DIRECTORY("maven.multiModuleProjectDirectory", null, null, false),
/** The path to the Maven local repository */
MAVEN_REPO_LOCAL("maven.repo.local", null, null, OptionType.PATH, Flags.NONE),
/** The location of the maven settings file */
MAVEN_SETTINGS("maven.settings", null, null, OptionType.PATH, Flags.NONE, "-s", "--settings"),
/** The root directory of the current multi module Maven project */
MAVEN_MULTIMODULE_PROJECT_DIRECTORY("maven.multiModuleProjectDirectory", null, null, OptionType.PATH, Flags.NONE),
//
// mvnd properties
//
/**
* Location of the user supplied mvnd properties
* The location of the user supplied <code>mvnd.properties</code> file.
*/
MVND_PROPERTIES_PATH("mvnd.propertiesPath", "MVND_PROPERTIES_PATH", null, false),
MVND_PROPERTIES_PATH("mvnd.propertiesPath", "MVND_PROPERTIES_PATH", null, OptionType.PATH, Flags.NONE),
/**
* Directory where mvnd stores its files (the registry and the daemon logs).
* The directory under which the daemon stores its registry, log files, etc.
* Default: <code>${user.home}/.m2/mvnd</code>
*/
MVND_DAEMON_STORAGE("mvnd.daemonStorage", null, null, false),
MVND_DAEMON_STORAGE("mvnd.daemonStorage", null, null, OptionType.PATH, Flags.NONE),
/**
* The path to the daemon registry, defaults to <code>${mvnd.daemonStorage}/registry.bin</code>
* The path to the daemon registry.
* Default: <code>${mvnd.daemonStorage}/registry.bin</code>
*/
MVND_REGISTRY("mvnd.registry", null, null, false),
MVND_REGISTRY("mvnd.registry", null, null, OptionType.PATH, Flags.NONE),
/**
* Property that can be set to avoid buffering the output and display events continuously, closer to the usual maven
* display. Passing {@code -B} or {@code --batch-mode} on the command line enables this too for the given build.
* If <code>true</code> the log messages are displayed continuously like with stock Maven; otherwise buffer the
* messages and output at the end of the build, grouped by module. Passing <code>-B</code> or
* <code>--batch-mode</code> on the command line enables this too for the given build.
*/
MVND_NO_BUFERING("mvnd.noBuffering", null, "false", false),
MVND_NO_BUFERING("mvnd.noBuffering", null, Boolean.FALSE, OptionType.BOOLEAN, Flags.NONE),
/**
* The number of log lines to display for each Maven module that is built in parallel.
* The number of log lines to display for each Maven module that is built in parallel. The value can be increased
* or decreased by pressing + or - key during the build respectively. This option has no effect with
* <code>-Dmvnd.noBuffering=true</code>, <code>-B</code> or <code>--batch-mode</code>.
*/
MVND_ROLLING_WINDOW_SIZE("mvnd.rollingWindowSize", null, "0", false),
MVND_ROLLING_WINDOW_SIZE("mvnd.rollingWindowSize", null, "0", OptionType.INTEGER, Flags.NONE),
/**
* The automatic log purge period.
* Daemon log files older than this value will be removed automatically.
*/
MVND_LOG_PURGE_PERIOD("mvnd.logPurgePeriod", null, "7d", false, true),
MVND_LOG_PURGE_PERIOD("mvnd.logPurgePeriod", null, "7 days", OptionType.DURATION, Flags.NONE),
/**
* Property to disable using a daemon (usefull for debugging, and only available in non native mode).
* If <code>true</code>, the client and daemon will run in the same JVM that exits when the build is finished;
* otherwise the client starts/connects to a long living daemon process. This option is only available with
* non-native clients and is useful mostly for debugging.
*/
MVND_NO_DAEMON("mvnd.noDaemon", "MVND_NO_DAEMON", "false", true),
MVND_NO_DAEMON("mvnd.noDaemon", "MVND_NO_DAEMON", Boolean.FALSE, OptionType.BOOLEAN, Flags.DISCRIMINATING),
/**
* Property to launch the daemon in debug mode with the following JVM argument
* <code>-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000</code>
* If <code>true</code>, the daemon will be launched in debug mode with the following JVM argument:
* <code>-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000</code>; otherwise the debug argument is
* not passed to the daemon.
*/
MVND_DEBUG("mvnd.debug", null, false, true),
MVND_DEBUG("mvnd.debug", null, Boolean.FALSE, OptionType.BOOLEAN, Flags.DISCRIMINATING),
/**
* Duration after which an usused daemon will shut down.
* A time period after which an unused daemon will terminate by itself.
*/
MVND_IDLE_TIMEOUT("mvnd.idleTimeout", null, "3 hours", true, true),
MVND_IDLE_TIMEOUT("mvnd.idleTimeout", null, "3 hours", OptionType.DURATION, Flags.DISCRIMINATING),
/**
* Time after which a daemon will send a keep-alive message to the client if the current build
* has produced no output.
* If the daemon does not send any message to the client in this period of time, send a keep-alive message so that
* the client knows that the daemon is still alive.
*/
MVND_KEEP_ALIVE("mvnd.keepAlive", null, "100 ms", true, true),
MVND_KEEP_ALIVE("mvnd.keepAlive", null, "100 ms", OptionType.DURATION, Flags.DISCRIMINATING),
/**
* The maximum number of keep alive message that can be lost before the client considers the daemon
* as having had a failure.
* The maximum number of keep alive messages that can be missed by the client before the client considers the daemon
* to be dead.
*/
MVND_MAX_LOST_KEEP_ALIVE("mvnd.maxLostKeepAlive", null, 30, false),
MVND_MAX_LOST_KEEP_ALIVE("mvnd.maxLostKeepAlive", null, 30, OptionType.INTEGER, Flags.NONE),
/**
* The minimum number of threads to use when constructing the default {@code -T} parameter for the daemon.
* This value is ignored if the user passes @{@code -T}, @{@code --threads} or {@code -Dmvnd.threads} on the command
* line or if he sets {@code mvnd.threads} in {@code ~/.m2/mvnd.properties}.
* The minimum number of threads to use when constructing the default <code>-T</code> parameter for the daemon.
* This value is ignored if the user passes <code>-T</code>, <code>--threads</code> or <code>-Dmvnd.threads</code>
* on the command line or if he sets <code>mvnd.threads</code> in <code>~/.m2/mvnd.properties</code>.
*/
MVND_MIN_THREADS("mvnd.minThreads", null, 1, false),
MVND_MIN_THREADS("mvnd.minThreads", null, 1, OptionType.INTEGER, Flags.NONE),
/**
* The number of threads to pass to the daemon; same syntax as Maven's {@code -T}/{@code --threads} option. Ignored
* if the user passes @{@code -T}, @{@code --threads} or {@code -Dmvnd.threads} on the command
* line.
* The number of threads to pass to the daemon; same syntax as Maven's <code>-T</code>/<code>--threads</code>
* option.
*/
MVND_THREADS("mvnd.threads", null, null, false, new String[] { "--threads", "-T" }),
MVND_THREADS("mvnd.threads", null, null, OptionType.STRING, Flags.NONE, "-T", "--threads"),
/**
* The maven builder name to use. Ignored if the user passes
*
* {@code -b} or {@code --builder} on the command line
* The builder implementation the daemon should use
*/
MVND_BUILDER("mvnd.builder", null, "smart", false, new String[] { "--builder", "-b" }),
MVND_BUILDER("mvnd.builder", null, "smart", OptionType.STRING, Flags.NONE, "-b", "--builder"),
/**
* Internal system property set by the client when starting the daemon to identify its id
* An ID for a newly started daemon
*/
MVND_UID("mvnd.uid", null, null, false),
MVND_UID("mvnd.uid", null, null, OptionType.STRING, Flags.INTERNAL),
/**
* Internal option to specify the maven extension classpath
*/
MVND_EXT_CLASSPATH("mvnd.extClasspath", null, null, true),
MVND_EXT_CLASSPATH("mvnd.extClasspath", null, null, OptionType.STRING, Flags.DISCRIMINATING | Flags.INTERNAL),
/**
* Internal option to specify the list of maven extension to register
*/
MVND_CORE_EXTENSIONS("mvnd.coreExtensions", null, null, true),
MVND_CORE_EXTENSIONS("mvnd.coreExtensions", null, null, OptionType.STRING, Flags.DISCRIMINATING | Flags.INTERNAL),
/**
* JVM options for the daemon
* The <code>-Xms</code> value to pass to the daemon
*/
MVND_MIN_HEAP_SIZE("mvnd.minHeapSize", null, "128M", true),
MVND_MIN_HEAP_SIZE("mvnd.minHeapSize", null, "128M", OptionType.MEMORY_SIZE, Flags.DISCRIMINATING),
/**
* JVM options for the daemon
* The <code>-Xmx</code> value to pass to the daemon
*/
MVND_MAX_HEAP_SIZE("mvnd.maxHeapSize", null, "2G", true),
MVND_MAX_HEAP_SIZE("mvnd.maxHeapSize", null, "2G", OptionType.MEMORY_SIZE, Flags.DISCRIMINATING),
/**
* Additional JVM args for the daemon
* Additional JVM args to pass to the daemon
*/
MVND_JVM_ARGS("mvnd.jvmArgs", null, "", true),
MVND_JVM_ARGS("mvnd.jvmArgs", null, null, OptionType.STRING, Flags.DISCRIMINATING | Flags.OPTIONAL),
/**
* JVM options for the daemon
* If <code>true</code>, the <code>-ea</code> option will be passed to the daemon; otherwise the <code>-ea</code>
* option is not passed to the daemon.
*/
MVND_ENABLE_ASSERTIONS("mvnd.enableAssertions", null, false, true),
MVND_ENABLE_ASSERTIONS("mvnd.enableAssertions", null, Boolean.FALSE, OptionType.BOOLEAN, Flags.DISCRIMINATING),
/**
* Interval to check if the daemon should expire
* The daemon will check this often whether it should exit.
*/
MVND_EXPIRATION_CHECK_DELAY("mvnd.expirationCheckDelay", null, "10 seconds", true, true),
MVND_EXPIRATION_CHECK_DELAY("mvnd.expirationCheckDelay", null, "10 seconds", OptionType.DURATION, Flags.DISCRIMINATING),
/**
* Period after which idle daemons will shut down
* Period after which idle duplicate daemons will be shut down. Duplicate daemons are daemons with the same set of
* discriminating start parameters.
*/
MVND_DUPLICATE_DAEMON_GRACE_PERIOD("mvnd.duplicateDaemonGracePeriod", null, "10 seconds", true, true),
;
MVND_DUPLICATE_DAEMON_GRACE_PERIOD("mvnd.duplicateDaemonGracePeriod", null, "10 seconds", OptionType.DURATION,
Flags.DISCRIMINATING),
;
static Properties properties;
@@ -190,31 +209,19 @@ public enum Environment {
private final String property;
private final String environmentVariable;
private final String def;
private final boolean discriminating;
private final boolean duration;
private final String[] options;
private final String default_;
private final int flags;
private final OptionType type;
private final List<String> options;
Environment(String property, String environmentVariable, Object def, boolean discriminating) {
this(property, environmentVariable, def, discriminating, false, null);
}
Environment(String property, String environmentVariable, Object def, boolean discriminating, boolean duration) {
this(property, environmentVariable, def, discriminating, duration, null);
}
Environment(String property, String environmentVariable, Object def, boolean discriminating, String[] options) {
this(property, environmentVariable, def, discriminating, false, options);
}
Environment(String property, String environmentVariable, Object def, boolean discriminating, boolean duration,
String[] options) {
Environment(String property, String environmentVariable, Object default_, OptionType type, int flags,
String... options) {
this.property = Objects.requireNonNull(property);
this.environmentVariable = environmentVariable;
this.def = def != null ? def.toString() : null;
this.discriminating = discriminating;
this.duration = duration;
this.options = options;
this.default_ = default_ != null ? default_.toString() : null;
this.flags = flags;
this.type = type;
this.options = options.length == 0 ? Collections.emptyList() : Collections.unmodifiableList(Arrays.asList(options));
}
public String getProperty() {
@@ -225,12 +232,28 @@ public enum Environment {
return environmentVariable;
}
public String getDef() {
return def;
public String getDefault() {
return default_;
}
public List<String> getOptions() {
return options;
}
public OptionType getType() {
return type;
}
public boolean isDiscriminating() {
return discriminating;
return (flags & Flags.DISCRIMINATING) != 0;
}
public boolean isInternal() {
return (flags & Flags.INTERNAL) != 0;
}
public boolean isOptional() {
return (flags & Flags.OPTIONAL) != 0;
}
public String asString() {
@@ -241,6 +264,17 @@ public enum Environment {
return val;
}
public Optional<String> asOptional() {
String val = getProperty(property);
if (val != null) {
return Optional.of(val);
} else if (isOptional()) {
return Optional.empty();
} else {
throw new IllegalStateException("The system property " + property + " is missing");
}
}
public int asInt() {
return Integer.parseInt(asString());
}
@@ -261,21 +295,30 @@ public enum Environment {
return TimeUtils.toDuration(asString());
}
protected String prepareValue(String value) {
// For durations, we need to make sure spaces are removed, so reformat the value
return duration ? TimeUtils.printDuration(TimeUtils.toMilliSeconds(value)) : value;
}
public String asDaemonOpt(String value) {
return property + "=" + prepareValue(value);
return property + "=" + type.normalize(value);
}
public String asCommandLineProperty(String value) {
return (options != null ? options[0] : "-D" + property) + "=" + prepareValue(value);
public void appendAsCommandLineOption(Consumer<String> args, String value) {
if (!options.isEmpty()) {
args.accept(options.get(0));
args.accept(type.normalize(value));
} else {
args.accept("-D" + property + "=" + type.normalize(value));
}
}
public boolean hasCommandLineProperty(Collection<String> args) {
final String[] prefixes = options != null ? options : new String[] { "-D" + property + "=" };
public boolean hasCommandOption(Collection<String> args) {
final String[] prefixes;
if (options.isEmpty()) {
prefixes = new String[] { "-D" + property + "=" };
} else if (property != null) {
prefixes = new String[options.size() + 1];
options.toArray(prefixes);
prefixes[options.size()] = "-D" + property + "=";
} else {
prefixes = options.toArray(new String[options.size()]);
}
return args.stream().anyMatch(arg -> Stream.of(prefixes).anyMatch(arg::startsWith));
}
@@ -292,4 +335,45 @@ public enum Environment {
return "executable".equals(System.getProperty("org.graalvm.nativeimage.kind"));
}
public static Stream<DocumentedEnumEntry<Environment>> documentedEntries() {
Properties props = new Properties();
Environment[] values = values();
final String cliOptionsPath = values[0].getClass().getSimpleName() + ".javadoc.properties";
try (InputStream in = Environment.class.getResourceAsStream(cliOptionsPath)) {
props.load(in);
} catch (IOException e) {
throw new RuntimeException("Could not read " + cliOptionsPath, e);
}
return Stream.of(values)
.filter(env -> !env.isInternal())
.sorted(Comparator.comparing(Environment::getProperty))
.map(env -> new DocumentedEnumEntry<>(env, props.getProperty(env.name())));
}
public static class DocumentedEnumEntry<E> {
private final E entry;
private final String javaDoc;
public DocumentedEnumEntry(E entry, String javaDoc) {
this.entry = entry;
this.javaDoc = javaDoc;
}
public E getEntry() {
return entry;
}
public String getJavaDoc() {
return javaDoc;
}
}
static class Flags {
private static final int NONE = 0b0;
private static final int DISCRIMINATING = 0b1;
private static final int INTERNAL = 0b10;
public static final int OPTIONAL = 0b100;
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2019 the original author or authors.
*
* Licensed 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.mvndaemon.mvnd.common;
import java.io.IOException;
import java.io.InputStream;
import java.util.Comparator;
import java.util.Properties;
import java.util.stream.Stream;
import org.mvndaemon.mvnd.common.Environment.DocumentedEnumEntry;
public enum OptionType {
/** <code>true</code> or <code>false</code> */
BOOLEAN,
/**
* An unlabeled whole number of milliseconds or a whole number followed by an optional space and a unit
* which may be one of the following (in EBNF notation): <code>d[ay[s]]</code>, <code>h[our[s]]</code>,
* <code>m[in[ute[s]]]</code>, <code>s[ec[ond[s]]]</code> or <code>m[illi]s[ec[ond[s]]]</code>.
* <p>
* Examples: <code>7 days</code>, <code>7days</code>, <code>7d</code>, <code>100 milliseconds</code>,
* <code>100 millis</code>, <code>100ms</code>, <code>100</code>
*/
DURATION {
@Override
public String normalize(String value) {
return TimeUtils.printDuration(TimeUtils.toMilliSeconds(value));
}
},
/** A whole number */
INTEGER,
/**
* An amount of memory as accepted by the <code>-Xm*</code> family of HotSpot JVM options. Examples:
* <code>1024m</code>, <code>2g</code>, <code>5G</code>
*/
MEMORY_SIZE,
/** A local file system path */
PATH,
/** A string */
STRING;
public String normalize(String value) {
return value;
}
public static Stream<DocumentedEnumEntry<OptionType>> documentedEntries() {
Properties props = new Properties();
OptionType[] values = values();
final String cliOptionsPath = values[0].getClass().getSimpleName() + ".javadoc.properties";
try (InputStream in = Environment.class.getResourceAsStream(cliOptionsPath)) {
props.load(in);
} catch (IOException e) {
throw new RuntimeException("Could not read " + cliOptionsPath, e);
}
return Stream.of(values)
.sorted(Comparator.comparing(OptionType::name))
.map(env -> new DocumentedEnumEntry<>(env, props.getProperty(env.name())));
}
}

View File

@@ -19,12 +19,10 @@
package org.apache.maven.cli;
import com.google.inject.AbstractModule;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
@@ -96,6 +94,7 @@ import org.mvndaemon.mvnd.common.Environment;
import org.mvndaemon.mvnd.logging.internal.Slf4jLoggerManager;
import org.mvndaemon.mvnd.logging.smart.AbstractLoggingSpy;
import org.mvndaemon.mvnd.logging.smart.LoggingExecutionListener;
import org.mvndaemon.mvnd.logging.smart.LoggingOutputStream;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -252,7 +251,7 @@ public class DaemonMavenCli {
}
} catch (ParseException e) {
System.err.println("Unable to parse maven.config: " + e.getMessage());
cliManager.displayHelp(System.out);
AbstractLoggingSpy.instance().append(MvndHelpFormatter.displayHelp(cliManager));
throw e;
}
@@ -264,16 +263,12 @@ public class DaemonMavenCli {
}
} catch (ParseException e) {
System.err.println("Unable to parse command line options: " + e.getMessage());
cliManager.displayHelp(System.out);
AbstractLoggingSpy.instance().append(MvndHelpFormatter.displayHelp(cliManager));
throw e;
}
if (cliRequest.commandLine.hasOption(CLIManager.HELP)) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (PrintStream out = new PrintStream(baos, false, StandardCharsets.UTF_8.name())) {
cliManager.displayHelp(out);
}
AbstractLoggingSpy.instance().append(null, new String(baos.toByteArray(), StandardCharsets.UTF_8));
AbstractLoggingSpy.instance().append(MvndHelpFormatter.displayHelp(cliManager));
throw new ExitException(0);
}
@@ -342,6 +337,11 @@ public class DaemonMavenCli {
MessageUtils.setColorEnabled(false);
}
// Workaround for https://github.com/mvndaemon/mvnd/issues/39
final ch.qos.logback.classic.Logger mvndLogger = (ch.qos.logback.classic.Logger) slf4jLoggerFactory
.getLogger("org.mvndaemon.mvnd");
mvndLogger.setLevel(ch.qos.logback.classic.Level.toLevel(System.getProperty("mvnd.log.level", "INFO")));
// LOG STREAMS
if (cliRequest.commandLine.hasOption(CLIManager.LOG_FILE)) {
File logFile = new File(cliRequest.commandLine.getOptionValue(CLIManager.LOG_FILE));
@@ -357,17 +357,16 @@ public class DaemonMavenCli {
// Ignore
//
}
} else {
System.setOut(new LoggingOutputStream(s -> mvndLogger.info("[stdout] " + s)).printStream());
System.setErr(new LoggingOutputStream(s -> mvndLogger.error("[stderr] " + s)).printStream());
}
// Workaround for https://github.com/mvndaemon/mvnd/issues/39
ch.qos.logback.classic.Logger mvndLogger = (ch.qos.logback.classic.Logger) slf4jLoggerFactory
.getLogger("org.mvndaemon.mvnd");
mvndLogger.setLevel(ch.qos.logback.classic.Level.toLevel(System.getProperty("mvnd.log.level", "INFO")));
}
private void version(CliRequest cliRequest) throws ExitException {
if (cliRequest.debug || cliRequest.commandLine.hasOption(CLIManager.VERSION)) {
AbstractLoggingSpy.instance().append(null, CLIReportingUtils.showVersion());
AbstractLoggingSpy.instance().append(CLIReportingUtils.showVersion());
if (cliRequest.commandLine.hasOption(CLIManager.VERSION)) {
throw new ExitException(0);
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright 2019 the original author or authors.
*
* Licensed 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.apache.maven.cli;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.cli.HelpFormatter;
import org.mvndaemon.mvnd.common.Environment;
import org.mvndaemon.mvnd.common.OptionType;
/**
* Combines the help message from the stock Maven with {@code mvnd}'s help message.
*/
public class MvndHelpFormatter {
private static final Pattern HTML_TAGS_PATTERN = Pattern.compile("<[^>]*>");
private static final Pattern COLUMNS_DETECTOR_PATTERN = Pattern.compile("^[ ]+[^s]");
private static final Pattern WS_PATTERN = Pattern.compile("\\s+");
static String toPlainText(String javadocText) {
return HTML_TAGS_PATTERN.matcher(javadocText).replaceAll("");
}
/**
* Returns Maven option descriptions combined with mvnd options descriptions
*
* @param cliManager
* @return the string containing the help message
*/
public static String displayHelp(CLIManager cliManager) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (PrintStream out = new PrintStream(baos, false, StandardCharsets.UTF_8.name())) {
cliManager.displayHelp(out);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
final String mvnHelp = new String(baos.toByteArray(), StandardCharsets.UTF_8);
final Matcher m = COLUMNS_DETECTOR_PATTERN.matcher(mvnHelp);
final String indent = m.find() ? m.group() : " ";
final String lineSeparator = System.lineSeparator();
final StringBuilder help = new StringBuilder(mvnHelp)
.append(lineSeparator)
.append("mvnd specific options:")
.append(lineSeparator);
Environment.documentedEntries()
.forEach(entry -> {
final Environment env = entry.getEntry();
help.append(lineSeparator);
int indentPos = help.length() + indent.length();
int lineEnd = help.length() + HelpFormatter.DEFAULT_WIDTH;
spaces(help, HelpFormatter.DEFAULT_LEFT_PAD);
help
.append("-D")
.append(env.getProperty())
.append("=<")
.append(env.getType().name().toLowerCase(Locale.ROOT))
.append('>');
final List<String> opts = env.getOptions();
if (!opts.isEmpty()) {
for (String opt : opts) {
help
.append(',')
.append(opt);
}
help
.append(" <")
.append(env.getType().name().toLowerCase(Locale.ROOT))
.append('>');
}
help.append(' ');
spaces(help, indentPos - help.length());
wrap(help, toPlainText(entry.getJavaDoc()), HelpFormatter.DEFAULT_WIDTH, lineEnd, indent);
indentedLine(help, "Default", env.getDefault(), indent);
indentedLine(help, "Env. variable", env.getEnvironmentVariable(), indent);
});
help
.append(lineSeparator)
.append(lineSeparator)
.append("mvnd value types:")
.append(lineSeparator);
OptionType.documentedEntries()
.forEach(entry -> {
final OptionType type = entry.getEntry();
help.append(lineSeparator);
int indentPos = help.length() + indent.length();
int lineEnd = help.length() + HelpFormatter.DEFAULT_WIDTH;
spaces(help, HelpFormatter.DEFAULT_LEFT_PAD);
help.append(type.name().toLowerCase(Locale.ROOT));
spaces(help, indentPos - help.length());
wrap(help, toPlainText(entry.getJavaDoc()), HelpFormatter.DEFAULT_WIDTH, lineEnd, indent);
});
return help.toString();
}
private static void indentedLine(final StringBuilder stringBuilder, String key, final String value, final String indent) {
int lineEnd;
if (value != null) {
lineEnd = stringBuilder.length() + HelpFormatter.DEFAULT_WIDTH;
stringBuilder
.append(System.lineSeparator())
.append(indent);
wrap(stringBuilder, key + ": " + value, HelpFormatter.DEFAULT_WIDTH, lineEnd, indent);
}
}
/**
* Word-wrap the given {@code text} to the given {@link StringBuilder}
*
* @param stringBuilder the {@link StringBuilder} to append to
* @param text the text to wrap and append
* @param lineLength the preferred line length
* @param nextLineEnd the length of the {@code stringBuilder} at which the current line should end
* @param indent the indentation string
*/
static void wrap(StringBuilder stringBuilder, String text, int lineLength, int nextLineEnd, String indent) {
final StringTokenizer st = new StringTokenizer(text, " \t\n\r", true);
String lastWs = null;
while (st.hasMoreTokens()) {
final String token = st.nextToken();
if (WS_PATTERN.matcher(token).matches()) {
lastWs = token;
} else {
if (stringBuilder.length() + token.length() + (lastWs != null ? lastWs.length() : 0) < nextLineEnd) {
if (lastWs != null) {
stringBuilder.append(lastWs);
}
stringBuilder.append(token);
} else {
nextLineEnd = stringBuilder.length() + lineLength;
stringBuilder
.append(System.lineSeparator())
.append(indent)
.append(token);
}
lastWs = null;
}
}
}
/**
* Append {@code count} spaces to the given {@code stringBuilder}
*
* @param stringBuilder the {@link StringBuilder} to append to
* @param count the number of spaces to append
* @return the given {@code stringBuilder}
*/
static StringBuilder spaces(StringBuilder stringBuilder, int count) {
for (int i = 0; i < count; i++) {
stringBuilder.append(' ');
}
return stringBuilder;
}
}

View File

@@ -121,8 +121,7 @@ public class Server implements AutoCloseable, Runnable {
List<String> opts = new ArrayList<>();
Arrays.stream(Environment.values())
.filter(Environment::isDiscriminating)
.map(v -> v.getProperty() + "=" + v.asString())
.forEach(opts::add);
.forEach(envKey -> envKey.asOptional().ifPresent(val -> opts.add(envKey.getProperty() + "=" + val)));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(opts.stream().collect(Collectors.joining(
"\n ", "Initializing daemon with properties:\n ", "\n")));
@@ -638,11 +637,13 @@ public class Server implements AutoCloseable, Runnable {
this.queue = queue;
}
@Override
public void finish(int exitCode) throws Exception {
queue.add(new Message.BuildFinished(exitCode));
queue.add(Message.STOP_SINGLETON);
}
@Override
public void fail(Throwable t) throws Exception {
queue.add(new BuildException(t));
queue.add(Message.STOP_SINGLETON);

View File

@@ -34,11 +34,21 @@ public abstract class AbstractLoggingSpy {
AbstractLoggingSpy.instance = instance;
}
public void append(String event) {
append(null, event);
}
public void append(String projectId, String event) {
String msg = event.endsWith("\n") ? event.substring(0, event.length() - 1) : event;
onProjectLog(projectId, msg);
}
public void finish(int exitCode) throws Exception {
}
public void fail(Throwable t) throws Exception {
}
protected void notifySessionStart(ExecutionEvent event) {
onStartSession(event.getSession());
}

View File

@@ -17,20 +17,12 @@ package org.mvndaemon.mvnd.logging.smart;
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.ExecutionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
public class LoggingExecutionListener implements ExecutionListener {
private final ExecutionListener delegate;
static {
Logger logger = LoggerFactory.getLogger("org.mvndaemon.mvnd");
System.setOut(new LoggingOutputStream(s -> logger.info("[stdout] " + s)).printStream());
System.setErr(new LoggingOutputStream(s -> logger.info("[stderr] " + s)).printStream());
}
public LoggingExecutionListener(ExecutionListener delegate) {
this.delegate = delegate;
}

View File

@@ -205,9 +205,9 @@ public class MvndTestExtension implements BeforeAllCallback, BeforeEachCallback,
Paths.get(System.getProperty("java.home")).toAbsolutePath().normalize(),
localMavenRepository, settingsPath,
logback,
TimeUtils.toDuration(Environment.MVND_IDLE_TIMEOUT.getDef()),
TimeUtils.toDuration(Environment.MVND_KEEP_ALIVE.getDef()),
Integer.parseInt(Environment.MVND_MAX_LOST_KEEP_ALIVE.getDef()));
TimeUtils.toDuration(Environment.MVND_IDLE_TIMEOUT.getDefault()),
TimeUtils.toDuration(Environment.MVND_KEEP_ALIVE.getDefault()),
Integer.parseInt(Environment.MVND_MAX_LOST_KEEP_ALIVE.getDefault()));
final TestRegistry registry = new TestRegistry(parameters.registry());
return new MvndResource(parameters, registry, isNative, timeoutMs);

View File

@@ -52,23 +52,23 @@ public class NativeTestClient implements Client {
final List<String> cmd = new ArrayList<String>(args.size() + 1);
cmd.add(mvndNativeExecutablePath.toString());
cmd.addAll(args);
if (!Environment.MVND_DAEMON_STORAGE.hasCommandLineProperty(args)) {
if (!Environment.MVND_DAEMON_STORAGE.hasCommandOption(args)) {
Path daemonStorage = parameters.daemonStorage();
cmd.add(Environment.MVND_DAEMON_STORAGE.asCommandLineProperty(daemonStorage.toString()));
Environment.MVND_DAEMON_STORAGE.appendAsCommandLineOption(cmd::add, daemonStorage.toString());
}
if (!Environment.MAVEN_REPO_LOCAL.hasCommandLineProperty(args)) {
if (!Environment.MAVEN_REPO_LOCAL.hasCommandOption(args)) {
Path mavenRepoLocal = parameters.mavenRepoLocal();
cmd.add(Environment.MAVEN_REPO_LOCAL.asCommandLineProperty(mavenRepoLocal.toString()));
Environment.MAVEN_REPO_LOCAL.appendAsCommandLineOption(cmd::add, mavenRepoLocal.toString());
}
if (!Environment.MAVEN_SETTINGS.hasCommandLineProperty(args)) {
if (!Environment.MAVEN_SETTINGS.hasCommandOption(args)) {
final Path settings = parameters.settings();
if (settings != null) {
cmd.add(Environment.MAVEN_SETTINGS.asCommandLineProperty(settings.toString()));
Environment.MAVEN_SETTINGS.appendAsCommandLineOption(cmd::add, settings.toString());
}
}
if (!Environment.MVND_THREADS.hasCommandLineProperty(args)) {
if (!Environment.MVND_THREADS.hasCommandOption(args)) {
final String threads = parameters.threads();
cmd.add(Environment.MVND_THREADS.asCommandLineProperty(threads));
Environment.MVND_THREADS.appendAsCommandLineOption(cmd::add, threads);
}
final ProcessBuilder builder = new ProcessBuilder(cmd.toArray(new String[0]))
@@ -76,10 +76,10 @@ public class NativeTestClient implements Client {
.redirectErrorStream(true);
final Map<String, String> env = builder.environment();
if (!Environment.MVND_HOME.hasCommandLineProperty(args)) {
if (!Environment.MVND_HOME.hasCommandOption(args)) {
env.put("MVND_HOME", System.getProperty("mvnd.home"));
}
if (!Environment.JAVA_HOME.hasCommandLineProperty(args)) {
if (!Environment.JAVA_HOME.hasCommandOption(args)) {
env.put("JAVA_HOME", System.getProperty("java.home"));
}
final String cmdString = String.join(" ", cmd);

View File

@@ -65,6 +65,7 @@
</properties>
<modules>
<module>build-plugin</module>
<module>common</module>
<module>client</module>
<module>daemon</module>