Add utility modules: encryption, file_utils, git_utils, path_utils
Some checks failed
CI / test (push) Has been cancelled
CI / build (push) Has been cancelled

This commit is contained in:
2026-02-04 20:07:52 +00:00
parent 365259f895
commit d8cbe32f31

View File

@@ -0,0 +1,105 @@
"""File utility functions for ConfSync."""
import hashlib
import os
from pathlib import Path
from typing import List, Optional
def calculate_file_hash(content: str) -> str:
"""Calculate SHA256 hash of content."""
return hashlib.sha256(content.encode('utf-8')).hexdigest()
def read_file_safe(path: str, encoding: str = 'utf-8') -> Optional[str]:
"""Safely read a file, returning None on error."""
try:
with open(path, 'r', encoding=encoding) as f:
return f.read()
except (IOError, OSError, UnicodeDecodeError) as e:
print(f"Warning: Could not read file {path}: {e}")
return None
def write_file_safe(content: str, path: str, encoding: str = 'utf-8') -> bool:
"""Safely write to a file, returning success status."""
try:
Path(path).parent.mkdir(parents=True, exist_ok=True)
with open(path, 'w', encoding=encoding) as f:
f.write(content)
return True
except (IOError, OSError) as e:
print(f"Error: Could not write to file {path}: {e}")
return False
def find_files_matching(
base_path: str,
patterns: List[str],
recursive: bool = False
) -> List[str]:
"""Find files matching any of the given patterns."""
base = Path(base_path)
matches: List[str] = []
for pattern in patterns:
if recursive:
matches.extend(str(m) for m in base.rglob(pattern))
else:
matches.extend(str(m) for m in base.glob(pattern))
return list(set(matches))
def get_file_size(path: str) -> int:
"""Get file size in bytes."""
try:
return os.path.getsize(path)
except OSError:
return 0
def get_file_mtime(path: str) -> float:
"""Get file modification time."""
try:
return os.path.getmtime(path)
except OSError:
return 0
def ensure_directory(path: str) -> bool:
"""Ensure directory exists, creating if necessary."""
try:
Path(path).mkdir(parents=True, exist_ok=True)
return True
except OSError as e:
print(f"Error creating directory {path}: {e}")
return False
def normalize_line_endings(content: str, style: str = 'unix') -> str:
"""Normalize line endings to Unix (LF) or Windows (CRLF) style."""
if style == 'windows':
return content.replace('\n', '\r\n')
return content.replace('\r\n', '\n')
def is_binary_content(content: bytes) -> bool:
"""Check if content appears to be binary."""
text_chars = bytes([7, 8, 9, 10, 12, 13, 27]) + bytes(range(0x20, 0x100))
return bool(content.translate(None, text_chars))
def split_into_lines(content: str, max_line_length: int = 1000) -> List[str]:
"""Split content into lines, handling various formats."""
return content.splitlines()
def read_binary_file(path: str) -> Optional[bytes]:
"""Read a binary file, returning None on error."""
try:
with open(path, 'rb') as f:
return f.read()
except (IOError, OSError) as e:
print(f"Warning: Could not read binary file {path}: {e}")
return None