rclone-api 1.5.6__tar.gz → 1.5.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rclone_api-1.5.6 → rclone_api-1.5.7}/PKG-INFO +1 -1
- {rclone_api-1.5.6 → rclone_api-1.5.7}/pyproject.toml +1 -1
- rclone_api-1.5.7/src/rclone_api/mount.py +55 -0
- rclone_api-1.5.6/src/rclone_api/mount.py → rclone_api-1.5.7/src/rclone_api/mount_util.py +57 -97
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/rclone_impl.py +2 -1
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api.egg-info/PKG-INFO +1 -1
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api.egg-info/SOURCES.txt +1 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.aiderignore +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.github/workflows/lint.yml +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.github/workflows/push_macos.yml +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.github/workflows/push_ubuntu.yml +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.github/workflows/push_win.yml +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.gitignore +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.pylintrc +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.vscode/launch.json +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.vscode/settings.json +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/.vscode/tasks.json +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/LICENSE +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/MANIFEST.in +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/README.md +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/clean +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/install +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/lint +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/requirements.testing.txt +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/setup.cfg +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/setup.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/__init__.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/assets/example.txt +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/cli.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/cmd/analyze.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/cmd/copy_large_s3.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/cmd/copy_large_s3_finish.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/cmd/list_files.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/cmd/save_to_db.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/completed_process.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/config.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/convert.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/db/__init__.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/db/db.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/db/models.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/deprecated.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/detail/copy_file_parts_resumable.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/detail/walk.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/diff.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/dir.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/dir_listing.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/exec.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/experimental/flags.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/experimental/flags_base.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/file.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/file_item.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/file_part.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/file_stream.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/filelist.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/group_files.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/http_server.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/install.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/log.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/process.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/remote.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/rpath.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/api.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/basic_ops.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/chunk_task.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/create.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/file_info.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/finished_piece.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/info_json.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/merge_state.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/upload_info.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/upload_parts_inline.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/upload_parts_resumable.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/upload_parts_server_side_merge.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/upload_state.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/types.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/scan_missing_folders.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/types.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/util.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api.egg-info/dependency_links.txt +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api.egg-info/entry_points.txt +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api.egg-info/requires.txt +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api.egg-info/top_level.txt +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/test +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/archive/test_paramiko.py.disabled +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_cmd_list_files.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_copy.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_copy_bytes.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_copy_file_resumable_s3.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_copy_files.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_db.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_diff.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_file_item.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_group_files.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_install.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_is_synced.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_ls.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_ls_stream_files.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_mount.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_mount_s3.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_obscure.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_rclone_config.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_read_write_text.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_remote_control.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_remotes.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_s3.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_scan_missing_folders.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_serve_http.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_size_files.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_size_suffix.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tests/test_walk.py +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/tox.ini +0 -0
- {rclone_api-1.5.6 → rclone_api-1.5.7}/upload_package.sh +0 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from pathlib import Path
|
3
|
+
|
4
|
+
from rclone_api.process import Process
|
5
|
+
|
6
|
+
|
7
|
+
@dataclass
|
8
|
+
class Mount:
|
9
|
+
"""Mount information."""
|
10
|
+
|
11
|
+
src: str
|
12
|
+
mount_path: Path
|
13
|
+
process: Process
|
14
|
+
read_only: bool
|
15
|
+
cache_dir: Path | None = None
|
16
|
+
cache_dir_delete_on_exit: bool | None = None
|
17
|
+
_closed: bool = False
|
18
|
+
|
19
|
+
def __post_init__(self):
|
20
|
+
from rclone_api.mount_util import add_mount_for_gc, wait_for_mount
|
21
|
+
|
22
|
+
assert isinstance(self.mount_path, Path)
|
23
|
+
assert self.process is not None
|
24
|
+
wait_for_mount(self)
|
25
|
+
add_mount_for_gc(self)
|
26
|
+
|
27
|
+
def close(self, wait=True) -> None:
|
28
|
+
"""Clean up the mount."""
|
29
|
+
from rclone_api.mount_util import (
|
30
|
+
cache_dir_delete_on_exit,
|
31
|
+
clean_mount,
|
32
|
+
remove_mount_for_gc,
|
33
|
+
)
|
34
|
+
|
35
|
+
if self._closed:
|
36
|
+
return
|
37
|
+
self._closed = True
|
38
|
+
self.process.terminate()
|
39
|
+
clean_mount(self, verbose=False, wait=wait)
|
40
|
+
if self.cache_dir and self.cache_dir_delete_on_exit:
|
41
|
+
cache_dir_delete_on_exit(self.cache_dir)
|
42
|
+
remove_mount_for_gc(self)
|
43
|
+
|
44
|
+
def __enter__(self) -> "Mount":
|
45
|
+
return self
|
46
|
+
|
47
|
+
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
48
|
+
self.close(wait=True)
|
49
|
+
|
50
|
+
def __del__(self):
|
51
|
+
self.close(wait=False)
|
52
|
+
|
53
|
+
# make this a hashable object
|
54
|
+
def __hash__(self):
|
55
|
+
return hash(self.mount_path)
|
@@ -7,10 +7,9 @@ import time
|
|
7
7
|
import warnings
|
8
8
|
import weakref
|
9
9
|
from concurrent.futures import ThreadPoolExecutor
|
10
|
-
from dataclasses import dataclass
|
11
10
|
from pathlib import Path
|
12
|
-
from typing import Any
|
13
11
|
|
12
|
+
from rclone_api.mount import Mount
|
14
13
|
from rclone_api.process import Process
|
15
14
|
|
16
15
|
_SYSTEM = platform.system() # "Linux", "Darwin", "Windows", etc.
|
@@ -18,15 +17,6 @@ _SYSTEM = platform.system() # "Linux", "Darwin", "Windows", etc.
|
|
18
17
|
_MOUNTS_FOR_GC: weakref.WeakSet = weakref.WeakSet()
|
19
18
|
|
20
19
|
|
21
|
-
def _add_mount_for_gc(mount: "Mount") -> None:
|
22
|
-
# weak reference to avoid circular references
|
23
|
-
_MOUNTS_FOR_GC.add(mount)
|
24
|
-
|
25
|
-
|
26
|
-
def _remove_mount_for_gc(mount: "Mount") -> None:
|
27
|
-
_MOUNTS_FOR_GC.discard(mount)
|
28
|
-
|
29
|
-
|
30
20
|
def _cleanup_mounts() -> None:
|
31
21
|
with ThreadPoolExecutor() as executor:
|
32
22
|
mount: Mount
|
@@ -34,61 +24,7 @@ def _cleanup_mounts() -> None:
|
|
34
24
|
executor.submit(mount.close)
|
35
25
|
|
36
26
|
|
37
|
-
def
|
38
|
-
if cache_dir.exists():
|
39
|
-
try:
|
40
|
-
shutil.rmtree(cache_dir)
|
41
|
-
except Exception as e:
|
42
|
-
warnings.warn(f"Error removing cache directory {cache_dir}: {e}")
|
43
|
-
|
44
|
-
|
45
|
-
atexit.register(_cleanup_mounts)
|
46
|
-
|
47
|
-
|
48
|
-
@dataclass
|
49
|
-
class Mount:
|
50
|
-
"""Mount information."""
|
51
|
-
|
52
|
-
src: str
|
53
|
-
mount_path: Path
|
54
|
-
process: Process
|
55
|
-
read_only: bool
|
56
|
-
cache_dir: Path | None = None
|
57
|
-
cache_dir_delete_on_exit: bool | None = None
|
58
|
-
_closed: bool = False
|
59
|
-
|
60
|
-
def __post_init__(self):
|
61
|
-
assert isinstance(self.mount_path, Path)
|
62
|
-
assert self.process is not None
|
63
|
-
wait_for_mount(self.mount_path, self.process)
|
64
|
-
_add_mount_for_gc(self)
|
65
|
-
|
66
|
-
def close(self, wait=True) -> None:
|
67
|
-
"""Clean up the mount."""
|
68
|
-
if self._closed:
|
69
|
-
return
|
70
|
-
self._closed = True
|
71
|
-
self.process.terminate()
|
72
|
-
clean_mount(self, verbose=False, wait=wait)
|
73
|
-
if self.cache_dir and self.cache_dir_delete_on_exit:
|
74
|
-
_cache_dir_delete_on_exit(self.cache_dir)
|
75
|
-
_remove_mount_for_gc(self)
|
76
|
-
|
77
|
-
def __enter__(self) -> "Mount":
|
78
|
-
return self
|
79
|
-
|
80
|
-
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
81
|
-
self.close(wait=True)
|
82
|
-
|
83
|
-
def __del__(self):
|
84
|
-
self.close(wait=False)
|
85
|
-
|
86
|
-
# make this a hashable object
|
87
|
-
def __hash__(self):
|
88
|
-
return hash(self.mount_path)
|
89
|
-
|
90
|
-
|
91
|
-
def run_command(cmd: str, verbose: bool) -> int:
|
27
|
+
def _run_command(cmd: str, verbose: bool) -> int:
|
92
28
|
"""Run a shell command and print its output if verbose is True."""
|
93
29
|
if verbose:
|
94
30
|
print(f"Executing: {cmd}")
|
@@ -104,6 +40,26 @@ def run_command(cmd: str, verbose: bool) -> int:
|
|
104
40
|
return -1
|
105
41
|
|
106
42
|
|
43
|
+
atexit.register(_cleanup_mounts)
|
44
|
+
|
45
|
+
|
46
|
+
def cache_dir_delete_on_exit(cache_dir: Path) -> None:
|
47
|
+
if cache_dir.exists():
|
48
|
+
try:
|
49
|
+
shutil.rmtree(cache_dir)
|
50
|
+
except Exception as e:
|
51
|
+
warnings.warn(f"Error removing cache directory {cache_dir}: {e}")
|
52
|
+
|
53
|
+
|
54
|
+
def add_mount_for_gc(mount: Mount) -> None:
|
55
|
+
# weak reference to avoid circular references
|
56
|
+
_MOUNTS_FOR_GC.add(mount)
|
57
|
+
|
58
|
+
|
59
|
+
def remove_mount_for_gc(mount: Mount) -> None:
|
60
|
+
_MOUNTS_FOR_GC.discard(mount)
|
61
|
+
|
62
|
+
|
107
63
|
def prepare_mount(outdir: Path, verbose: bool) -> None:
|
108
64
|
if _SYSTEM == "Windows":
|
109
65
|
# Windows -> Must create parent directories only if they don't exist
|
@@ -118,8 +74,7 @@ def prepare_mount(outdir: Path, verbose: bool) -> None:
|
|
118
74
|
|
119
75
|
|
120
76
|
def wait_for_mount(
|
121
|
-
|
122
|
-
mount_process: Any,
|
77
|
+
mount: Mount,
|
123
78
|
timeout: int = 20,
|
124
79
|
post_mount_delay: int = 5,
|
125
80
|
poll_interval: float = 1.0,
|
@@ -132,7 +87,7 @@ def wait_for_mount(
|
|
132
87
|
is still running, and applies an extra delay after detecting content for stabilization.
|
133
88
|
|
134
89
|
Args:
|
135
|
-
|
90
|
+
src (Path): The mount point directory to check.
|
136
91
|
mount_process (Any): A Process instance handling the mount (must be an instance of Process).
|
137
92
|
timeout (int): Maximum time in seconds to wait for the mount to become available.
|
138
93
|
post_mount_delay (int): Additional seconds to wait after detecting files.
|
@@ -145,6 +100,9 @@ def wait_for_mount(
|
|
145
100
|
TypeError: If mount_process is not an instance of Process.
|
146
101
|
"""
|
147
102
|
|
103
|
+
mount_process = mount.process
|
104
|
+
src = mount.mount_path
|
105
|
+
|
148
106
|
if not isinstance(mount_process, Process):
|
149
107
|
raise TypeError("mount_process must be an instance of Process")
|
150
108
|
|
@@ -160,40 +118,42 @@ def wait_for_mount(
|
|
160
118
|
raise subprocess.CalledProcessError(rtn, cmd_str)
|
161
119
|
|
162
120
|
# Check if the mount path exists.
|
163
|
-
if
|
121
|
+
if src.exists():
|
164
122
|
# Optionally check if path is a mount point.
|
165
123
|
if check_mount_flag:
|
166
124
|
try:
|
167
|
-
if not os.path.ismount(str(
|
125
|
+
if not os.path.ismount(str(src)):
|
168
126
|
print(
|
169
|
-
f"{
|
127
|
+
f"{src} exists but is not recognized as a mount point yet."
|
170
128
|
)
|
171
129
|
time.sleep(poll_interval)
|
172
130
|
continue
|
173
131
|
except Exception as e:
|
174
|
-
print(f"Could not verify mount point status for {
|
132
|
+
print(f"Could not verify mount point status for {src}: {e}")
|
175
133
|
|
176
134
|
try:
|
177
135
|
# Check for at least one entry in the directory.
|
178
|
-
if any(
|
136
|
+
if any(src.iterdir()):
|
179
137
|
print(
|
180
|
-
f"Mount point {
|
138
|
+
f"Mount point {src} appears available with files. Waiting {post_mount_delay} seconds for stabilization."
|
181
139
|
)
|
182
140
|
time.sleep(post_mount_delay)
|
183
141
|
return
|
184
142
|
else:
|
185
|
-
print(f"Mount point {
|
143
|
+
print(f"Mount point {src} is empty. Waiting for files to appear.")
|
186
144
|
except Exception as e:
|
187
145
|
last_error = e
|
188
|
-
print(f"Error accessing {
|
146
|
+
print(f"Error accessing {src}: {e}")
|
189
147
|
else:
|
190
|
-
print(f"Mount point {
|
148
|
+
print(f"Mount point {src} does not exist yet.")
|
191
149
|
|
192
150
|
time.sleep(poll_interval)
|
193
151
|
|
194
|
-
raise TimeoutError(
|
195
|
-
|
196
|
-
)
|
152
|
+
# raise TimeoutError(
|
153
|
+
# f"Mount point {src} did not become available within {timeout} seconds. Last error: {last_error}"
|
154
|
+
# )
|
155
|
+
if last_error is not None:
|
156
|
+
raise last_error
|
197
157
|
|
198
158
|
|
199
159
|
def clean_mount(mount: Mount | Path, verbose: bool = False, wait=True) -> None:
|
@@ -205,10 +165,14 @@ def clean_mount(mount: Mount | Path, verbose: bool = False, wait=True) -> None:
|
|
205
165
|
and 'umount'. On macOS it uses 'umount' (and optionally 'diskutil unmount'),
|
206
166
|
while on Windows it attempts to remove the mount point via 'mountvol /D'.
|
207
167
|
"""
|
168
|
+
|
169
|
+
def verbose_print(msg: str):
|
170
|
+
if verbose:
|
171
|
+
print(msg)
|
172
|
+
|
208
173
|
proc = mount.process if isinstance(mount, Mount) else None
|
209
174
|
if proc is not None and proc.poll() is None:
|
210
|
-
|
211
|
-
print(f"Terminating mount process {proc.pid}")
|
175
|
+
verbose_print(f"Terminating mount process {proc.pid}")
|
212
176
|
proc.kill()
|
213
177
|
|
214
178
|
# Check if the mount path exists; if an OSError occurs, assume it exists.
|
@@ -224,26 +188,24 @@ def clean_mount(mount: Mount | Path, verbose: bool = False, wait=True) -> None:
|
|
224
188
|
time.sleep(2)
|
225
189
|
|
226
190
|
if not mount_exists:
|
227
|
-
|
228
|
-
print(f"{mount_path} does not exist; nothing to clean up.")
|
191
|
+
verbose_print(f"{mount_path} does not exist; nothing to clean up.")
|
229
192
|
return
|
230
193
|
|
231
|
-
|
232
|
-
print(f"{mount_path} still exists, attempting to unmount and remove.")
|
194
|
+
verbose_print(f"{mount_path} still exists, attempting to unmount and remove.")
|
233
195
|
|
234
196
|
# Platform-specific unmount procedures
|
235
197
|
if _SYSTEM == "Linux":
|
236
198
|
# Try FUSE unmount first (if applicable), then the regular umount.
|
237
|
-
|
238
|
-
|
199
|
+
_run_command(f"fusermount -u {mount_path}", verbose)
|
200
|
+
_run_command(f"umount {mount_path}", verbose)
|
239
201
|
elif _SYSTEM == "Darwin":
|
240
202
|
# On macOS, use umount; optionally try diskutil for stubborn mounts.
|
241
|
-
|
203
|
+
_run_command(f"umount {mount_path}", verbose)
|
242
204
|
# Optionally: uncomment the next line if diskutil unmount is preferred.
|
243
|
-
#
|
205
|
+
# _run_command(f"diskutil unmount {mount_path}", verbose)
|
244
206
|
elif _SYSTEM == "Windows":
|
245
207
|
# On Windows, remove the mount point using mountvol.
|
246
|
-
|
208
|
+
_run_command(f"mountvol {mount_path} /D", verbose)
|
247
209
|
# If that does not work, try to remove the directory directly.
|
248
210
|
try:
|
249
211
|
mount_path.rmdir()
|
@@ -267,19 +229,17 @@ def clean_mount(mount: Mount | Path, verbose: bool = False, wait=True) -> None:
|
|
267
229
|
still_exists = True
|
268
230
|
|
269
231
|
if still_exists:
|
270
|
-
|
271
|
-
print(f"{mount_path} still exists after unmount attempt.")
|
232
|
+
verbose_print(f"{mount_path} still exists after unmount attempt.")
|
272
233
|
# Attempt to remove the directory if it is empty.
|
273
234
|
try:
|
274
235
|
# Only remove if the directory is empty.
|
275
236
|
if not any(mount_path.iterdir()):
|
276
237
|
mount_path.rmdir()
|
277
238
|
if verbose:
|
278
|
-
|
239
|
+
verbose_print(f"Removed empty mount directory {mount_path}")
|
279
240
|
else:
|
280
241
|
warnings.warn(f"{mount_path} is not empty; cannot remove.")
|
281
242
|
except Exception as e:
|
282
243
|
warnings.warn(f"Failed during cleanup of {mount_path}: {e}")
|
283
244
|
else:
|
284
|
-
|
285
|
-
print(f"{mount_path} successfully cleaned up.")
|
245
|
+
verbose_print(f"{mount_path} successfully cleaned up.")
|
@@ -27,7 +27,7 @@ from rclone_api.file import File
|
|
27
27
|
from rclone_api.file_stream import FilesStream
|
28
28
|
from rclone_api.group_files import group_files
|
29
29
|
from rclone_api.http_server import HttpServer
|
30
|
-
from rclone_api.mount import Mount
|
30
|
+
from rclone_api.mount import Mount
|
31
31
|
from rclone_api.process import Process
|
32
32
|
from rclone_api.remote import Remote
|
33
33
|
from rclone_api.rpath import RPath
|
@@ -1017,6 +1017,7 @@ class RcloneImpl:
|
|
1017
1017
|
Raises:
|
1018
1018
|
subprocess.CalledProcessError: If the mount operation fails
|
1019
1019
|
"""
|
1020
|
+
from rclone_api.mount_util import clean_mount, prepare_mount
|
1020
1021
|
|
1021
1022
|
allow_writes = allow_writes or False
|
1022
1023
|
use_links = use_links or True
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{rclone_api-1.5.6 → rclone_api-1.5.7}/src/rclone_api/s3/multipart/upload_parts_server_side_merge.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|