fluxqueue-cli 0.1.0b4__tar.gz → 0.1.1__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.
- {fluxqueue_cli-0.1.0b4 → fluxqueue_cli-0.1.1}/PKG-INFO +2 -4
- {fluxqueue_cli-0.1.0b4 → fluxqueue_cli-0.1.1}/README.md +1 -1
- {fluxqueue_cli-0.1.0b4 → fluxqueue_cli-0.1.1}/pyproject.toml +3 -7
- fluxqueue_cli-0.1.1/src/fluxqueue_cli/__init__.py +1 -0
- {fluxqueue_cli-0.1.0b4 → fluxqueue_cli-0.1.1}/src/fluxqueue_cli/cli.py +13 -5
- fluxqueue_cli-0.1.1/src/fluxqueue_cli/config.py +18 -0
- {fluxqueue_cli-0.1.0b4 → fluxqueue_cli-0.1.1}/src/fluxqueue_cli/worker.py +133 -23
- fluxqueue_cli-0.1.0b4/src/fluxqueue_cli/__init__.py +0 -1
- {fluxqueue_cli-0.1.0b4 → fluxqueue_cli-0.1.1}/LICENSE +0 -0
- {fluxqueue_cli-0.1.0b4 → fluxqueue_cli-0.1.1}/src/fluxqueue_cli/exceptions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fluxqueue-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: A command-line tool for installing and running FluxQueue workers
|
|
5
5
|
Author-Email: Giorgi Merebashvili <mereba2627@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -9,9 +9,7 @@ Requires-Python: <3.15,>=3.11
|
|
|
9
9
|
Requires-Dist: typer>=0.17.0
|
|
10
10
|
Requires-Dist: requests>=2.29.0
|
|
11
11
|
Provides-Extra: dev
|
|
12
|
-
Requires-Dist: black; extra == "dev"
|
|
13
12
|
Requires-Dist: ruff; extra == "dev"
|
|
14
|
-
Requires-Dist: pdm; extra == "dev"
|
|
15
13
|
Description-Content-Type: text/markdown
|
|
16
14
|
|
|
17
15
|
## FluxQueue CLI
|
|
@@ -34,7 +32,7 @@ fluxqueue worker install
|
|
|
34
32
|
|
|
35
33
|
## Starting a Worker
|
|
36
34
|
|
|
37
|
-
To start a worker, provide the path to the module where your tasks are
|
|
35
|
+
To start a worker, provide the path to the module where your tasks are exported:
|
|
38
36
|
|
|
39
37
|
```bash
|
|
40
38
|
fluxqueue start --tasks-module-path src/tasks
|
|
@@ -18,7 +18,7 @@ fluxqueue worker install
|
|
|
18
18
|
|
|
19
19
|
## Starting a Worker
|
|
20
20
|
|
|
21
|
-
To start a worker, provide the path to the module where your tasks are
|
|
21
|
+
To start a worker, provide the path to the module where your tasks are exported:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
fluxqueue start --tasks-module-path src/tasks
|
|
@@ -21,26 +21,22 @@ dependencies = [
|
|
|
21
21
|
"typer>=0.17.0",
|
|
22
22
|
"requests>=2.29.0",
|
|
23
23
|
]
|
|
24
|
-
version = "0.1.
|
|
24
|
+
version = "0.1.1"
|
|
25
25
|
|
|
26
26
|
[project.scripts]
|
|
27
27
|
fluxqueue = "fluxqueue_cli.cli:app"
|
|
28
28
|
|
|
29
29
|
[project.optional-dependencies]
|
|
30
30
|
dev = [
|
|
31
|
-
"black",
|
|
32
31
|
"ruff",
|
|
33
|
-
"pdm",
|
|
34
32
|
]
|
|
35
33
|
|
|
36
34
|
[tool.pdm.version]
|
|
37
35
|
source = "file"
|
|
38
36
|
path = "src/fluxqueue_cli/__init__.py"
|
|
39
37
|
|
|
40
|
-
[tool.
|
|
41
|
-
line-length =
|
|
42
|
-
include = "\\.pyi?$"
|
|
43
|
-
preview = true
|
|
38
|
+
[tool.ruff]
|
|
39
|
+
line-length = 88
|
|
44
40
|
|
|
45
41
|
[tool.ruff.lint]
|
|
46
42
|
select = [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.1"
|
|
@@ -78,11 +78,21 @@ def start(
|
|
|
78
78
|
@worker_app.command(name="install")
|
|
79
79
|
def worker_install(
|
|
80
80
|
version: Annotated[
|
|
81
|
+
str | None,
|
|
82
|
+
typer.Option(help="Version to install. If omitted, installs the latest."),
|
|
83
|
+
] = None,
|
|
84
|
+
path: Annotated[
|
|
81
85
|
str | None,
|
|
82
86
|
typer.Option(
|
|
83
|
-
help="
|
|
87
|
+
help="Custom destination path. Otherwise installation will require sudo permissions."
|
|
84
88
|
),
|
|
85
89
|
] = None,
|
|
90
|
+
force: Annotated[
|
|
91
|
+
bool,
|
|
92
|
+
typer.Option(
|
|
93
|
+
help="In case of already installed worker in the destination path using this flag will force the installation."
|
|
94
|
+
),
|
|
95
|
+
] = False,
|
|
86
96
|
):
|
|
87
97
|
"""
|
|
88
98
|
Download and install [bold]fluxqueue-worker[/bold].
|
|
@@ -95,16 +105,14 @@ def worker_install(
|
|
|
95
105
|
"Invalid version. Please use versions like: 0.1.0, 0.2.3"
|
|
96
106
|
)
|
|
97
107
|
|
|
98
|
-
download_and_install(version)
|
|
108
|
+
download_and_install(version, path, force)
|
|
99
109
|
|
|
100
110
|
|
|
101
111
|
@worker_app.command(name="update")
|
|
102
112
|
def worker_update(
|
|
103
113
|
version: Annotated[
|
|
104
114
|
str | None,
|
|
105
|
-
typer.Option(
|
|
106
|
-
help="Version to update to. If omitted, updates to the latest."
|
|
107
|
-
),
|
|
115
|
+
typer.Option(help="Version to update to. If omitted, updates to the latest."),
|
|
108
116
|
] = None,
|
|
109
117
|
no_backup: Annotated[
|
|
110
118
|
bool,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tomllib
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_fluxqueue_config():
|
|
7
|
+
toml_path = Path(os.getcwd()) / "pyproject.toml"
|
|
8
|
+
|
|
9
|
+
if not toml_path.exists():
|
|
10
|
+
return {}
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
with open(toml_path, "rb") as f:
|
|
14
|
+
data = tomllib.load(f)
|
|
15
|
+
return data.get("tool", {}).get("fluxqueue_cli", {})
|
|
16
|
+
|
|
17
|
+
except (tomllib.TOMLDecodeError, PermissionError):
|
|
18
|
+
return {}
|
|
@@ -3,12 +3,15 @@ import platform
|
|
|
3
3
|
import shutil
|
|
4
4
|
import subprocess
|
|
5
5
|
import sys
|
|
6
|
+
import sysconfig
|
|
6
7
|
import tarfile
|
|
7
8
|
import tempfile
|
|
9
|
+
import zipfile
|
|
8
10
|
from pathlib import Path
|
|
9
11
|
|
|
10
12
|
import requests
|
|
11
13
|
|
|
14
|
+
from fluxqueue_cli.config import get_fluxqueue_config
|
|
12
15
|
from fluxqueue_cli.exceptions import (
|
|
13
16
|
AlreadyInstalledError,
|
|
14
17
|
BinaryNotFoundError,
|
|
@@ -19,9 +22,14 @@ from fluxqueue_cli.exceptions import (
|
|
|
19
22
|
|
|
20
23
|
REPO = "CCXLV/fluxqueue"
|
|
21
24
|
BINARY_NAME = "fluxqueue-worker"
|
|
22
|
-
|
|
25
|
+
if platform.system() == "Windows":
|
|
26
|
+
user_profile = os.environ.get("USERPROFILE", os.path.expanduser("~"))
|
|
27
|
+
install_dir = os.path.join(user_profile, ".fluxqueue", "bin")
|
|
28
|
+
INSTALL_DIR = install_dir
|
|
29
|
+
else:
|
|
30
|
+
INSTALL_DIR = "/usr/local/bin"
|
|
23
31
|
|
|
24
|
-
# TODO:
|
|
32
|
+
# TODO: Add startup wrapper support
|
|
25
33
|
|
|
26
34
|
|
|
27
35
|
def start_worker(
|
|
@@ -32,6 +40,9 @@ def start_worker(
|
|
|
32
40
|
queue: str,
|
|
33
41
|
save_dead_tasks=False,
|
|
34
42
|
):
|
|
43
|
+
config = get_fluxqueue_config()
|
|
44
|
+
worker_path = config.get("worker_path", "fluxqueue-worker")
|
|
45
|
+
|
|
35
46
|
# fmt: off
|
|
36
47
|
arguments = [
|
|
37
48
|
"--concurrency", str(concurrency),
|
|
@@ -44,18 +55,28 @@ def start_worker(
|
|
|
44
55
|
if save_dead_tasks:
|
|
45
56
|
arguments.append("--save-dead-tasks")
|
|
46
57
|
|
|
58
|
+
lib_dir = sysconfig.get_config_var("LIBDIR")
|
|
59
|
+
env = os.environ.copy()
|
|
60
|
+
if lib_dir:
|
|
61
|
+
current_ld = env.get("LD_LIBRARY_PATH", "")
|
|
62
|
+
env["LD_LIBRARY_PATH"] = f"{lib_dir}:{current_ld}" if current_ld else lib_dir
|
|
63
|
+
|
|
47
64
|
subprocess.run(
|
|
48
|
-
[
|
|
65
|
+
[worker_path, *arguments],
|
|
49
66
|
stdin=sys.stdin,
|
|
50
67
|
stdout=sys.stdout,
|
|
51
68
|
stderr=sys.stderr,
|
|
69
|
+
env=env,
|
|
52
70
|
)
|
|
53
71
|
|
|
54
72
|
|
|
55
73
|
def get_worker_version() -> str | None:
|
|
74
|
+
config = get_fluxqueue_config()
|
|
75
|
+
worker_path = config.get("worker_path", "fluxqueue-worker")
|
|
76
|
+
|
|
56
77
|
try:
|
|
57
78
|
result = subprocess.run(
|
|
58
|
-
[
|
|
79
|
+
[worker_path, "--version"],
|
|
59
80
|
check=True,
|
|
60
81
|
capture_output=True,
|
|
61
82
|
text=True,
|
|
@@ -140,14 +161,11 @@ def download_worker_binary(version: str | None = None):
|
|
|
140
161
|
|
|
141
162
|
|
|
142
163
|
def install_worker(
|
|
143
|
-
*,
|
|
164
|
+
*,
|
|
165
|
+
dest_path: Path,
|
|
166
|
+
actual_file_name: str,
|
|
167
|
+
temp_file_path: str,
|
|
144
168
|
):
|
|
145
|
-
dest_path = Path(INSTALL_DIR) / BINARY_NAME
|
|
146
|
-
if dest_path.exists() and not overwrite:
|
|
147
|
-
raise FileExistsError(
|
|
148
|
-
f"fluxqueue-worker is already installed at {dest_path}"
|
|
149
|
-
)
|
|
150
|
-
|
|
151
169
|
# Linux
|
|
152
170
|
if actual_file_name.endswith(".tar.gz"):
|
|
153
171
|
with tarfile.open(temp_file_path, "r:gz") as tar:
|
|
@@ -161,27 +179,103 @@ def install_worker(
|
|
|
161
179
|
except:
|
|
162
180
|
delete_installed_files(temp_file_path)
|
|
163
181
|
raise
|
|
164
|
-
#
|
|
182
|
+
# macOS + Windows
|
|
183
|
+
elif actual_file_name.endswith(".zip"):
|
|
184
|
+
with tempfile.TemporaryDirectory() as extract_temp_dir:
|
|
185
|
+
with zipfile.ZipFile(temp_file_path, "r") as zip_file:
|
|
186
|
+
zip_file.extractall(extract_temp_dir)
|
|
187
|
+
|
|
188
|
+
exe_name = (
|
|
189
|
+
f"{BINARY_NAME}.exe" if platform.system() == "Windows" else BINARY_NAME
|
|
190
|
+
)
|
|
191
|
+
found_binary = None
|
|
192
|
+
|
|
193
|
+
for root, _dirs, files in os.walk(extract_temp_dir):
|
|
194
|
+
if exe_name in files:
|
|
195
|
+
found_binary = Path(root) / exe_name
|
|
196
|
+
break
|
|
197
|
+
|
|
198
|
+
if not found_binary:
|
|
199
|
+
for root, _dirs, files in os.walk(extract_temp_dir):
|
|
200
|
+
for file in files:
|
|
201
|
+
if BINARY_NAME in file and (
|
|
202
|
+
platform.system() != "Windows" or file.endswith(".exe")
|
|
203
|
+
):
|
|
204
|
+
found_binary = Path(root) / file
|
|
205
|
+
break
|
|
206
|
+
if found_binary:
|
|
207
|
+
break
|
|
208
|
+
|
|
209
|
+
if not found_binary:
|
|
210
|
+
try:
|
|
211
|
+
os.remove(temp_file_path)
|
|
212
|
+
except PermissionError:
|
|
213
|
+
raise PermissionError(
|
|
214
|
+
f"Permission denied: Could not remove temporary file {temp_file_path}. "
|
|
215
|
+
"Please remove it manually."
|
|
216
|
+
) from None
|
|
217
|
+
except OSError as e:
|
|
218
|
+
if e.errno == 13: # Permission denied (EACCES)
|
|
219
|
+
raise PermissionError(
|
|
220
|
+
f"Permission denied: Could not remove temporary file {temp_file_path}. "
|
|
221
|
+
"Please remove it manually."
|
|
222
|
+
) from e
|
|
223
|
+
raise BinaryNotFoundError(
|
|
224
|
+
f"Could not find {exe_name} in the downloaded archive."
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
dest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
228
|
+
shutil.copy2(found_binary, dest_path)
|
|
229
|
+
|
|
230
|
+
if platform.system() != "Windows":
|
|
231
|
+
os.chmod(dest_path, 0o755)
|
|
232
|
+
try:
|
|
233
|
+
os.remove(temp_file_path)
|
|
234
|
+
except PermissionError:
|
|
235
|
+
raise PermissionError(
|
|
236
|
+
f"Permission denied: Could not remove temporary file {temp_file_path}. "
|
|
237
|
+
"Please remove it manually."
|
|
238
|
+
) from None
|
|
239
|
+
except OSError as e:
|
|
240
|
+
if e.errno == 13: # Permission denied (EACCES)
|
|
241
|
+
raise PermissionError(
|
|
242
|
+
f"Permission denied: Could not remove temporary file {temp_file_path}. "
|
|
243
|
+
"Please remove it manually."
|
|
244
|
+
) from e
|
|
245
|
+
raise
|
|
165
246
|
else:
|
|
166
247
|
delete_installed_files(temp_file_path)
|
|
167
|
-
raise NotImplementedError(
|
|
168
|
-
|
|
169
|
-
|
|
248
|
+
raise NotImplementedError("Only .tar.gz installation is implemented yet.")
|
|
249
|
+
|
|
250
|
+
print(f"Successfully installed {BINARY_NAME} to {dest_path}")
|
|
170
251
|
|
|
171
|
-
print(f"Successfully installed {BINARY_NAME} to {INSTALL_DIR}")
|
|
172
252
|
|
|
253
|
+
def download_and_install(
|
|
254
|
+
version: str | None = None, custom_dest_path: str | None = None, force: bool = False
|
|
255
|
+
):
|
|
256
|
+
dest_path = get_destination_path(custom_dest_path, force)
|
|
173
257
|
|
|
174
|
-
|
|
175
|
-
if shutil.which("fluxqueue-worker"):
|
|
258
|
+
if not custom_dest_path and shutil.which("fluxqueue-worker"):
|
|
176
259
|
raise AlreadyInstalledError(
|
|
177
260
|
"fluxqueue-worker is already installed, use `fluxqueue worker update` command to update it."
|
|
178
261
|
)
|
|
179
262
|
|
|
180
263
|
temp_path, target_name = download_worker_binary(version)
|
|
181
|
-
install_worker(
|
|
264
|
+
install_worker(
|
|
265
|
+
dest_path=dest_path,
|
|
266
|
+
actual_file_name=target_name,
|
|
267
|
+
temp_file_path=temp_path,
|
|
268
|
+
)
|
|
269
|
+
|
|
182
270
|
|
|
271
|
+
def update_worker(
|
|
272
|
+
*,
|
|
273
|
+
version: str | None = None,
|
|
274
|
+
custom_dest_path: str | None = None,
|
|
275
|
+
no_backup: bool = False,
|
|
276
|
+
):
|
|
277
|
+
dest_path = get_destination_path(custom_dest_path, no_backup)
|
|
183
278
|
|
|
184
|
-
def update_worker(*, version: str | None = None, no_backup: bool = False):
|
|
185
279
|
current_version = get_worker_version()
|
|
186
280
|
|
|
187
281
|
if not current_version:
|
|
@@ -193,21 +287,37 @@ def update_worker(*, version: str | None = None, no_backup: bool = False):
|
|
|
193
287
|
if version:
|
|
194
288
|
print(f"Desired Version: {version}")
|
|
195
289
|
|
|
196
|
-
|
|
290
|
+
backup_suffix = ".exe.backup" if platform.system() == "Windows" else ".backup"
|
|
291
|
+
|
|
197
292
|
if not no_backup:
|
|
198
293
|
new_name = os.path.join(
|
|
199
|
-
INSTALL_DIR, f"{BINARY_NAME}-{current_version}
|
|
294
|
+
INSTALL_DIR, f"{BINARY_NAME}-{current_version}{backup_suffix}"
|
|
200
295
|
)
|
|
201
296
|
os.rename(dest_path, new_name)
|
|
202
297
|
|
|
203
298
|
temp_path, target_name = download_worker_binary(version)
|
|
204
299
|
install_worker(
|
|
300
|
+
dest_path=dest_path,
|
|
205
301
|
actual_file_name=target_name,
|
|
206
302
|
temp_file_path=temp_path,
|
|
207
|
-
overwrite=no_backup,
|
|
208
303
|
)
|
|
209
304
|
|
|
210
305
|
|
|
306
|
+
def get_destination_path(custom_dest_path: str | None = None, force: bool = False):
|
|
307
|
+
dest_dir = Path(custom_dest_path) if custom_dest_path else Path(INSTALL_DIR)
|
|
308
|
+
if platform.system() == "Windows":
|
|
309
|
+
dest_path = dest_dir / f"{BINARY_NAME}.exe"
|
|
310
|
+
else:
|
|
311
|
+
dest_path = dest_dir / BINARY_NAME
|
|
312
|
+
|
|
313
|
+
if dest_path.exists() and not force:
|
|
314
|
+
raise FileExistsError(
|
|
315
|
+
f"fluxqueue-worker is already installed at {dest_path}. Use --force flag for forcing the installation."
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
return dest_path
|
|
319
|
+
|
|
320
|
+
|
|
211
321
|
def delete_installed_files(temp_path: str):
|
|
212
322
|
os.remove(BINARY_NAME)
|
|
213
323
|
os.remove(temp_path)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.0b4"
|
|
File without changes
|
|
File without changes
|