rclone-api 1.4.15__py2.py3-none-any.whl → 1.4.19__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/cmd/copy_large_s3_finish.py +11 -108
- rclone_api/detail/copy_file_parts.py +4 -1
- rclone_api/process.py +65 -40
- rclone_api/s3/merge_state.py +147 -0
- rclone_api/s3/multipart/finished_piece.py +15 -5
- rclone_api/s3/s3_multipart_uploader_by_copy.py +400 -151
- rclone_api/util.py +84 -23
- {rclone_api-1.4.15.dist-info → rclone_api-1.4.19.dist-info}/METADATA +1 -1
- {rclone_api-1.4.15.dist-info → rclone_api-1.4.19.dist-info}/RECORD +13 -12
- {rclone_api-1.4.15.dist-info → rclone_api-1.4.19.dist-info}/LICENSE +0 -0
- {rclone_api-1.4.15.dist-info → rclone_api-1.4.19.dist-info}/WHEEL +0 -0
- {rclone_api-1.4.15.dist-info → rclone_api-1.4.19.dist-info}/entry_points.txt +0 -0
- {rclone_api-1.4.15.dist-info → rclone_api-1.4.19.dist-info}/top_level.txt +0 -0
rclone_api/util.py
CHANGED
@@ -5,10 +5,13 @@ import shutil
|
|
5
5
|
import signal
|
6
6
|
import subprocess
|
7
7
|
import warnings
|
8
|
+
import weakref
|
8
9
|
from pathlib import Path
|
9
10
|
from threading import Lock
|
10
11
|
from typing import Any
|
11
12
|
|
13
|
+
import psutil
|
14
|
+
|
12
15
|
from rclone_api.config import Config
|
13
16
|
from rclone_api.dir import Dir
|
14
17
|
from rclone_api.remote import Remote
|
@@ -167,51 +170,109 @@ def rclone_execute(
|
|
167
170
|
tmpfile: Path | None = None
|
168
171
|
verbose = get_verbose(verbose)
|
169
172
|
|
170
|
-
# Handle the Path case for capture
|
171
|
-
output_file = None
|
173
|
+
# Handle the Path case for capture.
|
174
|
+
output_file: Path | None = None
|
172
175
|
if isinstance(capture, Path):
|
173
176
|
output_file = capture
|
174
|
-
capture = False #
|
177
|
+
capture = False # When redirecting to file, don't capture to memory.
|
175
178
|
else:
|
176
179
|
capture = capture if isinstance(capture, bool) else True
|
177
180
|
|
178
|
-
assert verbose is not None
|
179
|
-
|
180
181
|
try:
|
182
|
+
# Create a temporary config file if needed.
|
181
183
|
if isinstance(rclone_conf, Config):
|
182
184
|
tmpfile = make_temp_config_file()
|
183
185
|
tmpfile.write_text(rclone_conf.text, encoding="utf-8")
|
184
186
|
rclone_conf = tmpfile
|
185
|
-
|
187
|
+
|
188
|
+
# Build the command line.
|
189
|
+
full_cmd = (
|
186
190
|
[str(rclone_exe.resolve())] + ["--config", str(rclone_conf.resolve())] + cmd
|
187
191
|
)
|
188
192
|
if verbose:
|
189
|
-
cmd_str = subprocess.list2cmdline(
|
193
|
+
cmd_str = subprocess.list2cmdline(full_cmd)
|
190
194
|
print(f"\nRunning: {cmd_str}")
|
191
195
|
|
192
|
-
#
|
196
|
+
# Prepare subprocess parameters.
|
197
|
+
proc_kwargs: dict[str, Any] = {
|
198
|
+
"encoding": "utf-8",
|
199
|
+
"shell": False,
|
200
|
+
"stderr": subprocess.PIPE,
|
201
|
+
}
|
202
|
+
file_handle = None
|
193
203
|
if output_file:
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
stdout=f,
|
198
|
-
stderr=subprocess.PIPE,
|
199
|
-
encoding="utf-8",
|
200
|
-
check=False,
|
201
|
-
shell=False,
|
202
|
-
)
|
204
|
+
# Open the file for writing.
|
205
|
+
file_handle = open(output_file, "w", encoding="utf-8")
|
206
|
+
proc_kwargs["stdout"] = file_handle
|
203
207
|
else:
|
204
|
-
|
205
|
-
|
206
|
-
|
208
|
+
proc_kwargs["stdout"] = subprocess.PIPE if capture else None
|
209
|
+
|
210
|
+
# Start the process.
|
211
|
+
process = subprocess.Popen(full_cmd, **proc_kwargs)
|
212
|
+
|
213
|
+
# Register an atexit callback that uses psutil to kill the process tree.
|
214
|
+
proc_ref = weakref.ref(process)
|
215
|
+
|
216
|
+
def cleanup():
|
217
|
+
proc = proc_ref()
|
218
|
+
if proc is None:
|
219
|
+
return
|
220
|
+
try:
|
221
|
+
parent = psutil.Process(proc.pid)
|
222
|
+
except psutil.NoSuchProcess:
|
223
|
+
return
|
224
|
+
# Terminate all child processes first.
|
225
|
+
children = parent.children(recursive=True)
|
226
|
+
if children:
|
227
|
+
print(f"Terminating {len(children)} child process(es)...")
|
228
|
+
for child in children:
|
229
|
+
try:
|
230
|
+
child.terminate()
|
231
|
+
except Exception as e:
|
232
|
+
print(f"Error terminating child {child.pid}: {e}")
|
233
|
+
psutil.wait_procs(children, timeout=2)
|
234
|
+
for child in children:
|
235
|
+
if child.is_running():
|
236
|
+
try:
|
237
|
+
child.kill()
|
238
|
+
except Exception as e:
|
239
|
+
print(f"Error killing child {child.pid}: {e}")
|
240
|
+
# Now terminate the parent process.
|
241
|
+
if parent.is_running():
|
242
|
+
try:
|
243
|
+
parent.terminate()
|
244
|
+
parent.wait(timeout=3)
|
245
|
+
except (psutil.TimeoutExpired, Exception):
|
246
|
+
try:
|
247
|
+
parent.kill()
|
248
|
+
except Exception as e:
|
249
|
+
print(f"Error killing process {parent.pid}: {e}")
|
250
|
+
|
251
|
+
atexit.register(cleanup)
|
252
|
+
|
253
|
+
# Wait for the process to complete.
|
254
|
+
out, err = process.communicate()
|
255
|
+
# Close the file handle if used.
|
256
|
+
if file_handle:
|
257
|
+
file_handle.close()
|
258
|
+
|
259
|
+
cp: subprocess.CompletedProcess = subprocess.CompletedProcess(
|
260
|
+
args=full_cmd,
|
261
|
+
returncode=process.returncode,
|
262
|
+
stdout=out,
|
263
|
+
stderr=err,
|
264
|
+
)
|
265
|
+
|
266
|
+
# Warn or raise if return code is non-zero.
|
207
267
|
if cp.returncode != 0:
|
208
|
-
cmd_str = subprocess.list2cmdline(
|
268
|
+
cmd_str = subprocess.list2cmdline(full_cmd)
|
209
269
|
warnings.warn(
|
210
|
-
f"Error running: {cmd_str}, returncode: {cp.returncode}\n
|
270
|
+
f"Error running: {cmd_str}, returncode: {cp.returncode}\n"
|
271
|
+
f"{cp.stdout}\n{cp.stderr}"
|
211
272
|
)
|
212
273
|
if check:
|
213
274
|
raise subprocess.CalledProcessError(
|
214
|
-
cp.returncode,
|
275
|
+
cp.returncode, full_cmd, cp.stdout, cp.stderr
|
215
276
|
)
|
216
277
|
return cp
|
217
278
|
finally:
|
@@ -17,23 +17,23 @@ rclone_api/group_files.py,sha256=H92xPW9lQnbNw5KbtZCl00bD6iRh9yRbCuxku4j_3dg,803
|
|
17
17
|
rclone_api/http_server.py,sha256=3fPBV6l50erTe32DyeJBNmsDrn5KuujsbmEAbx13T-c,8720
|
18
18
|
rclone_api/log.py,sha256=VZHM7pNSXip2ZLBKMP7M1u-rp_F7zoafFDuR8CPUoKI,1271
|
19
19
|
rclone_api/mount.py,sha256=TE_VIBMW7J1UkF_6HRCt8oi_jGdMov4S51bm2OgxFAM,10045
|
20
|
-
rclone_api/process.py,sha256=
|
20
|
+
rclone_api/process.py,sha256=tGooS5NLdPuqHh7hCH8SfK44A6LGftPQCPQUNgSo0a0,5714
|
21
21
|
rclone_api/rclone_impl.py,sha256=xTTriz6-zn_aSrkY8B7wzT-zRXax7Og7ns6xu6-7O6g,48769
|
22
22
|
rclone_api/remote.py,sha256=mTgMTQTwxUmbLjTpr-AGTId2ycXKI9mLX5L7PPpDIoc,520
|
23
23
|
rclone_api/rpath.py,sha256=Y1JjQWcie39EgQrq-UtbfDz5yDLCwwfu27W7AQXllSE,2860
|
24
24
|
rclone_api/scan_missing_folders.py,sha256=-8NCwpCaHeHrX-IepCoAEsX1rl8S-GOCxcIhTr_w3gA,4747
|
25
25
|
rclone_api/types.py,sha256=HkpEZgZWhr5Gb04iHq5NxMRXxieWoN-PKmOfJFrg5Qg,12155
|
26
|
-
rclone_api/util.py,sha256=
|
26
|
+
rclone_api/util.py,sha256=yY72YKpmpT_ZM7AleVtPpl0YZZYQPTwTdqKn9qPwm8Y,9290
|
27
27
|
rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
|
28
28
|
rclone_api/cmd/analyze.py,sha256=RHbvk1G5ZUc3qLqlm1AZEyQzd_W_ZjcbCNDvW4YpTKQ,1252
|
29
29
|
rclone_api/cmd/copy_large_s3.py,sha256=B17GliDQyAauNglJCpsey0d3eArT2DAcT9g684TMQk8,3514
|
30
|
-
rclone_api/cmd/copy_large_s3_finish.py,sha256=
|
30
|
+
rclone_api/cmd/copy_large_s3_finish.py,sha256=Q_8uvC2J3V_jGQj8ualMlejWEPpkFn267bUKLC3Sp2M,2050
|
31
31
|
rclone_api/cmd/list_files.py,sha256=x8FHODEilwKqwdiU1jdkeJbLwOqUkUQuDWPo2u_zpf0,741
|
32
32
|
rclone_api/cmd/save_to_db.py,sha256=ylvnhg_yzexM-m6Zr7XDiswvoDVSl56ELuFAdb9gqBY,1957
|
33
33
|
rclone_api/db/__init__.py,sha256=OSRUdnSWUlDTOHmjdjVmxYTUNpTbtaJ5Ll9sl-PfZg0,40
|
34
34
|
rclone_api/db/db.py,sha256=YRnYrCaXHwytQt07uEZ_mMpvPHo9-0IWcOb95fVOOfs,10086
|
35
35
|
rclone_api/db/models.py,sha256=v7qaXUehvsDvU51uk69JI23fSIs9JFGcOa-Tv1c_wVs,1600
|
36
|
-
rclone_api/detail/copy_file_parts.py,sha256=
|
36
|
+
rclone_api/detail/copy_file_parts.py,sha256=1h-5JJmZdB0_TuVcuYMIClHqAgCXUI4eLyZHbdRiCHg,16280
|
37
37
|
rclone_api/detail/walk.py,sha256=-54NVE8EJcCstwDoaC_UtHm73R2HrZwVwQmsnv55xNU,3369
|
38
38
|
rclone_api/experimental/flags.py,sha256=qCVD--fSTmzlk9hloRLr0q9elzAOFzPsvVpKM3aB1Mk,2739
|
39
39
|
rclone_api/experimental/flags_base.py,sha256=ajU_czkTcAxXYU-SlmiCfHY7aCQGHvpCLqJ-Z8uZLk0,2102
|
@@ -41,16 +41,17 @@ rclone_api/s3/api.py,sha256=owoQ1H-R0hXcUozxC6sl53D7NmMOewHk2pUxK-ye8ms,4061
|
|
41
41
|
rclone_api/s3/basic_ops.py,sha256=hK3366xhVEzEcjz9Gk_8lFx6MRceAk72cax6mUrr6ko,2104
|
42
42
|
rclone_api/s3/chunk_task.py,sha256=waEYe-iYQ1_BR3NCS4BrzVrK9UANvH1EcbXx2I6Z_NM,6839
|
43
43
|
rclone_api/s3/create.py,sha256=_Q-faQ4Zl8XKTB28gireRxVXWP-YNxoAK4bligxDtiI,3998
|
44
|
-
rclone_api/s3/
|
44
|
+
rclone_api/s3/merge_state.py,sha256=ziTB9CYV-OWaky5C1fOT9hifSY2zgUrk5HmX1Xeu2UA,4978
|
45
|
+
rclone_api/s3/s3_multipart_uploader_by_copy.py,sha256=iuxnRaRDHvIMCu-9YDZzirRMc1R4gZgjigkM5u_MFJg,17188
|
45
46
|
rclone_api/s3/types.py,sha256=cYI5MbXRNdT-ps5kGIRQaYrseHyx_ozT4AcwBABTKwk,1616
|
46
47
|
rclone_api/s3/upload_file_multipart.py,sha256=V7syKjFyVIe4U9Ahl5XgqVTzt9akiew3MFjGmufLo2w,12503
|
47
48
|
rclone_api/s3/multipart/file_info.py,sha256=8v_07_eADo0K-Nsv7F0Ac1wcv3lkIsrR3MaRCmkYLTQ,105
|
48
|
-
rclone_api/s3/multipart/finished_piece.py,sha256=
|
49
|
+
rclone_api/s3/multipart/finished_piece.py,sha256=LtlX_mm6_hsADR8FxgfC2_pcO5Wou_20-jE34IcRXew,1633
|
49
50
|
rclone_api/s3/multipart/upload_info.py,sha256=d6_OfzFR_vtDzCEegFfzCfWi2kUBUV4aXZzqAEVp1c4,1874
|
50
51
|
rclone_api/s3/multipart/upload_state.py,sha256=f-Aq2NqtAaMUMhYitlICSNIxCKurWAl2gDEUVizLIqw,6019
|
51
|
-
rclone_api-1.4.
|
52
|
-
rclone_api-1.4.
|
53
|
-
rclone_api-1.4.
|
54
|
-
rclone_api-1.4.
|
55
|
-
rclone_api-1.4.
|
56
|
-
rclone_api-1.4.
|
52
|
+
rclone_api-1.4.19.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
53
|
+
rclone_api-1.4.19.dist-info/METADATA,sha256=RpqVhvMVSL_isjprjoRJJWMStau5WxyiiyO1OkHBydo,4628
|
54
|
+
rclone_api-1.4.19.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
|
55
|
+
rclone_api-1.4.19.dist-info/entry_points.txt,sha256=fJteOlYVwgX3UbNuL9jJ0zUTuX2O79JFAeNgK7Sw7EQ,255
|
56
|
+
rclone_api-1.4.19.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
|
57
|
+
rclone_api-1.4.19.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|