Push patchbisect
This commit is contained in:
parent
97999f4119
commit
2c93292bc1
2 changed files with 122 additions and 3 deletions
18
BUILDING.md
18
BUILDING.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#### Toolchain setup
|
#### Toolchain setup
|
||||||
|
|
||||||
- Get apktool (due to 2 bugs present in v2.3.4, you're strongly recommended to use v2.4.0 or higher)
|
- Get apktool (due to 2 bugs present in v2.3.4, you're strongly recommended to use v2.4.0 or higher, I compile latest from source).
|
||||||
- Get a keystore, see [here](https://stackoverflow.com/a/14994354/3286892), step 1.
|
- Get a keystore, see [here](https://stackoverflow.com/a/14994354/3286892), step 1.
|
||||||
- If you want Mutant Standard emoji patches, get 72x72 PNG copies of latest version of mutant standard emojis with codepoints. I have a zip [here](https://mutant.lavatech.top/72x72.zip).
|
- If you want Mutant Standard emoji patches, get 72x72 PNG copies of latest version of mutant standard emojis with codepoints. I have a zip [here](https://mutant.lavatech.top/72x72.zip).
|
||||||
- If you want Blob emoji patches, get 72x72 PNG copies of blobmojis with codepoints. I personally resized the png/128 folder in this [repo](https://github.com/C1710/blobmoji) (`find /home/ave/blobmoji/png/72 -iname '*.png' -exec convert \{\} -verbose -resize 72x72\> \{\} \;`).
|
- If you want Blob emoji patches, get 72x72 PNG copies of blobmojis with codepoints. I personally resized the png/128 folder in this [repo](https://github.com/C1710/blobmoji) (`find /home/ave/blobmoji/png/72 -iname '*.png' -exec convert \{\} -verbose -resize 72x72\> \{\} \;`).
|
||||||
|
@ -51,8 +51,20 @@ To get the diff, run `diff -crB -x "dist" -x "res/raw" -x "build" CleanFolder Pa
|
||||||
|
|
||||||
#### Porting patches
|
#### Porting patches
|
||||||
|
|
||||||
You can use `patchport.py` to easily attempt to port patches.
|
You can use `patchport.py` to easily attempt to port patches. This is what I use to port between every single version.
|
||||||
|
|
||||||
It's not really intelligent and doesn't do much more than manually preparing necessary patch, checking if an existing patch can be applied to a given version, replacing relevant variables required for porting various patches and eliminating offsets caused by updates, but it saves a lot of time if used carefully.
|
It's not really intelligent and doesn't do much more than manually preparing necessary patch, checking if an existing patch can be applied to a given version, replacing relevant variables required for porting various patches and eliminating offsets caused by updates, but it saves a lot of time if used carefully.
|
||||||
|
|
||||||
Example command: `python3 patchport.py /home/ave/Downloads/dic/com.discord-841`
|
Example command: `python3 patchport.py /home/ave/workbench/ctc/com.discord-968`
|
||||||
|
|
||||||
|
#### Figuring out which patch is causing your build to break
|
||||||
|
|
||||||
|
You can use `patchbisect.py` to have a `git bisect`-like system of switching between patchsets to find which patch(es) is(/are) the ones that cause issues.
|
||||||
|
|
||||||
|
Simply let it do its thing, do whatever test you want to make, type `y` if it works or `n` if it doesn't and finally hit return, rinse and repeat until you find what's wrong.
|
||||||
|
|
||||||
|
There's no automated checking to allow checking for a wide range of issues like build issues, app crashing on boot, or simple functionality breakages.
|
||||||
|
|
||||||
|
Keep in mind that this doesn't account for the case of multiple patches being used together causing issues, nor does it account for conflicting patches.
|
||||||
|
|
||||||
|
Example command: `python3 patchbisect.py /home/ave/workbench/ctc/com.discord-968`
|
||||||
|
|
107
patchbisect.py
Normal file
107
patchbisect.py
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#!/bin/env python3
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# Example invocation:
|
||||||
|
# python3 patchbisect.py /home/ave/workbench/ctc/com.discord-968
|
||||||
|
|
||||||
|
# This is really bad code that I wrote between 3am and 6am
|
||||||
|
# Please do not criticize or judge my programming skills by this.
|
||||||
|
|
||||||
|
apk_folder = sys.argv[1]
|
||||||
|
cutthecord_folder = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
def apply_patch(patch, reverse=False):
|
||||||
|
patch_path = os.path.join(cutthecord_folder, "patches", patch,
|
||||||
|
f"{to_versioncode}.patch")
|
||||||
|
with open(patch_path) as f:
|
||||||
|
patch_contents = f.read()
|
||||||
|
cmd = f"patch -p1 {'-R' if reverse else ''} --no-backup-if-mismatch --force"
|
||||||
|
subprocess.run(cmd,
|
||||||
|
shell=True, input=patch_contents, text=True,
|
||||||
|
cwd=apk_folder, capture_output=True)
|
||||||
|
|
||||||
|
|
||||||
|
re_versioncode_yml = re.compile(r'versionCode: \'([0-9]+)\'')
|
||||||
|
re_versionname_yml = re.compile(r'versionName: (.+)$')
|
||||||
|
|
||||||
|
|
||||||
|
# Get version code and name
|
||||||
|
with open(os.path.join(apk_folder, "apktool.yml")) as f:
|
||||||
|
file_contents = f.read()
|
||||||
|
to_versioncode = re_versioncode_yml.findall(file_contents)[0]
|
||||||
|
to_versionname = re_versionname_yml.findall(file_contents)[0]
|
||||||
|
|
||||||
|
|
||||||
|
unsure = []
|
||||||
|
|
||||||
|
# Load list of patches
|
||||||
|
for patch in os.listdir(os.path.join(cutthecord_folder, "patches")):
|
||||||
|
# Ignore non-dirs
|
||||||
|
if not os.path.isdir(os.path.join(cutthecord_folder, "patches", patch)):
|
||||||
|
continue
|
||||||
|
|
||||||
|
patch_path = os.path.join(cutthecord_folder, "patches", patch,
|
||||||
|
f"{to_versioncode}.patch")
|
||||||
|
|
||||||
|
# Check if patch exists for from_version, if it doesn't, warn user
|
||||||
|
if not os.path.isfile(patch_path) and patch not in ["necessary"]:
|
||||||
|
# Don't warn on instructional patches
|
||||||
|
if patch not in ["customfont", "customring",
|
||||||
|
"bettertm", "bettertmlight",
|
||||||
|
"blobs"]:
|
||||||
|
print(f"SKIPPED: No {to_versionname} version found for {patch}.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Append patch name to the list
|
||||||
|
unsure.append(patch)
|
||||||
|
|
||||||
|
|
||||||
|
failcount = 1
|
||||||
|
applied = []
|
||||||
|
good = []
|
||||||
|
bad = []
|
||||||
|
|
||||||
|
while unsure:
|
||||||
|
print("So far...")
|
||||||
|
print(f"Unsure patches: {', '.join(unsure)}")
|
||||||
|
print(f"Good patches: {', '.join(good)}")
|
||||||
|
print(f"Bad patches: {', '.join(bad)}")
|
||||||
|
count_this_round = int(len(unsure) / failcount)
|
||||||
|
for i in range(0, count_this_round):
|
||||||
|
patch_name = unsure[i]
|
||||||
|
print(f"Applying: {patch_name}")
|
||||||
|
apply_patch(patch_name)
|
||||||
|
applied.append(patch_name)
|
||||||
|
|
||||||
|
# Very cursed lines of code.
|
||||||
|
is_working = ""
|
||||||
|
while is_working not in ["y", "n"]:
|
||||||
|
is_working = input("Is the current patchset working? (y/n) ")
|
||||||
|
|
||||||
|
# <3 3.8
|
||||||
|
# while (is_working := input("Is the current patchset working? (y/n) ")) not in ["y", "n"]:
|
||||||
|
# continue
|
||||||
|
|
||||||
|
if is_working == "y":
|
||||||
|
good.extend(applied)
|
||||||
|
unsure = list(set(unsure) - set(applied))
|
||||||
|
failcount = 1
|
||||||
|
elif count_this_round > 1:
|
||||||
|
failcount += 1
|
||||||
|
else:
|
||||||
|
bad.extend(applied)
|
||||||
|
unsure = list(set(unsure) - set(applied))
|
||||||
|
failcount = 1
|
||||||
|
|
||||||
|
for patch_name in applied:
|
||||||
|
apply_patch(patch_name, True)
|
||||||
|
|
||||||
|
applied.clear()
|
||||||
|
|
||||||
|
print("Done, all patches identified as good or bad.")
|
||||||
|
print(f"Good: {', '.join(good)}")
|
||||||
|
print(f"Bad: {', '.join(bad)}")
|
Reference in a new issue