Bug 273874 - Firefox migrator for new profiles r=mak

--HG--
rename : browser/components/migration/src/ChromeProfileMigrator.js => browser/components/migration/src/FirefoxProfileMigrator.js
extra : rebase_source : d5dfea053ede5abb3a535296085bdfe93ece8511
This commit is contained in:
Matthew Noorenberghe 2011-11-29 02:30:40 -08:00
parent 96d9667774
commit e3d293ca55
10 changed files with 428 additions and 1 deletions

View File

@ -339,6 +339,9 @@ var MigrationWizard = {
case "chrome": case "chrome":
source = "sourceNameChrome"; source = "sourceNameChrome";
break; break;
case "firefox":
source = "sourceNameFirefox";
break;
} }
// semi-wallpaper for crash when multiple profiles exist, since we haven't initialized mSourceProfile in places // semi-wallpaper for crash when multiple profiles exist, since we haven't initialized mSourceProfile in places

View File

@ -76,6 +76,7 @@
#endif #endif
#endif #endif
<radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/> <radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/>
<radio id="firefox" label="&importFromFirefox.label;" accesskey="&importFromFirefox.accesskey;"/>
<radio id="fromfile" label="&importFromHTMLFile.label;" accesskey="&importFromHTMLFile.accesskey;" hidden="true"/> <radio id="fromfile" label="&importFromHTMLFile.label;" accesskey="&importFromHTMLFile.accesskey;" hidden="true"/>
<radio id="nothing" label="&importFromNothing.label;" accesskey="&importFromNothing.accesskey;" hidden="true"/> <radio id="nothing" label="&importFromNothing.label;" accesskey="&importFromNothing.accesskey;" hidden="true"/>
</radiogroup> </radiogroup>

View File

@ -1,2 +1,4 @@
component {4cec1de4-1671-4fc3-a53e-6c539dc77a26} ChromeProfileMigrator.js component {4cec1de4-1671-4fc3-a53e-6c539dc77a26} ChromeProfileMigrator.js
contract @mozilla.org/profile/migrator;1?app=browser&type=chrome {4cec1de4-1671-4fc3-a53e-6c539dc77a26} contract @mozilla.org/profile/migrator;1?app=browser&type=chrome {4cec1de4-1671-4fc3-a53e-6c539dc77a26}
component {91185366-ba97-4438-acba-48deaca63386} FirefoxProfileMigrator.js
contract @mozilla.org/profile/migrator;1?app=browser&type=firefox {91185366-ba97-4438-acba-48deaca63386}

View File

