Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite Migrations #577

Merged
merged 7 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 0 additions & 69 deletions app/src/main/java/eu/kanade/tachiyomi/Migrations.kt

This file was deleted.

35 changes: 20 additions & 15 deletions app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ import cafe.adriel.voyager.navigator.NavigatorDisposeBehavior
import cafe.adriel.voyager.navigator.currentOrThrow
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import eu.kanade.domain.base.BasePreferences
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.components.AppStateBanners
import eu.kanade.presentation.components.DownloadedOnlyBannerBackgroundColor
import eu.kanade.presentation.components.IncognitoModeBannerBackgroundColor
Expand All @@ -61,7 +59,6 @@ import eu.kanade.presentation.more.settings.screen.data.RestoreBackupScreen
import eu.kanade.presentation.util.AssistContentScreen
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.Migrations
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.download.DownloadCache
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
Expand Down Expand Up @@ -89,7 +86,11 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import logcat.LogPriority
import mihon.core.migration.Migrator
import mihon.core.migration.migrations.migrations
import tachiyomi.core.common.Constants
import tachiyomi.core.common.preference.Preference
import tachiyomi.core.common.preference.PreferenceStore
import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.library.service.LibraryPreferences
Expand All @@ -105,9 +106,7 @@ import androidx.compose.ui.graphics.Color.Companion as ComposeColor

