""" SPDX-FileCopyrightText: 2023-2025 PeppermintOS Team (peppermintosteam@proton.me) SPDX-License-Identifier: GPL-3.0-or-later This module provides utility functions for customizing the bootstrapped system, such as setting up PipeWire. 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 logging import shutil try: from builder.core.bootstrap.paths import paths from builder.configs import logger_config from builder.core.config_loader import load_yaml_config from builder.core.utils import ensure_directory_exists, copy_directory, copy_file, check_path_exists except ImportError as e: print(f"Error importing necessary modules: {e}. Ensure your environment is set up correctly. Details: {e}") sys.exit(1) logger = logger_config.setup_logger('copy_customizations') def copy_custom_files(customizations_path, rootfs_path, desktop_config_path): """Recursively copies customization files to the rootfs.""" peppermint_base_path = os.path.join(paths['CUSTOM_FILES_DIR'], customizations_path) desktop_config = load_yaml_config(desktop_config_path, os.path.basename(desktop_config_path)) login_manager = desktop_config.get('desktop_environment', {}).get('login_manager') lightdm_session = desktop_config.get('desktop_environment', {}).get('lightdm_session') if login_manager == "lightdm" and lightdm_session: lightdm_dir = os.path.join(rootfs_path, 'etc', 'lightdm') session_file_path = os.path.join(lightdm_dir, '.session') greeter_config_path = os.path.join(lightdm_dir, 'lightdm-gtk-greeter.conf') ensure_directory_exists(lightdm_dir, create_parents=True) try: with open(session_file_path, 'w') as f: f.write(lightdm_session + '\n') logger.info(f"=> Created LightDM session file: {session_file_path}") greeter_config = desktop_config.get('desktop_environment', {}).get('lightdm_greeter') if greeter_config: with open(greeter_config_path, 'w') as f: for key, value in greeter_config.items(): f.write(f"{key} = {value}\n") logger.info(f"=> Created LightDM greeter configuration file: {greeter_config_path}") except Exception as e: logger.error(f"=> An error occurred while creating LightDM configuration files: {e}") # We can add 'elif' blocks here for other login managers in the future # elif login_manager == "another_manager": # # Logic to configure another login manager # pass copy_operations = desktop_config.get('desktop_environment', {}).get('copy_files') if not copy_operations: logger.info("=> No specific customizations defined for copying.") return True if isinstance(copy_operations, list): for operation in copy_operations: source_name = operation.get('source') destination_path = operation.get('destination') if source_name and destination_path: source_full_path = os.path.join(peppermint_base_path, source_name) destination_full_path = os.path.join(rootfs_path, destination_path.lstrip('/')) if check_path_exists(source_full_path): logger.info(f"=> Copying '{source_name}' from '{source_full_path}' to '{destination_full_path}'") try: if os.path.isdir(source_full_path): if copy_directory(source_full_path, destination_full_path, merge=True): logger.info(f"=> Directory '{source_name}' copied successfully.") else: logger.error(f"=> Failed to copy directory '{source_name}'.") elif os.path.isfile(source_full_path): ensure_directory_exists(os.path.dirname(destination_full_path), create_parents=True) if copy_file(source_full_path, destination_full_path): logger.info(f"=> File '{source_name}' copied successfully.") else: logger.error(f"=> Failed to copy file '{source_name}'.") else: logger.warning(f"=> Source '{source_full_path}' is neither a file nor a directory.") except Exception as e: logger.error(f"=> An error occurred while copying '{source_name}': {e}") else: logger.warning(f"=> Source not found: '{source_full_path}'") else: logger.warning("=> Invalid entry in the copy_files list.") else: logger.warning("=> The copy_files list is not a list or is not defined. Ignoring.") plymouth_config = desktop_config.get('desktop_environment', {}).get('plymouth_theme') if plymouth_config: if isinstance(plymouth_config, list): for theme_config in plymouth_config: source_path = theme_config.get('source') destination_path = os.path.join(rootfs_path, theme_config.get('destination', '').lstrip('/')) if source_path and check_path_exists(os.path.join(peppermint_base_path, source_path)): source_full_path = os.path.join(peppermint_base_path, source_path) logger.info(f"=> Copying Plymouth theme from '{source_path}' to '{destination_path}'") try: if os.path.isdir(source_full_path): if copy_directory(source_full_path, destination_path, merge=True): logger.info("=> Plymouth theme copied successfully.") else: logger.error("=> Failed to copy Plymouth theme.") else: logger.warning(f"=> Plymouth theme source path is not a directory.") except Exception as e: logger.error(f"=> An error occurred while copying the Plymouth theme: {e}") elif not source_path: logger.warning("=> Plymouth theme source path not defined in the configuration.") else: logger.warning(f"=> Plymouth theme source path not found: '{source_path}'") else: source_path = plymouth_config.get('source') destination_path = os.path.join(rootfs_path, plymouth_config.get('destination', '').lstrip('/')) if source_path and check_path_exists(os.path.join(peppermint_base_path, source_path)): source_full_path = os.path.join(peppermint_base_path, source_path) logger.info(f"=> Copying Plymouth theme from '{source_path}' to '{destination_path}'") try: if os.path.isdir(source_full_path): if copy_directory(source_full_path, destination_path, merge=True): logger.info("=> Plymouth theme copied successfully.") else: logger.error("=> Failed to copy Plymouth theme.") else: logger.warning(f"=> Plymouth theme source path is not a directory.") except Exception as e: logger.error(f"=> An error occurred while copying the Plymouth theme: {e}") elif not source_path: logger.warning("=> Plymouth theme source path not defined in the configuration.") else: logger.warning(f"=> Plymouth theme source path not found: '{source_path}'") logger.info("=> Customizations copied successfully.") return True def copy_grub_theme(theme_source_path, iso_boot_path): """Copies the custom GRUB theme to the GRUB themes directory in the ISO.""" iso_grub_themes_dir = os.path.join(iso_boot_path, "grub", "themes") destination_theme_dir = os.path.join(iso_grub_themes_dir) logger.info(f"=> Custom theme directory (source): {theme_source_path}") logger.info(f"=> GRUB themes directory in ISO (destination): {iso_grub_themes_dir}") logger.info(f"=> 'peppermint' theme directory in ISO (final destination): {destination_theme_dir}") # Create the themes directory in the ISO if it doesn't exist ensure_directory_exists(iso_grub_themes_dir, create_parents=True) # Copy the custom theme to the ISO if os.path.exists(theme_source_path): logger.info(f"=> Copying GRUB theme from '{theme_source_path}' to '{destination_theme_dir}'...") try: if os.path.exists(destination_theme_dir): shutil.rmtree(destination_theme_dir) shutil.copytree(theme_source_path, destination_theme_dir) logger.info("=> GRUB theme copied successfully.") except Exception as e: logger.error(f"Error copying the GRUB theme: {e}") else: logger.warning(f"=> Custom theme directory not found: {theme_source_path}. Ignoring.")