Add utility modules: encryption, file_utils, git_utils, path_utils
This commit is contained in:
105
confsync/utils/file_utils.py
Normal file
105
confsync/utils/file_utils.py
Normal 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
|
||||
Reference in New Issue
Block a user