#!/usr/bin/env python3
"""Build an independent, read-only recovery filesystem from its own rootfs."""
import argparse
import json
from pathlib import Path
import subprocess
import sys
import tarfile
import tempfile
import uuid

project = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(project / 'tools'))
from image_formats import digest, NAMESPACE

parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--rootfs', type=Path, default=project / 'out/rootfs-recovery.tar')
parser.add_argument('--output-directory', type=Path)
args = parser.parse_args()
rootfs = args.rootfs.resolve(strict=True)
with tarfile.open(rootfs) as archive:
    profile = archive.extractfile('usr/share/fds/image-profile').read(64).decode().strip()
    try:
        root = archive.getmember('.')
    except KeyError:
        parser.error('rootfs omits root directory metadata; rebuild the rootfs')
    if not root.isdir() or (root.uid, root.gid, root.mode) != (0, 0, 0o755):
        parser.error('rootfs must explicitly record / as root:root mode 0755; rebuild the rootfs')
if profile != 'recovery':
    parser.error('input must be a separately built recovery rootfs')
work = args.output_directory or Path(tempfile.mkdtemp(prefix='recovery-build.', dir=project / 'out'))
if not work.is_dir() or any(work.iterdir()):
    parser.error('output directory must exist and be empty')
epoch = int(subprocess.check_output(['git', '-C', str(project / 'vendor/void-packages'), 'show', '-s', '--format=%ct', 'HEAD']))
identity = uuid.uuid5(NAMESPACE, 'recovery:' + digest(rootfs))
runner = str(project / 'tools/in-image-tools')
image = work / 'recovery.erofs'
subprocess.run([runner, 'mkfs.erofs', '-T', str(epoch), '-U', str(identity), '-b4096',
                '-L', 'FDS_RECOVERY', '--tar=f', str(image), str(rootfs)], check=True)
subprocess.run([runner, 'fsck.erofs', '--extract', str(image)], check=True)
(work / 'manifest.json').write_text(json.dumps({
    'format': 1, 'profile': profile, 'rootfs_sha256': digest(rootfs),
    'image_sha256': digest(image), 'bytes': image.stat().st_size,
    'partition_name': 'FDS_RECOVERY', 'filesystem': 'erofs',
}, indent=2) + '\n')
if args.output_directory is None:
    target = project / 'out/fds-recovery.img.next'
    target.symlink_to(work.name + '/recovery.erofs')
    target.replace(project / 'out/fds-recovery.img')
print(f'PASS: independent recovery EROFS (partition payload): {work}')
