Files
Pac-cogs/videoarchiver/utils/path_manager.py
pacnpal a4ca6e8ea6 Core Systems:
Component-based architecture with lifecycle management
Enhanced error handling and recovery mechanisms
Comprehensive state management and tracking
Event-driven architecture with monitoring
Queue Management:

Multiple processing strategies for different scenarios
Advanced state management with recovery
Comprehensive metrics and health monitoring
Sophisticated cleanup system with multiple strategies
Processing Pipeline:

Enhanced message handling with validation
Improved URL extraction and processing
Better queue management and monitoring
Advanced cleanup mechanisms
Overall Benefits:

Better code organization and maintainability
Improved error handling and recovery
Enhanced monitoring and reporting
More robust and reliable system
2024-11-16 05:01:29 +00:00

224 lines
7.6 KiB
Python

"""Path management utilities"""
import os
import tempfile
import shutil
import stat
import logging
import contextlib
import time
from typing import Generator, List, Optional
from pathlib import Path
from .exceptions import FileCleanupError
from .permission_manager import PermissionManager
logger = logging.getLogger("PathManager")
class TempDirectoryManager:
"""Manages temporary directory creation and cleanup"""
def __init__(self):
self.permission_manager = PermissionManager()
self.max_retries = 3
self.retry_delay = 1
async def create_temp_dir(self, prefix: str = "videoarchiver_") -> str:
"""Create a temporary directory with proper permissions
Args:
prefix: Prefix for temporary directory name
Returns:
str: Path to temporary directory
Raises:
FileCleanupError: If directory creation fails
"""
try:
# Create temp directory
temp_dir = tempfile.mkdtemp(prefix=prefix)
logger.debug(f"Created temporary directory: {temp_dir}")
# Set proper permissions
await self.permission_manager.set_permissions(
temp_dir,
stat.S_IRWXU, # rwx for user only
recursive=False
)
# Verify directory
if not await self._verify_directory(temp_dir):
raise FileCleanupError(f"Failed to verify temporary directory: {temp_dir}")
return temp_dir
except Exception as e:
logger.error(f"Error creating temporary directory: {e}")
raise FileCleanupError(f"Failed to create temporary directory: {str(e)}")
async def cleanup_temp_dir(self, temp_dir: str) -> List[str]:
"""Clean up a temporary directory
Args:
temp_dir: Path to temporary directory
Returns:
List[str]: List of any cleanup errors
"""
if not temp_dir or not os.path.exists(temp_dir):
return []
cleanup_errors = []
try:
# Set permissions recursively
await self._prepare_for_cleanup(temp_dir, cleanup_errors)
# Attempt cleanup with retries
for attempt in range(self.max_retries):
try:
# Remove directory
shutil.rmtree(temp_dir, ignore_errors=True)
# Verify removal
if not os.path.exists(temp_dir):
logger.debug(f"Successfully cleaned up temporary directory: {temp_dir}")
break
if attempt < self.max_retries - 1:
await self._retry_delay()
except Exception as e:
if attempt == self.max_retries - 1:
cleanup_errors.append(
f"Failed to clean up temporary directory {temp_dir} "
f"after {self.max_retries} attempts: {e}"
)
elif attempt < self.max_retries - 1:
await self._retry_delay()
continue
except Exception as e:
cleanup_errors.append(f"Error during temp directory cleanup: {str(e)}")
return cleanup_errors
async def _prepare_for_cleanup(
self,
temp_dir: str,
cleanup_errors: List[str]
) -> None:
"""Prepare directory for cleanup by setting permissions"""
for root, dirs, files in os.walk(temp_dir):
# Set directory permissions
for d in dirs:
try:
dir_path = os.path.join(root, d)
await self.permission_manager.set_permissions(
dir_path,
stat.S_IRWXU
)
except Exception as e:
cleanup_errors.append(
f"Failed to set permissions on directory {dir_path}: {e}"
)
# Set file permissions
for f in files:
try:
file_path = os.path.join(root, f)
await self.permission_manager.set_permissions(
file_path,
stat.S_IRWXU
)
except Exception as e:
cleanup_errors.append(
f"Failed to set permissions on file {file_path}: {e}"
)
async def _verify_directory(self, directory: str) -> bool:
"""Verify a directory exists and is writable"""
if not os.path.exists(directory):
return False
return await self.permission_manager.check_permissions(
directory,
require_writable=True,
require_readable=True,
require_executable=True
)
async def _retry_delay(self) -> None:
"""Sleep between retry attempts"""
await asyncio.sleep(self.retry_delay)
class PathManager:
"""Manages path operations and validation"""
def __init__(self):
self.temp_dir_manager = TempDirectoryManager()
@contextlib.asynccontextmanager
async def temp_path_context(
self,
prefix: str = "videoarchiver_"
) -> Generator[str, None, None]:
"""Async context manager for temporary path creation and cleanup
Args:
prefix: Prefix for temporary directory name
Yields:
str: Path to temporary directory
Raises:
FileCleanupError: If directory creation or cleanup fails
"""
temp_dir = None
try:
# Create temporary directory
temp_dir = await self.temp_dir_manager.create_temp_dir(prefix)
yield temp_dir
except FileCleanupError:
raise
except Exception as e:
logger.error(f"Error in temp_path_context: {str(e)}")
raise FileCleanupError(f"Temporary directory error: {str(e)}")
finally:
if temp_dir:
# Clean up directory
cleanup_errors = await self.temp_dir_manager.cleanup_temp_dir(temp_dir)
if cleanup_errors:
error_msg = "\n".join(cleanup_errors)
logger.error(error_msg)
# Don't raise here as we're in finally block
async def ensure_directory(self, directory: str) -> None:
"""Ensure a directory exists with proper permissions
Args:
directory: Path to ensure exists
Raises:
FileCleanupError: If directory cannot be created or accessed
"""
try:
path = Path(directory)
path.mkdir(parents=True, exist_ok=True)
# Set proper permissions
await self.temp_dir_manager.permission_manager.set_permissions(
directory,
stat.S_IRWXU
)
# Verify directory
if not await self.temp_dir_manager._verify_directory(directory):
raise FileCleanupError(f"Failed to verify directory: {directory}")
except Exception as e:
logger.error(f"Error ensuring directory {directory}: {e}")
raise FileCleanupError(f"Failed to ensure directory: {str(e)}")