summaryrefslogtreecommitdiffstats
path: root/browser/components/backup/BackupService.sys.mjs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
commitd8bbc7858622b6d9c278469aab701ca0b609cddf (patch)
treeeff41dc61d9f714852212739e6b3738b82a2af87 /browser/components/backup/BackupService.sys.mjs
parentReleasing progress-linux version 125.0.3-1~progress7.99u1. (diff)
downloadfirefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz
firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/components/backup/BackupService.sys.mjs')
-rw-r--r--browser/components/backup/BackupService.sys.mjs129
1 files changed, 123 insertions, 6 deletions
diff --git a/browser/components/backup/BackupService.sys.mjs b/browser/components/backup/BackupService.sys.mjs
index 853f4768ce..3521f315fd 100644
--- a/browser/components/backup/BackupService.sys.mjs
+++ b/browser/components/backup/BackupService.sys.mjs
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-import * as BackupResources from "resource:///modules/backup/BackupResources.sys.mjs";
+import * as DefaultBackupResources from "resource:///modules/backup/BackupResources.sys.mjs";
const lazy = {};
@@ -37,6 +37,13 @@ export class BackupService {
#resources = new Map();
/**
+ * True if a backup is currently in progress.
+ *
+ * @type {boolean}
+ */
+ #backupInProgress = false;
+
+ /**
* Returns a reference to a BackupService singleton. If this is the first time
* that this getter is accessed, this causes the BackupService singleton to be
* be instantiated.
@@ -48,27 +55,130 @@ export class BackupService {
if (this.#instance) {
return this.#instance;
}
- this.#instance = new BackupService(BackupResources);
+ this.#instance = new BackupService(DefaultBackupResources);
this.#instance.takeMeasurements();
return this.#instance;
}
/**
+ * Returns a reference to the BackupService singleton. If the singleton has
+ * not been initialized, an error is thrown.
+ *
+ * @static
+ * @returns {BackupService}
+ */
+ static get() {
+ if (!this.#instance) {
+ throw new Error("BackupService not initialized");
+ }
+ return this.#instance;
+ }
+
+ /**
* Create a BackupService instance.
*
- * @param {object} [backupResources=BackupResources] - Object containing BackupResource classes to associate with this service.
+ * @param {object} [backupResources=DefaultBackupResources] - Object containing BackupResource classes to associate with this service.
*/
- constructor(backupResources = BackupResources) {
+ constructor(backupResources = DefaultBackupResources) {
lazy.logConsole.debug("Instantiated");
for (const resourceName in backupResources) {
- let resource = BackupResources[resourceName];
+ let resource = backupResources[resourceName];
this.#resources.set(resource.key, resource);
}
}
/**
+ * Create a backup of the user's profile.
+ *
+ * @param {object} [options]
+ * Options for the backup.
+ * @param {string} [options.profilePath=PathUtils.profileDir]
+ * The path to the profile to backup. By default, this is the current
+ * profile.
+ * @returns {Promise<undefined>}
+ */
+ async createBackup({ profilePath = PathUtils.profileDir } = {}) {
+ // createBackup does not allow re-entry or concurrent backups.
+ if (this.#backupInProgress) {
+ lazy.logConsole.warn("Backup attempt already in progress");
+ return;
+ }
+
+ this.#backupInProgress = true;
+
+ try {
+ lazy.logConsole.debug(`Creating backup for profile at ${profilePath}`);
+
+ // First, check to see if a `backups` directory already exists in the
+ // profile.
+ let backupDirPath = PathUtils.join(profilePath, "backups");
+ lazy.logConsole.debug("Creating backups folder");
+
+ // ignoreExisting: true is the default, but we're being explicit that it's
+ // okay if this folder already exists.
+ await IOUtils.makeDirectory(backupDirPath, { ignoreExisting: true });
+
+ let stagingPath = await this.#prepareStagingFolder(backupDirPath);
+
+ // Perform the backup for each resource.
+ for (let resourceClass of this.#resources.values()) {
+ try {
+ lazy.logConsole.debug(
+ `Backing up resource with key ${resourceClass.key}. ` +
+ `Requires encryption: ${resourceClass.requiresEncryption}`
+ );
+ let resourcePath = PathUtils.join(stagingPath, resourceClass.key);
+ await IOUtils.makeDirectory(resourcePath);
+
+ // `backup` on each BackupResource should return us a ManifestEntry
+ // that we eventually write to a JSON manifest file, but for now,
+ // we're just going to log it.
+ let manifestEntry = await new resourceClass().backup(
+ resourcePath,
+ profilePath
+ );
+ lazy.logConsole.debug(
+ `Backup of resource with key ${resourceClass.key} completed`,
+ manifestEntry
+ );
+ } catch (e) {
+ lazy.logConsole.error(
+ `Failed to backup resource: ${resourceClass.key}`,
+ e
+ );
+ }
+ }
+ } finally {
+ this.#backupInProgress = false;
+ }
+ }
+
+ /**
+ * Constructs the staging folder for the backup in the passed in backup
+ * folder. If a pre-existing staging folder exists, it will be cleared out.
+ *
+ * @param {string} backupDirPath
+ * The path to the backup folder.
+ * @returns {Promise<string>}
+ * The path to the empty staging folder.
+ */
+ async #prepareStagingFolder(backupDirPath) {
+ let stagingPath = PathUtils.join(backupDirPath, "staging");
+ lazy.logConsole.debug("Checking for pre-existing staging folder");
+ if (await IOUtils.exists(stagingPath)) {
+ // A pre-existing staging folder exists. A previous backup attempt must
+ // have failed or been interrupted. We'll clear it out.
+ lazy.logConsole.warn("A pre-existing staging folder exists. Clearing.");
+ await IOUtils.remove(stagingPath, { recursive: true });
+ }
+ await IOUtils.makeDirectory(stagingPath);
+
+ return stagingPath;
+ }
+
+ /**
* Take measurements of the current profile state for Telemetry.
*
* @returns {Promise<undefined>}
@@ -97,7 +207,14 @@ export class BackupService {
// Measure the size of each file we are going to backup.
for (let resourceClass of this.#resources.values()) {
- await new resourceClass().measure(PathUtils.profileDir);
+ try {
+ await new resourceClass().measure(PathUtils.profileDir);
+ } catch (e) {
+ lazy.logConsole.error(
+ `Failed to measure for resource: ${resourceClass.key}`,
+ e
+ );
+ }
}
}
}