Files
verstack/scripts/install_local_tools.py

72 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""Install pinned official archives from docs/toolchain.lock.json. No system writes."""
import hashlib
import json
from pathlib import Path
import tarfile
import urllib.request
import zipfile
ROOT = Path(__file__).resolve().parents[1]
TOOLS = ROOT / "tools"
DOWNLOADS = TOOLS / "downloads"
def download(url, name, digest=None):
dest = DOWNLOADS / name
if not dest.exists():
part = dest.with_suffix(dest.suffix + ".part")
with urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": "verstack-local-setup"}), timeout=120) as src, part.open("wb") as out:
while chunk := src.read(1024 * 1024):
out.write(chunk)
part.rename(dest)
with dest.open("rb") as stream:
actual = hashlib.file_digest(stream, "sha256").hexdigest()
if digest and actual != digest.removeprefix("sha256:"):
raise ValueError(f"Checksum mismatch: {name}")
print(f"Verified {name}: sha256:{actual}", flush=True)
return dest, actual
def main():
DOWNLOADS.mkdir(parents=True, exist_ok=True)
lock = json.loads((ROOT / "docs/toolchain.lock.json").read_text())
ghidra = lock["ghidra"]
archive, digest = download(ghidra["url"], ghidra["url"].rsplit('/', 1)[1], ghidra["sha256"])
with zipfile.ZipFile(archive) as z:
folder = z.namelist()[0].split('/')[0]
if not (TOOLS / folder).exists():
z.extractall(TOOLS)
for e in z.infolist():
mode = e.external_attr >> 16
if mode:
(TOOLS / e.filename).chmod(mode & 0o777)
ghidra_home = TOOLS / folder
jdk = lock["jdk"]
java_archive, java_digest = download(jdk["url"], jdk["url"].rsplit('/', 1)[1], jdk["sha256"])
with tarfile.open(java_archive) as t:
java_folder = t.getnames()[0].split('/')[0]
if not (TOOLS / java_folder).exists():
t.extractall(TOOLS, filter="data")
java_home = TOOLS / java_folder
record = {"schema": 1, "ghidra_home": str(ghidra_home), "ghidra_version": ghidra["version"], "ghidra_archive_sha256": digest,
"java_home": str(java_home), "java_version": jdk["version"], "java_archive_sha256": java_digest}
(TOOLS / "installed.json").write_text(json.dumps(record, indent=2))
(TOOLS / "bin").mkdir(exist_ok=True)
for name, script in [("ghidra", "ghidraRun"), ("ghidra-headless", "support/analyzeHeadless")]:
launcher = TOOLS / "bin" / name
launcher.write_text('''#!/usr/bin/env python3
import json,os,pathlib,sys
root=pathlib.Path(__file__).resolve().parents[2]
record=json.loads((root/'tools/installed.json').read_text())
env=os.environ.copy()
env['JAVA_HOME']=record['java_home']
env['XDG_CONFIG_HOME']=str(root/'data/ghidra-user/config')
env['XDG_CACHE_HOME']=str(root/'data/ghidra-user/cache')
launcher=str(pathlib.Path(record['ghidra_home'])/SCRIPT)
os.execve(launcher,[launcher,*sys.argv[1:]],env)
'''.replace("SCRIPT", repr(script)))
launcher.chmod(0o755)
print(json.dumps(record, indent=2))
if __name__ == "__main__":
main()