diff options
Diffstat (limited to 'toolkit/mozapps/webextensions/internal/AddonRepository_SQLiteMigrator.jsm')
-rw-r--r-- | toolkit/mozapps/webextensions/internal/AddonRepository_SQLiteMigrator.jsm | 522 |
1 files changed, 0 insertions, 522 deletions
diff --git a/toolkit/mozapps/webextensions/internal/AddonRepository_SQLiteMigrator.jsm b/toolkit/mozapps/webextensions/internal/AddonRepository_SQLiteMigrator.jsm deleted file mode 100644 index e3479643b..000000000 --- a/toolkit/mozapps/webextensions/internal/AddonRepository_SQLiteMigrator.jsm +++ /dev/null @@ -1,522 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/AddonManager.jsm"); -/* globals AddonManagerPrivate*/ -Cu.import("resource://gre/modules/FileUtils.jsm"); - -const KEY_PROFILEDIR = "ProfD"; -const FILE_DATABASE = "addons.sqlite"; -const LAST_DB_SCHEMA = 4; - -// Add-on properties present in the columns of the database -const PROP_SINGLE = ["id", "type", "name", "version", "creator", "description", - "fullDescription", "developerComments", "eula", - "homepageURL", "supportURL", "contributionURL", - "contributionAmount", "averageRating", "reviewCount", - "reviewURL", "totalDownloads", "weeklyDownloads", - "dailyUsers", "sourceURI", "repositoryStatus", "size", - "updateDate"]; - -Cu.import("resource://gre/modules/Log.jsm"); -const LOGGER_ID = "addons.repository.sqlmigrator"; - -// Create a new logger for use by the Addons Repository SQL Migrator -// (Requires AddonManager.jsm) -var logger = Log.repository.getLogger(LOGGER_ID); - -this.EXPORTED_SYMBOLS = ["AddonRepository_SQLiteMigrator"]; - - -this.AddonRepository_SQLiteMigrator = { - - /** - * Migrates data from a previous SQLite version of the - * database to the JSON version. - * - * @param structFunctions an object that contains functions - * to create the various objects used - * in the new JSON format - * @param aCallback A callback to be called when migration - * finishes, with the results in an array - * @returns bool True if a migration will happen (DB was - * found and succesfully opened) - */ - migrate: function(aCallback) { - if (!this._openConnection()) { - this._closeConnection(); - aCallback([]); - return false; - } - - logger.debug("Importing addon repository from previous " + FILE_DATABASE + " storage."); - - this._retrieveStoredData((results) => { - this._closeConnection(); - let resultArray = Object.keys(results).map(k => results[k]); - logger.debug(resultArray.length + " addons imported.") - aCallback(resultArray); - }); - - return true; - }, - - /** - * Synchronously opens a new connection to the database file. - * - * @return bool Whether the DB was opened successfully. - */ - _openConnection: function() { - delete this.connection; - - let dbfile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true); - if (!dbfile.exists()) - return false; - - try { - this.connection = Services.storage.openUnsharedDatabase(dbfile); - } catch (e) { - return false; - } - - this.connection.executeSimpleSQL("PRAGMA locking_mode = EXCLUSIVE"); - - // Any errors in here should rollback - try { - this.connection.beginTransaction(); - - switch (this.connection.schemaVersion) { - case 0: - return false; - - case 1: - logger.debug("Upgrading database schema to version 2"); - this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN width INTEGER"); - this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN height INTEGER"); - this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN thumbnailWidth INTEGER"); - this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN thumbnailHeight INTEGER"); - case 2: - logger.debug("Upgrading database schema to version 3"); - this.connection.createTable("compatibility_override", - "addon_internal_id INTEGER, " + - "num INTEGER, " + - "type TEXT, " + - "minVersion TEXT, " + - "maxVersion TEXT, " + - "appID TEXT, " + - "appMinVersion TEXT, " + - "appMaxVersion TEXT, " + - "PRIMARY KEY (addon_internal_id, num)"); - case 3: - logger.debug("Upgrading database schema to version 4"); - this.connection.createTable("icon", - "addon_internal_id INTEGER, " + - "size INTEGER, " + - "url TEXT, " + - "PRIMARY KEY (addon_internal_id, size)"); - this._createIndices(); - this._createTriggers(); - this.connection.schemaVersion = LAST_DB_SCHEMA; - case LAST_DB_SCHEMA: - break; - default: - return false; - } - this.connection.commitTransaction(); - } catch (e) { - logger.error("Failed to open " + FILE_DATABASE + ". Data import will not happen.", e); - this.logSQLError(this.connection.lastError, this.connection.lastErrorString); - this.connection.rollbackTransaction(); - return false; - } - - return true; - }, - - _closeConnection: function() { - for (let key in this.asyncStatementsCache) { - let stmt = this.asyncStatementsCache[key]; - stmt.finalize(); - } - this.asyncStatementsCache = {}; - - if (this.connection) - this.connection.asyncClose(); - - delete this.connection; - }, - - /** - * Asynchronously retrieve all add-ons from the database, and pass it - * to the specified callback - * - * @param aCallback - * The callback to pass the add-ons back to - */ - _retrieveStoredData: function(aCallback) { - let addons = {}; - - // Retrieve all data from the addon table - let getAllAddons = () => { - this.getAsyncStatement("getAllAddons").executeAsync({ - handleResult: aResults => { - let row = null; - while ((row = aResults.getNextRow())) { - let internal_id = row.getResultByName("internal_id"); - addons[internal_id] = this._makeAddonFromAsyncRow(row); - } - }, - - handleError: this.asyncErrorLogger, - - handleCompletion: function(aReason) { - if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) { - logger.error("Error retrieving add-ons from database. Returning empty results"); - aCallback({}); - return; - } - - getAllDevelopers(); - } - }); - } - - // Retrieve all data from the developer table - let getAllDevelopers = () => { - this.getAsyncStatement("getAllDevelopers").executeAsync({ - handleResult: aResults => { - let row = null; - while ((row = aResults.getNextRow())) { - let addon_internal_id = row.getResultByName("addon_internal_id"); - if (!(addon_internal_id in addons)) { - logger.warn("Found a developer not linked to an add-on in database"); - continue; - } - - let addon = addons[addon_internal_id]; - if (!addon.developers) - addon.developers = []; - - addon.developers.push(this._makeDeveloperFromAsyncRow(row)); - } - }, - - handleError: this.asyncErrorLogger, - - handleCompletion: function(aReason) { - if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) { - logger.error("Error retrieving developers from database. Returning empty results"); - aCallback({}); - return; - } - - getAllScreenshots(); - } - }); - } - - // Retrieve all data from the screenshot table - let getAllScreenshots = () => { - this.getAsyncStatement("getAllScreenshots").executeAsync({ - handleResult: aResults => { - let row = null; - while ((row = aResults.getNextRow())) { - let addon_internal_id = row.getResultByName("addon_internal_id"); - if (!(addon_internal_id in addons)) { - logger.warn("Found a screenshot not linked to an add-on in database"); - continue; - } - - let addon = addons[addon_internal_id]; - if (!addon.screenshots) - addon.screenshots = []; - addon.screenshots.push(this._makeScreenshotFromAsyncRow(row)); - } - }, - - handleError: this.asyncErrorLogger, - - handleCompletion: function(aReason) { - if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) { - logger.error("Error retrieving screenshots from database. Returning empty results"); - aCallback({}); - return; - } - - getAllCompatOverrides(); - } - }); - } - - let getAllCompatOverrides = () => { - this.getAsyncStatement("getAllCompatOverrides").executeAsync({ - handleResult: aResults => { - let row = null; - while ((row = aResults.getNextRow())) { - let addon_internal_id = row.getResultByName("addon_internal_id"); - if (!(addon_internal_id in addons)) { - logger.warn("Found a compatibility override not linked to an add-on in database"); - continue; - } - - let addon = addons[addon_internal_id]; - if (!addon.compatibilityOverrides) - addon.compatibilityOverrides = []; - addon.compatibilityOverrides.push(this._makeCompatOverrideFromAsyncRow(row)); - } - }, - - handleError: this.asyncErrorLogger, - - handleCompletion: function(aReason) { - if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) { - logger.error("Error retrieving compatibility overrides from database. Returning empty results"); - aCallback({}); - return; - } - - getAllIcons(); - } - }); - } - - let getAllIcons = () => { - this.getAsyncStatement("getAllIcons").executeAsync({ - handleResult: aResults => { - let row = null; - while ((row = aResults.getNextRow())) { - let addon_internal_id = row.getResultByName("addon_internal_id"); - if (!(addon_internal_id in addons)) { - logger.warn("Found an icon not linked to an add-on in database"); - continue; - } - - let addon = addons[addon_internal_id]; - let { size, url } = this._makeIconFromAsyncRow(row); - addon.icons[size] = url; - if (size == 32) - addon.iconURL = url; - } - }, - - handleError: this.asyncErrorLogger, - - handleCompletion: function(aReason) { - if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) { - logger.error("Error retrieving icons from database. Returning empty results"); - aCallback({}); - return; - } - - let returnedAddons = {}; - for (let id in addons) { - let addon = addons[id]; - returnedAddons[addon.id] = addon; - } - aCallback(returnedAddons); - } - }); - } - - // Begin asynchronous process - getAllAddons(); - }, - - // A cache of statements that are used and need to be finalized on shutdown - asyncStatementsCache: {}, - - /** - * Gets a cached async statement or creates a new statement if it doesn't - * already exist. - * - * @param aKey - * A unique key to reference the statement - * @return a mozIStorageAsyncStatement for the SQL corresponding to the - * unique key - */ - getAsyncStatement: function(aKey) { - if (aKey in this.asyncStatementsCache) - return this.asyncStatementsCache[aKey]; - - let sql = this.queries[aKey]; - try { - return this.asyncStatementsCache[aKey] = this.connection.createAsyncStatement(sql); - } catch (e) { - logger.error("Error creating statement " + aKey + " (" + sql + ")"); - throw Components.Exception("Error creating statement " + aKey + " (" + sql + "): " + e, - e.result); - } - }, - - // The queries used by the database - queries: { - getAllAddons: "SELECT internal_id, id, type, name, version, " + - "creator, creatorURL, description, fullDescription, " + - "developerComments, eula, homepageURL, supportURL, " + - "contributionURL, contributionAmount, averageRating, " + - "reviewCount, reviewURL, totalDownloads, weeklyDownloads, " + - "dailyUsers, sourceURI, repositoryStatus, size, updateDate " + - "FROM addon", - - getAllDevelopers: "SELECT addon_internal_id, name, url FROM developer " + - "ORDER BY addon_internal_id, num", - - getAllScreenshots: "SELECT addon_internal_id, url, width, height, " + - "thumbnailURL, thumbnailWidth, thumbnailHeight, caption " + - "FROM screenshot ORDER BY addon_internal_id, num", - - getAllCompatOverrides: "SELECT addon_internal_id, type, minVersion, " + - "maxVersion, appID, appMinVersion, appMaxVersion " + - "FROM compatibility_override " + - "ORDER BY addon_internal_id, num", - - getAllIcons: "SELECT addon_internal_id, size, url FROM icon " + - "ORDER BY addon_internal_id, size", - }, - - /** - * Make add-on structure from an asynchronous row. - * - * @param aRow - * The asynchronous row to use - * @return The created add-on - */ - _makeAddonFromAsyncRow: function(aRow) { - // This is intentionally not an AddonSearchResult object in order - // to allow AddonDatabase._parseAddon to parse it, same as if it - // was read from the JSON database. - - let addon = { icons: {} }; - - for (let prop of PROP_SINGLE) { - addon[prop] = aRow.getResultByName(prop) - } - - return addon; - }, - - /** - * Make a developer from an asynchronous row - * - * @param aRow - * The asynchronous row to use - * @return The created developer - */ - _makeDeveloperFromAsyncRow: function(aRow) { - let name = aRow.getResultByName("name"); - let url = aRow.getResultByName("url") - return new AddonManagerPrivate.AddonAuthor(name, url); - }, - - /** - * Make a screenshot from an asynchronous row - * - * @param aRow - * The asynchronous row to use - * @return The created screenshot - */ - _makeScreenshotFromAsyncRow: function(aRow) { - let url = aRow.getResultByName("url"); - let width = aRow.getResultByName("width"); - let height = aRow.getResultByName("height"); - let thumbnailURL = aRow.getResultByName("thumbnailURL"); - let thumbnailWidth = aRow.getResultByName("thumbnailWidth"); - let thumbnailHeight = aRow.getResultByName("thumbnailHeight"); - let caption = aRow.getResultByName("caption"); - return new AddonManagerPrivate.AddonScreenshot(url, width, height, thumbnailURL, - thumbnailWidth, thumbnailHeight, caption); - }, - - /** - * Make a CompatibilityOverride from an asynchronous row - * - * @param aRow - * The asynchronous row to use - * @return The created CompatibilityOverride - */ - _makeCompatOverrideFromAsyncRow: function(aRow) { - let type = aRow.getResultByName("type"); - let minVersion = aRow.getResultByName("minVersion"); - let maxVersion = aRow.getResultByName("maxVersion"); - let appID = aRow.getResultByName("appID"); - let appMinVersion = aRow.getResultByName("appMinVersion"); - let appMaxVersion = aRow.getResultByName("appMaxVersion"); - return new AddonManagerPrivate.AddonCompatibilityOverride(type, - minVersion, - maxVersion, - appID, - appMinVersion, - appMaxVersion); - }, - - /** - * Make an icon from an asynchronous row - * - * @param aRow - * The asynchronous row to use - * @return An object containing the size and URL of the icon - */ - _makeIconFromAsyncRow: function(aRow) { - let size = aRow.getResultByName("size"); - let url = aRow.getResultByName("url"); - return { size: size, url: url }; - }, - - /** - * A helper function to log an SQL error. - * - * @param aError - * The storage error code associated with the error - * @param aErrorString - * An error message - */ - logSQLError: function(aError, aErrorString) { - logger.error("SQL error " + aError + ": " + aErrorString); - }, - - /** - * A helper function to log any errors that occur during async statements. - * - * @param aError - * A mozIStorageError to log - */ - asyncErrorLogger: function(aError) { - logger.error("Async SQL error " + aError.result + ": " + aError.message); - }, - - /** - * Synchronously creates the triggers in the database. - */ - _createTriggers: function() { - this.connection.executeSimpleSQL("DROP TRIGGER IF EXISTS delete_addon"); - this.connection.executeSimpleSQL("CREATE TRIGGER delete_addon AFTER DELETE " + - "ON addon BEGIN " + - "DELETE FROM developer WHERE addon_internal_id=old.internal_id; " + - "DELETE FROM screenshot WHERE addon_internal_id=old.internal_id; " + - "DELETE FROM compatibility_override WHERE addon_internal_id=old.internal_id; " + - "DELETE FROM icon WHERE addon_internal_id=old.internal_id; " + - "END"); - }, - - /** - * Synchronously creates the indices in the database. - */ - _createIndices: function() { - this.connection.executeSimpleSQL("CREATE INDEX IF NOT EXISTS developer_idx " + - "ON developer (addon_internal_id)"); - this.connection.executeSimpleSQL("CREATE INDEX IF NOT EXISTS screenshot_idx " + - "ON screenshot (addon_internal_id)"); - this.connection.executeSimpleSQL("CREATE INDEX IF NOT EXISTS compatibility_override_idx " + - "ON compatibility_override (addon_internal_id)"); - this.connection.executeSimpleSQL("CREATE INDEX IF NOT EXISTS icon_idx " + - "ON icon (addon_internal_id)"); - } -} |