InstantMesh / scripts /template_update.py
Jeremy Leibs
Initial commit
344c16f unverified
#!/usr/bin/env python3
# Copied from https://github.com/rerun-io/rerun_template
"""
The script has two purposes.
After using `rerun_template` as a template, run this to clean out things you don't need.
Use `scripts/template_update.py init --languages cpp,rust,python` for this.
Update an existing repository with the latest changes from the template.
Use `scripts/template_update.py update --languages cpp,rust,python` for this.
In either case, make sure the list of languages matches the languages you want to support.
You can also use `--dry-run` to see what would happen without actually changing anything.
"""
from __future__ import annotations
import argparse
import os
import shutil
import tempfile
from git import Repo # pip install GitPython
OWNER = "rerun-io"
# Don't overwrite these when updating existing repository from the template
DO_NOT_OVERWRITE = {
"Cargo.lock",
"CHANGELOG.md",
"main.py",
"pixi.lock",
"README.md",
"requirements.txt",
}
# Files required by C++, but not by _both_ Python and Rust
CPP_FILES = {
".clang-format",
".github/workflows/cpp.yml",
"CMakeLists.txt",
"pixi.lock", # Pixi is only C++ & Python - For Rust we only use cargo
"pixi.toml", # Pixi is only C++ & Python - For Rust we only use cargo
"src/",
"src/main.cpp",
}
# Files required by Python, but not by _both_ C++ and Rust
PYTHON_FILES = {
".github/workflows/python.yml",
".mypy.ini",
"main.py",
"pixi.lock", # Pixi is only C++ & Python - For Rust we only use cargo
"pixi.toml", # Pixi is only C++ & Python - For Rust we only use cargo
"pyproject.toml",
"requirements.txt",
}
# Files required by Rust, but not by _both_ C++ and Python
RUST_FILES = {
".github/workflows/rust.yml",
"bacon.toml",
"Cargo.lock",
"Cargo.toml",
"CHANGELOG.md", # We only keep a changelog for Rust crates at the moment
"clippy.toml",
"Cranky.toml",
"deny.toml",
"rust-toolchain",
"scripts/clippy_wasm/",
"scripts/clippy_wasm/clippy.toml",
"scripts/generate_changelog.py", # We only keep a changelog for Rust crates at the moment
"src/",
"src/lib.rs",
"src/main.rs",
}
# Files we used to have, but have been removed in never version of rerun_template
DEAD_FILES = ["bacon.toml", "Cranky.toml"]
def parse_languages(lang_str: str) -> set[str]:
languages = lang_str.split(",") if lang_str else []
for lang in languages:
assert lang in ["cpp", "python", "rust"], f"Unsupported language: {lang}"
return set(languages)
def calc_deny_set(languages: set[str]) -> set[str]:
"""The set of files to delete/ignore."""
files_to_delete = CPP_FILES | PYTHON_FILES | RUST_FILES
if "cpp" in languages:
files_to_delete -= CPP_FILES
if "python" in languages:
files_to_delete -= PYTHON_FILES
if "rust" in languages:
files_to_delete -= RUST_FILES
return files_to_delete
def init(languages: set[str], dry_run: bool) -> None:
print("Removing all language-specific files not needed for languages {languages}.")
files_to_delete = calc_deny_set(languages)
delete_files_and_folder(files_to_delete, dry_run)
def remove_file(filepath: str):
try:
os.remove(filepath)
except FileNotFoundError:
pass
def delete_files_and_folder(paths: set[str], dry_run: bool) -> None:
repo_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
for path in paths:
full_path = os.path.join(repo_path, path)
if os.path.exists(full_path):
if os.path.isfile(full_path):
print(f"Removing file {full_path}…")
if not dry_run:
remove_file(full_path)
elif os.path.isdir(full_path):
print(f"Removing folder {full_path}…")
if not dry_run:
shutil.rmtree(full_path)
def update(languages: set[str], dry_run: bool) -> None:
for file in DEAD_FILES:
print(f"Removing dead file {file}…")
if not dry_run:
remove_file(file)
files_to_ignore = calc_deny_set(languages) | DO_NOT_OVERWRITE
repo_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
with tempfile.TemporaryDirectory() as temp_dir:
Repo.clone_from("https://github.com/rerun-io/rerun_template.git", temp_dir)
for root, dirs, files in os.walk(temp_dir):
for file in files:
src_path = os.path.join(root, file)
rel_path = os.path.relpath(src_path, temp_dir)
if rel_path.startswith(".git/"):
continue
if rel_path.startswith("src/"):
continue
if rel_path in files_to_ignore:
continue
dest_path = os.path.join(repo_path, rel_path)
print(f"Updating {rel_path}…")
if not dry_run:
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
shutil.copy2(src_path, dest_path)
def main() -> None:
parser = argparse.ArgumentParser(description="Handle the Rerun template.")
subparsers = parser.add_subparsers(dest="command")
init_parser = subparsers.add_parser("init", help="Initialize a new checkout of the template.")
init_parser.add_argument(
"--languages", default="", nargs="?", const="", help="The languages to support (e.g. `cpp,python,rust`)."
)
init_parser.add_argument("--dry-run", action="store_true", help="Don't actually delete any files.")
update_parser = subparsers.add_parser(
"update", help="Update all existing Rerun repositories with the latest changes from the template"
)
update_parser.add_argument(
"--languages", default="", nargs="?", const="", help="The languages to support (e.g. `cpp,python,rust`)."
)
update_parser.add_argument("--dry-run", action="store_true", help="Don't actually delete any files.")
args = parser.parse_args()
if args.command == "init":
init(parse_languages(args.languages), args.dry_run)
elif args.command == "update":
update(parse_languages(args.languages), args.dry_run)
else:
parser.print_help()
exit(1)
if __name__ == "__main__":
main()