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