2024-08-17 19:25:06 +00:00
|
|
|
from .parser import parse_patch_file
|
2024-08-17 17:14:45 +00:00
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
2024-08-17 19:25:06 +00:00
|
|
|
from task.util import *
|
|
|
|
|
|
|
|
def resolve_position(location, src: str):
|
|
|
|
if location["type"] == "char":
|
|
|
|
return location["index"]
|
|
|
|
elif location["type"] == "lncol":
|
|
|
|
j = 0
|
|
|
|
for i, x in enumerate(src.split('\n')):
|
|
|
|
if (i+1) == location["line"]:
|
|
|
|
if location["column"] > len(x):
|
|
|
|
print(f"Cannot insert at line {location['line']} column {location['column']}. The line is not that long.")
|
|
|
|
exit(-1)
|
|
|
|
return j + location["column"]
|
|
|
|
j += len(x) + 1
|
|
|
|
|
|
|
|
print(f"Cannot insert at line {location['line']}. The file is not long enough.")
|
|
|
|
exit(-1)
|
2024-08-17 17:14:45 +00:00
|
|
|
|
2024-08-17 17:38:23 +00:00
|
|
|
def read_insertion(action, src):
|
|
|
|
position = resolve_position(action["at"], src)
|
|
|
|
return {"content": action["content"], "pos": position}
|
2024-08-17 17:14:45 +00:00
|
|
|
|
|
|
|
def process_patch_file(patch_file: str, check_date: bool = True):
|
|
|
|
patches = parse_patch_file(patch_file)
|
|
|
|
|
|
|
|
for patch in patches:
|
2024-08-17 17:38:23 +00:00
|
|
|
target_src = EXTRACTED_DIR / patch["target"]
|
|
|
|
target_dest = PATCHED_RSC_DIR / patch["target"]
|
|
|
|
|
|
|
|
# Skip old patches
|
2024-08-17 17:14:45 +00:00
|
|
|
if check_date and target_dest.exists() and target_dest.stat().st_mtime > patch["timestamp"]:
|
2024-08-17 17:38:23 +00:00
|
|
|
print(f"Skipping patch {patch['target']}...")
|
2024-08-17 17:14:45 +00:00
|
|
|
continue
|
|
|
|
|
2024-08-17 17:38:23 +00:00
|
|
|
print(f"Patching {patch['target']} with {len(patch['actions'])} actions")
|
|
|
|
|
|
|
|
# Read the source of the file
|
|
|
|
with open(target_src, 'r') as f:
|
|
|
|
src = f.read()
|
|
|
|
|
|
|
|
# Resolve the actual char locations in the patches
|
|
|
|
insertions = [read_insertion(action, src) for action in patch["actions"]]
|
2024-08-17 17:14:45 +00:00
|
|
|
insertions = [x for x in insertions if x is not None]
|
|
|
|
|
2024-08-17 17:38:23 +00:00
|
|
|
for insertion in insertions:
|
|
|
|
src = src[:insertion["pos"]] + insertion["content"] + src[insertion["pos"]:]
|
|
|
|
|
|
|
|
# Correct insertions that follow this one
|
|
|
|
for i2 in insertions:
|
|
|
|
# Only update insertions that come *after* this one
|
|
|
|
if i2 == insertion or i2["pos"] < insertion["pos"]:
|
|
|
|
continue
|
|
|
|
|
|
|
|
i2["pos"] += len(insertion["content"])
|
2024-08-17 20:16:36 +00:00
|
|
|
|
|
|
|
# Make parent dirs
|
|
|
|
target_dest.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
2024-08-17 17:38:23 +00:00
|
|
|
# Write the changed output
|
|
|
|
with open(target_dest, 'w') as f:
|
2024-08-17 19:25:06 +00:00
|
|
|
f.write(src)
|
|
|
|
|
|
|
|
def process_all_patches(dir: Path | str, check_date: bool = True):
|
|
|
|
dir = Path(dir)
|
|
|
|
|
2024-08-17 20:16:36 +00:00
|
|
|
for patch_file in dir.rglob("*.patch"):
|
|
|
|
print("Processing patch {}".format(patch_file.relative_to(dir)))
|
|
|
|
process_patch_file(str(patch_file), check_date=check_date)
|