[app] Add ContentProviderMigrator to migrate old repos to new DB

This commit is contained in:
Torsten Grote
2022-12-12 15:50:23 -03:00
parent 90a14f82a1
commit 9bd49fc5fc
5 changed files with 99 additions and 5 deletions

View File

@@ -1,4 +1,5 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'checkstyle'
apply plugin: 'pmd'

View File

@@ -57,6 +57,7 @@ import org.fdroid.database.Repository;
import org.fdroid.fdroid.Preferences.ChangeListener;
import org.fdroid.fdroid.Preferences.Theme;
import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.ContentProviderMigrator;
import org.fdroid.fdroid.data.DBHelper;
import org.fdroid.fdroid.installer.ApkFileProvider;
import org.fdroid.fdroid.installer.InstallHistoryService;
@@ -414,6 +415,17 @@ public class FDroidApp extends Application implements androidx.work.Configuratio
if (Preferences.get().isScanRemovableStorageEnabled()) {
SDCardScannerService.scan(this);
}
// Migrate repos from old content providers to new Room-based DB.
// Added end of 2022 for alphas, can be removed after sufficient time has passed.
Utils.runOffUiThread(() -> {
ContentProviderMigrator migrator = ContentProviderMigrator.INSTANCE;
if (migrator.needsMigration(this)) {
migrator.migrateOldRepos(this, db);
migrator.removeOldDb(this);
UpdateService.forceUpdateRepo(this);
}
});
}
/**

View File

@@ -406,11 +406,7 @@ public class UpdateService extends JobIntentService {
}
} else if ((manualUpdate || forcedUpdate) && fdroidPrefs.isOnDemandDownloadAllowed()) {
Utils.debugLog(TAG, "manually requested or forced update");
if (forcedUpdate) {
DBHelper.resetRepos(this);
// TODO check if we still need something like this:
// InstalledAppProviderService.compareToPackageManager(this);
}
if (forcedUpdate) DBHelper.resetTransient(this);
} else if (!fdroidPrefs.isBackgroundDownloadAllowed() && !fdroidPrefs.isOnDemandDownloadAllowed()) {
Utils.debugLog(TAG, "don't run update");
return;

View File

@@ -0,0 +1,75 @@
package org.fdroid.fdroid.data
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import org.fdroid.database.FDroidDatabase
import org.fdroid.database.InitialRepository
object ContentProviderMigrator {
private const val OLD_DB_NAME = "fdroid"
fun needsMigration(context: Context): Boolean {
return context.databaseList().contains(OLD_DB_NAME)
}
fun migrateOldRepos(context: Context, db: FDroidDatabase) {
val repoDao = db.getRepositoryDao()
val repos = repoDao.getRepositories()
var weight = repos.last().weight
ContentProviderDbHelper(context).readableDatabase.use { oldDb ->
val projection = arrayOf("address", "pubkey", "inuse", "userMirrors", "disabledMirrors")
oldDb.query("fdroid_repo", projection, null, null, null, null, null).use { c ->
while (c.moveToNext()) {
val address = c.getString(c.getColumnIndexOrThrow("address"))
val certificate = c.getString(c.getColumnIndexOrThrow("pubkey"))
?.lowercase() ?: continue
val enabled = c.getInt(c.getColumnIndexOrThrow("inuse")) == 1
val userMirrors = c.getString(c.getColumnIndexOrThrow("userMirrors"))
?.split(',')
val disabledMirrors = c.getString(c.getColumnIndexOrThrow("disabledMirrors"))
?.split(',')
// find existing repos by address, because F-Droid archive re-uses certificate
val repo = repos.find { it.address == address }
if (repo == null) { // new repo to be added to new DB
val newRepo = InitialRepository(
name = "",
address = address,
description = "",
certificate = certificate,
version = 0,
enabled = enabled,
weight = ++weight,
)
repoDao.insert(newRepo)
} else { // old repo that may need an update for the new DB
if (repo.certificate != certificate) {
continue // don't update with certificate does not match
}
if (repo.enabled != enabled) {
repoDao.setRepositoryEnabled(repo.repoId, enabled)
}
if (!userMirrors.isNullOrEmpty()) {
repoDao.updateUserMirrors(repo.repoId, userMirrors)
}
if (!disabledMirrors.isNullOrEmpty()) {
repoDao.updateDisabledMirrors(repo.repoId, disabledMirrors)
}
}
}
}
}
}
fun removeOldDb(context: Context) {
context.deleteDatabase(OLD_DB_NAME)
}
private class ContentProviderDbHelper(
context: Context,
) : SQLiteOpenHelper(context, OLD_DB_NAME, null, 85) {
override fun onCreate(db: SQLiteDatabase) {}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {}
}
}

View File

@@ -81,6 +81,16 @@ public class DBHelper {
}
}
/**
* Removes all index data related to apps from the DB.
* Leaves repositories, their preferences as well as app preferences in place.
*/
@AnyThread
public static void resetTransient(Context context) {
FDroidDatabase db = getDb(context);
Utils.runOffUiThread(() -> db.getAppDao().clearAll());
}
@AnyThread
public static void resetRepos(Context context) {
FDroidDatabase db = getDb(context);