From 6889572045b307e259cdf18eff7d2558d1eab345 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 26 Jun 2022 00:19:09 -0400 Subject: [PATCH] Fix native library cleanup Ref https://github.com/sbt/sbt/issues/6931 Problem ------- JNI version of the ipc-socket extracts native library into a temp directory, and after it's done tries to delete it. Because it uses /tmp by default, this effectively attemps to remove empty directories it. Solution -------- 1. Namespace it to use `.sbt` under temp. 2. Check that the file has the libsbtipcsocket prefix. --- build.sbt | 1 - project/build.properties | 2 +- .../org/scalasbt/ipcsocket/NativeLoader.java | 27 ++++++++++++------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/build.sbt b/build.sbt index cfb1fdb..9c51c02 100644 --- a/build.sbt +++ b/build.sbt @@ -99,7 +99,6 @@ buildWin32 / skip := { isWin || Try(s"which ${(buildWin32 / nativeCompiler).value}".!!).fold(_ => true, _.isEmpty) } Test / fork := true -Test / javaOptions += s"-Dsbt.ipcsocket.tmpdir=${(Compile / target).value}/jni" Test / fullClasspath := (Test / fullClasspath).dependsOn(buildDarwin, buildLinux, buildWin32).value clangfmt / fileInputs += baseDirectory.value.toGlob / "jni" / "*.c" diff --git a/project/build.properties b/project/build.properties index 67d27a1..c8fcab5 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.3 +sbt.version=1.6.2 diff --git a/src/main/java/org/scalasbt/ipcsocket/NativeLoader.java b/src/main/java/org/scalasbt/ipcsocket/NativeLoader.java index 44ab43c..d0f06c9 100644 --- a/src/main/java/org/scalasbt/ipcsocket/NativeLoader.java +++ b/src/main/java/org/scalasbt/ipcsocket/NativeLoader.java @@ -34,10 +34,18 @@ class NativeLoader { private static final String pid = isWindows ? "" : ManagementFactory.getRuntimeMXBean().getName().replaceAll("@.*", ""); - private static String tmpDirLocation() { - return System.getProperty("sbt.ipcsocket.tmpdir", System.getProperty("java.io.tmpdir")); + private static Path tmpDir() { + String prop = System.getProperty("sbt.ipcsocket.tmpdir"); + String tmp = System.getProperty("java.io.tmpdir"); + if (prop != null) { + return Paths.get(prop); + } else { + return Paths.get(tmp).resolve(".sbt").resolve("ipcsocket"); + } } + private static final String tempFilePrefix = "libsbtipcsocket"; + static void load() throws UnsatisfiedLinkError { if (!loaded.get()) { final String os = System.getProperty("os.name", "").toLowerCase(); @@ -45,7 +53,6 @@ static void load() throws UnsatisfiedLinkError { final boolean isLinux = os.startsWith("linux"); final boolean isWindows = os.startsWith("windows"); final boolean is64bit = System.getProperty("sun.arch.data.model", "64").equals("64"); - String tmpDir = tmpDirLocation(); if (is64bit && (isMac || isLinux || isWindows)) { final String extension = "." + (isMac ? "dylib" : isWindows ? "dll" : "so"); final String libName = (isWindows ? "" : "lib") + "sbtipcsocket" + extension; @@ -55,11 +62,8 @@ static void load() throws UnsatisfiedLinkError { final URL url = NativeLoader.class.getClassLoader().getResource(resource); if (url == null) throw new UnsatisfiedLinkError(resource + " not found on classpath"); try { - final Path base = - tmpDir == null - ? Files.createTempDirectory("sbtipcsocket") - : Files.createDirectories(Paths.get(tmpDir)); - final Path output = Files.createTempFile(base, "libsbtipcsocket", extension); + final Path base = Files.createDirectories(tmpDir()); + final Path output = Files.createTempFile(base, tempFilePrefix, extension); try (final InputStream in = url.openStream(); final FileChannel channel = FileChannel.open(output, StandardOpenOption.WRITE)) { int total = 0; @@ -117,7 +121,7 @@ private static class CleanupRunnable implements Runnable { public void run() { try { Files.walkFileTree( - Paths.get(tmpDirLocation()), + tmpDir(), new FileVisitor() { @Override public FileVisitResult preVisitDirectory( @@ -128,7 +132,10 @@ public FileVisitResult preVisitDirectory( @Override public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { - if (isWindows) { + if (!file.getFileName().toString().startsWith(tempFilePrefix)) { + // do nothing + return FileVisitResult.CONTINUE; + } else if (isWindows) { try { Files.deleteIfExists(file); } catch (final IOException e) {