recipe-generator: Update to new template structure with install and live templates

- Replaced individual templates with unified 'install' (desktop, server, hypervisor) and 'live' (live-desktop, live-server) templates

- Added new modifiers: variant_type, hypervisor-type, desktop, initial-setup, virtualization

- Updated generate_recipe.py to handle new modifier structure with additive flags

- Updated recipes_manifest.yaml with new modifier structure

- Added missing fragment files and directories
This commit is contained in:
Lukas Greve
2026-03-25 19:15:32 +01:00
parent 3782777058
commit 520657dcee
35 changed files with 465 additions and 532 deletions
+1
View File
@@ -16,6 +16,7 @@ install-deps:
pip install -r requirements.txt
generate-recipes:
rm -f ../recipes/*.cfg
python generate_recipe.py \
--manifest recipes_manifest.yaml \
--output-dir ../recipes/
+121 -30
View File
@@ -136,17 +136,32 @@ class RecipeGenerator:
for opt_key, opt_config in template.get('optional', {}).items():
if isinstance(opt_config, dict):
for value, fragment_path in opt_config.items():
if fragment_path.startswith('fragments/'):
full_path = self.project_root / fragment_path
elif fragment_path is None:
# Skip None values
if fragment_path is None:
continue
# Handle lists
if isinstance(fragment_path, list):
for fp in fragment_path:
if fp is None:
continue
if fp.startswith('fragments/'):
full_path = self.project_root / fp
else:
full_path = self.ingredients_dir / f"{fp}.cfg"
if not full_path.exists():
errors.append(f"Optional fragment not found: {fp} (in list for {opt_key}={value})")
else:
full_path = self.ingredients_dir / f"{fragment_path}.cfg"
if not full_path.exists():
errors.append(f"Optional fragment not found: {fragment_path} (for {opt_key}={value})")
if fragment_path.startswith('fragments/'):
full_path = self.project_root / fragment_path
else:
full_path = self.ingredients_dir / f"{fragment_path}.cfg"
if not full_path.exists():
errors.append(f"Optional fragment not found: {fragment_path} (for {opt_key}={value})")
elif isinstance(opt_config, list):
for fragment_path in opt_config:
if fragment_path is None:
continue
if fragment_path.startswith('fragments/'):
full_path = self.project_root / fragment_path
else:
@@ -156,7 +171,6 @@ class RecipeGenerator:
errors.append(f"Optional fragment not found: {fragment_path} (in list)")
return errors
def validate_manifest(self, manifest: Dict) -> List[str]:
"""Validate manifest structure."""
errors = []
@@ -175,6 +189,11 @@ class RecipeGenerator:
for variant in recipe_config['variants']:
if 'version' not in variant:
errors.append(f"Recipe '{recipe_config['name']}' variant missing 'version'")
# Support explicit variant name for install variants
if 'name' in variant:
variant_subname = variant['name']
else:
variant_subname = ''
return errors
@@ -238,27 +257,86 @@ class RecipeGenerator:
for opt_key, opt_config in template.get('optional', {}).items():
if opt_key in modifiers:
value = modifiers[opt_key]
if isinstance(opt_config, dict):
# Case 1: opt_config is nested dict (e.g., virtualization, variant_type)
# and value is string/int (select from options)
if isinstance(opt_config, dict) and not isinstance(value, (dict, list)):
if value in opt_config:
fragment_path = opt_config[value]
if fragment_path not in seen:
if isinstance(fragment_path, list):
for fp in fragment_path:
if fp is not None and fp not in seen:
includes.append(f"%ksappend {fp}")
seen.add(fp)
elif fragment_path and fragment_path not in seen:
includes.append(f"%ksappend {fragment_path}")
seen.add(fragment_path)
# Case 2: opt_config is nested dict (e.g., virtualization)
# and value is dict (nested structure)
elif isinstance(opt_config, dict) and isinstance(value, dict):
for nested_key in value:
if nested_key in opt_config:
nested_value = opt_config[nested_key]
if isinstance(nested_value, list):
for fp in nested_value:
if fp is not None and fp not in seen:
includes.append(f"%ksappend {fp}")
seen.add(fp)
elif nested_value is not None and nested_value not in seen:
includes.append(f"%ksappend {nested_value}")
seen.add(nested_value)
# Case 3: opt_config is nested dict, value is boolean (additive)
elif isinstance(opt_config, dict) and isinstance(value, bool) and value:
for nested_key, nested_value in opt_config.items():
if isinstance(nested_value, list):
for fp in nested_value:
if fp is not None and fp not in seen:
includes.append(f"%ksappend {fp}")
seen.add(fp)
elif nested_value is not None and nested_value not in seen:
includes.append(f"%ksappend {nested_value}")
seen.add(nested_value)
# Case 4: opt_config is list, value is boolean (boolean flag)
elif isinstance(opt_config, list) and value is True:
for fragment_path in opt_config:
if fragment_path not in seen:
if fragment_path is not None and fragment_path not in seen:
includes.append(f"%ksappend {fragment_path}")
seen.add(fragment_path)
# Handle special modifiers (CPU, GPU)
# Handle modifiers section
for mod_key, mod_value in modifiers.items():
if mod_key in template.get('modifiers', {}):
mod_config = template['modifiers'][mod_key]
if isinstance(mod_config, dict) and mod_value in mod_config:
fragment_path = mod_config[mod_value]
if fragment_path and fragment_path not in seen:
includes.append(f"%ksappend {fragment_path}")
seen.add(fragment_path)
# Handle nested dict modifiers
if isinstance(mod_config, dict) and isinstance(mod_value, str):
if mod_value in mod_config:
fragment_path = mod_config[mod_value]
if isinstance(fragment_path, list):
for fp in fragment_path:
if fp is not None and fp not in seen:
includes.append(f"%ksappend {fp}")
seen.add(fp)
elif fragment_path and fragment_path not in seen:
includes.append(f"%ksappend {fragment_path}")
seen.add(fragment_path)
# Handle list modifiers
elif isinstance(mod_config, dict) and isinstance(mod_value, list):
for item in mod_value:
if item in mod_config:
fragment_path = mod_config[item]
if isinstance(fragment_path, list):
for fp in fragment_path:
if fp is not None and fp not in seen:
includes.append(f"%ksappend {fp}")
seen.add(fp)
elif fragment_path and fragment_path not in seen:
includes.append(f"%ksappend {fragment_path}")
seen.add(fragment_path)
return includes
@@ -380,14 +458,20 @@ class RecipeGenerator:
def generate_filename(self, recipe_type: str, version: str, **modifiers) -> str:
"""Generate recipe filename from parameters."""
# Map modifiers to filename components
# Extract variant subname if present
variant_subname = modifiers.get('variant_subname', '')
# Build base parts
parts = [recipe_type.replace('_', '-')]
# Add CPU/GPU first (hypervisors)
if modifiers.get('cpu') and modifiers.get('cpu') != 'generic':
parts.append(modifiers['cpu'])
if modifiers.get('gpu') and modifiers.get('gpu') != 'none':
parts.append(modifiers['gpu'])
# Add variant subname for install variants (desktop, server, hypervisor)
if variant_subname and variant_subname in ['desktop', 'server', 'hypervisor']:
parts.append(variant_subname)
# Add hypervisor-type (list, first type only for filename)
if modifiers.get('hypervisor-type') and isinstance(modifiers['hypervisor-type'], list):
types = modifiers['hypervisor-type']
parts.extend(types)
# Add desktop (non-GNOME only, since GNOME is default)
if modifiers.get('desktop') and modifiers['desktop'] != 'gnome':
@@ -396,10 +480,6 @@ class RecipeGenerator:
# Add version
parts.append(str(version))
# Add hypervisor suffix (only when hypervisor is enabled)
if modifiers.get('hypervisor'):
parts.append('hypervisor')
# Add security suffix (devel only, since secure is default)
if modifiers.get('security') == 'devel':
parts.append('devel')
@@ -450,6 +530,7 @@ def main():
help='Fedora version (default: rawhide)')
parser.add_argument('--desktop',
choices=['gnome', 'labwc'],
default='gnome',
help='Desktop environment (default: gnome)')
parser.add_argument('--storage',
choices=['standard', 'encrypted'],
@@ -571,7 +652,16 @@ def main():
for variant in recipe_config.get('variants', []):
version = variant['version']
modifiers = {k: v for k, v in variant.items() if k not in ['version']}
# Build modifiers dict (exclude 'name', 'version')
modifiers = {k: v for k, v in variant.items() if k not in ['name', 'version']}
# Extract subname (variant name) if present, otherwise empty
variant_subname = variant.get('name', '')
# Use variant_name as variant_type modifier
if variant_subname:
modifiers['variant_type'] = variant_subname
# Add variant_subname to modifiers for generate_filename
if variant_subname:
modifiers['variant_subname'] = variant_subname
content = generator.generate_recipe(recipe_type, version, **modifiers)
@@ -600,7 +690,8 @@ def main():
# Single generation mode
if args.type:
modifiers = {
'desktop': args.desktop if args.desktop and args.desktop != 'gnome' else None,
'variant_type': 'desktop',
'desktop': args.desktop if args.desktop else None,
'storage': args.storage if args.storage != 'standard' else None,
'security': args.security if args.security != 'secure' else None,
'cpu': args.cpu if args.cpu and args.cpu != 'generic' else None,
+50 -139
View File
@@ -4,183 +4,94 @@
# Fragment paths use relative paths from project root
templates:
# Virtual desktop recipe
# Modifiers: desktop (gnome|labwc), storage (standard|encrypted),
# security (secure|devel), version (43|rawhide), post (true|false)
virtual-desktop:
description: "A recipe for a virtual desktop"
# Install recipe - for desktop, server, or hypervisor
install:
description: "An install recipe for desktop, server, or hypervisor"
base: core
required:
- core: fragments/shared/core/base.ks
- storage: fragments/shared/storage/standard.ks
- bootloader: fragments/platform/generic-43/bootloader/grub.ks
- bootloader: fragments/shared/bootloader/grub.ks
- locale: fragments/shared/core/locale.ks
- services: fragments/shared/core/services.ks
- network: fragments/shared/core/network.ks
- packages: fragments/shared/packages/core-group.ks
- fedora-remix: fragments/shared/packages/fedora-remix.ks
- hand-picked: fragments/shared/packages/hand-picked.ks
- initial-setup: fragments/shared/initial-setup/server/config.ks
optional:
security:
secure: fragments/shared/core/security/enabled.ks
devel: fragments/shared/core/security/disabled.ks
hardware-support: fragments/shared/packages/hardware-support.ks
variant_type:
desktop:
- fragments/shared/desktop/gnome/packages.ks
- fragments/shared/desktop/gnome/post-scripts.ks
server:
hypervisor:
- fragments/shared/hypervisor/base/packages.ks
- fragments/shared/hypervisor/base/services.ks
- fragments/shared/hypervisor/base/post-scripts.ks
- fragments/platform/generic-rawhide/repo/rawhide-mirrors.ks
- fragments/shared/packages/virtual-machine-manager/packages.ks
- fragments/shared/packages/virtual-machine-manager/post-scripts.ks
- fragments/shared/guest-agents/packages.ks
modifiers:
version:
"43": fragments/platform/generic-43/repo/fedora-mirrors.ks
"rawhide": fragments/platform/generic-rawhide/repo/rawhide-mirrors.ks
storage:
standard: fragments/shared/storage/standard.ks
encrypted: fragments/shared/storage/encrypted.ks
bootloader:
grub: fragments/shared/bootloader/grub.ks
systemd-boot: fragments/shared/bootloader/systemd-boot.ks
desktop:
gnome: fragments/shared/desktop/gnome/packages.ks
labwc: fragments/shared/desktop/labwc/config.ks
post: fragments/shared/section-data/post/base.ks
extras:
- fragments/shared/guest-agents/packages.ks
modifiers:
storage:
standard: fragments/shared/storage/standard.ks
encrypted: fragments/shared/storage/encrypted.ks
bootloader:
systemd-boot: fragments/platform/generic-43/bootloader/systemd-boot.ks
# Virtual server recipe
# Modifiers: security (secure|devel), version (43|rawhide), post (true|false)
virtual-server:
description: "A recipe for a virtual server"
base: core
required:
- core: fragments/shared/core/base.ks
- storage: fragments/shared/storage/standard.ks
- bootloader: fragments/platform/generic-43/bootloader/grub.ks
- locale: fragments/shared/core/locale.ks
- services: fragments/shared/core/services.ks
- network: fragments/shared/core/network.ks
- packages: fragments/shared/packages/core-group.ks
- fedora-remix: fragments/shared/packages/fedora-remix.ks
- hand-picked: fragments/shared/packages/hand-picked.ks
- initial-setup: fragments/shared/initial-setup/server/config.ks
optional:
gnome:
- fragments/shared/desktop/gnome/config.ks
- fragments/shared/desktop/gnome/packages.ks
- fragments/shared/desktop/gnome/post-scripts.ks
labwc:
- fragments/shared/desktop/labwc/config.ks
security:
secure: fragments/shared/core/security/enabled.ks
devel: fragments/shared/core/security/disabled.ks
version:
"43": fragments/platform/generic-43/repo/fedora-mirrors.ks
"rawhide": fragments/platform/generic-rawhide/repo/rawhide-mirrors.ks
post: fragments/shared/section-data/post/base.ks
extras:
- fragments/shared/guest-agents/packages.ks
modifiers:
storage:
standard: fragments/shared/storage/standard.ks
encrypted: fragments/shared/storage/encrypted.ks
bootloader:
systemd-boot: fragments/platform/generic-43/bootloader/systemd-boot.ks
# Desktop hypervisor recipe
# Modifiers: cpu (generic|amdcpu|intelcpu), gpu (none|intelgpu),
# security (secure|devel), version (rawhide), post (true|false)
desktop-hypervisor:
description: "A recipe for a desktop hypervisor"
base: core
required:
- core: fragments/shared/core/base.ks
- storage: fragments/shared/storage/standard.ks
- bootloader: fragments/platform/generic-rawhide/bootloader/grub.ks
- locale: fragments/shared/core/locale.ks
- services: fragments/shared/core/services.ks
- network: fragments/shared/core/network.ks
- packages: fragments/shared/packages/core-group.ks
- fedora-remix: fragments/shared/packages/fedora-remix.ks
- hand-picked: fragments/shared/packages/hand-picked.ks
- hardware-support: fragments/shared/packages/hardware-support.ks
- initial-setup: fragments/shared/initial-setup/desktop/config.ks
- desktop: fragments/shared/desktop/gnome/config.ks
- desktop-gnome-packages: fragments/shared/desktop/gnome/packages.ks
- desktop-gnome-post: fragments/shared/desktop/gnome/post-scripts.ks
- vmm: fragments/shared/desktop/vmm/packages.ks
- vmm-post: fragments/shared/desktop/vmm/post-scripts.ks
- repo: fragments/platform/generic-rawhide/repo/rawhide-mirrors.ks
- hypervisor-base-services: fragments/shared/hypervisor/base/services.ks
- hypervisor-base-packages: fragments/shared/hypervisor/base/packages.ks
- hypervisor-base-post: fragments/shared/hypervisor/base/post-scripts.ks
optional:
security:
secure: fragments/shared/core/security/enabled.ks
devel: fragments/shared/core/security/disabled.ks
cpu:
generic: fragments/shared/hypervisor/base/services.ks
initial-setup:
server: fragments/shared/initial-setup/server/config.ks
desktop: fragments/shared/initial-setup/desktop/config.ks
hypervisor-type:
amdcpu: fragments/shared/hypervisor/amdcpu.ks
intelcpu: fragments/shared/hypervisor/intelcpu.ks
gpu:
intelgpu: fragments/shared/hypervisor/intelgpu.ks
post: fragments/shared/section-data/post/base.ks
modifiers:
cpu:
generic: fragments/shared/hypervisor/base/services.ks
amdcpu: fragments/shared/hypervisor/amdcpu.ks
intelcpu: fragments/shared/hypervisor/intelcpu.ks
gpu:
none: null
intelgpu: fragments/shared/hypervisor/intelgpu.ks
storage:
standard: fragments/shared/storage/standard.ks
encrypted: fragments/shared/storage/encrypted.ks
# Live desktop recipe
# Modifiers: desktop (gnome|none), security (secure|devel), version (rawhide)
live-desktop:
description: "A recipe for a live desktop"
# Live recipe - for live-desktop or live-server
live:
description: "A live recipe for live-desktop or live-server"
base: live-core
required:
- live-core: fragments/shared/live/core/base.ks
- storage: fragments/shared/live/core/storage.ks
- bootloader: fragments/platform/generic-rawhide/bootloader/grub.ks
- bootloader: fragments/shared/bootloader/grub.ks
- locale: fragments/shared/core/locale.ks
- services: fragments/shared/core/services.ks
- network: fragments/shared/core/network.ks
- packages: fragments/shared/live/core/packages.ks
- mandatory: fragments/shared/live/core/packages.ks
- post: fragments/shared/live/post/base.ks
- session: fragments/shared/live/post/session.ks
- initial-setup: fragments/shared/initial-setup/desktop/config.ks
- desktop: fragments/shared/desktop/gnome/config.ks
- desktop-gnome-packages: fragments/shared/desktop/gnome/packages.ks
- desktop-gnome-post: fragments/shared/desktop/gnome/post-scripts.ks
- repo: fragments/platform/generic-rawhide/repo/rawhide-mirrors.ks
optional:
variant_type:
desktop:
- fragments/shared/desktop/gnome/packages.ks
server:
security:
secure: fragments/shared/core/security/enabled.ks
devel: fragments/shared/core/security/disabled.ks
packages-hw: fragments/shared/packages/hardware-support.ks
extras: fragments/shared/guest-agents/packages.ks
modifiers:
storage:
standard: fragments/shared/live/core/storage.ks
encrypted: fragments/shared/live/core/storage.ks
# Live server recipe
# Modifiers: security (secure|devel), version (rawhide), hypervisor (true|false)
live-server:
description: "A recipe for a live server"
base: live-core
required:
- live-core: fragments/shared/live/core/base.ks
- storage: fragments/shared/live/core/storage.ks
- bootloader: fragments/platform/generic-rawhide/bootloader/grub.ks
- locale: fragments/shared/core/locale.ks
- services: fragments/shared/core/services.ks
- network: fragments/shared/core/network.ks
- packages: fragments/shared/live/core/packages.ks
- mandatory: fragments/shared/live/core/packages.ks
- post: fragments/shared/live/post/base.ks
- session: fragments/shared/live/post/session.ks
- initial-setup: fragments/shared/initial-setup/server/config.ks
- repo: fragments/platform/generic-rawhide/repo/rawhide-mirrors.ks
optional:
security:
secure: fragments/shared/core/security/enabled.ks
devel: fragments/shared/core/security/disabled.ks
packages-hw: fragments/shared/packages/hardware-support.ks
hardware-support: fragments/shared/packages/hardware-support.ks
hypervisor: fragments/shared/live/hypervisor.ks
modifiers:
version:
"43": fragments/platform/generic-43/repo/fedora-mirrors.ks
"rawhide": fragments/platform/generic-rawhide/repo/rawhide-mirrors.ks
storage:
standard: fragments/shared/live/core/storage.ks
encrypted: fragments/shared/live/core/storage.ks
bootloader:
grub: fragments/shared/bootloader/grub.ks
systemd-boot: fragments/shared/bootloader/systemd-boot.ks
+97 -56
View File
@@ -3,85 +3,126 @@
# Edit this file to add new variants, then run: make generate-recipes
recipes:
# Virtual Desktop variants
- name: virtual-desktop
# Install variants - desktop
- name: install
variants:
- version: 43
- name: desktop
version: 43
desktop: gnome
storage: standard
bootloader: grub
security: secure
extras: true
- version: 43
hardware-support: true
initial-setup: server
- name: desktop
version: 43
desktop: gnome
storage: standard
bootloader: grub
security: devel
extras: true
- version: 43
hardware-support: true
initial-setup: server
- name: desktop
version: 43
desktop: labwc
storage: standard
bootloader: grub
security: secure
extras: true
- version: rawhide
hardware-support: true
initial-setup: server
- name: desktop
version: rawhide
desktop: gnome
storage: standard
bootloader: grub
security: secure
extras: true
- version: rawhide
hardware-support: true
initial-setup: server
- name: desktop
version: rawhide
desktop: gnome
storage: encrypted
bootloader: grub
security: secure
extras: true
hardware-support: true
initial-setup: server
# Virtual Server variants
- name: virtual-server
# Install variants - server (minimal, no desktop packages)
- name: install
variants:
- version: 43
- name: server
version: 43
storage: standard
bootloader: grub
security: secure
extras: true
post: true
- version: 43
hardware-support: true
initial-setup: server
- name: server
version: 43
storage: standard
bootloader: grub
security: devel
extras: true
post: false
- version: rawhide
hardware-support: true
initial-setup: server
- name: server
version: rawhide
storage: standard
bootloader: grub
security: secure
extras: true
post: true
- version: rawhide
hardware-support: true
initial-setup: server
- name: server
version: rawhide
storage: standard
bootloader: grub
security: devel
extras: true
post: false
hardware-support: true
initial-setup: server
# Desktop Hypervisor variants
- name: desktop-hypervisor
# Install variants - hypervisor
- name: install
variants:
- version: rawhide
- name: hypervisor
version: rawhide
storage: standard
bootloader: grub
security: secure
- version: rawhide
cpu: amdcpu
security: secure
- version: rawhide
cpu: intelcpu
security: secure
- version: rawhide
cpu: intelcpu
gpu: intelgpu
security: secure
# Live Desktop variants
- name: live-desktop
variants:
- version: rawhide
security: secure
packages-hw: true
# Live Server variants
- name: live-server
variants:
- version: rawhide
security: secure
packages-hw: true
- version: rawhide
security: secure
packages-hw: true
hardware-support: true
hypervisor: true
hypervisor-type:
- amdcpu
- name: hypervisor
version: rawhide
storage: standard
bootloader: grub
security: secure
hardware-support: true
hypervisor: true
hypervisor-type:
- intelcpu
- name: hypervisor
version: rawhide
storage: standard
bootloader: grub
security: secure
hardware-support: true
hypervisor: true
hypervisor-type:
- intelcpu
- intelgpu
# Live variants - desktop
- name: live
variants:
- name: desktop
version: rawhide
security: secure
hardware-support: true
# Live variants - server
- name: live
variants:
- name: server
version: rawhide
security: secure
hardware-support: true