""" 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}')