remove useless parameters
This commit is contained in:
@@ -15,10 +15,7 @@ from retrobuilder.entrypoints import BaseEntry, cli_dispatch
|
||||
from retrobuilder.model import BaseSpec
|
||||
|
||||
SPEC = BaseSpec(
|
||||
name='retrodebian-common',
|
||||
description='Common inherited base resources shared by concrete bases.',
|
||||
packages=(),
|
||||
package_lists=(),
|
||||
docker_overrides={},
|
||||
)
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
THIS_DIR = Path(__file__).resolve().parent
|
||||
PACKAGE_ROOT = THIS_DIR / 'retrobuilder'
|
||||
if str(THIS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(THIS_DIR))
|
||||
|
||||
@@ -22,7 +21,6 @@ from retrobuilder.loader import (
|
||||
load_feature_spec,
|
||||
load_profile,
|
||||
)
|
||||
from retrobuilder.model import DockerStageSpec
|
||||
from retrobuilder.operations import (
|
||||
apply_profile_common_configuration,
|
||||
clear_directory_contents,
|
||||
@@ -50,55 +48,35 @@ def root_dir() -> Path:
|
||||
def list_names(path: Path) -> list[str]:
|
||||
if not path.exists():
|
||||
return []
|
||||
return sorted(child.name for child in path.iterdir() if child.is_dir())
|
||||
return sorted(item.name for item in path.iterdir() if item.is_dir())
|
||||
|
||||
|
||||
def list_profiles(path: Path) -> list[str]:
|
||||
if not path.exists():
|
||||
return []
|
||||
return sorted(p.stem for p in path.glob('*.py') if p.is_file())
|
||||
return sorted(item.stem for item in path.iterdir() if item.is_file() and item.suffix == '.py')
|
||||
|
||||
|
||||
def build_context(root: Path, phase: str, kind: str, profile_name: str = '', base_name: str = '', feature_name: str = '') -> BuildContext:
|
||||
live_dir = root / 'live'
|
||||
artifacts_root = root / 'artifacts'
|
||||
def build_context(root: Path, phase: str, kind: str, profile_name: str, base_name: str = '', feature_name: str = '') -> BuildContext:
|
||||
profile = load_profile(root, profile_name) if profile_name else None
|
||||
base = load_base_spec(root, base_name or (profile.base if profile else '')) if (base_name or profile) else None
|
||||
feature = load_feature_spec(root, feature_name) if feature_name else None
|
||||
|
||||
current_name = {
|
||||
'profile': profile_name,
|
||||
'base': base.name if base else '',
|
||||
'feature': feature.name if feature else '',
|
||||
}[kind]
|
||||
current_dir = {
|
||||
'profile': root / 'profiles' / f'{profile_name}.py',
|
||||
'base': base_dir(root, base.name if base else base_name),
|
||||
'feature': feature_dir(root, feature.name if feature else feature_name),
|
||||
}[kind]
|
||||
current_artifact_dir = {
|
||||
'profile': profile_artifacts_dir(root, profile_name),
|
||||
'base': base_artifacts_dir(root, base.name if base else base_name),
|
||||
'feature': feature_artifacts_dir(root, feature.name if feature else feature_name),
|
||||
}[kind]
|
||||
|
||||
return BuildContext(
|
||||
project_root=root,
|
||||
live_dir=live_dir,
|
||||
artifacts_root=artifacts_root,
|
||||
live_dir=root / 'live',
|
||||
artifacts_root=root / 'artifacts',
|
||||
phase=phase,
|
||||
current_kind=kind,
|
||||
current_name=current_name,
|
||||
current_module_dir=current_dir,
|
||||
current_module_artifact_dir=current_artifact_dir,
|
||||
profile_name=profile.name if profile else profile_name,
|
||||
profile_artifact_dir=profile_artifacts_dir(root, profile.name) if profile else None,
|
||||
base_name=base.name if base else '',
|
||||
base_dir=base_dir(root, base.name) if base else None,
|
||||
base_artifact_dir=base_artifacts_dir(root, base.name) if base else None,
|
||||
feature_name=feature.name if feature else '',
|
||||
feature_dir=feature_dir(root, feature.name) if feature else None,
|
||||
feature_artifact_dir=feature_artifacts_dir(root, feature.name) if feature else None,
|
||||
current_name=base_name or feature_name or profile_name,
|
||||
current_module_artifact_dir=(
|
||||
base_artifacts_dir(root, base_name) if kind == 'base' else
|
||||
feature_artifacts_dir(root, feature_name) if kind == 'feature' else
|
||||
profile_artifacts_dir(root, profile_name)
|
||||
),
|
||||
profile_name=profile_name,
|
||||
profile_artifact_dir=profile_artifacts_dir(root, profile_name) if profile_name else None,
|
||||
base_name=base_name,
|
||||
base_artifact_dir=base_artifacts_dir(root, base_name) if base_name else None,
|
||||
feature_name=feature_name,
|
||||
feature_artifact_dir=feature_artifacts_dir(root, feature_name) if feature_name else None,
|
||||
profile_features=tuple(profile.features) if profile else (),
|
||||
)
|
||||
|
||||
@@ -120,8 +98,7 @@ def run_python_phase(args: argparse.Namespace) -> int:
|
||||
|
||||
def export_env(args: argparse.Namespace) -> int:
|
||||
root = root_dir()
|
||||
kind = args.kind
|
||||
ctx = build_context(root, args.phase, kind, args.profile or '', args.base or '', args.feature or '')
|
||||
ctx = build_context(root, args.phase, args.kind, args.profile or '', args.base or '', args.feature or '')
|
||||
values = ctx.to_env()
|
||||
values['RETRODEBIAN_FAKE_LEGACY_TOOLS'] = os.environ.get('RETRODEBIAN_FAKE_LEGACY_TOOLS', '1')
|
||||
write_env_file(Path(args.output), values)
|
||||
@@ -133,6 +110,7 @@ def cmd_validate(args: argparse.Namespace) -> int:
|
||||
for profile_name in list_profiles(root / 'profiles'):
|
||||
profile = load_profile(root, profile_name)
|
||||
load_base_spec(root, profile.base)
|
||||
load_base_chain(root, profile.base)
|
||||
for feature_name in profile.features:
|
||||
load_feature_spec(root, feature_name)
|
||||
print('Validation OK')
|
||||
@@ -152,26 +130,11 @@ def cmd_list(args: argparse.Namespace) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def _load_module_spec(root: Path, kind: str, name: str):
|
||||
if kind == 'base':
|
||||
return load_base_spec(root, name)
|
||||
if kind == 'feature':
|
||||
return load_feature_spec(root, name)
|
||||
raise ValueError(kind)
|
||||
|
||||
|
||||
def _docker_override_field(spec, phase: str, field: str) -> str:
|
||||
stage = spec.docker_overrides.get(phase)
|
||||
if stage is None:
|
||||
return ''
|
||||
value = getattr(stage, field)
|
||||
return value or ''
|
||||
|
||||
|
||||
def cmd_module_docker(args: argparse.Namespace) -> int:
|
||||
root = root_dir()
|
||||
spec = _load_module_spec(root, args.kind, args.name)
|
||||
print(_docker_override_field(spec, args.phase, args.field))
|
||||
spec = load_base_spec(root, args.name) if args.kind == 'base' else load_feature_spec(root, args.name)
|
||||
stage = spec.docker_overrides.get(args.phase)
|
||||
print(getattr(stage, args.field) if stage is not None and getattr(stage, args.field) else '')
|
||||
return 0
|
||||
|
||||
|
||||
@@ -181,8 +144,8 @@ def cmd_profile_info(args: argparse.Namespace) -> int:
|
||||
if args.field == 'base':
|
||||
print(profile.base)
|
||||
elif args.field == 'base-chain':
|
||||
for base_spec in load_base_chain(root, profile.base):
|
||||
print(base_spec.name)
|
||||
for name, _spec in load_base_chain(root, profile.base):
|
||||
print(name)
|
||||
elif args.field == 'features':
|
||||
for feature in profile.features:
|
||||
print(feature)
|
||||
@@ -199,16 +162,16 @@ def cmd_prepare_profile(args: argparse.Namespace) -> int:
|
||||
live_dir = root / 'live'
|
||||
clear_directory_contents(live_dir)
|
||||
ensure_live_structure(live_dir)
|
||||
save_profile_metadata(profile_artifacts_dir(root, profile.name) / 'profile.json', profile, base, base_chain)
|
||||
apply_profile_common_configuration(root, live_dir, profile)
|
||||
save_profile_metadata(profile_artifacts_dir(root, args.profile) / 'profile.json', args.profile, profile, profile.base, base, base_chain)
|
||||
apply_profile_common_configuration(root, live_dir, args.profile, profile)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_save_feature_metadata(args: argparse.Namespace) -> int:
|
||||
root = root_dir()
|
||||
feature = load_feature_spec(root, args.feature)
|
||||
target = profile_artifacts_dir(root, args.profile) / 'features' / f'{feature.name}.json'
|
||||
save_feature_metadata(target, feature)
|
||||
target = profile_artifacts_dir(root, args.profile) / 'features' / f'{args.feature}.json'
|
||||
save_feature_metadata(target, args.feature, feature)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -217,8 +180,8 @@ def cmd_inject_resources(args: argparse.Namespace) -> int:
|
||||
live_dir = root / 'live'
|
||||
ensure_live_structure(live_dir)
|
||||
if args.kind == 'base':
|
||||
for base_spec in load_base_chain(root, args.name):
|
||||
inject_module_resources(base_dir(root, base_spec.name), live_dir, base_spec.name)
|
||||
for base_name, _base_spec in load_base_chain(root, args.name):
|
||||
inject_module_resources(base_dir(root, base_name), live_dir, base_name)
|
||||
else:
|
||||
inject_module_resources(feature_dir(root, args.name), live_dir, args.name)
|
||||
return 0
|
||||
@@ -227,7 +190,7 @@ def cmd_inject_resources(args: argparse.Namespace) -> int:
|
||||
def cmd_profile_common(args: argparse.Namespace) -> int:
|
||||
root = root_dir()
|
||||
profile = load_profile(root, args.profile)
|
||||
apply_profile_common_configuration(root, root / 'live', profile)
|
||||
apply_profile_common_configuration(root, root / 'live', args.profile, profile)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -268,11 +231,12 @@ def cmd_run_local(args: argparse.Namespace) -> int:
|
||||
env, _ = _env_and_path(root, 'feature', 'post-gen', args.profile, feature=feature_name)
|
||||
_run([sys.executable, str(feature_dir(root, feature_name) / 'entry.py'), 'post-gen'], env=env)
|
||||
|
||||
env, env_path = _env_and_path(root, 'base', 'pre-gen', args.profile, base=profile.base)
|
||||
_run([sys.executable, str(base_dir(root, profile.base) / 'entry.py'), 'pre-gen'], env=env)
|
||||
_run([str(root / 'builder' / 'bash' / 'run_generate.sh'), str(base_dir(root, profile.base)), str(env_path)])
|
||||
env, _ = _env_and_path(root, 'base', 'post-gen', args.profile, base=profile.base)
|
||||
_run([sys.executable, str(base_dir(root, profile.base) / 'entry.py'), 'post-gen'], env=env)
|
||||
for base_name, _base_spec in load_base_chain(root, profile.base):
|
||||
env, env_path = _env_and_path(root, 'base', 'pre-gen', args.profile, base=base_name)
|
||||
_run([sys.executable, str(base_dir(root, base_name) / 'entry.py'), 'pre-gen'], env=env)
|
||||
_run([str(root / 'builder' / 'bash' / 'run_generate.sh'), str(base_dir(root, base_name)), str(env_path)])
|
||||
env, _ = _env_and_path(root, 'base', 'post-gen', args.profile, base=base_name)
|
||||
_run([sys.executable, str(base_dir(root, base_name) / 'entry.py'), 'post-gen'], env=env)
|
||||
|
||||
_run([sys.executable, str(root / 'builder' / 'py' / 'build.py'), 'prepare-profile', '--profile', args.profile])
|
||||
env, env_path = _env_and_path(root, 'profile', 'config', args.profile)
|
||||
@@ -322,22 +286,22 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
p.set_defaults(func=cmd_profile_info)
|
||||
|
||||
p = sub.add_parser('module-docker')
|
||||
p.add_argument('--kind', choices=['base', 'feature'], required=True)
|
||||
p.add_argument('--kind', required=True, choices=['base', 'feature'])
|
||||
p.add_argument('--name', required=True)
|
||||
p.add_argument('--phase', required=True)
|
||||
p.add_argument('field', choices=['image', 'dockerfile', 'docker_context'])
|
||||
p.set_defaults(func=cmd_module_docker)
|
||||
|
||||
p = sub.add_parser('run-python-phase')
|
||||
p.add_argument('--kind', choices=['base', 'feature'], required=True)
|
||||
p.add_argument('--kind', required=True, choices=['base', 'feature'])
|
||||
p.add_argument('--phase', required=True)
|
||||
p.add_argument('--profile')
|
||||
p.add_argument('--base')
|
||||
p.add_argument('--feature')
|
||||
p.add_argument('--profile', default='')
|
||||
p.add_argument('--base', default='')
|
||||
p.add_argument('--feature', default='')
|
||||
p.set_defaults(func=run_python_phase)
|
||||
|
||||
p = sub.add_parser('export-env')
|
||||
p.add_argument('--kind', choices=['profile', 'base', 'feature'], required=True)
|
||||
p.add_argument('--kind', required=True, choices=['profile', 'base', 'feature'])
|
||||
p.add_argument('--phase', required=True)
|
||||
p.add_argument('--profile', default='')
|
||||
p.add_argument('--base', default='')
|
||||
@@ -355,7 +319,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
p.set_defaults(func=cmd_save_feature_metadata)
|
||||
|
||||
p = sub.add_parser('inject-resources')
|
||||
p.add_argument('--kind', choices=['base', 'feature'], required=True)
|
||||
p.add_argument('--kind', required=True, choices=['base', 'feature'])
|
||||
p.add_argument('--name', required=True)
|
||||
p.set_defaults(func=cmd_inject_resources)
|
||||
|
||||
@@ -381,7 +345,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
def main() -> int:
|
||||
parser = build_parser()
|
||||
args = parser.parse_args()
|
||||
return args.func(args)
|
||||
return int(args.func(args))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -13,15 +13,12 @@ class BuildContext:
|
||||
phase: str
|
||||
current_kind: str
|
||||
current_name: str
|
||||
current_module_dir: Path
|
||||
current_module_artifact_dir: Path
|
||||
profile_name: str = ''
|
||||
profile_artifact_dir: Path | None = None
|
||||
base_name: str = ''
|
||||
base_dir: Path | None = None
|
||||
base_artifact_dir: Path | None = None
|
||||
feature_name: str = ''
|
||||
feature_dir: Path | None = None
|
||||
feature_artifact_dir: Path | None = None
|
||||
profile_features: tuple[str, ...] = ()
|
||||
|
||||
@@ -33,7 +30,6 @@ class BuildContext:
|
||||
'PHASE': self.phase,
|
||||
'CURRENT_KIND': self.current_kind,
|
||||
'CURRENT_NAME': self.current_name,
|
||||
'CURRENT_MODULE_DIR': str(self.current_module_dir),
|
||||
'CURRENT_MODULE_ARTIFACT_DIR': str(self.current_module_artifact_dir),
|
||||
'PROFILE_NAME': self.profile_name,
|
||||
'BASE_NAME': self.base_name,
|
||||
@@ -42,12 +38,8 @@ class BuildContext:
|
||||
}
|
||||
if self.profile_artifact_dir is not None:
|
||||
env['PROFILE_ARTIFACT_DIR'] = str(self.profile_artifact_dir)
|
||||
if self.base_dir is not None:
|
||||
env['BASE_DIR'] = str(self.base_dir)
|
||||
if self.base_artifact_dir is not None:
|
||||
env['BASE_ARTIFACT_DIR'] = str(self.base_artifact_dir)
|
||||
if self.feature_dir is not None:
|
||||
env['FEATURE_DIR'] = str(self.feature_dir)
|
||||
if self.feature_artifact_dir is not None:
|
||||
env['FEATURE_ARTIFACT_DIR'] = str(self.feature_artifact_dir)
|
||||
return env
|
||||
@@ -66,15 +58,12 @@ class BuildContext:
|
||||
phase=env['PHASE'],
|
||||
current_kind=env['CURRENT_KIND'],
|
||||
current_name=env['CURRENT_NAME'],
|
||||
current_module_dir=Path(env['CURRENT_MODULE_DIR']),
|
||||
current_module_artifact_dir=Path(env['CURRENT_MODULE_ARTIFACT_DIR']),
|
||||
profile_name=env.get('PROFILE_NAME', ''),
|
||||
profile_artifact_dir=p('PROFILE_ARTIFACT_DIR'),
|
||||
base_name=env.get('BASE_NAME', ''),
|
||||
base_dir=p('BASE_DIR'),
|
||||
base_artifact_dir=p('BASE_ARTIFACT_DIR'),
|
||||
feature_name=env.get('FEATURE_NAME', ''),
|
||||
feature_dir=p('FEATURE_DIR'),
|
||||
feature_artifact_dir=p('FEATURE_ARTIFACT_DIR'),
|
||||
profile_features=features,
|
||||
)
|
||||
|
||||
@@ -42,8 +42,8 @@ def load_base_spec(root: Path, name: str) -> BaseSpec:
|
||||
return spec
|
||||
|
||||
|
||||
def load_base_chain(root: Path, name: str) -> list[BaseSpec]:
|
||||
chain: list[BaseSpec] = []
|
||||
def load_base_chain(root: Path, name: str) -> list[tuple[str, BaseSpec]]:
|
||||
chain: list[tuple[str, BaseSpec]] = []
|
||||
seen: set[str] = set()
|
||||
current = name
|
||||
while current:
|
||||
@@ -51,7 +51,7 @@ def load_base_chain(root: Path, name: str) -> list[BaseSpec]:
|
||||
raise RuntimeError(f'Base inheritance loop detected at {current}')
|
||||
seen.add(current)
|
||||
spec = load_base_spec(root, current)
|
||||
chain.append(spec)
|
||||
chain.append((current, spec))
|
||||
current = spec.parent or ''
|
||||
chain.reverse()
|
||||
return chain
|
||||
|
||||
@@ -4,16 +4,6 @@ from dataclasses import dataclass, field, asdict
|
||||
from typing import Any
|
||||
|
||||
|
||||
def _tuple(values: Any) -> tuple[str, ...]:
|
||||
if values is None:
|
||||
return ()
|
||||
if isinstance(values, tuple):
|
||||
return values
|
||||
if isinstance(values, list):
|
||||
return tuple(str(v) for v in values)
|
||||
raise TypeError(f'Expected list/tuple/None, got {type(values)!r}')
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DockerStageSpec:
|
||||
image: str | None = None
|
||||
@@ -59,13 +49,10 @@ def _docker_overrides(values: Any) -> dict[str, DockerStageSpec]:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ModuleSpec:
|
||||
title: str = ''
|
||||
description: str = ''
|
||||
docker_overrides: dict[str, DockerStageSpec] = field(default_factory=dict)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
object.__setattr__(self, 'packages', _tuple(self.packages))
|
||||
object.__setattr__(self, 'package_lists', _tuple(self.package_lists))
|
||||
object.__setattr__(self, 'docker_overrides', _docker_overrides(self.docker_overrides))
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
@@ -86,7 +73,6 @@ class FeatureSpec(ModuleSpec):
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ProfileSpec:
|
||||
title: str = ''
|
||||
base: str
|
||||
features: tuple[str, ...] = field(default_factory=tuple)
|
||||
edition: str = ''
|
||||
@@ -94,7 +80,10 @@ class ProfileSpec:
|
||||
splash: str | None = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
object.__setattr__(self, 'features', _tuple(self.features))
|
||||
if isinstance(self.features, list):
|
||||
object.__setattr__(self, 'features', tuple(str(v) for v in self.features))
|
||||
elif not isinstance(self.features, tuple):
|
||||
raise TypeError('ProfileSpec.features must be list or tuple')
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return asdict(self)
|
||||
|
||||
@@ -59,24 +59,36 @@ def save_json(path: Path, payload: dict) -> None:
|
||||
path.write_text(json.dumps(payload, indent=2, sort_keys=True) + '\n', encoding='utf-8')
|
||||
|
||||
|
||||
def save_profile_metadata(path: Path, profile: ProfileSpec, base: BaseSpec, base_chain: list[BaseSpec] | None = None) -> None:
|
||||
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': [item.to_dict() for item in (base_chain or [base])],
|
||||
'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: FeatureSpec) -> None:
|
||||
save_json(path, feature.to_dict())
|
||||
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: ProfileSpec) -> None:
|
||||
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'profile={profile_name}',
|
||||
f'base={profile.base}',
|
||||
f'features={"|".join(profile.features)}',
|
||||
]
|
||||
|
||||
@@ -15,12 +15,8 @@ from retrobuilder.entrypoints import FeatureEntry, cli_dispatch
|
||||
from retrobuilder.model import FeatureSpec
|
||||
|
||||
SPEC = FeatureSpec(
|
||||
name='sample-feature',
|
||||
description='Sample feature used to validate the V2 builder flow.',
|
||||
packages=('sample-feature-package',),
|
||||
package_lists=('sample-feature.list',),
|
||||
docker_overrides={
|
||||
# Example: override the generate phase with a custom Etch image or Dockerfile.
|
||||
# 'pre-gen': {'image': 'python:3.11-alpine'},
|
||||
# 'post-gen': {'dockerfile': 'features/sample-feature/Dockerfile.python'},
|
||||
# 'pre-inj': {'image': 'retrodebian/custom-lenny:latest'},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from retrobuilder.model import ProfileSpec
|
||||
|
||||
PROFILE = ProfileSpec(
|
||||
name='demo',
|
||||
base='sample-base',
|
||||
features=('sample-feature',),
|
||||
edition='Demo',
|
||||
|
||||
Reference in New Issue
Block a user