зеркало из https://github.com/mozilla/gecko-dev.git
Bug 853388: Trigger XPI database conversion from SQLITE based on schema version preference; r=unfocused
This commit is contained in:
Родитель
cd8845f657
Коммит
9146a071a9
|
@ -15,7 +15,7 @@ endif
|
||||||
|
|
||||||
# This is used in multiple places, so is defined here to avoid it getting
|
# This is used in multiple places, so is defined here to avoid it getting
|
||||||
# out of sync.
|
# out of sync.
|
||||||
DEFINES += -DMOZ_EXTENSIONS_DB_SCHEMA=14
|
DEFINES += -DMOZ_EXTENSIONS_DB_SCHEMA=15
|
||||||
|
|
||||||
# Additional debugging info is exposed in debug builds, or by setting the
|
# Additional debugging info is exposed in debug builds, or by setting the
|
||||||
# MOZ_EM_DEBUG environment variable when building.
|
# MOZ_EM_DEBUG environment variable when building.
|
||||||
|
|
|
@ -43,6 +43,8 @@ const FILE_XPI_ADDONS_LIST = "extensions.ini";
|
||||||
// The value for this is in Makefile.in
|
// The value for this is in Makefile.in
|
||||||
#expand const DB_SCHEMA = __MOZ_EXTENSIONS_DB_SCHEMA__;
|
#expand const DB_SCHEMA = __MOZ_EXTENSIONS_DB_SCHEMA__;
|
||||||
|
|
||||||
|
// The last version of DB_SCHEMA implemented in SQLITE
|
||||||
|
const LAST_SQLITE_DB_SCHEMA = 14;
|
||||||
const PREF_DB_SCHEMA = "extensions.databaseSchema";
|
const PREF_DB_SCHEMA = "extensions.databaseSchema";
|
||||||
const PREF_PENDING_OPERATIONS = "extensions.pendingOperations";
|
const PREF_PENDING_OPERATIONS = "extensions.pendingOperations";
|
||||||
const PREF_EM_ENABLED_ADDONS = "extensions.enabledAddons";
|
const PREF_EM_ENABLED_ADDONS = "extensions.enabledAddons";
|
||||||
|
@ -469,26 +471,21 @@ this.XPIDatabase = {
|
||||||
* {location: {id1:{addon1}, id2:{addon2}}, location2:{...}, ...}
|
* {location: {id1:{addon1}, id2:{addon2}}, location2:{...}, ...}
|
||||||
* if there is useful information
|
* if there is useful information
|
||||||
*/
|
*/
|
||||||
loadSqliteData: function XPIDB_loadSqliteData() {
|
getMigrateDataFromSQLITE: function XPIDB_getMigrateDataFromSQLITE() {
|
||||||
let connection = null;
|
let connection = null;
|
||||||
let dbfile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true);
|
let dbfile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true);
|
||||||
if (!dbfile.exists()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Attempt to open the database
|
// Attempt to open the database
|
||||||
try {
|
try {
|
||||||
connection = Services.storage.openUnsharedDatabase(dbfile);
|
connection = Services.storage.openUnsharedDatabase(dbfile);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
// exists but SQLITE can't open it
|
|
||||||
WARN("Failed to open sqlite database " + dbfile.path + " for upgrade", e);
|
WARN("Failed to open sqlite database " + dbfile.path + " for upgrade", e);
|
||||||
this.migrateData = null;
|
return null;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
LOG("Migrating data from sqlite");
|
LOG("Migrating data from sqlite");
|
||||||
this.migrateData = this.getMigrateDataFromDatabase(connection);
|
let migrateData = this.getMigrateDataFromDatabase(connection);
|
||||||
connection.close();
|
connection.close();
|
||||||
return true;
|
return migrateData;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -578,13 +575,18 @@ this.XPIDatabase = {
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (e.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
|
if (e.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
|
||||||
// XXX re-implement logic to decide whether to upgrade database
|
try {
|
||||||
// by checking the DB_SCHEMA_VERSION preference.
|
let schemaVersion = Services.prefs.getIntPref(PREF_DB_SCHEMA);
|
||||||
// Fall back to attempting database upgrades
|
if (schemaVersion <= LAST_SQLITE_DB_SCHEMA) {
|
||||||
WARN("Extensions database not found; attempting to upgrade");
|
// we should have an older SQLITE database
|
||||||
// See if there is SQLITE to migrate from
|
this.migrateData = this.getMigrateDataFromSQLITE();
|
||||||
if (!this.loadSqliteData()) {
|
}
|
||||||
// Nope, try RDF
|
// else we've upgraded before but the JSON file is gone, fall through
|
||||||
|
// and rebuild from scratch
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
// No schema version pref means either a really old upgrade (RDF) or
|
||||||
|
// a new profile
|
||||||
this.migrateData = this.getMigrateDataFromRDF();
|
this.migrateData = this.getMigrateDataFromRDF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,6 +597,7 @@ this.XPIDatabase = {
|
||||||
" exists but is not readable; rebuilding in memory", e);
|
" exists but is not readable; rebuilding in memory", e);
|
||||||
// XXX open question - if we can overwrite at save time, should we, or should we
|
// XXX open question - if we can overwrite at save time, should we, or should we
|
||||||
// leave the locked database in case we can recover from it next time we start up?
|
// leave the locked database in case we can recover from it next time we start up?
|
||||||
|
// The old code made one attempt to remove the locked file before it rebuilt in memory
|
||||||
this.lockedDatabase = true;
|
this.lockedDatabase = true;
|
||||||
// XXX TELEMETRY report when this happens?
|
// XXX TELEMETRY report when this happens?
|
||||||
this.rebuildDatabase(aRebuildOnError);
|
this.rebuildDatabase(aRebuildOnError);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Checks that we migrate data from future versions of the database
|
// Checks that we migrate data from SQLITE databases
|
||||||
// Note that since the database doesn't contain the foreignInstall field we
|
// Note that since the database doesn't contain the foreignInstall field we
|
||||||
// should just assume that no add-ons in the user profile were foreignInstalls
|
// should just assume that no add-ons in the user profile were foreignInstalls
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ function run_test() {
|
||||||
stmt.finalize();
|
stmt.finalize();
|
||||||
|
|
||||||
db.schemaVersion = 10000;
|
db.schemaVersion = 10000;
|
||||||
Services.prefs.setIntPref("extensions.databaseSchema", 100);
|
Services.prefs.setIntPref("extensions.databaseSchema", 14);
|
||||||
db.close();
|
db.close();
|
||||||
|
|
||||||
startupManager();
|
startupManager();
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Checks that we don't migrate data from SQLITE if
|
||||||
|
// the "extensions.databaseSchema" preference shows we've
|
||||||
|
// already upgraded to JSON
|
||||||
|
|
||||||
|
// Enable loading extensions from the user and system scopes
|
||||||
|
Services.prefs.setIntPref("extensions.enabledScopes",
|
||||||
|
AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_USER +
|
||||||
|
AddonManager.SCOPE_SYSTEM);
|
||||||
|
|
||||||
|
var addon1 = {
|
||||||
|
id: "addon1@tests.mozilla.org",
|
||||||
|
version: "1.0",
|
||||||
|
name: "Test 1",
|
||||||
|
targetApplications: [{
|
||||||
|
id: "xpcshell@tests.mozilla.org",
|
||||||
|
minVersion: "1",
|
||||||
|
maxVersion: "1"
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||||
|
const profileDir = gProfD.clone();
|
||||||
|
profileDir.append("extensions");
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
writeInstallRDFForExtension(addon1, profileDir);
|
||||||
|
|
||||||
|
// Write out a minimal database
|
||||||
|
let dbfile = gProfD.clone();
|
||||||
|
dbfile.append("extensions.sqlite");
|
||||||
|
let db = AM_Cc["@mozilla.org/storage/service;1"].
|
||||||
|
getService(AM_Ci.mozIStorageService).
|
||||||
|
openDatabase(dbfile);
|
||||||
|
db.createTable("addon", "internal_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||||
|
"id TEXT, location TEXT, version TEXT, active INTEGER, " +
|
||||||
|
"userDisabled INTEGER, installDate INTEGER");
|
||||||
|
db.createTable("targetApplication", "addon_internal_id INTEGER, " +
|
||||||
|
"id TEXT, minVersion TEXT, maxVersion TEXT");
|
||||||
|
let stmt = db.createStatement("INSERT INTO addon VALUES (NULL, :id, :location, " +
|
||||||
|
":version, :active, :userDisabled, :installDate)");
|
||||||
|
|
||||||
|
let internal_ids = {};
|
||||||
|
|
||||||
|
[["addon1@tests.mozilla.org", "app-profile", "1.0", "0", "1", "0"]
|
||||||
|
].forEach(function(a) {
|
||||||
|
stmt.params.id = a[0];
|
||||||
|
stmt.params.location = a[1];
|
||||||
|
stmt.params.version = a[2];
|
||||||
|
stmt.params.active = a[3];
|
||||||
|
stmt.params.userDisabled = a[4];
|
||||||
|
stmt.params.installDate = a[5];
|
||||||
|
stmt.execute();
|
||||||
|
internal_ids[a[0]] = db.lastInsertRowID;
|
||||||
|
});
|
||||||
|
stmt.finalize();
|
||||||
|
|
||||||
|
db.schemaVersion = 15;
|
||||||
|
Services.prefs.setIntPref("extensions.databaseSchema", 14);
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
startupManager();
|
||||||
|
|
||||||
|
AddonManager.getAddonByID("addon1@tests.mozilla.org",
|
||||||
|
function check_before_rebuild (a1) {
|
||||||
|
// First check that it migrated OK once
|
||||||
|
// addon1 was disabled in the database
|
||||||
|
do_check_neq(a1, null);
|
||||||
|
do_check_true(a1.userDisabled);
|
||||||
|
do_check_false(a1.appDisabled);
|
||||||
|
do_check_false(a1.isActive);
|
||||||
|
do_check_false(a1.strictCompatibility);
|
||||||
|
do_check_false(a1.foreignInstall);
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// now shut down, remove the JSON database,
|
||||||
|
// start up again, and make sure the data didn't migrate this time
|
||||||
|
add_test(function rebuild_again() {
|
||||||
|
shutdownManager();
|
||||||
|
gExtensionsJSON.remove(true);
|
||||||
|
startupManager();
|
||||||
|
|
||||||
|
AddonManager.getAddonByID("addon1@tests.mozilla.org",
|
||||||
|
function check_after_rebuild(a1) {
|
||||||
|
// addon1 was rebuilt from extensions directory,
|
||||||
|
// so it appears enabled as a foreign install
|
||||||
|
do_check_neq(a1, null);
|
||||||
|
do_check_false(a1.userDisabled);
|
||||||
|
do_check_false(a1.appDisabled);
|
||||||
|
do_check_true(a1.isActive);
|
||||||
|
do_check_false(a1.strictCompatibility);
|
||||||
|
do_check_true(a1.foreignInstall);
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
});
|
|
@ -205,6 +205,7 @@ skip-if = os == "android"
|
||||||
[test_migrate4.js]
|
[test_migrate4.js]
|
||||||
[test_migrate5.js]
|
[test_migrate5.js]
|
||||||
[test_migrateAddonRepository.js]
|
[test_migrateAddonRepository.js]
|
||||||
|
[test_migrate_max_version.js]
|
||||||
[test_onPropertyChanged_appDisabled.js]
|
[test_onPropertyChanged_appDisabled.js]
|
||||||
[test_permissions.js]
|
[test_permissions.js]
|
||||||
[test_plugins.js]
|
[test_plugins.js]
|
||||||
|
|
Загрузка…
Ссылка в новой задаче