Release Vulpes OS 2.7-preview.24

This commit is contained in:
OverSu 2026-11-04 12:52:20 +01:00
commit 97ef99f827
135 changed files with 7717 additions and 2524 deletions

View file

@ -5,6 +5,8 @@ import argparse
import json
import os
from pathlib import Path
import shlex
import shutil
import subprocess
import uuid
from persistent_state import FEATURES, digest
@ -15,6 +17,8 @@ def main():
parser.add_argument('--output', type=Path, required=True)
parser.add_argument('--system-image', type=Path, required=True)
parser.add_argument('--size-mib', type=int, default=2048)
parser.add_argument('--profile-dir', type=Path,
help='Copy an existing droidian-trial browser profile into a fresh P23 state')
args = parser.parse_args()
if args.size_mib < 512 or args.size_mib > 8192:
parser.error('Choose 512–8192 MiB')
@ -31,6 +35,23 @@ def main():
for directory in ('upper','work'):
(seed/directory).mkdir(mode=0o755 if directory == 'upper' else 0o700)
(seed/'upper').chmod(0o755)
migrated = []
opt_layer = None
if args.profile_dir:
profile = args.profile_dir.resolve(strict=True)
if not profile.is_dir() or profile.is_symlink():
raise ValueError('Profile source must be a real directory')
opt_layer = seed/'upper/opt'
vulpes_layer = opt_layer/'vulpes'
profiles_layer = vulpes_layer/'profiles'
profiles_layer.mkdir(parents=True)
opt_layer.chmod(0o755)
vulpes_layer.chmod(0o755)
profiles_layer.chmod(0o755)
target = profiles_layer/'droidian-trial'
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copytree(profile, target, symlinks=True)
migrated = [vulpes_layer, profiles_layer, target, *target.rglob('*')]
identifier = str(uuid.uuid4())
image = out/(identifier+'.ext4')
with image.open('xb') as stream:
@ -42,12 +63,23 @@ def main():
for field in ('uid','gid'):
subprocess.run(['debugfs','-w','-R',f'set_inode_field {name} {field} 0',str(image)],
check=True,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
if migrated:
# Gaia runs as the droidian account (UID/GID 32011) on Sargo.
commands = out/'profile-ownership.debugfs'
commands.write_text(''.join(
f'set_inode_field {shlex.quote("/upper/" + str(path.relative_to(seed/"upper")))} {field} 32011\n'
for path in migrated for field in ('uid','gid')) +
'set_inode_field /upper/opt uid 0\nset_inode_field /upper/opt gid 0\n')
subprocess.run(['debugfs','-w','-f',str(commands),str(image)],check=True,
stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
commands.unlink()
check = subprocess.run(['e2fsck','-f','-n',str(image)],text=True,capture_output=True)
(out/'filesystem-check.txt').write_text(check.stdout+check.stderr)
if check.returncode:raise RuntimeError('Data image failed filesystem verification')
manifest = {'schema':1,'device':'sargo','uuid':identifier,'image':image.name,
'imageSha256':digest(image),'bytes':image.stat().st_size,
'systemImageSha256':system['imageSha256'],'filesystemCheckPassed':True,
'migratedProfile':bool(args.profile_dir),
'scope':'Private persistent overlay; containing filesystem retained; no partition formatting'}
(out/'state.json').write_text(json.dumps(manifest,indent=2)+'\n')
print(out/'state.json')