번역툴 2.0 업데이트
This commit is contained in:
161
lib/file_manager.py
Normal file
161
lib/file_manager.py
Normal file
@ -0,0 +1,161 @@
|
||||
"""
|
||||
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}')
|
||||
Reference in New Issue
Block a user