SXXXXXXX_CppPythonDebug/tools/update_dumper_version.py
VALLONGOL c93ef640e5 add
2025-11-12 13:41:22 +01:00

110 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""
Update the DUMPER_VERSION placeholder in cpp_python_debug/core/gdb_dumper.py.
Usage:
python tools/update_dumper_version.py [--version X.Y.Z] [--commit]
Behavior:
- If --version is provided, that version will be used.
- Otherwise the script will try, in order:
1) read cpp_python_debug/_version.py for __version__
2) run `git describe --tags --always` in the repository root (searching upwards)
- The script replaces the first occurrence of DUMPER_VERSION = "..." in
`cpp_python_debug/core/gdb_dumper.py` with the chosen version string.
- If --commit is passed and the repo is a git repo, it will stage and commit
the updated file with a message.
Note: This script does not assume the dumper will be executed in the repo; it
writes the version directly into the dumper file so that copies of the file
still carry a concrete version string.
"""
import argparse
import os
import re
import subprocess
import sys
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
DUMPER_PATH = os.path.join(ROOT, "cpp_python_debug", "core", "gdb_dumper.py")
VERSION_FILE = os.path.join(ROOT, "cpp_python_debug", "_version.py")
def read_version_from_file():
if not os.path.exists(VERSION_FILE):
return None
content = open(VERSION_FILE, "r", encoding="utf-8").read()
m = re.search(r"^__version__\s*=\s*['\"]([^'\"]+)['\"]", content, re.M)
return m.group(1) if m else None
def git_describe_from(path):
# Walk upwards looking for a .git directory
cur = os.path.abspath(path)
for _ in range(50):
if os.path.isdir(os.path.join(cur, ".git")):
try:
out = subprocess.check_output(["git", "-C", cur, "describe", "--tags", "--always"], stderr=subprocess.DEVNULL)
return out.decode().strip()
except Exception:
return None
parent = os.path.dirname(cur)
if parent == cur:
break
cur = parent
# As a last resort, try running git describe in the provided path
try:
out = subprocess.check_output(["git", "describe", "--tags", "--always"], cwd=path, stderr=subprocess.DEVNULL)
return out.decode().strip()
except Exception:
return None
def replace_dumper_version(new_version: str, commit: bool = False):
if not os.path.exists(DUMPER_PATH):
print(f"ERROR: dumper file not found at {DUMPER_PATH}")
return 2
txt = open(DUMPER_PATH, "r", encoding="utf-8").read()
# Replace the first occurrence of DUMPER_VERSION = "..."
new_txt, count = re.subn(r"DUMPER_VERSION\s*=\s*\"[^\"]*\"", f'DUMPER_VERSION = "{new_version}"', txt, count=1)
if count == 0:
print("WARNING: placeholder not found; inserting at top of file")
# Prepend definition after imports block heuristically
new_txt = txt.replace("from typing import Optional, Dict, Any, List, Tuple\n", "from typing import Optional, Dict, Any, List, Tuple\n\n# DUMPER_VERSION injected by tools/update_dumper_version.py\nDUMPER_VERSION = \"{0}\"\n".format(new_version), 1)
if new_txt == txt:
print("No changes needed (version already set).")
return 0
open(DUMPER_PATH, "w", encoding="utf-8").write(new_txt)
print(f"Updated {DUMPER_PATH} -> DUMPER_VERSION = {new_version}")
if commit:
try:
subprocess.check_call(["git", "add", DUMPER_PATH], cwd=ROOT)
subprocess.check_call(["git", "commit", "-m", f"chore: update dumper version to {new_version}"], cwd=ROOT)
print("Committed change to git.")
except Exception as e:
print(f"Failed to commit: {e}")
return 3
return 0
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--version", help="explicit version to write")
ap.add_argument("--commit", action="store_true", help="stage and commit the change")
args = ap.parse_args()
version = args.version
if not version:
version = read_version_from_file()
if not version:
version = git_describe_from(ROOT)
if not version:
print("Could not determine version from _version.py or git; please pass --version")
return 10
return replace_dumper_version(version, commit=args.commit)
if __name__ == "__main__":
sys.exit(main())