Release standalone PPT template workflow 0.5.0
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Add a bundled native builder to a clean initialized project, without relocking."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import ppt_project as project_cli
|
||||
import template_ref as ref
|
||||
|
||||
|
||||
def prepare(root: Path):
|
||||
root = project_cli.root_path(root)
|
||||
config, _ = project_cli.check(root)
|
||||
ref.require(config["authoring"]["route"] == "native", "prepare requires authoring.route=native")
|
||||
ref.require(config["build"]["entrypoint"] is None and not config["build"]["inputs"], "prepare refuses an existing/custom builder")
|
||||
environment = project_cli.safe_path(root, config["environment"], "environment")
|
||||
old_environment = environment.read_bytes()
|
||||
env = ref.read_json(environment, (1,))
|
||||
ref.require(not env["packages"] and not env["fonts"] and not env["tools"], "prepare refuses to overwrite a configured environment")
|
||||
manifest = ref.load_manifest(root / config["template"]["manifest"])
|
||||
ref.require(manifest["schema_version"] == 2, "prepare requires manifest schema 2")
|
||||
template_root = (root / config["template"]["manifest"]).parent
|
||||
style = ref.read_json(ref.file_path(template_root, manifest["style"], "style"), None)
|
||||
workflow = root / "vendor/native-workflow"
|
||||
builder = root / "tools/native_builder.py"
|
||||
ref.require(not workflow.exists() and not builder.exists(), "prepare refuses existing native-workflow or native_builder.py paths")
|
||||
skill = Path(__file__).resolve().parent.parent
|
||||
provenance = ref.read_json(skill / "runtime/provenance.json", (1,))
|
||||
package_lines = (skill / "runtime/requirements.txt").read_text(encoding="utf-8").splitlines()
|
||||
packages = dict(line.split("==", 1) for line in package_lines if line.strip() and not line.startswith("#"))
|
||||
fonts = [{"role": role, **entry, "distributed": False, "embedded": False,
|
||||
"verification": "declared by the selected template; installation, file identity and licenses require destination readback"}
|
||||
for role, entry in style["typography"]["families"].items()]
|
||||
new_env = {"schema_version": 1, "python": {"minimum": "3.12", "project_cli_minimum": "3.10"},
|
||||
"packages": packages, "fonts": fonts,
|
||||
"tools": [{"name": provenance["component"], "version": provenance["version"],
|
||||
"path": "vendor/native-workflow/runtime/ppt-master", "source": provenance["source"],
|
||||
"license": provenance["license"], "upstream_modified": False}],
|
||||
"external_executables": [], "capabilities": {"image_generation": "host tool when needed",
|
||||
"PowerPoint": "host application and supported UI tool for application checks"}}
|
||||
old_config = (root / "project.json").read_bytes()
|
||||
created = []
|
||||
with tempfile.TemporaryDirectory(prefix="native-prepare-", dir=root.parent) as temporary:
|
||||
staging = Path(temporary) / "native-workflow"
|
||||
staging.mkdir()
|
||||
shutil.copytree(skill / "runtime", staging / "runtime", ignore=shutil.ignore_patterns("__pycache__", "*.pyc", "*.pyo"))
|
||||
(staging / "scripts").mkdir()
|
||||
for name in ("native_export.py", "finalize_theme.py", "template_ref.py"):
|
||||
shutil.copyfile(skill / "scripts" / name, staging / "scripts" / name)
|
||||
# The snapshot is an explicit build input; no installed Skill is needed
|
||||
# after this project is moved to a different directory or machine.
|
||||
inputs = ["vendor/native-workflow/" + path.relative_to(staging).as_posix()
|
||||
for path in sorted(staging.rglob("*")) if path.is_file()]
|
||||
try:
|
||||
shutil.copytree(staging, workflow)
|
||||
created.append(workflow)
|
||||
with builder.open("xb") as target:
|
||||
target.write((skill / "scripts/native_builder.py").read_bytes())
|
||||
created.append(builder)
|
||||
config["build"]["entrypoint"] = "tools/native_builder.py"
|
||||
config["build"]["inputs"] = inputs
|
||||
project_cli.atomic_json(environment, new_env)
|
||||
project_cli.atomic_json(root / "project.json", config)
|
||||
project_cli.check(root, author_lock=False)
|
||||
except Exception:
|
||||
environment.write_bytes(old_environment)
|
||||
(root / "project.json").write_bytes(old_config)
|
||||
for item in reversed(created):
|
||||
shutil.rmtree(item) if item.is_dir() else item.unlink(missing_ok=True)
|
||||
raise
|
||||
return {"ok": True, "project": str(root), "builder": config["build"]["entrypoint"],
|
||||
"copied_inputs": len(inputs), "author_lock_updated": False,
|
||||
"next": "Review source and environment changes, add finalized page SVGs/notes, then run tools/ppt_project.py lock --project ."}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--project", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
print(json.dumps(prepare(args.project), ensure_ascii=False, indent=2))
|
||||
return 0
|
||||
except (ref.InputError, OSError, ValueError, KeyError, TypeError) as error:
|
||||
print(json.dumps({"error": str(error)}, ensure_ascii=False), file=sys.stderr)
|
||||
return 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user