rclone-api 1.5.45__py3-none-any.whl → 1.5.47__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,168 @@
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
+ # Try system-wide installation first
83
+ system_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 system_bin_path.exists():
88
+ if system_bin_path.is_symlink():
89
+ system_bin_path.unlink()
90
+ else:
91
+ os.remove(system_bin_path)
92
+
93
+ # Move the binary to standard path
94
+ shutil.move(str(exe_path), str(system_bin_path))
95
+
96
+ # Make it executable
97
+ os.chmod(system_bin_path, 0o755)
98
+
99
+ # Create a symlink in the original location
100
+ exe_path.symlink_to(system_bin_path)
101
+
102
+ logger.info(
103
+ f"Moved rclone to {system_bin_path} and created symlink at {exe_path}"
104
+ )
105
+ else:
106
+ # Fall back to user's home directory if no root access
107
+ home_bin_dir = Path.home() / ".local" / "bin"
108
+ home_bin_dir.mkdir(parents=True, exist_ok=True)
109
+ home_bin_path = home_bin_dir / "rclone"
110
+
111
+ # Remove existing binary if it exists
112
+ if home_bin_path.exists():
113
+ if home_bin_path.is_symlink():
114
+ home_bin_path.unlink()
115
+ else:
116
+ os.remove(home_bin_path)
117
+
118
+ # Move the binary to user's bin directory
119
+ shutil.move(str(exe_path), str(home_bin_path))
120
+
121
+ # Make it executable
122
+ os.chmod(home_bin_path, 0o755)
123
+
124
+ # Create a symlink in the original location
125
+ exe_path.symlink_to(home_bin_path)
126
+
127
+ logger.info(
128
+ f"Moved rclone to {home_bin_path} and created symlink at {exe_path}"
129
+ )
130
+
131
+ # Check if ~/.local/bin is in PATH, if not suggest adding it
132
+ if str(home_bin_dir) not in os.environ.get("PATH", ""):
133
+ logger.warning(
134
+ f"{home_bin_dir} is not in PATH. Consider adding it to your shell profile."
135
+ )
136
+ except Exception as e:
137
+ logger.warning(f"Failed to move rclone to standard paths: {e}")
138
+
139
+
140
+ def rclone_download(out: Path, replace=False) -> Exception | None:
141
+ if out.exists() and not replace:
142
+ return None
143
+ try:
144
+ url = rclone_download_url()
145
+ with TemporaryDirectory() as tmpdir:
146
+ tmp = Path(tmpdir)
147
+ logging.info(f"Downloading rclone from {url} to {tmp.absolute()}")
148
+ download(url, tmp, kind="zip", replace=True)
149
+ exe = _find_rclone_exe(tmp)
150
+ if exe is None:
151
+ raise FileNotFoundError("rclone executable not found")
152
+ if os.path.exists(out):
153
+ os.remove(out)
154
+ out.parent.mkdir(parents=True, exist_ok=True)
155
+ shutil.move(exe, out)
156
+ _remove_signed_binary_requirements(out)
157
+ _make_executable(out)
158
+
159
+ # Move to standard paths on Linux
160
+ _move_to_standard_linux_paths(out)
161
+
162
+ return None
163
+ except Exception as e:
164
+ import traceback
165
+
166
+ stacktrace = traceback.format_exc()
167
+ warn(f"Failed to download rclone: {e}\n{stacktrace}")
168
+ 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.47
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=ZDG8QNj1JciS_DSqYnMTECwhJksUPAoqZQxtX804TDk,5679
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.47.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
59
+ rclone_api-1.5.47.dist-info/METADATA,sha256=UZGLiUY8lZA3ToCEOlD_oo1YtUONlTkAt16OMk9Dzv8,37305
60
+ rclone_api-1.5.47.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
61
+ rclone_api-1.5.47.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
62
+ rclone_api-1.5.47.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
63
+ rclone_api-1.5.47.dist-info/RECORD,,