From 3a4d86bc64aea218dde64e8554d8cd9a81c783fa Mon Sep 17 00:00:00 2001 From: Peter Palaga Date: Tue, 8 Dec 2020 09:59:05 +0100 Subject: [PATCH] Let -h/--help display also mvnd specific options #243 --- build-plugin/pom.xml | 103 ++++++ .../mvndaemon/mvnd/plugin/doc/DocMojo.java | 184 +++++++++++ .../mvnd/client/DaemonConnector.java | 14 +- .../mvnd/client/DaemonParameters.java | 82 +++-- common/pom.xml | 13 + .../mvndaemon/mvnd/common/Environment.java | 298 +++++++++++------- .../org/mvndaemon/mvnd/common/OptionType.java | 71 +++++ .../org/apache/maven/cli/DaemonMavenCli.java | 27 +- .../apache/maven/cli/MvndHelpFormatter.java | 183 +++++++++++ .../org/mvndaemon/mvnd/daemon/Server.java | 5 +- .../logging/smart/AbstractLoggingSpy.java | 10 + .../smart/LoggingExecutionListener.java | 8 - .../mvnd/junit/MvndTestExtension.java | 6 +- .../mvnd/junit/NativeTestClient.java | 20 +- pom.xml | 1 + 15 files changed, 843 insertions(+), 182 deletions(-) create mode 100644 build-plugin/pom.xml create mode 100644 build-plugin/src/main/java/org/mvndaemon/mvnd/plugin/doc/DocMojo.java create mode 100644 common/src/main/java/org/mvndaemon/mvnd/common/OptionType.java create mode 100644 daemon/src/main/java/org/apache/maven/cli/MvndHelpFormatter.java diff --git a/build-plugin/pom.xml b/build-plugin/pom.xml new file mode 100644 index 000000000..54df857f8 --- /dev/null +++ b/build-plugin/pom.xml @@ -0,0 +1,103 @@ + + + + 4.0.0 + + org.mvndaemon.mvnd + mvnd + 0.1.2-SNAPSHOT + + + mvnd-build-maven-plugin + + maven-plugin + Maven Daemon - Documentation Maven Plugin + + + 11 + 11 + + 2.22.2.Final + 3.6.0 + ${maven.plugin-tools.version} + + + + + + org.apache.maven + maven-plugin-api + ${maven.version} + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${maven.plugin-tools.version} + + + + + + + + org.apache.maven + maven-plugin-api + provided + + + org.apache.maven.plugin-tools + maven-plugin-annotations + provided + + + + org.jboss.forge.roaster + roaster-jdt + ${roaster.version} + + + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + ${maven-plugin-plugin.version} + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + + mvnd-build + + org.apache.maven:maven-plugin-api + + + + + + + \ No newline at end of file diff --git a/build-plugin/src/main/java/org/mvndaemon/mvnd/plugin/doc/DocMojo.java b/build-plugin/src/main/java/org/mvndaemon/mvnd/plugin/doc/DocMojo.java new file mode 100644 index 000000000..6945606c3 --- /dev/null +++ b/build-plugin/src/main/java/org/mvndaemon/mvnd/plugin/doc/DocMojo.java @@ -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 ${basedir} + */ + @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 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 keys() { + final Iterator it = new TreeSet<>(keySet()).iterator(); + return new Enumeration() { + public boolean hasMoreElements() { + return it.hasNext(); + } + + public Object nextElement() { + return (SaslClientFactory) it.next(); + } + }; + } + + public Set> entrySet() { + Comparator> comparator = Comparator.comparing(e -> (Comparable) e.getKey()); + final Set> 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); + } + } + + } + + } +} diff --git a/client/src/main/java/org/mvndaemon/mvnd/client/DaemonConnector.java b/client/src/main/java/org/mvndaemon/mvnd/client/DaemonConnector.java index dde0385a8..8dcf4b6f6 100644 --- a/client/src/main/java/org/mvndaemon/mvnd/client/DaemonConnector.java +++ b/client/src/main/java/org/mvndaemon/mvnd/client/DaemonConnector.java @@ -327,13 +327,13 @@ private Process startDaemon(String uid) { 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); diff --git a/client/src/main/java/org/mvndaemon/mvnd/client/DaemonParameters.java b/client/src/main/java/org/mvndaemon/mvnd/client/DaemonParameters.java index f299cc7c2..3af07b40f 100644 --- a/client/src/main/java/org/mvndaemon/mvnd/client/DaemonParameters.java +++ b/client/src/main/java/org/mvndaemon/mvnd/client/DaemonParameters.java @@ -31,10 +31,12 @@ 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 @@ protected DaemonParameters(PropertiesBuilder propertiesBuilder) { } public List 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 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 getDaemonCommandLineProperties() { + Stream 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 args) { + discriminatingValues() + .forEach(envValue -> envValue.envKey.appendAsCommandLineOption(args, envValue.asString())); } public Path mvndHome() { @@ -350,7 +356,7 @@ private String defaultValue(Environment env) { throw new RuntimeException("Unable to parse core extensions", e); } } else { - return env.getDef(); + return env.getDefault(); } } @@ -506,7 +512,7 @@ public EnvValue or(ValueSource source) { } public EnvValue orDefault() { - return orDefault(envKey::getDef); + return orDefault(envKey::getDefault); } public EnvValue orDefault(Supplier defaultSupplier) { @@ -516,28 +522,32 @@ public EnvValue orDefault(Supplier defaultSupplier) { 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 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 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 Duration asDuration() { return TimeUtils.toDuration(get()); } + public boolean isSet() { + if (get() != null) { + return true; + } else if (envKey.isOptional()) { + return false; + } else { + throw couldNotgetValue(); + } + } + } } diff --git a/common/pom.xml b/common/pom.xml index 78d7bda36..bd1cfd7c1 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -82,6 +82,19 @@ + + org.mvndaemon.mvnd + mvnd-build-maven-plugin + ${project.version} + + + + doc + + generate-resources + + + io.takari.maven.plugins takari-lifecycle-plugin diff --git a/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java b/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java index 5641e10de..96501e11e 100644 --- a/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java +++ b/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java @@ -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 @@ * * 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 2h30m, 600ms or 10 seconds. * The available units are d/day/days, h/hour/hours, m/min/minute/minutes, * s/sec/second/seconds and ms/millis/msec/milliseconds. */ @@ -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 mvnd + * 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 mvnd.properties 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: ${user.home}/.m2/mvnd */ - 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 ${mvnd.daemonStorage}/registry.bin + * The path to the daemon registry. + * Default: ${mvnd.daemonStorage}/registry.bin */ - 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 true 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 -B or + * --batch-mode 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 + * -Dmvnd.noBuffering=true, -B or --batch-mode. */ - 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 true, 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 - * -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000 + * If true, the daemon will be launched in debug mode with the following JVM argument: + * -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000; 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 -T parameter for the daemon. + * This value is ignored if the user passes -T, --threads or -Dmvnd.threads + * on the command line or if he sets mvnd.threads in ~/.m2/mvnd.properties. */ - 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 -T/--threads + * 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 -Xms 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 -Xmx 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 true, the -ea option will be passed to the daemon; otherwise the -ea + * 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 static String getProperty(String property) { private final String property; private final String environmentVariable; - private final String def; - private final boolean discriminating; - private final boolean duration; - private final 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); - } + private final String default_; + private final int flags; + private final OptionType type; + private final List 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 String getEnvironmentVariable() { return environmentVariable; } - public String getDef() { - return def; + public String getDefault() { + return default_; + } + + public List 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 String asString() { return val; } + public Optional 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 Duration asDuration() { 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 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 args) { - final String[] prefixes = options != null ? options : new String[] { "-D" + property + "=" }; + public boolean hasCommandOption(Collection 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 static boolean isNative() { return "executable".equals(System.getProperty("org.graalvm.nativeimage.kind")); } + public static Stream> 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 { + + 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; + } + } diff --git a/common/src/main/java/org/mvndaemon/mvnd/common/OptionType.java b/common/src/main/java/org/mvndaemon/mvnd/common/OptionType.java new file mode 100644 index 000000000..09a5861e3 --- /dev/null +++ b/common/src/main/java/org/mvndaemon/mvnd/common/OptionType.java @@ -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 { + /** true or false */ + 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): d[ay[s]], h[our[s]], + * m[in[ute[s]]], s[ec[ond[s]]] or m[illi]s[ec[ond[s]]]. + *

+ * Examples: 7 days, 7days, 7d, 100 milliseconds, + * 100 millis, 100ms, 100 + */ + 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 -Xm* family of HotSpot JVM options. Examples: + * 1024m, 2g, 5G + */ + MEMORY_SIZE, + /** A local file system path */ + PATH, + /** A string */ + STRING; + + public String normalize(String value) { + return value; + } + + public static Stream> 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()))); + } +} diff --git a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java index e6244da83..46eb059ab 100644 --- a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java +++ b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java @@ -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.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 @@ void cli(CliRequest cliRequest) } } 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 @@ void cli(CliRequest cliRequest) } } 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 @@ void logging(CliRequest cliRequest) { 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 @@ void logging(CliRequest cliRequest) { // 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); } diff --git a/daemon/src/main/java/org/apache/maven/cli/MvndHelpFormatter.java b/daemon/src/main/java/org/apache/maven/cli/MvndHelpFormatter.java new file mode 100644 index 000000000..d2583375b --- /dev/null +++ b/daemon/src/main/java/org/apache/maven/cli/MvndHelpFormatter.java @@ -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 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; + } + +} diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java b/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java index 4deda3a03..f140b3730 100644 --- a/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java +++ b/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java @@ -121,8 +121,7 @@ public Server() throws IOException { List 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 DaemonLoggingSpy(BlockingQueue queue) { 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); diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/logging/smart/AbstractLoggingSpy.java b/daemon/src/main/java/org/mvndaemon/mvnd/logging/smart/AbstractLoggingSpy.java index 78e2573a3..2f0a30cf8 100644 --- a/daemon/src/main/java/org/mvndaemon/mvnd/logging/smart/AbstractLoggingSpy.java +++ b/daemon/src/main/java/org/mvndaemon/mvnd/logging/smart/AbstractLoggingSpy.java @@ -34,11 +34,21 @@ public static void instance(AbstractLoggingSpy instance) { 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()); } diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/logging/smart/LoggingExecutionListener.java b/daemon/src/main/java/org/mvndaemon/mvnd/logging/smart/LoggingExecutionListener.java index f0ff0fd3d..66eb8063d 100644 --- a/daemon/src/main/java/org/mvndaemon/mvnd/logging/smart/LoggingExecutionListener.java +++ b/daemon/src/main/java/org/mvndaemon/mvnd/logging/smart/LoggingExecutionListener.java @@ -17,20 +17,12 @@ 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; } diff --git a/integration-tests/src/test/java/org/mvndaemon/mvnd/junit/MvndTestExtension.java b/integration-tests/src/test/java/org/mvndaemon/mvnd/junit/MvndTestExtension.java index d43c38047..7982fae71 100644 --- a/integration-tests/src/test/java/org/mvndaemon/mvnd/junit/MvndTestExtension.java +++ b/integration-tests/src/test/java/org/mvndaemon/mvnd/junit/MvndTestExtension.java @@ -205,9 +205,9 @@ public static MvndResource create(String className, String rawProjectDir, boolea 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); diff --git a/integration-tests/src/test/java/org/mvndaemon/mvnd/junit/NativeTestClient.java b/integration-tests/src/test/java/org/mvndaemon/mvnd/junit/NativeTestClient.java index 65a4b0a27..947a1ca9a 100644 --- a/integration-tests/src/test/java/org/mvndaemon/mvnd/junit/NativeTestClient.java +++ b/integration-tests/src/test/java/org/mvndaemon/mvnd/junit/NativeTestClient.java @@ -52,23 +52,23 @@ public ExecutionResult execute(ClientOutput output, List args) throws In final List cmd = new ArrayList(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 ExecutionResult execute(ClientOutput output, List args) throws In .redirectErrorStream(true); final Map 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); diff --git a/pom.xml b/pom.xml index 65cad5d00..5f328891d 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,7 @@ + build-plugin common client daemon