Skip to content
Snippets Groups Projects
Commit b6e51f9f authored by Mark Winter's avatar Mark Winter
Browse files

Merge branch 'leversc-fixes'

parents dea197d7 27dab9cc
No related branches found
No related tags found
No related merge requests found
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.leverjs</groupId>
<artifactId>Leversc_Plugin</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>leversc-installer</artifactId>
<version>21.5.21</version>
<packaging>jar</packaging>
<name>Leversc User-Mode Installer</name>
<description>A jar wrapping the leversc executable folder that self-extracts to a user-executable folder</description>
<properties>
<name>${project.name}</name>
<version>${project.version}</version>
</properties>
<dependencies>
<dependency>
<groupId>net.leverjs</groupId>
<artifactId>Leversc_IJ</artifactId>
<version>${project.version}</version>
</dependency>
<!-- <dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency> -->
<dependency>
<groupId>net.imagej</groupId>
<artifactId>ij</artifactId>
<version>1.53h</version>
<scope>provided</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>win64</id>
<build>
<finalName>${project.artifactId}-natives-win64-${project.version}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>leversc-win64/**</include>
</includes>
</resource>
</resources>
</build>
</profile>
<profile>
<id>linux64</id>
<build>
<finalName>${project.artifactId}-natives-linux64-${project.version}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>leversc-linux64/**</include>
</includes>
</resource>
</resources>
</build>
</profile>
<profile>
<id>macos</id>
<build>
<finalName>${project.artifactId}-natives-macosx-${project.version}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>leversc-macosx/**</include>
</includes>
</resource>
</resources>
</build>
</profile>
</profiles>
<build>
<plugins>
<!-- <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin> -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>write-project-properties</goal>
</goals>
<configuration>
<outputFile>${project.build.outputDirectory}/${project.artifactId}-build.properties</outputFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>show-profiles</id>
<phase>compile</phase>
<goals>
<goal>active-profiles</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package net.leverjs;
import net.leverjs.LeverscInstallInterface;
import net.leverjs.PlatformInfo;
import net.leverjs.PluginHelper;
import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Enumeration;
import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;
import java.io.IOException;
import java.util.zip.ZipException;
import java.net.URISyntaxException;
import java.io.FileNotFoundException;
import ij.IJ;
public class LeverscJarInstaller implements LeverscInstallInterface
{
public File installLeversc()
{
try
{
String localAppdata = PlatformInfo.getAppDataPath();
Path installPath = Paths.get(localAppdata, "leversc");
Path jarPath = PluginHelper.getJarPath(getClass());
// IJ.log(String.format("Installer JarPath: %s", jarPath.toString()));
if ( !Files.exists(installPath) )
Files.createDirectories(installPath);
// Check installed (and compare build-numbers)
String build = PluginHelper.getResourceProperty(getClass(), "/leversc-installer-build.properties", "buildNumber");
if ( build == null )
{
IJ.log("Malformed installer jar: No buildNumber in build.properties");
return null;
}
boolean bNeedsUpdate = true;
Path buildFile = Paths.get(installPath.toString(), "version.txt");
if ( Files.exists(buildFile) )
{
IJ.log("Levesc install found, checking build version...");
String installedBuild = new String(Files.readAllBytes(buildFile), StandardCharsets.UTF_8).trim();
bNeedsUpdate = ( !build.equalsIgnoreCase(installedBuild) );
}
// Early out if we already have an up-to-date install
boolean bNeedsInstall = !Files.exists(buildFile);
if ( !bNeedsUpdate )
{
IJ.log("Leversc up-to-date");
return getLeverscExecutable(installPath);
}
IJ.showStatus(String.format("%s Leversc Executable...", (bNeedsInstall ? "Installing" : "Updating")));
IJ.showProgress(0.0);
// TODO: Warn users that install/update might take some time
removeChildren(installPath.toFile());
// TODO: Use showProgress to give feedback during install
String prefix = String.format("leversc-%s/", PlatformInfo.getPlatformString());
extractJar(installPath.toFile(), jarPath.toFile(), prefix);
writeBuild(installPath.toFile(), build);
IJ.showStatus("");
IJ.showProgress(1.0);
IJ.log("Leversc update complete");
return getLeverscExecutable(installPath);
}
catch (FileNotFoundException e)
{
IJ.log(String.format("File not found: %s", e.toString()));
}
catch (URISyntaxException e)
{
IJ.log(String.format("URI error: %s", e.toString()));
}
catch (IOException e)
{
IJ.log(String.format("IO error: %s", e.toString()));
}
return null;
}
private static void removeChildren(File inPath)
{
File[] contents = inPath.listFiles();
if ( contents == null )
return;
for ( File entry : contents )
{
if ( entry.isDirectory() )
removeChildren(entry);
entry.delete();
}
}
private static File getLeverscExecutable(Path installPath)
{
File leverscExec = null;
if ( PlatformInfo.isWindows() )
leverscExec = new File(installPath.toFile(), "leverjs.exe");
else if ( PlatformInfo.isLinux() )
leverscExec = new File(installPath.toFile(), "leverjs");
else if ( PlatformInfo.isMac() )
leverscExec = new File(installPath.toFile(), "leverjs.app");;
if ( leverscExec != null )
{
if ( PlatformInfo.isMac() )
{
Path macosExec = Paths.get(leverscExec.toString(), "Contents", "MacOS", "leverjs");
macosExec.toFile().setExecutable(true);
}
else
leverscExec.setExecutable(true);
}
return leverscExec;
}
private void extractJar(File installPath, File jarFile, String matchPrefix) throws ZipException, IOException
{
// IJ.log(String.format("Extracting %s -> %s", jarFile.getPath(), installPath.getPath()));
ZipFile zipFile = new ZipFile(jarFile);
try
{
int outBytes = 0;
List<ZipEntry> matchEntries = new ArrayList<ZipEntry>(50);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while ( entries.hasMoreElements() )
{
ZipEntry entry = entries.nextElement();
if ( entry.getName().startsWith(matchPrefix) )
{
matchEntries.add(entry);
if ( !entry.isDirectory() )
outBytes += entry.getSize();
}
}
int extractBytes = 0;
for ( ZipEntry ze : matchEntries )
{
String outName = ze.getName().substring(matchPrefix.length());
// Ignore the leversc-* directory entry
if ( outName.length() > 0 )
{
File target = new File(installPath, outName);
if ( ze.isDirectory() )
{
if ( !target.mkdirs() )
throw new IOException(String.format("Unable to create directory: %s", target.getPath()));
}
else
{
extractEntry(target, ze, zipFile);
extractBytes += ze.getSize();
IJ.showProgress(((float)extractBytes) / outBytes);
}
}
}
}
finally
{
zipFile.close();
}
}
private void extractEntry(File target, ZipEntry entry, ZipFile zipFile) throws FileNotFoundException, IOException
{
byte[] buffer = new byte[100*1024];
InputStream zis = zipFile.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(target);
try
{
int len = zis.read(buffer);
while ( len > 0 )
{
fos.write(buffer, 0,len);
len = zis.read(buffer);
}
}
finally
{
zis.close();
fos.close();
}
}
private static void writeBuild(File installPath, String build) throws FileNotFoundException, IOException
{
File verFile = new File(installPath, "version.txt");
OutputStreamWriter outWriter = new OutputStreamWriter(new FileOutputStream(verFile.toString()), StandardCharsets.UTF_8);
try
{
outWriter.write(build);
}
finally
{
outWriter.close();
}
}
}
......@@ -56,12 +56,10 @@ public class LeverscIJ implements PlugInFilter
}
protected static int npack = 4;
protected static String host = "host.docker.internal";
protected static String host = "127.0.0.1";
protected static int base_port = 3000;
protected static byte[] _crlf = {0x0D, 0x0A};
private static LeverscInstallInterface installer = LeverscInstallLoader.load();
// Current image
protected ImagePlus image;
public int imType;
......@@ -70,13 +68,8 @@ public class LeverscIJ implements PlugInFilter
public int setup(String arg, ImagePlus imp)
{
// TODO - Try default install folders (e.g. LOCALAPPDATA/leversc)
leverscExec = null;
if ( installer != null )
{
IJ.log(String.format("Found installer: %s", installer.toString()));
leverscExec = installer.installLeversc();
}
image = imp;
// TODO - Should we try to support any color (drop DOES_8C or add DOES_RGB) stacks?
......@@ -96,7 +89,7 @@ public class LeverscIJ implements PlugInFilter
Metadata meta = load_metadata();
if ( !init_leversc(fignum) )
{
Path logpath = Paths.get(System.getProperty("user.home"),".lever");
Path logpath = Paths.get(PlatformInfo.getUserHome(),".lever");
IJ.log("Unable to initialize leversc!");
IJ.log(String.format("Check leversc log files for details at: %s", logpath.toString()));
......@@ -123,6 +116,9 @@ public class LeverscIJ implements PlugInFilter
int port = base_port + fignum;
URL url = new URL("http", host, port, "/loadfig");
if ( IJ.debugMode )
IJ.log(String.format("LEVERSC send: %s", url.toString()));
String boundary = "---------------Leversc_" + UUID.randomUUID().toString();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
......@@ -139,8 +135,10 @@ public class LeverscIJ implements PlugInFilter
dos.write(_crlf);
dos.close();
int resp = conn.getResponseCode();
// IJ.log(String.format("Got leversc resp: %d", resp));
// TODO: We don't curently do anything with this response code, but it's important to retrieve it for proper data transmission
int status = conn.getResponseCode();
if ( IJ.debugMode )
IJ.log(String.format("LEVERSC response: %d", status));
conn.disconnect();
}
......@@ -326,7 +324,8 @@ public class LeverscIJ implements PlugInFilter
final Genson genson = new Genson();
String json = genson.serialize(meta);
// IJ.log(String.format("JSON: %s", json));
if ( IJ.debugMode )
IJ.log(String.format("LEVERSC JSON Header: %s", json));
return json;
}
......@@ -383,6 +382,7 @@ public class LeverscIJ implements PlugInFilter
conn.setConnectTimeout(500);
BufferedReader resp_reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// TODO: We should verify a version string here once that is properly returned by LEVERSC
String resp = read_all_buffered(resp_reader);
resp_reader.close();
......
package net.leverjs;
import java.io.File;
public interface LeverscInstallInterface
{
public File installLeversc();
}
package net.leverjs;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.PathMatcher;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.function.Predicate;
import java.io.IOException;
import java.net.URISyntaxException;
import ij.IJ;
public class LeverscInstallLoader
{
private static class InstallerPredicate implements Predicate<Path>
{
private PathMatcher matcher;
public InstallerPredicate(PathMatcher inMatcher)
{
matcher = inMatcher;
}
@Override
public boolean test(Path path)
{
return matcher.matches(path);
}
}
public static LeverscInstallInterface load()
{
// NOTE: IJ Platforms: { "linux32", "linux64", "macosx", "tiger", "win32", "win64" }
final Class pluginClass = LeverscIJ.class;
String platform = PlatformInfo.getPlatformString();
String version = PluginHelper.getResourceProperty(pluginClass, "/Leversc_IJ-build.properties", "version");
try
{
Path jarFolderPath = PluginHelper.getJarPath(pluginClass).getParent();
String glob = String.format("glob:**/leversc-installer-natives-%s-%s.jar",platform,version);
PathMatcher matcher = FileSystems.getDefault().getPathMatcher(glob);
InstallerPredicate matchPred = new InstallerPredicate(matcher);
Path checkDir = Paths.get(jarFolderPath.toString(), platform);
if ( !Files.exists(checkDir) )
checkDir = Paths.get(jarFolderPath.toString());
Path installerJar = Files.walk(checkDir).filter(matchPred).findFirst().orElse(null);
if ( installerJar == null )
{
IJ.log(String.format("No installer jar found: %s", checkDir));
return null;
}
ClassLoader loader = URLClassLoader.newInstance(
new URL[] {installerJar.toUri().toURL()},
pluginClass.getClassLoader()
);
Class<?> installClass = Class.forName("net.leverjs.LeverscJarInstaller", true, loader);
Class<? extends LeverscInstallInterface> subClass = installClass.asSubclass(LeverscInstallInterface.class);
return subClass.newInstance();
}
catch (IllegalAccessException e)
{
IJ.log(e.toString());
}
catch (InstantiationException e)
{
IJ.log(String.format("Unable to instantiate installer class: %s", e.toString()));
}
catch (ClassNotFoundException e)
{
IJ.log(String.format("Unable to find class: %s", e.toString()));
}
catch (ClassCastException e)
{
IJ.log(String.format("Invalid installer class: %s", e.toString()));
}
catch (URISyntaxException e)
{
IJ.log(String.format("Invalid file URL: %s", e.toString()));
}
catch (IOException e)
{
IJ.log(String.format("IO error: %s:%s", e.toString(), e.getStackTrace()[0].getLineNumber()));
}
return null;
}
}
......@@ -72,7 +72,7 @@ public class LeverscLaunch
public static boolean launch(File localLeverscExec, int fignum, int base_port)
{
// Always put .lever files in ~/.lever folder
Path cwd_lever = Paths.get(System.getProperty("user.home"),".lever");
Path cwd_lever = Paths.get(PlatformInfo.getUserHome(),".lever");
// Make sure ~/.lever folder exists
try
......@@ -145,7 +145,8 @@ public class LeverscLaunch
private static boolean exec_process(List<String> cmdArgs)
{
IJ.log(String.format("Run Leversc: %s", cmdArgs.toString()));
if ( IJ.debugMode )
IJ.log(String.format("Launching Leversc: %s", cmdArgs.toString()));
String[] strArgs = new String[cmdArgs.size()];
strArgs = cmdArgs.toArray(strArgs);
......@@ -156,8 +157,8 @@ public class LeverscLaunch
p = Runtime.getRuntime().exec(strArgs);
if ( p!= null )
{
File stdoutLog = Paths.get(System.getProperty("user.home"),".lever", "leversc_out.log").toFile();
File stderrLog = Paths.get(System.getProperty("user.home"),".lever", "leversc_err.log").toFile();
File stdoutLog = Paths.get(PlatformInfo.getUserHome(),".lever", "leversc_out.log").toFile();
File stderrLog = Paths.get(PlatformInfo.getUserHome(),".lever", "leversc_err.log").toFile();
LogThread stdoutLogger = new LogThread(p.getInputStream(), stdoutLog);
LogThread stderrLogger = new LogThread(p.getErrorStream(), stderrLog);
......
package net.leverjs;
import java.nio.file.Path;
import java.nio.file.Paths;
public class PlatformInfo
......@@ -20,6 +19,11 @@ public class PlatformInfo
return "unknown";
}
public static String getUserHome()
{
return System.getProperty("user.home");
}
public static String getAppDataPath()
{
......@@ -29,15 +33,15 @@ public class PlatformInfo
{
String xdg_home = System.getenv("XDG_DATA_HOME");
if ( xdg_home == null )
xdg_home = Paths.get(System.getProperty("user.home"), ".local", "share").toString();
xdg_home = Paths.get(getUserHome(), ".local", "share").toString();
return xdg_home;
}
else if ( isMac() )
{
return Paths.get(System.getProperty("user.home"), "Applications").toString();
return Paths.get(getUserHome(), "Applications").toString();
}
else
return System.getProperty("user.home");
return getUserHome();
}
public static boolean isWindows()
......
......@@ -14,13 +14,13 @@ import ij.IJ;
public class PluginHelper
{
public static Path getJarPath(Class inClass) throws URISyntaxException
public static Path getJarPath(Class<?> inClass) throws URISyntaxException
{
URL jarUrl = inClass.getProtectionDomain().getCodeSource().getLocation();
return Paths.get(jarUrl.toURI());
}
public static String getResourceProperty(Class inClass, String resourcePath, String propertyName)
public static String getResourceProperty(Class<?> inClass, String resourcePath, String propertyName)
{
try
{
......
......@@ -30,7 +30,6 @@
</scm>
<modules>
<module>plugin-ij</module>
<module>install-native</module>
</modules>
</project>
......@@ -125,7 +125,7 @@ end
function launch_electron_windows(port,fignum,workdir, leverpath, strDB)
elec_cmd = 'leverjs.exe';
if ( ~isempty(leverpath) )
elec_path = fullfile(leverpath,'node_modules','electron','dist','electron.exe');
elec_path = fullfile(leverpath,'node_modules','.bin','electron.cmd');
elec_cmd = [elec_path ' ' fullfile(leverpath,'elever','main.js')];
else
[status,~] = system(['where ' elec_cmd]);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment