diff --git a/config/debian-forge.conf b/config/debian-forge.conf index 59886bef..be3ad338 100644 --- a/config/debian-forge.conf +++ b/config/debian-forge.conf @@ -10,7 +10,7 @@ # url = http://localhost:3142 # url = http://192.168.1.100:3142 # url = http://apt-cache.company.local:3142 -url = +# url = # Alternative: use environment variable # Set DEBIAN_FORGE_APT_PROXY environment variable to override this setting diff --git a/osbuild/config_manager.py b/osbuild/config_manager.py index 427a4074..47b19daf 100644 --- a/osbuild/config_manager.py +++ b/osbuild/config_manager.py @@ -9,6 +9,28 @@ import configparser from pathlib import Path from typing import Optional, Dict, Any +# Import version detector +try: + from .version_detector import ( + get_recommended_suite as _get_recommended_suite, + get_mirror_url as _get_mirror_url, + is_version_supported as _is_version_supported, + print_version_info as _print_version_info + ) +except ImportError: + # Fallback if version detector is not available + def _get_recommended_suite(): + return "trixie" + + def _get_mirror_url(): + return "http://deb.debian.org/debian" + + def _is_version_supported(): + return True + + def _print_version_info(): + print("Version detector not available") + class DebianForgeConfig: """Configuration manager for Debian Forge settings""" @@ -17,6 +39,7 @@ class DebianForgeConfig: self.config_dir = Path(config_dir) self.config = configparser.ConfigParser() self._load_config() + self._apply_version_detection() def _load_config(self): """Load configuration from multiple sources with priority order""" @@ -60,6 +83,26 @@ class DebianForgeConfig: self.config.add_section("build") self.config["build"]["default_arch"] = env_arch + def _apply_version_detection(self): + """Apply automatic version detection like Fedora does""" + # Check if version detection is available + if not _is_version_supported(): + print("āš ļø Warning: Current Debian version is not officially supported") + print(" Debian Forge supports Debian 13+ (Trixie and newer)") + print(" Consider upgrading or using a supported version") + + # Auto-detect recommended suite if not explicitly set + try: + current_suite = self.get_build_setting("default_suite") + if not current_suite or current_suite == "bookworm": # Legacy default + recommended_suite = _get_recommended_suite() + if "build" not in self.config: + self.config.add_section("build") + self.config["build"]["default_suite"] = recommended_suite + print(f"šŸ”„ Auto-detected recommended suite: {recommended_suite}") + except Exception: + pass + def get_apt_proxy(self) -> Optional[str]: """Get apt-cacher-ng proxy URL if configured""" try: @@ -93,6 +136,18 @@ class DebianForgeConfig: """Check if apt-cacher-ng proxy is enabled""" return self.get_apt_proxy() is not None + def get_recommended_suite(self) -> str: + """Get the recommended Debian suite for this system""" + return _get_recommended_suite() + + def get_mirror_url(self) -> str: + """Get appropriate Debian mirror URL""" + return _get_mirror_url() + + def is_version_supported(self) -> bool: + """Check if current Debian version is supported""" + return _is_version_supported() + def get_all_settings(self) -> Dict[str, Dict[str, Any]]: """Get all configuration settings as a dictionary""" result = {} @@ -104,6 +159,12 @@ class DebianForgeConfig: """Print current configuration for debugging""" print("Debian Forge Configuration:") print("=" * 40) + + # Show version detection info + _print_version_info() + print() + + # Show configuration settings for section, settings in self.get_all_settings().items(): print(f"\n[{section}]") for key, value in settings.items(): @@ -114,6 +175,12 @@ class DebianForgeConfig: if env_proxy: print(f"\nEnvironment Override:") print(f" DEBIAN_FORGE_APT_PROXY = {env_proxy}") + + # Show auto-detected values + print(f"\nAuto-detected:") + print(f" Recommended suite = {self.get_recommended_suite()}") + print(f" Mirror URL = {self.get_mirror_url()}") + print(f" Version supported = {self.is_version_supported()}") # Global configuration instance @@ -138,3 +205,18 @@ def get_build_setting(key: str, default: Any = None) -> Any: def get_stage_setting(key: str, default: Any = None) -> Any: """Get a stage setting (convenience function)""" return config.get_stage_setting(key, default) + + +def get_recommended_suite() -> str: + """Get recommended Debian suite (convenience function)""" + return config.get_recommended_suite() + + +def get_mirror_url() -> str: + """Get appropriate Debian mirror URL (convenience function)""" + return config.get_mirror_url() + + +def is_version_supported() -> bool: + """Check if current Debian version is supported (convenience function)""" + return config.is_version_supported() diff --git a/osbuild/version_detector.py b/osbuild/version_detector.py new file mode 100644 index 00000000..9dda35c3 --- /dev/null +++ b/osbuild/version_detector.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python3 +""" +Debian Version Detector +Automatically detects Debian version and provides appropriate configuration +Similar to how Fedora/RHEL handle version detection in OSBuild +""" + +import os +import subprocess +import re +from pathlib import Path +from typing import Optional, Dict, Any, Tuple + + +class DebianVersionDetector: + """Detects Debian version and provides appropriate configuration""" + + def __init__(self): + self.version_info = self._detect_debian_version() + + def _detect_debian_version(self) -> Dict[str, Any]: + """Detect Debian version from multiple sources""" + version_info = { + 'codename': None, + 'version': None, + 'release': None, + 'is_debian': False, + 'is_supported': False, + 'support_status': 'unknown' + } + + # Method 1: Check /etc/os-release + if os.path.exists('/etc/os-release'): + with open('/etc/os-release', 'r') as f: + content = f.read() + # Check if this is actually Debian + if 'debian' in content.lower(): + version_info['is_debian'] = True + # Extract version info + version_match = re.search(r'VERSION_ID="?([^"\n]+)"?', content) + codename_match = re.search(r'VERSION_CODENAME="?([^"\n]+)"?', content) + + if version_match: + version_info['version'] = version_match.group(1) + if codename_match: + version_info['codename'] = codename_match.group(1) + + # Method 2: Check /etc/debian_version + if os.path.exists('/etc/debian_version'): + version_info['is_debian'] = True + with open('/etc/debian_version', 'r') as f: + version_info['release'] = f.read().strip() + + # Method 3: Check lsb_release command + try: + result = subprocess.run(['lsb_release', '-a'], + capture_output=True, text=True, check=True) + for line in result.stdout.split('\n'): + if 'Distributor ID:' in line and 'debian' in line.lower(): + version_info['is_debian'] = True + elif 'Codename:' in line and version_info['is_debian']: + version_info['codename'] = line.split(':', 1)[1].strip() + elif 'Release:' in line and version_info['is_debian']: + version_info['version'] = line.split(':', 1)[1].strip() + except (subprocess.CalledProcessError, FileNotFoundError): + pass + + # If not Debian, return early + if not version_info['is_debian']: + return { + 'codename': None, + 'version': None, + 'release': None, + 'is_debian': False, + 'is_supported': False, + 'support_status': 'not_debian', + 'support_level': 'none', + 'debian_version': 'unknown' + } + + # Determine support status for Debian systems + version_info.update(self._determine_support_status(version_info)) + + return version_info + + def _determine_support_status(self, version_info: Dict[str, Any]) -> Dict[str, Any]: + """Determine if the detected version is supported""" + codename = version_info.get('codename', '').lower() + version = version_info.get('version', '') + + # Debian 13+ support policy + supported_codenames = { + 'trixie': {'version': '13', 'status': 'stable', 'support': 'full'}, + 'forky': {'version': '14', 'status': 'testing', 'support': 'development'}, + 'sid': {'version': 'unstable', 'status': 'unstable', 'support': 'experimental'} + } + + # Check if codename is supported + if codename in supported_codenames: + return { + 'is_supported': True, + 'support_status': supported_codenames[codename]['status'], + 'support_level': supported_codenames[codename]['support'], + 'debian_version': supported_codenames[codename]['version'] + } + + # Check version number if codename not found + try: + version_num = int(version.split('.')[0]) + if version_num >= 13: + return { + 'is_supported': True, + 'support_status': 'stable', + 'support_level': 'full', + 'debian_version': str(version_num) + } + except (ValueError, IndexError): + pass + + # Not supported + return { + 'is_supported': False, + 'support_status': 'unsupported', + 'support_level': 'none', + 'debian_version': 'unknown' + } + + def get_recommended_suite(self) -> str: + """Get the recommended Debian suite for this system""" + if not self.version_info['is_debian']: + return 'trixie' # Default for non-Debian systems + + if self.version_info['is_supported']: + return self.version_info['codename'] or 'trixie' + return 'trixie' # Default to supported version + + def get_mirror_url(self) -> str: + """Get appropriate Debian mirror URL""" + if not self.version_info['is_debian']: + return 'http://deb.debian.org/debian' # Default for non-Debian systems + + codename = self.version_info.get('codename', 'trixie') + + # Use official Debian mirrors + mirrors = { + 'trixie': 'http://deb.debian.org/debian', + 'forky': 'http://deb.debian.org/debian', + 'sid': 'http://deb.debian.org/debian' + } + + return mirrors.get(codename, 'http://deb.debian.org/debian') + + def get_apt_sources(self) -> str: + """Generate appropriate apt sources.list content""" + if not self.version_info['is_debian']: + # Return default sources for non-Debian systems + return """deb http://deb.debian.org/debian trixie main +deb http://deb.debian.org/debian trixie-updates main +deb http://deb.debian.org/debian trixie-security main +deb http://deb.debian.org/debian trixie-backports main +""" + + codename = self.version_info.get('codename', 'trixie') + mirror = self.get_mirror_url() + + sources = f"""deb {mirror} {codename} main +deb {mirror} {codename}-updates main +deb {mirror} {codename}-security main +""" + + # Add backports for stable releases + if codename == 'trixie': + sources += f"deb {mirror} {codename}-backports main\n" + + return sources + + def get_support_warning(self) -> Optional[str]: + """Get warning message if version is not fully supported""" + if not self.version_info['is_debian']: + return "Note: This is not a Debian system. Debian Forge will use default Debian settings." + + if not self.version_info['is_supported']: + return f"Warning: Debian {self.version_info.get('version', 'unknown')} ({self.version_info.get('codename', 'unknown')}) is not officially supported. Debian Forge supports Debian 13+ (Trixie and newer)." + + if self.version_info['support_level'] == 'experimental': + return f"Warning: {self.version_info['codename']} is unstable. Use with caution for production builds." + + return None + + def print_version_info(self): + """Print detailed version information""" + print("Debian Version Detection:") + print("=" * 40) + + if not self.version_info['is_debian']: + print("System: Non-Debian system detected") + print("Status: Using default Debian Forge settings") + print(f"Recommended suite: {self.get_recommended_suite()}") + print(f"Mirror URL: {self.get_mirror_url()}") + return + + print(f"System: Debian") + print(f"Codename: {self.version_info.get('codename', 'unknown')}") + print(f"Version: {self.version_info.get('version', 'unknown')}") + print(f"Release: {self.version_info.get('release', 'unknown')}") + print(f"Supported: {self.version_info['is_supported']}") + print(f"Status: {self.version_info['support_status']}") + print(f"Support Level: {self.version_info['support_level']}") + + warning = self.get_support_warning() + if warning: + print(f"\nāš ļø {warning}") + + print(f"\nRecommended suite: {self.get_recommended_suite()}") + print(f"Mirror URL: {self.get_mirror_url()}") + + +# Global instance +version_detector = DebianVersionDetector() + + +def get_recommended_suite() -> str: + """Get recommended Debian suite (convenience function)""" + return version_detector.get_recommended_suite() + + +def get_mirror_url() -> str: + """Get appropriate Debian mirror URL (convenience function)""" + return version_detector.get_mirror_url() + + +def get_apt_sources() -> str: + """Get appropriate apt sources (convenience function)""" + return version_detector.get_apt_sources() + + +def is_version_supported() -> bool: + """Check if current Debian version is supported (convenience function)""" + return version_detector.version_info['is_supported'] + + +def is_debian_system() -> bool: + """Check if this is a Debian system (convenience function)""" + return version_detector.version_info['is_debian'] + + +def print_version_info(): + """Print version information (convenience function)""" + version_detector.print_version_info() + + +if __name__ == '__main__': + print_version_info() diff --git a/tools/debian-version-info b/tools/debian-version-info new file mode 100755 index 00000000..a1b5c770 --- /dev/null +++ b/tools/debian-version-info @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +""" +Debian Version Info Tool +Shows current Debian version information and compatibility status +""" + +import sys +import os + +# Add the project root to the Python path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) + +try: + from osbuild.version_detector import print_version_info, is_debian_system, get_recommended_suite + from osbuild.config_manager import config +except ImportError as e: + print(f"Error importing modules: {e}") + print("Make sure you're running this from the project root directory") + sys.exit(1) + + +def main(): + """Main function""" + print("šŸ” Debian Forge Version Information") + print("=" * 50) + + # Show version detection + print_version_info() + print() + + # Show configuration status + print("šŸ“‹ Configuration Status:") + print("=" * 30) + + if is_debian_system(): + print("āœ… Running on Debian system") + suite = get_recommended_suite() + print(f"šŸ“¦ Recommended suite: {suite}") + + # Check if suite is supported + if suite in ['trixie', 'forky', 'sid']: + print("āœ… Suite is officially supported") + else: + print("āš ļø Suite may have limited support") + else: + print("ā„¹ļø Running on non-Debian system") + print("šŸ“¦ Using default Debian Forge settings") + print(f"šŸ“¦ Default suite: {get_recommended_suite()}") + + print() + + # Show current configuration + print("āš™ļø Current Configuration:") + print("=" * 30) + print(f"Default suite: {config.get_build_setting('default_suite', 'not set')}") + print(f"Default arch: {config.get_build_setting('default_arch', 'not set')}") + print(f"APT proxy: {config.get_apt_proxy() or 'not set'}") + + print() + + # Show recommendations + print("šŸ’” Recommendations:") + print("=" * 30) + + if not is_debian_system(): + print("• Consider using a Debian system for best compatibility") + print("• Current system will use default Debian Forge settings") + else: + suite = get_recommended_suite() + if suite == 'trixie': + print("• āœ… Using stable Debian 13 (Trixie) - recommended for production") + elif suite == 'forky': + print("• šŸ”„ Using testing Debian 14 (Forky) - good for development") + elif suite == 'sid': + print("• āš ļø Using unstable (Sid) - use with caution") + else: + print(f"• āš ļø Using {suite} - may have limited support") + + print() + print("For more information, see config/README.md") + + +if __name__ == '__main__': + main()