diff --git a/database/src/androidTest/java/org/fdroid/database/AppTest.kt b/database/src/androidTest/java/org/fdroid/database/AppTest.kt index 295fc1672..b2b4e69f7 100644 --- a/database/src/androidTest/java/org/fdroid/database/AppTest.kt +++ b/database/src/androidTest/java/org/fdroid/database/AppTest.kt @@ -28,7 +28,7 @@ internal class AppTest : DbTest() { @Test fun insertGetDeleteSingleApp() { - val repoId = repoDao.insert(getRandomRepo()) + val repoId = repoDao.insertOrReplace(getRandomRepo()) val metadataV2 = getRandomMetadataV2() appDao.insert(repoId, packageId, metadataV2) @@ -53,7 +53,7 @@ internal class AppTest : DbTest() { @Test fun testAppOverViewItem() { - val repoId = repoDao.insert(getRandomRepo()) + val repoId = repoDao.insertOrReplace(getRandomRepo()) val packageId1 = getRandomString() val packageId2 = getRandomString() val packageId3 = getRandomString() @@ -90,7 +90,7 @@ internal class AppTest : DbTest() { assertNull(apps3.find { it.packageId == packageId3 }) // app4 is the same as app1 and thus will not be shown again - val repoId2 = repoDao.insert(getRandomRepo()) + val repoId2 = repoDao.insertOrReplace(getRandomRepo()) val app4 = getRandomMetadataV2().copy(name = name2, icon = icons2) appDao.insert(repoId2, packageId1, app4) val apps4 = appDao.getAppOverviewItems().getOrAwaitValue() ?: fail() @@ -99,8 +99,8 @@ internal class AppTest : DbTest() { @Test fun testAppByRepoWeight() { - val repoId1 = repoDao.insert(getRandomRepo()) - val repoId2 = repoDao.insert(getRandomRepo()) + val repoId1 = repoDao.insertOrReplace(getRandomRepo()) + val repoId2 = repoDao.insertOrReplace(getRandomRepo()) val metadata1 = getRandomMetadataV2() val metadata2 = metadata1.copy(lastUpdated = metadata1.lastUpdated + 1) diff --git a/database/src/androidTest/java/org/fdroid/database/IndexV1InsertTest.kt b/database/src/androidTest/java/org/fdroid/database/IndexV1InsertTest.kt index 58259a64b..48b9b76cd 100644 --- a/database/src/androidTest/java/org/fdroid/database/IndexV1InsertTest.kt +++ b/database/src/androidTest/java/org/fdroid/database/IndexV1InsertTest.kt @@ -6,8 +6,16 @@ import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import kotlinx.serialization.SerializationException import org.apache.commons.io.input.CountingInputStream +import org.fdroid.CompatibilityChecker import org.fdroid.index.v1.IndexV1StreamProcessor -import org.fdroid.index.v2.IndexStreamProcessor +import org.fdroid.index.v1.IndexV1StreamReceiver +import org.fdroid.index.v2.AntiFeatureV2 +import org.fdroid.index.v2.CategoryV2 +import org.fdroid.index.v2.IndexV2StreamProcessor +import org.fdroid.index.v2.MetadataV2 +import org.fdroid.index.v2.PackageVersionV2 +import org.fdroid.index.v2.ReleaseChannelV2 +import org.fdroid.index.v2.RepoV2 import org.junit.Test import org.junit.runner.RunWith import kotlin.math.roundToInt @@ -25,7 +33,8 @@ internal class IndexV1InsertTest : DbTest() { val fileSize = c.resources.assets.openFd("index-v1.json").use { it.length } val inputStream = CountingInputStream(c.resources.assets.open("index-v1.json")) var currentByteCount: Long = 0 - val indexProcessor = IndexV1StreamProcessor(DbV1StreamReceiver(db) { true }, null) { + val repoId = db.getRepositoryDao().insertEmptyRepo("https://f-droid.org/repo") + val streamReceiver = TestStreamReceiver(repoId) { val bytesRead = inputStream.byteCount val bytesSinceLastCall = bytesRead - currentByteCount if (bytesSinceLastCall > 0) { @@ -36,13 +45,12 @@ internal class IndexV1InsertTest : DbTest() { // the stream gets read in big chunks, but ensure they are not too big, e.g. entire file assertTrue(bytesSinceLastCall < 600_000, "$bytesSinceLastCall") currentByteCount = bytesRead - bytesRead } + val indexProcessor = IndexV1StreamProcessor(streamReceiver, null) db.runInTransaction { - val repoId = db.getRepositoryDao().insertEmptyRepo("https://f-droid.org/repo") inputStream.use { indexStream -> - indexProcessor.process(repoId, indexStream) + indexProcessor.process(indexStream) } } assertTrue(repoDao.getRepositories().size == 1) @@ -112,11 +120,11 @@ internal class IndexV1InsertTest : DbTest() { private fun insertV2ForComparison(version: Int) { val c = getApplicationContext() val inputStream = CountingInputStream(c.resources.assets.open("index-v2.json")) - val indexProcessor = IndexStreamProcessor(DbStreamReceiver(db) { true }, null) + val repoId = db.getRepositoryDao().insertEmptyRepo("https://f-droid.org/repo") + val indexProcessor = IndexV2StreamProcessor(DbV2StreamReceiver(db, { true }, repoId), null) db.runInTransaction { - val repoId = db.getRepositoryDao().insertEmptyRepo("https://f-droid.org/repo") inputStream.use { indexStream -> - indexProcessor.process(repoId, version, indexStream) + indexProcessor.process(version, indexStream) } } } @@ -125,15 +133,17 @@ internal class IndexV1InsertTest : DbTest() { fun testExceptionWhileStreamingDoesNotSaveIntoDb() { val c = getApplicationContext() val cIn = CountingInputStream(c.resources.assets.open("index-v1.json")) - val indexProcessor = IndexStreamProcessor(DbStreamReceiver(db) { true }, null) { + val compatibilityChecker = CompatibilityChecker { if (cIn.byteCount > 824096) throw SerializationException() - cIn.byteCount + true } + val indexProcessor = + IndexV2StreamProcessor(DbV2StreamReceiver(db, compatibilityChecker, 1), null) assertFailsWith { db.runInTransaction { cIn.use { indexStream -> - indexProcessor.process(1, 42, indexStream) + indexProcessor.process(42, indexStream) } } } @@ -145,4 +155,40 @@ internal class IndexV1InsertTest : DbTest() { assertTrue(versionDao.countVersionedStrings() == 0) } + inner class TestStreamReceiver( + repoId: Long, + private val callback: () -> Unit, + ) : IndexV1StreamReceiver { + private val streamReceiver = DbV1StreamReceiver(db, { true }, repoId) + override fun receive(repo: RepoV2, version: Int, certificate: String?) { + streamReceiver.receive(repo, version, certificate) + callback() + } + + override fun receive(packageId: String, m: MetadataV2) { + streamReceiver.receive(packageId, m) + callback() + } + + override fun receive(packageId: String, v: Map) { + streamReceiver.receive(packageId, v) + callback() + } + + override fun updateRepo( + antiFeatures: Map, + categories: Map, + releaseChannels: Map, + ) { + streamReceiver.updateRepo(antiFeatures, categories, releaseChannels) + callback() + } + + override fun updateAppMetadata(packageId: String, preferredSigner: String?) { + streamReceiver.updateAppMetadata(packageId, preferredSigner) + callback() + } + + } + } diff --git a/database/src/androidTest/java/org/fdroid/database/IndexV2InsertTest.kt b/database/src/androidTest/java/org/fdroid/database/IndexV2InsertTest.kt index 141a6cc45..3446dee29 100644 --- a/database/src/androidTest/java/org/fdroid/database/IndexV2InsertTest.kt +++ b/database/src/androidTest/java/org/fdroid/database/IndexV2InsertTest.kt @@ -6,7 +6,8 @@ import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import kotlinx.serialization.SerializationException import org.apache.commons.io.input.CountingInputStream -import org.fdroid.index.v2.IndexStreamProcessor +import org.fdroid.CompatibilityChecker +import org.fdroid.index.v2.IndexV2StreamProcessor import org.junit.Test import org.junit.runner.RunWith import kotlin.math.roundToInt @@ -22,7 +23,7 @@ internal class IndexV2InsertTest : DbTest() { val fileSize = c.resources.assets.openFd("index-v2.json").use { it.length } val inputStream = CountingInputStream(c.resources.assets.open("index-v2.json")) var currentByteCount: Long = 0 - val indexProcessor = IndexStreamProcessor(DbStreamReceiver(db) { true }, null) { + val compatibilityChecker = CompatibilityChecker { val bytesRead = inputStream.byteCount val bytesSinceLastCall = bytesRead - currentByteCount if (bytesSinceLastCall > 0) { @@ -33,13 +34,15 @@ internal class IndexV2InsertTest : DbTest() { // the stream gets read in big chunks, but ensure they are not too big, e.g. entire file assertTrue(bytesSinceLastCall < 400_000, "$bytesSinceLastCall") currentByteCount = bytesRead - bytesRead + true } + val repoId = db.getRepositoryDao().insertEmptyRepo("https://f-droid.org/repo") + val streamReceiver = DbV2StreamReceiver(db, compatibilityChecker, repoId) + val indexProcessor = IndexV2StreamProcessor(streamReceiver, null) db.runInTransaction { - val repoId = db.getRepositoryDao().insertEmptyRepo("https://f-droid.org/repo") inputStream.use { indexStream -> - indexProcessor.process(repoId, 42, indexStream) + indexProcessor.process(42, indexStream) } } assertTrue(repoDao.getRepositories().size == 1) @@ -60,15 +63,17 @@ internal class IndexV2InsertTest : DbTest() { fun testExceptionWhileStreamingDoesNotSaveIntoDb() { val c = getApplicationContext() val cIn = CountingInputStream(c.resources.assets.open("index-v2.json")) - val indexProcessor = IndexStreamProcessor(DbStreamReceiver(db) { true }, null) { + val compatibilityChecker = CompatibilityChecker { if (cIn.byteCount > 824096) throw SerializationException() - cIn.byteCount + true } - assertFailsWith { db.runInTransaction { + val repoId = db.getRepositoryDao().insertEmptyRepo("http://example.org") + val streamReceiver = DbV2StreamReceiver(db, compatibilityChecker, repoId) + val indexProcessor = IndexV2StreamProcessor(streamReceiver, null) cIn.use { indexStream -> - indexProcessor.process(1, 42, indexStream) + indexProcessor.process(42, indexStream) } } } diff --git a/database/src/androidTest/java/org/fdroid/database/RepositoryDiffTest.kt b/database/src/androidTest/java/org/fdroid/database/RepositoryDiffTest.kt index 4fa401a6d..962e86b4d 100644 --- a/database/src/androidTest/java/org/fdroid/database/RepositoryDiffTest.kt +++ b/database/src/androidTest/java/org/fdroid/database/RepositoryDiffTest.kt @@ -48,10 +48,10 @@ internal class RepositoryDiffTest : DbTest() { fun timestampDiffTwoReposInDb() { // insert repo val repo = getRandomRepo() - repoDao.insert(repo) + repoDao.insertOrReplace(repo) // insert another repo before updating - repoDao.insert(getRandomRepo()) + repoDao.insertOrReplace(getRandomRepo()) // check that the repo got added and retrieved as expected var repos = repoDao.getRepositories().sortedBy { it.repoId } @@ -244,7 +244,7 @@ internal class RepositoryDiffTest : DbTest() { private fun testDiff(repo: RepoV2, json: String, repoChecker: (List) -> Unit) { // insert repo - repoDao.insert(repo) + repoDao.insertOrReplace(repo) // check that the repo got added and retrieved as expected var repos = repoDao.getRepositories() diff --git a/database/src/androidTest/java/org/fdroid/database/RepositoryTest.kt b/database/src/androidTest/java/org/fdroid/database/RepositoryTest.kt index be4ed360d..dd9e189bb 100644 --- a/database/src/androidTest/java/org/fdroid/database/RepositoryTest.kt +++ b/database/src/androidTest/java/org/fdroid/database/RepositoryTest.kt @@ -20,7 +20,7 @@ internal class RepositoryTest : DbTest() { fun insertAndDeleteTwoRepos() { // insert first repo val repo1 = getRandomRepo() - val repoId1 = repoDao.insert(repo1) + val repoId1 = repoDao.insertOrReplace(repo1) // check that first repo got added and retrieved as expected var repos = repoDao.getRepositories() @@ -31,7 +31,7 @@ internal class RepositoryTest : DbTest() { // insert second repo val repo2 = getRandomRepo() - val repoId2 = repoDao.insert(repo2) + val repoId2 = repoDao.insertOrReplace(repo2) // check that both repos got added and retrieved as expected repos = repoDao.getRepositories().sortedBy { it.repoId } @@ -58,8 +58,8 @@ internal class RepositoryTest : DbTest() { } @Test - fun replacingRepoRemovesAllAssociatedData() { - val repoId = repoDao.insert(getRandomRepo()) + fun clearingRepoRemovesAllAssociatedData() { + val repoId = repoDao.insertOrReplace(getRandomRepo()) val repositoryPreferences = repoDao.getRepositoryPreferences(repoId) val packageId = getRandomString() val versionId = getRandomString() @@ -72,22 +72,20 @@ internal class RepositoryTest : DbTest() { assertEquals(1, versionDao.getAppVersions(repoId, packageId).size) assertTrue(versionDao.getVersionedStrings(repoId, packageId).isNotEmpty()) - val cert = getRandomString() - repoDao.replace(repoId, getRandomRepo(), 42, cert) + repoDao.clear(repoId) assertEquals(1, repoDao.getRepositories().size) assertEquals(0, appDao.getAppMetadata().size) assertEquals(0, appDao.getLocalizedFiles().size) assertEquals(0, appDao.getLocalizedFileLists().size) assertEquals(0, versionDao.getAppVersions(repoId, packageId).size) assertEquals(0, versionDao.getVersionedStrings(repoId, packageId).size) - - assertEquals(cert, repoDao.getRepository(repoId)?.certificate) + // preferences are not touched by clearing assertEquals(repositoryPreferences, repoDao.getRepositoryPreferences(repoId)) } @Test - fun certGetsUpdates() { - val repoId = repoDao.insert(getRandomRepo()) + fun certGetsUpdated() { + val repoId = repoDao.insertOrReplace(getRandomRepo()) assertEquals(1, repoDao.getRepositories().size) assertEquals(null, repoDao.getRepositories()[0].certificate) diff --git a/database/src/androidTest/java/org/fdroid/database/UpdateCheckerTest.kt b/database/src/androidTest/java/org/fdroid/database/UpdateCheckerTest.kt index 07d84215c..9cd38ae1d 100644 --- a/database/src/androidTest/java/org/fdroid/database/UpdateCheckerTest.kt +++ b/database/src/androidTest/java/org/fdroid/database/UpdateCheckerTest.kt @@ -25,16 +25,16 @@ internal class UpdateCheckerTest : DbTest() { updateChecker = UpdateChecker(db, context.packageManager) } - @OptIn(ExperimentalTime::class) @Test + @OptIn(ExperimentalTime::class) fun testGetUpdates() { val inputStream = CountingInputStream(context.resources.assets.open("index-v1.json")) - val indexProcessor = IndexV1StreamProcessor(DbV1StreamReceiver(db) { true }, null) + val repoId = db.getRepositoryDao().insertEmptyRepo("https://f-droid.org/repo") + val indexProcessor = IndexV1StreamProcessor(DbV1StreamReceiver(db, { true }, repoId), null) db.runInTransaction { - val repoId = db.getRepositoryDao().insertEmptyRepo("https://f-droid.org/repo") inputStream.use { indexStream -> - indexProcessor.process(repoId, indexStream) + indexProcessor.process(indexStream) } } diff --git a/database/src/androidTest/java/org/fdroid/database/VersionTest.kt b/database/src/androidTest/java/org/fdroid/database/VersionTest.kt index 5db57b37e..8468685b5 100644 --- a/database/src/androidTest/java/org/fdroid/database/VersionTest.kt +++ b/database/src/androidTest/java/org/fdroid/database/VersionTest.kt @@ -25,7 +25,7 @@ internal class VersionTest : DbTest() { @Test fun insertGetDeleteSingleVersion() { - val repoId = repoDao.insert(getRandomRepo()) + val repoId = repoDao.insertOrReplace(getRandomRepo()) appDao.insert(repoId, packageId, getRandomMetadataV2()) val packageVersion = getRandomPackageVersionV2() val isCompatible = Random.nextBoolean() @@ -57,7 +57,7 @@ internal class VersionTest : DbTest() { @Test fun insertGetDeleteTwoVersions() { // insert two versions along with required objects - val repoId = repoDao.insert(getRandomRepo()) + val repoId = repoDao.insertOrReplace(getRandomRepo()) appDao.insert(repoId, packageId, getRandomMetadataV2()) val packageVersion1 = getRandomPackageVersionV2() val packageVersion2 = getRandomPackageVersionV2() diff --git a/database/src/main/java/org/fdroid/database/DbStreamReceiver.kt b/database/src/main/java/org/fdroid/database/DbStreamReceiver.kt deleted file mode 100644 index b5304505e..000000000 --- a/database/src/main/java/org/fdroid/database/DbStreamReceiver.kt +++ /dev/null @@ -1,33 +0,0 @@ -package org.fdroid.database - -import android.content.res.Resources -import androidx.core.os.ConfigurationCompat.getLocales -import androidx.core.os.LocaleListCompat -import org.fdroid.CompatibilityChecker -import org.fdroid.index.v2.IndexStreamReceiver -import org.fdroid.index.v2.PackageV2 -import org.fdroid.index.v2.RepoV2 - -internal class DbStreamReceiver( - private val db: FDroidDatabaseInt, - private val compatibilityChecker: CompatibilityChecker, -) : IndexStreamReceiver { - - private val locales: LocaleListCompat = getLocales(Resources.getSystem().configuration) - - override fun receive(repoId: Long, repo: RepoV2, version: Int, certificate: String?) { - db.getRepositoryDao().replace(repoId, repo, version, certificate) - } - - override fun receive(repoId: Long, packageId: String, p: PackageV2) { - db.getAppDao().insert(repoId, packageId, p.metadata, locales) - db.getVersionDao().insert(repoId, packageId, p.versions) { - compatibilityChecker.isCompatible(it.manifest) - } - } - - override fun onStreamEnded(repoId: Long) { - db.afterUpdatingRepo(repoId) - } - -} diff --git a/database/src/main/java/org/fdroid/database/DbV1StreamReceiver.kt b/database/src/main/java/org/fdroid/database/DbV1StreamReceiver.kt index 84cd5231a..5a0cbe8cd 100644 --- a/database/src/main/java/org/fdroid/database/DbV1StreamReceiver.kt +++ b/database/src/main/java/org/fdroid/database/DbV1StreamReceiver.kt @@ -12,29 +12,35 @@ import org.fdroid.index.v2.PackageVersionV2 import org.fdroid.index.v2.ReleaseChannelV2 import org.fdroid.index.v2.RepoV2 +/** + * Note that this class expects that its [receive] method with [RepoV2] gets called first. + * A different order of calls is not supported. + */ +@Deprecated("Use DbV2StreamReceiver instead") internal class DbV1StreamReceiver( private val db: FDroidDatabaseInt, private val compatibilityChecker: CompatibilityChecker, + private val repoId: Long, ) : IndexV1StreamReceiver { private val locales: LocaleListCompat = getLocales(Resources.getSystem().configuration) - override fun receive(repoId: Long, repo: RepoV2, version: Int, certificate: String?) { - db.getRepositoryDao().replace(repoId, repo, version, certificate) + override fun receive(repo: RepoV2, version: Int, certificate: String?) { + db.getRepositoryDao().clear(repoId) + db.getRepositoryDao().update(repoId, repo, version, certificate) } - override fun receive(repoId: Long, packageId: String, m: MetadataV2) { + override fun receive(packageId: String, m: MetadataV2) { db.getAppDao().insert(repoId, packageId, m, locales) } - override fun receive(repoId: Long, packageId: String, v: Map) { + override fun receive(packageId: String, v: Map) { db.getVersionDao().insert(repoId, packageId, v) { compatibilityChecker.isCompatible(it.manifest) } } override fun updateRepo( - repoId: Long, antiFeatures: Map, categories: Map, releaseChannels: Map, @@ -47,7 +53,7 @@ internal class DbV1StreamReceiver( db.afterUpdatingRepo(repoId) } - override fun updateAppMetadata(repoId: Long, packageId: String, preferredSigner: String?) { + override fun updateAppMetadata(packageId: String, preferredSigner: String?) { db.getAppDao().updatePreferredSigner(repoId, packageId, preferredSigner) } diff --git a/database/src/main/java/org/fdroid/database/DbV2StreamReceiver.kt b/database/src/main/java/org/fdroid/database/DbV2StreamReceiver.kt new file mode 100644 index 000000000..c06d612a9 --- /dev/null +++ b/database/src/main/java/org/fdroid/database/DbV2StreamReceiver.kt @@ -0,0 +1,52 @@ +package org.fdroid.database + +import android.content.res.Resources +import androidx.core.os.ConfigurationCompat.getLocales +import androidx.core.os.LocaleListCompat +import org.fdroid.CompatibilityChecker +import org.fdroid.index.v2.IndexV2StreamReceiver +import org.fdroid.index.v2.PackageV2 +import org.fdroid.index.v2.RepoV2 + +internal class DbV2StreamReceiver( + private val db: FDroidDatabaseInt, + private val compatibilityChecker: CompatibilityChecker, + private val repoId: Long, +) : IndexV2StreamReceiver { + + private val locales: LocaleListCompat = getLocales(Resources.getSystem().configuration) + private var clearedRepoData = false + + @Synchronized + override fun receive(repo: RepoV2, version: Int, certificate: String?) { + clearRepoDataIfNeeded() + db.getRepositoryDao().update(repoId, repo, version, certificate) + } + + @Synchronized + override fun receive(packageId: String, p: PackageV2) { + clearRepoDataIfNeeded() + db.getAppDao().insert(repoId, packageId, p.metadata, locales) + db.getVersionDao().insert(repoId, packageId, p.versions) { + compatibilityChecker.isCompatible(it.manifest) + } + } + + @Synchronized + override fun onStreamEnded() { + db.afterUpdatingRepo(repoId) + } + + /** + * As it is a valid index to receive packages before the repo, + * we can not clear all repo data when receiving the repo, + * but need to do it once at the beginning. + */ + private fun clearRepoDataIfNeeded() { + if (!clearedRepoData) { + db.getRepositoryDao().clear(repoId) + clearedRepoData = true + } + } + +} diff --git a/database/src/main/java/org/fdroid/database/RepositoryDao.kt b/database/src/main/java/org/fdroid/database/RepositoryDao.kt index 8dc64af5e..ccb8815c9 100644 --- a/database/src/main/java/org/fdroid/database/RepositoryDao.kt +++ b/database/src/main/java/org/fdroid/database/RepositoryDao.kt @@ -25,8 +25,15 @@ public interface RepositoryDao { /** * Use when replacing an existing repo with a full index. * This removes all existing index data associated with this repo from the database. + * @throws IllegalStateException if no repo with the given [repoId] exists. */ - public fun replace(repoId: Long, repository: RepoV2, version: Int, certificate: String?) + public fun clear(repoId: Long) + + /** + * Updates an existing repo with new data from a full index update. + * Call [clear] first to ensure old data was removed. + */ + public fun update(repoId: Long, repository: RepoV2, version: Int, certificate: String?) public fun getRepository(repoId: Long): Repository? public fun insertEmptyRepo( @@ -50,7 +57,10 @@ public interface RepositoryDao { internal interface RepositoryDaoInt : RepositoryDao { @Insert(onConflict = REPLACE) - fun insert(repository: CoreRepository): Long + fun insertOrReplace(repository: CoreRepository): Long + + @Update + fun update(repository: CoreRepository) @Insert(onConflict = REPLACE) fun insertMirrors(mirrors: List) @@ -78,7 +88,7 @@ internal interface RepositoryDaoInt : RepositoryDao { description = mapOf("en-US" to initialRepo.description), certificate = initialRepo.certificate, ) - val repoId = insert(repo) + val repoId = insertOrReplace(repo) val repositoryPreferences = RepositoryPreferences( repoId = repoId, weight = initialRepo.weight, @@ -102,7 +112,7 @@ internal interface RepositoryDaoInt : RepositoryDao { version = null, certificate = null, ) - val repoId = insert(repo) + val repoId = insertOrReplace(repo) val currentMaxWeight = getMaxRepositoryWeight() val repositoryPreferences = RepositoryPreferences( repoId = repoId, @@ -117,8 +127,8 @@ internal interface RepositoryDaoInt : RepositoryDao { @Transaction @VisibleForTesting - fun insert(repository: RepoV2): Long { - val repoId = insert(repository.toCoreRepository(version = 0)) + fun insertOrReplace(repository: RepoV2): Long { + val repoId = insertOrReplace(repository.toCoreRepository(version = 0)) insertRepositoryPreferences(repoId) insertRepoTables(repoId, repository) return repoId @@ -131,9 +141,15 @@ internal interface RepositoryDaoInt : RepositoryDao { } @Transaction - override fun replace(repoId: Long, repository: RepoV2, version: Int, certificate: String?) { - val newRepoId = insert(repository.toCoreRepository(repoId, version, certificate)) - require(newRepoId == repoId) { "New repoId $newRepoId did not match old $repoId" } + override fun clear(repoId: Long) { + val repo = getRepository(repoId) ?: error("repo with id $repoId does not exist") + // this clears all foreign key associated data since the repo gets replaced + insertOrReplace(repo.repository) + } + + @Transaction + override fun update(repoId: Long, repository: RepoV2, version: Int, certificate: String?) { + update(repository.toCoreRepository(repoId, version, certificate)) insertRepoTables(repoId, repository) } diff --git a/database/src/main/java/org/fdroid/index/v1/IndexV1Updater.kt b/database/src/main/java/org/fdroid/index/v1/IndexV1Updater.kt index f7e2ccafe..e8e947a09 100644 --- a/database/src/main/java/org/fdroid/index/v1/IndexV1Updater.kt +++ b/database/src/main/java/org/fdroid/index/v1/IndexV1Updater.kt @@ -65,9 +65,9 @@ public class IndexV1Updater( db.runInTransaction { val cert = verifier.getStreamAndVerify { inputStream -> updateListener?.onStartProcessing() // TODO maybe do more fine-grained reporting - val streamReceiver = DbV1StreamReceiver(db, compatibilityChecker) + val streamReceiver = DbV1StreamReceiver(db, compatibilityChecker, repoId) val streamProcessor = IndexV1StreamProcessor(streamReceiver, certificate) - streamProcessor.process(repoId, inputStream) + streamProcessor.process(inputStream) } // update certificate, if we didn't have any before if (certificate == null) {