Coverage for src/sync_drive.py: 100%
45 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-16 04:41 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-16 04:41 +0000
1"""Sync drive module.
3This module provides the main entry point for iCloud Drive synchronization,
4orchestrating the sync process using specialized utility modules per SRP.
5"""
7__author__ = "Mandar Patil (mandarons@pm.me)"
9import os
10import unicodedata
11from pathlib import Path
12from typing import Any
14from src import config_parser, configure_icloudpy_logging, get_logger
15from src.drive_cleanup import remove_obsolete # noqa: F401
16from src.drive_file_download import download_file # noqa: F401
17from src.drive_file_existence import file_exists, is_package, package_exists # noqa: F401
18from src.drive_filtering import ignored_path, wanted_file, wanted_folder, wanted_parent_folder # noqa: F401
19from src.drive_folder_processing import process_folder # noqa: F401
20from src.drive_package_processing import process_package # noqa: F401
21from src.drive_parallel_download import collect_file_for_download, download_file_task, files_lock # noqa: F401
22from src.drive_sync_directory import sync_directory
23from src.drive_thread_config import get_max_threads # noqa: F401
25# Configure icloudpy logging immediately after import
26configure_icloudpy_logging()
28LOGGER = get_logger()
31def sync_drive(config: Any, drive: Any) -> set[str]:
32 """Synchronize iCloud Drive to local filesystem.
34 This function serves as the main entry point for drive synchronization,
35 preparing the destination and delegating to the sync_directory orchestrator.
37 Args:
38 config: Configuration dictionary containing drive settings
39 drive: iCloud drive service instance
41 Returns:
42 Set of all synchronized file paths
43 """
44 destination_path = config_parser.prepare_drive_destination(config=config)
45 return sync_directory(
46 drive=drive,
47 destination_path=destination_path,
48 root=destination_path,
49 items=drive.dir(),
50 top=True,
51 filters=config["drive"]["filters"] if "drive" in config and "filters" in config["drive"] else None,
52 ignore=config["drive"]["ignore"] if "drive" in config and "ignore" in config["drive"] else None,
53 remove=config_parser.get_drive_remove_obsolete(config=config),
54 config=config,
55 )
58def process_file(item: Any, destination_path: str, filters: list[str], ignore: list[str], files: set[str]) -> bool:
59 """Process given item as file (legacy compatibility function).
61 This function maintains backward compatibility with existing tests.
62 New code should use the specialized modules directly.
64 Args:
65 item: iCloud file item to process
66 destination_path: Local destination directory
67 filters: File extension filters
68 ignore: Ignore patterns
69 files: Set to track processed files
71 Returns:
72 True if file was processed successfully, False otherwise
73 """
74 if not (item and destination_path and files is not None):
75 return False
76 local_file = os.path.join(destination_path, item.name)
77 local_file = unicodedata.normalize("NFC", local_file)
78 if not wanted_file(filters=filters, ignore=ignore, file_path=local_file):
79 return False
80 files.add(local_file)
81 item_is_package = is_package(item=item)
82 if item_is_package:
83 if package_exists(item=item, local_package_path=local_file):
84 for f in Path(local_file).glob("**/*"):
85 files.add(str(f))
86 return False
87 elif file_exists(item=item, local_file=local_file):
88 return False
89 local_file = download_file(item=item, local_file=local_file)
90 if local_file and item_is_package:
91 for f in Path(local_file).glob("**/*"):
92 f = str(f)
93 f_normalized = unicodedata.normalize("NFD", f)
94 if os.path.exists(f):
95 os.rename(f, f_normalized)
96 files.add(f_normalized)
97 return bool(local_file)