summaryrefslogtreecommitdiffstats
path: root/browser/components/migration/AutoMigrate.jsm
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-06-04 13:17:38 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-06-04 13:17:38 +0200
commita1be17c1cea81ebb1e8b131a662c698d78f3f7f2 (patch)
treea92f7de513be600cc07bac458183e9af40e00c06 /browser/components/migration/AutoMigrate.jsm
parentbf11fdd304898ac675e39b01b280d39550e419d0 (diff)
downloadUXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.tar
UXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.tar.gz
UXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.tar.lz
UXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.tar.xz
UXP-a1be17c1cea81ebb1e8b131a662c698d78f3f7f2.zip
Issue #303 Part 1: Move basilisk files from /browser to /application/basilisk
Diffstat (limited to 'browser/components/migration/AutoMigrate.jsm')
-rw-r--r--browser/components/migration/AutoMigrate.jsm670
1 files changed, 0 insertions, 670 deletions
diff --git a/browser/components/migration/AutoMigrate.jsm b/browser/components/migration/AutoMigrate.jsm
deleted file mode 100644
index b38747825..000000000
--- a/browser/components/migration/AutoMigrate.jsm
+++ /dev/null
@@ -1,670 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["AutoMigrate"];
-
-const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
-
-const kAutoMigrateEnabledPref = "browser.migrate.automigrate.enabled";
-const kUndoUIEnabledPref = "browser.migrate.automigrate.ui.enabled";
-
-const kAutoMigrateBrowserPref = "browser.migrate.automigrate.browser";
-const kAutoMigrateImportedItemIds = "browser.migrate.automigrate.imported-items";
-
-const kAutoMigrateLastUndoPromptDateMsPref = "browser.migrate.automigrate.lastUndoPromptDateMs";
-const kAutoMigrateDaysToOfferUndoPref = "browser.migrate.automigrate.daysToOfferUndo";
-
-const kAutoMigrateUndoSurveyPref = "browser.migrate.automigrate.undo-survey";
-const kAutoMigrateUndoSurveyLocalePref = "browser.migrate.automigrate.undo-survey-locales";
-
-const kNotificationId = "automigration-undo";
-
-Cu.import("resource:///modules/MigrationUtils.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
- "resource://gre/modules/AsyncShutdown.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
- "resource://gre/modules/LoginHelper.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
- "resource://gre/modules/NewTabUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
- "resource://gre/modules/PlacesUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
- "resource://gre/modules/TelemetryStopwatch.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
- const kBrandBundle = "chrome://branding/locale/brand.properties";
- return Services.strings.createBundle(kBrandBundle);
-});
-
-XPCOMUtils.defineLazyGetter(this, "gHardcodedStringBundle", function() {
- const kBundleURI = "chrome://browser/content/migration/extra-migration-strings.properties";
- return Services.strings.createBundle(kBundleURI);
-});
-
-Cu.importGlobalProperties(["URL"]);
-
-/* globals kUndoStateFullPath */
-XPCOMUtils.defineLazyGetter(this, "kUndoStateFullPath", function() {
- return OS.Path.join(OS.Constants.Path.profileDir, "initialMigrationMetadata.jsonlz4");
-});
-
-const AutoMigrate = {
- get resourceTypesToUse() {
- let {BOOKMARKS, HISTORY, PASSWORDS} = Ci.nsIBrowserProfileMigrator;
- return BOOKMARKS | HISTORY | PASSWORDS;
- },
-
- _checkIfEnabled() {
- let pref = Preferences.get(kAutoMigrateEnabledPref, false);
- // User-set values should take precedence:
- if (Services.prefs.prefHasUserValue(kAutoMigrateEnabledPref)) {
- return pref;
- }
- // If we're using the default value, make sure the distribution.ini
- // value is taken into account even early on startup.
- try {
- let distributionFile = Services.dirsvc.get("XREAppDist", Ci.nsIFile);
- distributionFile.append("distribution.ini");
- let parser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
- getService(Ci.nsIINIParserFactory).
- createINIParser(distributionFile);
- return JSON.parse(parser.getString("Preferences", kAutoMigrateEnabledPref));
- } catch (ex) { /* ignore exceptions (file doesn't exist, invalid value, etc.) */ }
-
- return pref;
- },
-
- init() {
- this.enabled = this._checkIfEnabled();
- },
-
- /**
- * Automatically pick a migrator and resources to migrate,
- * then migrate those and start up.
- *
- * @throws if automatically deciding on migrators/data
- * failed for some reason.
- */
- migrate(profileStartup, migratorKey, profileToMigrate) {
- let histogram = Services.telemetry.getHistogramById(
- "FX_STARTUP_MIGRATION_AUTOMATED_IMPORT_PROCESS_SUCCESS");
- histogram.add(0);
- let {migrator, pickedKey} = this.pickMigrator(migratorKey);
- histogram.add(5);
-
- profileToMigrate = this.pickProfile(migrator, profileToMigrate);
- histogram.add(10);
-
- let resourceTypes = migrator.getMigrateData(profileToMigrate, profileStartup);
- if (!(resourceTypes & this.resourceTypesToUse)) {
- throw new Error("No usable resources were found for the selected browser!");
- }
- histogram.add(15);
-
- let sawErrors = false;
- let migrationObserver = (subject, topic) => {
- if (topic == "Migration:ItemError") {
- sawErrors = true;
- } else if (topic == "Migration:Ended") {
- histogram.add(25);
- if (sawErrors) {
- histogram.add(26);
- }
- Services.obs.removeObserver(migrationObserver, "Migration:Ended");
- Services.obs.removeObserver(migrationObserver, "Migration:ItemError");
- Services.prefs.setCharPref(kAutoMigrateBrowserPref, pickedKey);
- // Save the undo history and block shutdown on that save completing.
- AsyncShutdown.profileBeforeChange.addBlocker(
- "AutoMigrate Undo saving", this.saveUndoState(), () => {
- return {state: this._saveUndoStateTrackerForShutdown};
- });
- }
- };
-
- MigrationUtils.initializeUndoData();
- Services.obs.addObserver(migrationObserver, "Migration:Ended", false);
- Services.obs.addObserver(migrationObserver, "Migration:ItemError", false);
- migrator.migrate(this.resourceTypesToUse, profileStartup, profileToMigrate);
- histogram.add(20);
- },
-
- /**
- * Pick and return a migrator to use for automatically migrating.
- *
- * @param {String} migratorKey optional, a migrator key to prefer/pick.
- * @returns {Object} an object with the migrator to use for migrating, as
- * well as the key we eventually ended up using to obtain it.
- */
- pickMigrator(migratorKey) {
- if (!migratorKey) {
- let defaultKey = MigrationUtils.getMigratorKeyForDefaultBrowser();
- if (!defaultKey) {
- throw new Error("Could not determine default browser key to migrate from");
- }
- migratorKey = defaultKey;
- }
- if (migratorKey == "firefox") {
- throw new Error("Can't automatically migrate from Firefox.");
- }
-
- let migrator = MigrationUtils.getMigrator(migratorKey);
- if (!migrator) {
- throw new Error("Migrator specified or a default was found, but the migrator object is not available (or has no data).");
- }
- return {migrator, pickedKey: migratorKey};
- },
-
- /**
- * Pick a source profile (from the original browser) to use.
- *
- * @param {Migrator} migrator the migrator object to use
- * @param {String} suggestedId the id of the profile to migrate, if pre-specified, or null
- * @returns the profile to migrate, or null if migrating
- * from the default profile.
- */
- pickProfile(migrator, suggestedId) {
- let profiles = migrator.sourceProfiles;
- if (profiles && !profiles.length) {
- throw new Error("No profile data found to migrate.");
- }
- if (suggestedId) {
- if (!profiles) {
- throw new Error("Profile specified but only a default profile found.");
- }
- let suggestedProfile = profiles.find(profile => profile.id == suggestedId);
- if (!suggestedProfile) {
- throw new Error("Profile specified was not found.");
- }
- return suggestedProfile;
- }
- if (profiles && profiles.length > 1) {
- throw new Error("Don't know how to pick a profile when more than 1 profile is present.");
- }
- return profiles ? profiles[0] : null;
- },
-
- _pendingUndoTasks: false,
- canUndo: Task.async(function* () {
- if (this._savingPromise) {
- yield this._savingPromise;
- }
- if (this._pendingUndoTasks) {
- return false;
- }
- let fileExists = false;
- try {
- fileExists = yield OS.File.exists(kUndoStateFullPath);
- } catch (ex) {
- Cu.reportError(ex);
- }
- return fileExists;
- }),
-
- undo: Task.async(function* () {
- let browserId = Preferences.get(kAutoMigrateBrowserPref, "unknown");
- TelemetryStopwatch.startKeyed("FX_STARTUP_MIGRATION_UNDO_TOTAL_MS", browserId);
- let histogram = Services.telemetry.getHistogramById("FX_STARTUP_MIGRATION_AUTOMATED_IMPORT_UNDO");
- histogram.add(0);
- if (!(yield this.canUndo())) {
- histogram.add(5);
- throw new Error("Can't undo!");
- }
-
- this._pendingUndoTasks = true;
- this._removeNotificationBars();
- histogram.add(10);
-
- let readPromise = OS.File.read(kUndoStateFullPath, {
- encoding: "utf-8",
- compression: "lz4",
- });
- let stateData = this._dejsonifyUndoState(yield readPromise);
- histogram.add(12);
-
- this._errorMap = {bookmarks: 0, visits: 0, logins: 0};
- let reportErrorTelemetry = (type) => {
- let histogramId = `FX_STARTUP_MIGRATION_UNDO_${type.toUpperCase()}_ERRORCOUNT`;
- Services.telemetry.getKeyedHistogramById(histogramId).add(browserId, this._errorMap[type]);
- };
-
- let startTelemetryStopwatch = resourceType => {
- let histogramId = `FX_STARTUP_MIGRATION_UNDO_${resourceType.toUpperCase()}_MS`;
- TelemetryStopwatch.startKeyed(histogramId, browserId);
- };
- let stopTelemetryStopwatch = resourceType => {
- let histogramId = `FX_STARTUP_MIGRATION_UNDO_${resourceType.toUpperCase()}_MS`;
- TelemetryStopwatch.finishKeyed(histogramId, browserId);
- };
- startTelemetryStopwatch("bookmarks");
- yield this._removeUnchangedBookmarks(stateData.get("bookmarks")).catch(ex => {
- Cu.reportError("Uncaught exception when removing unchanged bookmarks!");
- Cu.reportError(ex);
- });
- stopTelemetryStopwatch("bookmarks");
- reportErrorTelemetry("bookmarks");
- histogram.add(15);
-
- startTelemetryStopwatch("visits");
- yield this._removeSomeVisits(stateData.get("visits")).catch(ex => {
- Cu.reportError("Uncaught exception when removing history visits!");
- Cu.reportError(ex);
- });
- stopTelemetryStopwatch("visits");
- reportErrorTelemetry("visits");
- histogram.add(20);
-
- startTelemetryStopwatch("logins");
- yield this._removeUnchangedLogins(stateData.get("logins")).catch(ex => {
- Cu.reportError("Uncaught exception when removing unchanged logins!");
- Cu.reportError(ex);
- });
- stopTelemetryStopwatch("logins");
- reportErrorTelemetry("logins");
- histogram.add(25);
-
- // This is async, but no need to wait for it.
- NewTabUtils.links.populateCache(() => {
- NewTabUtils.allPages.update();
- }, true);
-
- this._purgeUndoState(this.UNDO_REMOVED_REASON_UNDO_USED);
- histogram.add(30);
- TelemetryStopwatch.finishKeyed("FX_STARTUP_MIGRATION_UNDO_TOTAL_MS", browserId);
- }),
-
- _removeNotificationBars() {
- let browserWindows = Services.wm.getEnumerator("navigator:browser");
- while (browserWindows.hasMoreElements()) {
- let win = browserWindows.getNext();
- if (!win.closed) {
- for (let browser of win.gBrowser.browsers) {
- let nb = win.gBrowser.getNotificationBox(browser);
- let notification = nb.getNotificationWithValue(kNotificationId);
- if (notification) {
- nb.removeNotification(notification);
- }
- }
- }
- }
- },
-
- _purgeUndoState(reason) {
- // We don't wait for the off-main-thread removal to complete. OS.File will
- // ensure it happens before shutdown.
- OS.File.remove(kUndoStateFullPath, {ignoreAbsent: true}).then(() => {
- this._pendingUndoTasks = false;
- });
-
- let migrationBrowser = Preferences.get(kAutoMigrateBrowserPref, "unknown");
- Services.prefs.clearUserPref(kAutoMigrateBrowserPref);
-
- let histogram =
- Services.telemetry.getKeyedHistogramById("FX_STARTUP_MIGRATION_UNDO_REASON");
- histogram.add(migrationBrowser, reason);
- },
-
- getBrowserUsedForMigration() {
- let browserId = Services.prefs.getCharPref(kAutoMigrateBrowserPref);
- if (browserId) {
- return MigrationUtils.getBrowserName(browserId);
- }
- return null;
- },
-
- /**
- * Show the user a notification bar indicating we automatically imported
- * their data and offering them the possibility of removing it.
- * @param target (xul:browser)
- * The browser in which we should show the notification.
- */
- maybeShowUndoNotification: Task.async(function* (target) {
- if (!(yield this.canUndo())) {
- return;
- }
-
- // The tab might have navigated since we requested the undo state:
- let canUndoFromThisPage = ["about:home", "about:newtab"].includes(target.currentURI.spec);
- if (!canUndoFromThisPage ||
- !Preferences.get(kUndoUIEnabledPref, false)) {
- return;
- }
-
- let win = target.ownerGlobal;
- let notificationBox = win.gBrowser.getNotificationBox(target);
- if (!notificationBox || notificationBox.getNotificationWithValue(kNotificationId)) {
- return;
- }
-
- // At this stage we're committed to show the prompt - unless we shouldn't,
- // in which case we remove the undo prefs (which will cause canUndo() to
- // return false from now on.):
- if (!this.shouldStillShowUndoPrompt()) {
- this._purgeUndoState(this.UNDO_REMOVED_REASON_OFFER_EXPIRED);
- this._removeNotificationBars();
- return;
- }
-
- let browserName = this.getBrowserUsedForMigration();
- if (!browserName) {
- browserName = gHardcodedStringBundle.GetStringFromName("automigration.undo.unknownbrowser");
- }
- const kMessageId = "automigration.undo.message." +
- Preferences.get(kAutoMigrateImportedItemIds, "all");
- const kBrandShortName = gBrandBundle.GetStringFromName("brandShortName");
- let message = gHardcodedStringBundle.formatStringFromName(kMessageId,
- [browserName, kBrandShortName], 2);
-
- let buttons = [
- {
- label: gHardcodedStringBundle.GetStringFromName("automigration.undo.keep2.label"),
- accessKey: gHardcodedStringBundle.GetStringFromName("automigration.undo.keep2.accesskey"),
- callback: () => {
- this._purgeUndoState(this.UNDO_REMOVED_REASON_OFFER_REJECTED);
- this._removeNotificationBars();
- },
- },
- {
- label: gHardcodedStringBundle.GetStringFromName("automigration.undo.dontkeep2.label"),
- accessKey: gHardcodedStringBundle.GetStringFromName("automigration.undo.dontkeep2.accesskey"),
- callback: () => {
- this._maybeOpenUndoSurveyTab(win);
- this.undo();
- },
- },
- ];
- notificationBox.appendNotification(
- message, kNotificationId, null, notificationBox.PRIORITY_INFO_HIGH, buttons
- );
- let remainingDays = Preferences.get(kAutoMigrateDaysToOfferUndoPref, 0);
- Services.telemetry.getHistogramById("FX_STARTUP_MIGRATION_UNDO_OFFERED").add(4 - remainingDays);
- }),
-
- shouldStillShowUndoPrompt() {
- let today = new Date();
- // Round down to midnight:
- today = new Date(today.getFullYear(), today.getMonth(), today.getDate());
- // We store the unix timestamp corresponding to midnight on the last day
- // on which we prompted. Fetch that and compare it to today's date.
- // (NB: stored as a string because int prefs are too small for unix
- // timestamps.)
- let previousPromptDateMsStr = Preferences.get(kAutoMigrateLastUndoPromptDateMsPref, "0");
- let previousPromptDate = new Date(parseInt(previousPromptDateMsStr, 10));
- if (previousPromptDate < today) {
- let remainingDays = Preferences.get(kAutoMigrateDaysToOfferUndoPref, 4) - 1;
- Preferences.set(kAutoMigrateDaysToOfferUndoPref, remainingDays);
- Preferences.set(kAutoMigrateLastUndoPromptDateMsPref, today.valueOf().toString());
- if (remainingDays <= 0) {
- return false;
- }
- }
- return true;
- },
-
- UNDO_REMOVED_REASON_UNDO_USED: 0,
- UNDO_REMOVED_REASON_SYNC_SIGNIN: 1,
- UNDO_REMOVED_REASON_PASSWORD_CHANGE: 2,
- UNDO_REMOVED_REASON_BOOKMARK_CHANGE: 3,
- UNDO_REMOVED_REASON_OFFER_EXPIRED: 4,
- UNDO_REMOVED_REASON_OFFER_REJECTED: 5,
-
- _jsonifyUndoState(state) {
- if (!state) {
- return "null";
- }
- // Deal with date serialization.
- let bookmarks = state.get("bookmarks");
- for (let bm of bookmarks) {
- bm.lastModified = bm.lastModified.getTime();
- }
- let serializableState = {
- bookmarks,
- logins: state.get("logins"),
- visits: state.get("visits"),
- };
- return JSON.stringify(serializableState);
- },
-
- _dejsonifyUndoState(state) {
- state = JSON.parse(state);
- if (!state) {
- return new Map();
- }
- for (let bm of state.bookmarks) {
- bm.lastModified = new Date(bm.lastModified);
- }
- return new Map([
- ["bookmarks", state.bookmarks],
- ["logins", state.logins],
- ["visits", state.visits],
- ]);
- },
-
- /**
- * Store the items we've saved into a pref. We use this to be able to show
- * a detailed message to the user indicating what we've imported.
- * @param state (Map)
- * The 'undo' state for the import, which contains info about
- * how many items of each kind we've (tried to) import.
- */
- _setImportedItemPrefFromState(state) {
- let itemsWithData = [];
- if (state) {
- for (let itemType of state.keys()) {
- if (state.get(itemType).length) {
- itemsWithData.push(itemType);
- }
- }
- }
- if (itemsWithData.length == 3) {
- itemsWithData = "all";
- } else {
- itemsWithData = itemsWithData.sort().join(".");
- }
- if (itemsWithData) {
- Preferences.set(kAutoMigrateImportedItemIds, itemsWithData);
- }
- },
-
- /**
- * Used for the shutdown blocker's information field.
- */
- _saveUndoStateTrackerForShutdown: "not running",
- /**
- * Store the information required for using 'undo' of the automatic
- * migration in the user's profile.
- */
- saveUndoState: Task.async(function* () {
- let resolveSavingPromise;
- this._saveUndoStateTrackerForShutdown = "processing undo history";
- this._savingPromise = new Promise(resolve => { resolveSavingPromise = resolve });
- let state = yield MigrationUtils.stopAndRetrieveUndoData();
-
- if (!state || ![...state.values()].some(ary => ary.length > 0)) {
- // If we didn't import anything, abort now.
- resolveSavingPromise();
- return Promise.resolve();
- }
-
- this._saveUndoStateTrackerForShutdown = "saving imported item list";
- this._setImportedItemPrefFromState(state);
-
- this._saveUndoStateTrackerForShutdown = "writing undo history";
- this._undoSavePromise = OS.File.writeAtomic(
- kUndoStateFullPath, this._jsonifyUndoState(state), {
- encoding: "utf-8",
- compression: "lz4",
- tmpPath: kUndoStateFullPath + ".tmp",
- });
- this._undoSavePromise.then(
- rv => {
- resolveSavingPromise(rv);
- delete this._savingPromise;
- },
- e => {
- Cu.reportError("Could not write undo state for automatic migration.");
- throw e;
- });
- return this._undoSavePromise;
- }),
-
- _removeUnchangedBookmarks: Task.async(function* (bookmarks) {
- if (!bookmarks.length) {
- return;
- }
-
- let guidToLMMap = new Map(bookmarks.map(b => [b.guid, b.lastModified]));
- let bookmarksFromDB = [];
- let bmPromises = Array.from(guidToLMMap.keys()).map(guid => {
- // Ignore bookmarks where the promise doesn't resolve (ie that are missing)
- // Also check that the bookmark fetch returns isn't null before adding it.
- try {
- return PlacesUtils.bookmarks.fetch(guid).then(bm => bm && bookmarksFromDB.push(bm), () => {});
- } catch (ex) {
- // Ignore immediate exceptions, too.
- }
- return Promise.resolve();
- });
- // We can't use the result of Promise.all because that would include nulls
- // for bookmarks that no longer exist (which we're catching above).
- yield Promise.all(bmPromises);
- let unchangedBookmarks = bookmarksFromDB.filter(bm => {
- return bm.lastModified.getTime() == guidToLMMap.get(bm.guid).getTime();
- });
-
- // We need to remove items without children first, followed by their
- // parents, etc. In order to do this, find out how many ancestors each item
- // has that also appear in our list of things to remove, and sort the items
- // by those numbers. This ensures that children are always removed before
- // their parents.
- function determineAncestorCount(bm) {
- if (bm._ancestorCount) {
- return bm._ancestorCount;
- }
- let myCount = 0;
- let parentBM = unchangedBookmarks.find(item => item.guid == bm.parentGuid);
- if (parentBM) {
- myCount = determineAncestorCount(parentBM) + 1;
- }
- bm._ancestorCount = myCount;
- return myCount;
- }
- unchangedBookmarks.forEach(determineAncestorCount);
- unchangedBookmarks.sort((a, b) => b._ancestorCount - a._ancestorCount);
- for (let {guid} of unchangedBookmarks) {
- // Can't just use a .catch() because Bookmarks.remove() can throw (rather
- // than returning rejected promises).
- try {
- yield PlacesUtils.bookmarks.remove(guid, {preventRemovalOfNonEmptyFolders: true});
- } catch (err) {
- if (err && err.message != "Cannot remove a non-empty folder.") {
- this._errorMap.bookmarks++;
- Cu.reportError(err);
- }
- }
- }
- }),
-
- _removeUnchangedLogins: Task.async(function* (logins) {
- for (let login of logins) {
- let foundLogins = LoginHelper.searchLoginsWithObject({guid: login.guid});
- if (foundLogins.length) {
- let foundLogin = foundLogins[0];
- foundLogin.QueryInterface(Ci.nsILoginMetaInfo);
- if (foundLogin.timePasswordChanged == login.timePasswordChanged) {
- try {
- Services.logins.removeLogin(foundLogin);
- } catch (ex) {
- Cu.reportError("Failed to remove a login for " + foundLogins.hostname);
- Cu.reportError(ex);
- this._errorMap.logins++;
- }
- }
- }
- }
- }),
-
- _removeSomeVisits: Task.async(function* (visits) {
- for (let urlVisits of visits) {
- let urlObj;
- try {
- urlObj = new URL(urlVisits.url);
- } catch (ex) {
- continue;
- }
- let visitData = {
- url: urlObj,
- beginDate: PlacesUtils.toDate(urlVisits.first),
- endDate: PlacesUtils.toDate(urlVisits.last),
- limit: urlVisits.visitCount,
- };
- try {
- yield PlacesUtils.history.removeVisitsByFilter(visitData);
- } catch (ex) {
- this._errorMap.visits++;
- try {
- visitData.url = visitData.url.href;
- } catch (ignoredEx) {}
- Cu.reportError("Failed to remove a visit: " + JSON.stringify(visitData));
- Cu.reportError(ex);
- }
- }
- }),
-
- /**
- * Maybe open a new tab with a survey. The tab will only be opened if all of
- * the following are true:
- * - the 'browser.migrate.automigrate.undo-survey' pref is not empty.
- * It should contain the URL of the survey to open.
- * - the 'browser.migrate.automigrate.undo-survey-locales' pref, a
- * comma-separated list of language codes, contains the language code
- * that is currently in use for the 'global' chrome pacakge (ie the
- * locale in which the user is currently using Firefox).
- * The URL will be passed through nsIURLFormatter to allow including
- * build ids etc. The special additional formatting variable
- * "%IMPORTEDBROWSER" is also replaced with the name of the browser
- * from which we imported data.
- *
- * @param {Window} chromeWindow A reference to the window in which to open a link.
- */
- _maybeOpenUndoSurveyTab(chromeWindow) {
- let canDoSurveyInLocale = false;
- try {
- let surveyLocales = Preferences.get(kAutoMigrateUndoSurveyLocalePref, "");
- surveyLocales = surveyLocales.split(",").map(str => str.trim());
- // Strip out any empty elements, so an empty pref doesn't
- // lead to a an array with 1 empty string in it.
- surveyLocales = new Set(surveyLocales.filter(str => !!str));
- let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"]
- .getService(Ci.nsIXULChromeRegistry);
- canDoSurveyInLocale =
- surveyLocales.has(chromeRegistry.getSelectedLocale("global"));
- } catch (ex) {
- /* ignore exceptions and just don't do the survey. */
- }
-
- let migrationBrowser = this.getBrowserUsedForMigration();
- let rawURL = Preferences.get(kAutoMigrateUndoSurveyPref, "");
- if (!canDoSurveyInLocale || !migrationBrowser || !rawURL) {
- return;
- }
-
- let url = Services.urlFormatter.formatURL(rawURL);
- url = url.replace("%IMPORTEDBROWSER%", encodeURIComponent(migrationBrowser));
- chromeWindow.openUILinkIn(url, "tab");
- },
-
- QueryInterface: XPCOMUtils.generateQI(
- [Ci.nsIObserver, Ci.nsINavBookmarkObserver, Ci.nsISupportsWeakReference]
- ),
-};
-
-AutoMigrate.init();