in client/src/main/java/org/mvndaemon/mvnd/client/DaemonConnector.java [337:491]
private Process startDaemonProcess(String daemonId, ClientOutput output) {
final Path mvndHome = parameters.mvndHome();
final Path workingDir = parameters.userDir();
String command = "";
try {
List<String> args = new ArrayList<>();
// executable
final String java = Os.current().isUnixLike() ? "bin/java" : "bin\\java.exe";
args.add(parameters.javaHome().resolve(java).toString());
// classpath
String mvndAgentPath = null;
String plexusClassworldsPath = null;
try (DirectoryStream<Path> jarPaths = Files.newDirectoryStream(
mvndHome.resolve("mvn").resolve("lib").resolve("mvnd"))) {
for (Path jar : jarPaths) {
String s = jar.getFileName().toString();
if (s.endsWith(".jar")) {
if (s.startsWith("mvnd-agent-")) {
mvndAgentPath = jar.toString();
}
}
}
}
try (DirectoryStream<Path> jarPaths =
Files.newDirectoryStream(mvndHome.resolve("mvn").resolve("boot"))) {
for (Path jar : jarPaths) {
String s = jar.getFileName().toString();
if (s.endsWith(".jar")) {
if (s.startsWith("plexus-classworlds-")) {
plexusClassworldsPath = jar.toString();
}
}
}
}
if (mvndAgentPath == null) {
throw new IllegalStateException("Could not find mvnd-agent jar in mvn/lib/mvnd/");
}
if (plexusClassworldsPath == null) {
throw new IllegalStateException("Could not find plexus-classworlds jar in boot/");
}
args.add("-classpath");
args.add(plexusClassworldsPath);
args.add("-javaagent:" + mvndAgentPath);
// debug options
if (parameters.property(Environment.MVND_DEBUG).asBoolean()) {
String address =
parameters.property(Environment.MVND_DEBUG_ADDRESS).asString();
String host;
String port;
int column = address.indexOf(':');
if (column >= 0) {
host = address.substring(0, column);
port = address.substring(column + 1);
} else {
host = "localhost";
port = address;
}
if (!port.matches("[0-9]+")) {
throw new IllegalArgumentException("Wrong debug address syntax: " + address);
}
int iPort = Integer.parseInt(port);
if (iPort == 0) {
try (ServerSocketChannel channel = SocketFamily.inet.openServerSocket()) {
iPort = ((InetSocketAddress) channel.getLocalAddress()).getPort();
} catch (IOException e) {
throw new IllegalStateException("Unable to find a free debug port", e);
}
}
address = host + ":" + iPort;
output.accept(Message.buildStatus("Daemon listening for debugger on address: " + address));
args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + address);
if (Environment.MVND_KEEP_ALIVE.getCommandLineOption(args) == null) {
System.setProperty(Environment.MVND_KEEP_ALIVE.getProperty(), "1h");
}
if (Environment.MVND_CONNECT_TIMEOUT.getCommandLineOption(args) == null) {
System.setProperty(Environment.MVND_CONNECT_TIMEOUT.getProperty(), "1h");
}
}
// jvm args
String jvmArgs = parameters.jvmArgs();
if (jvmArgs != null) {
for (String arg : jvmArgs.split(" ")) {
if (!arg.isEmpty()) {
args.add(arg);
}
}
}
// memory
String minHeapSize = parameters.minHeapSize();
if (minHeapSize != null) {
args.add("-Xms" + minHeapSize);
}
String maxHeapSize = parameters.maxHeapSize();
if (maxHeapSize != null) {
args.add("-Xmx" + maxHeapSize);
}
String threadStackSize = parameters.threadStackSize();
if (threadStackSize != null) {
args.add("-Xss" + threadStackSize);
}
Environment.MVND_HOME.addSystemProperty(args, mvndHome.toString());
args.add("-Dmaven.home=" + mvndHome.resolve("mvn"));
args.add("-Dmaven.conf=" + mvndHome.resolve("mvn").resolve("conf"));
args.add("-Dclassworlds.conf=" + mvndHome.resolve("bin").resolve("mvnd-daemon.conf"));
args.add("-D" + Constants.MAVEN_LOGGER_LOG_FILE + "="
+ parameters.daemonStorage().resolve("daemon-" + daemonId + ".log"));
Environment.MVND_JAVA_HOME.addSystemProperty(
args, parameters.javaHome().toString());
Environment.MVND_ID.addSystemProperty(args, daemonId);
Environment.MVND_DAEMON_STORAGE.addSystemProperty(
args, parameters.daemonStorage().toString());
Environment.MVND_REGISTRY.addSystemProperty(
args, parameters.registry().toString());
Environment.MVND_SOCKET_FAMILY.addSystemProperty(
args,
parameters
.socketFamily()
.orElseGet(() -> getJavaVersion() >= 16.0f ? SocketFamily.unix : SocketFamily.inet)
.toString());
parameters.discriminatingSystemProperties(args);
args.add("org.codehaus.plexus.classworlds.launcher.Launcher");
command = String.join(" ", args);
LOGGER.debug(
"Starting daemon process: id = {}, workingDir = {}, daemonArgs: {}", daemonId, workingDir, command);
Path daemonOutLog = parameters.daemonOutLog(daemonId);
Files.writeString(
daemonOutLog,
"Starting daemon process: id = " + daemonId + ", workingDir = " + workingDir + ", daemonArgs: "
+ command,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
ProcessBuilder.Redirect redirect = ProcessBuilder.Redirect.appendTo(daemonOutLog.toFile());
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder
.environment()
.put(Environment.JDK_JAVA_OPTIONS.getEnvironmentVariable(), parameters.jdkJavaOpts());
Process process = processBuilder
.directory(workingDir.toFile())
.command(args)
.redirectOutput(redirect)
.redirectError(redirect)
.start();
return process;
} catch (Exception e) {
throw new DaemonException.StartException(
String.format(
"Error starting daemon: id = %s, workingDir = %s, daemonArgs: %s",
daemonId, workingDir, command),
e);
}
}