Save the tested release workflows, RAM media processing, program discovery, FLIRT library, and shared-object maintenance. Add Git exclusions, file attributes, and instructions for a later push using a forwarded SSH agent.
57 lines
3.0 KiB
Python
57 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Adapter for a pinned local bdash/spike-spk executable; wrapper coverage is partial."""
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import pathlib
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from parallelism import worker_count
|
|
from progress import report
|
|
|
|
def run(request):
|
|
if request["protocol"] != 1:
|
|
raise ValueError("unsupported protocol")
|
|
settings = request["settings"]
|
|
tool = pathlib.Path(settings["tool"]).resolve()
|
|
with tool.open("rb") as stream:
|
|
tool_hash = hashlib.file_digest(stream, "sha256").hexdigest()
|
|
if tool_hash != settings["expected_sha256"]:
|
|
raise ValueError("SPK tool build differs from pinned expected_sha256")
|
|
source = pathlib.Path(request["input_dir"])
|
|
output = pathlib.Path(request["output_dir"])
|
|
env = os.environ.copy()
|
|
limit=settings.get('max_threads',0)
|
|
if not isinstance(limit,int) or limit<0:raise ValueError('max_threads must be a nonnegative integer (0 selects automatic sizing)')
|
|
threads=worker_count(request,limit or 1_000_000)
|
|
env["RAYON_NUM_THREADS"] = str(threads)
|
|
candidates = [p for p in sorted(source.rglob("*")) if p.is_file() and not p.is_symlink()
|
|
and (p.name.lower().endswith(".spk") or re.search(r"\.spk\.\d{3}\.000$", p.name, re.I))]
|
|
if not candidates:
|
|
raise ValueError("no SPK or first split-package part found")
|
|
packages = []
|
|
for index, path in enumerate(candidates):
|
|
# Let the upstream parser validate actual structure; never assume generation
|
|
# or architecture from extension, package name, or release metadata.
|
|
destination = output / f"package-{index:04d}"
|
|
destination.mkdir()
|
|
report('Extracting SPK package',None,None,'files',f'{path.name} · up to {threads} threads',force=True)
|
|
# Extraction verifies all checksums itself; avoid reading every payload twice.
|
|
subprocess.run([str(tool), "extract", str(path), "--output", str(destination)], check=True, env=env)
|
|
packages.append({"source": path.relative_to(source).as_posix(), "generation": "unknown", "tool_sha256": tool_hash})
|
|
# Symlinks need portable metadata rather than links the host could traverse.
|
|
links = []
|
|
for path in sorted(output.rglob("*")):
|
|
if path.is_symlink():
|
|
links.append({"path": path.relative_to(output).as_posix(), "target": str(path.readlink())})
|
|
path.unlink()
|
|
(output / "package-evidence.json").write_text(json.dumps({"schema": 1, "packages": packages, "symlinks": links}))
|
|
files = [p.relative_to(output).as_posix() for p in sorted(output.rglob("*")) if p.is_file()]
|
|
return {"protocol": 1, "layer": "extracted", "coverage": "partial", "files": files,
|
|
"warnings": ["Generation not inferred. Nested asset containers remain opaque; SPIKE 3 LUKS wrappers need a separate decoder. Original inputs retained."]}
|
|
|
|
if __name__ == "__main__":
|
|
request = json.loads(pathlib.Path(sys.argv[1]).read_text())
|
|
pathlib.Path(request["result_file"]).write_text(json.dumps(run(request)))
|