1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 const { AddonManager } = ChromeUtils.import(
8 "resource://gre/modules/AddonManager.jsm"
10 const { FileUtils } = ChromeUtils.import(
11 "resource://gre/modules/FileUtils.jsm"
14 const { UnknownError } = ChromeUtils.import(
15 "chrome://marionette/content/error.js"
18 this.EXPORTED_SYMBOLS = ["Addon"];
20 // from https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/AddonManager#AddonInstall_errors
22 [-1]: "ERROR_NETWORK_FAILURE: A network error occured.",
23 [-2]: "ERROR_INCORECT_HASH: The downloaded file did not match the expected hash.",
24 [-3]: "ERROR_CORRUPT_FILE: The file appears to be corrupt.",
25 [-4]: "ERROR_FILE_ACCESS: There was an error accessing the filesystem.",
26 [-5]: "ERROR_SIGNEDSTATE_REQUIRED: The addon must be signed and isn't.",
29 async function installAddon(file) {
30 let install = await AddonManager.getInstallForFile(file, null, {
35 throw new UnknownError(ERRORS[install.error]);
38 return install.install().catch(err => {
39 throw new UnknownError(ERRORS[install.error]);
43 /** Installs addons by path and uninstalls by ID. */
46 * Install a Firefox addon.
48 * If the addon is restartless, it can be used right away. Otherwise a
49 * restart is required.
51 * Temporary addons will automatically be uninstalled on shutdown and
52 * do not need to be signed, though they must be restartless.
54 * @param {string} path
55 * Full path to the extension package archive.
56 * @param {boolean=} temporary
57 * True to install the addon temporarily, false (default) otherwise.
59 * @return {Promise.<string>}
62 * @throws {UnknownError}
63 * If there is a problem installing the addon.
65 static async install(path, temporary = false) {
70 file = new FileUtils.File(path);
72 throw new UnknownError(`Expected absolute path: ${e}`, e);
76 throw new UnknownError(`No such file or directory: ${path}`);
81 addon = await AddonManager.installTemporaryAddon(file);
83 addon = await installAddon(file);
86 throw new UnknownError(
87 `Could not install add-on: ${path}: ${e.message}`,
96 * Uninstall a Firefox addon.
98 * If the addon is restartless it will be uninstalled right away.
99 * Otherwise, Firefox must be restarted for the change to take effect.
102 * ID of the addon to uninstall.
106 * @throws {UnknownError}
107 * If there is a problem uninstalling the addon.
109 static async uninstall(id) {
110 let candidate = await AddonManager.getAddonByID(id);
112 return new Promise(resolve => {
114 onOperationCancelled: addon => {
115 if (addon.id === candidate.id) {
116 AddonManager.removeAddonListener(listener);
117 throw new UnknownError(
118 `Uninstall of ${candidate.id} has been canceled`
123 onUninstalled: addon => {
124 if (addon.id === candidate.id) {
125 AddonManager.removeAddonListener(listener);
131 AddonManager.addAddonListener(listener);
132 candidate.uninstall();