From: Ben Soares Date: Wed, 12 Jun 2024 22:22:17 +0000 (+0100) Subject: JAL-3631 Spot system property triggers in getdown to create/activate using a user... X-Git-Tag: Release_2_11_4_0~24^2~43 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=ddcbcdbcbf276a40b074374ce69f7f02eaa2705a;p=jalview.git JAL-3631 Spot system property triggers in getdown to create/activate using a user-space location (dependent on OS), and copy digest-tested files from the Application's app dir to the user's new app dir. Debugging statements left in for testing on other OSes. --- diff --git a/getdown/lib/getdown-core.jar b/getdown/lib/getdown-core.jar index 8c9e44b..6c20166 100644 Binary files a/getdown/lib/getdown-core.jar and b/getdown/lib/getdown-core.jar differ diff --git a/getdown/lib/getdown-launcher-local.jar b/getdown/lib/getdown-launcher-local.jar index a3528ac..02d1a13 100644 Binary files a/getdown/lib/getdown-launcher-local.jar and b/getdown/lib/getdown-launcher-local.jar differ diff --git a/getdown/lib/getdown-launcher.jar b/getdown/lib/getdown-launcher.jar index f803c4f..7862c28 100644 Binary files a/getdown/lib/getdown-launcher.jar and b/getdown/lib/getdown-launcher.jar differ diff --git a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java index f83add3..52876f0 100644 --- a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java +++ b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java @@ -19,6 +19,8 @@ import java.net.URLEncoder; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.OverlappingFileLockException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; import java.security.*; import java.security.cert.Certificate; import java.util.*; @@ -35,7 +37,7 @@ import jalview.util.LaunchUtils; import com.threerings.getdown.util.*; // avoid ambiguity with java.util.Base64 which we can't use as it's 1.8+ import com.threerings.getdown.util.Base64; - +import com.threerings.getdown.Log; import com.threerings.getdown.data.EnvConfig; import com.threerings.getdown.data.EnvConfig.Note; @@ -1090,7 +1092,7 @@ public class Application // add the marker indicating the app is running in getdown args.add("-D" + Properties.GETDOWN + "=true"); args.add("-Dsys.install4jVersion=" + Application.i4jVersion); - args.add("-Dinstaller_template_version=" + System.getProperty("installer_template_version")); + args.add("-Dinstaller.template_version=" + System.getProperty("installer.template_version")); args.add("-Dlauncher_version=" + Build.version()); // set HiDPI property if wanted @@ -2062,6 +2064,135 @@ public class Application return _appbase; } + protected static boolean copyApplicationAppDirToUserAppDir(String applicationAppDirName, String userAppDirName) { + System.out.println("##### About to run copyApplicationAppDirToUserAppDir"); + System.out.println("##### applicationAppDirName='"+applicationAppDirName+"'"); + System.out.println("##### userAppDirName='"+userAppDirName+"'"); + if (applicationAppDirName == null || userAppDirName == null) { + log.warning("Null parameter", "applicationAppDirName", applicationAppDirName, "userAppDirName", userAppDirName); + return false; + } + File applicationAppDir = new File(applicationAppDirName); + File userAppDir = new File(userAppDirName); + if (!userAppDir.exists()) { + userAppDir.mkdirs(); + } + if (!(applicationAppDir.isDirectory() && userAppDir.isDirectory())) { + log.warning("Parameter not a directory", "applicaitonAppDirName", applicationAppDirName, "userAppDirName", userAppDirName); + return false; + } + File configFile = new File(applicationAppDir, CONFIG_FILE); + File userConfigFile = new File(userAppDir, CONFIG_FILE); + + if (userConfigFile.exists()) { + // We don't need to do this + return true; + } + + if (!configFile.isFile()) { + log.warning("Config file path not a file", "config", configFile); + return false; + } + + Config.ParseOpts opts = Config.createOpts(false); + Config config; + try { + config = Config.parseConfig(configFile, opts); + } catch (IOException e) { + log.warning("Problem opening application config file", configFile); + return false; + } + // get all types of local resource + String[] resourceNames = { "code", "ucode", "resource", "uresource", "xresource", "presource", "nresource" }; + List copyResources = new ArrayList<>(); + for (String resourceName: resourceNames) { + parseSimpleLocalResources(config, resourceName, applicationAppDir.getPath(), copyResources, resourceName.equals("xresource")); + } + Digest digest2; + Digest digest; + try { + digest2 = new Digest(applicationAppDir, true); + digest = new Digest(applicationAppDir, 1, true); + } catch (IOException e) { + log.warning("Problem opening application digest files", new File(applicationAppDir, Digest.digestFile(Digest.VERSION))); + return false; + } + // copy getdown.txt, digest.txt and digest2.txt + for (File from: new File[] {configFile, digest2.getFile(), digest.getFile()}) { + try { + File to = new File(userAppDir, from.getName()); + Files.copy(from.toPath(), to.toPath()); + } catch (IOException e) { + log.warning("Couldn't copy config/digest file", from); + } + } + + MessageDigest md = Digest.getMessageDigest(Digest.VERSION); + for (Resource rsc: copyResources) { + System.out.println("##### resource: "+rsc.toString()); + String digestHash = digest2.getDigest(rsc); + String actualHash; + try { + actualHash = rsc.computeDigest(Digest.VERSION, md, null); + } catch(IOException e) { + log.warning("Failed digest hash creation for resource", rsc); + continue; + } + System.out.println("####### digest "+rsc.getPath()+": "+digestHash); + System.out.println("####### actual "+rsc.getPath()+": "+actualHash); + if (digestHash == null || actualHash == null) { + log.warning("Something went wrong with digest hashes", digestHash, actualHash); + continue; + } + if (!digestHash.equals(actualHash)) { + log.warning("Digest does not match for resource", rsc); + continue; + } + File from = new File(applicationAppDir, rsc.getPath()); + File to = new File(userAppDir, rsc.getPath()); + if (!from.exists()) { + log.warning("Resource does not exist", rsc); + continue; + } + if (!to.getParentFile().exists()) { + to.getParentFile().mkdirs(); + } + try { + Files.copy(from.toPath(), to.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + log.info("Copying resource file", from, to); + System.out.println("##### Copying file '"+from.toString()+" to "+to.toString()); + try { + rsc.applyAttrs(); + } catch(IOException e2) { + log.error("Could not apply attributes to resource", rsc); + } + } catch(IOException e) { + log.warning("Could not copy resource file", from, to); + continue; + } + } + + return true; + } + + protected static void parseSimpleLocalResources (Config config, String name, String applicationAppDir, List list, boolean executable) + { + String[] rsrcs = config.getMultiValue(name); + if (rsrcs == null) { + return; + } + for (String resourcePath : rsrcs) { + try { + list.add(new Resource(resourcePath, null, new File(applicationAppDir, resourcePath), executable? Resource.EXEC : Resource.NORMAL)); + log.info("##### Adding resource to list", resourcePath); + //System.out.println("##### Adding resource to list"+ resourcePath); + } catch (Exception e) { + log.warning("Invalid resource '" + resourcePath + "'. " + e); + //System.out.println("##### Invalid resource "+ resourcePath); + } + } + } + protected final EnvConfig _envc; protected File _config; protected File _backupConfig; diff --git a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Digest.java b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Digest.java index bc8d140..c654638 100644 --- a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Digest.java +++ b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Digest.java @@ -150,7 +150,7 @@ public class Digest // parse and validate our digest file contents String filename = digestFile(version); StringBuilder data = new StringBuilder(); - File dfile = new File(appdir, filename); + dfile = new File(appdir, filename); Config.ParseOpts opts = Config.createOpts(false); opts.strictComments = strictComments; // bias = toward key: the key is the filename and could conceivably contain = signs, value @@ -213,6 +213,10 @@ public class Digest { return _digests.get(resource.getPath()); } + + public File getFile() { + return dfile; + } /** Used by {@link #createDigest} and {@link Digest}. */ protected static void note (StringBuilder data, String path, String digest) @@ -225,4 +229,5 @@ public class Digest protected static final String FILE_NAME = "digest"; protected static final String FILE_SUFFIX = ".txt"; + protected File dfile = null; } diff --git a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/EnvConfig.java b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/EnvConfig.java index 862c18e..6f99851 100644 --- a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/EnvConfig.java +++ b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/EnvConfig.java @@ -14,8 +14,10 @@ import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.*; +import com.threerings.getdown.util.LaunchUtil; import com.threerings.getdown.util.StringUtil; +import jalview.util.ChannelProperties; import jalview.util.HttpUtils; import com.threerings.getdown.data.Application; @@ -56,10 +58,15 @@ public final class EnvConfig { * configuration source. */ public static EnvConfig create (String[] argv, List notes) { + System.out.println("##### out Starting EnvConfig.create()"); + System.err.println("##### err Starting EnvConfig.create()"); String appDir = null, appDirProv = null; String appId = null, appIdProv = null; String appBase = null, appBaseProv = null; - + applicationFolder = System.getProperty("installer.application_folder"); + installerAppdir = System.getProperty("installer.appdir"); + appName = System.getProperty("channel.app_name"); + // start with bootstrap.properties config, if avaialble try { ResourceBundle bundle = ResourceBundle.getBundle("bootstrap"); @@ -123,7 +130,7 @@ public final class EnvConfig { } } - // finally obtain config from command line arguments + // not quite finally obtain config from command line arguments String argvAppDir = argv.length > 0 ? argv[0] : null; if (!StringUtil.isBlank(argvAppDir)) { if (appDir == null) { @@ -145,6 +152,14 @@ public final class EnvConfig { } } + boolean userAppDir = false; + // platform user appdir addition + if (StringUtil.isBlank(appDir)) { + appDir = getUserAppdir(); + appDirProv = "user default"; + userAppDir = true; + } + int skipArgs = 2; // Look for locator file, pass to Application and remove from appArgs String argvLocatorFilename = argv.length > 2 ? argv[2] : null; @@ -163,24 +178,35 @@ public final class EnvConfig { } notes.add(Note.info("Using appdir from " + appDirProv + ": " + appDir)); + System.out.println(Note.info("##### Using appdir from " + appDirProv + ": " + appDir)); if (appId != null) notes.add(Note.info("Using appid from " + appIdProv + ": " + appId)); - if (appBase != null) notes.add( + if (appBase != null) { + notes.add( Note.info("Using appbase from " + appBaseProv + ": " + appBase)); + System.out.println("##### Using appbase from " + appBaseProv + ": " + appBase); + } // ensure that the appdir refers to a directory that exists File appDirFile = new File(appDir); if (!appDirFile.exists()) { + System.out.println("##### appDir '"+appDir+"' doesn't exist"); // if we have a bootstrap URL then we auto-create the app dir; this enables an // installer to simply place a getdown.jar file somewhere and create an OS shortcut // that runs getdown with an appdir and appbase specified, and have getdown create the // appdir and download the app into it + System.out.println("##### appBase='"+appBase+"'"); if (!StringUtil.isBlank(appBase)) { if (appDirFile.mkdirs()) { notes.add(Note.info("Auto-created app directory '" + appDir + "'")); } else { notes.add(Note.warn("Unable to auto-create app dir: '" + appDir + "'")); } + } else if (userAppDir && Boolean.valueOf(System.getProperty(POPULATE_DEFAULT_APPDIR_PROPERTY))) { + System.out.println("##### Created appDir='"+appDir+"'"); + appBase = System.getProperty(APPLICATION_APPDIR_PROPERTY); + Application.copyApplicationAppDirToUserAppDir(System.getProperty(APPLICATION_APPDIR_PROPERTY), appDir); } else { + System.out.println("##### Invalid appDir='"+appDir+"' and no appBase set"); notes.add(Note.error("Invalid appdir '" + appDir + "': directory does not exist")); return null; } @@ -242,6 +268,42 @@ public final class EnvConfig { this.certs = certs; this.appArgs = appArgs; } + + private static final String getUserAppdir() { + System.out.println("##### Property '" + USE_DEFAULT_APPDIR_PROPERTY + "' is '" + System.getProperty(USE_DEFAULT_APPDIR_PROPERTY) + "'"); + if (!Boolean.valueOf(System.getProperty(USE_DEFAULT_APPDIR_PROPERTY))) { + System.out.println("##### NOT setting default app dir"); + return null; + } + String appdirname = installerAppdir == null || installerAppdir.length() == 0 ? ChannelProperties.FALLBACK_APPNAME : installerAppdir; + String userAppDataPath; + String home = System.getProperty("user.home"); + String appname = StringUtil.isBlank(appName) ? ChannelProperties.FALLBACK_APPNAME : appName; + final String FS = File.separator; + if (LaunchUtil.isMacOS()) { + userAppDataPath = home + FS + "Library" + FS + "Application Support" + FS + "Jalview-Desktop" + FS + appname + FS + "app"; + } else if (LaunchUtil.isWindows()) { + userAppDataPath = home + FS + "AppData" + FS + "Local" + FS + "Jalview-Desktop" + FS + appdirname + FS + "app"; + } else if (LaunchUtil.isLinux()) { + userAppDataPath = home + FS + ".local" + FS + "share" + FS + "jalview-desktop" + FS + appdirname.toLowerCase(Locale.ROOT) + FS + "app"; + } else { + userAppDataPath = home + FS + ".jalview-desktop" + FS + appdirname.toLowerCase(Locale.ROOT) + FS + "app"; + } + System.out.println("##### About to return userAppDataPath value '"+userAppDataPath+"'"); + return userAppDataPath; + } private static final String USER_HOME_KEY = "${user.home}"; + + private static String applicationFolder = null; + + private static String installerAppdir = null; + + private static String appName = null; + + private static final String USE_DEFAULT_APPDIR_PROPERTY = "usedefaultappdir"; + + private static final String APPLICATION_APPDIR_PROPERTY = "applicationappdir"; + + private static final String POPULATE_DEFAULT_APPDIR_PROPERTY= "populatedefaultappdir"; } diff --git a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java index 1faaa28..3b81fbb 100644 --- a/getdown/src/getdown/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java +++ b/getdown/src/getdown/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java @@ -17,6 +17,7 @@ import javax.xml.bind.DatatypeConverter; import java.security.MessageDigest; +import jalview.util.ChannelProperties; import jalview.util.LaunchUtils; import static com.threerings.getdown.Log.log; @@ -273,12 +274,12 @@ public class LaunchUtil protected static String checkJVMPath (String vmhome, boolean windebug) { String vmbase = vmhome + File.separator + "bin" + File.separator; - String appName = System.getProperty("channel.app_name", "Jalview"); + String appName = System.getProperty("channel.app_name", ChannelProperties.FALLBACK_APPNAME); String vmpath = vmbase + appName; if (checkJVMSymlink(vmpath)) { return vmpath; } - vmpath = vmbase + "Jalview"; + vmpath = vmbase + ChannelProperties.FALLBACK_APPNAME; if (checkJVMSymlink(vmpath)) { return vmpath; } diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java b/getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java index ffcb6a1..cf7da8c 100644 --- a/getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java +++ b/getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java @@ -51,12 +51,14 @@ public class ChannelProperties private static final ArrayList iconList; + public static final String FALLBACK_APPNAME = "Jalview"; + static { defaultProps = new Properties(); // these should be kept up to date, but in real life they should never // actually be used anyway. - defaultProps.put("app_name", "Jalview"); + defaultProps.put("app_name", FALLBACK_APPNAME); defaultProps.put("banner", "/default_images/jalview_banner.png"); defaultProps.put("logo.16", "/default_images/jalview_logo-16.png"); defaultProps.put("logo.32", "/default_images/jalview_logo-32.png"); diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java b/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java index 5894fec..f8cc269 100644 --- a/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java +++ b/getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java @@ -230,7 +230,7 @@ public class LaunchUtils // appName and "Jalview" will not point to javaw.exe or java.exe but in // this case that's okay because the taskbar display name problem doesn't // manifest in Windows. See JAL-3820, JAL-4189. - for (String name : new String[] { appName, "Jalview", java, javaExe }) + for (String name : new String[] { appName, ChannelProperties.FALLBACK_APPNAME, java, javaExe }) { if (LaunchUtils.checkJVMSymlink(javaBinDir + name, winConsole)) { diff --git a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java index dbc50db..87ed8d2 100644 --- a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java +++ b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java @@ -116,7 +116,7 @@ public class GetdownApp log.info("-- Java Vers: " + System.getProperty("java.version")); log.info("-- Java Home: " + System.getProperty("java.home")); log.info("-- Install4j Vers: " + Application.i4jVersion); - log.info("-- Install4j Template Vers: " + System.getProperty("installer_template_version")); + log.info("-- Install4j Template Vers: " + System.getProperty("installer.template_version")); log.info("-- User Name: " + System.getProperty("user.name")); log.info("-- User Home: " + System.getProperty("user.home")); log.info("-- Cur dir: " + System.getProperty("user.dir")); diff --git a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/StatusPanel.java b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/StatusPanel.java index a144c83..70da717 100644 --- a/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/StatusPanel.java +++ b/getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/StatusPanel.java @@ -282,7 +282,7 @@ public final class StatusPanel extends JComponent labelText.append("\n"); labelText.append("install4j version: " + Application.i4jVersion); labelText.append("\n"); - labelText.append("installer version: " + System.getProperty("installer_template_version")); + labelText.append("installer version: " + System.getProperty("installer.template_version")); labelText.append("\n"); } if (_ifc.displayAppbase) { diff --git a/j11lib/getdown-core.jar b/j11lib/getdown-core.jar index 8c9e44b..6c20166 100644 Binary files a/j11lib/getdown-core.jar and b/j11lib/getdown-core.jar differ diff --git a/j8lib/getdown-core.jar b/j8lib/getdown-core.jar index 8c9e44b..6c20166 100644 Binary files a/j8lib/getdown-core.jar and b/j8lib/getdown-core.jar differ