Files
docview/tests/ubuntu_vm/prepare_downloads.py
T
2026-09-21 13:41:40 +09:00

43 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""Disposable local Ubuntu validation VM helper; no host package installation."""
import os
import urllib.request, hashlib, json, pathlib, time, subprocess, concurrent.futures
ROOT=pathlib.Path(os.environ.get('DOCVIEW_VM_WORK', 'build-ubuntu-vm')).resolve()
D=ROOT/'downloads'
for sub in ['downloads','metadata','logs','tools','private']: (ROOT/sub).mkdir(parents=True,exist_ok=True)
os.chmod(ROOT/'private',0o700)
entries=[
('SHA256SUMS','https://cloud-images.ubuntu.com/noble/20260911/SHA256SUMS',100000),
('SHA256SUMS.gpg','https://cloud-images.ubuntu.com/noble/20260911/SHA256SUMS.gpg',100000),
('ubuntu-cloud-key.asc','https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xD2EB44626FDDC30B513D5BB71A5D6C4C7DB87C81',100000),
('noble-server-cloudimg-amd64.img','https://cloud-images.ubuntu.com/noble/20260911/noble-server-cloudimg-amd64.img',700*1024*1024),
('noble-server-cloudimg-amd64.manifest','https://cloud-images.ubuntu.com/noble/20260911/noble-server-cloudimg-amd64.manifest',100000),
('qemu-img-11.1.1-2-x86_64.pkg.tar.zst','https://geo.mirror.pkgbuild.com/extra/os/x86_64/qemu-img-11.1.1-2-x86_64.pkg.tar.zst',5*1024*1024),
('qemu-img-11.1.1-2-x86_64.pkg.tar.zst.sig','https://geo.mirror.pkgbuild.com/extra/os/x86_64/qemu-img-11.1.1-2-x86_64.pkg.tar.zst.sig',100000),
('qt-base-Updates.xml','https://download.qt.io/online/qtsdkrepository/linux_x64/desktop/qt6_6112/qt6_6112/Updates.xml',1000000),
('qt-webengine-Updates.xml','https://download.qt.io/online/qtsdkrepository/linux_x64/extensions/qtwebengine/6112/x86_64/Updates.xml',1000000),
('pycdlib.json','https://pypi.org/pypi/pycdlib/1.14.0/json',1000000)]
def fetch(e):
name,url,limit=e;p=D/name;start=time.time();h=hashlib.sha256();n=0
if p.exists():
with p.open('rb') as f:
for b in iter(lambda:f.read(1024*1024),b''):h.update(b);n+=len(b)
return dict(name=name,url=url,size=n,sha256=h.hexdigest(),reused=True)
try:
with urllib.request.urlopen(url,timeout=60) as r,p.with_suffix(p.suffix+'.part').open('wb') as f:
final=r.url
while True:
b=r.read(1024*1024)
if not b:break
n+=len(b)
if n>limit:raise RuntimeError('download size bound exceeded')
f.write(b);h.update(b)
p.with_suffix(p.suffix+'.part').rename(p)
print(name,n,'downloaded',flush=True)
return dict(name=name,url=url,finalUrl=final,size=n,sha256=h.hexdigest(),seconds=round(time.time()-start,3))
except Exception as ex:
print(name,'FAILED',str(ex),flush=True);return dict(name=name,url=url,error=str(ex))
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as pool: records=list(pool.map(fetch,entries))
(ROOT/'metadata/downloads.json').write_text(json.dumps(records,indent=2)+'\n')
if any('error' in e for e in records):raise SystemExit(1)