diff --git a/common/content/dactyl.js b/common/content/dactyl.js index 26ec0c30..ebf206d3 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -106,7 +106,22 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { forceNewWindow: false, /** @property {string} The Dactyl version string. */ - version: null, + version: Class.memoize(function () { + if (/pre$/.test(util.addon.version)) { + let uri = util.addon.getResourceURI("../.hg"); + if (uri instanceof Ci.nsIFileURL && + uri.QueryInterface(Ci.nsIFileURL).file.exists() && + io.pathSearch("hg")) { + return io.system(["hg", "-R", uri.file.parent.path, + "log", "-r.", + "--template=hg{rev} ({date|isodate})"]); + } + } + let version = util.addon.version; + if ("@DATE" !== "@" + "DATE@") + version += " (created: @DATE@)" + return version; + }), /** * @property {Object} The map of command-line options. These are @@ -1515,70 +1530,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { /////////////////////////////////////////////////////////////////////////// - if (typeof AddonManager == "undefined") - modules.AddonManager = { - getAddonByID: function (id, callback) { - callback = callback || util.identity; - let addon = id; - if (!isObject(addon)) - addon = services.extensionManager.getItemForID(id); - if (!addon) - return callback(null); - addon = Object.create(addon); - - function getRdfProperty(item, property) { - let resource = services.rdf.GetResource("urn:mozilla:item:" + item.id); - let value = ""; - - if (resource) { - let target = services.extensionManager.datasource.GetTarget(resource, - services.rdf.GetResource("http://www.mozilla.org/2004/em-rdf#" + property), true); - if (target && target instanceof Ci.nsIRDFLiteral) - value = target.Value; - } - - return value; - } - - ["aboutURL", "creator", "description", "developers", - "homepageURL", "iconURL", "installDate", "name", - "optionsURL", "releaseNotesURI", "updateDate", "version"].forEach(function (item) { - addon[item] = getRdfProperty(addon, item); - }); - addon.isActive = getRdfProperty(addon, "isDisabled") != "true"; - - addon.uninstall = function () { - services.extensionManager.uninstallItem(this.id); - }; - addon.appDisabled = false; - addon.__defineGetter__("userDisabled", function () getRdfProperty(addon, "userDisabled") === "true"); - addon.__defineSetter__("userDisabled", function (val) { - services.extensionManager[val ? "disableItem" : "enableItem"](this.id); - }); - - return callback(addon); - }, - getAddonsByTypes: function (types, callback) { - let res = []; - for (let [, type] in Iterator(types)) - for (let [, item] in Iterator(services.extensionManager - .getItemList(Ci.nsIUpdateItem["TYPE_" + type.toUpperCase()], {}))) - res.push(this.getAddonByID(item)); - callback(res); - }, - getInstallForFile: function (file, callback, mimetype) { - callback({ - addListener: function () {}, - install: function () { - services.extensionManager.installItemFromFile(file, "app-profile"); - } - }); - }, - getInstallForURL: function (url, callback, mimetype) { - dactyl.assert(false, "Install by URL not implemented"); - }, - }; - const addonErrors = array.toObject([ [AddonManager.ERROR_NETWORK_FAILURE, "A network error occurred"], [AddonManager.ERROR_INCORRECT_HASH, "The downloaded file did not match the expected hash"], @@ -2140,12 +2091,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { dactyl.log("All modules loaded", 3); - AddonManager.getAddonByID(services["dactyl:"].addonID, this.wrapCallback(function (addon) { - // @DATE@ token replaced by the Makefile - // TODO: Find it automatically - prefs.set("extensions.dactyl.version", addon.version); - dactyl.version = addon.version + " (created: @DATE@)"; - })); + prefs.set("extensions.dactyl.version", util.addon.version); if (!services.commandLineHandler) services.add("commandLineHandler", "@mozilla.org/commandlinehandler/general-startup;1?type=" + config.name); diff --git a/common/content/io.js b/common/content/io.js index 0f923b28..f9da15df 100644 --- a/common/content/io.js +++ b/common/content/io.js @@ -226,6 +226,34 @@ var IO = Module("io", { return ""; }, + pathSearch: function (bin) { + let dirs = services.environment.get("PATH").split(util.OS.isWindows ? ";" : ":"); + // Windows tries the CWD first TODO: desirable? + if (util.OS.isWindows) + dirs = [io.cwd].concat(dirs); + + for (let [, dir] in Iterator(dirs)) + try { + dir = io.File(dir, true); + let file = dir.child(bin); + if (file.exists()) + return file; + + // TODO: couldn't we just palm this off to the start command? + // automatically try to add the executable path extensions on windows + if (util.OS.isWindows) { + let extensions = services.environment.get("PATHEXT").split(";"); + for (let [, extension] in Iterator(extensions)) { + file = dir.child(bin + extension); + if (file.exists()) + return file; + } + } + } + catch (e) {} + return null; + }, + /** * Runs an external program. * @@ -239,33 +267,8 @@ var IO = Module("io", { if (File.isAbsolutePath(program)) file = io.File(program, true); - else { - let dirs = services.environment.get("PATH").split(util.OS.isWindows ? ";" : ":"); - // Windows tries the CWD first TODO: desirable? - if (util.OS.isWindows) - dirs = [io.cwd].concat(dirs); - -lookup: - for (let [, dir] in Iterator(dirs)) { - file = File.joinPaths(dir, program, io.cwd); - try { - if (file.exists()) - break; - - // TODO: couldn't we just palm this off to the start command? - // automatically try to add the executable path extensions on windows - if (util.OS.isWindows) { - let extensions = services.environment.get("PATHEXT").split(";"); - for (let [, extension] in Iterator(extensions)) { - file = File.joinPaths(dir, program + extension, io.cwd); - if (file.exists()) - break lookup; - } - } - } - catch (e) {} - } - } + else + file = io.pathSearch(program); if (!file || !file.exists()) { dactyl.echoerr("Command not found: " + program); @@ -426,6 +429,10 @@ lookup: stdin.write(input); let shell = File.expandPath(options["shell"]); + + if (isArray(command)) + command = command.map(escape).join(" "); + // TODO: implement 'shellredir' if (util.OS.isWindows && !/sh/.test(options["shell"])) { command = "cd /D " + this.cwd + " && " + command + " > " + stdout.path + " 2>&1" + " < " + stdin.path; diff --git a/common/modules/services.jsm b/common/modules/services.jsm index c29ecb95..87db57df 100644 --- a/common/modules/services.jsm +++ b/common/modules/services.jsm @@ -6,9 +6,11 @@ try { +var global = this; Components.utils.import("resource://dactyl/base.jsm"); defineModule("services", { - exports: ["AddonManager", "Services", "services"] + exports: ["AddonManager", "Services", "services"], + use: ["util"] }); /** @@ -76,6 +78,80 @@ var Services = Module("Services", { if (!this.extensionManager) Components.utils.import("resource://gre/modules/AddonManager.jsm"); + else + global.AddonManager = { + getAddonByID: function (id, callback) { + callback = callback || util.identity; + let addon = id; + if (!isObject(addon)) + addon = services.extensionManager.getItemForID(id); + if (!addon) + return callback(null); + addon = Object.create(addon); + + function getRdfProperty(item, property) { + let resource = services.rdf.GetResource("urn:mozilla:item:" + item.id); + let value = ""; + + if (resource) { + let target = services.extensionManager.datasource.GetTarget(resource, + services.rdf.GetResource("http://www.mozilla.org/2004/em-rdf#" + property), true); + if (target && target instanceof Ci.nsIRDFLiteral) + value = target.Value; + } + + return value; + } + + ["aboutURL", "creator", "description", "developers", + "homepageURL", "iconURL", "installDate", + "optionsURL", "releaseNotesURI", "updateDate", "version"].forEach(function (item) { + addon[item] = getRdfProperty(addon, item); + }); + update(addon, { + + appDisabled: false, + + installLocation: Class.memoize(function () services.extensionManager.getInstallLocation(this.id)), + getResourceURI: function getResourceURI(path) { + let file = this.installLocation.getItemFile(this.id, path); + return services.io.newFileURI(file); + }, + + isActive: getRdfProperty(addon, "isDisabled") != "true", + + uninstall: function uninstall() { + services.extensionManager.uninstallItem(this.id); + }, + + get userDisabled() getRdfProperty(addon, "userDisabled") === "true", + set userDisabled(val) { + services.extensionManager[val ? "disableItem" : "enableItem"](this.id); + } + }); + + return callback(addon); + }, + getAddonsByTypes: function (types, callback) { + let res = []; + for (let [, type] in Iterator(types)) + for (let [, item] in Iterator(services.extensionManager + .getItemList(Ci.nsIUpdateItem["TYPE_" + type.toUpperCase()], {}))) + res.push(this.getAddonByID(item)); + callback(res); + }, + getInstallForFile: function (file, callback, mimetype) { + callback({ + addListener: function () {}, + install: function () { + services.extensionManager.installItemFromFile(file, "app-profile"); + } + }); + }, + getInstallForURL: function (url, callback, mimetype) { + dactyl.assert(false, "Install by URL not implemented"); + }, + }; }, reinit: function () {}, diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 156158ee..881acd9a 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -59,7 +59,12 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), } }, - get addon() services.fuel.storage.get("dactyl.bootstrap", null).addon, + addon: Class.memoize(function () { + let addon = services.fuel.storage.get("dactyl.bootstrap", {}).addon; + if (!addon) + addon = AddonManager.getAddonByID(services["dactyl:"].addonID); + return addon; + }), // FIXME: Only works for Pentadactyl get activeWindow() services.windowMediator.getMostRecentWindow("navigator:browser"),