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)