Skip to content

Abstract import and custom config for enhance kernel customisation experience. #4430

@guidryheal-create

Description

@guidryheal-create

describe the request

Core Objectives:

  1. Abstract Imports and Profiles: Create a unified, abstract way to import and use application profiles dynamically based on metadata. This allows easy addition of new configuration, bumble of application, modules without modifying core logic.

  2. Automated Configuration Script Parsing: Implement a system where a configuration script can automatically parse and generate classes based on profiles and application bundles. This would enable more customization in creating installation profiles.

  3. Modular Application Menu: Refactor the application menu logic to support automatic inclusion of items based on available configurations. This would make the installer more flexible and adaptable.

  4. Use of Data Classes and Type Safety: Implement type-checking with data classes to ensure configuration values are validated and safe. If a value doesn't meet the expected format or constraints, warnings can be generated.


Refactored Plan

1. Abstract Imports and Configuration Handling

To make it easy to import and manage all available profiles and configuration options, we should implement a centralized module that handles the import logic dynamically.

Changes to be made:

  • Refactor __init__.py and __all__ to fetch all possible applications or profiles dynamically.
  • Create a MetaTag system that determines if a class or profile should be added to the installation menu.
# archinstall/lib/profiles.py

from archinstall.lib.models.application import (
    ApplicationConfiguration, Audio, BluetoothConfiguration, FirewallConfiguration, PowerManagementConfiguration, PrintServiceConfiguration
)
from typing import List

# Abstract all application profiles dynamically based on metadata
def get_profiles(filter: str = "all") -> List:
    profiles = []

    # Check available profiles from models (this could be dynamic based on your folder structure)
    available_profiles = [ApplicationConfiguration, Audio, BluetoothConfiguration, FirewallConfiguration, PowerManagementConfiguration, PrintServiceConfiguration]
    
    # Filter profiles based on provided filter criteria
    if filter == "config":
        profiles = [profile for profile in available_profiles if hasattr(profile, 'configuration')]
    
    return profiles

# Dynamically load application profiles based on the meta-tag
def load_application_profile(profile: str):
    profiles = get_profiles()
    for p in profiles:
        if p.__name__.lower() == profile.lower():
            return p
    return None

2. Parsing Custom Configuration Scripts

Allow users to import a JSON file or any custom configuration script, which would automatically add the necessary configuration options based on the profiles.

# archinstall/lib/config_parser.py

import json
from archinstall.lib.models.application import ApplicationConfiguration

# Parse a JSON config file to generate the needed profile classes
def parse_custom_config(config_file: str):
    with open(config_file, 'r') as f:
        config_data = json.load(f)
    
    generated_classes = []
    
    for profile in config_data.get("profiles", []):
        profile_class = load_application_profile(profile)
        if profile_class:
            generated_classes.append(profile_class(**config_data[profile]))
    
    return generated_classes

3. Refactor Menu System

The menu should dynamically populate based on available profiles and configurations. This will reduce the need for manual menu item additions and allow future profiles to be automatically added.

# archinstall/lib/menu/abstract_menu.py

from archinstall.lib.menu.helpers import Confirmation, Selection
from archinstall.lib.models.application import ApplicationConfiguration

class DynamicApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
    def __init__(self, preset: ApplicationConfiguration | None = None):
        if preset:
            self._app_config = preset
        else:
            self._app_config = ApplicationConfiguration()

        # Dynamically generate menu options
        menu_options = self._define_dynamic_menu_options()
        self._item_group = MenuItemGroup(menu_options, checkmarks=True)

        super().__init__(
            self._item_group,
            config=self._app_config,
            allow_reset=True,
        )

    def _define_dynamic_menu_options(self):
        profiles = get_profiles(filter="config")
        menu_items = []
        
        for profile in profiles:
            menu_items.append(
                MenuItem(
                    text=profile.__name__,
                    action=select_application,
                    key=profile.__name__.lower() + "_config",
                )
            )
        
        return menu_items

4. Data Class Validation and Type Safety

We should ensure that all configuration options use type-safe data classes and apply validation rules. Here, using Python’s dataclasses module can help enforce type constraints on configurations.

from dataclasses import dataclass, field
from typing import Optional

@dataclass
class PowerManagementConfiguration:
    power_management: Optional[str] = field(default="balanced")

    def __post_init__(self):
        if self.power_management not in ["balanced", "performance", "powersave"]:
            raise ValueError(f"Invalid power management setting: {self.power_management}")

@dataclass
class BluetoothConfiguration:
    enabled: bool = False

    def __post_init__(self):
        if not isinstance(self.enabled, bool):
            raise ValueError("Bluetooth enabled setting must be a boolean.")

5. Generalized Installer Logic

The general idea is to make the installation process more flexible by allowing users to select profiles, configure applications, and even add custom configuration options.

# archinstall/lib/installer.py

async def install_customized_system(config_file: str):
    profiles = parse_custom_config(config_file)
    
    for profile in profiles:
        # Handle installation logic for each profile (e.g., audio, firewall, etc.)
        await configure_profile(profile)

async def configure_profile(profile):
    # Placeholder: Implement the actual configuration logic here.
    pass

Final Thoughts:

  • Dynamic Configuration Handling: By refactoring the code to automatically handle profiles and configuration options, adding new applications or profiles becomes a simple matter of adding the relevant metadata or creating new profile classes.

  • Meta-Tags and Profiles: Using meta tags for classes and profiles allows the system to identify which configurations are available for selection, making the installer truly dynamic.

  • Validation and Type Safety: By leveraging Python’s dataclasses and post-init validation, we ensure that only valid configuration options are allowed, reducing the risk of misconfigurations and improving overall stability.

  • Ease of Use: The refactor aims to make the system more flexible and less code-heavy by relying on configuration scripts, automatic parsing, and dynamic menu generation. This makes it easier for users to create custom installation setups and for developers to maintain the system.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions