mirror of
https://github.com/ReVanced/revanced-library.git
synced 2026-01-11 13:56:17 +00:00
feat: Add PatchUtils#getMostCommonCompatibleVersions utility function
This commit is contained in:
@@ -63,6 +63,8 @@ public final class app/revanced/library/Options$Patch$Option {
|
|||||||
public final class app/revanced/library/PatchUtils {
|
public final class app/revanced/library/PatchUtils {
|
||||||
public static final field INSTANCE Lapp/revanced/library/PatchUtils;
|
public static final field INSTANCE Lapp/revanced/library/PatchUtils;
|
||||||
public final fun getMostCommonCompatibleVersion (Ljava/util/Set;Ljava/lang/String;)Ljava/lang/String;
|
public final fun getMostCommonCompatibleVersion (Ljava/util/Set;Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
public final fun getMostCommonCompatibleVersions (Ljava/util/Set;Ljava/util/Set;Z)Ljava/util/Map;
|
||||||
|
public static synthetic fun getMostCommonCompatibleVersions$default (Lapp/revanced/library/PatchUtils;Ljava/util/Set;Ljava/util/Set;ZILjava/lang/Object;)Ljava/util/Map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class app/revanced/library/adb/AdbManager {
|
public abstract class app/revanced/library/adb/AdbManager {
|
||||||
@@ -87,6 +89,7 @@ public final class app/revanced/library/adb/AdbManager$Companion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/library/adb/AdbManager$DeviceNotFoundException : java/lang/Exception {
|
public final class app/revanced/library/adb/AdbManager$DeviceNotFoundException : java/lang/Exception {
|
||||||
|
public fun <init> ()V
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/library/adb/AdbManager$FailedToFindInstalledPackageException : java/lang/Exception {
|
public final class app/revanced/library/adb/AdbManager$FailedToFindInstalledPackageException : java/lang/Exception {
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
package app.revanced.library
|
package app.revanced.library
|
||||||
|
|
||||||
import app.revanced.patcher.PatchSet
|
import app.revanced.patcher.PatchSet
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
private typealias PackageName = String
|
||||||
|
private typealias Version = String
|
||||||
|
private typealias Count = Int
|
||||||
|
|
||||||
|
private typealias VersionMap = SortedMap<Version, Count>
|
||||||
|
internal typealias PackageNameMap = Map<PackageName, VersionMap>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility functions for working with patches.
|
* Utility functions for working with patches.
|
||||||
@@ -14,6 +22,13 @@ object PatchUtils {
|
|||||||
* @param packageName The name of the compatible package.
|
* @param packageName The name of the compatible package.
|
||||||
* @return The most common version of.
|
* @return The most common version of.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(
|
||||||
|
"Use getMostCommonCompatibleVersions instead.",
|
||||||
|
ReplaceWith(
|
||||||
|
"getMostCommonCompatibleVersions(patches, setOf(packageName))" +
|
||||||
|
".entries.firstOrNull()?.value?.keys?.firstOrNull()",
|
||||||
|
),
|
||||||
|
)
|
||||||
fun getMostCommonCompatibleVersion(
|
fun getMostCommonCompatibleVersion(
|
||||||
patches: PatchSet,
|
patches: PatchSet,
|
||||||
packageName: String,
|
packageName: String,
|
||||||
@@ -28,4 +43,35 @@ object PatchUtils {
|
|||||||
.groupingBy { it }
|
.groupingBy { it }
|
||||||
.eachCount()
|
.eachCount()
|
||||||
.maxByOrNull { it.value }?.key
|
.maxByOrNull { it.value }?.key
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the count of versions for each compatible package from a supplied set of [patches] ordered by the most common version.
|
||||||
|
*
|
||||||
|
* @param patches The set of patches to check.
|
||||||
|
* @param packageNames The names of the compatible packages.
|
||||||
|
* @param countUnusedPatches Whether to count patches that are not used.
|
||||||
|
* @return A map of package names to a map of versions to their count.
|
||||||
|
*/
|
||||||
|
fun getMostCommonCompatibleVersions(
|
||||||
|
patches: PatchSet,
|
||||||
|
packageNames: Set<String>,
|
||||||
|
countUnusedPatches: Boolean = false,
|
||||||
|
): PackageNameMap {
|
||||||
|
val wantedPackages = packageNames.toHashSet()
|
||||||
|
return buildMap {
|
||||||
|
patches
|
||||||
|
.filter { it.use || countUnusedPatches }
|
||||||
|
.flatMap { it.compatiblePackages ?: emptyList() }
|
||||||
|
.filter { it.name in wantedPackages }
|
||||||
|
.forEach { compatiblePackage ->
|
||||||
|
compatiblePackage.versions?.let { versions ->
|
||||||
|
val versionMap = getOrPut(compatiblePackage.name) { sortedMapOf() }
|
||||||
|
|
||||||
|
versions.forEach { version ->
|
||||||
|
versionMap[version] = versionMap.getOrDefault(version, 0) + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,83 @@ import org.junit.jupiter.api.Test
|
|||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
internal object PatchUtilsTest {
|
internal object PatchUtilsTest {
|
||||||
|
private val patches =
|
||||||
|
arrayOf(
|
||||||
|
newPatch("some.package", "a"),
|
||||||
|
newPatch("some.package", "a", "b", use = false),
|
||||||
|
newPatch("some.package", "a", "b", "c", use = false),
|
||||||
|
newPatch("some.other.package", "b", use = false),
|
||||||
|
newPatch("some.other.package", "b", "c"),
|
||||||
|
newPatch("some.other.package", "b", "c", "d"),
|
||||||
|
newPatch("some.other.other.package"),
|
||||||
|
newPatch("some.other.other.package", "a"),
|
||||||
|
newPatch("some.other.other.package", "b"),
|
||||||
|
newPatch("some.other.other.other.package", use = false),
|
||||||
|
newPatch("some.other.other.other.package", use = false),
|
||||||
|
).toSet()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `return common versions correctly ordered for each package`() {
|
||||||
|
assertEqualsVersions(
|
||||||
|
expected =
|
||||||
|
mapOf(
|
||||||
|
"some.package" to sortedMapOf("a" to 3, "b" to 2, "c" to 1),
|
||||||
|
"some.other.package" to sortedMapOf("b" to 3, "c" to 2, "d" to 1),
|
||||||
|
"some.other.other.package" to sortedMapOf("a" to 1, "b" to 1),
|
||||||
|
"some.other.other.other.package" to sortedMapOf(),
|
||||||
|
),
|
||||||
|
patches,
|
||||||
|
compatiblePackageNames =
|
||||||
|
setOf(
|
||||||
|
"some.package",
|
||||||
|
"some.other.package",
|
||||||
|
"some.other.other.package",
|
||||||
|
"some.other.other.other.package",
|
||||||
|
),
|
||||||
|
countUnusedPatches = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `return common versions correctly ordered for each package without counting unused patches`() {
|
||||||
|
assertEqualsVersions(
|
||||||
|
expected =
|
||||||
|
mapOf(
|
||||||
|
"some.package" to sortedMapOf("a" to 1),
|
||||||
|
"some.other.package" to sortedMapOf("b" to 2, "c" to 2, "d" to 1),
|
||||||
|
"some.other.other.package" to sortedMapOf("a" to 1, "b" to 1),
|
||||||
|
),
|
||||||
|
patches,
|
||||||
|
compatiblePackageNames =
|
||||||
|
setOf(
|
||||||
|
"some.package",
|
||||||
|
"some.other.package",
|
||||||
|
"some.other.other.package",
|
||||||
|
"some.other.other.other.package",
|
||||||
|
),
|
||||||
|
countUnusedPatches = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `return an empty map because no known package was supplied`() {
|
||||||
|
assertEqualsVersions(
|
||||||
|
expected = emptyMap(),
|
||||||
|
patches,
|
||||||
|
compatiblePackageNames = setOf("unknown.package"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `return empty set of versions because no compatible package is constrained to a version`() {
|
||||||
|
assertEqualsVersions(
|
||||||
|
expected = mapOf("some.package" to sortedMapOf()),
|
||||||
|
patches = setOf(newPatch("some.package")),
|
||||||
|
compatiblePackageNames = setOf("some.package"),
|
||||||
|
countUnusedPatches = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `return 'a' because it is the most common version`() {
|
fun `return 'a' because it is the most common version`() {
|
||||||
val patches =
|
val patches =
|
||||||
@@ -31,7 +108,7 @@ internal object PatchUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `return null because no patch compatible package is constrained to a version`() {
|
fun `return null because no compatible package is constrained to a version`() {
|
||||||
val patches =
|
val patches =
|
||||||
setOf(
|
setOf(
|
||||||
newPatch("other.package"),
|
newPatch("other.package"),
|
||||||
@@ -41,15 +118,39 @@ internal object PatchUtilsTest {
|
|||||||
assertEqualsVersion(null, patches, "other.package")
|
assertEqualsVersion(null, patches, "other.package")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun assertEqualsVersions(
|
||||||
|
expected: PackageNameMap,
|
||||||
|
patches: PatchSet,
|
||||||
|
compatiblePackageNames: Set<String>,
|
||||||
|
countUnusedPatches: Boolean = false,
|
||||||
|
) = assertEquals(
|
||||||
|
expected,
|
||||||
|
PatchUtils.getMostCommonCompatibleVersions(patches, compatiblePackageNames, countUnusedPatches),
|
||||||
|
)
|
||||||
|
|
||||||
private fun assertEqualsVersion(
|
private fun assertEqualsVersion(
|
||||||
expected: String?,
|
expected: String?,
|
||||||
patches: PatchSet,
|
patches: PatchSet,
|
||||||
compatiblePackageName: String,
|
compatiblePackageName: String,
|
||||||
) = assertEquals(expected, PatchUtils.getMostCommonCompatibleVersion(patches, compatiblePackageName))
|
) {
|
||||||
|
// Test both the deprecated and the new method.
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
expected,
|
||||||
|
PatchUtils.getMostCommonCompatibleVersion(patches, compatiblePackageName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
expected,
|
||||||
|
PatchUtils.getMostCommonCompatibleVersions(patches, setOf(compatiblePackageName))
|
||||||
|
.entries.firstOrNull()?.value?.keys?.firstOrNull(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun newPatch(
|
private fun newPatch(
|
||||||
packageName: String,
|
packageName: String,
|
||||||
vararg versions: String,
|
vararg versions: String,
|
||||||
|
use: Boolean = true,
|
||||||
) = object : BytecodePatch() {
|
) = object : BytecodePatch() {
|
||||||
init {
|
init {
|
||||||
// Set the compatible packages field to the supplied package name and versions reflectively,
|
// Set the compatible packages field to the supplied package name and versions reflectively,
|
||||||
@@ -58,8 +159,16 @@ internal object PatchUtilsTest {
|
|||||||
|
|
||||||
compatiblePackagesField.isAccessible = true
|
compatiblePackagesField.isAccessible = true
|
||||||
compatiblePackagesField.set(this, setOf(CompatiblePackage(packageName, versions.toSet())))
|
compatiblePackagesField.set(this, setOf(CompatiblePackage(packageName, versions.toSet())))
|
||||||
|
|
||||||
|
val useField = Patch::class.java.getDeclaredField("use")
|
||||||
|
|
||||||
|
useField.isAccessible = true
|
||||||
|
useField.set(this, use)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {}
|
override fun execute(context: BytecodeContext) {}
|
||||||
|
|
||||||
|
// Needed to make the patches unique.
|
||||||
|
override fun equals(other: Any?) = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user