@ -0,0 +1,404 @@
/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 sts=2 et
* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/. */
/*
* Migrates from a Firefox profile in a lossy manner in order to clean up a user's profile. Data
* is only migrated where the benefits outweigh the potential problems caused by importing
* undesired/invalid configurations from the source profile.
*/
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
const MIGRATOR = Ci.nsIBrowserProfileMigrator;
const LOCAL_FILE_CID = "@mozilla.org/file/local;1";
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
function FirefoxProfileMigrator()
{
// profD is not available when the migrator is run during startup so use ProfDS.
this._paths.currentProfile = FileUtils.getDir("ProfDS", []);
}
FirefoxProfileMigrator.prototype = {
_paths: {
bookmarks : null,
cookies : null,
currentProfile: null, // The currently running (destination) profile.
encryptionKey: null,
history : null,
passwords: null,
},
_homepageURL : null,
_replaceBookmarks : false,
_sourceProfile: null,
_profilesCache: null,
/**
* Notify to observers to start migration
*
* @param aType
* notification type such as MIGRATOR.BOOKMARKS
*/
_notifyStart : function Firefox_notifyStart(aType)
{
Services.obs.notifyObservers(null, "Migration:ItemBeforeMigrate", aType);
this._pendingCount++;
},
/**
* Notify observers that a migration error occured with an item
*
* @param aType
* notification type such as MIGRATOR.BOOKMARKS
*/
_notifyError : function Firefox_notifyError(aType)
{
Services.obs.notifyObservers(null, "Migration:ItemError", aType);
},
/**
* Notify to observers to finish migration for item
* If all items are finished, it sends migration end notification.
*
* @param aType
* notification type such as MIGRATOR.BOOKMARKS
*/
_notifyCompleted : function Firefox_notifyIfCompleted(aType)
{
Services.obs.notifyObservers(null, "Migration:ItemAfterMigrate", aType);
if (--this._pendingCount == 0) {
// All items are migrated, so we have to send end notification.
Services.obs.notifyObservers(null, "Migration:Ended", null);
}
},
/**
* The directory used for bookmark backups
* @return directory of the bookmark backups
*/
get _bookmarks_backup_folder()
{
let bookmarksBackupRelativePath = PlacesUtils.backups.profileRelativeFolderPath;
let bookmarksBackupDir = this._sourceProfile.clone().QueryInterface(Ci.nsILocalFile);
bookmarksBackupDir.appendRelativePath(bookmarksBackupRelativePath);
return bookmarksBackupDir;
},
/**
* Migrating bookmark items
*/
_migrateBookmarks : function Firefox_migrateBookmarks()
{
this._notifyStart(MIGRATOR.BOOKMARKS);
try {
let srcBackupsDir = this._bookmarks_backup_folder;
let backupFolder = this._paths.currentProfile.clone();
backupFolder.append(srcBackupsDir.leafName);
if (!backupFolder.exists())
srcBackupsDir.copyTo(this._paths.currentProfile, null);
} catch (e) {
Cu.reportError(e);
// Don't notify about backup migration errors since actual bookmarks are
// migrated with history.
} finally {
this._notifyCompleted(MIGRATOR.BOOKMARKS);
}
},
/**
* Migrating history
*/
_migrateHistory : function Firefox_migrateHistory()
{
this._notifyStart(MIGRATOR.HISTORY);
try {
// access sqlite3 database of history
let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
file.initWithPath(this._paths.history);
file.copyTo(this._paths.currentProfile, null);
} catch (e) {
Cu.reportError(e);
this._notifyError(MIGRATOR.HISTORY);
} finally {
this._notifyCompleted(MIGRATOR.HISTORY);
}
},
/**
* Migrating cookies
*
* @note Cookie permissions are not migrated since they may be inadvertently set leading to
* website login problems.
*/
_migrateCookies : function Firefox_migrateCookies()
{
this._notifyStart(MIGRATOR.COOKIES);
try {
// Access sqlite3 database of cookies
let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
file.initWithPath(this._paths.cookies);
file.copyTo(this._paths.currentProfile, null);
} catch (e) {
Cu.reportError(e);
this._notifyError(MIGRATOR.COOKIES);
} finally {
this._notifyCompleted(MIGRATOR.COOKIES);
}
},
/**
* Migrating passwords
*/
_migratePasswords : function Firefox_migratePasswords()
{
this._notifyStart(MIGRATOR.PASSWORDS);
try {
// Access sqlite3 database of passwords
let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
file.initWithPath(this._paths.passwords);
file.copyTo(this._paths.currentProfile, null);
let encryptionKey = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
encryptionKey.initWithPath(this._paths.encryptionKey);
encryptionKey.copyTo(this._paths.currentProfile, null);
} catch (e) {
Cu.reportError(e);
this._notifyError(MIGRATOR.PASSWORDS);
} finally {
this._notifyCompleted(MIGRATOR.PASSWORDS);
}
},
/**
* nsIBrowserProfileMigrator interface implementation
*/
/**
* Let's migrate all items
*
* @param aItems
* list of data items to migrate.
* @param aStartup
* non-null if called during startup.
* @param aProfile
* profile directory path to migrate from
*/
migrate : function Firefox_migrate(aItems, aStartup, aProfile)
{
if (aStartup) {
aStartup.doStartup();
this._replaceBookmarks = true;
}
Services.obs.notifyObservers(null, "Migration:Started", null);
// Reset pending count. If this count becomes 0, "Migration:Ended"
// notification is sent
this._pendingCount = 1;
if (aItems & MIGRATOR.HISTORY)
this._migrateHistory();
if (aItems & MIGRATOR.COOKIES)
this._migrateCookies();
if (aItems & MIGRATOR.BOOKMARKS)
this._migrateBookmarks();
if (aItems & MIGRATOR.PASSWORDS)
this._migratePasswords();
if (--this._pendingCount == 0) {
// When async imports are immediately completed unfortunately,
// this will be called.
// Usually, this notification is sent by _notifyCompleted()
Services.obs.notifyObservers(null, "Migration:Ended", null);
}
},
/**
* return supported migration types
*
* @param aProfile
* the profile path to migrate from
* @param aDoingStartup
* non-null if called during startup.
* @return supported migration types
*
* @todo Bug 715315 - make sure source databases are not in-use
*/
getMigrateData: function Firefox_getMigrateData(aProfile, aDoingStartup)
{
this._sourceProfile = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
this._sourceProfile.initWithPath(aProfile);
let result = 0;
if (!this._sourceProfile.exists() || !this._sourceProfile.isReadable()) {
Cu.reportError("source profile directory doesn't exist or is not readable");
return result;
}
// Migration initiated from the UI is not supported.
if (!aDoingStartup)
return result;
// Bookmark backups in JSON format
try {
let file = this._bookmarks_backup_folder;
if (file.exists()) {
this._paths.bookmarks = file.path;
result += MIGRATOR.BOOKMARKS;
}
} catch (e) {
Cu.reportError(e);
}
// Bookmarks, history and favicons
try {
let file = this._sourceProfile.clone();
file.append("places.sqlite");
if (file.exists()) {
this._paths.history = file.path;
result += MIGRATOR.HISTORY;
result |= MIGRATOR.BOOKMARKS;
}
} catch (e) {
Cu.reportError(e);
}
// Cookies
try {
let file = this._sourceProfile.clone();
file.append("cookies.sqlite");
if (file.exists()) {
this._paths.cookies = file.path;
result += MIGRATOR.COOKIES;
}
} catch (e) {
Cu.reportError(e);
}
// Passwords & encryption key
try {
let passwords = this._sourceProfile.clone();
passwords.append("signons.sqlite");
let encryptionKey = this._sourceProfile.clone();
encryptionKey.append("key3.db");
if (passwords.exists() && encryptionKey.exists()) {
this._paths.passwords = passwords.path;
this._paths.encryptionKey = encryptionKey.path;
result += MIGRATOR.PASSWORDS;
}
} catch (e) {
Cu.reportError(e);
}
return result;
},
/**
* Whether we support migration of Firefox
*
* @return true if supported
*/
get sourceExists()
{
let userData = Services.dirsvc.get("DefProfRt", Ci.nsIFile).path;
let result = 0;
try {
let userDataDir = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
userDataDir.initWithPath(userData);
if (!userDataDir.exists() || !userDataDir.isReadable())
return false;
let profiles = this.sourceProfiles;
if (profiles.length < 1)
return false;
// Check that we can get data from at least one profile since profile selection has not
// happened yet.
for (let i = 0; i < profiles.length; i++) {
result = this.getMigrateData(profiles.queryElementAt(i, Ci.nsISupportsString), true);
if (result)
break;
}
} catch (e) {
Cu.reportError(e);
}
return result > 0;
},
get sourceHasMultipleProfiles()
{
return this.sourceProfiles.length > 1;
},
get sourceProfiles()
{
try
{
if (!this._profilesCache)
{
this._profilesCache = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
.getService(Ci.nsIToolkitProfileService);
// Only allow migrating from the default (selected) profile since this will be the only one
// returned by the toolkit profile service after bug 214675 has landed.
var profile = profileService.selectedProfile;
if (profile.rootDir.path === this._paths.currentProfile.path)
return null;
let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
str.data = profile.rootDir.path;
this._profilesCache.appendElement(str, false);
}
} catch (e) {
Cu.reportError("Error detecting Firefox profiles: " + e);
}
return this._profilesCache;
},
/**
* Return home page URL
*
* @return home page URL
*
* @todo Bug 715348 will migrate preferences such as the homepage
*/
get sourceHomePageURL()
{
try {
if (this._homepageURL)
return this._homepageURL;
} catch (e) {
Cu.reportError(e);
}
return "";
},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIBrowserProfileMigrator
]),
classDescription: "Firefox Profile Migrator",
contractID: "@mozilla.org/profile/migrator;1?app=browser&type=firefox",
classID: Components.ID("{91185366-ba97-4438-acba-48deaca63386}")
};
const NSGetFactory = XPCOMUtils.generateNSGetFactory([FirefoxProfileMigrator]);

