From 2177a000eaa8fe85b25bf0d99df2d8f9002c539a Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Wed, 30 Dec 2015 04:31:57 -0500 Subject: [PATCH] Closes #891, Better incompatible-DB-version handling Fixes the incompatible-version dialog and adds info on the version used to upgrade the database, which may be helpful for troubleshooting. Also fixes showing of the Zotero toolbar icons even in case of a startup error. --- chrome/content/zotero/icon.js | 5 +-- chrome/content/zotero/overlay.js | 22 ++++++++++-- chrome/content/zotero/xpcom/db.js | 6 ++++ chrome/content/zotero/xpcom/schema.js | 26 +++++++++++--- chrome/content/zotero/xpcom/zotero.js | 37 ++++++++++++++------ chrome/locale/en-US/zotero/zotero.properties | 4 +-- resource/config.js | 1 + 7 files changed, 79 insertions(+), 22 deletions(-) diff --git a/chrome/content/zotero/icon.js b/chrome/content/zotero/icon.js index ccfcbee10..1f3ce8ce9 100644 --- a/chrome/content/zotero/icon.js +++ b/chrome/content/zotero/icon.js @@ -25,6 +25,7 @@ "use strict"; +Components.utils.import("resource://zotero/config.js"); Components.utils.import("resource:///modules/CustomizableUI.jsm"); var comboButtonsID = 'zotero-toolbar-buttons'; @@ -119,8 +120,8 @@ CustomizableUI.addListener({ CustomizableUI.createWidget({ id: comboButtonsID, type: 'custom', - label: 'Zotero', - tooltiptext: "Zotero", + label: ZOTERO_CONFIG.CLIENT_NAME, + tooltiptext: ZOTERO_CONFIG.CLIENT_NAME, defaultArea: CustomizableUI.AREA_NAVBAR, onBuild: function (document) { const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js index 91fe971f6..631d92156 100644 --- a/chrome/content/zotero/overlay.js +++ b/chrome/content/zotero/overlay.js @@ -40,10 +40,14 @@ var ZoteroOverlay = new function() zoteroSplitter = document.getElementById('zotero-splitter'); var self = this; + var iconLoaded = false; Zotero.Promise.try(function () { - if (!Zotero || Zotero.skipLoading) { - throw true; + if (!Zotero) { + throw new Error("No Zotero object"); + } + if (Zotero.skipLoading) { + throw new Error("Skipping loading"); } return Zotero.Promise.all([Zotero.initializationPromise, Zotero.unlockPromise]); }) @@ -51,7 +55,7 @@ var ZoteroOverlay = new function() Zotero.debug("Initializing overlay"); if (Zotero.skipLoading) { - throw true; + throw new Error("Skipping loading"); } ZoteroPane_Overlay = ZoteroPane; @@ -94,6 +98,7 @@ var ZoteroOverlay = new function() // Add toolbar icon try { + iconLoaded = true; Services.scriptloader.loadSubScript("chrome://zotero/content/icon.js", {}, "UTF-8"); } catch (e) { @@ -134,6 +139,17 @@ var ZoteroOverlay = new function() }) .catch(function (e) { Zotero.debug(e, 1); + + // Add toolbar icon if still necessary + if (!iconLoaded) { + try { + Services.scriptloader.loadSubScript("chrome://zotero/content/icon.js", {}, "UTF-8"); + } + catch (e) { + Zotero.logError(e); + } + } + throw e; }); } diff --git a/chrome/content/zotero/xpcom/db.js b/chrome/content/zotero/xpcom/db.js index 4e6b5451b..9629caf95 100644 --- a/chrome/content/zotero/xpcom/db.js +++ b/chrome/content/zotero/xpcom/db.js @@ -1317,3 +1317,9 @@ Zotero.DBConnection.prototype._getTypedValue = function (statement, i) { // Initialize main database connection Zotero.DB = new Zotero.DBConnection('zotero'); + +Zotero.DB.IncompatibleVersionException = function (msg, dbClientVersion) { + this.message = msg; + this.dbClientVersion = dbClientVersion; +} +Zotero.DB.IncompatibleVersionException.prototype = Object.create(Error.prototype); diff --git a/chrome/content/zotero/xpcom/schema.js b/chrome/content/zotero/xpcom/schema.js index 056ca4b79..c4c4ed0a2 100644 --- a/chrome/content/zotero/xpcom/schema.js +++ b/chrome/content/zotero/xpcom/schema.js @@ -106,8 +106,13 @@ Zotero.Schema = new function(){ } if (compatibility > _maxCompatibility) { - throw new Error("Database is incompatible this Zotero version " - + "(" + compatibility + " > " + _maxCompatibility + ")"); + let dbClientVersion = yield Zotero.DB.valueQueryAsync( + "SELECT value FROM settings " + + "WHERE setting='client' AND key='lastCompatibleVersion'" + ); + let msg = "Database is incompatible with this Zotero version " + + `(${compatibility} > ${_maxCompatibility})` + throw new Zotero.DB.IncompatibleVersionException(msg, dbClientVersion); } var schemaVersion = yield _getSchemaSQLVersion('userdata'); @@ -1554,6 +1559,19 @@ Zotero.Schema = new function(){ } + var _updateCompatibility = Zotero.Promise.coroutine(function* (version) { + if (version > _maxCompatibility) { + throw new Error("Can't set compatibility greater than _maxCompatibility"); + } + + yield Zotero.DB.queryAsync( + "REPLACE INTO settings VALUES (?, ?, ?)", + ['client', 'lastCompatibleVersion', Zotero.version] + ); + yield _updateDBVersion('compatibility', version); + }); + + /** * Process the response from the repository * @@ -1944,7 +1962,7 @@ Zotero.Schema = new function(){ // previous revision to that one. for (let i = fromVersion + 1; i <= toVersion; i++) { if (i == 80) { - yield _updateDBVersion('compatibility', 1); + yield _updateCompatibility(1); yield Zotero.DB.queryAsync("ALTER TABLE libraries RENAME TO librariesOld"); yield Zotero.DB.queryAsync("CREATE TABLE libraries (\n libraryID INTEGER PRIMARY KEY,\n type TEXT NOT NULL,\n editable INT NOT NULL,\n filesEditable INT NOT NULL,\n version INT NOT NULL DEFAULT 0,\n lastSync INT NOT NULL DEFAULT 0,\n lastStorageSync INT NOT NULL DEFAULT 0\n)"); @@ -2282,7 +2300,7 @@ Zotero.Schema = new function(){ } if (i == 81) { - yield _updateDBVersion('compatibility', 2); + yield _updateCompatibility(2); yield Zotero.DB.queryAsync("ALTER TABLE libraries RENAME TO librariesOld"); yield Zotero.DB.queryAsync("CREATE TABLE libraries (\n libraryID INTEGER PRIMARY KEY,\n type TEXT NOT NULL,\n editable INT NOT NULL,\n filesEditable INT NOT NULL,\n version INT NOT NULL DEFAULT 0,\n storageVersion INT NOT NULL DEFAULT 0,\n lastSync INT NOT NULL DEFAULT 0\n)"); diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js index a6efd8c8f..eb95c60e5 100644 --- a/chrome/content/zotero/xpcom/zotero.js +++ b/chrome/content/zotero/xpcom/zotero.js @@ -630,23 +630,23 @@ Components.utils.import("resource://gre/modules/osfile.jsm"); Zotero.Items.startEmptyTrashTimer(); } catch (e) { - Zotero.debug(e, 1); - Components.utils.reportError(e); // DEBUG: doesn't always work + Zotero.logError(e); - if (e.toString().match('newer than SQL file')) { - let versions = e.toString().match(/\((\d+) < (\d+)\)/); + if (e instanceof Zotero.DB.IncompatibleVersionException) { let kbURL = "https://www.zotero.org/support/kb/newer_db_version"; - let msg = Zotero.getString('startupError.zoteroVersionIsOlder') + " " - + Zotero.getString('startupError.zoteroVersionIsOlder.upgrade') + "\n\n" + let msg = Zotero.getString('startupError.incompatibleDBVersion', + [Zotero.clientName, e.dbClientVersion]) + "\n\n" + Zotero.getString('startupError.zoteroVersionIsOlder.current', Zotero.version) - + (versions ? " (" + versions[1] + " < " + versions[2] + ")" : "") + "\n\n" - + Zotero.getString('general.seeForMoreInformation', kbURL); + + "\n\n" + + Zotero.getString('startupError.zoteroVersionIsOlder.upgrade', + ZOTERO_CONFIG.DOMAIN_NAME); Zotero.startupError = msg; _startupErrorHandler = function() { var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService); var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING) + (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL) + + (ps.BUTTON_POS_2) * (ps.BUTTON_TITLE_IS_STRING) + ps.BUTTON_POS_0_DEFAULT; var index = ps.confirmEx( @@ -655,10 +655,13 @@ Components.utils.import("resource://gre/modules/osfile.jsm"); Zotero.startupError, buttonFlags, Zotero.getString('general.checkForUpdate'), - null, null, null, {} + null, + Zotero.getString('general.moreInformation'), + null, + {} ); - // "Check for updates" button + // "Check for Update" button if(index === 0) { if(Zotero.isStandalone) { Components.classes["@mozilla.org/embedcomp/window-watcher;1"] @@ -703,11 +706,23 @@ Components.utils.import("resource://gre/modules/osfile.jsm"); ); } } + // Load More Info page + else if (index == 2) { + let io = Components.classes['@mozilla.org/network/io-service;1'] + .getService(Components.interfaces.nsIIOService); + let uri = io.newURI(kbURL, null, null); + let handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1'] + .getService(Components.interfaces.nsIExternalProtocolService) + .getProtocolHandlerInfo('http'); + handler.preferredAction = Components.interfaces.nsIHandlerInfo.useSystemDefault; + handler.launchWithURI(uri, null); + } }; + throw e; } Zotero.startupError = Zotero.getString('startupError.databaseUpgradeError') + "\n\n" + e; - throw true; + throw e; }; return true; diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index a7feffd0c..fcf6f6c97 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -138,9 +138,9 @@ startupError.closeStandalone = If Zotero Standalone is open, please close it startupError.closeFirefox = If Firefox with the Zotero extension is open, please close it and restart Zotero Standalone. startupError.databaseCannotBeOpened = The Zotero database cannot be opened. startupError.checkPermissions = Make sure you have read and write permissions for all files in the Zotero data directory. -startupError.zoteroVersionIsOlder = This version of Zotero is older than the version last used with your database. -startupError.zoteroVersionIsOlder.upgrade = Please upgrade to the latest version from zotero.org. +startupError.incompatibleDBVersion = This %1$S database requires %1$S %2$S or later. startupError.zoteroVersionIsOlder.current = Current version: %S +startupError.zoteroVersionIsOlder.upgrade = Please upgrade to the latest version from %S. startupError.databaseUpgradeError = Database upgrade error date.relative.secondsAgo.one = 1 second ago diff --git a/resource/config.js b/resource/config.js index 5cd95fe59..b5aaf5734 100644 --- a/resource/config.js +++ b/resource/config.js @@ -1,6 +1,7 @@ var ZOTERO_CONFIG = { GUID: 'zotero@chnm.gmu.edu', CLIENT_NAME: 'Zotero', + DOMAIN_NAME: 'zotero.org', REPOSITORY_URL: 'https://repo.zotero.org/repo/', REPOSITORY_CHECK_INTERVAL: 86400, // 24 hours REPOSITORY_RETRY_INTERVAL: 3600, // 1 hour