Files
DS_L10N/lib/file_manager.py
2025-10-29 13:32:42 +09:00

162 lines
5.7 KiB
Python

"""
File Manager for DS_L10N
파일 자동 관리 및 정리
"""
import shutil
from pathlib import Path
from datetime import datetime, timedelta
from typing import List, Tuple
class FileManager:
"""파일 관리자"""
def __init__(self, config: dict, logger):
self.config = config
self.logger = logger
self.cleanup_config = config.get('cleanup', {})
def cleanup_old_files(self, target_dir: Path) -> Tuple[int, int]:
"""
오래된 파일 정리
Returns:
(archived_count, deleted_count)
"""
if not self.cleanup_config.get('auto_archive', True):
self.logger.info('자동 정리가 비활성화되어 있습니다.')
return 0, 0
keep_recent = self.cleanup_config.get('keep_recent_files', 5)
archive_patterns = self.cleanup_config.get('archive_patterns', [])
archive_dir = Path(self.config.get('paths', {}).get('archive_dir', './archive'))
archived_count = 0
self.logger.info(f'파일 정리 시작: {target_dir}')
self.logger.info(f'최근 {keep_recent}개 파일 유지, 나머지는 보관')
for pattern in archive_patterns:
files = sorted(target_dir.glob(pattern), key=lambda p: p.stat().st_mtime, reverse=True)
if len(files) <= keep_recent:
continue
# 오래된 파일들
old_files = files[keep_recent:]
for file_path in old_files:
archived = self._archive_file(file_path, archive_dir)
if archived:
archived_count += 1
# 오래된 로그 파일 삭제
logs_dir = Path(self.config.get('paths', {}).get('logs_dir', './logs'))
deleted_count = self._delete_old_logs(logs_dir)
if archived_count > 0:
self.logger.success(f'{archived_count}개 파일 보관 완료')
if deleted_count > 0:
self.logger.success(f'{deleted_count}개 오래된 로그 파일 삭제')
return archived_count, deleted_count
def _archive_file(self, file_path: Path, archive_dir: Path) -> bool:
"""파일을 archive 폴더로 이동"""
try:
archive_dir.mkdir(parents=True, exist_ok=True)
# 날짜별 하위 폴더
date_folder = archive_dir / datetime.now().strftime('%Y%m')
date_folder.mkdir(parents=True, exist_ok=True)
# 대상 경로
dest_path = date_folder / file_path.name
# 이미 존재하면 타임스탬프 추가
if dest_path.exists():
timestamp = datetime.now().strftime('%H%M%S')
dest_path = date_folder / f"{file_path.stem}_{timestamp}{file_path.suffix}"
shutil.move(str(file_path), str(dest_path))
self.logger.info(f' 📦 보관: {file_path.name}{dest_path.relative_to(archive_dir)}')
return True
except Exception as e:
self.logger.warning(f'파일 보관 실패: {file_path.name} - {e}')
return False
def _delete_old_logs(self, logs_dir: Path) -> int:
"""오래된 로그 파일 삭제"""
if not logs_dir.exists():
return 0
delete_days = self.cleanup_config.get('delete_old_logs_days', 30)
cutoff_date = datetime.now() - timedelta(days=delete_days)
deleted_count = 0
for log_file in logs_dir.glob('*.log'):
try:
mtime = datetime.fromtimestamp(log_file.stat().st_mtime)
if mtime < cutoff_date:
log_file.unlink()
self.logger.debug(f' 🗑️ 삭제: {log_file.name}')
deleted_count += 1
except Exception as e:
self.logger.warning(f'로그 파일 삭제 실패: {log_file.name} - {e}')
return deleted_count
def delete_old_backups(self, localization_root: Path) -> int:
"""오래된 백업 파일 삭제"""
keep_days = self.config.get('backup', {}).get('keep_backups_days', 7)
cutoff_date = datetime.now() - timedelta(days=keep_days)
deleted_count = 0
self.logger.info(f'백업 파일 정리 중 ({keep_days}일 이상 된 파일 삭제)...')
for lang_folder in localization_root.iterdir():
if not lang_folder.is_dir():
continue
for backup_file in lang_folder.glob('*.backup_*.po'):
try:
mtime = datetime.fromtimestamp(backup_file.stat().st_mtime)
if mtime < cutoff_date:
backup_file.unlink()
self.logger.debug(f' 🗑️ 백업 삭제: {backup_file.name}')
deleted_count += 1
except Exception as e:
self.logger.warning(f'백업 파일 삭제 실패: {backup_file.name} - {e}')
if deleted_count > 0:
self.logger.success(f'{deleted_count}개 백업 파일 삭제 완료')
return deleted_count
def ensure_directories(self):
"""필요한 디렉토리 생성"""
paths = [
Path(self.config.get('paths', {}).get('output_dir', './output')),
Path(self.config.get('paths', {}).get('logs_dir', './logs')),
Path(self.config.get('paths', {}).get('archive_dir', './archive')),
Path(self.config.get('paths', {}).get('temp_dir', './temp')),
]
for path in paths:
if not path.is_absolute():
# 상대 경로를 절대 경로로 변환
base_dir = Path(__file__).parent.parent
path = (base_dir / path).resolve()
path.mkdir(parents=True, exist_ok=True)
self.logger.debug(f'디렉토리 확인: {path}')