71 lines
2.7 KiB
Python
71 lines
2.7 KiB
Python
from .parser import parse_patch_file
|
|
|
|
from pathlib import Path
|
|
|
|
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)
|
|
|
|
def read_insertion(action, src):
|
|
position = resolve_position(action["at"], src)
|
|
return {"content": action["content"], "pos": position}
|
|
|
|
def process_patch_file(patch_file: str, check_date: bool = True):
|
|
patches = parse_patch_file(patch_file)
|
|
|
|
for patch in patches:
|
|
target_src = EXTRACTED_DIR / patch["target"]
|
|
target_dest = PATCHED_RSC_DIR / patch["target"]
|
|
|
|
# Skip old patches
|
|
if check_date and target_dest.exists() and target_dest.stat().st_mtime > patch["timestamp"]:
|
|
print(f"Skipping patch {patch['target']}...")
|
|
continue
|
|
|
|
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"]]
|
|
insertions = [x for x in insertions if x is not None]
|
|
|
|
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"])
|
|
|
|
# Write the changed output
|
|
with open(target_dest, 'w') as f:
|
|
f.write(src)
|
|
|
|
def process_all_patches(dir: Path | str, check_date: bool = True):
|
|
dir = Path(dir)
|
|
|
|
for (cd, _, files) in dir.walk():
|
|
for f in files:
|
|
if f.endswith(".patch"):
|
|
print("Processing patch {}".format((cd / f).relative_to(dir)))
|
|
process_patch_file(str(cd / f), check_date=check_date) |