* [#1974] Uninstall extension completely on install failure * Add changelog entry --------- Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
This commit is contained in:
@@ -50,6 +50,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||||||
- (**Source/API**) Fix handling of nullable preference keys (TYPE "preferences")
|
- (**Source/API**) Fix handling of nullable preference keys (TYPE "preferences")
|
||||||
- (**Source**) Fix local manga thumbnails handling
|
- (**Source**) Fix local manga thumbnails handling
|
||||||
- (**Extension**) Fix missing icon for manually installed source
|
- (**Extension**) Fix missing icon for manually installed source
|
||||||
|
- (**Extension**) Fix installation retry always fails
|
||||||
- (**Extension**) Fixed a java.lang.VerifyError when installing an extension that has ProGuard enabled.
|
- (**Extension**) Fixed a java.lang.VerifyError when installing an extension that has ProGuard enabled.
|
||||||
- (**Backup**) Fix importing of backups with missing server settings
|
- (**Backup**) Fix importing of backups with missing server settings
|
||||||
- (**Backup**) Fix importing of backups with invalid server settings
|
- (**Backup**) Fix importing of backups with invalid server settings
|
||||||
|
|||||||
@@ -119,7 +119,6 @@ object Extension {
|
|||||||
|
|
||||||
val dirPathWithoutType = "${applicationDirs.extensionsRoot}/$fileNameWithoutType"
|
val dirPathWithoutType = "${applicationDirs.extensionsRoot}/$fileNameWithoutType"
|
||||||
val jarFilePath = "$dirPathWithoutType.jar"
|
val jarFilePath = "$dirPathWithoutType.jar"
|
||||||
val dexFilePath = "$dirPathWithoutType.dex"
|
|
||||||
|
|
||||||
val packageInfo = getPackageInfo(apkFilePath)
|
val packageInfo = getPackageInfo(apkFilePath)
|
||||||
val pkgName = packageInfo.packageName
|
val pkgName = packageInfo.packageName
|
||||||
@@ -163,71 +162,79 @@ object Extension {
|
|||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
File(apkFilePath).delete()
|
File(apkFilePath).delete()
|
||||||
File(dexFilePath).delete()
|
|
||||||
|
|
||||||
// collect sources from the extension
|
try {
|
||||||
val extensionMainClassInstance = loadExtensionSources(jarFilePath, className)
|
// collect sources from the extension
|
||||||
val sources: List<CatalogueSource> =
|
val extensionMainClassInstance = loadExtensionSources(jarFilePath, className)
|
||||||
when (extensionMainClassInstance) {
|
val sources: List<CatalogueSource> =
|
||||||
is Source -> listOf(extensionMainClassInstance)
|
when (extensionMainClassInstance) {
|
||||||
is SourceFactory -> extensionMainClassInstance.createSources()
|
is Source -> listOf(extensionMainClassInstance)
|
||||||
else -> throw RuntimeException("Unknown source class type! ${extensionMainClassInstance.javaClass}")
|
is SourceFactory -> extensionMainClassInstance.createSources()
|
||||||
}.map { it as CatalogueSource }
|
else -> throw RuntimeException("Unknown source class type! ${extensionMainClassInstance.javaClass}")
|
||||||
|
}.map { it as CatalogueSource }
|
||||||
|
|
||||||
val langs = sources.map { it.lang }.toSet()
|
val langs = sources.map { it.lang }.toSet()
|
||||||
val extensionLang =
|
val extensionLang =
|
||||||
when (langs.size) {
|
when (langs.size) {
|
||||||
0 -> ""
|
0 -> ""
|
||||||
1 -> langs.first()
|
1 -> langs.first()
|
||||||
else -> "all"
|
else -> "all"
|
||||||
}
|
}
|
||||||
|
|
||||||
val extensionName =
|
val extensionName =
|
||||||
packageInfo.applicationInfo.nonLocalizedLabel
|
packageInfo.applicationInfo.nonLocalizedLabel
|
||||||
.toString()
|
.toString()
|
||||||
.substringAfter("Tachiyomi: ")
|
.substringAfter("Tachiyomi: ")
|
||||||
|
|
||||||
// update extension info
|
// update extension info
|
||||||
transaction {
|
transaction {
|
||||||
if (ExtensionTable.selectAll().where { ExtensionTable.pkgName eq pkgName }.firstOrNull() == null) {
|
if (ExtensionTable.selectAll().where { ExtensionTable.pkgName eq pkgName }.firstOrNull() == null) {
|
||||||
ExtensionTable.insert {
|
ExtensionTable.insert {
|
||||||
|
it[this.apkName] = apkName
|
||||||
|
it[name] = extensionName
|
||||||
|
it[this.pkgName] = packageInfo.packageName
|
||||||
|
it[versionName] = packageInfo.versionName
|
||||||
|
it[versionCode] = packageInfo.versionCode
|
||||||
|
it[lang] = extensionLang
|
||||||
|
it[this.isNsfw] = isNsfw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtensionTable.update({ ExtensionTable.pkgName eq pkgName }) {
|
||||||
it[this.apkName] = apkName
|
it[this.apkName] = apkName
|
||||||
it[name] = extensionName
|
it[this.isInstalled] = true
|
||||||
it[this.pkgName] = packageInfo.packageName
|
it[this.classFQName] = className
|
||||||
it[versionName] = packageInfo.versionName
|
it[versionName] = packageInfo.versionName
|
||||||
it[versionCode] = packageInfo.versionCode
|
it[versionCode] = packageInfo.versionCode
|
||||||
it[lang] = extensionLang
|
}
|
||||||
it[this.isNsfw] = isNsfw
|
|
||||||
|
val extensionId =
|
||||||
|
ExtensionTable
|
||||||
|
.selectAll()
|
||||||
|
.where { ExtensionTable.pkgName eq pkgName }
|
||||||
|
.first()[ExtensionTable.id]
|
||||||
|
.value
|
||||||
|
|
||||||
|
sources.forEach { httpSource ->
|
||||||
|
SourceTable.insert {
|
||||||
|
it[id] = httpSource.id
|
||||||
|
it[name] = httpSource.name
|
||||||
|
it[lang] = httpSource.lang
|
||||||
|
it[extension] = extensionId
|
||||||
|
it[SourceTable.isNsfw] = isNsfw
|
||||||
|
}
|
||||||
|
logger.debug { "Installed source ${httpSource.name} (${httpSource.lang}) with id:${httpSource.id}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 201 // we installed successfully
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
// free up the file descriptor if exists
|
||||||
|
PackageTools.jarLoaderMap.remove(jarFilePath)?.close()
|
||||||
|
File(jarFilePath).delete()
|
||||||
|
|
||||||
ExtensionTable.update({ ExtensionTable.pkgName eq pkgName }) {
|
uninstallExtension(pkgName)
|
||||||
it[this.apkName] = apkName
|
throw e
|
||||||
it[this.isInstalled] = true
|
|
||||||
it[this.classFQName] = className
|
|
||||||
it[versionName] = packageInfo.versionName
|
|
||||||
it[versionCode] = packageInfo.versionCode
|
|
||||||
}
|
|
||||||
|
|
||||||
val extensionId =
|
|
||||||
ExtensionTable
|
|
||||||
.selectAll()
|
|
||||||
.where { ExtensionTable.pkgName eq pkgName }
|
|
||||||
.first()[ExtensionTable.id]
|
|
||||||
.value
|
|
||||||
|
|
||||||
sources.forEach { httpSource ->
|
|
||||||
SourceTable.insert {
|
|
||||||
it[id] = httpSource.id
|
|
||||||
it[name] = httpSource.name
|
|
||||||
it[lang] = httpSource.lang
|
|
||||||
it[extension] = extensionId
|
|
||||||
it[SourceTable.isNsfw] = isNsfw
|
|
||||||
}
|
|
||||||
logger.debug { "Installed source ${httpSource.name} (${httpSource.lang}) with id:${httpSource.id}" }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 201 // we installed successfully
|
|
||||||
} else {
|
} else {
|
||||||
return 302 // extension was already installed
|
return 302 // extension was already installed
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user