--- a/browser/components/migration/360seProfileMigrator.js
+++ b/browser/components/migration/360seProfileMigrator.js
@@ -207,93 +207,91 @@ function Qihoo360seProfileMigrator() {
this._defaultUserPath = path.defaultUser;
break;
}
}
}
Qihoo360seProfileMigrator.prototype = Object.create(MigratorPrototype);
-Object.defineProperty(Qihoo360seProfileMigrator.prototype, "sourceProfiles", {
- get() {
- if ("__sourceProfiles" in this)
- return this.__sourceProfiles;
+Qihoo360seProfileMigrator.prototype.getSourceProfiles = function() {
+ if ("__sourceProfiles" in this)
+ return this.__sourceProfiles;
+
+ if (!this._usersDir) {
+ this.__sourceProfiles = [];
+ return this.__sourceProfiles;
+ }
- if (!this._usersDir) {
- this.__sourceProfiles = [];
- return this.__sourceProfiles;
+ let profiles = [];
+ let noLoggedInUser = true;
+ try {
+ let loginIni = this._usersDir.clone();
+ loginIni.append("login.ini");
+ if (!loginIni.exists()) {
+ throw new Error("360 Secure Browser's 'login.ini' does not exist.");
+ }
+ if (!loginIni.isReadable()) {
+ throw new Error("360 Secure Browser's 'login.ini' file could not be read.");
}
- let profiles = [];
- let noLoggedInUser = true;
+ let loginIniInUtf8 = copyToTempUTF8File(loginIni, "GBK");
+ let loginIniObj = parseINIStrings(loginIniInUtf8);
try {
- let loginIni = this._usersDir.clone();
- loginIni.append("login.ini");
- if (!loginIni.exists()) {
- throw new Error("360 Secure Browser's 'login.ini' does not exist.");
- }
- if (!loginIni.isReadable()) {
- throw new Error("360 Secure Browser's 'login.ini' file could not be read.");
+ loginIniInUtf8.remove(false);
+ } catch (ex) {}
+
+ let nowLoginEmail = loginIniObj.NowLogin && loginIniObj.NowLogin.email;
+
+ /*
+ * NowLogin section may:
+ * 1. be missing or without email, before any user logs in.
+ * 2. represents the current logged in user
+ * 3. represents the most recent logged in user
+ *
+ * In the second case, user represented by NowLogin should be the first
+ * profile; otherwise the default user should be selected by default.
+ */
+ if (nowLoginEmail) {
+ if (loginIniObj.NowLogin.IsLogined === "1") {
+ noLoggedInUser = false;
}
- let loginIniInUtf8 = copyToTempUTF8File(loginIni, "GBK");
- let loginIniObj = parseINIStrings(loginIniInUtf8);
- try {
- loginIniInUtf8.remove(false);
- } catch (ex) {}
-
- let nowLoginEmail = loginIniObj.NowLogin && loginIniObj.NowLogin.email;
-
- /*
- * NowLogin section may:
- * 1. be missing or without email, before any user logs in.
- * 2. represents the current logged in user
- * 3. represents the most recent logged in user
- *
- * In the second case, user represented by NowLogin should be the first
- * profile; otherwise the default user should be selected by default.
- */
- if (nowLoginEmail) {
- if (loginIniObj.NowLogin.IsLogined === "1") {
- noLoggedInUser = false;
- }
-
- profiles.push({
- id: this._getIdFromConfig(loginIniObj.NowLogin),
- name: nowLoginEmail,
- });
- }
-
- for (let section in loginIniObj) {
- if (!loginIniObj[section].email ||
- (nowLoginEmail && loginIniObj[section].email == nowLoginEmail)) {
- continue;
- }
-
- profiles.push({
- id: this._getIdFromConfig(loginIniObj[section]),
- name: loginIniObj[section].email,
- });
- }
- } catch (e) {
- Cu.reportError("Error detecting 360 Secure Browser profiles: " + e);
- } finally {
- profiles[noLoggedInUser ? "unshift" : "push"]({
- id: this._defaultUserPath,
- name: "Default",
+ profiles.push({
+ id: this._getIdFromConfig(loginIniObj.NowLogin),
+ name: nowLoginEmail,
});
}
- this.__sourceProfiles = profiles.filter(profile => {
- let resources = this.getResources(profile);
- return resources && resources.length > 0;
+ for (let section in loginIniObj) {
+ if (!loginIniObj[section].email ||
+ (nowLoginEmail && loginIniObj[section].email == nowLoginEmail)) {
+ continue;
+ }
+
+ profiles.push({
+ id: this._getIdFromConfig(loginIniObj[section]),
+ name: loginIniObj[section].email,
+ });
+ }
+ } catch (e) {
+ Cu.reportError("Error detecting 360 Secure Browser profiles: " + e);
+ } finally {
+ profiles[noLoggedInUser ? "unshift" : "push"]({
+ id: this._defaultUserPath,
+ name: "Default",
});
- return this.__sourceProfiles;
- },
-});
+ }
+
+ this.__sourceProfiles = profiles.filter(profile => {
+ let resources = this.getResources(profile);
+ return resources && resources.length > 0;
+ });
+ return this.__sourceProfiles;
+};
Qihoo360seProfileMigrator.prototype._getIdFromConfig = function(aConfig) {
return aConfig.UserMd5 || getHash(aConfig.email);
};
Qihoo360seProfileMigrator.prototype.getResources = function(aProfile) {
let profileFolder = this._usersDir.clone();
profileFolder.append(aProfile.id);
@@ -303,22 +301,23 @@ Qihoo360seProfileMigrator.prototype.getR
}
let resources = [
new Bookmarks(profileFolder),
];
return resources.filter(r => r.exists);
};
-Qihoo360seProfileMigrator.prototype.getLastUsedDate = function() {
- let bookmarksPaths = this.sourceProfiles.map(({id}) => {
+Qihoo360seProfileMigrator.prototype.getLastUsedDate = async function() {
+ let sourceProfiles = await this.getSourceProfiles();
+ let bookmarksPaths = sourceProfiles.map(({id}) => {
return OS.Path.join(this._usersDir.path, id, kBookmarksFileName);
});
if (!bookmarksPaths.length) {
- return Promise.resolve(new Date(0));
+ return new Date(0);
}
let datePromises = bookmarksPaths.map(path => {
return OS.File.stat(path).catch(() => null).then(info => {
return info ? info.lastModificationDate : 0;
});
});
return Promise.all(datePromises).then(dates => {
return new Date(Math.max.apply(Math, dates));
--- a/browser/components/migration/AutoMigrate.jsm
+++ b/browser/components/migration/AutoMigrate.jsm
@@ -85,27 +85,27 @@ const AutoMigrate = {
/**
* 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) {
+ async 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);
+ let {migrator, pickedKey} = await this.pickMigrator(migratorKey);
histogram.add(5);
- profileToMigrate = this.pickProfile(migrator, profileToMigrate);
+ profileToMigrate = await this.pickProfile(migrator, profileToMigrate);
histogram.add(10);
- let resourceTypes = migrator.getMigrateData(profileToMigrate, profileStartup);
+ let resourceTypes = await 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") {
@@ -124,56 +124,56 @@ const AutoMigrate = {
return {state: this._saveUndoStateTrackerForShutdown};
});
}
};
MigrationUtils.initializeUndoData();
Services.obs.addObserver(migrationObserver, "Migration:Ended");
Services.obs.addObserver(migrationObserver, "Migration:ItemError");
- migrator.migrate(this.resourceTypesToUse, profileStartup, profileToMigrate);
+ await 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) {
+ async 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);
+ let migrator = await 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;
+ async pickProfile(migrator, suggestedId) {
+ let profiles = await migrator.getSourceProfiles();
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);
--- a/browser/components/migration/ChromeProfileMigrator.js
+++ b/browser/components/migration/ChromeProfileMigrator.js
@@ -135,18 +135,18 @@ ChromeProfileMigrator.prototype.getLastU
});
});
return Promise.all(datePromises).then(dates => {
dates.push(0);
return new Date(Math.max.apply(Math, dates));
});
};
-Object.defineProperty(ChromeProfileMigrator.prototype, "sourceProfiles", {
- get: function Chrome_sourceProfiles() {
+ChromeProfileMigrator.prototype.getSourceProfiles =
+ async function Chrome_getSourceProfiles() {
if ("__sourceProfiles" in this)
return this.__sourceProfiles;
if (!this._chromeUserDataFolder)
return [];
let profiles = [];
try {
@@ -173,21 +173,20 @@ Object.defineProperty(ChromeProfileMigra
}
// Only list profiles from which any data can be imported
this.__sourceProfiles = profiles.filter(function(profile) {
let resources = this.getResources(profile);
return resources && resources.length > 0;
}, this);
return this.__sourceProfiles;
- },
-});
+ };
-Object.defineProperty(ChromeProfileMigrator.prototype, "sourceHomePageURL", {
- get: function Chrome_sourceHomePageURL() {
+ChromeProfileMigrator.prototype.getSourceHomePageURL =
+ async function Chrome_getSourceHomePageURL() {
let prefsFile = this._chromeUserDataFolder.clone();
prefsFile.append("Preferences");
if (prefsFile.exists()) {
// XXX reading and parsing JSON is synchronous.
let fstream = Cc[FILE_INPUT_STREAM_CID].
createInstance(Ci.nsIFileInputStream);
fstream.init(prefsFile, -1, 0, 0);
try {
@@ -195,18 +194,17 @@ Object.defineProperty(ChromeProfileMigra
NetUtil.readInputStreamToString(fstream, fstream.available(),
{ charset: "UTF-8" })
).homepage;
} catch (e) {
Cu.reportError("Error parsing Chrome's preferences file: " + e);
}
}
return "";
- },
-});
+ };
Object.defineProperty(ChromeProfileMigrator.prototype, "sourceLocked", {
get: function Chrome_sourceLocked() {
// There is an exclusive lock on some SQLite databases. Assume they are locked for now.
return true;
},
});
--- a/browser/components/migration/EdgeProfileMigrator.js
+++ b/browser/components/migration/EdgeProfileMigrator.js
@@ -369,20 +369,21 @@ EdgeProfileMigrator.prototype.getResourc
];
let windowsVaultFormPasswordsMigrator =
MSMigrationUtils.getWindowsVaultFormPasswordsMigrator();
windowsVaultFormPasswordsMigrator.name = "EdgeVaultFormPasswords";
resources.push(windowsVaultFormPasswordsMigrator);
return resources.filter(r => r.exists);
};
-EdgeProfileMigrator.prototype.getLastUsedDate = function() {
+EdgeProfileMigrator.prototype.getLastUsedDate = async function() {
// Don't do this if we don't have a single profile (see the comment for
// sourceProfiles) or if we can't find the database file:
- if (this.sourceProfiles !== null || !gEdgeDatabase) {
+ let sourceProfiles = await this.getSourceProfiles();
+ if (sourceProfiles !== null || !gEdgeDatabase) {
return Promise.resolve(new Date(0));
}
let logFilePath = OS.Path.join(gEdgeDatabase.parent.path, "LogFiles", "edb.log");
let dbPath = gEdgeDatabase.path;
let cookieMigrator = MSMigrationUtils.getCookiesMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE);
let cookiePaths = cookieMigrator._cookiesFolders.map(f => f.path);
let datePromises = [logFilePath, dbPath, ...cookiePaths].map(path => {
return OS.File.stat(path).catch(() => null).then(info => {
@@ -403,20 +404,20 @@ EdgeProfileMigrator.prototype.getLastUse
});
};
/* Somewhat counterintuitively, this returns:
* - |null| to indicate "There is only 1 (default) profile" (on win10+)
* - |[]| to indicate "There are no profiles" (on <=win8.1) which will avoid using this migrator.
* See MigrationUtils.jsm for slightly more info on how sourceProfiles is used.
*/
-EdgeProfileMigrator.prototype.__defineGetter__("sourceProfiles", function() {
+EdgeProfileMigrator.prototype.getSourceProfiles = function() {
let isWin10OrHigher = AppConstants.isPlatformAndVersionAtLeast("win", "10");
return isWin10OrHigher ? null : [];
-});
+};
EdgeProfileMigrator.prototype.__defineGetter__("sourceLocked", function() {
// There is an exclusive lock on some databases. Assume they are locked for now.
return true;
});
EdgeProfileMigrator.prototype.classDescription = "Edge Profile Migrator";
--- a/browser/components/migration/FirefoxProfileMigrator.js
+++ b/browser/components/migration/FirefoxProfileMigrator.js
@@ -56,21 +56,19 @@ FirefoxProfileMigrator.prototype._getAll
}
return allProfiles;
};
function sorter(a, b) {
return a.id.toLocaleLowerCase().localeCompare(b.id.toLocaleLowerCase());
}
-Object.defineProperty(FirefoxProfileMigrator.prototype, "sourceProfiles", {
- get() {
- return [...this._getAllProfiles().keys()].map(x => ({id: x, name: x})).sort(sorter);
- },
-});
+FirefoxProfileMigrator.prototype.getSourceProfiles = function() {
+ return [...this._getAllProfiles().keys()].map(x => ({id: x, name: x})).sort(sorter);
+};
FirefoxProfileMigrator.prototype._getFileObject = function(dir, fileName) {
let file = dir.clone();
file.append(fileName);
// File resources are monolithic. We don't make partial copies since
// they are not expected to work alone. Return null to avoid trying to
// copy non-existing files.
--- a/browser/components/migration/IEProfileMigrator.js
+++ b/browser/components/migration/IEProfileMigrator.js
@@ -373,40 +373,38 @@ IEProfileMigrator.prototype.getLastUsedD
// dates is an array of PRTimes, which are in microseconds - convert to milliseconds
resolve(Math.max.apply(Math, dates) / 1000);
}));
return Promise.all(datePromises).then(dates => {
return new Date(Math.max.apply(Math, dates));
});
};
-Object.defineProperty(IEProfileMigrator.prototype, "sourceHomePageURL", {
- get: function IE_get_sourceHomePageURL() {
- let defaultStartPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
- kMainKey, "Default_Page_URL");
- let startPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
- kMainKey, "Start Page");
- // If the user didn't customize the Start Page, he is still on the default
- // page, that may be considered the equivalent of our about:home. There's
- // no reason to retain it, since it is heavily targeted to IE.
- let homepage = startPage != defaultStartPage ? startPage : "";
+IEProfileMigrator.prototype.getSourceHomePageURL = function IE_getSourceHomePageURL() {
+ let defaultStartPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
+ kMainKey, "Default_Page_URL");
+ let startPage = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+ kMainKey, "Start Page");
+ // If the user didn't customize the Start Page, he is still on the default
+ // page, that may be considered the equivalent of our about:home. There's
+ // no reason to retain it, since it is heavily targeted to IE.
+ let homepage = startPage != defaultStartPage ? startPage : "";
- // IE7+ supports secondary home pages located in a REG_MULTI_SZ key. These
- // are in addition to the Start Page, and no empty entries are possible,
- // thus a Start Page is always defined if any of these exists, though it
- // may be the default one.
- let secondaryPages = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
- kMainKey, "Secondary Start Pages");
- if (secondaryPages) {
- if (homepage)
- secondaryPages.unshift(homepage);
- homepage = secondaryPages.join("|");
- }
+ // IE7+ supports secondary home pages located in a REG_MULTI_SZ key. These
+ // are in addition to the Start Page, and no empty entries are possible,
+ // thus a Start Page is always defined if any of these exists, though it
+ // may be the default one.
+ let secondaryPages = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+ kMainKey, "Secondary Start Pages");
+ if (secondaryPages) {
+ if (homepage)
+ secondaryPages.unshift(homepage);
+ homepage = secondaryPages.join("|");
+ }
- return homepage;
- },
-});
+ return homepage;
+};
IEProfileMigrator.prototype.classDescription = "IE Profile Migrator";
IEProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=ie";
IEProfileMigrator.prototype.classID = Components.ID("{3d2532e3-4932-4774-b7ba-968f5899d3a4}");
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IEProfileMigrator]);
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -78,17 +78,17 @@ function getMigrationBundle() {
* 2. Create the prototype for the migrator, extending MigratorPrototype.
* Namely: MosaicMigrator.prototype = Object.create(MigratorPrototype);
* 3. Set classDescription, contractID and classID for your migrator, and set
* NSGetFactory appropriately.
* 4. If the migrator supports multiple profiles, override the sourceProfiles
* Here we default for single-profile migrator.
* 5. Implement getResources(aProfile) (see below).
* 6. If the migrator supports reading the home page of the source browser,
- * override |sourceHomePageURL| getter.
+ * override |getSourceHomePageURL| getter.
* 7. For startup-only migrators, override |startupOnlyMigrator|.
*/
this.MigratorPrototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserProfileMigrator]),
/**
* OVERRIDE IF AND ONLY IF the source supports multiple profiles.
*
@@ -98,17 +98,17 @@ this.MigratorPrototype = {
* name - a pretty name to display to the user in the UI
*
* Only profiles from which data can be imported should be listed. Otherwise
* the behavior of the migration wizard isn't well-defined.
*
* For a single-profile source (e.g. safari, ie), this returns null,
* and not an empty array. That is the default implementation.
*/
- get sourceProfiles() {
+ getSourceProfiles() {
return null;
},
/**
* MUST BE OVERRIDDEN.
*
* Returns an array of "migration resources" objects for the given profile,
* or for the "default" profile, if the migrator does not support multiple
@@ -201,18 +201,18 @@ this.MigratorPrototype = {
},
/**
* DO NOT OVERRIDE - After deCOMing migration, the UI will just call
* getResources.
*
* @see nsIBrowserProfileMigrator
*/
- getMigrateData: function MP_getMigrateData(aProfile) {
- let resources = this._getMaybeCachedResources(aProfile);
+ getMigrateData: async function MP_getMigrateData(aProfile) {
+ let resources = await this._getMaybeCachedResources(aProfile);
if (!resources) {
return [];
}
let types = resources.map(r => r.type);
return types.reduce((a, b) => { a |= b; return a; }, 0);
},
getBrowserKey: function MP_getBrowserKey() {
@@ -220,18 +220,18 @@ this.MigratorPrototype = {
},
/**
* DO NOT OVERRIDE - After deCOMing migration, the UI will just call
* migrate for each resource.
*
* @see nsIBrowserProfileMigrator
*/
- migrate: function MP_migrate(aItems, aStartup, aProfile) {
- let resources = this._getMaybeCachedResources(aProfile);
+ migrate: async function MP_migrate(aItems, aStartup, aProfile) {
+ let resources = await this._getMaybeCachedResources(aProfile);
if (resources.length == 0)
throw new Error("migrate called for a non-existent source");
if (aItems != Ci.nsIBrowserProfileMigrator.ALL)
resources = resources.filter(r => aItems & r.type);
// Used to periodically give back control to the main-thread loop.
let unblockMainThread = function() {
@@ -406,49 +406,49 @@ this.MigratorPrototype = {
},
/**
* DO NOT OVERRIDE - After deCOMing migration, this code
* won't be part of the migrator itself.
*
* @see nsIBrowserProfileMigrator
*/
- get sourceExists() {
+ async isSourceAvailable() {
if (this.startupOnlyMigrator && !MigrationUtils.isStartupMigration)
return false;
// For a single-profile source, check if any data is available.
// For multiple-profiles source, make sure that at least one
// profile is available.
let exists = false;
try {
- let profiles = this.sourceProfiles;
+ let profiles = await this.getSourceProfiles();
if (!profiles) {
- let resources = this._getMaybeCachedResources("");
+ let resources = await this._getMaybeCachedResources("");
if (resources && resources.length > 0)
exists = true;
} else {
exists = profiles.length > 0;
}
} catch (ex) {
Cu.reportError(ex);
}
return exists;
},
/** * PRIVATE STUFF - DO NOT OVERRIDE ***/
- _getMaybeCachedResources: function PMB__getMaybeCachedResources(aProfile) {
+ _getMaybeCachedResources: async function PMB__getMaybeCachedResources(aProfile) {
let profileKey = aProfile ? aProfile.id : "";
if (this._resourcesByProfile) {
if (profileKey in this._resourcesByProfile)
return this._resourcesByProfile[profileKey];
} else {
this._resourcesByProfile = { };
}
- this._resourcesByProfile[profileKey] = this.getResources(aProfile);
+ this._resourcesByProfile[profileKey] = await this.getResources(aProfile);
return this._resourcesByProfile[profileKey];
},
};
this.MigrationUtils = Object.freeze({
resourceTypes: {
SETTINGS: Ci.nsIBrowserProfileMigrator.SETTINGS,
COOKIES: Ci.nsIBrowserProfileMigrator.COOKIES,
@@ -658,16 +658,38 @@ this.MigrationUtils = Object.freeze({
get _migrators() {
if (!gMigrators) {
gMigrators = new Map();
}
return gMigrators;
},
+ spinResolve: function MU_spinResolve(promise) {
+ if (!(promise instanceof Promise)) {
+ return promise;
+ }
+ let done = false;
+ let result = null;
+ let error = null;
+ promise.catch(e => {
+ error = e;
+ }).then(r => {
+ result = r;
+ done = true;
+ });
+
+ Services.tm.spinEventLoopUntil(() => done);
+ if (error) {
+ throw error;
+ } else {
+ return result;
+ }
+ },
+
/*
* Returns the migrator for the given source, if any data is available
* for this source, or null otherwise.
*
* @param aKey internal name of the migration source.
* Supported values: ie (windows),
* edge (windows),
* safari (mac),
@@ -680,30 +702,30 @@ this.MigrationUtils = Object.freeze({
* If null is returned, either no data can be imported
* for the given migrator, or aMigratorKey is invalid (e.g. ie on mac,
* or mosaic everywhere). This method should be used rather than direct
* getService for future compatibility (see bug 718280).
*
* @return profile migrator implementing nsIBrowserProfileMigrator, if it can
* import any data, null otherwise.
*/
- getMigrator: function MU_getMigrator(aKey) {
+ getMigrator: async function MU_getMigrator(aKey) {
let migrator = null;
if (this._migrators.has(aKey)) {
migrator = this._migrators.get(aKey);
} else {
try {
migrator = Cc["@mozilla.org/profile/migrator;1?app=browser&type=" +
aKey].createInstance(Ci.nsIBrowserProfileMigrator);
} catch (ex) { Cu.reportError(ex); }
this._migrators.set(aKey, migrator);
}
try {
- return migrator && migrator.sourceExists ? migrator : null;
+ return migrator && (await migrator.isSourceAvailable()) ? migrator : null;
} catch (ex) { Cu.reportError(ex); return null; }
},
/**
* Figure out what is the default browser, and if there is a migrator
* for it, return that migrator's internal name.
* For the time being, the "internal name" of a migrator is its contract-id
* trailer (e.g. ie for @mozilla.org/profile/migrator;1?app=browser&type=ie),
@@ -871,17 +893,18 @@ this.MigrationUtils = Object.freeze({
"_blank",
features,
params);
},
/**
* Show the migration wizard for startup-migration. This should only be
* called by ProfileMigrator (see ProfileMigrator.js), which implements
- * nsIProfileMigrator.
+ * nsIProfileMigrator. This runs asynchronously if we are running an
+ * automigration.
*
* @param aProfileStartup
* the nsIProfileStartup instance provided to ProfileMigrator.migrate.
* @param [optional] aMigratorKey
* If set, the migration wizard will import from the corresponding
* migrator, bypassing the source-selection page. Otherwise, the
* source-selection page will be displayed, either with the default
* browser selected, if it could be detected and if there is a
@@ -890,60 +913,74 @@ this.MigrationUtils = Object.freeze({
* the OS we run on. See migration.xul).
* @param [optional] aProfileToMigrate
* If set, the migration wizard will import from the profile indicated.
* @throws if aMigratorKey is invalid or if it points to a non-existent
* source.
*/
startupMigration:
function MU_startupMigrator(aProfileStartup, aMigratorKey, aProfileToMigrate) {
+ if (Services.prefs.getBoolPref("browser.migrate.automigrate.enabled", false)) {
+ this.asyncStartupMigration(aProfileStartup,
+ aMigratorKey,
+ aProfileToMigrate);
+ } else {
+ this.spinResolve(this.asyncStartupMigration(aProfileStartup,
+ aMigratorKey,
+ aProfileToMigrate));
+ }
+ },
+
+ asyncStartupMigration:
+ async function MU_asyncStartupMigrator(aProfileStartup, aMigratorKey, aProfileToMigrate) {
if (!aProfileStartup) {
throw new Error("an profile-startup instance is required for startup-migration");
}
gProfileStartup = aProfileStartup;
let skipSourcePage = false, migrator = null, migratorKey = "";
if (aMigratorKey) {
- migrator = this.getMigrator(aMigratorKey);
+ migrator = await this.getMigrator(aMigratorKey);
if (!migrator) {
// aMigratorKey must point to a valid source, so, if it doesn't
// cleanup and throw.
this.finishMigration();
throw new Error("startMigration was asked to open auto-migrate from " +
"a non-existent source: " + aMigratorKey);
}
migratorKey = aMigratorKey;
skipSourcePage = true;
} else {
let defaultBrowserKey = this.getMigratorKeyForDefaultBrowser();
if (defaultBrowserKey) {
- migrator = this.getMigrator(defaultBrowserKey);
+ migrator = await this.getMigrator(defaultBrowserKey);
if (migrator)
migratorKey = defaultBrowserKey;
}
}
if (!migrator) {
+ let migrators = await Promise.all(gAvailableMigratorKeys.map(key => this.getMigrator(key)));
// If there's no migrator set so far, ensure that there is at least one
// migrator available before opening the wizard.
// Note that we don't need to check the default browser first, because
// if that one existed we would have used it in the block above this one.
- if (!gAvailableMigratorKeys.some(key => !!this.getMigrator(key))) {
+ if (!migrators.some(m => m)) {
// None of the keys produced a usable migrator, so finish up here:
this.finishMigration();
return;
}
}
let isRefresh = migrator && skipSourcePage &&
migratorKey == AppConstants.MOZ_APP_NAME;
if (!isRefresh && AutoMigrate.enabled) {
try {
- AutoMigrate.migrate(aProfileStartup, migratorKey, aProfileToMigrate);
+ await AutoMigrate.migrate(aProfileStartup, migratorKey, aProfileToMigrate);
return;
} catch (ex) {
// If automigration failed, continue and show the dialog.
Cu.reportError(ex);
}
}
let migrationEntryPoint = this.MIGRATION_ENTRYPOINT_FIRSTRUN;
--- a/browser/components/migration/SafariProfileMigrator.js
+++ b/browser/components/migration/SafariProfileMigrator.js
@@ -283,34 +283,16 @@ MainPreferencesPropertyList.prototype =
} catch (ex) {
Cu.reportError(ex);
}
}
this._callbacks.splice(0);
});
}
},
-
- // Workaround for nsIBrowserProfileMigrator.sourceHomePageURL until
- // it's replaced with an async method.
- _readSync: function MPPL__readSync() {
- if ("_dict" in this)
- return this._dict;
-
- let inputStream = Cc["@mozilla.org/network/file-input-stream;1"].
- createInstance(Ci.nsIFileInputStream);
- inputStream.init(this._file, -1, -1, 0);
- let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
- createInstance(Ci.nsIBinaryInputStream);
- binaryStream.setInputStream(inputStream);
- let bytes = binaryStream.readByteArray(inputStream.available());
- this._dict = PropertyListUtils._readFromArrayBufferSync(
- new Uint8Array(bytes).buffer);
- return this._dict;
- },
};
function SearchStrings(aMainPreferencesPropertyListInstance) {
this._mainPreferencesPropertyList = aMainPreferencesPropertyListInstance;
}
SearchStrings.prototype = {
type: MigrationUtils.resourceTypes.OTHERDATA,
@@ -397,24 +379,22 @@ Object.defineProperty(SafariProfileMigra
}
this._mainPreferencesPropertyList = null;
return this._mainPreferencesPropertyList;
}
return this._mainPreferencesPropertyList;
},
});
-Object.defineProperty(SafariProfileMigrator.prototype, "sourceHomePageURL", {
- get: function get_sourceHomePageURL() {
- if (this.mainPreferencesPropertyList) {
- let dict = this.mainPreferencesPropertyList._readSync();
- if (dict.has("HomePage"))
- return dict.get("HomePage");
- }
- return "";
- },
-});
+SafariProfileMigrator.prototype.getSourceHomePageURL = async function SM_getSourceHomePageURL() {
+ if (this.mainPreferencesPropertyList) {
+ let dict = await new Promise(resolve => this.mainPreferencesPropertyList.read(resolve));
+ if (dict.has("HomePage"))
+ return dict.get("HomePage");
+ }
+ return "";
+};
SafariProfileMigrator.prototype.classDescription = "Safari Profile Migrator";
SafariProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=safari";
SafariProfileMigrator.prototype.classID = Components.ID("{4b609ecf-60b2-4655-9df4-dc149e474da1}");
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SafariProfileMigrator]);
--- a/browser/components/migration/nsIBrowserProfileMigrator.idl
+++ b/browser/components/migration/nsIBrowserProfileMigrator.idl
@@ -33,45 +33,48 @@ interface nsIBrowserProfileMigrator : ns
void migrate(in unsigned short aItems, in nsIProfileStartup aStartup, in jsval aProfile);
/**
* A bit field containing profile items that this migrator
* offers for import.
* @param aProfile the profile that we are looking for available data
* to import
* @param aDoingStartup "true" if the profile is not currently being used.
- * @return bit field containing profile items (see above)
+ * @return Promise containing a bit field containing profile items (see above)
* @note a return value of 0 represents no items rather than ALL.
*/
- unsigned short getMigrateData(in jsval aProfile, in boolean aDoingStartup);
+ jsval getMigrateData(in jsval aProfile, in boolean aDoingStartup);
/**
* Get the last time data from this browser was modified
* @return a promise that resolves to a JS Date object
*/
jsval getLastUsedDate();
/**
- * Whether or not there is any data that can be imported from this
+ * Get whether or not there is any data that can be imported from this
* browser (i.e. whether or not it is installed, and there exists
* a user profile)
+ * @return a promise that resolves with a boolean.
*/
- readonly attribute boolean sourceExists;
+ jsval isSourceAvailable();
/**
* An enumeration of available profiles. If the import source does
* not support profiles, this attribute is null.
+ * @return a promise that resolves with an array of profiles or null.
*/
- readonly attribute jsval sourceProfiles;
+ jsval getSourceProfiles();
/**
* The import source homepage. Returns null if not present/available
+ * @return a promise that resolves with a string or null.
*/
- readonly attribute AUTF8String sourceHomePageURL;
+ jsval getSourceHomePageURL();
/**
* Whether the source browser data is locked/in-use meaning migration likely
* won't succeed and the user should be warned.
*/
readonly attribute boolean sourceLocked;
};