Bug 674168 - support chrome multiple profile migration r=mak

--HG--
extra : rebase_source : fe0149f8df6328933c88128e83e28d3c06a5420c
This commit is contained in:
Matthew Noorenberghe 2011-11-21 14:45:54 -08:00
parent 58ded20f8a
commit f0bcb6d262
2 changed files with 101 additions and 32 deletions

View File

@ -68,7 +68,8 @@ interface nsIBrowserProfileMigrator : nsISupports
* @param aProfile the profile that we are looking for available data
* to import
* @param aDoingStartup "true" if the profile is not currently being used.
* @returns bit field containing profile items (see above)
* @return bit field containing profile items (see above)
* @note a return value of 0 represents no items rather than ALL.
*/
unsigned short getMigrateData(in wstring aProfile, in boolean aDoingStartup);

View File

@ -39,6 +39,7 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
const LOCAL_FILE_CID = "@mozilla.org/file/local;1";
const FILE_INPUT_STREAM_CID = "@mozilla.org/network/file-input-stream;1";
@ -129,10 +130,13 @@ ChromeProfileMigrator.prototype = {
cookies : null,
history : null,
prefs : null,
userData : null,
},
_homepageURL : null,
_replaceBookmarks : false,
_sourceProfile: null,
_profilesCache: null,
/**
* Notify to observers to start migration
@ -384,11 +388,11 @@ ChromeProfileMigrator.prototype = {
* Let's migrate all items
*
* @param aItems
* list of data items to migrate. but this is unused.
* list of data items to migrate.
* @param aStartup
* non-null if called during startup.
* @param aProfile
* this is unused due to single profile support only
* profile directory name to migrate
*/
migrate : function Chrome_migrate(aItems, aStartup, aProfile)
{
@ -397,6 +401,8 @@ ChromeProfileMigrator.prototype = {
this._replaceBookmarks = true;
}
this._sourceProfile = aProfile;
Services.obs.notifyObservers(null, "Migration:Started", null);
// Reset panding count. If this count becomes 0, "Migration:Ended"
@ -424,49 +430,47 @@ ChromeProfileMigrator.prototype = {
* return supported migration types
*
* @param aProfile
* this is unused due to single profile support only
* directory name of the profile
* @param aDoingStartup
* non-null if called during startup.
* @return supported migration types
*/
getMigrateData: function Chrome_getMigrateData(aProfile, aDoingStartup)
{
#ifdef XP_WIN
let chromepath = Services.dirsvc.get("LocalAppData", Ci.nsIFile).path +
"\\Google\\Chrome\\User Data\\Default\\";
#elifdef XP_MACOSX
let chromepath = Services.dirsvc.get("Home", Ci.nsIFile).path +
"/Library/Application Support/Google/Chrome/Default/";
#else
let chromepath = Services.dirsvc.get("Home", Ci.nsIFile).path +
"/.config/google-chrome/Default/";
#endif
this._sourceProfile = aProfile;
let chromeProfileDir = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
chromeProfileDir.initWithPath(this._paths.userData + aProfile);
let result = 0;
if (!chromeProfileDir.exists() || !chromeProfileDir.isReadable())
return result;
// bookmark and preference are JSON format
try {
let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
file.initWithPath(chromepath + "Bookmarks");
let file = chromeProfileDir.clone();
file.append("Bookmarks");
if (file.exists()) {
this._paths.bookmarks = file.path
this._paths.bookmarks = file.path;
result += MIGRATE_BOOKMARKS;
}
} catch (e) {
Cu.reportError(e);
}
if (!this._paths.prefs)
this._paths.prefs = chromepath + "Preferences";
if (!this._paths.prefs) {
let file = chromeProfileDir.clone();
file.append("Preferences");
this._paths.prefs = file.path;
}
// history and cookies are SQLite database
try {
let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
file.initWithPath(chromepath + "History");
let file = chromeProfileDir.clone();
file.append("History");
if (file.exists()) {
this._paths.history = file.path
this._paths.history = file.path;
result += MIGRATE_HISTORY;
}
} catch (e) {
@ -474,10 +478,10 @@ ChromeProfileMigrator.prototype = {
}
try {
let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
file.initWithPath(chromepath + "Cookies");
let file = chromeProfileDir.clone();
file.append("Cookies");
if (file.exists()) {
this._paths.cookies = file.path
this._paths.cookies = file.path;
result += MIGRATE_COOKIES;
}
} catch (e) {
@ -494,14 +498,78 @@ ChromeProfileMigrator.prototype = {
*/
get sourceExists()
{
let result = this.getMigrateData(null, false);
return result != 0;
#ifdef XP_WIN
this._paths.userData = Services.dirsvc.get("LocalAppData", Ci.nsIFile).path +
"\\Google\\Chrome\\User Data\\";
#elifdef XP_MACOSX
this._paths.userData = Services.dirsvc.get("Home", Ci.nsIFile).path +
"/Library/Application Support/Google/Chrome/";
#else
this._paths.userData = Services.dirsvc.get("Home", Ci.nsIFile).path +
"/.config/google-chrome/";
#endif
let result = 0;
try {
let userDataDir = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
userDataDir.initWithPath(this._paths.userData);
if (!userDataDir.exists() || !userDataDir.isReadable())
return false;
let profiles = this.sourceProfiles;
if (profiles.length < 1)
return false;
// check that we can actually get data from the first profile
result = this.getMigrateData(profiles.queryElementAt(0, Ci.nsISupportsString), false);
} catch (e) {
Cu.reportError(e);
}
return result > 0;
},
// Although Chrome supports multi-profiles, there is no way
// to get profile lists.
sourceHasMultipleProfiles: false,
sourceProfiles: null,
get sourceHasMultipleProfiles()
{
return this.sourceProfiles.length > 1;
},
get sourceProfiles()
{
let profiles = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
try {
if (!this._profilesCache) {
let localState = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
// Local State is a JSON file that contains profile info.
localState.initWithPath(this._paths.userData + "Local State");
if (!localState.exists())
throw new Components.Exception("Chrome's 'Local State' file does not exist.",
Cr.NS_ERROR_FILE_NOT_FOUND);
if (!localState.isReadable())
throw new Components.Exception("Chrome's 'Local State' file could not be read.",
Cr.NS_ERROR_FILE_ACCESS_DENIED);
let fstream = Cc[FILE_INPUT_STREAM_CID].createInstance(Ci.nsIFileInputStream);
fstream.init(localState, -1, 0, 0);
let inputStream = NetUtil.readInputStreamToString(fstream, fstream.available(),
{ charset: "UTF-8" });
this._profilesCache = JSON.parse(inputStream).profile.info_cache;
}
for (let index in this._profilesCache) {
let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
str.data = index;
profiles.appendElement(str, false);
}
} catch (e) {
Cu.reportError("Error detecting Chrome profiles: " + e);
// if we weren't able to detect any profiles above, fallback to the Default profile.
if (profiles.length < 1) {
let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
// the default profile name is "Default"
str.data = "Default";
profiles.appendElement(str, false);
}
}
return profiles;
},
/**
* Return home page URL
@ -515,7 +583,7 @@ ChromeProfileMigrator.prototype = {
return this._homepageURL;
if (!this._paths.prefs)
this.getMigrateData(null, false);
this.getMigrateData(this._sourceProfile, false);
// XXX reading and parsing JSON is synchronous.
let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);