diff --git a/README.md b/README.md index d2d0765d9..74aa608b9 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,7 @@ All components are modularized, including all their dependencies. In case a dependency is (sadly) not modularized yet, module information is manually added using [moditect](https://github.com/moditect/moditect-gradle-plugin). These dependency generation rules are accumulated in the [X-Pipe dependencies](https://github.com/xpipe-io/xpipe_java_deps) repository, which is shared between all components and integrated as a git submodule. + +Some unit tests depend on a connection to an X-Pipe daemon to properly function. +To launch the installed daemon, it is required that the `XPIPE_HOME` environment variable +is set or the `xpipe` / `xpipe.exe` CLI executable is added to the `PATH` variable. diff --git a/api/build.gradle b/api/build.gradle index c80b96920..aec245a1c 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -28,7 +28,10 @@ dependencies { } def canTestWithDev = findProject(':app') != null -def daemonCommand = canTestWithDev ? "cmd.exe /c \"$rootDir\\gradlew.bat\" :app:run" : 'xpipe.exe' +def home = System.getenv('XPIPE_HOME') +String daemonCommand = canTestWithDev ? + "cmd.exe /c \\\"$rootDir\\gradlew.bat\\\" :app:run" : + "cmd.exe /c \\\"$home\\app\\xpipe.exe\\\"" test { workingDir = rootDir @@ -40,11 +43,12 @@ test { " -Dio.xpipe.app.dataDir=$projectDir/local/" + " -Dio.xpipe.storage.persist=false" + " -Dio.xpipe.app.writeSysOut=true" + + " -Dio.xpipe.app.writeLogs=true" + // " -Dio.xpipe.beacon.debugOutput=true" + " -Dio.xpipe.app.logLevel=trace" // API properties // systemProperty 'io.xpipe.beacon.debugOutput', "true" - // systemProperty 'io.xpipe.beacon.debugExecOutput', "true" + systemProperty 'io.xpipe.beacon.debugExecOutput', "true" systemProperty "io.xpipe.beacon.port", "21722" } diff --git a/api/src/test/java/io/xpipe/api/test/ConnectionFactory.java b/api/src/test/java/io/xpipe/api/test/ConnectionFactory.java index 6790da803..4a6f24191 100644 --- a/api/src/test/java/io/xpipe/api/test/ConnectionFactory.java +++ b/api/src/test/java/io/xpipe/api/test/ConnectionFactory.java @@ -18,7 +18,7 @@ public class ConnectionFactory { throw new AssertionError(); } - XPipeConnection.waitForStartup(); + XPipeConnection.waitForStartup().orElseThrow(); if (!BeaconServer.isRunning()) { throw new AssertionError(); } diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconServer.java b/beacon/src/main/java/io/xpipe/beacon/BeaconServer.java index 98887efda..075492143 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconServer.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconServer.java @@ -33,6 +33,10 @@ public class BeaconServer { private static void startFork(String custom) throws IOException { boolean print = BeaconConfig.execDebugEnabled(); + if (print) { + System.out.println("Executing custom daemon launch command: " + custom); + } + System.out.println(System.getenv()); var proc = Runtime.getRuntime().exec(custom); new Thread(null, () -> { try { @@ -44,10 +48,29 @@ public class BeaconServer { System.out.println("[xpiped] " + line); } } - } catch (IOException ioe) { + } catch (Exception ioe) { ioe.printStackTrace(); } - }, "daemon fork").start(); + }, "daemon fork sysout").start(); + + new Thread(null, () -> { + try { + InputStreamReader isr = new InputStreamReader(proc.getErrorStream()); + BufferedReader br = new BufferedReader(isr); + String line; + while ((line = br.readLine()) != null) { + if (print) { + System.err.println("[xpiped] " + line); + } + } + int exit = proc.waitFor(); + if (exit != 0) { + System.err.println("Daemon launch command failed"); + } + } catch (Exception ioe) { + ioe.printStackTrace(); + } + }, "daemon fork syserr").start(); } public static boolean tryStart() throws Exception { @@ -57,10 +80,10 @@ public class BeaconServer { return true; } - var launcher = getLauncherExecutable(); - if (launcher.isPresent()) { - // Tell launcher that we launched from an external tool - new ProcessBuilder(launcher.get().toString(), "--external") + var daemonExecutable = getDaemonExecutable(); + if (daemonExecutable.isPresent()) { + // Tell daemon that we launched from an external tool + new ProcessBuilder(daemonExecutable.get().toString(), "--external") .redirectErrorStream(true) .redirectOutput(ProcessBuilder.Redirect.DISCARD) .start(); @@ -76,35 +99,20 @@ public class BeaconServer { return res.isSuccess(); } - private static Optional getPortableLauncherExecutable() { + private static Optional getDaemonExecutableFromHome() { var env = System.getenv("XPIPE_HOME"); + if (env == null) { + return Optional.empty(); + } + Path file; // Prepare for invalid XPIPE_HOME path value try { if (System.getProperty("os.name").startsWith("Windows")) { - file = Path.of(env, "xpipe_launcher.exe"); + file = Path.of(env, "app", "xpipe.exe"); } else { - file = Path.of(env, "xpipe_launcher"); - } - return Files.exists(file) ? Optional.of(file) : Optional.empty(); - } catch (Exception ex) { - return Optional.empty(); - } - } - - public static Optional getLauncherExecutable() { - var portable = getPortableLauncherExecutable(); - if (portable.isPresent()) { - return portable; - } - - try { - Path file; - if (System.getProperty("os.name").startsWith("Windows")) { - file = Path.of(System.getenv("LOCALAPPDATA"), "X-Pipe", "xpipe_launcher.exe"); - } else { - file = Path.of("/opt/xpipe/xpipe_launcher"); + file = Path.of(env, "app", "bin", "xpipe"); } return Files.exists(file) ? Optional.of(file) : Optional.empty(); } catch (Exception ex) { @@ -113,15 +121,21 @@ public class BeaconServer { } public static Optional getDaemonExecutable() { - try { - Path file; - if (System.getProperty("os.name").startsWith("Windows")) { - file = Path.of(System.getenv("LOCALAPPDATA"), "X-Pipe", "app", "xpipe.exe"); - } else { - file = Path.of("/opt/xpipe/bin/xpipe"); - } - return Files.exists(file) ? Optional.of(file) : Optional.empty(); - } catch (Exception ex) { + var home = getDaemonExecutableFromHome(); + if (home.isPresent()) { + return home; + } + + Path file; + if (System.getProperty("os.name").startsWith("Windows")) { + file = Path.of(System.getenv("LOCALAPPDATA"), "X-Pipe", "app", "xpipe.exe"); + } else { + file = Path.of("/opt/xpipe/app/bin/xpipe"); + } + + if (Files.exists(file)) { + return Optional.of(file); + } else { return Optional.empty(); } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fbce071a3..b1159fc54 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle index df119b379..992233ce8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,8 +1,8 @@ rootProject.name = 'xpipe_java' +include 'api' include 'core' include 'beacon' -include 'api' include 'extension' include 'sample_extension'