from preflight import R, OLD, g, HEAD
import hashlib
import json
import os
import shutil
import signal
import subprocess
import tarfile
import time

assert not (R / 'build-started.json').exists()
v = json.loads((OLD / 'source-verify.json').read_text())
assert v['tests'] == 2 and v['errors'] == v['failures'] == 0
assert json.loads((R / 'once-trial.json').read_text())['stage'] == 'PASS'
assert g.sh(['git', '-C', str(g.REPO), 'rev-parse', 'HEAD']).strip() == HEAD
assert not g.sh(['git', '-C', str(g.REPO), 'status', '--porcelain']).strip()
for rel, record in v['imports'].items():
    assert g.sha(g.REPO / rel) == record['sha256']
plan = json.loads((R / 'plan.json').read_text())
free = lambda: shutil.disk_usage(plan['docker_root']).free
assert free() >= 15 * 1024**3
hashes = {p: g.sha(g.REPO / p) for p in ('app/api/streams.py', 'app/stream_manager.py', 'docker/Dockerfile')}
digest = hashlib.sha256((HEAD + json.dumps(hashes, sort_keys=True)).encode()).hexdigest()
tag = 'contextra-analytics:rtsp-ready-b0d7d25-' + digest[:8]
assert subprocess.run(['docker', 'image', 'inspect', tag], capture_output=True).returncode != 0
snap = R / 'snapshot'
snap.mkdir(mode=0o700)
proc = subprocess.Popen(['git', '-C', str(g.REPO), 'archive', HEAD], stdout=subprocess.PIPE)
with tarfile.open(fileobj=proc.stdout, mode='r|') as archive:
    archive.extractall(snap, filter='data')
assert proc.wait() == 0
(R / 'source.json').write_text(json.dumps(dict(head=HEAD, hashes=hashes, tag=tag), indent=2))
(R / 'build-started.json').write_text(json.dumps(dict(build_count=1, tag=tag, disk_free=free())))
ledger = json.loads((R / 'ledger.json').read_text())
ledger['builds'] += 1
(R / 'ledger.json').write_text(json.dumps(ledger, indent=2))
start = time.monotonic()
reason = None
with (R / 'build.log').open('x') as log:
    proc = subprocess.Popen(['docker', 'build', '-f', 'docker/Dockerfile', '--target', 'app', '-t', tag, '.'],
        cwd=snap, stdout=log, stderr=log, start_new_session=True, env=dict(os.environ, DOCKER_BUILDKIT='1'))
    while proc.poll() is None:
        if time.monotonic() - start > 1200 or free() < 15 * 1024**3:
            reason = 'TIME_OR_DISK_CAP'
            os.killpg(proc.pid, signal.SIGTERM)
            try:
                proc.wait(15)
            except subprocess.TimeoutExpired:
                os.killpg(proc.pid, signal.SIGKILL)
            break
        time.sleep(2)
    code = proc.wait()
result = dict(tag=tag, returncode=code, abort_reason=reason, elapsed_s=time.monotonic()-start, disk_free=free())
if code == 0:
    result['image_id'] = json.loads(g.sh(['docker', 'image', 'inspect', tag]))[0]['Id']
(R / 'build.json').write_text(json.dumps(result, indent=2))
print(json.dumps(result))
assert code == 0 and reason is None
