mirror of
https://github.com/apache/maven-mvnd.git
synced 2025-10-18 08:24:11 +00:00
Native tests
This commit is contained in:
@@ -1,261 +1,14 @@
|
||||
/*
|
||||
* 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.jboss.fuse.mvnd.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.fusesource.jansi.Ansi;
|
||||
import org.jboss.fuse.mvnd.client.ClientOutput.TerminalOutput;
|
||||
import org.jboss.fuse.mvnd.client.Message.BuildEvent;
|
||||
import org.jboss.fuse.mvnd.client.Message.BuildException;
|
||||
import org.jboss.fuse.mvnd.client.Message.BuildMessage;
|
||||
import org.jboss.fuse.mvnd.client.Message.MessageSerializer;
|
||||
import org.jboss.fuse.mvnd.jpm.Process;
|
||||
import org.jboss.fuse.mvnd.jpm.ProcessImpl;
|
||||
import org.jboss.fuse.mvnd.jpm.ScriptUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
public interface Client {
|
||||
|
||||
public class Client {
|
||||
ExecutionResult execute(ClientOutput output, List<String> args) throws InterruptedException;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Client.class);
|
||||
public static final String DAEMON_DEBUG = "daemon.debug";
|
||||
public static final String DAEMON_IDLE_TIMEOUT = "daemon.idleTimeout";
|
||||
public static final int DEFAULT_IDLE_TIMEOUT = (int) TimeUnit.HOURS.toMillis(3);
|
||||
public static final int DEFAULT_PERIODIC_CHECK_INTERVAL_MILLIS = 10 * 1000;
|
||||
public static final int CANCEL_TIMEOUT = 10 * 1000;
|
||||
private final ClientLayout layout;
|
||||
private final Properties buildProperties;
|
||||
|
||||
public static void main(String[] argv) throws Exception {
|
||||
final List<String> args = new ArrayList<>(Arrays.asList(argv));
|
||||
|
||||
Path logFile = null;
|
||||
for (int i = 0; i < args.size() - 2; i++) {
|
||||
String arg = args.get(i);
|
||||
if ("-l".equals(arg) || "--log-file".equals(arg)) {
|
||||
logFile = Paths.get(args.get(i + 1));
|
||||
args.remove(i);
|
||||
args.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try (TerminalOutput output = new TerminalOutput(logFile)) {
|
||||
new Client(ClientLayout.getEnvInstance()).execute(output, args);
|
||||
}
|
||||
}
|
||||
|
||||
public Client(ClientLayout layout) {
|
||||
this.layout = layout;
|
||||
this.buildProperties = new Properties();
|
||||
try (InputStream is = Client.class.getResourceAsStream("build.properties")) {
|
||||
buildProperties.load(is);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not read build.properties");
|
||||
}
|
||||
}
|
||||
|
||||
public <O extends ClientOutput> ClientResult<O> execute(O output, String... argv) throws IOException {
|
||||
return execute(output, Arrays.asList(argv));
|
||||
}
|
||||
|
||||
public <O extends ClientOutput> ClientResult<O> execute(O output, List<String> argv) throws IOException {
|
||||
output.debug("Starting client");
|
||||
|
||||
final List<String> args = new ArrayList<>(argv);
|
||||
|
||||
// Print version if needed
|
||||
boolean version = args.contains("-v") || args.contains("-version") || args.contains("--version");
|
||||
boolean showVersion = args.contains("-V") || args.contains("--show-version");
|
||||
boolean debug = args.contains("-X") || args.contains("--debug");
|
||||
if (version || showVersion || debug) {
|
||||
final String nativeSuffix = Layout.isNative() ? " (native)" : "";
|
||||
final String v = Ansi.ansi().bold().a("Maven Daemon " + buildProperties.getProperty("version") + nativeSuffix).reset().toString();
|
||||
output.log(v);
|
||||
/* Do not return, rather pass -v to the server so that the client module does not need to depend on any Maven artifacts */
|
||||
}
|
||||
|
||||
final Path javaHome = layout.javaHome();
|
||||
try (DaemonRegistry registry = new DaemonRegistry(layout.registry())) {
|
||||
boolean status = args.remove("--status");
|
||||
if (status) {
|
||||
output.log(String.format(" %36s %7s %5s %7s %s",
|
||||
"UUID", "PID", "Port", "Status", "Last activity"));
|
||||
registry.getAll().forEach(d -> output.log(String.format(" %36s %7s %5s %7s %s",
|
||||
d.getUid(), d.getPid(), d.getAddress(), d.getState(),
|
||||
LocalDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(Math.max(d.getLastIdle(), d.getLastBusy())),
|
||||
ZoneId.systemDefault()))));
|
||||
return new ClientResult<O>(argv, true, output);
|
||||
}
|
||||
boolean stop = args.remove("--stop");
|
||||
if (stop) {
|
||||
DaemonInfo[] dis = registry.getAll().toArray(new DaemonInfo[0]);
|
||||
if (dis.length > 0) {
|
||||
output.log("Stopping " + dis.length + " running daemons");
|
||||
for (DaemonInfo di : dis) {
|
||||
try {
|
||||
new ProcessImpl(di.getPid()).destroy();
|
||||
} catch (IOException t) {
|
||||
System.out.println("Daemon " + di.getUid() + ": " + t.getMessage());
|
||||
} catch (Exception t) {
|
||||
System.out.println("Daemon " + di.getUid() + ": " + t);
|
||||
} finally {
|
||||
registry.remove(di.getUid());
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ClientResult<O>(argv, true, output);
|
||||
}
|
||||
|
||||
setDefaultArgs(args);
|
||||
final Path settings = layout.getSettings();
|
||||
if (settings != null && !args.stream().anyMatch(arg -> arg.equals("-s") || arg.equals("--settings"))) {
|
||||
args.add("-s");
|
||||
args.add(settings.toString());
|
||||
}
|
||||
|
||||
final Path localMavenRepository = layout.getLocalMavenRepository();
|
||||
if (localMavenRepository != null && !args.stream().anyMatch(arg -> arg.startsWith("-Dmaven.repo.local"))) {
|
||||
args.add("-Dmaven.repo.local=" + localMavenRepository.toString());
|
||||
}
|
||||
|
||||
DaemonConnector connector = new DaemonConnector(layout, registry, this::startDaemon, new MessageSerializer());
|
||||
List<String> opts = new ArrayList<>();
|
||||
DaemonClientConnection daemon = connector.connect(new DaemonCompatibilitySpec(javaHome, opts));
|
||||
|
||||
daemon.dispatch(new Message.BuildRequest(
|
||||
args,
|
||||
layout.userDir().toString(),
|
||||
layout.multiModuleProjectDirectory().toString()));
|
||||
|
||||
while (true) {
|
||||
Message m = daemon.receive();
|
||||
if (m instanceof BuildException) {
|
||||
output.error((BuildException) m);
|
||||
return new ClientResult<O>(argv, false, output);
|
||||
} else if (m instanceof BuildEvent) {
|
||||
BuildEvent be = (BuildEvent) m;
|
||||
switch (be.getType()) {
|
||||
case BuildStarted:
|
||||
break;
|
||||
case BuildStopped:
|
||||
return new ClientResult<O>(argv, true, output);
|
||||
case ProjectStarted:
|
||||
case MojoStarted:
|
||||
case MojoStopped:
|
||||
output.projectStateChanged(be.projectId, be.display);
|
||||
break;
|
||||
case ProjectStopped:
|
||||
output.projectFinished(be.projectId);
|
||||
}
|
||||
} else if (m instanceof BuildMessage) {
|
||||
BuildMessage bm = (BuildMessage) m;
|
||||
output.log(bm.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void setDefaultArgs(List<String> args) {
|
||||
if (!args.stream().anyMatch(arg -> arg.startsWith("-T") || arg.equals("--threads"))) {
|
||||
args.add("-T1C");
|
||||
}
|
||||
if (!args.stream().anyMatch(arg -> arg.startsWith("-b") || arg.equals("--builder"))) {
|
||||
args.add("-bsmart");
|
||||
}
|
||||
}
|
||||
|
||||
String startDaemon() {
|
||||
// DaemonParameters parms = new DaemonParameters();
|
||||
// for (String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
|
||||
//
|
||||
// }
|
||||
// List<String> args = new ArrayList<>();
|
||||
// args.add(javaHome.resolve(java).toString());
|
||||
// args.addAll(parms.getEffectiveJvmArgs());
|
||||
// args.add("-cp");
|
||||
// args.add(classpath);
|
||||
|
||||
final String uid = UUID.randomUUID().toString();
|
||||
final Path mavenHome = layout.mavenHome();
|
||||
final Path workingDir = layout.userDir();
|
||||
String command = "";
|
||||
try {
|
||||
String classpath = findClientJar(mavenHome).toString();
|
||||
final String java = ScriptUtils.isWindows() ? "bin\\java.exe" : "bin/java";
|
||||
List<String> args = new ArrayList<>();
|
||||
args.add("\"" + layout.javaHome().resolve(java) + "\"");
|
||||
args.add("-classpath");
|
||||
args.add("\"" + classpath + "\"");
|
||||
if (Boolean.getBoolean(DAEMON_DEBUG)) {
|
||||
args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000");
|
||||
}
|
||||
args.add("-Dmaven.home=\"" + mavenHome + "\"");
|
||||
args.add("-Dlogback.configurationFile=logback.xml");
|
||||
args.add("-Ddaemon.uid=" + uid);
|
||||
args.add("-Xmx4g");
|
||||
final String timeout = System.getProperty(DAEMON_IDLE_TIMEOUT);
|
||||
if (timeout != null) {
|
||||
args.add("-D" + DAEMON_IDLE_TIMEOUT + "=" + timeout);
|
||||
}
|
||||
args.add("\"-Dmaven.multiModuleProjectDirectory=" + layout.multiModuleProjectDirectory().toString() + "\"");
|
||||
|
||||
args.add(ServerMain.class.getName());
|
||||
command = String.join(" ", args);
|
||||
|
||||
LOGGER.debug("Starting daemon process: uid = {}, workingDir = {}, daemonArgs: {}", uid, workingDir, command);
|
||||
Process.create(workingDir.toFile(), command);
|
||||
return uid;
|
||||
} catch (Exception e) {
|
||||
throw new DaemonException.StartException(
|
||||
String.format("Error starting daemon: uid = %s, workingDir = %s, daemonArgs: %s",
|
||||
uid, workingDir, command), e);
|
||||
}
|
||||
}
|
||||
|
||||
Path findClientJar(Path mavenHome) {
|
||||
final Path ext = mavenHome.resolve("lib/ext");
|
||||
final String clientJarName = "mvnd-client-"+ buildProperties.getProperty("version") + ".jar";
|
||||
try (Stream<Path> files = Files.list(ext)) {
|
||||
return files
|
||||
.filter(f -> f.getFileName().toString().equals(clientJarName))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Could not find " + clientJarName + " in " + ext));
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not find " + clientJarName + " in " + ext, e);
|
||||
}
|
||||
default ExecutionResult execute(ClientOutput output, String... args) throws InterruptedException {
|
||||
return execute(output, Arrays.asList(args));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Local paths relevant for the {@link Client}.
|
||||
* Local paths relevant for the {@link DefaultClient}.
|
||||
*/
|
||||
public class ClientLayout extends Layout {
|
||||
|
||||
@@ -28,7 +28,7 @@ public class ClientLayout extends Layout {
|
||||
pwd,
|
||||
findMultiModuleProjectDirectory(pwd),
|
||||
findJavaHome(mvndProperties),
|
||||
null,
|
||||
findLocalRepo(),
|
||||
null);
|
||||
}
|
||||
return ENV_INSTANCE;
|
||||
@@ -60,6 +60,11 @@ public class ClientLayout extends Layout {
|
||||
return javaHome;
|
||||
}
|
||||
|
||||
static Path findLocalRepo() {
|
||||
final String rawValue = System.getProperty("maven.repo.local");
|
||||
return rawValue != null ? Paths.get(rawValue) : null;
|
||||
}
|
||||
|
||||
static Path findJavaHome(Properties mvndProperties) {
|
||||
String rawValue = System.getenv("JAVA_HOME");
|
||||
if (rawValue == null) {
|
||||
|
@@ -29,18 +29,17 @@ import org.slf4j.LoggerFactory;
|
||||
/**
|
||||
* A sink for various kinds of events sent by the daemon.
|
||||
*/
|
||||
public interface ClientOutput extends AutoCloseable {
|
||||
public interface ClientOutput extends AutoCloseable, Consumer<String> {
|
||||
|
||||
public void projectStateChanged(String projectId, String display);
|
||||
|
||||
public void projectFinished(String projectId);
|
||||
|
||||
public void log(String message);
|
||||
/** Receive a log message */
|
||||
public void accept(String message);
|
||||
|
||||
public void error(BuildException m);
|
||||
|
||||
public void debug(String string);
|
||||
|
||||
/**
|
||||
* A terminal {@link ClientOutput} based on JLine.
|
||||
*/
|
||||
@@ -70,7 +69,7 @@ public interface ClientOutput extends AutoCloseable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String message) {
|
||||
public void accept(String message) {
|
||||
try {
|
||||
queue.put(new AbstractMap.SimpleImmutableEntry<>(TerminalUpdater.LOG, message));
|
||||
} catch (InterruptedException e) {
|
||||
@@ -98,11 +97,6 @@ public interface ClientOutput extends AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg) {
|
||||
LOGGER.debug(msg);
|
||||
}
|
||||
|
||||
static class TerminalUpdater implements AutoCloseable {
|
||||
private static final String LOG = "<log>";
|
||||
private static final String ERROR = "<error>";
|
||||
@@ -180,12 +174,18 @@ public interface ClientOutput extends AutoCloseable {
|
||||
private void update() {
|
||||
// no need to refresh the display at every single step
|
||||
final Size size = terminal.getSize();
|
||||
display.resize(size.getRows(), size.getColumns());
|
||||
final int displayableProjectCount = size.getRows() - 1;
|
||||
final int rows = size.getRows();
|
||||
display.resize(rows, size.getColumns());
|
||||
if (rows <= 0) {
|
||||
display.update(Collections.emptyList(), 0);
|
||||
return;
|
||||
}
|
||||
final int displayableProjectCount = rows - 1;
|
||||
final int skipRows = projects.size() > displayableProjectCount ? projects.size() - displayableProjectCount : 0;
|
||||
final List<AttributedString> lines = new ArrayList<>(projects.size() - skipRows);
|
||||
final int lineMaxLength = size.getColumns();
|
||||
int i = 0;
|
||||
lines.add(new AttributedString("Building..." + (skipRows > 0 ? " (" + skipRows + " more)" : "")));
|
||||
for (String line : projects.values()) {
|
||||
if (i < skipRows) {
|
||||
i++;
|
||||
@@ -193,7 +193,6 @@ public interface ClientOutput extends AutoCloseable {
|
||||
lines.add(shortenIfNeeded(AttributedString.fromAnsi(line), lineMaxLength));
|
||||
}
|
||||
}
|
||||
lines.add(0, new AttributedString("Building..." + (skipRows > 0 ? " (" + skipRows + " more)" : "")));
|
||||
display.update(lines, -1);
|
||||
}
|
||||
|
||||
|
@@ -1,54 +0,0 @@
|
||||
package org.jboss.fuse.mvnd.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A result of a {@code mvnd} build.
|
||||
*
|
||||
* @param <O> the type of the {@link ClientOutput}.
|
||||
*/
|
||||
public class ClientResult<O extends ClientOutput> {
|
||||
|
||||
private final boolean success;
|
||||
private final O clientOutput;
|
||||
private final List<String> args;
|
||||
|
||||
public ClientResult(List<String> args, boolean success, O clientOutput) {
|
||||
super();
|
||||
this.args = new ArrayList<>(args);
|
||||
this.success = success;
|
||||
this.clientOutput = clientOutput;
|
||||
}
|
||||
|
||||
public ClientResult<O> assertSuccess() {
|
||||
if (!this.success) {
|
||||
throw new AssertionError(appendCommand(new StringBuilder("Build failed: ")));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientResult<O> assertFailure() {
|
||||
if (this.success) {
|
||||
throw new AssertionError(appendCommand(new StringBuilder("Build did not fail: ")));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public O getClientOutput() {
|
||||
return clientOutput;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
StringBuilder appendCommand(StringBuilder sb) {
|
||||
sb.append("mvnd");
|
||||
for (String arg : args) {
|
||||
sb.append(" \"").append(arg).append('"');
|
||||
}
|
||||
return sb;
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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.jboss.fuse.mvnd.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.fusesource.jansi.Ansi;
|
||||
import org.jboss.fuse.mvnd.client.ClientOutput.TerminalOutput;
|
||||
import org.jboss.fuse.mvnd.client.Message.BuildEvent;
|
||||
import org.jboss.fuse.mvnd.client.Message.BuildException;
|
||||
import org.jboss.fuse.mvnd.client.Message.BuildMessage;
|
||||
import org.jboss.fuse.mvnd.client.Message.MessageSerializer;
|
||||
import org.jboss.fuse.mvnd.jpm.Process;
|
||||
import org.jboss.fuse.mvnd.jpm.ProcessImpl;
|
||||
import org.jboss.fuse.mvnd.jpm.ScriptUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class DefaultClient implements Client {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultClient.class);
|
||||
public static final String DAEMON_DEBUG = "daemon.debug";
|
||||
public static final String DAEMON_IDLE_TIMEOUT = "daemon.idleTimeout";
|
||||
public static final int DEFAULT_IDLE_TIMEOUT = (int) TimeUnit.HOURS.toMillis(3);
|
||||
public static final int DEFAULT_PERIODIC_CHECK_INTERVAL_MILLIS = 10 * 1000;
|
||||
public static final int CANCEL_TIMEOUT = 10 * 1000;
|
||||
private final ClientLayout layout;
|
||||
private final Properties buildProperties;
|
||||
|
||||
public static void main(String[] argv) throws Exception {
|
||||
final List<String> args = new ArrayList<>(Arrays.asList(argv));
|
||||
|
||||
Path logFile = null;
|
||||
for (int i = 0; i < args.size() - 2; i++) {
|
||||
String arg = args.get(i);
|
||||
if ("-l".equals(arg) || "--log-file".equals(arg)) {
|
||||
logFile = Paths.get(args.get(i + 1));
|
||||
args.remove(i);
|
||||
args.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try (TerminalOutput output = new TerminalOutput(logFile)) {
|
||||
new DefaultClient(ClientLayout.getEnvInstance()).execute(output, args);
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultClient(ClientLayout layout) {
|
||||
this.layout = layout;
|
||||
this.buildProperties = new Properties();
|
||||
try (InputStream is = DefaultClient.class.getResourceAsStream("build.properties")) {
|
||||
buildProperties.load(is);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not read build.properties");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionResult execute(ClientOutput output, List<String> argv) {
|
||||
LOGGER.debug("Starting client");
|
||||
|
||||
final List<String> args = new ArrayList<>(argv);
|
||||
|
||||
// Print version if needed
|
||||
boolean version = args.contains("-v") || args.contains("-version") || args.contains("--version");
|
||||
boolean showVersion = args.contains("-V") || args.contains("--show-version");
|
||||
boolean debug = args.contains("-X") || args.contains("--debug");
|
||||
if (version || showVersion || debug) {
|
||||
final String nativeSuffix = Layout.isNative() ? " (native)" : "";
|
||||
final String v = Ansi.ansi().bold().a("Maven Daemon " + buildProperties.getProperty("version") + nativeSuffix).reset().toString();
|
||||
output.accept(v);
|
||||
/* Do not return, rather pass -v to the server so that the client module does not need to depend on any Maven artifacts */
|
||||
}
|
||||
|
||||
final Path javaHome = layout.javaHome();
|
||||
try (DaemonRegistry registry = new DaemonRegistry(layout.registry())) {
|
||||
boolean status = args.remove("--status");
|
||||
if (status) {
|
||||
output.accept(String.format(" %36s %7s %5s %7s %s",
|
||||
"UUID", "PID", "Port", "Status", "Last activity"));
|
||||
registry.getAll().forEach(d -> output.accept(String.format(" %36s %7s %5s %7s %s",
|
||||
d.getUid(), d.getPid(), d.getAddress(), d.getState(),
|
||||
LocalDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(Math.max(d.getLastIdle(), d.getLastBusy())),
|
||||
ZoneId.systemDefault()))));
|
||||
return new DefaultResult(argv, true);
|
||||
}
|
||||
boolean stop = args.remove("--stop");
|
||||
if (stop) {
|
||||
DaemonInfo[] dis = registry.getAll().toArray(new DaemonInfo[0]);
|
||||
if (dis.length > 0) {
|
||||
output.accept("Stopping " + dis.length + " running daemons");
|
||||
for (DaemonInfo di : dis) {
|
||||
try {
|
||||
new ProcessImpl(di.getPid()).destroy();
|
||||
} catch (IOException t) {
|
||||
System.out.println("Daemon " + di.getUid() + ": " + t.getMessage());
|
||||
} catch (Exception t) {
|
||||
System.out.println("Daemon " + di.getUid() + ": " + t);
|
||||
} finally {
|
||||
registry.remove(di.getUid());
|
||||
}
|
||||
}
|
||||
}
|
||||
return new DefaultResult(argv, true);
|
||||
}
|
||||
|
||||
setDefaultArgs(args);
|
||||
final Path settings = layout.getSettings();
|
||||
if (settings != null && !args.stream().anyMatch(arg -> arg.equals("-s") || arg.equals("--settings"))) {
|
||||
args.add("-s");
|
||||
args.add(settings.toString());
|
||||
}
|
||||
|
||||
final Path localMavenRepository = layout.getLocalMavenRepository();
|
||||
if (localMavenRepository != null) {
|
||||
args.add("-Dmaven.repo.local=" + localMavenRepository.toString());
|
||||
}
|
||||
|
||||
DaemonConnector connector = new DaemonConnector(layout, registry, this::startDaemon, new MessageSerializer());
|
||||
List<String> opts = new ArrayList<>();
|
||||
DaemonClientConnection daemon = connector.connect(new DaemonCompatibilitySpec(javaHome, opts));
|
||||
|
||||
daemon.dispatch(new Message.BuildRequest(
|
||||
args,
|
||||
layout.userDir().toString(),
|
||||
layout.multiModuleProjectDirectory().toString()));
|
||||
|
||||
while (true) {
|
||||
Message m = daemon.receive();
|
||||
if (m instanceof BuildException) {
|
||||
output.error((BuildException) m);
|
||||
return new DefaultResult(argv, false);
|
||||
} else if (m instanceof BuildEvent) {
|
||||
BuildEvent be = (BuildEvent) m;
|
||||
switch (be.getType()) {
|
||||
case BuildStarted:
|
||||
break;
|
||||
case BuildStopped:
|
||||
return new DefaultResult(argv, true);
|
||||
case ProjectStarted:
|
||||
case MojoStarted:
|
||||
case MojoStopped:
|
||||
output.projectStateChanged(be.projectId, be.display);
|
||||
break;
|
||||
case ProjectStopped:
|
||||
output.projectFinished(be.projectId);
|
||||
}
|
||||
} else if (m instanceof BuildMessage) {
|
||||
BuildMessage bm = (BuildMessage) m;
|
||||
output.accept(bm.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void setDefaultArgs(List<String> args) {
|
||||
if (!args.stream().anyMatch(arg -> arg.startsWith("-T") || arg.equals("--threads"))) {
|
||||
args.add("-T1C");
|
||||
}
|
||||
if (!args.stream().anyMatch(arg -> arg.startsWith("-b") || arg.equals("--builder"))) {
|
||||
args.add("-bsmart");
|
||||
}
|
||||
}
|
||||
|
||||
String startDaemon() {
|
||||
// DaemonParameters parms = new DaemonParameters();
|
||||
// for (String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
|
||||
//
|
||||
// }
|
||||
// List<String> args = new ArrayList<>();
|
||||
// args.add(javaHome.resolve(java).toString());
|
||||
// args.addAll(parms.getEffectiveJvmArgs());
|
||||
// args.add("-cp");
|
||||
// args.add(classpath);
|
||||
|
||||
final String uid = UUID.randomUUID().toString();
|
||||
final Path mavenHome = layout.mavenHome();
|
||||
final Path workingDir = layout.userDir();
|
||||
String command = "";
|
||||
try {
|
||||
String classpath = findClientJar(mavenHome).toString();
|
||||
final String java = ScriptUtils.isWindows() ? "bin\\java.exe" : "bin/java";
|
||||
List<String> args = new ArrayList<>();
|
||||
args.add("\"" + layout.javaHome().resolve(java) + "\"");
|
||||
args.add("-classpath");
|
||||
args.add("\"" + classpath + "\"");
|
||||
if (Boolean.getBoolean(DAEMON_DEBUG)) {
|
||||
args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000");
|
||||
}
|
||||
args.add("-Dmaven.home=\"" + mavenHome + "\"");
|
||||
args.add("-Dlogback.configurationFile=logback.xml");
|
||||
args.add("-Ddaemon.uid=" + uid);
|
||||
args.add("-Xmx4g");
|
||||
final String timeout = System.getProperty(DAEMON_IDLE_TIMEOUT);
|
||||
if (timeout != null) {
|
||||
args.add("-D" + DAEMON_IDLE_TIMEOUT + "=" + timeout);
|
||||
}
|
||||
args.add("\"-Dmaven.multiModuleProjectDirectory=" + layout.multiModuleProjectDirectory().toString() + "\"");
|
||||
|
||||
args.add(ServerMain.class.getName());
|
||||
command = String.join(" ", args);
|
||||
|
||||
LOGGER.debug("Starting daemon process: uid = {}, workingDir = {}, daemonArgs: {}", uid, workingDir, command);
|
||||
Process.create(workingDir.toFile(), command);
|
||||
return uid;
|
||||
} catch (Exception e) {
|
||||
throw new DaemonException.StartException(
|
||||
String.format("Error starting daemon: uid = %s, workingDir = %s, daemonArgs: %s",
|
||||
uid, workingDir, command), e);
|
||||
}
|
||||
}
|
||||
|
||||
Path findClientJar(Path mavenHome) {
|
||||
final Path ext = mavenHome.resolve("lib/ext");
|
||||
final String clientJarName = "mvnd-client-"+ buildProperties.getProperty("version") + ".jar";
|
||||
try (Stream<Path> files = Files.list(ext)) {
|
||||
return files
|
||||
.filter(f -> f.getFileName().toString().equals(clientJarName))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Could not find " + clientJarName + " in " + ext));
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not find " + clientJarName + " in " + ext, e);
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultResult implements ExecutionResult {
|
||||
|
||||
private final boolean success;
|
||||
private final List<String> args;
|
||||
|
||||
private DefaultResult(List<String> args, boolean success) {
|
||||
super();
|
||||
this.args = args;
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionResult assertSuccess() {
|
||||
if (!this.success) {
|
||||
throw new AssertionError(appendCommand(new StringBuilder("Build failed: ")));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionResult assertFailure() {
|
||||
if (this.success) {
|
||||
throw new AssertionError(appendCommand(new StringBuilder("Build did not fail: ")));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
StringBuilder appendCommand(StringBuilder sb) {
|
||||
sb.append("mvnd");
|
||||
for (String arg : args) {
|
||||
sb.append(" \"").append(arg).append('"');
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package org.jboss.fuse.mvnd.client;
|
||||
|
||||
/**
|
||||
* A result of a {@code mvnd} build.
|
||||
*/
|
||||
public interface ExecutionResult {
|
||||
|
||||
boolean isSuccess();
|
||||
|
||||
ExecutionResult assertFailure();
|
||||
|
||||
ExecutionResult assertSuccess();
|
||||
|
||||
}
|
Reference in New Issue
Block a user