builder_peppermint_void/builder/core/rootfs_cleanup.py
2025-04-25 12:38:42 +00:00

203 lines
9.6 KiB
Python

# -*- coding: utf-8 -*-
"""
SPDX-FileCopyrightText: 2023-2025 PeppermintOS Team
(peppermintosteam@proton.me)
SPDX-License-Identifier: GPL-3.0-or-later
This module provides functions to clean up the root filesystem (rootfs) and image directory
during the ISO build process. It includes functionalities for removing specified packages,
unnecessary dracut modules, clearing temporary files and caches, and ensuring the loading
of the dm-raid module if necessary.
The module uses the `subprocess` module to execute commands within a chroot environment,
`shutil` for file and directory removal, `logging` for logging activities, `os` for
path manipulation, `sys` for system-specific parameters and functions, and `glob` for
finding files matching a specified pattern.
It relies on configurations loaded by `builder.core.config_loader` and utilizes helper
functions from `builder.core.mount_helper`, `builder.core.system_reconfigure`,
`builder.core.command_runner`, and `builder.core.xbps_commands`.
The module defines the following functions:
- `clear_directory_contents(directory_path)`: Removes all files and subdirectories within a given directory.
- `cleanup_rootfs(rootfs_path, iso_build_config)`: Cleans the rootfs by removing specified packages and dracut modules.
- `cleanup_image_dir(iso_build_dir, iso_build_config)`: Cleans the 'image' directory by removing the specific build folder.
- `post_install_cleanup(rootfs_path, iso_build_config)`: Executes post-installation cleanup tasks in the rootfs, such as removing caches and ensuring dm-raid module loading.
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 subprocess
import shutil
import logging
import os
import sys
import glob
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, BASE_DIR)
try:
from builder.configs import logger_config
logger = logger_config.setup_logger('rootfs_cleanup')
except ImportError as e:
print(f"Error importing necessary modules: {e}. Ensure your environment is set up correctly.")
sys.exit(1)
def clear_directory_contents(directory_path):
"""Removes all files and subdirectories within a given directory."""
if os.path.exists(directory_path):
try:
for item in os.listdir(directory_path):
item_path = os.path.join(directory_path, item)
if os.path.isfile(item_path) or os.path.islink(item_path):
os.unlink(item_path)
elif os.path.isdir(item_path):
shutil.rmtree(item_path)
logger.info(f"=> Contents of directory '{directory_path}' removed successfully.")
except Exception as e:
logger.error(f"=> ERROR while removing contents of directory '{directory_path}': {e}")
else:
logger.warning(f"=> Directory '{directory_path}' not found. Skipping content cleanup.")
def cleanup_rootfs(rootfs_path, iso_build_config):
"""
Cleans the rootfs by removing specified packages and unnecessary dracut modules.
Args:
rootfs_path (str): The path to the root filesystem directory.
iso_build_config (dict): The ISO build configuration dictionary.
"""
logger.info("=> Starting ROOTFS cleanup...")
initramfs_pkgs_to_remove = iso_build_config.get('initramfs_packages_remove', [])
if not initramfs_pkgs_to_remove:
logger.info("=> No initramfs packages specified for removal in the configuration. Skipping package removal.")
else:
logger.info(f"=> Packages to remove from ROOTFS: {initramfs_pkgs_to_remove}")
for pkg_name in initramfs_pkgs_to_remove:
logger.info(f"=> Processing package: '{pkg_name}' for cleanup...")
revdeps_command = [
"chroot", rootfs_path,
"xbps-query", "-X", pkg_name
]
logger.debug(f"=> Executing command to check reverse dependencies: {revdeps_command}")
process = subprocess.run(revdeps_command, capture_output=True, text=True)
revdeps_output = process.stdout.strip()
if process.returncode != 0:
logger.error(f"=> ERROR while checking reverse dependencies for '{pkg_name}'. Return code: {process.returncode}")
logger.error(f"=> STDERR: {process.stderr}")
continue
if revdeps_output:
logger.info(f"=> Package '{pkg_name}' has reverse dependencies: '{revdeps_output}'. Marking as 'auto'.")
auto_cmd = [
"chroot", rootfs_path,
"xbps-pkgdb", "-m", "auto", pkg_name
]
logger.debug(f"=> Executing command to mark as auto: {auto_cmd}")
auto_process = subprocess.run(auto_cmd, capture_output=True, text=True)
if auto_process.returncode != 0:
logger.error(f"=> ERROR while marking '{pkg_name}' as 'auto'. Code: {auto_process.returncode}, Error: {auto_process.stderr}")
else:
logger.info(f"=> Package '{pkg_name}' has NO reverse dependencies. Removing...")
remove_cmd = [
"chroot", rootfs_path,
"xbps-remove", "-Ry", pkg_name
]
logger.debug(f"=> Executing command to remove package: {remove_cmd}")
remove_process = subprocess.run(remove_cmd, capture_output=True, text=True)
if remove_process.returncode != 0:
logger.error(f"=> ERROR while removing package '{pkg_name}'. Code: {remove_process.returncode}, Error: {remove_process.stderr}")
# Remove specific dracut modules
dracut_modules_to_remove = [
"01vmklive",
]
logger.info(f"=> Removing dracut modules: {dracut_modules_to_remove}")
for module_name in dracut_modules_to_remove:
module_path = os.path.join(rootfs_path, "usr", "lib", "dracut", "modules.d", module_name)
if os.path.exists(module_path):
try:
shutil.rmtree(module_path)
logger.info(f"=> Dracut module '{module_name}' removed successfully from: '{module_path}'")
except Exception as e:
logger.error(f"=> ERROR while removing dracut module '{module_name}' at: '{module_path}'. Error: {e}")
else:
logger.warning(f"=> Dracut module '{module_name}' not found at: '{module_path}'. Skipping removal.")
logger.info("=> ROOTFS cleanup completed.")
def post_install_cleanup(rootfs_path, iso_build_config):
"""
Executes post-installation cleanup tasks in the ROOTFS, removing caches and ensuring dm-raid module loading.
Args:
rootfs_path (str): The path to the root filesystem directory.
iso_build_config (dict): The ISO build configuration dictionary.
"""
logger.info("=> Starting POST-INSTALL cleanup in ROOTFS...")
# 1. Cleanup of temporary files and caches
dirs_to_cleanup = [
os.path.join(rootfs_path, "var", "cache"),
os.path.join(rootfs_path, "run"),
os.path.join(rootfs_path, "var", "run")
]
logger.info(f"=> Cleaning the contents of temporary directories: {dirs_to_cleanup}")
for cleanup_dir in dirs_to_cleanup:
if os.path.exists(cleanup_dir):
try:
clear_directory_contents(cleanup_dir)
logger.info(f"=> Contents of '{cleanup_dir}' cleaned successfully.")
except Exception as e:
logger.error(f"=> ERROR while cleaning contents of directory '{cleanup_dir}'. Error: {e}")
else:
logger.warning(f"=> Directory '{cleanup_dir}' not found. Skipping cleanup.")
# 2. Ensure dm-raid module loading (if necessary)
logger.info("=> Checking and configuring dm-raid module loading (if necessary)...")
modules_dir = os.path.join(rootfs_path, "usr", "lib", "modules")
logger.debug(f"=> Looking for kernel versions in: '{modules_dir}'")
kernel_versions = []
if os.path.isdir(modules_dir):
kernel_versions = [d for d in os.listdir(modules_dir) if os.path.isdir(os.path.join(modules_dir, d))]
logger.debug(f"=> Kernel versions found: {kernel_versions}")
if kernel_versions:
kernel_version = sorted(kernel_versions)[-1]
logger.info(f"=> Detected kernel version for POST-INSTALL cleanup: '{kernel_version}'")
dm_raid_module_pattern = os.path.join(rootfs_path, "usr", "lib", "modules", kernel_version, "kernel", "drivers", "md", "dm-raid.ko.*")
dm_raid_module_files = glob.glob(dm_raid_module_pattern)
if dm_raid_module_files:
dm_raid_conf_path = os.path.join(rootfs_path, "etc", "modules-load.d", "dm-raid.conf")
try:
with open(dm_raid_conf_path, "w") as f:
f.write("dm-raid\n")
logger.info(f"=> Configuration file 'dm-raid.conf' created at: '{dm_raid_conf_path}' to ensure dm-raid module loading.")
except Exception as e:
logger.error(f"=> ERROR while creating 'dm-raid.conf' file at: '{dm_raid_conf_path}'. Error: {e}")
else:
logger.info(f"=> Module 'dm-raid' not found at: '{dm_raid_module_pattern}'. Skipping 'dm-raid.conf' creation.")
else:
logger.error("=> Could not find any kernel versions in '/usr/lib/modules'. Unable to configure 'dm-raid' module.")
logger.warning("=> 'dm-raid' module configuration functionality will be skipped.")
logger.info("=> POST-INSTALL cleanup in ROOTFS completed.")