Backed out 2 changesets (bug 1855992) for causing talos failures @ mozilla::net:...
[gecko.git] / remote / marionette / addon.sys.mjs
blob6dabcc19e32b1ce7558584a5777c3c984047e28b
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/. */
5 const lazy = {};
7 ChromeUtils.defineESModuleGetters(lazy, {
8   AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
9   FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
10   error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
11 });
13 // from https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/AddonManager#AddonInstall_errors
14 const ERRORS = {
15   [-1]: "ERROR_NETWORK_FAILURE: A network error occured.",
16   [-2]: "ERROR_INCORRECT_HASH: The downloaded file did not match the expected hash.",
17   [-3]: "ERROR_CORRUPT_FILE: The file appears to be corrupt.",
18   [-4]: "ERROR_FILE_ACCESS: There was an error accessing the filesystem.",
19   [-5]: "ERROR_SIGNEDSTATE_REQUIRED: The addon must be signed and isn't.",
20   [-6]: "ERROR_UNEXPECTED_ADDON_TYPE: The downloaded add-on had a different type than expected (during an update).",
21   [-7]: "ERROR_INCORRECT_ID: The addon did not have the expected ID (during an update).",
22   [-8]: "ERROR_INVALID_DOMAIN: The addon install_origins does not list the 3rd party domain.",
23   [-9]: "ERROR_UNEXPECTED_ADDON_VERSION: The downloaded add-on had a different version than expected (during an update).",
24   [-10]: "ERROR_BLOCKLISTED: The add-on is blocklisted.",
25   [-11]:
26     "ERROR_INCOMPATIBLE: The add-on is incompatible (w.r.t. the compatibility range).",
29 async function installAddon(file) {
30   let install = await lazy.AddonManager.getInstallForFile(file, null, {
31     source: "internal",
32   });
34   if (install.error) {
35     throw new lazy.error.UnknownError(ERRORS[install.error]);
36   }
38   return install.install().catch(err => {
39     throw new lazy.error.UnknownError(ERRORS[install.error]);
40   });
43 /** Installs addons by path and uninstalls by ID. */
44 export class Addon {
45   /**
46    * Install a Firefox addon.
47    *
48    * If the addon is restartless, it can be used right away.  Otherwise a
49    * restart is required.
50    *
51    * Temporary addons will automatically be uninstalled on shutdown and
52    * do not need to be signed, though they must be restartless.
53    *
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.
58    *
59    * @returns {Promise.<string>}
60    *     Addon ID.
61    *
62    * @throws {UnknownError}
63    *     If there is a problem installing the addon.
64    */
65   static async install(path, temporary = false) {
66     let addon;
67     let file;
69     try {
70       file = new lazy.FileUtils.File(path);
71     } catch (e) {
72       throw new lazy.error.UnknownError(`Expected absolute path: ${e}`, e);
73     }
75     if (!file.exists()) {
76       throw new lazy.error.UnknownError(`No such file or directory: ${path}`);
77     }
79     try {
80       if (temporary) {
81         addon = await lazy.AddonManager.installTemporaryAddon(file);
82       } else {
83         addon = await installAddon(file);
84       }
85     } catch (e) {
86       throw new lazy.error.UnknownError(
87         `Could not install add-on: ${path}: ${e.message}`,
88         e
89       );
90     }
92     return addon.id;
93   }
95   /**
96    * Uninstall a Firefox addon.
97    *
98    * If the addon is restartless it will be uninstalled right away.
99    * Otherwise, Firefox must be restarted for the change to take effect.
100    *
101    * @param {string} id
102    *     ID of the addon to uninstall.
103    *
104    * @returns {Promise}
105    *
106    * @throws {UnknownError}
107    *     If there is a problem uninstalling the addon.
108    */
109   static async uninstall(id) {
110     let candidate = await lazy.AddonManager.getAddonByID(id);
111     if (candidate === null) {
112       // `AddonManager.getAddonByID` never rejects but instead
113       // returns `null` if the requested addon cannot be found.
114       throw new lazy.error.UnknownError(`Addon ${id} is not installed`);
115     }
117     return new Promise(resolve => {
118       let listener = {
119         onOperationCancelled: addon => {
120           if (addon.id === candidate.id) {
121             lazy.AddonManager.removeAddonListener(listener);
122             throw new lazy.error.UnknownError(
123               `Uninstall of ${candidate.id} has been canceled`
124             );
125           }
126         },
128         onUninstalled: addon => {
129           if (addon.id === candidate.id) {
130             lazy.AddonManager.removeAddonListener(listener);
131             resolve();
132           }
133         },
134       };
136       lazy.AddonManager.addAddonListener(listener);
137       candidate.uninstall();
138     });
139   }