feat: feedback verbetering
This commit is contained in:
+314
-150
@@ -16,18 +16,18 @@ class TaskRunner:
|
||||
self._filesystem = filesystem
|
||||
self._history_repository = history_repository
|
||||
|
||||
def enqueue_copy_file(self, task_id: str, source: str, destination: str, total_bytes: int) -> None:
|
||||
def enqueue_copy_file(self, task_id: str, source: str, destination: str, total_bytes: int, current_item: str) -> None:
|
||||
thread = threading.Thread(
|
||||
target=self._run_copy_file,
|
||||
args=(task_id, source, destination, total_bytes),
|
||||
args=(task_id, source, destination, total_bytes, current_item),
|
||||
daemon=True,
|
||||
)
|
||||
thread.start()
|
||||
|
||||
def enqueue_copy_directory(self, task_id: str, source: str, destination: str) -> None:
|
||||
def enqueue_copy_directory(self, task_id: str, item: dict[str, object]) -> None:
|
||||
thread = threading.Thread(
|
||||
target=self._run_copy_directory,
|
||||
args=(task_id, source, destination),
|
||||
args=(task_id, item),
|
||||
daemon=True,
|
||||
)
|
||||
thread.start()
|
||||
@@ -47,18 +47,19 @@ class TaskRunner:
|
||||
destination: str,
|
||||
total_bytes: int,
|
||||
same_root: bool,
|
||||
current_item: str,
|
||||
) -> None:
|
||||
thread = threading.Thread(
|
||||
target=self._run_move_file,
|
||||
args=(task_id, source, destination, total_bytes, same_root),
|
||||
args=(task_id, source, destination, total_bytes, same_root, current_item),
|
||||
daemon=True,
|
||||
)
|
||||
thread.start()
|
||||
|
||||
def enqueue_move_directory(self, task_id: str, source: str, destination: str) -> None:
|
||||
def enqueue_move_directory(self, task_id: str, item: dict[str, object]) -> None:
|
||||
thread = threading.Thread(
|
||||
target=self._run_move_directory,
|
||||
args=(task_id, source, destination),
|
||||
args=(task_id, item),
|
||||
daemon=True,
|
||||
)
|
||||
thread.start()
|
||||
@@ -94,14 +95,16 @@ class TaskRunner:
|
||||
)
|
||||
thread.start()
|
||||
|
||||
def _run_copy_file(self, task_id: str, source: str, destination: str, total_bytes: int) -> None:
|
||||
def _run_copy_file(self, task_id: str, source: str, destination: str, total_bytes: int, current_item: str) -> None:
|
||||
if not self._repository.mark_running(
|
||||
task_id=task_id,
|
||||
done_bytes=0,
|
||||
total_bytes=total_bytes,
|
||||
current_item=source,
|
||||
done_items=0,
|
||||
total_items=1,
|
||||
current_item=current_item,
|
||||
):
|
||||
self._finalize_if_already_cancelled(task_id, done_bytes=0, total_bytes=total_bytes)
|
||||
self._finalize_if_already_cancelled(task_id, done_bytes=0, total_bytes=total_bytes, done_items=0, total_items=1)
|
||||
return
|
||||
|
||||
progress = {"done": 0}
|
||||
@@ -112,7 +115,9 @@ class TaskRunner:
|
||||
task_id=task_id,
|
||||
done_bytes=done_bytes,
|
||||
total_bytes=total_bytes,
|
||||
current_item=source,
|
||||
done_items=0,
|
||||
total_items=1,
|
||||
current_item=current_item,
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -121,32 +126,6 @@ class TaskRunner:
|
||||
task_id=task_id,
|
||||
done_bytes=total_bytes,
|
||||
total_bytes=total_bytes,
|
||||
)
|
||||
except OSError as exc:
|
||||
self._repository.mark_failed(
|
||||
task_id=task_id,
|
||||
error_code="io_error",
|
||||
error_message=str(exc),
|
||||
failed_item=source,
|
||||
done_bytes=progress["done"],
|
||||
total_bytes=total_bytes,
|
||||
)
|
||||
self._update_history_failed(task_id, str(exc))
|
||||
|
||||
def _run_copy_directory(self, task_id: str, source: str, destination: str) -> None:
|
||||
if not self._repository.mark_running(
|
||||
task_id=task_id,
|
||||
done_items=0,
|
||||
total_items=1,
|
||||
current_item=source,
|
||||
):
|
||||
self._finalize_if_already_cancelled(task_id, done_items=0, total_items=1)
|
||||
return
|
||||
|
||||
try:
|
||||
self._filesystem.copy_directory(source=source, destination=destination)
|
||||
self._complete_or_cancel_item_task(
|
||||
task_id=task_id,
|
||||
done_items=1,
|
||||
total_items=1,
|
||||
)
|
||||
@@ -156,16 +135,58 @@ class TaskRunner:
|
||||
error_code="io_error",
|
||||
error_message=str(exc),
|
||||
failed_item=source,
|
||||
done_bytes=None,
|
||||
total_bytes=None,
|
||||
done_bytes=progress["done"],
|
||||
total_bytes=total_bytes,
|
||||
done_items=0,
|
||||
total_items=1,
|
||||
)
|
||||
self._update_history_failed(task_id, str(exc))
|
||||
|
||||
def _run_copy_directory(self, task_id: str, item: dict[str, object]) -> None:
|
||||
files = self._file_entries(item)
|
||||
directories = self._directory_entries(item)
|
||||
total_items = len(files)
|
||||
if not self._repository.mark_running(
|
||||
task_id=task_id,
|
||||
done_items=0,
|
||||
total_items=total_items,
|
||||
current_item=files[0]["label"] if files else None,
|
||||
):
|
||||
self._finalize_if_already_cancelled(task_id, done_items=0, total_items=total_items)
|
||||
return
|
||||
|
||||
try:
|
||||
completed_items = self._copy_directory_files(
|
||||
directories,
|
||||
files,
|
||||
task_id=task_id,
|
||||
completed_items=0,
|
||||
total_items=total_items,
|
||||
)
|
||||
if self._is_cancel_requested(task_id):
|
||||
self._finalize_cancelled(task_id, done_items=completed_items, total_items=total_items)
|
||||
return
|
||||
self._complete_or_cancel_item_task(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
)
|
||||
except OSError as exc:
|
||||
self._repository.mark_failed(
|
||||
task_id=task_id,
|
||||
error_code="io_error",
|
||||
error_message=str(exc),
|
||||
failed_item=str(item["source"]),
|
||||
done_bytes=None,
|
||||
total_bytes=None,
|
||||
done_items=self._completed_files(task_id),
|
||||
total_items=total_items,
|
||||
)
|
||||
self._update_history_failed(task_id, str(exc))
|
||||
|
||||
def _run_copy_batch(self, task_id: str, items: list[dict[str, str]]) -> None:
|
||||
total_items = len(items)
|
||||
current_item = items[0]["source"] if items else None
|
||||
total_items = self._total_file_count(items)
|
||||
current_item = self._first_file_label(items)
|
||||
if not self._repository.mark_running(
|
||||
task_id=task_id,
|
||||
done_items=0,
|
||||
@@ -180,21 +201,12 @@ class TaskRunner:
|
||||
if self._is_cancel_requested(task_id):
|
||||
self._finalize_cancelled(task_id, done_items=completed_items, total_items=total_items)
|
||||
return
|
||||
source = item["source"]
|
||||
destination = item["destination"]
|
||||
try:
|
||||
if item["kind"] == "directory":
|
||||
self._filesystem.copy_directory(source=source, destination=destination)
|
||||
completed_items = self._copy_directory_item(task_id, item, completed_items, total_items)
|
||||
else:
|
||||
self._filesystem.copy_file(source=source, destination=destination)
|
||||
completed_items = index + 1
|
||||
next_item = items[index + 1]["source"] if index + 1 < total_items else source
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=next_item,
|
||||
)
|
||||
file_entry = self._file_entries(item)[0]
|
||||
completed_items = self._copy_single_planned_file(task_id, file_entry, completed_items, total_items)
|
||||
if self._is_cancel_requested(task_id):
|
||||
self._finalize_cancelled(task_id, done_items=completed_items, total_items=total_items)
|
||||
return
|
||||
@@ -203,7 +215,7 @@ class TaskRunner:
|
||||
task_id=task_id,
|
||||
error_code="io_error",
|
||||
error_message=str(exc),
|
||||
failed_item=source,
|
||||
failed_item=str(item["source"]),
|
||||
done_bytes=None,
|
||||
total_bytes=None,
|
||||
done_items=completed_items,
|
||||
@@ -225,14 +237,17 @@ class TaskRunner:
|
||||
destination: str,
|
||||
total_bytes: int,
|
||||
same_root: bool,
|
||||
current_item: str,
|
||||
) -> None:
|
||||
if not self._repository.mark_running(
|
||||
task_id=task_id,
|
||||
done_bytes=0,
|
||||
total_bytes=total_bytes,
|
||||
current_item=source,
|
||||
done_items=0,
|
||||
total_items=1,
|
||||
current_item=current_item,
|
||||
):
|
||||
self._finalize_if_already_cancelled(task_id, done_bytes=0, total_bytes=total_bytes)
|
||||
self._finalize_if_already_cancelled(task_id, done_bytes=0, total_bytes=total_bytes, done_items=0, total_items=1)
|
||||
return
|
||||
|
||||
progress = {"done": 0}
|
||||
@@ -244,6 +259,8 @@ class TaskRunner:
|
||||
task_id=task_id,
|
||||
done_bytes=total_bytes,
|
||||
total_bytes=total_bytes,
|
||||
done_items=1,
|
||||
total_items=1,
|
||||
)
|
||||
return
|
||||
|
||||
@@ -253,7 +270,9 @@ class TaskRunner:
|
||||
task_id=task_id,
|
||||
done_bytes=done_bytes,
|
||||
total_bytes=total_bytes,
|
||||
current_item=source,
|
||||
done_items=0,
|
||||
total_items=1,
|
||||
current_item=current_item,
|
||||
)
|
||||
|
||||
self._filesystem.copy_file(source=source, destination=destination, on_progress=on_progress)
|
||||
@@ -262,32 +281,6 @@ class TaskRunner:
|
||||
task_id=task_id,
|
||||
done_bytes=total_bytes,
|
||||
total_bytes=total_bytes,
|
||||
)
|
||||
except OSError as exc:
|
||||
self._repository.mark_failed(
|
||||
task_id=task_id,
|
||||
error_code="io_error",
|
||||
error_message=str(exc),
|
||||
failed_item=source,
|
||||
done_bytes=progress["done"],
|
||||
total_bytes=total_bytes,
|
||||
)
|
||||
self._update_history_failed(task_id, str(exc))
|
||||
|
||||
def _run_move_directory(self, task_id: str, source: str, destination: str) -> None:
|
||||
if not self._repository.mark_running(
|
||||
task_id=task_id,
|
||||
done_items=0,
|
||||
total_items=1,
|
||||
current_item=source,
|
||||
):
|
||||
self._finalize_if_already_cancelled(task_id, done_items=0, total_items=1)
|
||||
return
|
||||
|
||||
try:
|
||||
self._filesystem.move_directory(source=source, destination=destination)
|
||||
self._complete_or_cancel_item_task(
|
||||
task_id=task_id,
|
||||
done_items=1,
|
||||
total_items=1,
|
||||
)
|
||||
@@ -297,14 +290,56 @@ class TaskRunner:
|
||||
error_code="io_error",
|
||||
error_message=str(exc),
|
||||
failed_item=source,
|
||||
done_bytes=progress["done"],
|
||||
total_bytes=total_bytes,
|
||||
done_items=0,
|
||||
total_items=1,
|
||||
)
|
||||
self._update_history_failed(task_id, str(exc))
|
||||
|
||||
def _run_move_directory(self, task_id: str, item: dict[str, object]) -> None:
|
||||
files = self._file_entries(item)
|
||||
directories = self._directory_entries(item)
|
||||
total_items = len(files)
|
||||
if not self._repository.mark_running(
|
||||
task_id=task_id,
|
||||
done_items=0,
|
||||
total_items=total_items,
|
||||
current_item=files[0]["label"] if files else None,
|
||||
):
|
||||
self._finalize_if_already_cancelled(task_id, done_items=0, total_items=total_items)
|
||||
return
|
||||
|
||||
try:
|
||||
completed_items = self._move_directory_files(
|
||||
directories,
|
||||
files,
|
||||
task_id=task_id,
|
||||
completed_items=0,
|
||||
total_items=total_items,
|
||||
)
|
||||
if self._is_cancel_requested(task_id):
|
||||
self._finalize_cancelled(task_id, done_items=completed_items, total_items=total_items)
|
||||
return
|
||||
self._complete_or_cancel_item_task(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
)
|
||||
except OSError as exc:
|
||||
self._repository.mark_failed(
|
||||
task_id=task_id,
|
||||
error_code="io_error",
|
||||
error_message=str(exc),
|
||||
failed_item=str(item["source"]),
|
||||
done_items=self._completed_files(task_id),
|
||||
total_items=total_items,
|
||||
)
|
||||
self._update_history_failed(task_id, str(exc))
|
||||
|
||||
def _run_move_batch(self, task_id: str, items: list[dict[str, str]]) -> None:
|
||||
total_items = len(items)
|
||||
current_item = items[0]["source"] if items else None
|
||||
total_items = self._total_file_count(items)
|
||||
current_item = self._first_file_label(items)
|
||||
if not self._repository.mark_running(
|
||||
task_id=task_id,
|
||||
done_items=0,
|
||||
@@ -319,21 +354,12 @@ class TaskRunner:
|
||||
if self._is_cancel_requested(task_id):
|
||||
self._finalize_cancelled(task_id, done_items=completed_items, total_items=total_items)
|
||||
return
|
||||
source = item["source"]
|
||||
destination = item["destination"]
|
||||
try:
|
||||
if item["kind"] == "directory":
|
||||
self._filesystem.move_directory(source=source, destination=destination)
|
||||
completed_items = self._move_directory_item(task_id, item, completed_items, total_items)
|
||||
else:
|
||||
self._filesystem.move_file(source=source, destination=destination)
|
||||
completed_items = index + 1
|
||||
next_item = items[index + 1]["source"] if index + 1 < total_items else source
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=next_item,
|
||||
)
|
||||
file_entry = self._file_entries(item)[0]
|
||||
completed_items = self._move_single_planned_file(task_id, file_entry, completed_items, total_items)
|
||||
if self._is_cancel_requested(task_id):
|
||||
self._finalize_cancelled(task_id, done_items=completed_items, total_items=total_items)
|
||||
return
|
||||
@@ -342,7 +368,7 @@ class TaskRunner:
|
||||
task_id=task_id,
|
||||
error_code="io_error",
|
||||
error_message=str(exc),
|
||||
failed_item=source,
|
||||
failed_item=str(item["source"]),
|
||||
done_bytes=None,
|
||||
total_bytes=None,
|
||||
done_items=completed_items,
|
||||
@@ -358,8 +384,8 @@ class TaskRunner:
|
||||
)
|
||||
|
||||
def _run_duplicate_batch(self, task_id: str, items: list[dict[str, str]]) -> None:
|
||||
total_items = len(items)
|
||||
current_item = items[0]["source"] if items else None
|
||||
total_items = self._total_file_count(items)
|
||||
current_item = self._first_file_label(items)
|
||||
if not self._repository.mark_running(
|
||||
task_id=task_id,
|
||||
done_items=0,
|
||||
@@ -374,31 +400,25 @@ class TaskRunner:
|
||||
if self._is_cancel_requested(task_id):
|
||||
self._finalize_cancelled(task_id, done_items=completed_items, total_items=total_items)
|
||||
return
|
||||
source = item["source"]
|
||||
destination = item["destination"]
|
||||
try:
|
||||
if item["kind"] == "directory":
|
||||
self._duplicate_directory(source=Path(source), destination=Path(destination))
|
||||
completed_items = self._copy_directory_item(task_id, item, completed_items, total_items, cleanup_on_failure=True)
|
||||
else:
|
||||
self._filesystem.copy_file(source=source, destination=destination)
|
||||
completed_items = index + 1
|
||||
next_item = items[index + 1]["source"] if index + 1 < total_items else source
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=next_item,
|
||||
)
|
||||
file_entry = self._file_entries(item)[0]
|
||||
completed_items = self._copy_single_planned_file(task_id, file_entry, completed_items, total_items)
|
||||
if self._is_cancel_requested(task_id):
|
||||
self._finalize_cancelled(task_id, done_items=completed_items, total_items=total_items)
|
||||
return
|
||||
except OSError as exc:
|
||||
self._cleanup_partial_duplicate(Path(destination))
|
||||
if item["kind"] == "directory":
|
||||
self._cleanup_partial_duplicate(Path(str(item["destination"])))
|
||||
else:
|
||||
self._cleanup_partial_duplicate(Path(self._file_entries(item)[0]["destination"]))
|
||||
self._repository.mark_failed(
|
||||
task_id=task_id,
|
||||
error_code="io_error",
|
||||
error_message=str(exc),
|
||||
failed_item=source,
|
||||
failed_item=str(item["source"]),
|
||||
done_bytes=None,
|
||||
total_bytes=None,
|
||||
done_items=completed_items,
|
||||
@@ -449,40 +469,6 @@ class TaskRunner:
|
||||
)
|
||||
self._update_history_failed(task_id, str(exc))
|
||||
|
||||
def _duplicate_directory(self, source: Path, destination: Path) -> None:
|
||||
destination.mkdir()
|
||||
copied_directories: list[tuple[Path, Path]] = [(source, destination)]
|
||||
try:
|
||||
for root, dirnames, filenames in os.walk(source, topdown=True, followlinks=False):
|
||||
root_path = Path(root)
|
||||
target_root = destination / root_path.relative_to(source)
|
||||
dirnames[:] = [name for name in dirnames if not name.startswith("._")]
|
||||
|
||||
for name in dirnames:
|
||||
source_dir = root_path / name
|
||||
if source_dir.is_symlink():
|
||||
raise OSError("Source directory must not contain symlinks")
|
||||
target_dir = target_root / name
|
||||
target_dir.mkdir()
|
||||
copied_directories.append((source_dir, target_dir))
|
||||
|
||||
for name in filenames:
|
||||
if name.startswith("._"):
|
||||
continue
|
||||
source_file = root_path / name
|
||||
if source_file.is_symlink():
|
||||
raise OSError("Source directory must not contain symlinks")
|
||||
self._filesystem.copy_file(
|
||||
source=str(source_file),
|
||||
destination=str(target_root / name),
|
||||
)
|
||||
|
||||
for source_dir, target_dir in reversed(copied_directories):
|
||||
shutil.copystat(source_dir, target_dir, follow_symlinks=False)
|
||||
except Exception:
|
||||
self._cleanup_partial_duplicate(destination)
|
||||
raise
|
||||
|
||||
def _cleanup_partial_duplicate(self, path: Path) -> None:
|
||||
if not path.exists():
|
||||
return
|
||||
@@ -491,6 +477,180 @@ class TaskRunner:
|
||||
return
|
||||
path.unlink()
|
||||
|
||||
@staticmethod
|
||||
def _file_entries(item: dict[str, object]) -> list[dict[str, str]]:
|
||||
return list(item.get("files", [])) # type: ignore[arg-type]
|
||||
|
||||
@staticmethod
|
||||
def _directory_entries(item: dict[str, object]) -> list[dict[str, str]]:
|
||||
return list(item.get("directories", [])) # type: ignore[arg-type]
|
||||
|
||||
def _total_file_count(self, items: list[dict[str, object]]) -> int:
|
||||
return sum(len(self._file_entries(item)) for item in items)
|
||||
|
||||
def _first_file_label(self, items: list[dict[str, object]]) -> str | None:
|
||||
for item in items:
|
||||
files = self._file_entries(item)
|
||||
if files:
|
||||
return files[0]["label"]
|
||||
return None
|
||||
|
||||
def _completed_files(self, task_id: str) -> int:
|
||||
task = self._repository.get_task(task_id)
|
||||
if not task or task["done_items"] is None:
|
||||
return 0
|
||||
return int(task["done_items"])
|
||||
|
||||
def _copy_single_planned_file(
|
||||
self,
|
||||
task_id: str,
|
||||
file_entry: dict[str, str],
|
||||
completed_items: int,
|
||||
total_items: int,
|
||||
) -> int:
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=file_entry["label"],
|
||||
)
|
||||
self._filesystem.copy_file(source=file_entry["source"], destination=file_entry["destination"])
|
||||
completed_items += 1
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=self._next_item_label_after_completion(completed_items, total_items, file_entry["label"]),
|
||||
)
|
||||
return completed_items
|
||||
|
||||
def _copy_directory_item(
|
||||
self,
|
||||
task_id: str,
|
||||
item: dict[str, object],
|
||||
completed_items: int,
|
||||
total_items: int,
|
||||
cleanup_on_failure: bool = False,
|
||||
) -> int:
|
||||
directories = self._directory_entries(item)
|
||||
files = self._file_entries(item)
|
||||
try:
|
||||
return self._copy_directory_files(directories, files, task_id=task_id, completed_items=completed_items, total_items=total_items)
|
||||
except Exception:
|
||||
if cleanup_on_failure:
|
||||
self._cleanup_partial_duplicate(Path(str(item["destination"])))
|
||||
raise
|
||||
|
||||
def _copy_directory_files(
|
||||
self,
|
||||
directories: list[dict[str, str]],
|
||||
files: list[dict[str, str]],
|
||||
*,
|
||||
task_id: str | None = None,
|
||||
completed_items: int = 0,
|
||||
total_items: int = 0,
|
||||
) -> int:
|
||||
for directory in directories:
|
||||
Path(directory["destination"]).mkdir(parents=True, exist_ok=True)
|
||||
for file_entry in files:
|
||||
if task_id is not None and self._is_cancel_requested(task_id):
|
||||
return completed_items
|
||||
if task_id is not None:
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=file_entry["label"],
|
||||
)
|
||||
self._filesystem.copy_file(source=file_entry["source"], destination=file_entry["destination"])
|
||||
completed_items += 1
|
||||
if task_id is not None:
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=self._next_item_label_after_completion(completed_items, total_items, file_entry["label"]),
|
||||
)
|
||||
if task_id is not None and self._is_cancel_requested(task_id):
|
||||
return completed_items
|
||||
for directory in reversed(directories):
|
||||
shutil.copystat(Path(directory["source"]), Path(directory["destination"]), follow_symlinks=False)
|
||||
return completed_items
|
||||
|
||||
def _move_single_planned_file(
|
||||
self,
|
||||
task_id: str,
|
||||
file_entry: dict[str, str],
|
||||
completed_items: int,
|
||||
total_items: int,
|
||||
) -> int:
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=file_entry["label"],
|
||||
)
|
||||
self._filesystem.move_file(source=file_entry["source"], destination=file_entry["destination"])
|
||||
completed_items += 1
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=self._next_item_label_after_completion(completed_items, total_items, file_entry["label"]),
|
||||
)
|
||||
return completed_items
|
||||
|
||||
def _move_directory_item(
|
||||
self,
|
||||
task_id: str,
|
||||
item: dict[str, object],
|
||||
completed_items: int,
|
||||
total_items: int,
|
||||
) -> int:
|
||||
return self._move_directory_files(self._directory_entries(item), self._file_entries(item), task_id=task_id, completed_items=completed_items, total_items=total_items)
|
||||
|
||||
def _move_directory_files(
|
||||
self,
|
||||
directories: list[dict[str, str]],
|
||||
files: list[dict[str, str]],
|
||||
*,
|
||||
task_id: str | None = None,
|
||||
completed_items: int = 0,
|
||||
total_items: int = 0,
|
||||
) -> int:
|
||||
for directory in directories:
|
||||
Path(directory["destination"]).mkdir(parents=True, exist_ok=True)
|
||||
for file_entry in files:
|
||||
if task_id is not None and self._is_cancel_requested(task_id):
|
||||
return completed_items
|
||||
if task_id is not None:
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=file_entry["label"],
|
||||
)
|
||||
self._filesystem.move_file(source=file_entry["source"], destination=file_entry["destination"])
|
||||
completed_items += 1
|
||||
if task_id is not None:
|
||||
self._repository.update_progress(
|
||||
task_id=task_id,
|
||||
done_items=completed_items,
|
||||
total_items=total_items,
|
||||
current_item=self._next_item_label_after_completion(completed_items, total_items, file_entry["label"]),
|
||||
)
|
||||
if task_id is not None and self._is_cancel_requested(task_id):
|
||||
return completed_items
|
||||
for directory in reversed(directories):
|
||||
shutil.copystat(Path(directory["source"]), Path(directory["destination"]), follow_symlinks=False)
|
||||
for directory in reversed(directories):
|
||||
self._filesystem.delete_empty_directory(Path(directory["source"]))
|
||||
return completed_items
|
||||
|
||||
@staticmethod
|
||||
def _next_item_label_after_completion(completed_items: int, total_items: int, current_label: str) -> str | None:
|
||||
return None
|
||||
|
||||
def _is_cancel_requested(self, task_id: str) -> bool:
|
||||
task = self._repository.get_task(task_id)
|
||||
return bool(task) and task["status"] == "cancelling"
|
||||
@@ -523,18 +683,22 @@ class TaskRunner:
|
||||
task_id: str,
|
||||
done_bytes: int | None,
|
||||
total_bytes: int | None,
|
||||
done_items: int | None = None,
|
||||
total_items: int | None = None,
|
||||
) -> None:
|
||||
if self._is_cancel_requested(task_id):
|
||||
self._finalize_cancelled(task_id, done_bytes=done_bytes, total_bytes=total_bytes)
|
||||
self._finalize_cancelled(task_id, done_bytes=done_bytes, total_bytes=total_bytes, done_items=done_items, total_items=total_items)
|
||||
return
|
||||
if self._repository.mark_completed(
|
||||
task_id=task_id,
|
||||
done_bytes=done_bytes,
|
||||
total_bytes=total_bytes,
|
||||
done_items=done_items,
|
||||
total_items=total_items,
|
||||
):
|
||||
self._update_history_completed(task_id)
|
||||
return
|
||||
self._finalize_if_already_cancelled(task_id, done_bytes=done_bytes, total_bytes=total_bytes)
|
||||
self._finalize_if_already_cancelled(task_id, done_bytes=done_bytes, total_bytes=total_bytes, done_items=done_items, total_items=total_items)
|
||||
|
||||
def _complete_or_cancel_item_task(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user