Compare commits

..

6 Commits

Author SHA1 Message Date
semantic-release-bot
cdf94ffeca chore(release): 1.4.0-dev.2 [skip ci]
# [1.4.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.4.0-dev.1...v1.4.0-dev.2) (2023-11-27)

### Bug Fixes

* Differentiate no package compatibility to any version compatibility ([762b7e3](762b7e3bc0))
* Sort the version maps by the most common version ([e4be6db](e4be6dbccd))

### Features

* Allow getting most common compatible versions for all packages ([96845ba](96845ba265))
2023-11-27 21:43:22 +00:00
oSumAtrIX
37434cf4a4 build: Bump dependencies 2023-11-27 22:40:07 +01:00
oSumAtrIX
73c97abedd chore: Lint code 2023-11-27 22:40:00 +01:00
oSumAtrIX
762b7e3bc0 fix: Differentiate no package compatibility to any version compatibility 2023-11-27 22:30:59 +01:00
oSumAtrIX
e4be6dbccd fix: Sort the version maps by the most common version 2023-11-27 21:21:25 +01:00
oSumAtrIX
96845ba265 feat: Allow getting most common compatible versions for all packages 2023-11-27 21:03:23 +01:00
5 changed files with 110 additions and 62 deletions

View File

@@ -1,3 +1,16 @@
# [1.4.0-dev.2](https://github.com/ReVanced/revanced-library/compare/v1.4.0-dev.1...v1.4.0-dev.2) (2023-11-27)
### Bug Fixes
* Differentiate no package compatibility to any version compatibility ([762b7e3](https://github.com/ReVanced/revanced-library/commit/762b7e3bc01e2ca33dfcdbb1b5028d60ef6e0a48))
* Sort the version maps by the most common version ([e4be6db](https://github.com/ReVanced/revanced-library/commit/e4be6dbccd86700ffafe7cd8395e845bbd3d5138))
### Features
* Allow getting most common compatible versions for all packages ([96845ba](https://github.com/ReVanced/revanced-library/commit/96845ba265e6dc208c7ac96f5e58734209cd1720))
# [1.4.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.3.0...v1.4.0-dev.1) (2023-11-27) # [1.4.0-dev.1](https://github.com/ReVanced/revanced-library/compare/v1.3.0...v1.4.0-dev.1) (2023-11-27)

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true org.gradle.parallel = true
org.gradle.caching = true org.gradle.caching = true
kotlin.code.style = official kotlin.code.style = official
version = 1.4.0-dev.1 version = 1.4.0-dev.2

View File

@@ -4,7 +4,7 @@ bcpkix-jdk18on = "1.76"
jackson-module-kotlin = "2.14.3" jackson-module-kotlin = "2.14.3"
jadb = "1.2.1" jadb = "1.2.1"
kotlin-reflect = "1.9.10" kotlin-reflect = "1.9.10"
kotlin-test = "1.9.10" kotlin-test = "1.9.20"
revanced-patcher = "19.0.0" revanced-patcher = "19.0.0"
binary-compatibility-validator = "0.13.2" binary-compatibility-validator = "0.13.2"

View File

@@ -1,14 +1,14 @@
package app.revanced.library package app.revanced.library
import app.revanced.patcher.PatchSet import app.revanced.patcher.PatchSet
import java.util.* import app.revanced.patcher.patch.Patch
private typealias PackageName = String typealias PackageName = String
private typealias Version = String typealias Version = String
private typealias Count = Int typealias Count = Int
private typealias VersionMap = SortedMap<Version, Count> typealias VersionMap = LinkedHashMap<Version, Count>
internal typealias PackageNameMap = Map<PackageName, VersionMap> typealias PackageNameMap = Map<PackageName, VersionMap>
/** /**
* Utility functions for working with patches. * Utility functions for working with patches.
@@ -48,30 +48,46 @@ object PatchUtils {
* Get the count of versions for each compatible package from a supplied set of [patches] ordered by the most common version. * 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 patches The set of patches to check.
* @param packageNames The names of the compatible packages. * @param packageNames The names of the compatible packages to include. If null, all packages will be included.
* @param countUnusedPatches Whether to count patches that are not used. * @param countUnusedPatches Whether to count patches that are not used.
* @return A map of package names to a map of versions to their count. * @return A map of package names to a map of versions to their count.
*/ */
fun getMostCommonCompatibleVersions( fun getMostCommonCompatibleVersions(
patches: PatchSet, patches: PatchSet,
packageNames: Set<String>, packageNames: Set<String>? = null,
countUnusedPatches: Boolean = false, countUnusedPatches: Boolean = false,
): PackageNameMap { ): PackageNameMap =
val wantedPackages = packageNames.toHashSet() buildMap {
return buildMap { fun filterWantedPackages(compatiblePackages: Iterable<Patch.CompatiblePackage>): Iterable<Patch.CompatiblePackage> {
val wantedPackages = packageNames?.toHashSet() ?: return compatiblePackages
return compatiblePackages.filter { it.name in wantedPackages }
}
patches patches
.filter { it.use || countUnusedPatches } .filter { it.use || countUnusedPatches }
.flatMap { it.compatiblePackages ?: emptyList() } .flatMap { it.compatiblePackages ?: emptyList() }
.filter { it.name in wantedPackages } .let(::filterWantedPackages)
.forEach { compatiblePackage -> .forEach { compatiblePackage ->
compatiblePackage.versions?.let { versions -> if (compatiblePackage.versions?.isEmpty() == true) {
val versionMap = getOrPut(compatiblePackage.name) { sortedMapOf() } return@forEach
}
val versionMap = getOrPut(compatiblePackage.name) { linkedMapOf() }
compatiblePackage.versions?.let { versions ->
versions.forEach { version -> versions.forEach { version ->
versionMap[version] = versionMap.getOrDefault(version, 0) + 1 versionMap[version] = versionMap.getOrDefault(version, 0) + 1
} }
} }
} }
// Sort the version maps by the most common version.
forEach { (packageName, versionMap) ->
this[packageName] =
versionMap
.asIterable()
.sortedWith(compareByDescending { it.value })
.associate { it.key to it.value } as VersionMap
}
} }
}
} }

View File

@@ -10,30 +10,64 @@ import kotlin.test.assertEquals
internal object PatchUtilsTest { internal object PatchUtilsTest {
private val patches = private val patches =
arrayOf( arrayOf(
newPatch("some.package", "a"), newPatch("some.package", setOf("a")),
newPatch("some.package", "a", "b", use = false), newPatch("some.package", setOf("a", "b"), use = false),
newPatch("some.package", "a", "b", "c", use = false), newPatch("some.package", setOf("a", "b", "c"), use = false),
newPatch("some.other.package", "b", use = false), newPatch("some.other.package", setOf("b"), use = false),
newPatch("some.other.package", "b", "c"), newPatch("some.other.package", setOf("b", "c")),
newPatch("some.other.package", "b", "c", "d"), newPatch("some.other.package", setOf("b", "c", "d")),
newPatch("some.other.other.package"), newPatch("some.other.other.package"),
newPatch("some.other.other.package", "a"), newPatch("some.other.other.package", setOf("a")),
newPatch("some.other.other.package", "b"), newPatch("some.other.other.package", setOf("b")),
newPatch("some.other.other.other.package", use = false), newPatch("some.other.other.other.package", use = false),
newPatch("some.other.other.other.package", use = false), newPatch("some.other.other.other.package", use = false),
).toSet() ).toSet()
@Test @Test
fun `return common versions correctly ordered for each package`() { fun `empty because package is incompatible with any version`() {
assertEqualsVersions( assertEqualsVersions(
expected = expected = emptyMap(),
mapOf( patches = setOf(newPatch("some.package", emptySet(), use = true)),
"some.package" to sortedMapOf("a" to 3, "b" to 2, "c" to 1), compatiblePackageNames = setOf("some.package"),
"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(),
), @Test
fun `empty list of versions because package is unconstrained to any version`() {
assertEqualsVersions(
expected = mapOf("some.package" to linkedMapOf()),
patches = setOf(newPatch("some.package")),
compatiblePackageNames = setOf("some.package"),
countUnusedPatches = true,
)
}
@Test
fun `empty because no known package was supplied`() {
assertEqualsVersions(
expected = emptyMap(),
patches, patches,
compatiblePackageNames = setOf("unknown.package"),
)
}
@Test
fun `common versions correctly ordered for each package`() {
fun assertEqualsExpected(compatiblePackageNames: Set<String>?) =
assertEqualsVersions(
expected =
mapOf(
"some.package" to linkedMapOf("a" to 3, "b" to 2, "c" to 1),
"some.other.package" to linkedMapOf("b" to 3, "c" to 2, "d" to 1),
"some.other.other.package" to linkedMapOf("a" to 1, "b" to 1),
"some.other.other.other.package" to linkedMapOf(),
),
patches,
compatiblePackageNames,
countUnusedPatches = true,
)
assertEqualsExpected(
compatiblePackageNames = compatiblePackageNames =
setOf( setOf(
"some.package", "some.package",
@@ -41,18 +75,21 @@ internal object PatchUtilsTest {
"some.other.other.package", "some.other.other.package",
"some.other.other.other.package", "some.other.other.other.package",
), ),
countUnusedPatches = true, )
assertEqualsExpected(
compatiblePackageNames = null,
) )
} }
@Test @Test
fun `return common versions correctly ordered for each package without counting unused patches`() { fun `common versions correctly ordered for each package without counting unused patches`() {
assertEqualsVersions( assertEqualsVersions(
expected = expected =
mapOf( mapOf(
"some.package" to sortedMapOf("a" to 1), "some.package" to linkedMapOf("a" to 1),
"some.other.package" to sortedMapOf("b" to 2, "c" to 2, "d" to 1), "some.other.package" to linkedMapOf("b" to 2, "c" to 2, "d" to 1),
"some.other.other.package" to sortedMapOf("a" to 1, "b" to 1), "some.other.other.package" to linkedMapOf("a" to 1, "b" to 1),
), ),
patches, patches,
compatiblePackageNames = compatiblePackageNames =
@@ -66,30 +103,11 @@ internal object PatchUtilsTest {
) )
} }
@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 =
arrayOf("a", "a", "c", "d", "a", "b", "c", "d", "a", "b", "c", "d") arrayOf("a", "a", "c", "d", "a", "b", "c", "d", "a", "b", "c", "d")
.map { version -> newPatch("some.package", version) } .map { version -> newPatch("some.package", setOf(version)) }
.toSet() .toSet()
assertEqualsVersion("a", patches, "some.package") assertEqualsVersion("a", patches, "some.package")
@@ -102,7 +120,7 @@ internal object PatchUtilsTest {
@Test @Test
fun `return null because no patch is compatible with the supplied package name`() { fun `return null because no patch is compatible with the supplied package name`() {
val patches = setOf(newPatch("some.package", "a")) val patches = setOf(newPatch("some.package", setOf("a")))
assertEqualsVersion(null, patches, "other.package") assertEqualsVersion(null, patches, "other.package")
} }
@@ -121,7 +139,7 @@ internal object PatchUtilsTest {
private fun assertEqualsVersions( private fun assertEqualsVersions(
expected: PackageNameMap, expected: PackageNameMap,
patches: PatchSet, patches: PatchSet,
compatiblePackageNames: Set<String>, compatiblePackageNames: Set<String>?,
countUnusedPatches: Boolean = false, countUnusedPatches: Boolean = false,
) = assertEquals( ) = assertEquals(
expected, expected,
@@ -135,6 +153,7 @@ internal object PatchUtilsTest {
) { ) {
// Test both the deprecated and the new method. // Test both the deprecated and the new method.
@Suppress("DEPRECATION")
assertEquals( assertEquals(
expected, expected,
PatchUtils.getMostCommonCompatibleVersion(patches, compatiblePackageName), PatchUtils.getMostCommonCompatibleVersion(patches, compatiblePackageName),
@@ -149,7 +168,7 @@ internal object PatchUtilsTest {
private fun newPatch( private fun newPatch(
packageName: String, packageName: String,
vararg versions: String, versions: Set<String>? = null,
use: Boolean = true, use: Boolean = true,
) = object : BytecodePatch() { ) = object : BytecodePatch() {
init { init {
@@ -158,7 +177,7 @@ internal object PatchUtilsTest {
val compatiblePackagesField = Patch::class.java.getDeclaredField("compatiblePackages") val compatiblePackagesField = Patch::class.java.getDeclaredField("compatiblePackages")
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") val useField = Patch::class.java.getDeclaredField("use")