View File

@ -65,6 +65,7 @@ endif
EXTRA_PP_COMPONENTS = \ EXTRA_PP_COMPONENTS = \
ChromeProfileMigrator.js \ ChromeProfileMigrator.js \
FirefoxProfileMigrator.js \
$(NULL) $(NULL)
EXTRA_COMPONENTS = \ EXTRA_COMPONENTS = \

View File

@ -140,6 +140,7 @@ NS_IMPL_ISUPPORTS1(nsProfileMigrator, nsIProfileMigrator)
#define INTERNAL_NAME_IEXPLORE "iexplore" #define INTERNAL_NAME_IEXPLORE "iexplore"
#define INTERNAL_NAME_MOZILLA_SUITE "apprunner" #define INTERNAL_NAME_MOZILLA_SUITE "apprunner"
#define INTERNAL_NAME_CHROME "chrome" #define INTERNAL_NAME_CHROME "chrome"
#define INTERNAL_NAME_FIREFOX "firefox"
#endif #endif
nsresult nsresult
@ -223,6 +224,10 @@ nsProfileMigrator::GetDefaultBrowserMigratorKey(nsACString& aKey,
aKey = "chrome"; aKey = "chrome";
return NS_OK; return NS_OK;
} }
else if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_FIREFOX)) {
aKey = "firefox";
return NS_OK;
}
#else #else
bool exists = false; bool exists = false;
@ -239,6 +244,7 @@ nsProfileMigrator::GetDefaultBrowserMigratorKey(nsACString& aKey,
CHECK_MIGRATOR("safari"); CHECK_MIGRATOR("safari");
#endif #endif
CHECK_MIGRATOR("chrome"); CHECK_MIGRATOR("chrome");
CHECK_MIGRATOR("firefox");
#undef CHECK_MIGRATOR #undef CHECK_MIGRATOR
#endif #endif

View File

@ -372,6 +372,7 @@
#endif #endif
@BINPATH@/components/BrowserProfileMigrators.manifest @BINPATH@/components/BrowserProfileMigrators.manifest
@BINPATH@/components/ChromeProfileMigrator.js @BINPATH@/components/ChromeProfileMigrator.js
@BINPATH@/components/FirefoxProfileMigrator.js
#ifdef XP_MACOSX #ifdef XP_MACOSX
@BINPATH@/components/libalerts_s.dylib @BINPATH@/components/libalerts_s.dylib
#endif #endif

View File

@ -13,6 +13,8 @@
<!ENTITY importFromSafari.accesskey "S"> <!ENTITY importFromSafari.accesskey "S">
<!ENTITY importFromChrome.label "Chrome"> <!ENTITY importFromChrome.label "Chrome">
<!ENTITY importFromChrome.accesskey "C"> <!ENTITY importFromChrome.accesskey "C">
<!ENTITY importFromFirefox.label "Firefox">
<!ENTITY importFromFirefox.accesskey "X">
<!ENTITY importFromHTMLFile.label "From an HTML File"> <!ENTITY importFromHTMLFile.label "From an HTML File">
<!ENTITY importFromHTMLFile.accesskey "F"> <!ENTITY importFromHTMLFile.accesskey "F">

View File

@ -4,6 +4,7 @@ profileName_format=%S %S
sourceNameIE=Internet Explorer sourceNameIE=Internet Explorer
sourceNameSafari=Safari sourceNameSafari=Safari
sourceNameChrome=Google Chrome sourceNameChrome=Google Chrome
sourceNameFirefox=Mozilla Firefox
importedBookmarksFolder=From %S importedBookmarksFolder=From %S
importedSearchURLsFolder=Keyword Searches (From %S) importedSearchURLsFolder=Keyword Searches (From %S)
@ -20,10 +21,12 @@ importedSafariBookmarks=From Safari
2_ie=Cookies 2_ie=Cookies
2_safari=Cookies 2_safari=Cookies
2_chrome=Cookies 2_chrome=Cookies
2_firefox=Cookies
4_ie=Browsing History 4_ie=Browsing History
4_safari=Browsing History 4_safari=Browsing History
4_chrome=Browsing History 4_chrome=Browsing History
4_firefox=Browsing History
8_ie=Saved Form History 8_ie=Saved Form History
8_safari=Saved Form History 8_safari=Saved Form History
@ -32,10 +35,12 @@ importedSafariBookmarks=From Safari
16_ie=Saved Passwords 16_ie=Saved Passwords
16_safari=Saved Passwords 16_safari=Saved Passwords
16_chrome=Saved Passwords 16_chrome=Saved Passwords
16_firefox=Saved Passwords
32_ie=Favorites 32_ie=Favorites
32_safari=Bookmarks 32_safari=Bookmarks
32_chrome=Bookmarks 32_chrome=Bookmarks
32_firefox=Bookmarks
64_ie=Other Data 64_ie=Other Data
64_safari=Other Data 64_safari=Other Data

View File

@ -1818,7 +1818,7 @@ var PlacesUtils = {
get folder() { get folder() {
let bookmarksBackupDir = Services.dirsvc.get("ProfD", Ci.nsILocalFile); let bookmarksBackupDir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
bookmarksBackupDir.append("bookmarkbackups"); bookmarksBackupDir.append(this.profileRelativeFolderPath);
if (!bookmarksBackupDir.exists()) { if (!bookmarksBackupDir.exists()) {
bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700); bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
if (!bookmarksBackupDir.exists()) if (!bookmarksBackupDir.exists())
@ -1828,6 +1828,8 @@ var PlacesUtils = {
return this.folder = bookmarksBackupDir; return this.folder = bookmarksBackupDir;
}, },
get profileRelativeFolderPath() "bookmarkbackups",
/** /**
* Cache current backups in a sorted (by date DESC) array. * Cache current backups in a sorted (by date DESC) array.
*/ */