This repository has been archived by the owner on Apr 15, 2024. It is now read-only.
forked from inotia00/revanced-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix!: support null as option value (ReVanced#221)
BREAKING-CHANGE: serialize options as JSON instead of TOML
- Loading branch information
Showing
7 changed files
with
182 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package app.revanced.utils | ||
|
||
import app.revanced.cli.command.PatchList | ||
import app.revanced.cli.logging.CliLogger | ||
import app.revanced.patcher.extensions.PatchExtensions.options | ||
import app.revanced.patcher.extensions.PatchExtensions.patchName | ||
import app.revanced.patcher.patch.NoSuchOptionException | ||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper | ||
import java.io.File | ||
|
||
|
||
internal object Options { | ||
private var mapper = jacksonObjectMapper() | ||
|
||
/** | ||
* Serializes the options for the patches in the list. | ||
* | ||
* @param patches The list of patches to serialize. | ||
* @param prettyPrint Whether to pretty print the JSON. | ||
* @return The JSON string containing the options. | ||
* @see PatchList | ||
*/ | ||
fun serialize(patches: PatchList, prettyPrint: Boolean = false): String = patches | ||
.filter { it.options?.any() == true } | ||
.map { patch -> | ||
PatchOption( | ||
patch.patchName, | ||
patch.options!!.map { option -> PatchOption.Option(option.key, option.value) } | ||
) | ||
}.let { | ||
if (prettyPrint) | ||
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(it) | ||
else | ||
mapper.writeValueAsString(it) | ||
} | ||
|
||
/** | ||
* Deserializes the options for the patches in the list. | ||
* | ||
* @param json The JSON string containing the options. | ||
* @return The list of [PatchOption]s. | ||
* @see PatchOption | ||
* @see PatchList | ||
*/ | ||
@Suppress("MemberVisibilityCanBePrivate") | ||
fun deserialize(json: String): Array<PatchOption> = mapper.readValue(json, Array<PatchOption>::class.java) | ||
|
||
/** | ||
* Sets the options for the patches in the list. | ||
* | ||
* @param json The JSON string containing the options. | ||
* @param logger The logger to use for logging. | ||
*/ | ||
fun PatchList.setOptions(json: String, logger: CliLogger? = null) { | ||
filter { it.options?.any() == true }.let { patches -> | ||
if (patches.isEmpty()) return | ||
|
||
val patchOptions = deserialize(json) | ||
|
||
patches.forEach { patch -> | ||
patchOptions.find { option -> option.patchName == patch.patchName }?.let { | ||
it.options.forEach { option -> | ||
try { | ||
patch.options?.set(option.key, option.value) | ||
?: logger?.warn("${patch.patchName} has no options") | ||
} catch (e: NoSuchOptionException) { | ||
logger?.error(e.message ?: "Unknown error") | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Sets the options for the patches in the list. | ||
* | ||
* @param file The file containing the JSON string containing the options. | ||
* @param logger The logger to use for logging. | ||
* @see setOptions | ||
*/ | ||
fun PatchList.setOptions(file: File, logger: CliLogger? = null) = setOptions(file.readText(), logger) | ||
|
||
/** | ||
* Data class for a patch and its [Option]s. | ||
* | ||
* @property patchName The name of the patch. | ||
* @property options The [Option]s for the patch. | ||
*/ | ||
internal data class PatchOption( | ||
val patchName: String, | ||
val options: List<Option> | ||
) { | ||
|
||
/** | ||
* Data class for patch option. | ||
* | ||
* @property key The name of the option. | ||
* @property value The value of the option. | ||
*/ | ||
internal data class Option(val key: String, val value: Any?) | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
src/test/kotlin/app/revanced/patcher/options/PatchOptionOptionsTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package app.revanced.patcher.options | ||
|
||
import app.revanced.patcher.data.BytecodeContext | ||
import app.revanced.patcher.data.Context | ||
import app.revanced.patcher.patch.* | ||
import app.revanced.utils.Options | ||
import app.revanced.utils.Options.setOptions | ||
import org.junit.jupiter.api.Test | ||
|
||
class PatchOptionsTestPatch : BytecodePatch() { | ||
override fun execute(context: BytecodeContext): PatchResult { | ||
return PatchResultSuccess() | ||
} | ||
|
||
companion object : OptionsContainer() { | ||
var key1 by option( | ||
PatchOption.StringOption( | ||
"key1", null, "title1", "description1" | ||
) | ||
) | ||
|
||
var key2 by option( | ||
PatchOption.BooleanOption( | ||
"key2", true, "title2", "description2" | ||
) | ||
) | ||
} | ||
} | ||
|
||
internal object PatchOptionOptionsTest { | ||
private var patches = listOf(PatchOptionsTestPatch::class.java as Class<out Patch<Context>>) | ||
|
||
@Test | ||
fun serializeTest() { | ||
assert(SERIALIZED_JSON == Options.serialize(patches)) | ||
} | ||
|
||
@Test | ||
fun loadOptionsTest() { | ||
patches.setOptions(CHANGED_JSON) | ||
|
||
assert(PatchOptionsTestPatch.key1 == "test") | ||
assert(PatchOptionsTestPatch.key2 == false) | ||
} | ||
|
||
private const val SERIALIZED_JSON = | ||
"[{\"patchName\":\"PatchOptionsTestPatch\",\"options\":[{\"key\":\"key1\",\"value\":null},{\"key\":\"key2\",\"value\":true}]}]" | ||
|
||
private const val CHANGED_JSON = | ||
"[{\"patchName\":\"PatchOptionsTestPatch\",\"options\":[{\"key\":\"key1\",\"value\":\"test\"},{\"key\":\"key2\",\"value\":false}]}]" | ||
|
||
} |