Skip to content
Browse files

Merge pull request #270 from erikvold/prefs

fix bug 645207 - implement high-level preferences API
  • Loading branch information...
2 parents b9e53cc + b7a357a commit 5e5abf56321539af169b7d3639da63507e47eb60 @mykmelez mykmelez committed Nov 28, 2011
View
5 doc/dev-guide-source/addon-development/package-spec.md
@@ -48,6 +48,11 @@ called `package.json`. This file is also referred to as the
[`icon64URL` entry in the Install Manifest](https://developer.mozilla.org/en/install_manifests#icon64URL),
so the icon should be 64x64 pixels in size.
+* `preferences` - *experimental*
+ An array of JSON objects that use the following keys `name`, `type`, `value`,
+ `title`, and `description`. These JSON objects will be used to automatically
+ create a preferences interface for the addon in the Add-ons Manager.
+ For more information see the documentation of [simple-prefs](packages/addon-kit/docs/simple-prefs.html).
* `license` - the name of the license as a String, with an optional
URL in parentheses.
View
70 packages/addon-kit/docs/simple-prefs.md
@@ -0,0 +1,70 @@
+<!-- contributed by Erik Vold [erikvvold@gmail.com] -->
+
+#### *Experimental*
+
+The `simple-prefs` module lets you easily and persistently store preferences
+across application restarts, which can be configured by users in the
+Add-ons Manager.
+
+Introduction
+------------
+
+With the simple preferences module you can store booleans, integers, and string
+values.
+
+
+Inline Options & Default Values
+-------------------------------
+
+In order to have a `options.xul` (for inline options) generated, or a
+`defaults/preferences/prefs.js` for default preferences, you will need to
+define the preferences in your `package.json`, like so:
+
+ {
+ "fullName": "Example Add-on",
+ ...
+ "preferences": [{
+ "name": "somePreference",
+ "title": "Some preference title",
+ "type": "string",
+ "value": "this is the default string value"
+ }]
+ }
+
+
+<api name="prefs">
+@property {object}
+ *experimental* A persistent object private to your add-on. Properties with boolean,
+ number, and string values will be persisted in the Mozilla preferences system.
+</api>
+
+
+<api name="on">
+@function
+ *experimental* Registers an event `listener` that will be called when a preference is changed.
+
+**Example:**
+
+ function onPrefChange(prefName) {
+ console.log("The " + prefName + " preference changed.");
+ }
+ require("simple-prefs").on("somePreference", onPrefChange);
+ require("simple-prefs").on("someOtherPreference", onPrefChange);
+
+
+@param prefName {String}
+ The name of the preference to watch for changes.
+@param listener {Function}
+ The listener function that processes the event.
+</api>
+
+<api name="removeListener">
+@function
+ *experimental* Unregisters an event `listener` for the specified preference.
+
+@param prefName {String}
+ The name of the preference to watch for changes.
+@param listener {Function}
+ The listener function that processes the event.
+</api>
+
View
107 packages/addon-kit/lib/simple-prefs.js
@@ -0,0 +1,107 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Jetpack.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Hernan Rodriguez Colmeiro <colmeiro@gmail.com> (Original Author)
+ * Erik Vold <erikvvold@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const { Cc, Ci } = require("chrome");
+const observers = require("observer-service");
+const { EventEmitter } = require("events");
+const unload = require("unload");
+const prefService = require("preferences-service");
+const { jetpackID } = require("@packaging");
+
+const ADDON_BRANCH = "extensions." + jetpackID + ".";
+const BUTTON_PRESSED = jetpackID + "-cmdPressed";
+
+// XXX Currently, only Firefox implements the inline preferences.
+if (!require("xul-app").is("Firefox"))
+ throw Error("This API is only supported in Firefox");
+
+let branch = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefService).
+ getBranch(ADDON_BRANCH).
+ QueryInterface(Ci.nsIPrefBranch2);
+
+const events = EventEmitter.compose({
+ constructor: function Prefs() {
+ // Log unhandled errors.
+ this.on("error", console.exception.bind(console));
+
+ // Make sure we remove all the listeners
+ unload.ensure(this);
+
+ this._prefObserver = this._prefObserver.bind(this);
+ this._buttonObserver = this._buttonObserver.bind(this);
+
+ // Listen to changes in the preferences
+ branch.addObserver("", this._prefObserver, false);
+
+ // Listen to clicks on buttons
+ observers.add(BUTTON_PRESSED, this._buttonObserver, this);
+ },
+ _prefObserver: function PrefsPrefObserver(subject, topic, prefName) {
+ if (topic == "nsPref:changed") {
+ this._emit(prefName, prefName);
+ }
+ },
+ _buttonObserver: function PrefsButtonObserver(subject, data) {
+ this._emit(data);
+ },
+ unload: function manager_unload() {
+ this._removeAllListeners("error");
+ branch.removeObserver("", this._prefObserver);
+ },
+})();
+
+const simple = Proxy.create({
+ get: function(receiver, pref) {
+ return prefService.get(ADDON_BRANCH + pref);
+ },
+ set: function(receiver, pref, val) {
+ prefService.set(ADDON_BRANCH + pref, val);
+ },
+ delete: function(pref) {
+ prefService.reset(ADDON_BRANCH + pref);
+ return true;
+ },
+ has: function(pref) {
+ return prefService.has(ADDON_BRANCH + pref);
+ }
+});
+
+exports.on = events.on;
+exports.removeListener = events.removeListener;
+exports.prefs = simple;
View
180 packages/addon-kit/tests/test-simple-prefs.js
@@ -0,0 +1,180 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Jetpack.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Erik Vold <erikvvold@gmail.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+const { Loader } = require("./helpers");
+const setTimeout = require("timers").setTimeout;
+const notify = require("observer-service").notify;
+const { jetpackID } = require("@packaging");
+
+exports.testSetGetBool = function(test) {
+ test.waitUntilDone();
+
+ let loader = Loader(module);
+ let sp = loader.require("simple-prefs").prefs;
+
+ test.assertEqual(sp.test, undefined, "Value should not exist");
+ sp.test = true;
+ test.assert(sp.test, "Value read should be the value previously set");
+
+ loader.unload();
+ test.done();
+};
+
+exports.testSetGetInt = function(test) {
+ test.waitUntilDone();
+
+ // Load the module once, set a value.
+ let loader = Loader(module);
+ let sp = loader.require("simple-prefs").prefs;
+
+ test.assertEqual(sp["test-int"], undefined, "Value should not exist");
+ sp["test-int"] = 1;
+ test.assertEqual(sp["test-int"], 1, "Value read should be the value previously set");
+
+ loader.unload();
+ test.done();
+};
+
+exports.testSetComplex = function(test) {
+ test.waitUntilDone();
+
+ let loader = Loader(module);
+ let sp = loader.require("simple-prefs").prefs;
+
+ try {
+ sp["test-complex"] = {test: true};
+ test.fail("Complex values are not allowed");
+ }
+ catch (e) {
+ test.pass("Complex values are not allowed");
+ }
+
+ loader.unload();
+ test.done();
+};
+
+exports.testSetGetString = function(test) {
+ test.waitUntilDone();
+
+ let loader = Loader(module);
+ let sp = loader.require("simple-prefs").prefs;
+
+ test.assertEqual(sp["test-string"], undefined, "Value should not exist");
+ sp["test-string"] = "test";
+ test.assertEqual(sp["test-string"], "test", "Value read should be the value previously set");
+
+ loader.unload();
+ test.done();
+};
+
+exports.testHasAndRemove = function(test) {
+ test.waitUntilDone();
+
+ let loader = Loader(module);
+ let sp = loader.require("simple-prefs").prefs;
+
+ sp.test = true;
+ test.assert(("test" in sp), "Value exists");
+ delete sp.test;
+ test.assertEqual(sp.test, undefined, "Value should be undefined");
+
+ loader.unload();
+ test.done();
+
+};
+
+exports.testPrefListener = function(test) {
+ test.waitUntilDone();
+
+ let loader = Loader(module);
+ let sp = loader.require("simple-prefs");
+
+ let listener = function(prefName) {
+ test.assertEqual(prefName, "test-listen", "The prefs listener heard the right event");
+ test.done();
+ };
+
+ sp.on("test-listen", listener);
+
+ sp.prefs["test-listen"] = true;
+ loader.unload();
+};
+
+exports.testBtnListener = function(test) {
+ test.waitUntilDone();
+
+ let loader = Loader(module);
+ let sp = loader.require("simple-prefs");
+
+ sp.on("test-btn-listen", function() {
+ test.pass("Button press event was heard");
+ test.done();
+ });
+ notify((jetpackID + "-cmdPressed"), "", "test-btn-listen");
+
+ loader.unload();
+};
+
+exports.testPrefRemoveListener = function(test) {
+ test.waitUntilDone();
+
+ let loader = Loader(module);
+ let sp = loader.require("simple-prefs");
+ let counter = 0;
+
+ let listener = function() {
+ test.pass("The prefs listener was not removed yet");
+
+ if (++counter > 1)
+ test.fail("The prefs listener was not removed");
+
+ sp.removeListener("test-listen2", listener);
+
+ sp.prefs["test-listen2"] = false;
+
+ setTimeout(function() {
+ test.pass("The prefs listener was removed");
+ loader.unload();
+ test.done();
+ }, 250);
+ };
+
+ sp.on("test-listen2", listener);
+
+ sp.prefs["test-listen2"] = true;
+};
View
4 python-lib/cuddlefish/__init__.py
@@ -728,6 +728,10 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
mydir = os.path.dirname(os.path.abspath(__file__))
app_extension_dir = os.path.join(mydir, "app-extension")
+
+ if target_cfg.get('preferences'):
+ harness_options['preferences'] = target_cfg.get('preferences')
+
harness_options['manifest'] = manifest.get_harness_options_manifest(uri_prefix)
harness_options['allTestModules'] = manifest.get_all_test_modules()
View
63 python-lib/cuddlefish/app-extension/bootstrap.js
@@ -21,6 +21,7 @@
* Contributor(s):
* Irakli Gozalishvili <gozala@mozilla.com> (Original Author)
* Matteo Ferretti <zer0@mozilla.com>
+ * Erik Vold <erikvvold@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -48,12 +49,50 @@ const resourceHandler = ioService.getProtocolHandler('resource')
.QueryInterface(Ci.nsIResProtocolHandler);
const XMLHttpRequest = CC('@mozilla.org/xmlextras/xmlhttprequest;1',
'nsIXMLHttpRequest');
+const prefs = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefService).
+ QueryInterface(Ci.nsIPrefBranch2);
+const mozIJSSubScriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
+ getService(Ci.mozIJSSubScriptLoader);
const REASON = [ 'unknown', 'startup', 'shutdown', 'enable', 'disable',
'install', 'uninstall', 'upgrade', 'downgrade' ];
let loader = null;
+const URI = __SCRIPT_URI_SPEC__.replace(/bootstrap\.js$/, "");
+
+// Initializes default preferences
+function setDefaultPrefs() {
+ let branch = prefs.getDefaultBranch("");
+ let prefLoaderScope = {
+ pref: function(key, val) {
+ switch (typeof val) {
+ case "boolean":
+ branch.setBoolPref(key, val);
+ break;
+ case "number":
+ if (value % 1 == 0) // number must be a integer, otherwise ignore it
+ branch.setIntPref(key, val);
+ break;
+ case "string":
+ branch.setCharPref(key, val);
+ break;
+ }
+ }
+ };
+
+ let uri = ioService.newURI(
+ "defaults/preferences/prefs.js",
+ null,
+ ioService.newURI(URI, null, null));
+
+ // if there is a prefs.js file, then import the default prefs
+ if (uri.QueryInterface(Ci.nsIFileURL).file.exists()) {
+ // setup default prefs
+ mozIJSSubScriptLoader.loadSubScript(uri.spec, prefLoaderScope);
+ }
+}
// Gets the topic that fit best as application startup event, in according with
// the current application (e.g. Firefox, Fennec, Thunderbird...)
@@ -94,17 +133,6 @@ function readURI(uri) {
return request.responseText;
}
-// Shim function to get `resourceURI` in pre Gecko 7.0.
-// https://developer.mozilla.org/en/Extensions/Bootstrapped_extensions#Bootstrap_data
-function resourceURI(file) {
- // First creating "file:" URI.
- let uri = ioService.newFileURI(file);
- if (uri.spec.substr(-4) === '.xpi') // `unpack` is `false`
- uri = ioService.newURI('jar:' + uri.spec + '!/', null, null);
-
- return uri;
-}
-
// Function takes `topic` to be observer via `nsIObserverService` and returns
// promise that will be delivered once notification is published.
function on(topic) {
@@ -126,10 +154,10 @@ function on(topic) {
* handler with an associated key. Each path is resolved relative to the given
* `root` path.
*/
-function mapResources(root, resources) {
+function mapResources(resources) {
Object.keys(resources).forEach(function(id) {
let path = resources[id];
- let uri = Array.isArray(path) ? root + '/' + path.join('/')
+ let uri = Array.isArray(path) ? URI + '/' + path.join('/')
: 'file://' + path;
uri = ioService.newURI(uri + '/', null, null);
resourceHandler.setSubstitution(id, uri);
@@ -142,16 +170,19 @@ function install(data, reason) {}
function uninstall(data, reason) {}
function startup(data, reason) {
- let uri = (data.resourceURI || resourceURI(data.installPath)).spec;
+ // TODO: When bug 564675 is implemented this will no longer be needed
+ // Always set the default prefs, because they disappear on restart
+ setDefaultPrefs();
+
// TODO: Maybe we should perform read harness-options.json asynchronously,
// since we can't do anything until 'sessionstore-windows-restored' anyway.
- let options = JSON.parse(readURI(uri + './harness-options.json'));
+ let options = JSON.parse(readURI(URI + './harness-options.json'));
options.loadReason = REASON[reason];
// TODO: This is unnecessary overhead per add-on instance. Manifest should
// probably contain paths relative to add-on root to avoid this, but that
// requires simpler package layout that is being worked under the bug-660629.
- mapResources(uri, options.resources);
+ mapResources(options.resources);
// Import loader module using `Cu.imports` and bootstrap module loader.
loader = Cu.import(options.loader).Loader.new(options);
View
2 python-lib/cuddlefish/app-extension/install.rdf
@@ -25,7 +25,7 @@
<em:iconURL></em:iconURL>
<em:icon64URL></em:icon64URL>
<em:homepageURL></em:homepageURL>
- <em:optionsURL></em:optionsURL>
+ <em:optionsType></em:optionsType>
<em:updateURL></em:updateURL>
</Description>
</RDF>
View
22 python-lib/cuddlefish/options_defaults.py
@@ -0,0 +1,22 @@
+def parse_options_defaults(options, jetpack_id):
+ pref_list = []
+
+ for pref in options:
+ if ('value' in pref):
+ value = pref["value"]
+ vtype = str(type(value))
+
+ if ("<type 'float'>" == vtype):
+ continue
+ elif ("<type 'bool'>" == vtype):
+ value = str(pref["value"]).lower()
+ elif ("<type 'str'>" == vtype):
+ value = "\"" + str(pref["value"]) + "\""
+ elif ("<type 'unicode'>" == vtype):
+ value = "\"" + str(pref["value"]) + "\""
+ else:
+ value = str(pref["value"])
+
+ pref_list.append("pref(\"extensions." + jetpack_id + "." + pref["name"] + "\", " + value + ");")
+
+ return "\n".join(pref_list) + "\n"
View
60 python-lib/cuddlefish/options_xul.py
@@ -0,0 +1,60 @@
+from xml.dom.minidom import Document
+
+VALID_PREF_TYPES = ['bool', 'boolint', 'integer', 'string', 'color', 'file',
+ 'directory', 'control']
+
+class Error(Exception):
+ pass
+
+class BadPrefTypeError(Error):
+ pass
+
+class MissingPrefAttr(Error):
+ pass
+
+def validate_prefs(options):
+ for pref in options:
+ # Make sure there is a 'title'
+ if ("title" not in pref):
+ raise MissingPrefAttr("The '%s' pref requires a 'title'" % (pref["name"]))
+
+ # Make sure that the pref type is a valid inline pref type
+ if (pref["type"] not in VALID_PREF_TYPES):
+ raise BadPrefTypeError('%s is not a valid inline pref type' % (pref["type"]))
+
+ # Make sure the 'control' type has a 'label'
+ if (pref["type"] == "control"):
+ if ("label" not in pref):
+ raise MissingPrefAttr("The 'control' inline pref type requires a 'label'")
+
+ # TODO: Check that pref["type"] matches default value type
+
+def parse_options(options, jetpack_id):
+ doc = Document()
+ root = doc.createElement("vbox")
+ root.setAttribute("xmlns", "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")
+ doc.appendChild(root)
+
+ for pref in options:
+ setting = doc.createElement("setting")
+ setting.setAttribute("pref", "extensions." + jetpack_id + "." + pref["name"])
+ setting.setAttribute("type", pref["type"])
+ setting.setAttribute("title", pref["title"])
+
+ if ("description" in pref):
+ setting.appendChild(doc.createTextNode(pref["description"]))
+
+ if (pref["type"] == "control"):
+ button = doc.createElement("button")
+ button.setAttribute("label", pref["label"])
+ button.setAttribute("oncommand", "Services.obs.notifyObservers(null, '" +
+ jetpack_id + "-cmdPressed', '" +
+ pref["name"] + "');");
+ setting.appendChild(button)
+ elif (pref["type"] == "boolint"):
+ setting.setAttribute("on", pref["on"])
+ setting.setAttribute("off", pref["off"])
+
+ root.appendChild(setting)
+
+ return doc.toprettyxml(indent=" ")
View
7 python-lib/cuddlefish/packaging.py
@@ -318,6 +318,7 @@ def add_dep_to_build(dep):
dep_cfg.loader)
target_cfg = pkg_cfg.packages[target]
+
if include_tests and not include_dep_tests:
add_section_to_build(target_cfg, "tests", is_code=True)
@@ -335,6 +336,12 @@ def add_dep_to_build(dep):
build['icon64'] = os.path.join(target_cfg.root_dir, target_cfg.icon64)
del target_cfg['icon64']
+ if ('preferences' in target_cfg):
+ build['preferences'] = target_cfg.preferences
+
+ if ('id' in target_cfg):
+ build['jetpackID'] = target_cfg.id
+
return build
def _get_files_in_dir(path):
View
6 python-lib/cuddlefish/rdf.py
@@ -124,11 +124,17 @@ def gen_manifest(template_root_dir, target_cfg, bundle_id,
target_cfg.get("author", ""))
manifest.set("em:bootstrap", str(bootstrap).lower())
manifest.set("em:unpack", "true")
+
if update_url:
manifest.set("em:updateURL", update_url)
else:
manifest.remove("em:updateURL")
+ if target_cfg.get("preferences"):
+ manifest.set("em:optionsType", "2")
+ else:
+ manifest.remove("em:optionsType")
+
if enable_mobile:
dom = manifest.dom
target_app = dom.createElement("em:targetApplication")
View
0 python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/lib/main.js
No changes.
View
3 python-lib/cuddlefish/tests/preferences-files/packages/no-prefs/package.json
@@ -0,0 +1,3 @@
+{
+ "loader": "lib/main.js"
+}
View
0 python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/lib/main.js
No changes.
View
11 python-lib/cuddlefish/tests/preferences-files/packages/simple-prefs/package.json
@@ -0,0 +1,11 @@
+{
+ "id": "jid1-fZHqN9JfrDBa8A",
+ "fullName": "Simple Prefs Test",
+ "author": "Erik Vold",
+ "preferences": [{
+ "name": "test",
+ "type": "bool",
+ "title": "test"
+ }],
+ "loader": "lib/main.js"
+}
View
31 python-lib/cuddlefish/tests/test_xpi.py
@@ -14,6 +14,35 @@
fake_manifest = '<RDF><!-- Extension metadata is here. --></RDF>'
+class PrefsTests(unittest.TestCase):
+ def makexpi(self, pkg_name):
+ self.xpiname = "%s.xpi" % pkg_name
+ create_xpi(self.xpiname, pkg_name, 'preferences-files')
+ self.xpi = zipfile.ZipFile(self.xpiname, 'r')
+ options = self.xpi.read('harness-options.json')
+ self.xpi_harness_options = json.loads(options)
+
+ def setUp(self):
+ self.xpiname = None
+ self.xpi = None
+
+ def tearDown(self):
+ if self.xpi:
+ self.xpi.close()
+ if self.xpiname and os.path.exists(self.xpiname):
+ os.remove(self.xpiname)
+
+ def testPackageWithSimplePrefs(self):
+ self.makexpi('simple-prefs')
+ assert 'options.xul' in self.xpi.namelist()
+ assert 'defaults/preferences/prefs.js' in self.xpi.namelist()
+
+ def testPackageWithNoPrefs(self):
+ self.makexpi('no-prefs')
+ assert 'options.xul' not in self.xpi.namelist()
+ assert 'defaults/preferences/prefs.js' not in self.xpi.namelist()
+
+
class Bug588119Tests(unittest.TestCase):
def makexpi(self, pkg_name):
self.xpiname = "%s.xpi" % pkg_name
@@ -25,7 +54,7 @@ def makexpi(self, pkg_name):
def setUp(self):
self.xpiname = None
self.xpi = None
-
+
def tearDown(self):
if self.xpi:
self.xpi.close()
View
15 python-lib/cuddlefish/xpi.py
@@ -33,6 +33,21 @@ def build_xpi(template_root_dir, manifest, xpi_path,
zf.write(str(harness_options['icon64']), 'icon64.png')
del harness_options['icon64']
+ if 'preferences' in harness_options:
+ from options_xul import parse_options, validate_prefs
+
+ validate_prefs(harness_options["preferences"])
+
+ open('.options.xul', 'w').write(parse_options(harness_options["preferences"], harness_options["jetpackID"]))
+ zf.write('.options.xul', 'options.xul')
+ os.remove('.options.xul')
+
+ from options_defaults import parse_options_defaults
+ open('.prefs.js', 'w').write(parse_options_defaults(harness_options["preferences"], harness_options["jetpackID"]))
+ zf.write('.prefs.js', 'defaults/preferences/prefs.js')
+ os.remove('.prefs.js')
+
+
IGNORED_FILES = [".hgignore", ".DS_Store", "install.rdf",
"application.ini", xpi_path]

0 comments on commit 5e5abf5

Please sign in to comment.
Something went wrong with that request. Please try again.