- Add complete pytest testing framework with conftest.py and test files - Add performance monitoring and benchmarking capabilities - Add plugin system with ccache plugin example - Add comprehensive documentation (API, deployment, testing, etc.) - Add Docker API wrapper for service deployment - Add advanced configuration examples - Remove old wget package file - Update core modules with enhanced functionality
387 lines
17 KiB
Python
387 lines
17 KiB
Python
"""
|
|
Configuration management for deb-mock
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Any, Dict
|
|
|
|
import yaml
|
|
|
|
from .exceptions import ConfigurationError
|
|
|
|
|
|
class Config:
|
|
"""Configuration class for deb-mock"""
|
|
|
|
def __init__(self, **kwargs):
|
|
# Default configuration
|
|
self.chroot_name = kwargs.get("chroot_name", "bookworm-amd64")
|
|
self.architecture = kwargs.get("architecture", "amd64")
|
|
self.suite = kwargs.get("suite", "bookworm")
|
|
self.output_dir = kwargs.get("output_dir", "./output")
|
|
self.keep_chroot = kwargs.get("keep_chroot", False)
|
|
self.verbose = kwargs.get("verbose", False)
|
|
self.debug = kwargs.get("debug", False)
|
|
|
|
# Chroot configuration
|
|
self.basedir = kwargs.get("basedir", "/var/lib/deb-mock")
|
|
self.chroot_dir = kwargs.get("chroot_dir", "/var/lib/deb-mock/chroots")
|
|
self.chroot_config_dir = kwargs.get("chroot_config_dir", "/etc/schroot/chroot.d")
|
|
self.chroot_home = kwargs.get("chroot_home", "/home/build")
|
|
|
|
# sbuild configuration
|
|
self.sbuild_config = kwargs.get("sbuild_config", "/etc/sbuild/sbuild.conf")
|
|
self.sbuild_log_dir = kwargs.get("sbuild_log_dir", "/var/log/sbuild")
|
|
|
|
# Build configuration
|
|
self.build_deps = kwargs.get("build_deps", [])
|
|
self.build_env = kwargs.get("build_env", {})
|
|
self.build_options = kwargs.get("build_options", [])
|
|
|
|
# Metadata configuration
|
|
self.metadata_dir = kwargs.get("metadata_dir", "./metadata")
|
|
self.capture_logs = kwargs.get("capture_logs", True)
|
|
self.capture_changes = kwargs.get("capture_changes", True)
|
|
|
|
# Speed optimization (Mock-inspired features)
|
|
self.cache_dir = kwargs.get("cache_dir", "/var/cache/deb-mock")
|
|
self.use_root_cache = kwargs.get("use_root_cache", True)
|
|
self.root_cache_dir = kwargs.get("root_cache_dir", "/var/cache/deb-mock/root-cache")
|
|
self.root_cache_age = kwargs.get("root_cache_age", 7) # days
|
|
self.use_package_cache = kwargs.get("use_package_cache", True)
|
|
self.package_cache_dir = kwargs.get("package_cache_dir", "/var/cache/deb-mock/package-cache")
|
|
self.use_ccache = kwargs.get("use_ccache", False)
|
|
self.ccache_dir = kwargs.get("ccache_dir", "/var/cache/deb-mock/ccache")
|
|
self.use_tmpfs = kwargs.get("use_tmpfs", False)
|
|
self.tmpfs_size = kwargs.get("tmpfs_size", "2G")
|
|
|
|
# Parallel builds
|
|
self.parallel_jobs = kwargs.get("parallel_jobs", 4)
|
|
self.parallel_compression = kwargs.get("parallel_compression", True)
|
|
|
|
# Advanced parallel build support
|
|
self.parallel_builds = kwargs.get("parallel_builds", 2) # Number of parallel chroots
|
|
self.parallel_chroot_prefix = kwargs.get("parallel_chroot_prefix", "parallel")
|
|
self.parallel_build_timeout = kwargs.get("parallel_build_timeout", 3600) # seconds
|
|
self.parallel_build_cleanup = kwargs.get("parallel_build_cleanup", True)
|
|
|
|
# Advanced mount management
|
|
self.advanced_mounts = kwargs.get("advanced_mounts", {})
|
|
self.bind_mounts = kwargs.get("bind_mounts", [])
|
|
self.tmpfs_mounts = kwargs.get("tmpfs_mounts", [])
|
|
self.overlay_mounts = kwargs.get("overlay_mounts", [])
|
|
self.mount_options = kwargs.get("mount_options", {})
|
|
|
|
# Mount isolation and security
|
|
self.mount_proc = kwargs.get("mount_proc", True)
|
|
self.mount_sys = kwargs.get("mount_sys", True)
|
|
self.mount_dev = kwargs.get("mount_dev", True)
|
|
self.mount_devpts = kwargs.get("mount_devpts", True)
|
|
self.mount_tmp = kwargs.get("mount_tmp", True)
|
|
self.mount_home = kwargs.get("mount_home", False)
|
|
|
|
# Advanced chroot features
|
|
self.use_namespaces = kwargs.get("use_namespaces", False)
|
|
self.uid_mapping = kwargs.get("uid_mapping", None)
|
|
self.gid_mapping = kwargs.get("gid_mapping", None)
|
|
self.capabilities = kwargs.get("capabilities", [])
|
|
self.seccomp_profile = kwargs.get("seccomp_profile", None)
|
|
|
|
# UID/GID management
|
|
self.chroot_user = kwargs.get("chroot_user", "build")
|
|
self.chroot_group = kwargs.get("chroot_group", "build")
|
|
self.chroot_uid = kwargs.get("chroot_uid", 1000)
|
|
self.chroot_gid = kwargs.get("chroot_gid", 1000)
|
|
self.use_host_user = kwargs.get("use_host_user", False)
|
|
self.copy_host_users = kwargs.get("copy_host_users", [])
|
|
self.preserve_uid_gid = kwargs.get("preserve_uid_gid", True)
|
|
|
|
# Plugin system
|
|
self.plugins = kwargs.get("plugins", [])
|
|
self.plugin_conf = kwargs.get("plugin_conf", {})
|
|
self.plugin_dir = kwargs.get("plugin_dir", "/usr/share/deb-mock/plugins")
|
|
|
|
# Performance monitoring and optimization
|
|
self.enable_performance_monitoring = kwargs.get("enable_performance_monitoring", True)
|
|
self.performance_metrics_dir = kwargs.get("performance_metrics_dir", "./performance-metrics")
|
|
self.performance_retention_days = kwargs.get("performance_retention_days", 30)
|
|
self.performance_auto_optimization = kwargs.get("performance_auto_optimization", False)
|
|
self.performance_benchmark_iterations = kwargs.get("performance_benchmark_iterations", 3)
|
|
self.performance_reporting = kwargs.get("performance_reporting", True)
|
|
|
|
# Network and proxy
|
|
self.use_host_resolv = kwargs.get("use_host_resolv", True)
|
|
self.http_proxy = kwargs.get("http_proxy", None)
|
|
self.https_proxy = kwargs.get("https_proxy", None)
|
|
self.no_proxy = kwargs.get("no_proxy", None)
|
|
|
|
# Mirror configuration
|
|
self.mirror = kwargs.get("mirror", "http://deb.debian.org/debian/")
|
|
self.security_mirror = kwargs.get("security_mirror", None)
|
|
self.backports_mirror = kwargs.get("backports_mirror", None)
|
|
|
|
# Isolation and security
|
|
self.isolation = kwargs.get("isolation", "schroot") # schroot, simple, nspawn
|
|
self.enable_network = kwargs.get("enable_network", True)
|
|
self.selinux_enabled = kwargs.get("selinux_enabled", False)
|
|
|
|
# Bootstrap chroot support (Mock FAQ #2 - Cross-distribution builds)
|
|
self.use_bootstrap_chroot = kwargs.get("use_bootstrap_chroot", False)
|
|
self.bootstrap_chroot_name = kwargs.get("bootstrap_chroot_name", None)
|
|
self.bootstrap_arch = kwargs.get("bootstrap_arch", None)
|
|
self.bootstrap_suite = kwargs.get("bootstrap_suite", None)
|
|
|
|
# Build environment customization
|
|
self.chroot_setup_cmd = kwargs.get("chroot_setup_cmd", [])
|
|
self.chroot_additional_packages = kwargs.get("chroot_additional_packages", [])
|
|
|
|
# Environment variable preservation (Mock FAQ #1)
|
|
self.preserve_environment = kwargs.get("preserve_environment", [])
|
|
self.environment_sanitization = kwargs.get("environment_sanitization", True)
|
|
self.allowed_environment_vars = kwargs.get(
|
|
"allowed_environment_vars",
|
|
[
|
|
"DEB_BUILD_OPTIONS",
|
|
"DEB_BUILD_PROFILES",
|
|
"CC",
|
|
"CXX",
|
|
"CFLAGS",
|
|
"CXXFLAGS",
|
|
"LDFLAGS",
|
|
"MAKEFLAGS",
|
|
"CCACHE_DIR",
|
|
"CCACHE_HASHDIR",
|
|
"http_proxy",
|
|
"https_proxy",
|
|
"no_proxy",
|
|
"DISPLAY",
|
|
"XAUTHORITY",
|
|
],
|
|
)
|
|
|
|
# Advanced build options (Mock-inspired)
|
|
self.run_tests = kwargs.get("run_tests", True)
|
|
self.build_timeout = kwargs.get("build_timeout", 0) # 0 = no timeout
|
|
self.force_architecture = kwargs.get("force_architecture", None)
|
|
self.unique_extension = kwargs.get("unique_extension", None)
|
|
self.config_dir = kwargs.get("config_dir", None)
|
|
self.cleanup_after = kwargs.get("cleanup_after", True)
|
|
|
|
# APT configuration
|
|
self.apt_sources = kwargs.get("apt_sources", [])
|
|
self.apt_preferences = kwargs.get("apt_preferences", [])
|
|
self.apt_command = kwargs.get("apt_command", "apt-get")
|
|
self.apt_install_command = kwargs.get("apt_install_command", "apt-get install -y")
|
|
|
|
@classmethod
|
|
def from_file(cls, config_path: str) -> "Config":
|
|
"""Load configuration from a YAML file"""
|
|
try:
|
|
with open(config_path, "r") as f:
|
|
config_data = yaml.safe_load(f)
|
|
|
|
return cls(**config_data)
|
|
except FileNotFoundError:
|
|
raise ConfigurationError(f"Configuration file not found: {config_path}")
|
|
except yaml.YAMLError as e:
|
|
raise ConfigurationError(f"Invalid YAML in configuration file: {e}")
|
|
except Exception as e:
|
|
raise ConfigurationError(f"Error loading configuration: {e}")
|
|
|
|
@classmethod
|
|
def default(cls) -> "Config":
|
|
"""Create default configuration"""
|
|
return cls()
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
"""Convert configuration to dictionary"""
|
|
return {
|
|
"chroot_name": self.chroot_name,
|
|
"architecture": self.architecture,
|
|
"suite": self.suite,
|
|
"output_dir": self.output_dir,
|
|
"keep_chroot": self.keep_chroot,
|
|
"verbose": self.verbose,
|
|
"debug": self.debug,
|
|
"chroot_dir": self.chroot_dir,
|
|
"chroot_config_dir": self.chroot_config_dir,
|
|
"sbuild_config": self.sbuild_config,
|
|
"sbuild_log_dir": self.sbuild_log_dir,
|
|
"build_deps": self.build_deps,
|
|
"build_env": self.build_env,
|
|
"build_options": self.build_options,
|
|
"metadata_dir": self.metadata_dir,
|
|
"capture_logs": self.capture_logs,
|
|
"capture_changes": self.capture_changes,
|
|
"use_root_cache": self.use_root_cache,
|
|
"root_cache_dir": self.root_cache_dir,
|
|
"root_cache_age": self.root_cache_age,
|
|
"use_package_cache": self.use_package_cache,
|
|
"package_cache_dir": self.package_cache_dir,
|
|
"use_ccache": self.use_ccache,
|
|
"ccache_dir": self.ccache_dir,
|
|
"use_tmpfs": self.use_tmpfs,
|
|
"tmpfs_size": self.tmpfs_size,
|
|
"parallel_jobs": self.parallel_jobs,
|
|
"parallel_compression": self.parallel_compression,
|
|
"parallel_builds": self.parallel_builds,
|
|
"parallel_chroot_prefix": self.parallel_chroot_prefix,
|
|
"parallel_build_timeout": self.parallel_build_timeout,
|
|
"parallel_build_cleanup": self.parallel_build_cleanup,
|
|
"advanced_mounts": self.advanced_mounts,
|
|
"bind_mounts": self.bind_mounts,
|
|
"tmpfs_mounts": self.tmpfs_mounts,
|
|
"overlay_mounts": self.overlay_mounts,
|
|
"mount_options": self.mount_options,
|
|
"mount_proc": self.mount_proc,
|
|
"mount_sys": self.mount_sys,
|
|
"mount_dev": self.mount_dev,
|
|
"mount_devpts": self.mount_devpts,
|
|
"mount_tmp": self.mount_tmp,
|
|
"mount_home": self.mount_home,
|
|
"use_namespaces": self.use_namespaces,
|
|
"uid_mapping": self.uid_mapping,
|
|
"gid_mapping": self.gid_mapping,
|
|
"capabilities": self.capabilities,
|
|
"seccomp_profile": self.seccomp_profile,
|
|
"chroot_user": self.chroot_user,
|
|
"chroot_group": self.chroot_group,
|
|
"chroot_uid": self.chroot_uid,
|
|
"chroot_gid": self.chroot_gid,
|
|
"use_host_user": self.use_host_user,
|
|
"copy_host_users": self.copy_host_users,
|
|
"preserve_uid_gid": self.preserve_uid_gid,
|
|
"plugins": self.plugins,
|
|
"plugin_conf": self.plugin_conf,
|
|
"plugin_dir": self.plugin_dir,
|
|
"enable_performance_monitoring": self.enable_performance_monitoring,
|
|
"performance_metrics_dir": self.performance_metrics_dir,
|
|
"performance_retention_days": self.performance_retention_days,
|
|
"performance_auto_optimization": self.performance_auto_optimization,
|
|
"performance_benchmark_iterations": self.performance_benchmark_iterations,
|
|
"performance_reporting": self.performance_reporting,
|
|
"use_host_resolv": self.use_host_resolv,
|
|
"http_proxy": self.http_proxy,
|
|
"https_proxy": self.https_proxy,
|
|
"no_proxy": self.no_proxy,
|
|
"mirror": self.mirror,
|
|
"security_mirror": self.security_mirror,
|
|
"backports_mirror": self.backports_mirror,
|
|
"isolation": self.isolation,
|
|
"enable_network": self.enable_network,
|
|
"selinux_enabled": self.selinux_enabled,
|
|
"use_bootstrap_chroot": self.use_bootstrap_chroot,
|
|
"bootstrap_chroot_name": self.bootstrap_chroot_name,
|
|
"bootstrap_arch": self.bootstrap_arch,
|
|
"bootstrap_suite": self.bootstrap_suite,
|
|
"chroot_setup_cmd": self.chroot_setup_cmd,
|
|
"chroot_additional_packages": self.chroot_additional_packages,
|
|
"preserve_environment": self.preserve_environment,
|
|
"environment_sanitization": self.environment_sanitization,
|
|
"allowed_environment_vars": self.allowed_environment_vars,
|
|
}
|
|
|
|
def save(self, config_path: str) -> None:
|
|
"""Save configuration to a YAML file"""
|
|
try:
|
|
config_dir = Path(config_path).parent
|
|
config_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
with open(config_path, "w") as f:
|
|
yaml.dump(self.to_dict(), f, default_flow_style=False)
|
|
except Exception as e:
|
|
raise ConfigurationError(f"Error saving configuration: {e}")
|
|
|
|
def validate(self) -> None:
|
|
"""Validate configuration"""
|
|
errors = []
|
|
|
|
# Check required directories
|
|
if not os.path.exists(self.chroot_config_dir):
|
|
errors.append(f"Chroot config directory does not exist: {self.chroot_config_dir}")
|
|
|
|
if not os.path.exists(self.sbuild_config):
|
|
errors.append(f"sbuild config file does not exist: {self.sbuild_config}")
|
|
|
|
# Check architecture
|
|
valid_architectures = ["amd64", "i386", "arm64", "armhf", "ppc64el", "s390x"]
|
|
if self.architecture not in valid_architectures:
|
|
errors.append(f"Invalid architecture: {self.architecture}")
|
|
|
|
# Check suite
|
|
valid_suites = [
|
|
"trixie", # Debian 13+ (trixie) - required for OSTree support
|
|
"bookworm",
|
|
"sid",
|
|
"bullseye",
|
|
"buster",
|
|
"jammy",
|
|
"noble",
|
|
"focal",
|
|
]
|
|
if self.suite not in valid_suites:
|
|
errors.append(f"Invalid suite: {self.suite}")
|
|
|
|
# Check isolation method
|
|
valid_isolation = ["schroot", "simple", "nspawn"]
|
|
if self.isolation not in valid_isolation:
|
|
errors.append(f"Invalid isolation method: {self.isolation}")
|
|
|
|
# Check parallel jobs
|
|
if self.parallel_jobs < 1:
|
|
errors.append("Parallel jobs must be at least 1")
|
|
|
|
if errors:
|
|
raise ConfigurationError("Configuration validation failed:\n" + "\n".join(errors))
|
|
|
|
def get_chroot_path(self) -> str:
|
|
"""Get the full path to the chroot directory"""
|
|
return os.path.join(self.chroot_dir, self.chroot_name)
|
|
|
|
def get_output_path(self) -> str:
|
|
"""Get the full path to the output directory"""
|
|
return os.path.abspath(self.output_dir)
|
|
|
|
def get_metadata_path(self) -> str:
|
|
"""Get the full path to the metadata directory"""
|
|
return os.path.abspath(self.metadata_dir)
|
|
|
|
def get_root_cache_path(self) -> str:
|
|
"""Get the full path to the root cache directory"""
|
|
return os.path.join(self.root_cache_dir, self.chroot_name)
|
|
|
|
def get_package_cache_path(self) -> str:
|
|
"""Get the full path to the package cache directory"""
|
|
return os.path.join(self.package_cache_dir, self.chroot_name)
|
|
|
|
def get_ccache_path(self) -> str:
|
|
"""Get the full path to the ccache directory"""
|
|
return os.path.join(self.ccache_dir, self.chroot_name)
|
|
|
|
def setup_build_environment(self) -> Dict[str, str]:
|
|
"""Setup build environment variables"""
|
|
env = {}
|
|
|
|
# Set parallel build options
|
|
if self.parallel_jobs > 1:
|
|
env["DEB_BUILD_OPTIONS"] = f"parallel={self.parallel_jobs},nocheck"
|
|
env["MAKEFLAGS"] = f"-j{self.parallel_jobs}"
|
|
|
|
# Set ccache if enabled
|
|
if self.use_ccache:
|
|
env["CCACHE_DIR"] = self.get_ccache_path()
|
|
env["CCACHE_HASHDIR"] = "1"
|
|
|
|
# Set proxy if configured
|
|
if self.http_proxy:
|
|
env["http_proxy"] = self.http_proxy
|
|
if self.https_proxy:
|
|
env["https_proxy"] = self.https_proxy
|
|
if self.no_proxy:
|
|
env["no_proxy"] = self.no_proxy
|
|
|
|
# Merge with user-defined build environment
|
|
env.update(self.build_env)
|
|
|
|
return env
|