Compare commits

...

30 Commits

Author SHA1 Message Date
semantic-release-bot
86b8415ac6 chore(release): 4.1.0 [skip ci]
# [4.1.0](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.1.0) (2023-11-04)

### Features

* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](b2055ce07d))
* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](0139dfe0bf))

### Performance Improvements

* Use a `HashSet` to check for included and excluded patches ([616d14f](616d14f009))
2023-11-04 21:13:41 +00:00
oSumAtrIX
8f4aebc60b chore: Merge branch dev to main (#292) 2023-11-04 22:11:36 +01:00
semantic-release-bot
bd3171c7c5 chore(release): 4.1.0-dev.3 [skip ci]
# [4.1.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.2...v4.1.0-dev.3) (2023-11-03)
2023-11-03 17:27:32 +00:00
oSumAtrIX
6481ba68db build(Needs bump): Bump dependencies 2023-11-03 18:24:27 +01:00
semantic-release-bot
799882e6a6 chore(release): 4.1.0-dev.2 [skip ci]
# [4.1.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.1...v4.1.0-dev.2) (2023-11-03)

### Features

* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](b2055ce07d))

### Performance Improvements

* Use a `HashSet` to check for included and excluded patches ([616d14f](616d14f009))
2023-11-03 01:04:32 +00:00
oSumAtrIX
616d14f009 perf: Use a HashSet to check for included and excluded patches 2023-11-03 02:02:41 +01:00
oSumAtrIX
b2055ce07d feat: Include or exclude patches by their index in relation to supplied patch bundles 2023-11-03 02:02:40 +01:00
semantic-release-bot
4fc42089a5 chore(release): 4.1.0-dev.1 [skip ci]
# [4.1.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.2...v4.1.0-dev.1) (2023-11-03)

### Features

* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](0139dfe0bf))
2023-11-03 00:33:10 +00:00
SandaruKasa
0139dfe0bf feat: List patches which are compatible with any app (#297)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-11-03 01:31:45 +01:00
semantic-release-bot
7d1c0e663f chore(release): 4.0.3-dev.2 [skip ci]
## [4.0.3-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.1...v4.0.3-dev.2) (2023-10-30)
2023-10-30 21:24:43 +00:00
taku
6cc6960493 build(Needs bump): Bump dependencies to support PatchOption#valueType (#296) 2023-10-30 22:22:50 +01:00
semantic-release-bot
9f15ac6ec5 chore(release): 4.0.3-dev.1 [skip ci]
## [4.0.3-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.0.3-dev.1) (2023-10-23)
2023-10-23 00:15:36 +00:00
oSumAtrIX
6670d89c74 build(Needs bump): Bump dependencies to support new patch options fields 2023-10-23 02:04:50 +02:00
oSumAtrIX
a60d07fc5d build: Bump Kotlin Gradle plugin version 2023-10-22 16:14:47 +02:00
oSumAtrIX
362e6f5904 docs: Use shorter heading 2023-10-21 12:07:40 +02:00
Palm
51402ab8a7 build: Bump dependencies 2023-10-12 21:57:50 +02:00
semantic-release-bot
a8c8682116 chore(release): 4.0.2 [skip ci]
## [4.0.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.1...v4.0.2) (2023-10-12)

### Bug Fixes

* Move file to output even when mounting ([59dfc98](59dfc988e3))
* Use punctuation in option descriptions ([da4469f](da4469f402))

### Performance Improvements

* Use multiple threads for writing dex files ([28648a1](28648a1c53))
2023-10-12 17:58:47 +00:00
oSumAtrIX
a86919eb71 chore: Merge branch dev to main (#281) 2023-10-12 19:56:45 +02:00
semantic-release-bot
8b04b6790b chore(release): 4.0.2-dev.3 [skip ci]
## [4.0.2-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.0.2-dev.2...v4.0.2-dev.3) (2023-10-10)

### Bug Fixes

* Move file to output even when mounting ([59dfc98](59dfc988e3))
2023-10-10 08:11:07 +00:00
oSumAtrIX
59dfc988e3 fix: Move file to output even when mounting 2023-10-10 10:09:04 +02:00
oSumAtrIX
b01fef730a docs: Use preciser formulation 2023-10-10 10:01:39 +02:00
semantic-release-bot
a564aaa1b5 chore(release): 4.0.2-dev.2 [skip ci]
## [4.0.2-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.2-dev.1...v4.0.2-dev.2) (2023-10-10)

### Performance Improvements

* Use multiple threads for writing dex files ([28648a1](28648a1c53))
2023-10-10 08:00:39 +00:00
oSumAtrIX
f315485713 docs: Remove unneeded requirements 2023-10-10 09:58:49 +02:00
oSumAtrIX
28648a1c53 perf: Use multiple threads for writing dex files
This has an impact on memory, but should not cause any issues in the environment of ReVanced CLI.
2023-10-10 09:58:49 +02:00
oSumAtrIX
daac98817f docs: Remove unnecessary text 2023-10-10 09:54:28 +02:00
oSumAtrIX
9328475e11 docs: Use more fitting emojis for sections 2023-10-10 01:12:10 +02:00
oSumAtrIX
6507b5fe8a docs: Use consistent language 2023-10-10 01:09:46 +02:00
oSumAtrIX
349ff5749a docs: Move warning to the beginning of it's section 2023-10-10 01:08:17 +02:00
oSumAtrIX
495735f44c docs: Improve structural integrity 2023-10-10 01:07:11 +02:00
oSumAtrIX
f48da18e37 build: Use artifacts from Jitpack 2023-10-09 19:15:23 +02:00
10 changed files with 236 additions and 123 deletions

View File

@@ -1,3 +1,68 @@
# [4.1.0](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.1.0) (2023-11-04)
### Features
* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](https://github.com/ReVanced/revanced-cli/commit/b2055ce07df3ab9a9f3f73ab17d8c2cf02f2ae62))
* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](https://github.com/ReVanced/revanced-cli/commit/0139dfe0bfa06a13f56dc03e7718aaf644029614))
### Performance Improvements
* Use a `HashSet` to check for included and excluded patches ([616d14f](https://github.com/ReVanced/revanced-cli/commit/616d14f0097c1ee7ba6dc07be417590f6418e8e5))
# [4.1.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.2...v4.1.0-dev.3) (2023-11-03)
# [4.1.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.1...v4.1.0-dev.2) (2023-11-03)
### Features
* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](https://github.com/ReVanced/revanced-cli/commit/b2055ce07df3ab9a9f3f73ab17d8c2cf02f2ae62))
### Performance Improvements
* Use a `HashSet` to check for included and excluded patches ([616d14f](https://github.com/ReVanced/revanced-cli/commit/616d14f0097c1ee7ba6dc07be417590f6418e8e5))
# [4.1.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.2...v4.1.0-dev.1) (2023-11-03)
### Features
* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](https://github.com/ReVanced/revanced-cli/commit/0139dfe0bfa06a13f56dc03e7718aaf644029614))
## [4.0.3-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.1...v4.0.3-dev.2) (2023-10-30)
## [4.0.3-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.0.3-dev.1) (2023-10-23)
## [4.0.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.1...v4.0.2) (2023-10-12)
### Bug Fixes
* Move file to output even when mounting ([59dfc98](https://github.com/ReVanced/revanced-cli/commit/59dfc988e351374eb718923d19bd9bdd94e8d3c0))
* Use punctuation in option descriptions ([da4469f](https://github.com/ReVanced/revanced-cli/commit/da4469f402c26ad95898404236b0acf0202907e2))
### Performance Improvements
* Use multiple threads for writing dex files ([28648a1](https://github.com/ReVanced/revanced-cli/commit/28648a1c53520eef8c799504ff61a35947f878b8))
## [4.0.2-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.0.2-dev.2...v4.0.2-dev.3) (2023-10-10)
### Bug Fixes
* Move file to output even when mounting ([59dfc98](https://github.com/ReVanced/revanced-cli/commit/59dfc988e351374eb718923d19bd9bdd94e8d3c0))
## [4.0.2-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.2-dev.1...v4.0.2-dev.2) (2023-10-10)
### Performance Improvements
* Use multiple threads for writing dex files ([28648a1](https://github.com/ReVanced/revanced-cli/commit/28648a1c53520eef8c799504ff61a35947f878b8))
## [4.0.2-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.1...v4.0.2-dev.1) (2023-10-08)

View File

@@ -39,7 +39,7 @@
Continuing the legacy of Vanced
</p>
# 📙 ReVanced CLI contribution guidelines
# 👋 Contribution guidelines
This document describes how to contribute to ReVanced CLI.
@@ -76,4 +76,4 @@ If you encounter a bug while using ReVanced CLI, open an issue using the
it will be merged into the `dev` branch and will be included in the next release of ReVanced CLI
❤️ Thank you for considering contributing to ReVanced CLI,
ReVanced
ReVanced

View File

@@ -1,10 +1,17 @@
plugins {
kotlin("jvm") version "1.9.0"
kotlin("jvm") version "1.9.10"
alias(libs.plugins.shadow)
}
group = "app.revanced"
repositories {
mavenCentral()
mavenLocal()
google()
maven { url = uri("https://jitpack.io") }
}
dependencies {
implementation(libs.revanced.patcher)
implementation(libs.revanced.library)

View File

@@ -1,14 +1,12 @@
# 💼 Prerequisites
To use ReVanced CLI, you will need to fulfil specific requirements.
To use ReVanced CLI, you will need to fulfill specific requirements.
## 🤝 Requirements
- Java SDK 11 (Azul Zulu JDK or OpenJDK)
- [Android Debug Bridge (adb)](https://developer.android.com/studio/command-line/adb) if you want to install the patched APK file on your device
- An ABI other than ARMv7 such as x86 or x86-64 (or a custom AAPT binary that supports ARMv7)
- ReVanced Patches
- ReVanced Integrations, if the patches require it
## ⏭️ Whats next

View File

@@ -2,36 +2,17 @@
Learn how to ReVanced CLI.
## ⚡ Setup ADB
## 🔨 Usage
1. Ensure that ADB is working
ReVanced CLI is divided into the following fundamental commands:
```bash
adb shell exit
```
Optionally, you can install the patched APK file on your device by mounting it on top of the original APK file.
You will need root permissions for this. Check if you have root permissions by running the following command:
```bash
adb shell su -c exit
```
2. Get your device's serial
```bash
adb devices
```
## 🔨 Using ReVanced CLI
- ### ⚙️ Show all available options for ReVanced CLI
- ### 🚀 Show all available options for ReVanced CLI
```bash
java -jar revanced-cli.jar -h
```
- ### 📃 List patches from supplied patch bundles
- ### 📃 List patches
```bash
java -jar revanced-cli.jar list-patches \
@@ -41,7 +22,7 @@ Learn how to ReVanced CLI.
revanced-patches.jar [<patch-bundle> ...]
```
- ### ⚙️ Generate options from patches using ReVanced CLI
- ### ⚙️ Generate options
This will generate an `options.json` file for the patches from a list of supplied patch bundles.
The file can be supplied to ReVanced CLI later on.
@@ -53,53 +34,98 @@ Learn how to ReVanced CLI.
revanced-patches.jar [<patch-bundle> ...]
```
> **Note**: A default `options.json` file will be automatically generated, if it does not exist
> [!NOTE]
> A default `options.json` file will be automatically created, if it does not exist
without any need for intervention when using the `patch` command.
- ### 💉 Use ReVanced CLI to patch an APK file but install without root permissions
- ### 💉 Patch an app
This will install the patched APK file regularly on your device.
You can patch apps by supplying patch bundles and the app to patch.
After patching, ReVanced CLI can install the patched app on your device using two methods:
```bash
java -jar revanced-cli.jar patch \
--patch-bundle revanced-patches.jar \
--out output.apk \
--device-serial <device-serial> \
input.apk
```
> [!NOTE]
> For ReVanced CLI to be able to install the patched app on your device, make sure ADB is working:
>
> ```bash
> adb shell exit
> ```
>
> To get your device's serial, run the following command:
>
> ```bash
> adb devices
> ```
>
> If you want to mount the patched app on top of the un-patched app, make sure you have root permissions:
>
> ```bash
> adb shell su -c exit
> ```
>
- ### 👾 Use ReVanced CLI to patch an APK file but install with root permissions
> [!WARNING]
> Some patches may require integrations
> such as [ReVanced Integrations](https://github.com/revanced/revanced-integrations).
> Supply them with the option `--merge`. ReVanced Patcher will automatically determine if they are necessary.
This will install the patched APK file on your device by mounting it on top of the original APK file.
- #### 👾 Patch an app and install it on your device regularly
```bash
adb install input.apk
java -jar revanced-cli.jar patch \
--patch-bundle revanced-patches.jar \
--include some-other-patch \
--exclude some-patch \
--out patched-output.apk \
--device-serial <device-serial> \
--mount \
input.apk
```
```bash
java -jar revanced-cli.jar patch \
--patch-bundle revanced-patches.jar \
--out patched-app.apk \
--device-serial <device-serial> \
input.apk
```
> **Note**: Some patches may require integrations
such as [ReVanced Integrations](https://github.com/revanced/revanced-integrations).
Supply them with the option `--merge`. If any patches accepted by ReVanced Patcher require ReVanced Integrations,
they will be merged into the APK file automatically.
- #### 👾 Patch an app and mount it on top of the un-patched app with root permissions
> [!IMPORTANT]
> Ensure sure the same app you are patching and mounting over is installed on your device:
>
> ```bash
> adb install app.apk
> ```
> [!NOTE]
> You can use the option `--ii` to include or `--ie` to exclude
> patches by their index in relation to supplied patch bundles,
> similarly to the option `--include` and `--exclude`.
>
> This is useful in case two patches have the same name, and you need to include or exclude one of them.
> The index of a patch is calculated by the position of the patch in the list of patches
> from patch bundles supplied using the option `--patch-bundle`.
>
> You can list all patches with their indices using the command `list-patches`.
>
> Keep in mind, that the indices can change based on the order of the patch bundles supplied,
> as well if the patch bundles are updated, because patches can be added or removed.
```bash
java -jar revanced-cli.jar patch \
--patch-bundle revanced-patches.jar \
--include "Some patch" \
--ii 123 \
--exclude "Some other patch" \
--out patched-app.apk \
--device-serial <device-serial> \
--mount \
app.apk
```
- ### 🗑️ Uninstall an app
- ### 🗑️ Uninstall a patched APK file
```bash
java -jar revanced-cli.jar utility uninstall \
--package-name <package-name> \
<device-serial>
```
> **Note**: You can unmount an APK file
with the option `--unmount`.
> [!NOTE]
> You can unmount an APK file
by adding the option `--unmount`.
- ### ⚙️ Manually install an APK file
- ### 📦 Install an app
```bash
java -jar revanced-cli.jar utility install \
@@ -107,5 +133,6 @@ Learn how to ReVanced CLI.
<device-serial>
```
> **Note**: You can mount an APK file
by supplying the package name of the app to mount the supplied APK file to over the option `--mount`.
> [!NOTE]
> You can mount an APK file
> by supplying the package name of the app to mount the supplied APK file to over the option `--mount`.

View File

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

View File

@@ -3,8 +3,8 @@ shadow = "8.1.1"
kotlin-test = "1.8.20-RC"
kotlinx-coroutines-core = "1.7.3"
picocli = "4.7.3"
revanced-patcher = "16.0.2"
revanced-library = "1.1.2"
revanced-patcher = "19.0.0"
revanced-library = "1.2.0"
[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" }

View File

@@ -1,23 +1 @@
val githubUsername: String = providers.gradleProperty("gpr.user").orNull ?: System.getenv("GITHUB_ACTOR")
val githubPassword: String = providers.gradleProperty("gpr.key").orNull ?: System.getenv("GITHUB_TOKEN")
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
mavenLocal()
google()
maven { url = uri("https://jitpack.io") }
listOf("revanced-patcher", "jadb").forEach { repo ->
maven {
url = uri("https://maven.pkg.github.com/revanced/$repo")
credentials {
username = githubUsername
password = githubPassword
}
}
}
}
}
rootProject.name = "revanced-cli"

View File

@@ -42,6 +42,20 @@ internal object ListPatchesCommand : Runnable {
)
private var withOptions: Boolean = false
@Option(
names = ["-u", "--with-universal-patches"],
description = ["List patches which are compatible with any app."],
showDefaultValue = ALWAYS
)
private var withUniversalPatches: Boolean = true
@Option(
names = ["-i", "--index"],
description = ["List the index of of each patch in relation to the supplied patch bundles."],
showDefaultValue = ALWAYS
)
private var withIndex: Boolean = true
@Option(
names = ["-f", "--filter-package-name"], description = ["Filter patches by package name."]
)
@@ -58,41 +72,51 @@ internal object ListPatchesCommand : Runnable {
fun PatchOption<*>.buildString() = buildString {
appendLine("Title: $title")
appendLine("Description: $description")
value?.let {
description?.let { appendLine("Description: $it") }
default?.let {
appendLine("Key: $key")
append("Value: $it")
append("Default: $it")
} ?: append("Key: $key")
}
fun Patch<*>.buildString() = buildString {
append("Name: $name")
if (withDescriptions) append("\nDescription: $description")
if (withOptions && options.isNotEmpty()) {
appendLine("\nOptions:")
append(
options.values.joinToString("\n\n") { option ->
option.buildString()
}.prependIndent("\t")
)
}
if (withPackages && compatiblePackages != null) {
appendLine("\nCompatible packages:")
append(
compatiblePackages!!.joinToString("\n") { it.buildString() }.prependIndent("\t")
)
values?.let { values ->
appendLine("\nValid values:")
append(values.map { "${it.value} (${it.key})" }.joinToString("\n").prependIndent("\t"))
}
}
fun Patch<*>.anyPackageName(name: String) = compatiblePackages?.any { it.name == name } == true
fun IndexedValue<Patch<*>>.buildString() = let { (index, patch) ->
buildString {
if (withIndex) appendLine("Index: $index")
val patches = PatchBundleLoader.Jar(*patchBundles)
append("Name: ${patch.name}")
val filtered = packageName?.let { patches.filter { patch -> patch.anyPackageName(it) } } ?: patches
if (withDescriptions) append("\nDescription: ${patch.description}")
if (withOptions && patch.options.isNotEmpty()) {
appendLine("\nOptions:")
append(
patch.options.values.joinToString("\n\n") { option ->
option.buildString()
}.prependIndent("\t")
)
}
if (withPackages && patch.compatiblePackages != null) {
appendLine("\nCompatible packages:")
append(patch.compatiblePackages!!.joinToString("\n") {
it.buildString()
}.prependIndent("\t"))
}
}
}
fun Patch<*>.filterCompatiblePackages(name: String) = compatiblePackages?.any { it.name == name }
?: withUniversalPatches
val patches = PatchBundleLoader.Jar(*patchBundles).withIndex().toList()
val filtered =
packageName?.let { patches.filter { (_, patch) -> patch.filterCompatiblePackages(it) } } ?: patches
if (filtered.isNotEmpty()) logger.info(filtered.joinToString("\n\n") { it.buildString() })
}

View File

@@ -37,12 +37,24 @@ internal object PatchCommand : Runnable {
@CommandLine.Option(
names = ["-i", "--include"], description = ["List of patches to include."]
)
private var includedPatches = arrayOf<String>()
private var includedPatches = hashSetOf<String>()
@CommandLine.Option(
names = ["--ii"],
description = ["List of patches to include by their index in relation to the supplied patch bundles."]
)
private var includedPatchesByIndex = arrayOf<Int>()
@CommandLine.Option(
names = ["-e", "--exclude"], description = ["List of patches to exclude."]
)
private var excludedPatches = arrayOf<String>()
private var excludedPatches = hashSetOf<String>()
@CommandLine.Option(
names = ["--ei"],
description = ["List of patches to exclude by their index in relation to the supplied patch bundles."]
)
private var excludedPatchesByIndex = arrayOf<Int>()
@CommandLine.Option(
names = ["--options"], description = ["Path to patch options JSON file."], showDefaultValue = ALWAYS
@@ -188,7 +200,7 @@ internal object PatchCommand : Runnable {
// Warn if a patch can not be found in the supplied patch bundles.
if (warn) patches.map { it.name }.toHashSet().let { availableNames ->
arrayOf(*includedPatches, *excludedPatches).filter { name ->
(includedPatches + excludedPatches).filter { name ->
!availableNames.contains(name)
}
}.let { unknownPatches ->
@@ -204,6 +216,7 @@ internal object PatchCommand : Runnable {
resourceCachePath,
aaptBinaryPath?.path,
resourceCachePath.absolutePath,
true
)
).use { patcher ->
val filteredPatches = patcher.filterPatchSelection(patches).also { patches ->
@@ -236,7 +249,7 @@ internal object PatchCommand : Runnable {
// region Save
val tempFile = resourceCachePath.resolve(apk.name).apply {
val alignedFile = resourceCachePath.resolve(apk.name).apply {
ApkUtils.copyAligned(apk, this, patcherResult)
}
@@ -244,7 +257,7 @@ internal object PatchCommand : Runnable {
.resolve("${outputFilePath.nameWithoutExtension}.keystore")
if (!mount) ApkUtils.sign(
tempFile,
alignedFile,
outputFilePath,
ApkUtils.SigningOptions(
keystoreFilePath,
@@ -254,6 +267,7 @@ internal object PatchCommand : Runnable {
signer
)
)
else alignedFile.renameTo(outputFilePath)
// endregion
@@ -281,10 +295,10 @@ internal object PatchCommand : Runnable {
val packageName = context.packageMetadata.packageName
val packageVersion = context.packageMetadata.packageVersion
patches.forEach patch@{ patch ->
patches.withIndex().forEach patch@{ (i, patch) ->
val patchName = patch.name!!
val explicitlyExcluded = excludedPatches.contains(patchName)
val explicitlyExcluded = excludedPatches.contains(patchName) || excludedPatchesByIndex.contains(i)
if (explicitlyExcluded) return@patch logger.info("Excluding $patchName")
// Make sure the patch is compatible with the supplied APK files package name and version.
@@ -312,7 +326,7 @@ internal object PatchCommand : Runnable {
// If the patch is implicitly used, it will be only included if [exclusive] is false.
val implicitlyIncluded = !exclusive && patch.use
// If the patch is explicitly used, it will be included even if [exclusive] is false.
val explicitlyIncluded = includedPatches.contains(patchName)
val explicitlyIncluded = includedPatches.contains(patchName) || includedPatchesByIndex.contains(i)
val included = implicitlyIncluded || explicitlyIncluded
if (!included) return@patch logger.info("$patchName excluded") // Case 1.