rclone-api 1.0.66__py2.py3-none-any.whl → 1.0.68__py2.py3-none-any.whl
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/__init__.py +2 -1
- rclone_api/diff.py +59 -22
- rclone_api/rclone.py +6 -11
- {rclone_api-1.0.66.dist-info → rclone_api-1.0.68.dist-info}/METADATA +1 -1
- {rclone_api-1.0.66.dist-info → rclone_api-1.0.68.dist-info}/RECORD +9 -9
- {rclone_api-1.0.66.dist-info → rclone_api-1.0.68.dist-info}/LICENSE +0 -0
- {rclone_api-1.0.66.dist-info → rclone_api-1.0.68.dist-info}/WHEEL +0 -0
- {rclone_api-1.0.66.dist-info → rclone_api-1.0.68.dist-info}/entry_points.txt +0 -0
- {rclone_api-1.0.66.dist-info → rclone_api-1.0.68.dist-info}/top_level.txt +0 -0
rclone_api/__init__.py
CHANGED
@@ -6,7 +6,7 @@ from .dir_listing import DirListing
|
|
6
6
|
from .file import File
|
7
7
|
from .filelist import FileList
|
8
8
|
from .process import Process
|
9
|
-
from .rclone import DiffOption, Rclone, rclone_verbose
|
9
|
+
from .rclone import DiffOption, ListingOption, Rclone, rclone_verbose
|
10
10
|
from .remote import Remote
|
11
11
|
from .rpath import RPath
|
12
12
|
|
@@ -25,4 +25,5 @@ __all__ = [
|
|
25
25
|
"rclone_verbose",
|
26
26
|
"CompletedProcess",
|
27
27
|
"DiffOption",
|
28
|
+
"ListingOption",
|
28
29
|
]
|
rclone_api/diff.py
CHANGED
@@ -19,6 +19,15 @@ class DiffType(Enum):
|
|
19
19
|
ERROR = "!" # means there was an error
|
20
20
|
|
21
21
|
|
22
|
+
class DiffOption(Enum):
|
23
|
+
COMBINED = "combined"
|
24
|
+
MISSING_ON_SRC = "missing-on-src"
|
25
|
+
MISSING_ON_DST = "missing-on-dst"
|
26
|
+
DIFFER = "differ"
|
27
|
+
MATCH = "match"
|
28
|
+
ERROR = "error"
|
29
|
+
|
30
|
+
|
22
31
|
@dataclass
|
23
32
|
class DiffItem:
|
24
33
|
type: DiffType
|
@@ -42,31 +51,56 @@ class DiffItem:
|
|
42
51
|
return f"{self.src_prefix}/{self.path}"
|
43
52
|
|
44
53
|
|
45
|
-
def
|
54
|
+
def _parse_missing_on_src_dst(line: str) -> str | None:
|
55
|
+
if line.endswith("does-not-exist"):
|
56
|
+
# 2025/02/17 14:43:38 ERROR : zachs_video/breaking_ai_mind.mp4: file not in S3 bucket rclone-api-unit-test path does-not-exist
|
57
|
+
parts = line.split(" : ", 1)
|
58
|
+
if len(parts) < 1:
|
59
|
+
return None
|
60
|
+
right = parts[1]
|
61
|
+
file_path = right.split(":", 1)[0]
|
62
|
+
return file_path.strip()
|
63
|
+
return None
|
64
|
+
|
65
|
+
|
66
|
+
def _classify_diff(
|
67
|
+
line: str, src_slug: str, dst_slug: str, diff_option: DiffOption
|
68
|
+
) -> DiffItem | None:
|
46
69
|
def _new(type: DiffType, path: str) -> DiffItem:
|
47
70
|
return DiffItem(type, path, src_prefix=src_slug, dst_prefix=dst_slug)
|
48
71
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
72
|
+
if diff_option == DiffOption.COMBINED:
|
73
|
+
suffix = line[1:].strip() if len(line) > 0 else ""
|
74
|
+
if line.startswith(DiffType.EQUAL.value):
|
75
|
+
return _new(DiffType.EQUAL, suffix)
|
76
|
+
if line.startswith(DiffType.MISSING_ON_SRC.value):
|
77
|
+
return _new(DiffType.MISSING_ON_SRC, suffix)
|
78
|
+
if line.startswith(DiffType.MISSING_ON_DST.value):
|
79
|
+
return _new(DiffType.MISSING_ON_DST, suffix)
|
80
|
+
if line.startswith(DiffType.DIFFERENT.value):
|
81
|
+
return _new(DiffType.DIFFERENT, suffix)
|
82
|
+
if line.startswith(DiffType.ERROR.value):
|
83
|
+
return _new(DiffType.ERROR, suffix)
|
84
|
+
return None
|
85
|
+
if diff_option == DiffOption.MISSING_ON_SRC:
|
86
|
+
filename_src: str | None = _parse_missing_on_src_dst(line)
|
87
|
+
if filename_src is not None:
|
88
|
+
return _new(DiffType.MISSING_ON_SRC, filename_src)
|
89
|
+
return None
|
90
|
+
if diff_option == DiffOption.MISSING_ON_DST:
|
91
|
+
filename_dst: str | None = _parse_missing_on_src_dst(line)
|
92
|
+
if filename_dst is not None:
|
93
|
+
return _new(DiffType.MISSING_ON_DST, filename_dst)
|
94
|
+
return None
|
95
|
+
else:
|
96
|
+
raise ValueError(f"Unknown diff_option: {diff_option}")
|
64
97
|
|
65
98
|
|
66
99
|
def _async_diff_stream_from_running_process(
|
67
100
|
running_process: Process,
|
68
101
|
src_slug: str,
|
69
102
|
dst_slug: str,
|
103
|
+
diff_option: DiffOption,
|
70
104
|
output: Queue[DiffItem | None],
|
71
105
|
) -> None:
|
72
106
|
count = 0
|
@@ -81,7 +115,7 @@ def _async_diff_stream_from_running_process(
|
|
81
115
|
first_few_lines.append(line_str)
|
82
116
|
# _classify_line_type
|
83
117
|
diff_item: DiffItem | None = _classify_diff(
|
84
|
-
line_str, src_slug, dst_slug
|
118
|
+
line_str, src_slug, dst_slug, diff_option
|
85
119
|
)
|
86
120
|
if diff_item is None:
|
87
121
|
# Some other output that we don't care about, debug print etc.
|
@@ -111,14 +145,17 @@ def diff_stream_from_running_process(
|
|
111
145
|
running_process: Process,
|
112
146
|
src_slug: str,
|
113
147
|
dst_slug: str,
|
148
|
+
diff_option: DiffOption,
|
114
149
|
) -> Generator[DiffItem, None, None]:
|
115
150
|
output: Queue[DiffItem | None] = Queue()
|
116
151
|
# process_output_to_diff_stream(running_process, src_slug, dst_slug, output)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
152
|
+
|
153
|
+
def _task() -> None:
|
154
|
+
_async_diff_stream_from_running_process(
|
155
|
+
running_process, src_slug, dst_slug, diff_option, output
|
156
|
+
)
|
157
|
+
|
158
|
+
thread = Thread(target=_task, daemon=True)
|
122
159
|
thread.start()
|
123
160
|
while True:
|
124
161
|
item = output.get()
|
rclone_api/rclone.py
CHANGED
@@ -18,7 +18,7 @@ from rclone_api.completed_process import CompletedProcess
|
|
18
18
|
from rclone_api.config import Config
|
19
19
|
from rclone_api.convert import convert_to_filestr_list, convert_to_str
|
20
20
|
from rclone_api.deprecated import deprecated
|
21
|
-
from rclone_api.diff import DiffItem, diff_stream_from_running_process
|
21
|
+
from rclone_api.diff import DiffItem, DiffOption, diff_stream_from_running_process
|
22
22
|
from rclone_api.dir_listing import DirListing
|
23
23
|
from rclone_api.exec import RcloneExec
|
24
24
|
from rclone_api.file import File
|
@@ -47,15 +47,6 @@ class ModTimeStrategy(Enum):
|
|
47
47
|
NO_MODTIME = "no-modtime"
|
48
48
|
|
49
49
|
|
50
|
-
class DiffOption(Enum):
|
51
|
-
COMBINED = "combined"
|
52
|
-
MISSING_ON_SRC = "missing-on-src"
|
53
|
-
MISSING_ON_DST = "missing-on-dst"
|
54
|
-
DIFFER = "differ"
|
55
|
-
MATCH = "match"
|
56
|
-
ERROR = "error"
|
57
|
-
|
58
|
-
|
59
50
|
class ListingOption(Enum):
|
60
51
|
DIRS_ONLY = "dirs-only"
|
61
52
|
FILES_ONLY = "files-only"
|
@@ -241,11 +232,15 @@ class Rclone:
|
|
241
232
|
cmd += ["--min-size", min_size]
|
242
233
|
if max_size:
|
243
234
|
cmd += ["--max-size", max_size]
|
235
|
+
if diff_option == DiffOption.MISSING_ON_DST:
|
236
|
+
cmd += ["--one-way"]
|
244
237
|
if other_args:
|
245
238
|
cmd += other_args
|
246
239
|
proc = self._launch_process(cmd, capture=True)
|
247
240
|
item: DiffItem
|
248
|
-
for item in diff_stream_from_running_process(
|
241
|
+
for item in diff_stream_from_running_process(
|
242
|
+
running_process=proc, src_slug=src, dst_slug=dst, diff_option=diff_option
|
243
|
+
):
|
249
244
|
if item is None:
|
250
245
|
break
|
251
246
|
yield item
|
@@ -1,10 +1,10 @@
|
|
1
|
-
rclone_api/__init__.py,sha256=
|
1
|
+
rclone_api/__init__.py,sha256=B9q_4JU5Myh0DN-wqr_IgF5hZeAvszrGcqs2x-3hq-Q,633
|
2
2
|
rclone_api/cli.py,sha256=dibfAZIh0kXWsBbfp3onKLjyZXo54mTzDjUdzJlDlWo,231
|
3
3
|
rclone_api/completed_process.py,sha256=Pp-hXnLgej0IGO5ee9Fmx64dGzIofbQFEUyXdFCvO54,1371
|
4
4
|
rclone_api/config.py,sha256=tP6cU9DnCCEIRc_KP9HPur1jFLLg2QGFSxNwFm6_MVw,118
|
5
5
|
rclone_api/convert.py,sha256=Mx9Qo7zhkOedJd8LdhPvNGHp8znJzOk4f_2KWnoGc78,1012
|
6
6
|
rclone_api/deprecated.py,sha256=qWKpnZdYcBK7YQZKuVoWWXDwi-uqiAtbjgPcci_efow,590
|
7
|
-
rclone_api/diff.py,sha256=
|
7
|
+
rclone_api/diff.py,sha256=ggdDLUZxa13jMcPzKBcwAElmPCNWMOSR89D4yhpO74M,5264
|
8
8
|
rclone_api/dir.py,sha256=2-PFaDpjEs28z82DQ-TyaCgrm_OgpwlkwfTnx1-Wwpk,2194
|
9
9
|
rclone_api/dir_listing.py,sha256=9Qqf2SUswrOEkyqmaH23V51I18X6ePiXb9B1vUwRF5o,1571
|
10
10
|
rclone_api/exec.py,sha256=1ovvaMXDEfLiT7BrYZyE85u_yFhEUwUNW3jPOzqknR8,1023
|
@@ -12,16 +12,16 @@ rclone_api/file.py,sha256=YtR5Y6c0YfXTS-sReOy2UgiSnafcAeO6b2hnbojBQD4,1423
|
|
12
12
|
rclone_api/filelist.py,sha256=xbiusvNgaB_b_kQOZoHMJJxn6TWGtPrWd2J042BI28o,767
|
13
13
|
rclone_api/group_files.py,sha256=kOHh6ysFDkxjldSwvW6KqmiADUC1yFCdrZRY57TvbGY,5328
|
14
14
|
rclone_api/process.py,sha256=RrMfTe0bndmJ6gBK67ioqNvCstJ8aTC8RlGX1XBLlcw,4191
|
15
|
-
rclone_api/rclone.py,sha256=
|
15
|
+
rclone_api/rclone.py,sha256=Hnk74ZyCnxSkeNIGRfZLqtGdWHTzPRye2lzRah6vLeI,28071
|
16
16
|
rclone_api/remote.py,sha256=c9hlRKBCg1BFB9MCINaQIoCg10qyAkeqiS4brl8ce-8,343
|
17
17
|
rclone_api/rpath.py,sha256=8ZA_1wxWtskwcy0I8V2VbjKDmzPkiWd8Q2JQSvh-sYE,2586
|
18
18
|
rclone_api/util.py,sha256=_cvmHcJPRl2yXw4zgZiop3z-riA_8Ek6S5NDPw8cqSY,4198
|
19
19
|
rclone_api/walk.py,sha256=UaNOE3ICd8k5ouSFZvkVEH4r2GnnrD9TxfwkFcQnayo,3170
|
20
20
|
rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
|
21
21
|
rclone_api/cmd/list_files.py,sha256=x8FHODEilwKqwdiU1jdkeJbLwOqUkUQuDWPo2u_zpf0,741
|
22
|
-
rclone_api-1.0.
|
23
|
-
rclone_api-1.0.
|
24
|
-
rclone_api-1.0.
|
25
|
-
rclone_api-1.0.
|
26
|
-
rclone_api-1.0.
|
27
|
-
rclone_api-1.0.
|
22
|
+
rclone_api-1.0.68.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
23
|
+
rclone_api-1.0.68.dist-info/METADATA,sha256=p3oHKpaFeHKBgQhxdAqBHrHVBwzm7k_VuL8W8oYmx9U,4489
|
24
|
+
rclone_api-1.0.68.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
|
25
|
+
rclone_api-1.0.68.dist-info/entry_points.txt,sha256=XUoTX3m7CWxdj2VAKhEuO0NMOfX2qf-OcEDFwdyk9ZE,72
|
26
|
+
rclone_api-1.0.68.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
|
27
|
+
rclone_api-1.0.68.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|