68 lines
1.7 KiB
Python
68 lines
1.7 KiB
Python
"""File utilities."""
|
|
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
|
|
def read_file_safe(path: Path, encoding: str = "utf-8") -> Optional[str]:
|
|
"""Safely read a file, returning None on error."""
|
|
try:
|
|
return path.read_text(encoding=encoding)
|
|
except (OSError, UnicodeDecodeError):
|
|
return None
|
|
|
|
|
|
def find_translation_files(
|
|
path: Path,
|
|
patterns: Optional[List[str]] = None,
|
|
) -> List[Path]:
|
|
"""Find translation files in a directory."""
|
|
patterns = patterns or [
|
|
"**/*.json",
|
|
"**/*.po",
|
|
"**/*.pot",
|
|
"**/*.yaml",
|
|
"**/*.yml",
|
|
]
|
|
|
|
files = []
|
|
for pattern in patterns:
|
|
files.extend(path.rglob(pattern))
|
|
|
|
return sorted(set(files))
|
|
|
|
|
|
def is_text_file(path: Path, chunk_size: int = 8192) -> bool:
|
|
"""Check if a file is a text file."""
|
|
try:
|
|
with open(path, "rb") as f:
|
|
chunk = f.read(chunk_size)
|
|
if b"\x00" in chunk:
|
|
return False
|
|
return True
|
|
except OSError:
|
|
return False
|
|
|
|
|
|
def backup_file(path: Path) -> Path:
|
|
"""Create a backup of a file."""
|
|
backup_path = path.with_suffix(path.suffix + ".bak")
|
|
if backup_path.exists():
|
|
counter = 1
|
|
while backup_path.exists():
|
|
backup_path = path.with_suffix(f"{path.suffix}.bak{counter}")
|
|
counter += 1
|
|
|
|
backup_path.write_bytes(path.read_bytes())
|
|
return backup_path
|
|
|
|
|
|
def restore_backup(backup_path: Path, original_path: Path) -> bool:
|
|
"""Restore a file from backup."""
|
|
try:
|
|
original_path.write_bytes(backup_path.read_bytes())
|
|
backup_path.unlink()
|
|
return True
|
|
except OSError:
|
|
return False
|