rclone-api 1.5.45__py3-none-any.whl → 1.5.46__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/install.py CHANGED
@@ -1,100 +1,139 @@
1
- import logging
2
- import os
3
- import platform
4
- import shutil
5
- from pathlib import Path
6
- from tempfile import TemporaryDirectory
7
- from warnings import warn
8
-
9
- from download import download
10
-
11
- URL_WINDOWS = "https://downloads.rclone.org/rclone-current-windows-amd64.zip"
12
- URL_LINUX = "https://downloads.rclone.org/rclone-current-linux-amd64.zip"
13
- URL_MACOS_ARM = "https://downloads.rclone.org/rclone-current-osx-arm64.zip"
14
- URL_MACOS_X86 = "https://downloads.rclone.org/rclone-current-osx-amd64.zip"
15
-
16
- logger = logging.getLogger(__name__)
17
- logging.basicConfig(level=logging.DEBUG)
18
-
19
-
20
- def rclone_download_url() -> str:
21
- system = platform.system()
22
- arch = platform.machine()
23
- if system == "Windows":
24
- assert "arm" not in arch, f"Unsupported arch: {arch}"
25
- return URL_WINDOWS
26
- elif system == "Linux":
27
- assert "arm" not in arch, f"Unsupported arch: {arch}"
28
- return URL_LINUX
29
- elif system == "Darwin":
30
- if "x86" in arch:
31
- return URL_MACOS_X86
32
- elif "arm" in arch:
33
- return URL_MACOS_ARM
34
- else:
35
- raise Exception(f"Unsupported arch: {arch}")
36
- else:
37
- raise Exception("Unsupported system")
38
-
39
-
40
- def _remove_signed_binary_requirements(out: Path) -> None:
41
- if platform.system() == "Windows":
42
- return
43
- # mac os
44
- if platform.system() == "Darwin":
45
- # remove signed binary requirements
46
- #
47
- # xattr -d com.apple.quarantine rclone
48
- import subprocess
49
-
50
- subprocess.run(
51
- ["xattr", "-d", "com.apple.quarantine", str(out)],
52
- capture_output=True,
53
- check=False,
54
- )
55
- return
56
-
57
-
58
- def _make_executable(out: Path) -> None:
59
- if platform.system() == "Windows":
60
- return
61
- # linux and mac os
62
- os.chmod(out, 0o755)
63
-
64
-
65
- def _find_rclone_exe(start: Path) -> Path | None:
66
- for root, dirs, files in os.walk(start):
67
- if platform.system() == "Windows":
68
- if "rclone.exe" in files:
69
- return Path(root) / "rclone.exe"
70
- else:
71
- if "rclone" in files:
72
- return Path(root) / "rclone"
73
- return None
74
-
75
-
76
- def rclone_download(out: Path, replace=False) -> Exception | None:
77
- if out.exists() and not replace:
78
- return None
79
- try:
80
- url = rclone_download_url()
81
- with TemporaryDirectory() as tmpdir:
82
- tmp = Path(tmpdir)
83
- logging.info(f"Downloading rclone from {url} to {tmp.absolute()}")
84
- download(url, tmp, kind="zip", replace=True)
85
- exe = _find_rclone_exe(tmp)
86
- if exe is None:
87
- raise FileNotFoundError("rclone executable not found")
88
- if os.path.exists(out):
89
- os.remove(out)
90
- out.parent.mkdir(parents=True, exist_ok=True)
91
- shutil.move(exe, out)
92
- _remove_signed_binary_requirements(out)
93
- _make_executable(out)
94
- return None
95
- except Exception as e:
96
- import traceback
97
-
98
- stacktrace = traceback.format_exc()
99
- warn(f"Failed to download rclone: {e}\n{stacktrace}")
100
- return e
1
+ import logging
2
+ import os
3
+ import platform
4
+ import shutil
5
+ from pathlib import Path
6
+ from tempfile import TemporaryDirectory
7
+ from warnings import warn
8
+
9
+ from download import download
10
+
11
+ URL_WINDOWS = "https://downloads.rclone.org/rclone-current-windows-amd64.zip"
12
+ URL_LINUX = "https://downloads.rclone.org/rclone-current-linux-amd64.zip"
13
+ URL_MACOS_ARM = "https://downloads.rclone.org/rclone-current-osx-arm64.zip"
14
+ URL_MACOS_X86 = "https://downloads.rclone.org/rclone-current-osx-amd64.zip"
15
+
16
+ logger = logging.getLogger(__name__)
17
+ logging.basicConfig(level=logging.DEBUG)
18
+
19
+
20
+ def rclone_download_url() -> str:
21
+ system = platform.system()
22
+ arch = platform.machine()
23
+ if system == "Windows":
24
+ assert "arm" not in arch, f"Unsupported arch: {arch}"
25
+ return URL_WINDOWS
26
+ elif system == "Linux":
27
+ assert "arm" not in arch, f"Unsupported arch: {arch}"
28
+ return URL_LINUX
29
+ elif system == "Darwin":
30
+ if "x86" in arch:
31
+ return URL_MACOS_X86
32
+ elif "arm" in arch:
33
+ return URL_MACOS_ARM
34
+ else:
35
+ raise Exception(f"Unsupported arch: {arch}")
36
+ else:
37
+ raise Exception("Unsupported system")
38
+
39
+
40
+ def _remove_signed_binary_requirements(out: Path) -> None:
41
+ if platform.system() == "Windows":
42
+ return
43
+ # mac os
44
+ if platform.system() == "Darwin":
45
+ # remove signed binary requirements
46
+ #
47
+ # xattr -d com.apple.quarantine rclone
48
+ import subprocess
49
+
50
+ subprocess.run(
51
+ ["xattr", "-d", "com.apple.quarantine", str(out)],
52
+ capture_output=True,
53
+ check=False,
54
+ )
55
+ return
56
+
57
+
58
+ def _make_executable(out: Path) -> None:
59
+ if platform.system() == "Windows":
60
+ return
61
+ # linux and mac os
62
+ os.chmod(out, 0o755)
63
+
64
+
65
+ def _find_rclone_exe(start: Path) -> Path | None:
66
+ for root, dirs, files in os.walk(start):
67
+ if platform.system() == "Windows":
68
+ if "rclone.exe" in files:
69
+ return Path(root) / "rclone.exe"
70
+ else:
71
+ if "rclone" in files:
72
+ return Path(root) / "rclone"
73
+ return None
74
+
75
+
76
+ def _move_to_standard_linux_paths(exe_path: Path) -> None:
77
+ """Move rclone to standard paths on Linux systems and create a symlink in the original location."""
78
+ if platform.system() != "Linux":
79
+ return
80
+
81
+ try:
82
+ # Create directory in standard path if it doesn't exist
83
+ bin_path = Path("/usr/local/bin/rclone")
84
+
85
+ if os.access("/usr/local/bin", os.W_OK):
86
+ # Remove existing binary if it exists
87
+ if bin_path.exists():
88
+ if bin_path.is_symlink():
89
+ bin_path.unlink()
90
+ else:
91
+ os.remove(bin_path)
92
+
93
+ # Move the binary to standard path
94
+ shutil.move(str(exe_path), str(bin_path))
95
+
96
+ # Make it executable
97
+ os.chmod(bin_path, 0o755)
98
+
99
+ # Create a symlink in the original location
100
+ exe_path.symlink_to(bin_path)
101
+
102
+ logger.info(f"Moved rclone to {bin_path} and created symlink at {exe_path}")
103
+ else:
104
+ logger.warning(
105
+ "No write permission to /usr/local/bin, skipping move operation"
106
+ )
107
+ except Exception as e:
108
+ logger.warning(f"Failed to move rclone to standard paths: {e}")
109
+
110
+
111
+ def rclone_download(out: Path, replace=False) -> Exception | None:
112
+ if out.exists() and not replace:
113
+ return None
114
+ try:
115
+ url = rclone_download_url()
116
+ with TemporaryDirectory() as tmpdir:
117
+ tmp = Path(tmpdir)
118
+ logging.info(f"Downloading rclone from {url} to {tmp.absolute()}")
119
+ download(url, tmp, kind="zip", replace=True)
120
+ exe = _find_rclone_exe(tmp)
121
+ if exe is None:
122
+ raise FileNotFoundError("rclone executable not found")
123
+ if os.path.exists(out):
124
+ os.remove(out)
125
+ out.parent.mkdir(parents=True, exist_ok=True)
126
+ shutil.move(exe, out)
127
+ _remove_signed_binary_requirements(out)
128
+ _make_executable(out)
129
+
130
+ # Move to standard paths on Linux
131
+ _move_to_standard_linux_paths(out)
132
+
133
+ return None
134
+ except Exception as e:
135
+ import traceback
136
+
137
+ stacktrace = traceback.format_exc()
138
+ warn(f"Failed to download rclone: {e}\n{stacktrace}")
139
+ return e
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rclone_api
3
- Version: 1.5.45
3
+ Version: 1.5.46
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -16,7 +16,7 @@ rclone_api/filelist.py,sha256=xbiusvNgaB_b_kQOZoHMJJxn6TWGtPrWd2J042BI28o,767
16
16
  rclone_api/fs.py,sha256=xUkoSV2R9dByKgueZ3x2GjyCn9fM7tK1ydgK1Whiph0,8933
