refactor CLI command modules and synchronize docs
This commit is contained in:
+58
-2
@@ -40,6 +40,42 @@ def _is_sample_path(path: Path) -> bool:
|
||||
return bool(re.search(r"(^|[\s._-])sample($|[\s._-])", stem))
|
||||
|
||||
|
||||
def _analyze_directory_impact(operations: list[FileOperation]) -> dict:
|
||||
"""Analyze which directories will be emptied by the plan."""
|
||||
# Get all source directories that have files being moved/renamed
|
||||
source_dirs = set()
|
||||
moved_files = set()
|
||||
for operation in operations:
|
||||
if operation.operation_type in ("move", "rename"):
|
||||
source_dirs.add(operation.source_path.parent)
|
||||
moved_files.add(operation.source_path)
|
||||
|
||||
emptied_dirs = []
|
||||
for dir_path in source_dirs:
|
||||
# Only analyze directories that actually exist
|
||||
if not dir_path.exists():
|
||||
continue
|
||||
|
||||
# Count files that will remain in this directory after operations
|
||||
remaining_count = 0
|
||||
try:
|
||||
for item in dir_path.iterdir():
|
||||
if item.is_file() and item not in moved_files:
|
||||
remaining_count += 1
|
||||
except (OSError, PermissionError):
|
||||
# If we can't read the directory, skip analysis
|
||||
continue
|
||||
|
||||
# If no files will remain, this directory will be emptied
|
||||
if remaining_count == 0:
|
||||
emptied_dirs.append(dir_path)
|
||||
|
||||
return {
|
||||
"emptied_directories": emptied_dirs,
|
||||
"warning_required": len(emptied_dirs) > 0
|
||||
}
|
||||
|
||||
|
||||
def generate_plan(
|
||||
identities: list[tuple[VideoFile, Union[MovieIdentity, SeriesIdentity, None]]],
|
||||
config: Config,
|
||||
@@ -120,10 +156,29 @@ def generate_plan(
|
||||
conflict_reason=None,
|
||||
)
|
||||
|
||||
# Analyze directory impact and add preservation operations
|
||||
directory_analysis = _analyze_directory_impact(operations)
|
||||
if directory_analysis["warning_required"]:
|
||||
# Add directory preservation operations for emptied directories
|
||||
for emptied_dir in directory_analysis["emptied_directories"]:
|
||||
operations.append(FileOperation(
|
||||
operation_type="preserve-directory",
|
||||
source_path=emptied_dir,
|
||||
destination_path=None,
|
||||
reason=f"Preserve empty source directory: {emptied_dir.name}",
|
||||
has_conflict=False,
|
||||
conflict_reason=None
|
||||
))
|
||||
|
||||
summary = _generate_summary(operations)
|
||||
summary_by_reason = _generate_summary_by_reason(operations)
|
||||
human_summary = _generate_human_summary(operations, summary, summary_by_reason, metadata)
|
||||
|
||||
# Add directory warnings to metadata
|
||||
if directory_analysis["warning_required"]:
|
||||
metadata["emptied_directories"] = [str(d) for d in directory_analysis["emptied_directories"]]
|
||||
metadata["directory_warning"] = True
|
||||
|
||||
return ExecutionPlan(
|
||||
plan_id=str(uuid.uuid4()),
|
||||
created_at=utc_now(),
|
||||
@@ -445,9 +500,10 @@ def _generate_summary(operations: list[FileOperation]) -> dict:
|
||||
"move": 0,
|
||||
"rename": 0,
|
||||
"quarantine": 0,
|
||||
"no-op": 0
|
||||
"no-op": 0,
|
||||
"preserve-directory": 0
|
||||
}
|
||||
|
||||
|
||||
for operation in operations:
|
||||
op_type = operation.operation_type
|
||||
if op_type in summary:
|
||||
|
||||
Reference in New Issue
Block a user