Bug 477583 - Backups of bookmarks stops working if a future backup exists, r=mano

This commit is contained in:
Marco Bonardo 2009-09-29 12:44:18 +02:00
Родитель 9bddf793b1
Коммит dd2f545943
17 изменённых файлов: 526 добавлений и 424 удалений

Просмотреть файл

@ -53,12 +53,13 @@ Cu.import("resource:///modules/distribution.js");
const PREF_EM_NEW_ADDONS_LIST = "extensions.newAddons"; const PREF_EM_NEW_ADDONS_LIST = "extensions.newAddons";
// Check to see if bookmarks need backing up once per // We try to backup bookmarks at idle times, to avoid doing that at shutdown.
// day on 1 hour idle. // Number of idle seconds before trying to backup bookmarks. 15 minutes.
const BOOKMARKS_ARCHIVE_IDLE_TIME = 60 * 60; const BOOKMARKS_BACKUP_IDLE_TIME = 15 * 60;
// Minimum interval in milliseconds between backups.
// Backup bookmarks once every 24 hours. const BOOKMARKS_BACKUP_INTERVAL = 86400 * 1000;
const BOOKMARKS_ARCHIVE_INTERVAL = 86400 * 1000; // Maximum number of backups to create. Old ones will be purged.
const BOOKMARKS_BACKUP_MAX_BACKUPS = 10;
// Factory object // Factory object
const BrowserGlueServiceFactory = { const BrowserGlueServiceFactory = {
@ -76,29 +77,21 @@ const BrowserGlueServiceFactory = {
function BrowserGlue() { function BrowserGlue() {
this.__defineGetter__("_prefs", function() { XPCOMUtils.defineLazyServiceGetter(this, "_prefs",
delete this._prefs; "@mozilla.org/preferences-service;1",
return this._prefs = Cc["@mozilla.org/preferences-service;1"]. "nsIPrefBranch");
getService(Ci.nsIPrefBranch);
});
this.__defineGetter__("_bundleService", function() { XPCOMUtils.defineLazyServiceGetter(this, "_bundleService",
delete this._bundleService; "@mozilla.org/intl/stringbundle;1",
return this._bundleService = Cc["@mozilla.org/intl/stringbundle;1"]. "nsIStringBundleService");
getService(Ci.nsIStringBundleService);
});
this.__defineGetter__("_idleService", function() { XPCOMUtils.defineLazyServiceGetter(this, "_idleService",
delete this._idleService; "@mozilla.org/widget/idleservice;1",
return this._idleService = Cc["@mozilla.org/widget/idleservice;1"]. "nsIIdleService");
getService(Ci.nsIIdleService);
});
this.__defineGetter__("_observerService", function() { XPCOMUtils.defineLazyServiceGetter(this, "_observerService",
delete this._observerService; "@mozilla.org/observer-service;1",
return this._observerService = Cc['@mozilla.org/observer-service;1']. "nsIObserverService");
getService(Ci.nsIObserverService);
});
this._init(); this._init();
} }
@ -112,6 +105,10 @@ function BrowserGlue() {
BrowserGlue.prototype = { BrowserGlue.prototype = {
_saveSession: false, _saveSession: false,
_isIdleObserver: false,
_isPlacesInitObserver: false,
_isPlacesLockedObserver: false,
_isPlacesDatabaseLocked: false,
_setPrefToSaveSession: function() _setPrefToSaveSession: function()
{ {
@ -177,20 +174,21 @@ BrowserGlue.prototype = {
case "places-init-complete": case "places-init-complete":
this._initPlaces(); this._initPlaces();
this._observerService.removeObserver(this, "places-init-complete"); this._observerService.removeObserver(this, "places-init-complete");
this._isPlacesInitObserver = false;
// no longer needed, since history was initialized completely. // no longer needed, since history was initialized completely.
this._observerService.removeObserver(this, "places-database-locked"); this._observerService.removeObserver(this, "places-database-locked");
this._isPlacesLockedObserver = false;
break; break;
case "places-database-locked": case "places-database-locked":
this._isPlacesDatabaseLocked = true; this._isPlacesDatabaseLocked = true;
// stop observing, so further attempts to load history service // stop observing, so further attempts to load history service
// do not show the prompt. // do not show the prompt.
this._observerService.removeObserver(this, "places-database-locked"); this._observerService.removeObserver(this, "places-database-locked");
this._isPlacesLockedObserver = false;
break; break;
case "idle": case "idle":
if (this._idleService.idleTime > BOOKMARKS_ARCHIVE_IDLE_TIME * 1000) { if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000)
// Back up bookmarks. this._backupBookmarks();
this._archiveBookmarks();
}
break; break;
} }
}, },
@ -213,7 +211,9 @@ BrowserGlue.prototype = {
#endif #endif
osvr.addObserver(this, "session-save", false); osvr.addObserver(this, "session-save", false);
osvr.addObserver(this, "places-init-complete", false); osvr.addObserver(this, "places-init-complete", false);
this._isPlacesInitObserver = true;
osvr.addObserver(this, "places-database-locked", false); osvr.addObserver(this, "places-database-locked", false);
this._isPlacesLockedObserver = true;
}, },
// cleanup (called on application shutdown) // cleanup (called on application shutdown)
@ -227,12 +227,18 @@ BrowserGlue.prototype = {
osvr.removeObserver(this, "sessionstore-windows-restored"); osvr.removeObserver(this, "sessionstore-windows-restored");
osvr.removeObserver(this, "browser:purge-session-history"); osvr.removeObserver(this, "browser:purge-session-history");
osvr.removeObserver(this, "quit-application-requested"); osvr.removeObserver(this, "quit-application-requested");
osvr.removeObserver(this, "quit-application-granted");
#ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS #ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
osvr.removeObserver(this, "browser-lastwindow-close-requested"); osvr.removeObserver(this, "browser-lastwindow-close-requested");
osvr.removeObserver(this, "browser-lastwindow-close-granted"); osvr.removeObserver(this, "browser-lastwindow-close-granted");
#endif #endif
osvr.removeObserver(this, "quit-application-granted");
osvr.removeObserver(this, "session-save"); osvr.removeObserver(this, "session-save");
if (this._isIdleObserver)
this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
if (this._isPlacesInitObserver)
osvr.removeObserver(this, "places-init-complete");
if (this._isPlacesLockedObserver)
osvr.removeObserver(this, "places-database-locked");
}, },
_onAppDefaults: function() _onAppDefaults: function()
@ -288,7 +294,8 @@ BrowserGlue.prototype = {
_onProfileShutdown: function() _onProfileShutdown: function()
{ {
this._shutdownPlaces(); this._shutdownPlaces();
this._idleService.removeIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME); this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
this._isIdleObserver = false;
this.Sanitizer.onShutdown(); this.Sanitizer.onShutdown();
}, },
@ -592,8 +599,8 @@ BrowserGlue.prototype = {
restoreDefaultBookmarks = restoreDefaultBookmarks =
this._prefs.getBoolPref("browser.bookmarks.restore_default_bookmarks"); this._prefs.getBoolPref("browser.bookmarks.restore_default_bookmarks");
if (restoreDefaultBookmarks) { if (restoreDefaultBookmarks) {
// Ensure that we already have a bookmarks backup for today // Ensure that we already have a bookmarks backup for today.
this._archiveBookmarks(); this._backupBookmarks();
importBookmarks = true; importBookmarks = true;
} }
} catch(ex) {} } catch(ex) {}
@ -603,10 +610,10 @@ BrowserGlue.prototype = {
if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) { if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) {
// get latest JSON backup // get latest JSON backup
Cu.import("resource://gre/modules/utils.js"); Cu.import("resource://gre/modules/utils.js");
var bookmarksBackupFile = PlacesUtils.getMostRecentBackup(); var bookmarksBackupFile = PlacesUtils.backups.getMostRecent("json");
if (bookmarksBackupFile && bookmarksBackupFile.leafName.match("\.json$")) { if (bookmarksBackupFile) {
// restore from JSON backup // restore from JSON backup
PlacesUtils.restoreBookmarksFromJSONFile(bookmarksBackupFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(bookmarksBackupFile);
importBookmarks = false; importBookmarks = false;
} }
else { else {
@ -683,29 +690,29 @@ BrowserGlue.prototype = {
// Initialize bookmark archiving on idle. // Initialize bookmark archiving on idle.
// Once a day, either on idle or shutdown, bookmarks are backed up. // Once a day, either on idle or shutdown, bookmarks are backed up.
this._idleService.addIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME); if (!this._isIdleObserver) {
this._idleService.addIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
this._isIdleObserver = true;
}
}, },
/** /**
* Places shut-down tasks * Places shut-down tasks
* - back up and archive bookmarks * - back up bookmarks if needed.
* - export bookmarks as HTML, if so configured * - export bookmarks as HTML, if so configured.
* *
* Note: quit-application-granted notification is received twice * Note: quit-application-granted notification is received twice
* so replace this method with a no-op when first called. * so replace this method with a no-op when first called.
*/ */
_shutdownPlaces: function bg__shutdownPlaces() { _shutdownPlaces: function bg__shutdownPlaces() {
// Backup and archive Places bookmarks. this._backupBookmarks();
this._archiveBookmarks();
// Backup bookmarks to bookmarks.html to support apps that depend // Backup bookmarks to bookmarks.html to support apps that depend
// on the legacy format. // on the legacy format.
var autoExportHTML = false; var autoExportHTML = false;
try { try {
autoExportHTML = this._prefs.getBoolPref("browser.bookmarks.autoExportHTML"); autoExportHTML = this._prefs.getBoolPref("browser.bookmarks.autoExportHTML");
} catch(ex) { } catch(ex) { /* Don't export */ }
Components.utils.reportError(ex);
}
if (autoExportHTML) { if (autoExportHTML) {
Cc["@mozilla.org/browser/places/import-export-service;1"]. Cc["@mozilla.org/browser/places/import-export-service;1"].
@ -715,23 +722,24 @@ BrowserGlue.prototype = {
}, },
/** /**
* Back up and archive bookmarks * Backup bookmarks if needed.
*/ */
_archiveBookmarks: function nsBrowserGlue__archiveBookmarks() { _backupBookmarks: function nsBrowserGlue__backupBookmarks() {
Cu.import("resource://gre/modules/utils.js"); Cu.import("resource://gre/modules/utils.js");
var lastBackup = PlacesUtils.getMostRecentBackup(); let lastBackupFile = PlacesUtils.backups.getMostRecent();
// Backup bookmarks if there aren't any backups or // Backup bookmarks if there are no backups or the maximum interval between
// they haven't been backed up in the last 24 hrs. // backups elapsed.
if (!lastBackup || if (!lastBackupFile ||
Date.now() - lastBackup.lastModifiedTime > BOOKMARKS_ARCHIVE_INTERVAL) { new Date() - PlacesUtils.backups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL) {
var maxBackups = 5; let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS;
try { try {
maxBackups = this._prefs.getIntPref("browser.bookmarks.max_backups"); maxBackups = this._prefs.getIntPref("browser.bookmarks.max_backups");
} catch(ex) {} }
catch(ex) { /* Use default. */ }
PlacesUtils.archiveBookmarksFile(maxBackups, false /* don't force */); PlacesUtils.backups.create(maxBackups); // Don't force creation.
} }
}, },

Просмотреть файл

@ -423,54 +423,36 @@ var PlacesOrganizer = {
* Populates the restore menu with the dates of the backups available. * Populates the restore menu with the dates of the backups available.
*/ */
populateRestoreMenu: function PO_populateRestoreMenu() { populateRestoreMenu: function PO_populateRestoreMenu() {
var restorePopup = document.getElementById("fileRestorePopup"); let restorePopup = document.getElementById("fileRestorePopup");
var dateSvc = Cc["@mozilla.org/intl/scriptabledateformat;1"]. let dateSvc = Cc["@mozilla.org/intl/scriptabledateformat;1"].
getService(Ci.nsIScriptableDateFormat); getService(Ci.nsIScriptableDateFormat);
// remove existing menu items // Remove existing menu items. Last item is the restoreFromFile item.
// last item is the restoreFromFile item
while (restorePopup.childNodes.length > 1) while (restorePopup.childNodes.length > 1)
restorePopup.removeChild(restorePopup.firstChild); restorePopup.removeChild(restorePopup.firstChild);
// get list of files let backupFiles = PlacesUtils.backups.entries;
var localizedFilename = PlacesUtils.getString("bookmarksArchiveFilename"); if (backupFiles.length == 0)
var localizedFilenamePrefix = localizedFilename.substr(0, localizedFilename.indexOf("-"));
var fileList = [];
var files = this.bookmarksBackupDir.directoryEntries;
while (files.hasMoreElements()) {
var f = files.getNext().QueryInterface(Ci.nsIFile);
var rx = new RegExp("^(bookmarks|" + localizedFilenamePrefix +
")-([0-9]{4}-[0-9]{2}-[0-9]{2})\.json$");
if (!f.isHidden() && f.leafName.match(rx)) {
var date = f.leafName.match(rx)[2].replace(/-/g, "/");
var dateObj = new Date(date);
fileList.push({date: dateObj, filename: f.leafName});
}
}
fileList.sort(function PO_fileList_compare(a, b) {
return b.date - a.date;
});
if (fileList.length == 0)
return; return;
// populate menu // Populate menu with backups.
for (var i = 0; i < fileList.length; i++) { for (let i = 0; i < backupFiles.length; i++) {
var m = restorePopup.insertBefore let backupDate = PlacesUtils.backups.getDateForFile(backupFiles[i]);
(document.createElement("menuitem"), let m = restorePopup.insertBefore(document.createElement("menuitem"),
document.getElementById("restoreFromFile")); document.getElementById("restoreFromFile"));
m.setAttribute("label", m.setAttribute("label",
dateSvc.FormatDate("", dateSvc.FormatDate("",
Ci.nsIScriptableDateFormat.dateFormatLong, Ci.nsIScriptableDateFormat.dateFormatLong,
fileList[i].date.getFullYear(), backupDate.getFullYear(),
fileList[i].date.getMonth() + 1, backupDate.getMonth() + 1,
fileList[i].date.getDate())); backupDate.getDate()));
m.setAttribute("value", fileList[i].filename); m.setAttribute("value", backupFiles[i].leafName);
m.setAttribute("oncommand", m.setAttribute("oncommand",
"PlacesOrganizer.onRestoreMenuItemClick(this);"); "PlacesOrganizer.onRestoreMenuItemClick(this);");
} }
// Add the restoreFromFile item.
restorePopup.insertBefore(document.createElement("menuseparator"), restorePopup.insertBefore(document.createElement("menuseparator"),
document.getElementById("restoreFromFile")); document.getElementById("restoreFromFile"));
}, },
@ -479,14 +461,14 @@ var PlacesOrganizer = {
* Called when a menuitem is selected from the restore menu. * Called when a menuitem is selected from the restore menu.
*/ */
onRestoreMenuItemClick: function PO_onRestoreMenuItemClick(aMenuItem) { onRestoreMenuItemClick: function PO_onRestoreMenuItemClick(aMenuItem) {
var dirSvc = Cc["@mozilla.org/file/directory_service;1"]. let backupName = aMenuItem.getAttribute("value");
getService(Ci.nsIProperties); let backupFiles = PlacesUtils.backups.entries;
var bookmarksFile = dirSvc.get("ProfD", Ci.nsIFile); for (let i = 0; i < backupFiles.length; i++) {
bookmarksFile.append("bookmarkbackups"); if (backupFiles[i].leafName == backupName) {
bookmarksFile.append(aMenuItem.getAttribute("value")); this.restoreBookmarksFromFile(backupFiles[i]);
if (!bookmarksFile.exists()) break;
return; }
this.restoreBookmarksFromFile(bookmarksFile); }
}, },
/** /**
@ -529,7 +511,7 @@ var PlacesOrganizer = {
return; return;
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(aFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(aFile);
} }
catch(ex) { catch(ex) {
this._showErrorAlert(PlacesUIUtils.getString("bookmarksRestoreParseError")); this._showErrorAlert(PlacesUIUtils.getString("bookmarksRestoreParseError"));
@ -562,30 +544,10 @@ var PlacesOrganizer = {
var backupsDir = dirSvc.get("Desk", Ci.nsILocalFile); var backupsDir = dirSvc.get("Desk", Ci.nsILocalFile);
fp.displayDirectory = backupsDir; fp.displayDirectory = backupsDir;
fp.defaultString = PlacesUtils.getBackupFilename(); fp.defaultString = PlacesUtils.backups.getFilenameForDate();
if (fp.show() != Ci.nsIFilePicker.returnCancel) { if (fp.show() != Ci.nsIFilePicker.returnCancel)
PlacesUtils.backupBookmarksToFile(fp.file); PlacesUtils.backups.saveBookmarksToJSONFile(fp.file);
// copy new backup to /backups dir (bug 424389)
var latestBackup = PlacesUtils.getMostRecentBackup();
if (!latestBackup || latestBackup != fp.file) {
latestBackup.remove(false);
var name = PlacesUtils.getBackupFilename();
fp.file.copyTo(this.bookmarksBackupDir, name);
}
}
},
get bookmarksBackupDir() {
delete this.bookmarksBackupDir;
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
var bookmarksBackupDir = dirSvc.get("ProfD", Ci.nsIFile);
bookmarksBackupDir.append("bookmarkbackups");
if (!bookmarksBackupDir.exists())
bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
return this.bookmarksBackupDir = bookmarksBackupDir;
}, },
_paneDisabled: false, _paneDisabled: false,

Просмотреть файл

@ -157,10 +157,14 @@ const FILENAME_BOOKMARKS_HTML = "bookmarks.html";
let backup_date = new Date().toLocaleFormat("%Y-%m-%d"); let backup_date = new Date().toLocaleFormat("%Y-%m-%d");
const FILENAME_BOOKMARKS_JSON = "bookmarks-" + backup_date + ".json"; const FILENAME_BOOKMARKS_JSON = "bookmarks-" + backup_date + ".json";
// Smart bookmarks constants // Smart bookmarks constants.
const SMART_BOOKMARKS_VERSION = 2; const SMART_BOOKMARKS_VERSION = 2;
const SMART_BOOKMARKS_ON_TOOLBAR = 1; const SMART_BOOKMARKS_ON_TOOLBAR = 1;
const SMART_BOOKMARKS_ON_MENU = 2; const SMART_BOOKMARKS_ON_MENU = 3; // Takes in count the additional separator.
// Default bookmarks constants.
const DEFAULT_BOOKMARKS_ON_TOOLBAR = 2;
const DEFAULT_BOOKMARKS_ON_MENU = 3;
/** /**
* Creates a bookmarks.html file in the profile folder from a given source file. * Creates a bookmarks.html file in the profile folder from a given source file.

Просмотреть файл

@ -99,11 +99,11 @@ function run_test() {
// 3. import bookmarks.exported.json // 3. import bookmarks.exported.json
// 4. run the test-suite // 4. run the test-suite
try { try {
PlacesUtils.backupBookmarksToFile(jsonFile); PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't export to file: " + ex); } } catch(ex) { do_throw("couldn't export to file: " + ex); }
LOG("exported json"); LOG("exported json");
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); } } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
LOG("imported json"); LOG("imported json");
validate(); validate();

Просмотреть файл

@ -80,10 +80,10 @@ var tests = [
run: function () { run: function () {
this.file = createFile("bookmarks-test_restoreNotification.json"); this.file = createFile("bookmarks-test_restoreNotification.json");
addBookmarks(); addBookmarks();
PlacesUtils.backupBookmarksToFile(this.file); PlacesUtils.backups.saveBookmarksToJSONFile(this.file);
remove_all_bookmarks(); remove_all_bookmarks();
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(this.file); PlacesUtils.backups.restoreBookmarksFromJSONFile(this.file);
} }
catch (e) { catch (e) {
do_throw(" Restore should not have failed"); do_throw(" Restore should not have failed");
@ -100,7 +100,7 @@ var tests = [
run: function () { run: function () {
this.file = createFile("bookmarks-test_restoreNotification.json"); this.file = createFile("bookmarks-test_restoreNotification.json");
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(this.file); PlacesUtils.backups.restoreBookmarksFromJSONFile(this.file);
} }
catch (e) { catch (e) {
do_throw(" Restore should not have failed"); do_throw(" Restore should not have failed");
@ -118,7 +118,7 @@ var tests = [
this.file = dirSvc.get("ProfD", Ci.nsILocalFile); this.file = dirSvc.get("ProfD", Ci.nsILocalFile);
this.file.append("this file doesn't exist because nobody created it"); this.file.append("this file doesn't exist because nobody created it");
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(this.file); PlacesUtils.backups.restoreBookmarksFromJSONFile(this.file);
do_throw(" Restore should have failed"); do_throw(" Restore should have failed");
} }
catch (e) {} catch (e) {}

Просмотреть файл

@ -82,9 +82,9 @@ tests.push({
os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null); os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null);
// Count items on toolbar. // Count items on toolbar.
do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR); do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR);
// Count items on menu (+1 for the separator). // Count items on menu (+1 for the separator).
do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + 1); do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU);
// Check version has been updated. // Check version has been updated.
do_check_eq(ps.getIntPref(PREF_SMART_BOOKMARKS_VERSION), SMART_BOOKMARKS_VERSION); do_check_eq(ps.getIntPref(PREF_SMART_BOOKMARKS_VERSION), SMART_BOOKMARKS_VERSION);
@ -113,9 +113,9 @@ tests.push({
os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null); os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null);
// Count items on toolbar. // Count items on toolbar.
do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR); do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR);
// Count items on menu (+1 for the separator). // Count items on menu (+1 for the separator).
do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + 1); do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU);
// check smart bookmark has been replaced, itemId has changed. // check smart bookmark has been replaced, itemId has changed.
itemId = bs.getIdForItemAt(bs.toolbarFolder, 0); itemId = bs.getIdForItemAt(bs.toolbarFolder, 0);
@ -138,15 +138,15 @@ tests.push({
// Set preferences. // Set preferences.
ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 1); ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 1);
// Remove toolbar's smart bookmarks // Remove toolbar's smart bookmarks
bs.removeFolderChildren(bs.toolbarFolder); bs.removeItem(bs.getIdForItemAt(bs.toolbarFolder, 0));
// Force nsBrowserGlue::_initPlaces(). // Force nsBrowserGlue::_initPlaces().
os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null); os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null);
// Count items on toolbar, we should not have recreated the smart bookmark. // Count items on toolbar, we should not have recreated the smart bookmark.
do_check_eq(countFolderChildren(bs.toolbarFolder), 0); do_check_eq(countFolderChildren(bs.toolbarFolder), DEFAULT_BOOKMARKS_ON_TOOLBAR);
// Count items on menu (+1 for the separator). // Count items on menu (+1 for the separator).
do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + 1); do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU);
// Check version has been updated. // Check version has been updated.
do_check_eq(ps.getIntPref(PREF_SMART_BOOKMARKS_VERSION), SMART_BOOKMARKS_VERSION); do_check_eq(ps.getIntPref(PREF_SMART_BOOKMARKS_VERSION), SMART_BOOKMARKS_VERSION);
@ -167,9 +167,9 @@ tests.push({
os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null); os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null);
// Count items on toolbar, we should not have recreated the smart bookmark. // Count items on toolbar, we should not have recreated the smart bookmark.
do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR); do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR);
// Count items on menu (+1 for the separator). // Count items on menu (+1 for the separator).
do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + 1); do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU);
// Check version has been updated. // Check version has been updated.
do_check_eq(ps.getIntPref(PREF_SMART_BOOKMARKS_VERSION), SMART_BOOKMARKS_VERSION); do_check_eq(ps.getIntPref(PREF_SMART_BOOKMARKS_VERSION), SMART_BOOKMARKS_VERSION);
@ -193,23 +193,19 @@ function countFolderChildren(aFolderItemId) {
function finish_test() { function finish_test() {
// Clean up database from all bookmarks. // Clean up database from all bookmarks.
remove_all_bookmarks(); remove_all_bookmarks();
// Simulate application closing to remove the idle observer and avoid leaks.
os.notifyObservers(null, "quit-application-granted", null);
do_test_finished(); do_test_finished();
} }
var testIndex = 0; var testIndex = 0;
function next_test() { function next_test() {
// Simulate application closing to remove the idle observer and avoid leaks.
os.notifyObservers(null, "quit-application-granted", null);
// nsBrowserGlue stops observing topics after first notification, // nsBrowserGlue stops observing topics after first notification,
// so we add back the observer to test additional runs. // so we add back the observer to test additional runs.
os.addObserver(bg, TOPIC_PLACES_INIT_COMPLETE, false); os.addObserver(bg, TOPIC_PLACES_INIT_COMPLETE, false);
// Execute next test. // Execute next test.
var test = tests.shift(); let test = tests.shift();
dump("\nTEST " + (++testIndex) + ": " + test.description); print("\nTEST " + (++testIndex) + ": " + test.description);
test.exec(); test.exec();
} }

Просмотреть файл

@ -159,6 +159,12 @@ var PlacesUtils = {
getService(Ci.nsITaggingService); getService(Ci.nsITaggingService);
}, },
get observerSvc() {
delete this.observerSvc;
return this.observerSvc = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
},
/** /**
* Makes a URI from a spec. * Makes a URI from a spec.
* @param aSpec * @param aSpec
@ -278,9 +284,7 @@ var PlacesUtils = {
this.annotations.addObserver(this, false); this.annotations.addObserver(this, false);
// observe shutdown, so we can remove the anno observer // observe shutdown, so we can remove the anno observer
const os = Cc["@mozilla.org/observer-service;1"]. this.observerSvc.addObserver(this, "xpcom-shutdown", false);
getService(Ci.nsIObserverService);
os.addObserver(this, "xpcom-shutdown", false);
var readOnly = this.annotations.getItemsWithAnnotation(READ_ONLY_ANNO, {}); var readOnly = this.annotations.getItemsWithAnnotation(READ_ONLY_ANNO, {});
this.__defineGetter__("_readOnly", function() readOnly); this.__defineGetter__("_readOnly", function() readOnly);
@ -294,9 +298,7 @@ var PlacesUtils = {
observe: function PU_observe(aSubject, aTopic, aData) { observe: function PU_observe(aSubject, aTopic, aData) {
if (aTopic == "xpcom-shutdown") { if (aTopic == "xpcom-shutdown") {
this.annotations.removeObserver(this); this.annotations.removeObserver(this);
const os = Cc["@mozilla.org/observer-service;1"]. this.observerSvc.removeObserver(this, "xpcom-shutdown");
getService(Ci.nsIObserverService);
os.removeObserver(this, "xpcom-shutdown");
} }
}, },
@ -1170,62 +1172,6 @@ var PlacesUtils = {
return urls; return urls;
}, },
/**
* Restores bookmarks/tags from a JSON file.
* WARNING: This method *removes* any bookmarks in the collection before
* restoring from the file.
*
* @param aFile
* nsIFile of bookmarks in JSON format to be restored.
*/
restoreBookmarksFromJSONFile:
function PU_restoreBookmarksFromJSONFile(aFile) {
var failed = false;
var obsServ = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
obsServ.notifyObservers(null,
RESTORE_BEGIN_NSIOBSERVER_TOPIC,
RESTORE_NSIOBSERVER_DATA);
try {
// open file stream
var stream = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
stream.init(aFile, 0x01, 0, 0);
var converted = Cc["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Ci.nsIConverterInputStream);
converted.init(stream, "UTF-8", 8192,
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
// read in contents
var str = {};
var jsonStr = "";
while (converted.readString(8192, str) != 0)
jsonStr += str.value;
converted.close();
if (jsonStr.length == 0)
return; // empty file
this.restoreBookmarksFromJSONString(jsonStr, true);
}
catch (exc) {
failed = true;
obsServ.notifyObservers(null,
RESTORE_FAILED_NSIOBSERVER_TOPIC,
RESTORE_NSIOBSERVER_DATA);
Components.utils.reportError("Bookmarks JSON restore failed: " + exc);
throw exc;
}
finally {
if (!failed) {
obsServ.notifyObservers(null,
RESTORE_SUCCESS_NSIOBSERVER_TOPIC,
RESTORE_NSIOBSERVER_DATA);
}
}
},
/** /**
* Import bookmarks from a JSON string. * Import bookmarks from a JSON string.
* Note: any item annotated with "places/excludeFromBackup" won't be removed * Note: any item annotated with "places/excludeFromBackup" won't be removed
@ -1702,7 +1648,119 @@ var PlacesUtils = {
}, },
/** /**
* backupBookmarksToFile() * Helper to create and manage backups.
*/
backups: {
get _filenamesRegex() {
// Get the localized backup filename, will be used to clear out
// old backups with a localized name (bug 445704).
let localizedFilename =
PlacesUtils.getFormattedString("bookmarksArchiveFilename", [new Date()]);
let localizedFilenamePrefix =
localizedFilename.substr(0, localizedFilename.indexOf("-"));
delete this._filenamesRegex;
return this._filenamesRegex =
new RegExp("^(bookmarks|" + localizedFilenamePrefix + ")-([0-9-]+)\.(json|html)");
},
get folder() {
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
let bookmarksBackupDir = dirSvc.get("ProfD", Ci.nsILocalFile);
bookmarksBackupDir.append("bookmarkbackups");
if (!bookmarksBackupDir.exists()) {
bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
if (!bookmarksBackupDir.exists())
throw("Unable to create bookmarks backup folder");
}
delete this.folder;
return this.folder = bookmarksBackupDir;
},
/**
* Cache current backups in a sorted (by date DESC) array.
*/
get entries() {
delete this.entries;
this.entries = [];
let files = this.folder.directoryEntries;
while (files.hasMoreElements()) {
let entry = files.getNext().QueryInterface(Ci.nsIFile);
// A valid backup is any file that matches either the localized or
// not-localized filename (bug 445704).
let matches = entry.leafName.match(this._filenamesRegex);
if (!entry.isHidden() && matches) {
// Remove bogus backups in future dates.
if (this.getDateForFile(entry) > new Date()) {
entry.remove(false);
continue;
}
this.entries.push(entry);
}
}
this.entries.sort(function compare(a, b) {
aDate = PlacesUtils.backups.getDateForFile(a);
bDate = PlacesUtils.backups.getDateForFile(b);
return aDate < bDate ? 1 : aDate > bDate ? -1 : 0;
});
return this.entries;
},
/**
* Creates a filename for bookmarks backup files.
*
* @param [optional] aDateObj
* Date object used to build the filename.
* Will use current date if empty.
* @return A bookmarks backup filename.
*/
getFilenameForDate:
function PU_B_getFilenameForDate(aDateObj) {
let dateObj = aDateObj || new Date();
// Use YYYY-MM-DD (ISO 8601) as it doesn't contain illegal characters
// and makes the alphabetical order of multiple backup files more useful.
return "bookmarks-" + dateObj.toLocaleFormat("%Y-%m-%d") + ".json";
},
/**
* Creates a Date object from a backup file. The date is the backup
* creation date.
*
* @param aBackupFile
* nsIFile of the backup.
* @return A Date object for the backup's creation time.
*/
getDateForFile:
function PU_B_getDateForFile(aBackupFile) {
let filename = aBackupFile.leafName;
let matches = filename.match(this._filenamesRegex);
if (!matches)
do_throw("Invalid backup file name: " + filename);
return new Date(matches[2].replace(/-/g, "/"));
},
/**
* Get the most recent backup file.
*
* @param [optional] aFileExt
* Force file extension. Either "html" or "json".
* Will check for both if not defined.
* @returns nsIFile backup file
*/
getMostRecent:
function PU__B_getMostRecent(aFileExt) {
let fileExt = aFileExt || "(json|html)";
for (let i = 0; i < this.entries.length; i++) {
let rx = new RegExp("\." + fileExt + "$");
if (this.entries[i].leafName.match(rx))
return this.entries[i];
}
return null;
},
/**
* saveBookmarksToJSONFile()
* *
* Serializes bookmarks using JSON, and writes to the supplied file. * Serializes bookmarks using JSON, and writes to the supplied file.
* Note: any item that should not be backed up must be annotated with * Note: any item that should not be backed up must be annotated with
@ -1711,188 +1769,197 @@ var PlacesUtils = {
* @param aFile * @param aFile
* nsIFile where to save JSON backup. * nsIFile where to save JSON backup.
*/ */
backupBookmarksToFile: function PU_backupBookmarksToFile(aFile) { saveBookmarksToJSONFile:
if (aFile.exists() && !aFile.isWritable()) function PU_B_saveBookmarksToFile(aFile) {
return; // XXX if (!aFile.exists())
aFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
if (!aFile.exists() || !aFile.isWritable()) {
Cu.reportError("Unable to create bookmarks backup file: " + aFile.leafName);
return;
}
// init stream this._writeBackupFile(aFile);
var stream = Cc["@mozilla.org/network/file-output-stream;1"].
if (aFile.parent.equals(this.folder)) {
// Update internal cache.
this.entries.push(aFile);
}
else {
// If we are saving to a folder different than our backups folder, then
// we also want to copy this new backup to it.
// This way we ensure the latest valid backup is the same saved by the
// user. See bug 424389.
var latestBackup = this.getMostRecent("json");
if (!latestBackup || latestBackup != aFile) {
let name = this.getFilenameForDate();
let file = this.folder.clone();
file.append(name);
if (file.exists())
file.remove(false);
else {
// Update internal cache if we are not replacing an existing
// backup file.
this.entries.push(file);
}
aFile.copyTo(this.folder, name);
}
}
},
_writeBackupFile:
function PU_B__writeBackupFile(aFile) {
// Init stream.
let stream = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream); createInstance(Ci.nsIFileOutputStream);
stream.init(aFile, 0x02 | 0x08 | 0x20, 0600, 0); stream.init(aFile, 0x02 | 0x08 | 0x20, 0600, 0);
// utf-8 converter stream // UTF-8 converter stream.
var converter = Cc["@mozilla.org/intl/converter-output-stream;1"]. let converter = Cc["@mozilla.org/intl/converter-output-stream;1"].
createInstance(Ci.nsIConverterOutputStream); createInstance(Ci.nsIConverterOutputStream);
converter.init(stream, "UTF-8", 0, 0x0000); converter.init(stream, "UTF-8", 0, 0x0000);
// weep over stream interface variance // Weep over stream interface variance.
var streamProxy = { let streamProxy = {
converter: converter, converter: converter,
write: function(aData, aLen) { write: function(aData, aLen) {
this.converter.writeString(aData); this.converter.writeString(aData);
} }
}; };
// Get itemIds to be exluded from the backup // Get list of itemIds that must be exluded from the backup.
var excludeItems = this.annotations let excludeItems =
.getItemsWithAnnotation(EXCLUDE_FROM_BACKUP_ANNO, {}); PlacesUtils.annotations.getItemsWithAnnotation(EXCLUDE_FROM_BACKUP_ANNO, {});
// query places root // Query the Places root.
var options = this.history.getNewQueryOptions(); let options = PlacesUtils.history.getNewQueryOptions();
options.expandQueries = false; options.expandQueries = false;
var query = this.history.getNewQuery(); let query = PlacesUtils.history.getNewQuery();
query.setFolders([this.placesRootId], 1); query.setFolders([PlacesUtils.placesRootId], 1);
var result = this.history.executeQuery(query, options); let root = PlacesUtils.history.executeQuery(query, options).root;
result.root.containerOpen = true; root.containerOpen = true;
// serialize as JSON, write to stream // Serialize to JSON and write to stream.
this.serializeNodeAsJSONToOutputStream(result.root, streamProxy, PlacesUtils.serializeNodeAsJSONToOutputStream(root, streamProxy,
false, false, excludeItems); false, false, excludeItems);
result.root.containerOpen = false; root.containerOpen = false;
// close converter and stream // Close converter and stream.
converter.close(); converter.close();
stream.close(); stream.close();
}, },
/** /**
* Creates a filename for bookmarks backup files. * create()
* *
* @param [optional] aDateObj Date object used to build the filename. * Creates a dated backup in <profile>/bookmarkbackups.
* Will use current date if empty.
* @return A bookmarks backup filename.
*/
getBackupFilename:
function PU_getBackupFilename(aDateObj) {
if (!aDateObj)
aDateObj = new Date();
// Use YYYY-MM-DD (ISO 8601) as it doesn't contain illegal characters
// and makes the alphabetical order of multiple backup files more useful.
var date = aDateObj.toLocaleFormat("%Y-%m-%d");
return "bookmarks-" + date + ".json";
},
/**
* ArchiveBookmarksFile()
*
* Creates a dated backup once a day in <profile>/bookmarkbackups.
* Stores the bookmarks using JSON. * Stores the bookmarks using JSON.
* Note: any item that should not be backed up must be annotated with * Note: any item that should not be backed up must be annotated with
* "places/excludeFromBackup". * "places/excludeFromBackup".
* *
* @param int aNumberOfBackups - the maximum number of backups to keep * @param [optional] int aMaxBackups
* The maximum number of backups to keep.
* *
* @param bool aForceArchive - forces creating an archive even if one was * @param [optional] bool aForceBackup
* already created that day (overwrites) * Forces creating a backup even if one was already
* created that day (overwrites).
*/ */
archiveBookmarksFile: create:
function PU_archiveBookmarksFile(aNumberOfBackups, aForceArchive) { function PU_B_create(aMaxBackups, aForceBackup) {
// get/create backups directory
var dirService = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
var bookmarksBackupDir = dirService.get("ProfD", Ci.nsILocalFile);
bookmarksBackupDir.append("bookmarkbackups");
if (!bookmarksBackupDir.exists()) {
bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
if (!bookmarksBackupDir.exists())
return; // unable to create directory!
}
// Construct the new leafname. // Construct the new leafname.
var date = new Date(); let newBackupFilename = this.getFilenameForDate();
var backupFilename = this.getBackupFilename(date); let mostRecentBackupFile = this.getMostRecent();
var backupFile = null;
if (!aForceArchive) {
var backupFileNames = [];
var backupFilenamePrefix = backupFilename.substr(0, backupFilename.indexOf("-"));
// Get the localized backup filename, to clear out if (!aForceBackup) {
// old backups with a localized name (bug 445704). let numberOfBackupsToDelete = 0;
var localizedFilename = this.getFormattedString("bookmarksArchiveFilename", [date]); if (aMaxBackups !== undefined && aMaxBackups > -1)
var localizedFilenamePrefix = localizedFilename.substr(0, localizedFilename.indexOf("-")); numberOfBackupsToDelete = this.entries.length - aMaxBackups;
var rx = new RegExp("^(bookmarks|" + localizedFilenamePrefix + ")-([0-9-]+)\.(json|html)");
var entries = bookmarksBackupDir.directoryEntries;
while (entries.hasMoreElements()) {
var entry = entries.getNext().QueryInterface(Ci.nsIFile);
var backupName = entry.leafName;
// A valid backup is any file that matches either the localized or
// not-localized filename (bug 445704).
var matches = backupName.match(rx);
if (matches) {
if (backupName == backupFilename)
backupFile = entry;
backupFileNames.push({ filename: backupName, date: matches[2] });
}
}
var numberOfBackupsToDelete = 0;
if (aNumberOfBackups > -1)
numberOfBackupsToDelete = backupFileNames.length - aNumberOfBackups;
if (numberOfBackupsToDelete > 0) { if (numberOfBackupsToDelete > 0) {
// If we don't have today's backup, remove one more so that // If we don't have today's backup, remove one more so that
// the total backups after this operation does not exceed the // the total backups after this operation does not exceed the
// number specified in the pref. // number specified in the pref.
if (!backupFile) if (!mostRecentBackupFile ||
mostRecentBackupFile.leafName != newBackupFilename)
numberOfBackupsToDelete++; numberOfBackupsToDelete++;
backupFileNames.sort(function compare(a, b) {
return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
});
while (numberOfBackupsToDelete--) { while (numberOfBackupsToDelete--) {
let backupFile = bookmarksBackupDir.clone(); let oldestBackup = this.entries.pop();
backupFile.append(backupFileNames[0].filename); oldestBackup.remove(false);
backupFile.remove(false);
backupFileNames.shift();
} }
} }
// do nothing if we either have today's backup already // Do nothing if we already have this backup or we don't want backups.
// or the user has set the pref to zero. if (aMaxBackups === 0 ||
if (backupFile || aNumberOfBackups == 0) (mostRecentBackupFile &&
mostRecentBackupFile.leafName == newBackupFilename))
return; return;
} }
backupFile = bookmarksBackupDir.clone(); let newBackupFile = this.folder.clone();
backupFile.append(backupFilename); newBackupFile.append(newBackupFilename);
if (aForceArchive && backupFile.exists()) if (aForceBackup && newBackupFile.exists())
backupFile.remove(false); newBackupFile.remove(false);
if (!backupFile.exists()) if (newBackupFile.exists())
backupFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0600); return;
this.backupBookmarksToFile(backupFile); this.saveBookmarksToJSONFile(newBackupFile);
}, },
/** /**
* Get the most recent backup file. * Restores bookmarks and tags from a JSON file.
* @returns nsIFile backup file * WARNING: This method *removes* any bookmarks in the collection before
* restoring from the file.
*
* @param aFile
* nsIFile of bookmarks in JSON format to be restored.
*/ */
getMostRecentBackup: function PU_getMostRecentBackup() { restoreBookmarksFromJSONFile:
var dirService = Cc["@mozilla.org/file/directory_service;1"]. function PU_B_restoreBookmarksFromJSONFile(aFile) {
getService(Ci.nsIProperties); let failed = false;
var bookmarksBackupDir = dirService.get("ProfD", Ci.nsILocalFile); PlacesUtils.observerSvc.notifyObservers(null,
bookmarksBackupDir.append("bookmarkbackups"); RESTORE_BEGIN_NSIOBSERVER_TOPIC,
if (!bookmarksBackupDir.exists()) RESTORE_NSIOBSERVER_DATA);
return null;
var backups = []; try {
var entries = bookmarksBackupDir.directoryEntries; // open file stream
while (entries.hasMoreElements()) { var stream = Cc["@mozilla.org/network/file-input-stream;1"].
var entry = entries.getNext().QueryInterface(Ci.nsIFile); createInstance(Ci.nsIFileInputStream);
if (!entry.isHidden() && entry.leafName.match(/^bookmarks-.+(html|json)?$/)) stream.init(aFile, 0x01, 0, 0);
backups.push(entry.leafName); var converted = Cc["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Ci.nsIConverterInputStream);
converted.init(stream, "UTF-8", 8192,
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
// read in contents
var str = {};
var jsonStr = "";
while (converted.readString(8192, str) != 0)
jsonStr += str.value;
converted.close();
if (jsonStr.length == 0)
return; // empty file
PlacesUtils.restoreBookmarksFromJSONString(jsonStr, true);
}
catch (exc) {
failed = true;
PlacesUtils.observerSvc.notifyObservers(null,
RESTORE_FAILED_NSIOBSERVER_TOPIC,
RESTORE_NSIOBSERVER_DATA);
Components.utils.reportError("Bookmarks JSON restore failed: " + exc);
throw exc;
}
finally {
if (!failed) {
PlacesUtils.observerSvc.notifyObservers(null,
RESTORE_SUCCESS_NSIOBSERVER_TOPIC,
RESTORE_NSIOBSERVER_DATA);
}
}
} }
if (backups.length == 0)
return null;
backups.sort();
var filename = backups.pop();
var backupFile = bookmarksBackupDir.clone();
backupFile.append(filename);
return backupFile;
}, },
/** /**
@ -1900,6 +1967,6 @@ var PlacesUtils = {
* this method is called by browser.js in delayed startup. * this method is called by browser.js in delayed startup.
*/ */
startPlacesDBUtils: function PU_startPlacesDBUtils() { startPlacesDBUtils: function PU_startPlacesDBUtils() {
Components.utils.import("resource://gre/modules/PlacesDBUtils.jsm"); Cu.import("resource://gre/modules/PlacesDBUtils.jsm");
} }
}; };

Просмотреть файл

@ -239,7 +239,7 @@ function run_test() {
// export json to file // export json to file
try { try {
PlacesUtils.backupBookmarksToFile(jsonFile); PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't export to file: " + ex); } } catch(ex) { do_throw("couldn't export to file: " + ex); }
// clean // clean
@ -249,7 +249,7 @@ function run_test() {
// restore json file // restore json file
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); } } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
// validate // validate

Просмотреть файл

@ -157,14 +157,14 @@ function run_test() {
test.populate(); test.populate();
try { try {
PlacesUtils.backupBookmarksToFile(jsonFile); PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
} catch(ex) { } catch(ex) {
do_throw("couldn't export to file: " + ex); do_throw("couldn't export to file: " + ex);
} }
// restore json file // restore json file
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
} catch(ex) { } catch(ex) {
do_throw("couldn't import the exported file: " + ex); do_throw("couldn't import the exported file: " + ex);
} }
@ -180,7 +180,7 @@ function run_test() {
// restore json file // restore json file
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
} catch(ex) { } catch(ex) {
do_throw("couldn't import the exported file: " + ex); do_throw("couldn't import the exported file: " + ex);
} }

Просмотреть файл

@ -179,7 +179,7 @@ function run_test() {
}); });
try { try {
PlacesUtils.backupBookmarksToFile(jsonFile); PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't export to file: " + ex); } } catch(ex) { do_throw("couldn't export to file: " + ex); }
tests.forEach(function(aTest) { tests.forEach(function(aTest) {
@ -188,7 +188,7 @@ function run_test() {
// restore json file // restore json file
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile, excludedItemsFromRestore); PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile, excludedItemsFromRestore);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); } } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
// validate // validate

Просмотреть файл

@ -108,7 +108,7 @@ function run_test() {
// export json to file // export json to file
try { try {
PlacesUtils.backupBookmarksToFile(jsonFile); PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't export to file: " + ex); } } catch(ex) { do_throw("couldn't export to file: " + ex); }
// clean // clean
@ -118,7 +118,7 @@ function run_test() {
// restore json file // restore json file
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); } } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
// validate // validate

Просмотреть файл

@ -130,7 +130,7 @@ function run_test() {
// export json to file // export json to file
try { try {
PlacesUtils.backupBookmarksToFile(jsonFile); PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't export to file: " + ex); } } catch(ex) { do_throw("couldn't export to file: " + ex); }
// clean // clean
@ -140,7 +140,7 @@ function run_test() {
// restore json file // restore json file
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); } } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
// validate // validate

Просмотреть файл

@ -151,7 +151,7 @@ function run_test() {
// export json to file // export json to file
try { try {
PlacesUtils.backupBookmarksToFile(jsonFile); PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't export to file: " + ex); } } catch(ex) { do_throw("couldn't export to file: " + ex); }
// clean // clean
@ -161,7 +161,7 @@ function run_test() {
// restore json file // restore json file
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); } } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
// validate // validate

Просмотреть файл

@ -40,17 +40,9 @@ Components.utils.import("resource://gre/modules/utils.js");
const NUMBER_OF_BACKUPS = 1; const NUMBER_OF_BACKUPS = 1;
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
function run_test() { function run_test() {
// Get bookmarkBackups directory // Get bookmarkBackups directory
var bookmarksBackupDir = dirSvc.get("ProfD", Ci.nsILocalFile); var bookmarksBackupDir = PlacesUtils.backups.folder;
bookmarksBackupDir.append("bookmarkbackups");
if (!bookmarksBackupDir.exists()) {
bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
do_check_true(bookmarksBackupDir.exists());
}
// Create an html dummy backup in the past // Create an html dummy backup in the past
var htmlBackupFile = bookmarksBackupDir.clone(); var htmlBackupFile = bookmarksBackupDir.clone();
@ -70,15 +62,14 @@ function run_test() {
jsonBackupFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600); jsonBackupFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
do_check_true(jsonBackupFile.exists()); do_check_true(jsonBackupFile.exists());
// Export bookmarks // Export bookmarks to JSON.
var date = new Date().toLocaleFormat("%Y-%m-%d"); var backupFilename = PlacesUtils.backups.getFilenameForDate();
var backupFilename = "bookmarks-" + date + ".json";
var lastBackupFile = bookmarksBackupDir.clone(); var lastBackupFile = bookmarksBackupDir.clone();
lastBackupFile.append(backupFilename); lastBackupFile.append(backupFilename);
if (lastBackupFile.exists()) if (lastBackupFile.exists())
lastBackupFile.remove(false); lastBackupFile.remove(false);
do_check_false(lastBackupFile.exists()); do_check_false(lastBackupFile.exists());
PlacesUtils.archiveBookmarksFile(NUMBER_OF_BACKUPS); PlacesUtils.backups.create(NUMBER_OF_BACKUPS);
do_check_true(lastBackupFile.exists()); do_check_true(lastBackupFile.exists());
// Check that last backup has been retained // Check that last backup has been retained

Просмотреть файл

@ -0,0 +1,81 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Bug 466303 code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Marco Bonardo <mak77@bonardo.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
Components.utils.import("resource://gre/modules/utils.js");
function run_test() {
let bookmarksBackupDir = PlacesUtils.backups.folder;
// Remove all files from backups folder.
let files = bookmarksBackupDir.directoryEntries;
while (files.hasMoreElements()) {
let entry = files.getNext().QueryInterface(Ci.nsIFile);
entry.remove(false);
}
// Create a json dummy backup in the future.
let dateObj = new Date();
dateObj.setYear(dateObj.getFullYear() + 1);
let name = PlacesUtils.backups.getFilenameForDate(dateObj);
do_check_eq(name, "bookmarks-" + dateObj.toLocaleFormat("%Y-%m-%d") + ".json");
let futureBackupFile = bookmarksBackupDir.clone();
futureBackupFile.append(name);
if (futureBackupFile.exists())
futureBackupFile.remove(false);
do_check_false(futureBackupFile.exists());
futureBackupFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
do_check_true(futureBackupFile.exists());
do_check_eq(PlacesUtils.backups.entries.length, 0);
PlacesUtils.backups.create();
// Check that a backup for today has been created.
do_check_eq(PlacesUtils.backups.entries.length, 1);
let mostRecentBackupFile = PlacesUtils.backups.getMostRecent();
do_check_neq(mostRecentBackupFile, null);
let todayName = PlacesUtils.backups.getFilenameForDate();
do_check_eq(mostRecentBackupFile.leafName, todayName);
// Check that future backup has been removed.
do_check_false(futureBackupFile.exists());
// Cleanup.
mostRecentBackupFile.remove(false);
do_check_false(mostRecentBackupFile.exists());
}

Просмотреть файл

@ -96,7 +96,7 @@ function run_test() {
// export json to file // export json to file
try { try {
PlacesUtils.backupBookmarksToFile(jsonFile); PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't export to file: " + ex); } } catch(ex) { do_throw("couldn't export to file: " + ex); }
// clean // clean
@ -106,7 +106,7 @@ function run_test() {
// restore json file // restore json file
try { try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); } } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
// validate // validate

Просмотреть файл

@ -66,15 +66,7 @@ function run_test() {
dates.sort(); dates.sort();
// Get and cleanup the backups folder. // Get and cleanup the backups folder.
var dirSvc = Cc["@mozilla.org/file/directory_service;1"]. var bookmarksBackupDir = PlacesUtils.backups.folder;
getService(Ci.nsIProperties);
var bookmarksBackupDir = dirSvc.get("ProfD", Ci.nsILocalFile);
bookmarksBackupDir.append("bookmarkbackups");
if (bookmarksBackupDir.exists()) {
bookmarksBackupDir.remove(true);
do_check_false(bookmarksBackupDir.exists());
}
bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
// Fake backups are created backwards to ensure we won't consider file // Fake backups are created backwards to ensure we won't consider file
// creation time. // creation time.
@ -98,7 +90,7 @@ function run_test() {
return LOCALIZED_PREFIX + aValue; return LOCALIZED_PREFIX + aValue;
} }
PlacesUtils.archiveBookmarksFile(Math.floor(dates.length/2)); PlacesUtils.backups.create(Math.floor(dates.length/2));
// Add today's backup. // Add today's backup.
dates.push(dateObj.toLocaleFormat("%Y-%m-%d")); dates.push(dateObj.toLocaleFormat("%Y-%m-%d"));
@ -123,5 +115,6 @@ function run_test() {
// Cleanup backups folder. // Cleanup backups folder.
bookmarksBackupDir.remove(true); bookmarksBackupDir.remove(true);
do_check_false(bookmarksBackupDir.exists()); do_check_false(bookmarksBackupDir.exists());
bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777); // Recreate the folder.
PlacesUtils.backups.folder;
} }