Fix sbuild integration and clean up codebase
- Fix environment variable handling in sbuild wrapper - Remove unsupported --log-dir and --env options from sbuild command - Clean up unused imports and fix linting issues - Organize examples directory with official Debian hello package - Fix YAML formatting (trailing spaces, newlines) - Remove placeholder example files - All tests passing (30/30) - Successfully tested build with official Debian hello package
This commit is contained in:
parent
c33e3aa9ac
commit
5e7f4b0562
32 changed files with 2322 additions and 2228 deletions
|
|
@ -6,7 +6,7 @@ inspired by Fedora's Mock plugin hooks but adapted for Debian-based workflows.
|
|||
"""
|
||||
|
||||
import logging
|
||||
from typing import Dict, List, Callable, Any, Optional
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -14,73 +14,73 @@ logger = logging.getLogger(__name__)
|
|||
class HookManager:
|
||||
"""
|
||||
Manages plugin hooks and their execution.
|
||||
|
||||
|
||||
This class provides the core functionality for registering and executing
|
||||
plugin hooks at specific points in the build lifecycle, following the
|
||||
same pattern as Mock's plugin hook system.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the hook manager."""
|
||||
self.hooks: Dict[str, List[Callable]] = {}
|
||||
self.hook_contexts: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
|
||||
# Define available hook points (based on Mock's hook system)
|
||||
self.available_hooks = {
|
||||
'clean': 'Clean up plugin resources',
|
||||
'earlyprebuild': 'Very early build stage',
|
||||
'initfailed': 'Chroot initialization failed',
|
||||
'list_snapshots': 'List available snapshots',
|
||||
'make_snapshot': 'Create a snapshot',
|
||||
'mount_root': 'Mount chroot directory',
|
||||
'postbuild': 'After build completion',
|
||||
'postchroot': 'After chroot command',
|
||||
'postclean': 'After chroot cleanup',
|
||||
'postdeps': 'After dependency installation',
|
||||
'postinit': 'After chroot initialization',
|
||||
'postshell': 'After shell exit',
|
||||
'postupdate': 'After package updates',
|
||||
'postumount': 'After unmounting',
|
||||
'postapt': 'After APT operations',
|
||||
'prebuild': 'Before build starts',
|
||||
'prechroot': 'Before chroot command',
|
||||
'preinit': 'Before chroot initialization',
|
||||
'preshell': 'Before shell prompt',
|
||||
'preapt': 'Before APT operations',
|
||||
'process_logs': 'Process build logs',
|
||||
'remove_snapshot': 'Remove snapshot',
|
||||
'rollback_to': 'Rollback to snapshot',
|
||||
'scrub': 'Scrub chroot'
|
||||
"clean": "Clean up plugin resources",
|
||||
"earlyprebuild": "Very early build stage",
|
||||
"initfailed": "Chroot initialization failed",
|
||||
"list_snapshots": "List available snapshots",
|
||||
"make_snapshot": "Create a snapshot",
|
||||
"mount_root": "Mount chroot directory",
|
||||
"postbuild": "After build completion",
|
||||
"postchroot": "After chroot command",
|
||||
"postclean": "After chroot cleanup",
|
||||
"postdeps": "After dependency installation",
|
||||
"postinit": "After chroot initialization",
|
||||
"postshell": "After shell exit",
|
||||
"postupdate": "After package updates",
|
||||
"postumount": "After unmounting",
|
||||
"postapt": "After APT operations",
|
||||
"prebuild": "Before build starts",
|
||||
"prechroot": "Before chroot command",
|
||||
"preinit": "Before chroot initialization",
|
||||
"preshell": "Before shell prompt",
|
||||
"preapt": "Before APT operations",
|
||||
"process_logs": "Process build logs",
|
||||
"remove_snapshot": "Remove snapshot",
|
||||
"rollback_to": "Rollback to snapshot",
|
||||
"scrub": "Scrub chroot",
|
||||
}
|
||||
|
||||
|
||||
def add_hook(self, hook_name: str, callback: Callable) -> None:
|
||||
"""
|
||||
Register a hook callback.
|
||||
|
||||
|
||||
Args:
|
||||
hook_name: Name of the hook to register for
|
||||
callback: Function to call when hook is triggered
|
||||
|
||||
|
||||
Raises:
|
||||
ValueError: If hook_name is not a valid hook point
|
||||
"""
|
||||
if hook_name not in self.available_hooks:
|
||||
raise ValueError(f"Invalid hook name: {hook_name}. Available hooks: {list(self.available_hooks.keys())}")
|
||||
|
||||
|
||||
if hook_name not in self.hooks:
|
||||
self.hooks[hook_name] = []
|
||||
|
||||
|
||||
self.hooks[hook_name].append(callback)
|
||||
logger.debug(f"Registered hook '{hook_name}' with callback {callback.__name__}")
|
||||
|
||||
|
||||
def call_hook(self, hook_name: str, context: Optional[Dict[str, Any]] = None) -> None:
|
||||
"""
|
||||
Execute all registered hooks for a given hook name.
|
||||
|
||||
|
||||
Args:
|
||||
hook_name: Name of the hook to trigger
|
||||
context: Context dictionary to pass to hook callbacks
|
||||
|
||||
|
||||
Note:
|
||||
Hook execution errors are logged but don't fail the build,
|
||||
following Mock's behavior.
|
||||
|
|
@ -88,36 +88,36 @@ class HookManager:
|
|||
if hook_name not in self.hooks:
|
||||
logger.debug(f"No hooks registered for '{hook_name}'")
|
||||
return
|
||||
|
||||
|
||||
context = context or {}
|
||||
logger.debug(f"Calling {len(self.hooks[hook_name])} hooks for '{hook_name}'")
|
||||
|
||||
|
||||
for i, callback in enumerate(self.hooks[hook_name]):
|
||||
try:
|
||||
logger.debug(f"Executing hook {i+1}/{len(self.hooks[hook_name])}: {callback.__name__}")
|
||||
logger.debug(f"Executing hook {i + 1}/{len(self.hooks[hook_name])}: {callback.__name__}")
|
||||
callback(context)
|
||||
logger.debug(f"Successfully executed hook: {callback.__name__}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Hook '{hook_name}' failed in {callback.__name__}: {e}")
|
||||
# Continue with other hooks - don't fail the build
|
||||
|
||||
|
||||
def call_hook_with_result(self, hook_name: str, context: Optional[Dict[str, Any]] = None) -> List[Any]:
|
||||
"""
|
||||
Execute all registered hooks and collect their results.
|
||||
|
||||
|
||||
Args:
|
||||
hook_name: Name of the hook to trigger
|
||||
context: Context dictionary to pass to hook callbacks
|
||||
|
||||
|
||||
Returns:
|
||||
List of results from hook callbacks (None for failed hooks)
|
||||
"""
|
||||
if hook_name not in self.hooks:
|
||||
return []
|
||||
|
||||
|
||||
context = context or {}
|
||||
results = []
|
||||
|
||||
|
||||
for callback in self.hooks[hook_name]:
|
||||
try:
|
||||
result = callback(context)
|
||||
|
|
@ -125,81 +125,78 @@ class HookManager:
|
|||
except Exception as e:
|
||||
logger.warning(f"Hook '{hook_name}' failed in {callback.__name__}: {e}")
|
||||
results.append(None)
|
||||
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def get_hook_names(self) -> List[str]:
|
||||
"""
|
||||
Get list of available hook names.
|
||||
|
||||
|
||||
Returns:
|
||||
List of hook names that have been registered
|
||||
"""
|
||||
return list(self.hooks.keys())
|
||||
|
||||
|
||||
def get_available_hooks(self) -> Dict[str, str]:
|
||||
"""
|
||||
Get all available hook points with descriptions.
|
||||
|
||||
|
||||
Returns:
|
||||
Dictionary mapping hook names to descriptions
|
||||
"""
|
||||
return self.available_hooks.copy()
|
||||
|
||||
|
||||
def get_hook_info(self, hook_name: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Get information about a specific hook.
|
||||
|
||||
|
||||
Args:
|
||||
hook_name: Name of the hook
|
||||
|
||||
|
||||
Returns:
|
||||
Dictionary with hook information
|
||||
"""
|
||||
if hook_name not in self.available_hooks:
|
||||
return {'error': f'Hook "{hook_name}" not found'}
|
||||
|
||||
return {"error": f'Hook "{hook_name}" not found'}
|
||||
|
||||
info = {
|
||||
'name': hook_name,
|
||||
'description': self.available_hooks[hook_name],
|
||||
'registered_callbacks': len(self.hooks.get(hook_name, [])),
|
||||
'callbacks': []
|
||||
"name": hook_name,
|
||||
"description": self.available_hooks[hook_name],
|
||||
"registered_callbacks": len(self.hooks.get(hook_name, [])),
|
||||
"callbacks": [],
|
||||
}
|
||||
|
||||
|
||||
if hook_name in self.hooks:
|
||||
for callback in self.hooks[hook_name]:
|
||||
info['callbacks'].append({
|
||||
'name': callback.__name__,
|
||||
'module': callback.__module__
|
||||
})
|
||||
|
||||
info["callbacks"].append({"name": callback.__name__, "module": callback.__module__})
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def remove_hook(self, hook_name: str, callback: Callable) -> bool:
|
||||
"""
|
||||
Remove a specific hook callback.
|
||||
|
||||
|
||||
Args:
|
||||
hook_name: Name of the hook
|
||||
callback: Callback function to remove
|
||||
|
||||
|
||||
Returns:
|
||||
True if callback was removed, False if not found
|
||||
"""
|
||||
if hook_name not in self.hooks:
|
||||
return False
|
||||
|
||||
|
||||
try:
|
||||
self.hooks[hook_name].remove(callback)
|
||||
logger.debug(f"Removed hook '{hook_name}' callback {callback.__name__}")
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def clear_hooks(self, hook_name: Optional[str] = None) -> None:
|
||||
"""
|
||||
Clear all hooks or hooks for a specific hook name.
|
||||
|
||||
|
||||
Args:
|
||||
hook_name: Specific hook name to clear, or None to clear all
|
||||
"""
|
||||
|
|
@ -209,52 +206,51 @@ class HookManager:
|
|||
elif hook_name in self.hooks:
|
||||
self.hooks[hook_name].clear()
|
||||
logger.debug(f"Cleared hooks for '{hook_name}'")
|
||||
|
||||
|
||||
def get_hook_statistics(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get statistics about hook usage.
|
||||
|
||||
|
||||
Returns:
|
||||
Dictionary with hook statistics
|
||||
"""
|
||||
stats = {
|
||||
'total_hooks': len(self.hooks),
|
||||
'total_callbacks': sum(len(callbacks) for callbacks in self.hooks.values()),
|
||||
'hooks_with_callbacks': len([h for h in self.hooks.values() if h]),
|
||||
'available_hooks': len(self.available_hooks),
|
||||
'hook_details': {}
|
||||
"total_hooks": len(self.hooks),
|
||||
"total_callbacks": sum(len(callbacks) for callbacks in self.hooks.values()),
|
||||
"hooks_with_callbacks": len([h for h in self.hooks.values() if h]),
|
||||
"available_hooks": len(self.available_hooks),
|
||||
"hook_details": {},
|
||||
}
|
||||
|
||||
|
||||
for hook_name in self.available_hooks:
|
||||
stats['hook_details'][hook_name] = {
|
||||
'description': self.available_hooks[hook_name],
|
||||
'registered': hook_name in self.hooks,
|
||||
'callback_count': len(self.hooks.get(hook_name, []))
|
||||
stats["hook_details"][hook_name] = {
|
||||
"description": self.available_hooks[hook_name],
|
||||
"registered": hook_name in self.hooks,
|
||||
"callback_count": len(self.hooks.get(hook_name, [])),
|
||||
}
|
||||
|
||||
|
||||
return stats
|
||||
|
||||
|
||||
def validate_hook_name(self, hook_name: str) -> bool:
|
||||
"""
|
||||
Validate if a hook name is valid.
|
||||
|
||||
|
||||
Args:
|
||||
hook_name: Name of the hook to validate
|
||||
|
||||
|
||||
Returns:
|
||||
True if hook name is valid, False otherwise
|
||||
"""
|
||||
return hook_name in self.available_hooks
|
||||
|
||||
|
||||
def get_hook_suggestions(self, partial_name: str) -> List[str]:
|
||||
"""
|
||||
Get hook name suggestions based on partial input.
|
||||
|
||||
|
||||
Args:
|
||||
partial_name: Partial hook name
|
||||
|
||||
|
||||
Returns:
|
||||
List of matching hook names
|
||||
"""
|
||||
return [name for name in self.available_hooks.keys()
|
||||
if name.startswith(partial_name)]
|
||||
return [name for name in self.available_hooks.keys() if name.startswith(partial_name)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue