Bug 1776444 [wpt PR 34582] - Revert "Add TimedHTMLParserBudget to fieldtrial_testing_...
[gecko.git] / remote / marionette / addon.js
blobff6f8b8db53a3f77e31233e2555ea5ee84ee8d68
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 "use strict";
7 const EXPORTED_SYMBOLS = ["Addon"];
9 const { XPCOMUtils } = ChromeUtils.import(
10   "resource://gre/modules/XPCOMUtils.jsm"
13 const lazy = {};
15 XPCOMUtils.defineLazyModuleGetters(lazy, {
16   AddonManager: "resource://gre/modules/AddonManager.jsm",
17   FileUtils: "resource://gre/modules/FileUtils.jsm",
19   error: "chrome://remote/content/shared/webdriver/Errors.jsm",
20 });
22 // from https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/AddonManager#AddonInstall_errors
23 const ERRORS = {
24   [-1]: "ERROR_NETWORK_FAILURE: A network error occured.",
25   [-2]: "ERROR_INCORECT_HASH: The downloaded file did not match the expected hash.",
26   [-3]: "ERROR_CORRUPT_FILE: The file appears to be corrupt.",
27   [-4]: "ERROR_FILE_ACCESS: There was an error accessing the filesystem.",
28   [-5]: "ERROR_SIGNEDSTATE_REQUIRED: The addon must be signed and isn't.",
31 async function installAddon(file) {
32   let install = await lazy.AddonManager.getInstallForFile(file, null, {
33     source: "internal",
34   });
36   if (install.error) {
37     throw new lazy.error.UnknownError(ERRORS[install.error]);
38   }
40   return install.install().catch(err => {
41     throw new lazy.error.UnknownError(ERRORS[install.error]);
42   });
45 /** Installs addons by path and uninstalls by ID. */
46 class Addon {
47   /**
48    * Install a Firefox addon.
49    *
50    * If the addon is restartless, it can be used right away.  Otherwise a
51    * restart is required.
52    *
53    * Temporary addons will automatically be uninstalled on shutdown and
54    * do not need to be signed, though they must be restartless.
55    *
56    * @param {string} path
57    *     Full path to the extension package archive.
58    * @param {boolean=} temporary
59    *     True to install the addon temporarily, false (default) otherwise.
60    *
61    * @return {Promise.<string>}
62    *     Addon ID.
63    *
64    * @throws {UnknownError}
65    *     If there is a problem installing the addon.
66    */
67   static async install(path, temporary = false) {
68     let addon;
69     let file;
71     try {
72       file = new lazy.FileUtils.File(path);
73     } catch (e) {
74       throw new lazy.error.UnknownError(`Expected absolute path: ${e}`, e);
75     }
77     if (!file.exists()) {
78       throw new lazy.error.UnknownError(`No such file or directory: ${path}`);
79     }
81     try {
82       if (temporary) {
83         addon = await lazy.AddonManager.installTemporaryAddon(file);
84       } else {
85         addon = await installAddon(file);
86       }
87     } catch (e) {
88       throw new lazy.error.UnknownError(
89         `Could not install add-on: ${path}: ${e.message}`,
90         e
91       );
92     }
94     return addon.id;
95   }
97   /**
98    * Uninstall a Firefox addon.
99    *
100    * If the addon is restartless it will be uninstalled right away.
101    * Otherwise, Firefox must be restarted for the change to take effect.
102    *
103    * @param {string} id
104    *     ID of the addon to uninstall.
105    *
106    * @return {Promise}
107    *
108    * @throws {UnknownError}
109    *     If there is a problem uninstalling the addon.
110    */
111   static async uninstall(id) {
112     let candidate = await lazy.AddonManager.getAddonByID(id);
113     if (candidate === null) {
114       // `AddonManager.getAddonByID` never rejects but instead
115       // returns `null` if the requested addon cannot be found.
116       throw new lazy.error.UnknownError(`Addon ${id} is not installed`);
117     }
119     return new Promise(resolve => {
120       let listener = {
121         onOperationCancelled: addon => {
122           if (addon.id === candidate.id) {
123             lazy.AddonManager.removeAddonListener(listener);
124             throw new lazy.error.UnknownError(
125               `Uninstall of ${candidate.id} has been canceled`
126             );
127           }
128         },
130         onUninstalled: addon => {
131           if (addon.id === candidate.id) {
132             lazy.AddonManager.removeAddonListener(listener);
133             resolve();
134           }
135         },
136       };
138       lazy.AddonManager.addAddonListener(listener);
139       candidate.uninstall();
140     });
141   }