mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-20 10:51:05 -05:00
Updated extraction logic to handle BtbN's new archive structure with binaries in bin directory Added fallback to old structure for backward compatibility Improved binary verification and permissions handling Enhanced error handling during extraction and verification Fixed Exception Handling: Added missing FileCleanupError exception Updated file operations to use proper exceptions Improved error propagation and logging Better cleanup error handling Improved Resource Management: Better cleanup of failed downloads Proper handling of temporary files Enhanced queue management Improved file deletion with retries Enhanced Error Reporting: More detailed error messages Better logging of cleanup operations Proper error propagation through the system Improved user feedback The system now: Properly handles FFmpeg's new archive structure Better manages file operations and cleanup Provides more detailed error messages Cleans up resources properly Shows appropriate error messages for different failure types
99 lines
4.0 KiB
Python
99 lines
4.0 KiB
Python
"""Path management utilities"""
|
|
|
|
import os
|
|
import tempfile
|
|
import shutil
|
|
import stat
|
|
import logging
|
|
import contextlib
|
|
import time
|
|
|
|
from .exceptions import FileCleanupError
|
|
|
|
logger = logging.getLogger("VideoArchiver")
|
|
|
|
@contextlib.contextmanager
|
|
def temp_path_context():
|
|
"""Context manager for temporary path creation and cleanup
|
|
|
|
Yields:
|
|
str: Path to temporary directory
|
|
|
|
Raises:
|
|
FileCleanupError: If directory creation or cleanup fails
|
|
"""
|
|
temp_dir = None
|
|
try:
|
|
# Create temp directory with proper permissions
|
|
temp_dir = tempfile.mkdtemp(prefix="videoarchiver_")
|
|
logger.debug(f"Created temporary directory: {temp_dir}")
|
|
|
|
# Ensure directory has rwx permissions for user only
|
|
try:
|
|
os.chmod(temp_dir, stat.S_IRWXU)
|
|
except OSError as e:
|
|
raise FileCleanupError(f"Failed to set permissions on temporary directory: {str(e)}")
|
|
|
|
# Verify directory exists and is writable
|
|
if not os.path.exists(temp_dir):
|
|
raise FileCleanupError(f"Failed to create temporary directory: {temp_dir}")
|
|
if not os.access(temp_dir, os.W_OK):
|
|
raise FileCleanupError(f"Temporary directory is not writable: {temp_dir}")
|
|
|
|
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 and os.path.exists(temp_dir):
|
|
cleanup_errors = []
|
|
try:
|
|
# Ensure all files are deletable with retries
|
|
max_retries = 3
|
|
for attempt in range(max_retries):
|
|
try:
|
|
# Set permissions recursively
|
|
for root, dirs, files in os.walk(temp_dir):
|
|
for d in dirs:
|
|
try:
|
|
dir_path = os.path.join(root, d)
|
|
os.chmod(dir_path, stat.S_IRWXU)
|
|
except OSError as e:
|
|
cleanup_errors.append(f"Failed to set permissions on directory {dir_path}: {e}")
|
|
for f in files:
|
|
try:
|
|
file_path = os.path.join(root, f)
|
|
os.chmod(file_path, stat.S_IRWXU)
|
|
except OSError as e:
|
|
cleanup_errors.append(f"Failed to set permissions on file {file_path}: {e}")
|
|
|
|
# Try to remove the directory
|
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
|
|
|
# Verify directory is gone
|
|
if not os.path.exists(temp_dir):
|
|
logger.debug(f"Successfully cleaned up temporary directory: {temp_dir}")
|
|
break
|
|
|
|
if attempt < max_retries - 1:
|
|
time.sleep(1) # Wait before retry
|
|
|
|
except Exception as e:
|
|
if attempt == max_retries - 1:
|
|
cleanup_errors.append(f"Failed to clean up temporary directory {temp_dir} after {max_retries} attempts: {e}")
|
|
elif attempt < max_retries - 1:
|
|
time.sleep(1) # Wait before retry
|
|
continue
|
|
|
|
except Exception as e:
|
|
cleanup_errors.append(f"Error during temp directory cleanup: {str(e)}")
|
|
|
|
if cleanup_errors:
|
|
error_msg = "\n".join(cleanup_errors)
|
|
logger.error(error_msg)
|
|
# Don't raise here as we're in finally block and don't want to mask original error
|