203 lines
9.6 KiB
Python
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.") |