Fixed: Use launcher location to infer ij-dir, similar to path in argv[0] #5

This commit is contained in:
Jarek Sacha 2023-06-04 18:25:59 -04:00
parent 1d5b8887a3
commit 87882dc6e3
No known key found for this signature in database
GPG key ID: F29625CE62288163
4 changed files with 126 additions and 27 deletions

View file

@ -0,0 +1,40 @@
#include <stdio.h>
#if defined(__linux__)
#include <unistd.h>
#include <limits.h>
#elif defined(__APPLE__)
#include <stdint.h>
#include <sys/syslimits.h>
#elif defined(_WIN32)
#include <windows.h>
#endif
size_t path_max() {
#ifdef _WIN32
return MAX_PATH;
#else
return PATH_MAX + 1;
#endif
}
void get_exe_path(char* exe_path, size_t size) {
exe_path[0] = 0;
#if defined(__linux__)
// char arg1[20];
// sprintf( arg1, "/proc/%d/exe", getpid() );
// printf("arg1 = %d\n", arg1);
// readlink( arg1, exepath, PATH_MAX );
readlink( "/proc/self/exe", exe_path, size );
#elif defined(__APPLE__)
if (_NSGetExecutablePath(exe_path, &size) != 0)
printf("ERROR: buffer too small; need size %lu\n", size);
#elif defined(_WIN32)
unsigned int len = GetModuleFileNameA(GetModuleHandleA(0x0), exe_path, size);
if (len == 0) // memory not sufficient or general error occurred
printf("ERROR: buffer too small or general error.\n");
#endif
}

View file

@ -0,0 +1,58 @@
package ij_plugins.imagej_launcher
import ij_plugins.imagej_launcher.Main.Config
import os.{FilePath, Path, RelPath, SubPath}
import scala.util.control.NonFatal
object IJDir:
/** Name of an ImageJ sub-directory containing jars */
val jarsDirName = "jars"
/** Locate ImageJ directory */
def locate(config: Config, logger: Logger): Either[String, Path] =
logger.debug("Looking for ImageJ directory")
config.ijDir match
case Some(d) =>
logger.debug(s" Considering provided ij-dir: '$d''")
asPath(d.getPath).flatMap: p =>
logger.debug(s" '$p''")
if isIJDir(p) then Right(p)
else Left(s"ij-dir is not an ImageJ directory [$p]")
case None =>
logger.debug(" Considering application directory")
val appPath = Native.applicationPath()
logger.debug(s" Application directory: '$appPath'")
if isIJDir(appPath) then
Right(appPath)
else
logger.debug(" Application directory is not an ImageJ directory")
logger.debug(" Considering current working directory")
val cwd = os.pwd
logger.debug(s" Current working directory: '$cwd'")
if isIJDir(cwd) then
Right(cwd)
else
logger.debug(" Current working directory is not an ImageJ directory.")
Left("Cannot locate ImageJ directory.")
private def isIJDir(path: Path): Boolean =
os.exists(path) &&
os.isDir(path) &&
os.list(path).exists(f => f.last == jarsDirName && os.isDir(f))
private def asPath(filePath: String): Either[String, Path] =
if filePath.trim.startsWith("~") then
try
Right(Path.expandUser(filePath))
catch
case NonFatal(ex) =>
Left(s"Not an absolute path: '$filePath' [${ex.getMessage}]")
else
FilePath(filePath) match
case p: Path => Right(p)
case _ => Left(s"Not an absolute path: '$filePath''")
end IJDir

View file

@ -5,6 +5,7 @@
package ij_plugins.imagej_launcher
import ij_plugins.imagej_launcher.IJDir.jarsDirName
import ij_plugins.imagej_launcher.Launcher.javaExeFileName
import ij_plugins.imagej_launcher.Main.Config
import os.Path
@ -14,8 +15,6 @@ import java.lang.ProcessBuilder.Redirect
class Launcher(logger: Logger):
private val jarsDirName = "jars"
def run(config: Config): Unit =
prepareLaunch(config) match
case Right(commandLine) =>
@ -29,33 +28,15 @@ class Launcher(logger: Logger):
private def prepareLaunch(config: Config): Either[String, Seq[String]] =
for
ijDir <- locateIJDir(config)
_ <- Updater.update(Path(ijDir), config.dryRun, logger)
launcherJar <- findImageJLauncherJar(ijDir)
javaExe <- locateJavaExecutable(config, ijDir)
ijDir <- IJDir.locate(config, logger)
_ <- Updater.update(ijDir, config.dryRun, logger)
launcherJar <- findImageJLauncherJar(ijDir.toIO)
javaExe <- locateJavaExecutable(config, ijDir.toIO)
systemType <- determineSystemType()
yield
val maxMemoryMB = determineMaxMemoryMB()
logger.info(s"Max memory to use: ${maxMemoryMB}MB")
buildCommandLine(ijDir, javaExe, launcherJar, systemType, maxMemoryMB)
private def locateIJDir(config: Config): Either[String, File] =
logger.debug("Looking for ImageJ directory")
val dir = config.ijDir match
case Some(d) =>
logger.debug(" Considering provided ij-dir")
d
case None =>
logger.debug(" Considering current directory")
new File(".").getCanonicalFile
dir.listFiles().find(f => f.getName == jarsDirName && f.isDirectory) match
case Some(_) =>
logger.info(s" ImageJ directory set to: '$dir'")
Right(dir)
case None =>
Left(s"Cannot locate ImageJ directory. No subdirectory '$jarsDirName' in '$dir''")
buildCommandLine(ijDir.toIO, javaExe, launcherJar, systemType, maxMemoryMB)
private def findImageJLauncherJar(ijDir: File): Either[String, File] =
logger.debug("Looking for 'imagej-launcher*.jar'")
@ -119,7 +100,7 @@ class Launcher(logger: Logger):
p.toIO.getName == javaExeFileName &&
p.toIO.getParentFile.getName == "bin"
)
logger.debug(" Candidates: " + c2.mkString(", "))
logger.debug(" Candidates: " + c2.mkString(", "))
c2.map(_.toIO.getParentFile.getParentFile)
.headOption
else

View file

@ -1,9 +1,29 @@
package ij_plugins.imagej_launcher
import scala.scalanative.unsafe.extern
import os.{Path, up}
import scala.scalanative.unsafe
import scala.scalanative.unsafe.*
object Native:
def applicationPath(): Path =
val maxPath: CSize = argv0.path_max()
// use Zone to manage native memory
val exePath =
Zone { implicit z =>
val buffer: CString = alloc[CChar](maxPath)
argv0.get_exe_path(buffer, maxPath)
unsafe.fromCString(buffer)
}
Path(exePath) / up
@extern
object mem:
def determineTotalSystemMemory(): Long = extern
@extern
private object argv0:
def path_max(): CSize = extern
def get_exe_path(exe_path: CString, size: CSize): Unit = extern