mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-20 15:54:13 +08:00
165 lines
5.8 KiB
Python
165 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Publish rebuilt artifacts under a manifest namespace without changing sources."""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
def load_manifest(path: Path) -> tuple[dict, list[dict]]:
|
|
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
if not isinstance(payload, dict) or not isinstance(payload.get("models"), list):
|
|
raise ValueError(f"Expected an object containing a models list: {path}")
|
|
return payload, payload["models"]
|
|
|
|
|
|
def renamed_filename(filename: str, old_id: str, new_id: str) -> str:
|
|
old_prefix = f"{old_id}_driving_tinygrad.pkl"
|
|
if filename == old_prefix or filename.startswith(f"{old_prefix}."):
|
|
return f"{new_id}_driving_tinygrad.pkl{filename[len(old_prefix):]}"
|
|
return filename
|
|
|
|
|
|
def rename_model_files(directory: Path, old_id: str, new_id: str) -> None:
|
|
if not directory.is_dir():
|
|
return
|
|
|
|
candidates = [
|
|
path for path in directory.iterdir()
|
|
if renamed_filename(path.name, old_id, new_id) != path.name
|
|
]
|
|
if not candidates:
|
|
return
|
|
|
|
staged: list[tuple[Path, Path]] = []
|
|
for source in candidates:
|
|
temporary = source.with_name(f".{source.name}.namespace-tmp")
|
|
if temporary.exists():
|
|
temporary.unlink()
|
|
source.rename(temporary)
|
|
staged.append((temporary, directory / renamed_filename(source.name, old_id, new_id)))
|
|
|
|
for temporary, destination in staged:
|
|
if destination.exists():
|
|
destination.unlink()
|
|
temporary.rename(destination)
|
|
|
|
checksum = directory / f"{new_id}_driving_tinygrad.pkl.sha256"
|
|
if checksum.is_file():
|
|
text = checksum.read_text(encoding="utf-8")
|
|
text = text.replace(f"{old_id}_driving_tinygrad.pkl", f"{new_id}_driving_tinygrad.pkl")
|
|
checksum.write_text(text, encoding="utf-8")
|
|
|
|
|
|
def remap_multipart_handoff(path: Path, id_map: dict[str, str]) -> None:
|
|
if not path.is_file():
|
|
return
|
|
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
if not isinstance(payload, list):
|
|
raise ValueError(f"Expected a multipart handoff list: {path}")
|
|
for entry in payload:
|
|
if not isinstance(entry, dict):
|
|
continue
|
|
old_id = str(entry.get("id") or "")
|
|
new_id = id_map.get(old_id)
|
|
if not new_id:
|
|
continue
|
|
entry["id"] = new_id
|
|
for key in ("filename",):
|
|
if entry.get(key):
|
|
entry[key] = renamed_filename(str(entry[key]), old_id, new_id)
|
|
entry["parts"] = [renamed_filename(str(part), old_id, new_id) for part in entry.get("parts", [])]
|
|
path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
|
|
|
|
|
|
def build_id_map(models: list[dict], suffix: str, manifest_version: str) -> dict[str, str]:
|
|
"""Append the namespace suffix without colliding with an existing source ID."""
|
|
source_ids = [str(model["id"]) for model in models]
|
|
source_id_set = set(source_ids)
|
|
id_map: dict[str, str] = {}
|
|
for old_id in source_ids:
|
|
candidate = f"{old_id}{suffix}"
|
|
if candidate in source_id_set:
|
|
candidate = f"{old_id}{manifest_version}"
|
|
while candidate in id_map.values():
|
|
candidate += "_"
|
|
id_map[old_id] = candidate
|
|
return id_map
|
|
|
|
|
|
def namespace_workspace(
|
|
workspace: Path,
|
|
base_manifest: Path,
|
|
manifest_version: str,
|
|
suffix: str,
|
|
completed_ids: list[str] | None = None,
|
|
) -> Path:
|
|
payload, models = load_manifest(base_manifest)
|
|
if not suffix or any(not str(model.get("id") or "") for model in models):
|
|
raise ValueError("Every manifest model must have an ID and the suffix must be non-empty")
|
|
|
|
id_map = build_id_map(models, suffix, manifest_version)
|
|
if len(set(id_map.values())) != len(id_map):
|
|
raise ValueError("The requested model namespace contains ID collisions")
|
|
|
|
compiled = workspace / "compiled"
|
|
ready = workspace / "ready-for-resources"
|
|
ids_to_namespace = set(completed_ids) if completed_ids is not None else set(id_map)
|
|
unknown_ids = sorted(ids_to_namespace - set(id_map))
|
|
if unknown_ids:
|
|
raise KeyError(f"IDs are not present in the base manifest: {', '.join(unknown_ids)}")
|
|
missing = [
|
|
old_id for old_id in ids_to_namespace
|
|
if not (compiled / f"{old_id}_driving_tinygrad.pkl").is_file()
|
|
and not (compiled / f"{id_map[old_id]}_driving_tinygrad.pkl").is_file()
|
|
]
|
|
if missing:
|
|
raise FileNotFoundError(f"Missing compiled artifacts for: {', '.join(sorted(missing))}")
|
|
|
|
for old_id, new_id in id_map.items():
|
|
if old_id not in ids_to_namespace:
|
|
continue
|
|
rename_model_files(compiled, old_id, new_id)
|
|
rename_model_files(ready, old_id, new_id)
|
|
|
|
namespaced_models = []
|
|
for model in models:
|
|
namespaced = dict(model)
|
|
namespaced["id"] = id_map[str(model["id"])]
|
|
namespaced_models.append(namespaced)
|
|
|
|
output = dict(payload)
|
|
output["models"] = namespaced_models
|
|
output_path = workspace / "manifests" / f"model_names_{manifest_version}.json"
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
output_path.write_text(json.dumps(output, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
|
|
|
remap_multipart_handoff(ready / "multipart.json", id_map)
|
|
(workspace / "source-maps" / f"model_id_namespace_{manifest_version}.json").write_text(
|
|
json.dumps(id_map, indent=2) + "\n", encoding="utf-8",
|
|
)
|
|
return output_path
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--workspace", type=Path, required=True)
|
|
parser.add_argument("--base-manifest", type=Path, required=True)
|
|
parser.add_argument("--manifest-version", default="v23")
|
|
parser.add_argument("--suffix", default="3")
|
|
parser.add_argument(
|
|
"--completed-ids",
|
|
nargs="+",
|
|
help="Only namespace these confirmed rebuilt IDs; still write the full manifest.",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
output = namespace_workspace(args.workspace, args.base_manifest, args.manifest_version, args.suffix, args.completed_ids)
|
|
print(output)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|