128 lines
4.2 KiB
Python
128 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
from retrobuilder.model import BaseSpec, FeatureSpec, ProfileSpec
|
|
|
|
|
|
LIVE_DIR_STRUCTURE = (
|
|
'config/chroot_local-packageslists',
|
|
'config/chroot_local-packages',
|
|
'config/chroot_local-includes',
|
|
'config/chroot_local-hooks',
|
|
)
|
|
|
|
|
|
def ensure_live_structure(live_dir: Path) -> None:
|
|
for relative in LIVE_DIR_STRUCTURE:
|
|
(live_dir / relative).mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
def clear_directory_contents(path: Path) -> None:
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
for child in path.iterdir():
|
|
if child.name == '.gitkeep':
|
|
continue
|
|
if child.is_dir() and not child.is_symlink():
|
|
shutil.rmtree(child)
|
|
else:
|
|
child.unlink()
|
|
|
|
|
|
def copy_tree_contents(src: Path, dst: Path) -> None:
|
|
if not src.exists():
|
|
return
|
|
dst.mkdir(parents=True, exist_ok=True)
|
|
for child in src.iterdir():
|
|
target = dst / child.name
|
|
if child.is_dir():
|
|
shutil.copytree(child, target, dirs_exist_ok=True)
|
|
else:
|
|
shutil.copy2(child, target)
|
|
|
|
|
|
def copy_glob(src_dir: Path, pattern: str, dst_dir: Path, prefix: str = '') -> None:
|
|
if not src_dir.exists():
|
|
return
|
|
dst_dir.mkdir(parents=True, exist_ok=True)
|
|
for src in sorted(src_dir.glob(pattern)):
|
|
if src.is_dir():
|
|
continue
|
|
name = f'{prefix}{src.name}' if prefix else src.name
|
|
shutil.copy2(src, dst_dir / name)
|
|
|
|
|
|
def save_json(path: Path, payload: dict) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(json.dumps(payload, indent=2, sort_keys=True) + '\n', encoding='utf-8')
|
|
|
|
|
|
def save_profile_metadata(
|
|
path: Path,
|
|
profile_name: str,
|
|
profile: ProfileSpec,
|
|
base_name: str,
|
|
base: BaseSpec,
|
|
base_chain: list[tuple[str, BaseSpec]] | None = None,
|
|
) -> None:
|
|
save_json(path, {
|
|
'profile_name': profile_name,
|
|
'profile': profile.to_dict(),
|
|
'base_name': base_name,
|
|
'base': base.to_dict(),
|
|
'base_chain': [
|
|
{'name': item_name, 'spec': item_spec.to_dict()}
|
|
for item_name, item_spec in (base_chain or [(base_name, base)])
|
|
],
|
|
})
|
|
|
|
|
|
def save_feature_metadata(path: Path, feature_name: str, feature: FeatureSpec) -> None:
|
|
save_json(path, {'feature_name': feature_name, 'feature': feature.to_dict()})
|
|
|
|
|
|
def apply_profile_common_configuration(root: Path, live_dir: Path, profile_name: str, profile: ProfileSpec) -> None:
|
|
ensure_live_structure(live_dir)
|
|
notes_dir = live_dir / 'builder-notes'
|
|
notes_dir.mkdir(parents=True, exist_ok=True)
|
|
notes = [
|
|
f'profile={profile_name}',
|
|
f'base={profile.base}',
|
|
f'features={"|".join(profile.features)}',
|
|
]
|
|
if profile.splash:
|
|
splash_src = root / profile.splash
|
|
if splash_src.exists():
|
|
splash_dst = notes_dir / splash_src.name
|
|
shutil.copy2(splash_src, splash_dst)
|
|
notes.append(f'splash={profile.splash}')
|
|
(notes_dir / 'profile-common.txt').write_text('\n'.join(notes) + '\n', encoding='utf-8')
|
|
|
|
|
|
def inject_module_resources(module_dir: Path, live_dir: Path, prefix: str) -> None:
|
|
copy_tree_contents(module_dir / 'packageslists', live_dir / 'config' / 'chroot_local-packageslists')
|
|
copy_tree_contents(module_dir / 'packages', live_dir / 'config' / 'chroot_local-packages')
|
|
copy_tree_contents(module_dir / 'chroot', live_dir / 'config' / 'chroot_local-includes')
|
|
copy_glob(module_dir / 'hooks', '*.sh', live_dir / 'config' / 'chroot_local-hooks', prefix=f'{prefix}_')
|
|
|
|
|
|
def profile_pre_build(live_dir: Path, profile_name: str) -> None:
|
|
marker = live_dir / 'builder-notes' / 'pre-build.txt'
|
|
marker.parent.mkdir(parents=True, exist_ok=True)
|
|
marker.write_text(f'pre-build profile={profile_name}\n', encoding='utf-8')
|
|
|
|
|
|
def profile_finalize(root: Path, profile_name: str) -> None:
|
|
live_dir = root / 'live'
|
|
out_dir = root / 'artifacts' / 'profiles' / profile_name / 'final'
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
summary = out_dir / 'summary.txt'
|
|
summary.write_text(
|
|
'Profile finalization complete.\n'
|
|
f'profile={profile_name}\n'
|
|
f'live_exists={live_dir.exists()}\n',
|
|
encoding='utf-8',
|
|
)
|