class MainActivity : BaseActivity() {

private val sourcePreferences: SourcePreferences by injectLazy()
private val libraryPreferences: LibraryPreferences by injectLazy()
private val uiPreferences: UiPreferences by injectLazy()
private val preferences: BasePreferences by injectLazy()

private val downloadCache: DownloadCache by injectLazy()
Expand All @@ -130,16 +129,7 @@ class MainActivity : BaseActivity() {

super.onCreate(savedInstanceState)

val didMigration = if (isLaunch) {
Migrations.upgrade(
context = applicationContext,
preferenceStore = Injekt.get(),
sourcePreferences = Injekt.get(),
extensionRepoRepository = Injekt.get(),
)
} else {
false
}
val didMigration = migrate()

// Do not let the launcher create a new activity http://stackoverflow.com/questions/16283079
if (!isTaskRoot) {
Expand Down Expand Up @@ -350,6 +340,21 @@ class MainActivity : BaseActivity() {
}
}

private fun migrate(): Boolean {
val preferenceStore = Injekt.get<PreferenceStore>()
val preference = preferenceStore.getInt(Preference.appStateKey("last_version_code"), 0)
logcat { "Migration from ${preference.get()} to ${BuildConfig.VERSION_CODE}" }
return Migrator.migrate(
old = preference.get(),
new = BuildConfig.VERSION_CODE,
migrations = migrations,
onMigrationComplete = {
logcat { "Updating last version to ${BuildConfig.VERSION_CODE}" }
preference.set(BuildConfig.VERSION_CODE)
},
)
}

/**
* Sets custom splash screen exit animation on devices prior to Android 12.
*
Expand Down
19 changes: 19 additions & 0 deletions app/src/main/java/mihon/core/migration/Migration.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package mihon.core.migration

interface Migration {
val version: Float
AntsyLich marked this conversation as resolved.
Show resolved Hide resolved

suspend operator fun invoke(migrationContext: MigrationContext): Boolean

companion object {
const val ALWAYS = -1f

fun of(version: Float, action: suspend (MigrationContext) -> Boolean): Migration = object : Migration {
override val version: Float = version

override suspend operator fun invoke(migrationContext: MigrationContext): Boolean {
return action(migrationContext)
}
}
}
}
10 changes: 10 additions & 0 deletions app/src/main/java/mihon/core/migration/MigrationContext.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package mihon.core.migration

import uy.kohesive.injekt.Injekt

class MigrationContext {

inline fun <reified T> get(): T? {
return Injekt.getInstanceOrNull(T::class.java)
}
}
53 changes: 53 additions & 0 deletions app/src/main/java/mihon/core/migration/Migrator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package mihon.core.migration

import kotlinx.coroutines.runBlocking
import tachiyomi.core.common.util.system.logcat

object Migrator {

@SuppressWarnings("ReturnCount")
fun migrate(
old: Int,
new: Int,
migrations: List<Migration>,
dryrun: Boolean = false,
onMigrationComplete: () -> Unit
ghostbear marked this conversation as resolved.
Show resolved Hide resolved
): Boolean {
val migrationContext = MigrationContext()

if (old == 0) {
return migrationContext.migrate(
migrations = migrations.filter { it.isAlways() },
dryrun = dryrun
)
.also { onMigrationComplete() }
}

if (old >= new) {
return false
}

return migrationContext.migrate(
migrations = migrations.filter { it.isAlways() || it.version.toInt() in (old + 1)..new },
dryrun = dryrun
)
.also { onMigrationComplete() }
}

private fun Migration.isAlways() = version == Migration.ALWAYS

@SuppressWarnings("MaxLineLength")
private fun MigrationContext.migrate(migrations: List<Migration>, dryrun: Boolean): Boolean {
return migrations.sortedBy { it.version }
.map { migration ->
if (!dryrun) {
logcat { "Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" }
runBlocking { migration(this@migrate) }
} else {
logcat { "(Dry-run) Running migration: { name = ${migration::class.simpleName}, version = ${migration.version} }" }
true
}
}
.reduce { acc, b -> acc || b }
}
}
10 changes: 10 additions & 0 deletions app/src/main/java/mihon/core/migration/migrations/Migrations.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package mihon.core.migration.migrations

import mihon.core.migration.Migration

val migrations: List<Migration>
get() = listOf(
SetupBackupCreateMigration(),
SetupLibraryUpdateMigration(),
TrustExtensionRepositoryMigration(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package mihon.core.migration.migrations

import eu.kanade.tachiyomi.App
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
import mihon.core.migration.Migration
import mihon.core.migration.MigrationContext

class SetupBackupCreateMigration : Migration {
override val version: Float = Migration.ALWAYS

override suspend fun invoke(migrationContext: MigrationContext): Boolean {
val context = migrationContext.get<App>() ?: return false
BackupCreateJob.setupTask(context)
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package mihon.core.migration.migrations

import eu.kanade.tachiyomi.App
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import mihon.core.migration.Migration
import mihon.core.migration.MigrationContext

class SetupLibraryUpdateMigration : Migration {
override val version: Float = Migration.ALWAYS

override suspend fun invoke(migrationContext: MigrationContext): Boolean {
val context = migrationContext.get<App>() ?: return false
LibraryUpdateJob.setupTask(context)
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package mihon.core.migration.migrations

import eu.kanade.domain.source.service.SourcePreferences
import logcat.LogPriority
import mihon.core.migration.Migration
import mihon.core.migration.MigrationContext
import mihon.domain.extensionrepo.exception.SaveExtensionRepoException
import mihon.domain.extensionrepo.repository.ExtensionRepoRepository
import tachiyomi.core.common.util.lang.withIOContext
import tachiyomi.core.common.util.system.logcat

class TrustExtensionRepositoryMigration : Migration {
override val version: Float = 7f

override suspend fun invoke(migrationContext: MigrationContext): Boolean = withIOContext {
val sourcePreferences = migrationContext.get<SourcePreferences>() ?: return@withIOContext false
val extensionRepositoryRepository =
migrationContext.get<ExtensionRepoRepository>() ?: return@withIOContext false
for ((index, source) in sourcePreferences.extensionRepos().get().withIndex()) {
try {
extensionRepositoryRepository.upsertRepo(
source,
"Repo #${index + 1}",
null,
source,
"NOFINGERPRINT-${index + 1}",
)
} catch (e: SaveExtensionRepoException) {
logcat(LogPriority.ERROR, e) { "Error Migrating Extension Repo with baseUrl: $source" }
}
}
sourcePreferences.extensionRepos().delete()
return@withIOContext true
}
}
Loading