17
17
  rclone_api/group_files.py,sha256=H92xPW9lQnbNw5KbtZCl00bD6iRh9yRbCuxku4j_3dg,8036
18
18
  rclone_api/http_server.py,sha256=P-LT2GqCEM9tGbyzzr-CrSOc3FyCw1qXUSQ5bY2KBHU,12113
19
- rclone_api/install.py,sha256=4bFCX2KFLOX6_X_q_r5h4GXBAg605UBNrJUAeIZDwU8,3066
19
+ rclone_api/install.py,sha256=db7l5KoVBr84HbFxih1Sd82tUfzhOuczKfBLb_Dn3XU,4507
20
20
  rclone_api/log.py,sha256=VZHM7pNSXip2ZLBKMP7M1u-rp_F7zoafFDuR8CPUoKI,1271
21
21
  rclone_api/mount.py,sha256=LZqEhuKZunbWVqmsOIqkkCotaxWJpdFRS1InXveoU5E,1428
22
22
  rclone_api/mount_util.py,sha256=jqhJEVTHV6c6lOOzUYb4FLMbqDMHdz7-QRcdH-IobFc,10154
@@ -55,9 +55,9 @@ rclone_api/s3/multipart/upload_parts_inline.py,sha256=V7syKjFyVIe4U9Ahl5XgqVTzt9
55
55
  rclone_api/s3/multipart/upload_parts_resumable.py,sha256=6-nlMclS8jyVvMvFbQDcZOX9MY1WbCcKA_s9bwuYxnk,9793
56
56
  rclone_api/s3/multipart/upload_parts_server_side_merge.py,sha256=Fp2pdrs5dONQI9LkfNolgAGj1-Z2V1SsRd0r0sreuXI,18040
57
57
  rclone_api/s3/multipart/upload_state.py,sha256=f-Aq2NqtAaMUMhYitlICSNIxCKurWAl2gDEUVizLIqw,6019
58
- rclone_api-1.5.45.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
59
- rclone_api-1.5.45.dist-info/METADATA,sha256=_2SCmLKk1kenbWfd5e-xsbcJqMpXiQchdEzF96DdzUA,37305
60
- rclone_api-1.5.45.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
61
- rclone_api-1.5.45.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
62
- rclone_api-1.5.45.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
63
- rclone_api-1.5.45.dist-info/RECORD,,
58
+ rclone_api-1.5.46.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
59
+ rclone_api-1.5.46.dist-info/METADATA,sha256=KqRtpIh195KJQ-8gY8HYZLcY4Qm1KUFVXC5XCw_av8o,37305
60
+ rclone_api-1.5.46.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
61
+ rclone_api-1.5.46.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
62
+ rclone_api-1.5.46.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
63
+ rclone_api-1.5.46.dist-info/RECORD,,