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.*;
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;
// 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
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<Resource> 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<Resource> 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;
// 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
{
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)
protected static final String FILE_NAME = "digest";
protected static final String FILE_SUFFIX = ".txt";
+ protected File dfile = null;
}
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;
* configuration source.
*/
public static EnvConfig create (String[] argv, List<Note> 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");
}
}
- // 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) {
}
}
+ 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;
}
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;
}
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";
}
import java.security.MessageDigest;
+import jalview.util.ChannelProperties;
import jalview.util.LaunchUtils;
import static com.threerings.getdown.Log.log;
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;
}
private static final ArrayList<Image> 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");
// 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))
{
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"));
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) {