builder_peppermint_void/builder/core/install_desktop.py
2025-04-28 01:28:53 +00:00

228 lines
13 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Assuming this is in builder/core/install_desktop.py
# -*- coding: utf-8 -*-
"""
SPDX-FileCopyrightText: 2023-2025 PeppermintOS Team
(peppermintosteam@proton.me)
SPDX-License-Identifier: GPL-3.0-or-later
This module provides a function to install a specified desktop environment and enable
associated services, using the host-execution strategy and handling architecture-specific
package lists and services defined in YAML configuration files.
Credits:
- PeppermintOS Team (peppermintosteam@proton.me) - Development and maintenance of the project.
License:
This code is distributed under the GNU General Public License version 3 or later (GPL-3.0-or-later).
For more details, please refer to the LICENSE file included in the project or visit:
https://www.gnu.org/licenses/gpl-3.0.html
"""
import os
import sys
import logging
import yaml # Keep if load_yaml_config needs it or for other reasons
# Adjust BASE_DIR calculation as needed based on where this file is relative to the project root
# Assuming install_desktop.py is in builder/core/, and project root is parent of builder/
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.insert(0, BASE_DIR)
try:
# Import modules used by this function
from builder.core.command_runner import run_command
# xbps_commands is likely not needed here as construct_xbps_install_args handles it internally
# from builder.core.xbps_commands import xbps_commands
# enable_services_in_chroot implementation might need checking/adaptation later
from builder.core.enable_services import enable_services_in_chroot
# paths is passed as argument, so not needed as direct import here
# from builder.core.bootstrap.paths import paths
from builder.core.config_loader import load_yaml_config # Needed to load desktop YAML
from builder.configs import logger_config
from builder.core import bootstrap # Import bootstrap module for construct_xbps_install_args
# Module-level logger setup
logger = logger_config.setup_logger('install_desktop')
except ImportError as e:
# Handle import error for this module
try:
basic_logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.ERROR)
basic_logger.error(f"Error importing necessary modules for install_desktop: {e}. Ensure your environment is set up correctly.")
except Exception:
print(f"Error importing necessary modules for install_desktop: {e}. Ensure your environment is set up correctly.")
sys.exit(1)
# MODIFIED FUNCTION SIGNATURE to accept arguments passed from iso_builder_main
# Matching the order and names from the intended call
def install_desktop_environment(arch, desktop_environment_name, desktops_config, target_env='rootfs', paths=None, host_arch=None, repositories_data=None):
"""
Installs the specified desktop environment and enables associated services in the chroot system,
using the desktop configuration from the YAML, employing the host-execution strategy.
Args:
arch (str): Architecture (e.g., 'aarch64').
desktop_environment_name (str): Name of the desktop environment (e.g., 'xfce').
desktops_config (dict): Desktop configuration loaded from the YAML (desktops_config.yaml file).
 This contains info about the desktop, including the path to its specific YAML.
target_env (str): Target environment to install the desktop ('rootfs'). Defaults to 'rootfs'.
paths (dict): Dictionary of build paths. Required to get target path and cache dir.
host_arch (str): The architecture of the host system.
repositories_data (list): List of repository dictionaries from YAML config.
Expected structure: [{'name': '...', 'uri': '...', 'architectures': [...]}, ...]
Raises:
subprocess.CalledProcessError: If the xbps-install command fails.
ValueError: If configuration data is missing or incorrect.
KeyError: If required paths are not found.
"""
# Remove the logger = logging.getLogger(__name__) line here, use the module-level logger
logger.info(f"=> Starting installation of desktop environment: {desktop_environment_name} in environment: {target_env} ({arch})...")
# Ensure paths dict is available
if paths is None or not isinstance(paths, dict):
logger.error("Paths dictionary is missing or incorrect.")
raise ValueError("Paths dictionary is required.")
if target_env == 'rootfs':
target_path = paths.get('ROOTFS')
else:
# Desktop environments are typically only installed in rootfs in this build process
logger.error(f"Invalid target environment for desktop installation: {target_env}. Installation is only supported in ROOTFS.")
raise ValueError(f"Invalid target environment for desktop installation: {target_env}")
if not target_path:
logger.error(f"Path for environment '{target_env}' not found in paths dictionary.")
raise KeyError(f"Path for environment '{target_env}' not found.")
desktop_yaml_file = None
total_desktop_packages_list = []
services_to_enable_list = [] # Services are still handled separately
# Get the specific desktop YAML file path from the main desktops_config
if desktops_config and 'desktops' in desktops_config and desktop_environment_name.lower() in desktops_config['desktops']:
desktop_info = desktops_config['desktops'][desktop_environment_name.lower()]
# package_group is not used in this YAML-driven approach
# desktop_packages_group = desktop_info.get('package_group')
desktop_yaml_file = desktop_info.get('yaml_file') # This is the path like 'builder/configs/desktops/xfce.yaml'
else:
logger.error(f"Configuration for desktop environment '{desktop_environment_name}' not found in desktops_config.yaml.")
raise ValueError(f"Configuration for desktop environment '{desktop_environment_name}' not found.")
if desktop_yaml_file:
logger.info(f"=> Loading desktop configuration from YAML file: {desktop_yaml_file}")
# Need to construct the full path if desktop_yaml_file is relative
desktop_yaml_full_path = os.path.join(BASE_DIR, desktop_yaml_file) # Assumes BASE_DIR is project root
try:
# Use load_yaml_config helper
desktop_packages_config = load_yaml_config(desktop_yaml_full_path, os.path.basename(desktop_yaml_full_path))
except Exception as e:
logger.error(f"Error loading desktop packages YAML '{desktop_yaml_full_path}': {e}")
raise # Re-raise the exception
if desktop_packages_config:
logger.debug(f"=> Desktop YAML file loaded successfully from: {desktop_yaml_full_path}")
# Expected structure: {<architecture>: {desktop_packages: [...], login_manager_packages: [...], ...}}
# Get the configuration specifically for the target architecture
desktop_config_for_arch = desktop_packages_config.get(arch, {}) # Use 'arch' parameter
if desktop_config_for_arch:
logger.debug(f"=> Configuration found for architecture: {arch}")
# Get package lists for this architecture
desktop_packages = desktop_config_for_arch.get('desktop_packages', [])
login_manager_packages = desktop_config_for_arch.get('login_manager_packages', [])
default_packages = desktop_config_for_arch.get('default_packages', []) # Assuming this key exists
# Combine all package lists
if isinstance(desktop_packages, list):
total_desktop_packages_list.extend(desktop_packages)
else:
logger.warning(f"'desktop_packages' for {arch} in {desktop_yaml_full_path} is not a list. Ignoring.")
if isinstance(login_manager_packages, list):
total_desktop_packages_list.extend(login_manager_packages)
else:
logger.warning(f"'login_manager_packages' for {arch} in {desktop_yaml_full_path} is not a list. Ignoring.")
if isinstance(default_packages, list):
total_desktop_packages_list.extend(default_packages)
else:
logger.warning(f"'default_packages' for {arch} in {desktop_yaml_full_path} is not a list. Ignoring.")
# Get the services list for this architecture
services_to_enable_list = desktop_config_for_arch.get('services_enable', [])
if not isinstance(services_to_enable_list, list):
logger.warning(f"'services_enable' for {arch} in {desktop_yaml_full_path} is not a list. Ignoring.")
services_to_enable_list = []
else:
logger.warning(f"No configuration found for architecture {arch} in {desktop_yaml_full_path}. No desktop packages or services loaded.")
else:
logger.error(f"=> Failed to load desktop YAML configuration from: {desktop_yaml_full_path}")
# Decide if this should be a fatal error or if a package group fallback is possible
# Currently, if YAML fails or has no arch config, total_desktop_packages_list will be empty
# --- Install Desktop Packages ---
if total_desktop_packages_list:
logger.info(f"=> Desktop package list for {arch} extracted successfully. Building XBPS_INSTALL_CMD command...")
# Construct the xbps-install command arguments using the helper from bootstrap module
# construct_xbps_install_args expects the package list in the structure {'env_name': {'arch': [package_list]}}
# We are installing into the "rootfs" environment here.
adapted_package_structure = {"rootfs": {arch: total_desktop_packages_list}}
# construct_xbps_install_args handles repository filtering, -r, -c args internally
# It needs paths, target_architecture, repositories_data, and the adapted package structure
desktop_packages_args = bootstrap.construct_xbps_install_args(
"rootfs", # Environment name (determines target path like paths['ROOTFS'])
paths, # Paths dictionary (needed by construct_xbps_install_args for rootfs path and cache dir)
arch, # Target architecture (use the 'arch' parameter passed to this function)
repositories_data, # All repository data (passed to this function)
adapted_package_structure # Pass desktop packages in the structure expected by construct_xbps_install_args
)
if not desktop_packages_args:
logger.warning("Skipping desktop packages installation due to failure in constructing xbps-install arguments.")
# The error was likely logged within construct_xbps_install_args
else:
# Execute the xbps-install command directly on the host, targeting the rootfs
# Prepend the xbps-install binary path on the host
desktop_install_command = ["/usr/bin/xbps-install"] + desktop_packages_args
logger.info(f"Executing desktop packages installation command (host): {' '.join(desktop_install_command)}")
try:
run_command(desktop_install_command) # Use the existing run_command helper
logger.info(f"=> Installation of desktop packages completed successfully in environment: {target_env}.")
except Exception as e: # Catching general Exception, consider more specific CalledProcessError
logger.error(f"Error executing XBPS_INSTALL_CMD for desktop packages in environment: {target_env}: {e}")
raise # Re-raise the exception to stop the build
# --- Enable Services ---
# The enable_services_in_chroot function might need to be adapted if it uses chroot execution internally.
# For the host-execution strategy, it should either manipulate files directly or use a helper
# that runs commands in the target context without a full chroot wrapper if possible,
# or use the run_command_in_chroot if that's still deemed necessary for this specific step.
# Assuming enable_services_in_chroot receives the target path and service list and handles execution internally.
if services_to_enable_list:
logger.info("=> Services to enable found in the desktop YAML configuration.")
try:
# enable_services_in_chroot needs the target_path (rootfs_path)
enable_services_in_chroot(target_path, services_to_enable_list) # target_path is derived from paths
logger.info(f"=> Services specified in the desktop YAML enabled successfully in environment: {target_env}.")
except Exception as e:
logger.error(f"Error enabling services specified in the desktop YAML in environment: {target_env}: {e}")
raise
else:
logger.warning("=> No service list to enable found in the desktop YAML configuration. Skipping service activation.")
logger.info(f"=> Installation and configuration of desktop environment: {desktop_environment_name} ({target_env}) completed.")
logger.info(f"--------------------------------------------------------------------\n")