Non daemon option, fixes #43

This commit is contained in:
Guillaume Nodet
2020-07-17 13:53:35 +02:00
parent 60ea15cfda
commit e397627376
6 changed files with 294 additions and 8 deletions

View File

@@ -27,8 +27,10 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Properties;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.jboss.fuse.mvnd.common.BuildProperties; import org.jboss.fuse.mvnd.common.BuildProperties;
import org.jboss.fuse.mvnd.common.DaemonCompatibilitySpec; import org.jboss.fuse.mvnd.common.DaemonCompatibilitySpec;
@@ -84,6 +86,10 @@ public class DaemonConnector {
} }
public DaemonClientConnection connect(ClientOutput output) { public DaemonClientConnection connect(ClientOutput output) {
if (parameters.noDaemon()) {
return connectNoDaemon();
}
final DaemonCompatibilitySpec constraint = new DaemonCompatibilitySpec( final DaemonCompatibilitySpec constraint = new DaemonCompatibilitySpec(
parameters.javaHome(), parameters.getDaemonOpts()); parameters.javaHome(), parameters.getDaemonOpts());
output.accept(Message.buildStatus("Looking up daemon...")); output.accept(Message.buildStatus("Looking up daemon..."));
@@ -110,6 +116,49 @@ public class DaemonConnector {
return startDaemon(); return startDaemon();
} }
private DaemonClientConnection connectNoDaemon() {
if (Environment.isNative()) {
throw new UnsupportedOperationException(
"The " + Environment.MVND_NO_DAEMON.getProperty() + " property is not supported in native mode.");
}
String daemon = ProcessHandle.current().pid() + "-" + System.currentTimeMillis();
Properties properties = new Properties();
properties.put(Environment.JAVA_HOME.getProperty(), parameters.javaHome().toString());
properties.put(Environment.USER_DIR.getProperty(), parameters.userDir().toString());
properties.put(Environment.USER_HOME.getProperty(), parameters.userHome().toString());
properties.put(Environment.MVND_HOME.getProperty(), parameters.mvndHome().toString());
properties.put(Environment.DAEMON_UID.getProperty(), daemon);
properties.put(Environment.MVND_DAEMON_STORAGE.getProperty(), parameters.daemonStorage().toString());
properties.put(Environment.DAEMON_REGISTRY.getProperty(), parameters.registry().toString());
properties.putAll(parameters.getDaemonOptsMap());
Environment.setProperties(properties);
AtomicReference<Throwable> throwable = new AtomicReference<>();
Thread serverThread = new Thread(() -> {
try {
Class<?> clazz = getClass().getClassLoader().loadClass("org.jboss.fuse.mvnd.daemon.Server");
try (AutoCloseable server = (AutoCloseable) clazz.getConstructor().newInstance()) {
((Runnable) server).run();
}
} catch (Throwable t) {
throwable.set(t);
}
});
serverThread.start();
long start = System.currentTimeMillis();
do {
DaemonClientConnection daemonConnection = connectToDaemonWithId(daemon, true);
if (daemonConnection != null) {
return daemonConnection;
}
try {
sleep(50L);
} catch (InterruptedException e) {
throw new DaemonException.InterruptedException(e);
}
} while (serverThread.isAlive() && System.currentTimeMillis() - start < DEFAULT_CONNECT_TIMEOUT);
throw new RuntimeException("Unable to connect to internal daemon", throwable.get());
}
private String handleStopEvents(Collection<DaemonInfo> idleDaemons, Collection<DaemonInfo> busyDaemons) { private String handleStopEvents(Collection<DaemonInfo> idleDaemons, Collection<DaemonInfo> busyDaemons) {
final List<DaemonStopEvent> stopEvents = registry.getStopEvents(); final List<DaemonStopEvent> stopEvents = registry.getStopEvents();

View File

@@ -73,6 +73,13 @@ public class DaemonParameters {
.collect(Collectors.toList()); .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()));
}
public List<String> getDaemonCommandLineProperties() { public List<String> getDaemonCommandLineProperties() {
return Arrays.stream(Environment.values()) return Arrays.stream(Environment.values())
.filter(Environment::isDiscriminating) .filter(Environment::isDiscriminating)
@@ -239,6 +246,17 @@ public class DaemonParameters {
return property(Environment.MAVEN_REPO_LOCAL).asPath(); return property(Environment.MAVEN_REPO_LOCAL).asPath();
} }
/**
* @return <code>true</code> if maven should be executed within this process instead of spawning a daemon.
*/
public boolean noDaemon() {
return value(Environment.MVND_NO_DAEMON)
.orSystemProperty()
.orEnvironmentVariable()
.orDefault()
.asBoolean();
}
/** /**
* @param newUserDir where to change the current directory to * @param newUserDir where to change the current directory to
* @return a new {@link DaemonParameters} with {@code userDir} set to the given {@code newUserDir} * @return a new {@link DaemonParameters} with {@code userDir} set to the given {@code newUserDir}

View File

@@ -68,6 +68,7 @@ public enum Environment {
* The path to the daemon registry * The path to the daemon registry
*/ */
DAEMON_REGISTRY("daemon.registry", null, null, false), DAEMON_REGISTRY("daemon.registry", null, null, false),
MVND_NO_DAEMON("mvnd.noDaemon", "MVND_NO_DAEMON", "false", true),
DAEMON_DEBUG("daemon.debug", null, false, true), DAEMON_DEBUG("daemon.debug", null, false, true),
DAEMON_IDLE_TIMEOUT_MS("daemon.idleTimeoutMs", null, TimeUnit.HOURS.toMillis(3), true), DAEMON_IDLE_TIMEOUT_MS("daemon.idleTimeoutMs", null, TimeUnit.HOURS.toMillis(3), true),
DAEMON_KEEP_ALIVE_MS("daemon.keepAliveMs", null, TimeUnit.SECONDS.toMillis(1), true), DAEMON_KEEP_ALIVE_MS("daemon.keepAliveMs", null, TimeUnit.SECONDS.toMillis(1), true),

View File

@@ -72,6 +72,7 @@ public class Server implements AutoCloseable, Runnable {
public static final int CANCEL_TIMEOUT = 10 * 1000; public static final int CANCEL_TIMEOUT = 10 * 1000;
private final String uid; private final String uid;
private final boolean noDaemon;
private final ServerSocketChannel socket; private final ServerSocketChannel socket;
private final DaemonMavenCli cli; private final DaemonMavenCli cli;
private volatile DaemonInfo info; private volatile DaemonInfo info;
@@ -86,6 +87,7 @@ public class Server implements AutoCloseable, Runnable {
public Server() throws IOException { public Server() throws IOException {
this.uid = Environment.DAEMON_UID.asString(); this.uid = Environment.DAEMON_UID.asString();
this.noDaemon = Environment.MVND_NO_DAEMON.asBoolean();
try { try {
cli = new DaemonMavenCli(); cli = new DaemonMavenCli();
registry = new DaemonRegistry(Environment.DAEMON_REGISTRY.asPath()); registry = new DaemonRegistry(Environment.DAEMON_REGISTRY.asPath());
@@ -136,12 +138,14 @@ public class Server implements AutoCloseable, Runnable {
try { try {
socket.close(); socket.close();
} finally { } finally {
if (!noDaemon) {
clearCache("sun.net.www.protocol.jar.JarFileFactory", "urlCache"); clearCache("sun.net.www.protocol.jar.JarFileFactory", "urlCache");
clearCache("sun.net.www.protocol.jar.JarFileFactory", "fileCache"); clearCache("sun.net.www.protocol.jar.JarFileFactory", "fileCache");
} }
} }
} }
} }
}
} catch (Throwable t) { } catch (Throwable t) {
LOGGER.error("Error closing daemon", t); LOGGER.error("Error closing daemon", t);
} }
@@ -165,8 +169,14 @@ public class Server implements AutoCloseable, Runnable {
executor.scheduleAtFixedRate(this::expirationCheck, executor.scheduleAtFixedRate(this::expirationCheck,
expirationCheckDelayMs, expirationCheckDelayMs, TimeUnit.MILLISECONDS); expirationCheckDelayMs, expirationCheckDelayMs, TimeUnit.MILLISECONDS);
LOGGER.info("Daemon started"); LOGGER.info("Daemon started");
if (noDaemon) {
try (SocketChannel socket = this.socket.accept()) {
client(socket);
}
} else {
new DaemonThread(this::accept).start(); new DaemonThread(this::accept).start();
awaitStop(); awaitStop();
}
} catch (Throwable t) { } catch (Throwable t) {
LOGGER.error("Error running daemon loop", t); LOGGER.error("Error running daemon loop", t);
} finally { } finally {
@@ -516,11 +526,13 @@ public class Server implements AutoCloseable, Runnable {
} catch (Throwable t) { } catch (Throwable t) {
LOGGER.error("Error while building project", t); LOGGER.error("Error while building project", t);
} finally { } finally {
if (!noDaemon) {
LOGGER.info("Daemon back to idle"); LOGGER.info("Daemon back to idle");
updateState(DaemonState.Idle); updateState(DaemonState.Idle);
System.gc(); System.gc();
} }
} }
}
int getClassOrder(Message m) { int getClassOrder(Message m) {
switch (m.getType()) { switch (m.getType()) {

206
dist/src/main/distro/bin/mvnd.cmd vendored Normal file
View File

@@ -0,0 +1,206 @@
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM -----------------------------------------------------------------------------
@REM Apache Maven Startup Script
@REM
@REM Environment Variable Prerequisites
@REM
@REM JAVA_HOME Must point at your Java Development Kit installation.
@REM MAVEN_BATCH_ECHO (Optional) Set to 'on' to enable the echoing of the batch commands.
@REM MAVEN_BATCH_PAUSE (Optional) set to 'on' to wait for a key stroke before ending.
@REM MAVEN_OPTS (Optional) Java runtime options used when Maven is executed.
@REM MAVEN_SKIP_RC (Optional) Flag to disable loading of mavenrc files.
@REM -----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%"=="on" echo %MAVEN_BATCH_ECHO%
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat"
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%"=="" goto OkJHome
for %%i in (java.exe) do set "JAVACMD=%%~$PATH:i"
goto checkJCmd
:OkJHome
set "JAVACMD=%JAVA_HOME%\bin\java.exe"
:checkJCmd
if exist "%JAVACMD%" goto chkMHome
echo The JAVA_HOME environment variable is not defined correctly >&2
echo This environment variable is needed to run this program >&2
echo NB: JAVA_HOME should point to a JDK not a JRE >&2
goto error
:chkMHome
set "MVND_HOME=%~dp0.."
if not "%MVND_HOME%"=="" goto stripMHome
goto error
:stripMHome
if not "_%MVND_HOME:~-1%"=="_\" goto checkMCmd
set "MVND_HOME=%MVND_HOME:~0,-1%"
goto stripMHome
:checkMCmd
if exist "%MVND_HOME%\bin\mvnd.cmd" goto init
goto error
@REM ==== END VALIDATION ====
:init
set MAVEN_CMD_LINE_ARGS=%*
@REM Find the project basedir, i.e., the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set "MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%"
if not "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set "EXEC_DIR=%CD%"
set "WDIR=%EXEC_DIR%"
@REM Look for the --file switch and start the search for the .mvn directory from the specified
@REM POM location, if supplied.
set FILE_ARG=
:arg_loop
if "%~1" == "-f" (
set "FILE_ARG=%~2"
shift
goto process_file_arg
)
if "%~1" == "--file" (
set "FILE_ARG=%~2"
shift
goto process_file_arg
)
@REM If none of the above, skip the argument
shift
if not "%~1" == "" (
goto arg_loop
) else (
goto findBaseDir
)
:process_file_arg
if "%FILE_ARG%" == "" (
goto findBaseDir
)
if not exist "%FILE_ARG%" (
echo POM file "%FILE_ARG%" specified the -f/--file command-line argument does not exist >&2
goto error
)
if exist "%FILE_ARG%\*" (
set "POM_DIR=%FILE_ARG%"
) else (
call :get_directory_from_file "%FILE_ARG%"
)
if not exist "%POM_DIR%" (
echo Directory "%POM_DIR%" extracted from the -f/--file command-line argument "%FILE_ARG%" does not exist >&2
goto error
)
set "WDIR=%POM_DIR%"
goto findBaseDir
:get_directory_from_file
set "POM_DIR=%~dp1"
:stripPomDir
if not "_%POM_DIR:~-1%"=="_\" goto pomDirStripped
set "POM_DIR=%POM_DIR:~0,-1%"
goto stripPomDir
:pomDirStripped
exit /b
:findBaseDir
cd /d "%WDIR%"
:findBaseDirLoop
if exist "%WDIR%\.mvn" goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set "WDIR=%CD%"
goto findBaseDirLoop
:baseDirFound
set "MAVEN_PROJECTBASEDIR=%WDIR%"
cd /d "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
if "_%EXEC_DIR:~-1%"=="_\" set "EXEC_DIR=%EXEC_DIR:~0,-1%"
set "MAVEN_PROJECTBASEDIR=%EXEC_DIR%"
cd "%EXEC_DIR%"
:endDetectBaseDir
set "jvmConfig=\.mvn\jvm.config"
if not exist "%MAVEN_PROJECTBASEDIR%%jvmConfig%" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
for %%i in ("%MVND_HOME%"\boot\*.jar "%MVND_HOME%"\lib\ext\*.jar "%MVND_HOME%"\lib\*.jar) do set DAEMON_JAR="%%i"
set DAEMON_LAUNCHER=org.jboss.fuse.mvnd.client.DefaultClient
"%JAVACMD%" ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %DAEMON_JAR% ^
"-Dlogback.configurationFile=%MVND_HOME%\conf\logging\logback.xml" ^
"-Dmvnd.home=%MAVEN_HOME%" ^
"-Dmaven.home=%MAVEN_HOME%" ^
"-Dlibrary.jansi.path=%MAVEN_HOME%\lib\jansi-native" ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%DAEMON_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%

View File

@@ -102,7 +102,7 @@ if [ ! -x "$JAVACMD" ] ; then
exit 1 exit 1
fi fi
DAEMON_JAR=`echo "${MVND_HOME}"/mvn/lib/ext/*.jar "${MVND_HOME}"/mvn/lib/*.jar` DAEMON_JAR=`echo "${MVND_HOME}"/mvn/boot/*.jar "${MVND_HOME}"/mvn/lib/ext/*.jar "${MVND_HOME}"/mvn/lib/*.jar`
DAEMON_JAR=$(echo $DAEMON_JAR | sed -e 's/ /:/g') DAEMON_JAR=$(echo $DAEMON_JAR | sed -e 's/ /:/g')
DAEMON_LAUNCHER=org.jboss.fuse.mvnd.client.DefaultClient DAEMON_LAUNCHER=org.jboss.fuse.mvnd.client.DefaultClient