Added support for marking resources as executable.
This commit is contained in:
@@ -269,7 +269,7 @@ public class Application
|
||||
public Resource getConfigResource ()
|
||||
{
|
||||
try {
|
||||
return createResource(CONFIG_FILE, false);
|
||||
return createResource(CONFIG_FILE, Resource.NORMAL);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Invalid appbase '" + _vappbase + "'.", e);
|
||||
}
|
||||
@@ -395,7 +395,7 @@ public class Application
|
||||
String pfile = "patch" + infix + _version + ".dat";
|
||||
try {
|
||||
URL remote = new URL(createVAppBase(_targetVersion), encodePath(pfile));
|
||||
return new Resource(pfile, remote, getLocalPath(pfile), false);
|
||||
return new Resource(pfile, remote, getLocalPath(pfile), Resource.NORMAL);
|
||||
} catch (Exception e) {
|
||||
log.warning("Failed to create patch resource path",
|
||||
"pfile", pfile, "appbase", _appbase, "tvers", _targetVersion, "error", e);
|
||||
@@ -417,7 +417,8 @@ public class Application
|
||||
String vmfile = LaunchUtil.LOCAL_JAVA_DIR + ".jar";
|
||||
try {
|
||||
URL remote = new URL(createVAppBase(_targetVersion), encodePath(_javaLocation));
|
||||
return new Resource(vmfile, remote, getLocalPath(vmfile), true);
|
||||
return new Resource(vmfile, remote, getLocalPath(vmfile),
|
||||
EnumSet.of(Resource.Attr.UNPACK));
|
||||
} catch (Exception e) {
|
||||
log.warning("Failed to create VM resource", "vmfile", vmfile, "appbase", _appbase,
|
||||
"tvers", _targetVersion, "javaloc", _javaLocation, "error", e);
|
||||
@@ -434,7 +435,7 @@ public class Application
|
||||
String file = "full";
|
||||
try {
|
||||
URL remote = new URL(createVAppBase(_targetVersion), encodePath(file));
|
||||
return new Resource(file, remote, getLocalPath(file), false);
|
||||
return new Resource(file, remote, getLocalPath(file), Resource.NORMAL);
|
||||
} catch (Exception e) {
|
||||
log.warning("Failed to create full resource path",
|
||||
"file", file, "appbase", _appbase, "tvers", _targetVersion, "error", e);
|
||||
@@ -656,21 +657,22 @@ public class Application
|
||||
ConfigUtil.getMultiValue(cdata, "ucode") == null) {
|
||||
throw new IOException("m.missing_code");
|
||||
}
|
||||
parseResources(cdata, "code", false, _codes);
|
||||
parseResources(cdata, "ucode", true, _codes);
|
||||
parseResources(cdata, "code", Resource.NORMAL, _codes);
|
||||
parseResources(cdata, "ucode", Resource.UNPACK, _codes);
|
||||
|
||||
// parse our non-code resources
|
||||
parseResources(cdata, "resource", false, _resources);
|
||||
parseResources(cdata, "uresource", true, _resources);
|
||||
parseResources(cdata, "resource", Resource.NORMAL, _resources);
|
||||
parseResources(cdata, "uresource", Resource.UNPACK, _resources);
|
||||
parseResources(cdata, "xresource", Resource.EXEC, _resources);
|
||||
|
||||
// parse our auxiliary resource groups
|
||||
for (String auxgroup : parseList(cdata, "auxgroups")) {
|
||||
ArrayList<Resource> codes = new ArrayList<>();
|
||||
parseResources(cdata, auxgroup + ".code", false, codes);
|
||||
parseResources(cdata, auxgroup + ".ucode", true, codes);
|
||||
parseResources(cdata, auxgroup + ".code", Resource.NORMAL, codes);
|
||||
parseResources(cdata, auxgroup + ".ucode", Resource.UNPACK, codes);
|
||||
ArrayList<Resource> rsrcs = new ArrayList<>();
|
||||
parseResources(cdata, auxgroup + ".resource", false, rsrcs);
|
||||
parseResources(cdata, auxgroup + ".uresource", true, rsrcs);
|
||||
parseResources(cdata, auxgroup + ".resource", Resource.NORMAL, rsrcs);
|
||||
parseResources(cdata, auxgroup + ".uresource", Resource.UNPACK, rsrcs);
|
||||
_auxgroups.put(auxgroup, new AuxGroup(auxgroup, codes, rsrcs));
|
||||
}
|
||||
|
||||
@@ -1375,8 +1377,7 @@ public class Application
|
||||
toInstall.add(rsrc);
|
||||
return;
|
||||
}
|
||||
// unpack this resource if appropriate
|
||||
rsrc.unpackIfNeeded();
|
||||
rsrc.applyAttrs();
|
||||
unpacked.add(rsrc);
|
||||
rsrc.markAsValid();
|
||||
return;
|
||||
@@ -1672,15 +1673,15 @@ public class Application
|
||||
}
|
||||
|
||||
/** Helper function for creating {@link Resource} instances. */
|
||||
protected Resource createResource (String path, boolean unpack)
|
||||
protected Resource createResource (String path, EnumSet<Resource.Attr> attrs)
|
||||
throws MalformedURLException
|
||||
{
|
||||
return new Resource(path, getRemoteURL(path), getLocalPath(path), unpack);
|
||||
return new Resource(path, getRemoteURL(path), getLocalPath(path), attrs);
|
||||
}
|
||||
|
||||
/** Used to parse resources with the specified name. */
|
||||
protected void parseResources (Map<String,Object> cdata, String name, boolean unpack,
|
||||
List<Resource> list)
|
||||
protected void parseResources (Map<String,Object> cdata, String name,
|
||||
EnumSet<Resource.Attr> attrs, List<Resource> list)
|
||||
{
|
||||
String[] rsrcs = ConfigUtil.getMultiValue(cdata, name);
|
||||
if (rsrcs == null) {
|
||||
@@ -1688,7 +1689,7 @@ public class Application
|
||||
}
|
||||
for (String rsrc : rsrcs) {
|
||||
try {
|
||||
list.add(createResource(rsrc, unpack));
|
||||
list.add(createResource(rsrc, attrs));
|
||||
} catch (Exception e) {
|
||||
log.warning("Invalid resource '" + rsrc + "'. " + e);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.net.URL;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
@@ -27,6 +28,18 @@ import static com.threerings.getdown.Log.log;
|
||||
*/
|
||||
public class Resource implements Comparable<Resource>
|
||||
{
|
||||
/** Defines special attributes for resources. */
|
||||
public static enum Attr {
|
||||
/** Indicates that the resource should be unpacked. */
|
||||
UNPACK,
|
||||
/** Indicates that the resource should be marked executable. */
|
||||
EXEC
|
||||
};
|
||||
|
||||
public static EnumSet<Attr> NORMAL = EnumSet.noneOf(Attr.class);
|
||||
public static EnumSet<Attr> UNPACK = EnumSet.of(Attr.UNPACK);
|
||||
public static EnumSet<Attr> EXEC = EnumSet.of(Attr.EXEC);
|
||||
|
||||
/**
|
||||
* Computes the MD5 hash of the supplied file.
|
||||
* @param version the version of the digest protocol to use.
|
||||
@@ -115,7 +128,7 @@ public class Resource implements Comparable<Resource>
|
||||
/**
|
||||
* Creates a resource with the supplied remote URL and local path.
|
||||
*/
|
||||
public Resource (String path, URL remote, File local, boolean unpack)
|
||||
public Resource (String path, URL remote, File local, EnumSet<Attr> attrs)
|
||||
{
|
||||
_path = path;
|
||||
_remote = remote;
|
||||
@@ -124,12 +137,13 @@ public class Resource implements Comparable<Resource>
|
||||
String lpath = _local.getPath();
|
||||
_marker = new File(lpath + "v");
|
||||
|
||||
_unpack = unpack;
|
||||
_attrs = attrs;
|
||||
_isJar = isJar(lpath);
|
||||
_isPacked200Jar = isPacked200Jar(lpath);
|
||||
if (_unpack && _isJar) {
|
||||
boolean unpack = attrs.contains(Attr.UNPACK);
|
||||
if (unpack && _isJar) {
|
||||
_unpacked = _local.getParentFile();
|
||||
} else if(_unpack && _isPacked200Jar) {
|
||||
} else if(unpack && _isPacked200Jar) {
|
||||
String dotJar = ".jar", lname = _local.getName();
|
||||
String uname = lname.substring(0, lname.lastIndexOf(dotJar) + dotJar.length());
|
||||
_unpacked = new File(_local.getParent(), uname);
|
||||
@@ -189,7 +203,7 @@ public class Resource implements Comparable<Resource>
|
||||
*/
|
||||
public boolean shouldUnpack ()
|
||||
{
|
||||
return _unpack && !SysProps.noUnpack();
|
||||
return _attrs.contains(Attr.UNPACK) && !SysProps.noUnpack();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,8 +268,7 @@ public class Resource implements Comparable<Resource>
|
||||
if (!FileUtil.renameTo(source, dest)) {
|
||||
throw new IOException("Failed to rename " + source + " to " + dest);
|
||||
}
|
||||
// unpack the resource, now that it's installed, and mark it as valid
|
||||
unpackIfNeeded();
|
||||
applyAttrs();
|
||||
markAsValid();
|
||||
}
|
||||
|
||||
@@ -276,12 +289,16 @@ public class Resource implements Comparable<Resource>
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks this resource if needed.
|
||||
* Applies this resources special attributes: unpacks this resource if needed, marks it as
|
||||
* executable if needed.
|
||||
*/
|
||||
public void unpackIfNeeded () throws IOException {
|
||||
public void applyAttrs () throws IOException {
|
||||
if (shouldUnpack()) {
|
||||
unpack();
|
||||
}
|
||||
if (_attrs.contains(Attr.EXEC)) {
|
||||
FileUtil.makeExecutable(_local);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -341,7 +358,8 @@ public class Resource implements Comparable<Resource>
|
||||
protected String _path;
|
||||
protected URL _remote;
|
||||
protected File _local, _localNew, _marker, _unpacked;
|
||||
protected boolean _unpack, _isJar, _isPacked200Jar;
|
||||
protected EnumSet<Attr> _attrs;
|
||||
protected boolean _isJar, _isPacked200Jar;
|
||||
|
||||
/** Used to sort the entries in a jar file. */
|
||||
protected static final Comparator<JarEntry> ENTRY_COMP = new Comparator<JarEntry>() {
|
||||
|
||||
@@ -633,9 +633,9 @@ public abstract class Getdown extends Thread
|
||||
|
||||
// these only run on non-Windows platforms, so we use Unix file separators
|
||||
String localJavaDir = LaunchUtil.LOCAL_JAVA_DIR + "/";
|
||||
makeExecutable(localJavaDir + "bin/java");
|
||||
makeExecutable(localJavaDir + "lib/jspawnhelper");
|
||||
makeExecutable(localJavaDir + "lib/amd64/jspawnhelper");
|
||||
FileUtil.makeExecutable(_app.getLocalPath(localJavaDir + "bin/java"));
|
||||
FileUtil.makeExecutable(_app.getLocalPath(localJavaDir + "lib/jspawnhelper"));
|
||||
FileUtil.makeExecutable(_app.getLocalPath(localJavaDir + "lib/amd64/jspawnhelper"));
|
||||
|
||||
// lastly regenerate the .jsa dump file that helps Java to start up faster
|
||||
String vmpath = LaunchUtil.getJVMPath(_app.getLocalPath(""));
|
||||
@@ -649,23 +649,6 @@ public abstract class Getdown extends Thread
|
||||
reportTrackingEvent("jvm_complete", -1);
|
||||
}
|
||||
|
||||
protected void makeExecutable (String path) {
|
||||
// Java doesn't know anything about file permissions (and by extension then,
|
||||
// neither does Jar), so on Unix we have to hackily do so via chmod
|
||||
if (!RunAnywhere.isWindows()) {
|
||||
File target = _app.getLocalPath(path);
|
||||
String cmd = "chmod a+rx " + target;
|
||||
try {
|
||||
if (target.exists()) {
|
||||
log.info("Running: " + cmd);
|
||||
Runtime.getRuntime().exec(cmd);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warning("Failed to mark VM binary as executable", "cmd", cmd, "error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called if the application is determined to be of an old version.
|
||||
*/
|
||||
|
||||
@@ -169,7 +169,7 @@ public class GetdownApp
|
||||
if (icons.isEmpty()) {
|
||||
log.warning("Failed to load any icons", "iconImages", _ifc.iconImages);
|
||||
} else {
|
||||
SwingUtil.setFrameIcons(_frame, icons);
|
||||
_frame.setIconImages(icons);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -206,6 +206,21 @@ public class FileUtil
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks {@code file} as executable, if it exists. Catches and logs any errors that occur.
|
||||
*/
|
||||
public static void makeExecutable (File file) {
|
||||
try {
|
||||
if (file.exists()) {
|
||||
if (!file.setExecutable(true, false)) {
|
||||
log.warning("Failed to mark as executable", "file", file);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warning("Failed to mark as executable", "file", file, "error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by {@link #walkTree}.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user