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 05558d13..8b867176 100644 --- a/client/src/main/java/org/mvndaemon/mvnd/client/DaemonConnector.java +++ b/client/src/main/java/org/mvndaemon/mvnd/client/DaemonConnector.java @@ -23,8 +23,10 @@ import static org.mvndaemon.mvnd.common.DaemonState.Canceled; import java.io.File; import java.io.IOException; +import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; +import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.file.DirectoryStream; import java.nio.file.Files; @@ -122,7 +124,7 @@ public class DaemonConnector { final String daemonId = newId(); String message = handleStopEvents(daemonId, idleDaemons, busyDaemons); output.accept(Message.buildStatus(message)); - return startDaemon(daemonId); + return startDaemon(daemonId, output); } private DaemonClientConnection connectNoDaemon() { @@ -297,8 +299,8 @@ public class DaemonConnector { return null; } - public DaemonClientConnection startDaemon(String daemonId) { - final Process process = startDaemonProcess(daemonId); + public DaemonClientConnection startDaemon(String daemonId, ClientOutput output) { + final Process process = startDaemonProcess(daemonId, output); LOGGER.debug("Started Maven daemon {}", daemonId); long start = System.currentTimeMillis(); do { @@ -321,7 +323,7 @@ public class DaemonConnector { return String.format("%08x", new Random().nextInt()); } - private Process startDaemonProcess(String daemonId) { + private Process startDaemonProcess(String daemonId, ClientOutput output) { final Path mvndHome = parameters.mvndHome(); final Path workingDir = parameters.userDir(); String command = ""; @@ -354,7 +356,32 @@ public class DaemonConnector { args.add("-javaagent:" + mvndAgentPath); // debug options if (parameters.property(Environment.MVND_DEBUG).asBoolean()) { - args.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000"); + 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); } // jvm args String jvmArgs = parameters.jvmArgs(); 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 95cd046e..a7477de0 100644 --- a/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java +++ b/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java @@ -169,6 +169,13 @@ public enum Environment { * not passed to the daemon. */ MVND_DEBUG("mvnd.debug", null, Boolean.FALSE, OptionType.BOOLEAN, Flags.DISCRIMINATING), + /** + * The tcp address used to launch the debug mode. Defaults to 8000, which is similar to + * localhost:8000. In order to remote debug from a different computer, you need to allow + * remote connections using *:8000 for example. Use a port with a value of 0 + * to have mvnd to choose one. + */ + MVND_DEBUG_ADDRESS("mvnd.debug.address", null, "8000", OptionType.STRING, Flags.DISCRIMINATING), /** * A time period after which an unused daemon will terminate by itself. */ diff --git a/dist/src/main/distro/bin/mvnd-bash-completion.bash b/dist/src/main/distro/bin/mvnd-bash-completion.bash index 4b90feab..45ffc0d8 100644 --- a/dist/src/main/distro/bin/mvnd-bash-completion.bash +++ b/dist/src/main/distro/bin/mvnd-bash-completion.bash @@ -218,7 +218,7 @@ _mvnd() local mvnd_opts="-1" local mvnd_long_opts="--color|--completion|--purge|--serial|--status|--stop" - local mvnd_properties="-Djava.home|-Djdk.java.options|-Dmaven.multiModuleProjectDirectory|-Dmaven.repo.local|-Dmaven.settings|-Dmvnd.buildTime|-Dmvnd.builder|-Dmvnd.daemonStorage|-Dmvnd.debug|-Dmvnd.duplicateDaemonGracePeriod|-Dmvnd.enableAssertions|-Dmvnd.expirationCheckDelay|-Dmvnd.home|-Dmvnd.idleTimeout|-Dmvnd.jvmArgs|-Dmvnd.keepAlive|-Dmvnd.logPurgePeriod|-Dmvnd.logback|-Dmvnd.maxHeapSize|-Dmvnd.maxLostKeepAlive|-Dmvnd.minHeapSize|-Dmvnd.minThreads|-Dmvnd.noBuffering|-Dmvnd.noDaemon|-Dmvnd.pluginRealmEvictPattern|-Dmvnd.propertiesPath|-Dmvnd.registry|-Dmvnd.rollingWindowSize|-Dmvnd.serial|-Dmvnd.socketFamily|-Dmvnd.threadStackSize|-Dmvnd.threads|-Dstyle.color|-Duser.dir|-Duser.home" + local mvnd_properties="-Djava.home|-Djdk.java.options|-Dmaven.multiModuleProjectDirectory|-Dmaven.repo.local|-Dmaven.settings|-Dmvnd.buildTime|-Dmvnd.builder|-Dmvnd.daemonStorage|-Dmvnd.debug|-Dmvnd.debug.address|-Dmvnd.duplicateDaemonGracePeriod|-Dmvnd.enableAssertions|-Dmvnd.expirationCheckDelay|-Dmvnd.home|-Dmvnd.idleTimeout|-Dmvnd.jvmArgs|-Dmvnd.keepAlive|-Dmvnd.logPurgePeriod|-Dmvnd.logback|-Dmvnd.maxHeapSize|-Dmvnd.maxLostKeepAlive|-Dmvnd.minHeapSize|-Dmvnd.minThreads|-Dmvnd.noBuffering|-Dmvnd.noDaemon|-Dmvnd.pluginRealmEvictPattern|-Dmvnd.propertiesPath|-Dmvnd.registry|-Dmvnd.rollingWindowSize|-Dmvnd.serial|-Dmvnd.socketFamily|-Dmvnd.threadStackSize|-Dmvnd.threads|-Dstyle.color|-Duser.dir|-Duser.home" local opts="-am|-amd|-B|-C|-c|-cpu|-D|-e|-emp|-ep|-f|-fae|-ff|-fn|-gs|-h|-l|-N|-npr|-npu|-nsu|-o|-P|-pl|-q|-rf|-s|-T|-t|-U|-up|-V|-v|-X|${mvnd_opts}" local long_opts="--also-make|--also-make-dependents|--batch-mode|--strict-checksums|--lax-checksums|--check-plugin-updates|--define|--errors|--encrypt-master-password|--encrypt-password|--file|--fail-at-end|--fail-fast|--fail-never|--global-settings|--help|--log-file|--non-recursive|--no-plugin-registry|--no-plugin-updates|--no-snapshot-updates|--offline|--activate-profiles|--projects|--quiet|--resume-from|--settings|--threads|--toolchains|--update-snapshots|--update-plugins|--show-version|--version|--debug|${mvnd_long_opts}"