From fc3f4da370c49f05ad7e01fd6fba204e9b5fa50e Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Sat, 28 Jan 2023 14:19:04 -0500 Subject: [PATCH] scripts: update gsrc files with modifications using git merge (#2164) --- .github/workflows/linting.yaml | 3 ++ .vscode/opengoal.code-snippets | 6 +++ goal_src/jak2/levels/common/airlock.gc | 2 + scripts/gsrc/check-for-conflicts.py | 25 +++++++++++ scripts/gsrc/update-from-decomp.py | 58 +++++++++++++++++++++++++- 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 scripts/gsrc/check-for-conflicts.py diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml index ec4d6187b8..844234a441 100644 --- a/.github/workflows/linting.yaml +++ b/.github/workflows/linting.yaml @@ -31,3 +31,6 @@ jobs: run: | chmod +x ./third-party/run-clang-format/run-clang-format.py ./third-party/run-clang-format/run-clang-format.py -r common decompiler game goalc test tools lsp --color always + + - name: Check for Unresolved Conflicts + run: python ./scripts/gsrc/check-for-conflicts.py diff --git a/.vscode/opengoal.code-snippets b/.vscode/opengoal.code-snippets index 47520ed54a..9b42e28cf3 100644 --- a/.vscode/opengoal.code-snippets +++ b/.vscode/opengoal.code-snippets @@ -17,4 +17,10 @@ "body": [";; og:ignore-form:${1:substr}"], "description": "If the provided substr is found in the starting line of a form, the entire form will be omitted when copying decompiled code into the file" }, + "og:update-with-merge": { + "scope": "opengoal", + "prefix": ["og:update-with-merge"], + "body": [";; og:update-with-merge:${1:substr}"], + "description": "The file will be updated with a git merge-file instead of naive copy-paste" + }, } diff --git a/goal_src/jak2/levels/common/airlock.gc b/goal_src/jak2/levels/common/airlock.gc index 28542d1197..79a7797000 100644 --- a/goal_src/jak2/levels/common/airlock.gc +++ b/goal_src/jak2/levels/common/airlock.gc @@ -5,6 +5,8 @@ ;; name in dgo: airlock ;; dgos: GAME, COMMON +;; og:update-with-merge + ;; DECOMP BEGINS (deftype com-airlock (process-drawable) diff --git a/scripts/gsrc/check-for-conflicts.py b/scripts/gsrc/check-for-conflicts.py new file mode 100644 index 0000000000..eb60925f25 --- /dev/null +++ b/scripts/gsrc/check-for-conflicts.py @@ -0,0 +1,25 @@ +# Merge tools use specific algorithms or assumptions to detect conflicts +# and not all of them will obviously flag them, even if they use the standard format +# +# So this is to ensure no conflict markers get ignored in goal_src atleast +import os + +files_with_unresolved_conflicts = [] + +for dirpath, subdirs, files in os.walk("./goal_src"): + for filename in files: + # Get the file contents + with open(os.path.join(dirpath, filename), "r") as f: + lines = f.readlines() + for line in lines: + if "<<<<<<<" in line: + files_with_unresolved_conflicts.append(os.path.join(dirpath, filename)) + break + +if len(files_with_unresolved_conflicts) == 0: + exit(0) + +print("There are unresolved conflicts in ./goal_src/") +for file in files_with_unresolved_conflicts: + print(file) +exit(1) diff --git a/scripts/gsrc/update-from-decomp.py b/scripts/gsrc/update-from-decomp.py index 1007fceedb..f59bdab164 100644 --- a/scripts/gsrc/update-from-decomp.py +++ b/scripts/gsrc/update-from-decomp.py @@ -36,14 +36,22 @@ # - there are likely ways to make this more efficient import argparse +import os from code_retention.all_types_retention import update_alltypes_named_blocks from utils import get_gsrc_path_from_filename from code_retention.code_retention import * +import shutil +from pathlib import Path +import subprocess parser = argparse.ArgumentParser("update-from-decomp") parser.add_argument("--game", help="The name of the game", type=str) parser.add_argument("--file", help="The name of the file", type=str) -parser.add_argument("--preserve", help="Attempt to preserve comments and marked blocks", action="store_true") +parser.add_argument( + "--preserve", + help="Attempt to preserve comments and marked blocks", + action="store_true", +) parser.add_argument( "--debug", help="Output debug metadata on every block", action="store_true" ) @@ -61,6 +69,7 @@ comments = [] debug_lines = [] decomp_ignore_forms = ["defmethod inspect"] decomp_ignore_errors = False +update_with_merge = False with open(gsrc_path) as f: lines_temp = f.readlines() @@ -74,10 +83,28 @@ with open(gsrc_path) as f: decomp_ignore_errors = True if "og:ignore-form" in line: decomp_ignore_forms.append(line.partition("ignore-form:")[2].strip()) + if "og:update-with-merge" in line: + update_with_merge = True lines.append(line) if args.preserve: comments, debug_lines = process_original_lines(lines) +# If we are going to `update_with_merge` then make a backup of the file, and +# an empty file to use as the common ancestor. +# +# This means that all changes will be flagged as a conflict and will not be able to be +# merged into the repo without being explicitly resolved +if update_with_merge: + subprocess.run( + [ + "git", + "restore", + gsrc_path + ] + ) + shutil.copyfile(gsrc_path, gsrc_path.replace(".gc", ".before.gc")) + Path(gsrc_path.replace(".gc", ".empty.gc")).touch() + if args.debug: with open(gsrc_path, "w") as f: f.writelines(debug_lines) @@ -94,7 +121,7 @@ lines_to_ignore = [ ";; Used lq/sq", ";; this part is debug only", ";; WARN: Return type mismatch int vs none", - ";; WARN: Stack slot offset" + ";; WARN: Stack slot offset", ] if decomp_ignore_errors: @@ -113,6 +140,7 @@ def should_ignore_line(line): return True return False + # TODO - ignore brackets inside strings! decomp_file_path = "./decompiler_out/{}/{}_disasm.gc".format(args.game, args.file) @@ -197,3 +225,29 @@ with open(gsrc_path, "w") as f: while i + lines_to_ignore < len(final_lines): f.write(final_lines[i]) i = i + 1 + +# If we need to merge, now is the time! +if update_with_merge: + shutil.move(gsrc_path, gsrc_path.replace(".gc", ".after.gc")) + shutil.move(gsrc_path.replace(".gc", ".before.gc"), gsrc_path) + subprocess.run( + [ + "git", + "merge-file", + gsrc_path, + gsrc_path.replace(".gc", ".empty.gc"), + gsrc_path.replace(".gc", ".after.gc"), + "-L", + "Before Updating", + "-L", + "ignored", + "-L", + "After Updating", + ] + ) + if os.path.exists(gsrc_path.replace(".gc", ".empty.gc")): + os.remove(gsrc_path.replace(".gc", ".empty.gc")) + if os.path.exists(gsrc_path.replace(".gc", ".before.gc")): + os.remove(gsrc_path.replace(".gc", ".before.gc")) + if os.path.exists(gsrc_path.replace(".gc", ".after.gc")): + os.remove(gsrc_path.replace(".gc", ".after.gc"))