try a python script in runner

This commit is contained in:
2026-01-17 20:15:31 -05:00
parent 44af1518a3
commit 83c22af578
109 changed files with 227 additions and 28581 deletions

226
scripts/bundle.py Executable file
View File

@@ -0,0 +1,226 @@
#!/usr/bin/env python3
import os
import shutil
import subprocess
import sys
import tempfile
import xml.etree.ElementTree as ET
from datetime import datetime, timezone
from pathlib import Path
INKSCAPE_NS = "http://www.inkscape.org/namespace/inkscape/extension"
ET.register_namespace("", INKSCAPE_NS)
REPOS = [
{
"name": "botbox3000",
"url": "https://github.com/jondale/botbox3000.git",
"branch": "main",
"directory": "botbox3000",
"inx_file": "boxbot.inx",
"id": "org.knoxmakers.botbox",
"submenu": ["Knox Makers", "Laser"],
},
{
"name": "km-living-hinge",
"url": "https://github.com/KnoxMakers/km-living-hinge.git",
"branch": "main",
"directory": "km-living-hinge",
},
{
"name": "km-plot",
"url": "https://git.knoxmakers.org/KnoxMakers/km-plot.git",
"branch": "main",
"directory": "km-plot",
},
]
def run(cmd: list[str], cwd: str | None = None) -> str:
result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, check=True)
return result.stdout.strip()
def has_staged_changes(root: Path) -> bool:
result = subprocess.run(
["git", "diff", "--cached", "--quiet"],
cwd=root,
capture_output=True,
)
return result.returncode != 0
def sync_repo(repo: dict, ext_dir: Path, tmp_dir: Path) -> None:
name = repo["name"]
url = repo["url"]
branch = repo.get("branch", "main")
directory = repo["directory"]
work = tmp_dir / name
target = ext_dir / directory
print(f"==> Sync {name} from {url} ({branch}) -> extensions/{directory}")
subprocess.run(
["git", "clone", "--depth", "1", "--branch", branch, url, str(work)],
check=True,
)
if target.exists():
shutil.rmtree(target)
shutil.copytree(work, target)
git_dir = target / ".git"
if git_dir.exists():
shutil.rmtree(git_dir)
commit = run(["git", "rev-parse", "HEAD"], cwd=str(work))
(target / ".upstream_commit").write_text(commit + "\n")
(target / ".upstream_url").write_text(url + "\n")
(target / ".upstream_branch").write_text(branch + "\n")
def set_extension_id(root: ET.Element, new_id: str) -> bool:
ns = {"ink": INKSCAPE_NS}
id_elem = root.find("ink:id", ns)
if id_elem is None:
id_elem = root.find("id")
if id_elem is not None:
if id_elem.text != new_id:
id_elem.text = new_id
return True
return False
name_elem = root.find("ink:name", ns)
if name_elem is None:
name_elem = root.find("name")
id_elem = ET.Element("id")
id_elem.text = new_id
if name_elem is not None:
idx = list(root).index(name_elem)
root.insert(idx + 1, id_elem)
else:
root.insert(0, id_elem)
return True
def set_effects_submenu(root: ET.Element, submenus: list[str]) -> bool:
ns = {"ink": INKSCAPE_NS}
effect_elem = root.find(".//ink:effect", ns)
if effect_elem is None:
effect_elem = root.find(".//effect")
if effect_elem is None:
return False
menu_elem = None
for tag in ["effects-menu", "effectsmenu"]:
menu_elem = effect_elem.find(tag)
if menu_elem is not None:
break
menu_elem = effect_elem.find(f"ink:{tag}", ns)
if menu_elem is not None:
break
if menu_elem is None:
return False
menu_elem.clear()
menu_elem.tag = "effects-menu"
parent = menu_elem
for i, submenu_name in enumerate(submenus):
submenu = ET.SubElement(parent, "submenu")
submenu.set("_name", submenu_name)
if i < len(submenus) - 1:
parent = submenu
return True
def patch_inx(inx_path: Path, extension_id: str | None, submenus: list[str] | None) -> bool:
if not inx_path.exists():
print(f"ERROR: expected file not found: {inx_path}")
sys.exit(1)
print(f"Patching {inx_path}")
tree = ET.parse(inx_path)
root = tree.getroot()
modified = False
if extension_id is not None:
if set_extension_id(root, extension_id):
modified = True
if submenus is not None:
if set_effects_submenu(root, submenus):
modified = True
if modified:
ET.indent(tree, space=" ")
tree.write(inx_path, encoding="UTF-8", xml_declaration=True)
content = inx_path.read_text(encoding="utf-8")
if not content.endswith("\n"):
inx_path.write_text(content + "\n", encoding="utf-8")
return modified
def process_repo(repo: dict, ext_dir: Path) -> None:
inx_file = repo.get("inx_file")
extension_id = repo.get("id")
submenus = repo.get("submenu")
if inx_file and (extension_id or submenus):
inx_path = ext_dir / repo["directory"] / inx_file
patch_inx(inx_path, extension_id, submenus)
def main() -> None:
root = Path(__file__).resolve().parent.parent
ext_dir = root / "extensions"
ext_dir.mkdir(exist_ok=True)
os.chdir(root)
with tempfile.TemporaryDirectory() as tmp:
tmp_dir = Path(tmp)
for repo in REPOS:
sync_repo(repo, ext_dir, tmp_dir)
subprocess.run(["git", "add", "extensions"], check=True)
if not has_staged_changes(root):
print("No bundle changes.")
sys.exit(0)
subprocess.run(["git", "checkout", "extensions"], check=True)
with tempfile.TemporaryDirectory() as tmp:
tmp_dir = Path(tmp)
for repo in REPOS:
sync_repo(repo, ext_dir, tmp_dir)
process_repo(repo, ext_dir)
subprocess.run(["git", "add", "extensions"], check=True)
date_str = datetime.now(timezone.utc).strftime("%Y-%m-%d")
subprocess.run(
["git", "commit", "-m", f"bundle: update ({date_str})"],
check=True,
)
if __name__ == "__main__":
main()