primitive 0.2.59__py3-none-any.whl → 0.2.60__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.
- primitive/__about__.py +1 -1
- primitive/files/actions.py +73 -7
- primitive/files/commands.py +59 -2
- primitive/files/graphql/fragments.py +5 -2
- primitive/files/ui.py +37 -0
- primitive/hardware/actions.py +5 -4
- primitive/jobs/actions.py +1 -0
- primitive/monitor/actions.py +1 -1
- {primitive-0.2.59.dist-info → primitive-0.2.60.dist-info}/METADATA +1 -1
- {primitive-0.2.59.dist-info → primitive-0.2.60.dist-info}/RECORD +13 -12
- {primitive-0.2.59.dist-info → primitive-0.2.60.dist-info}/WHEEL +0 -0
- {primitive-0.2.59.dist-info → primitive-0.2.60.dist-info}/entry_points.txt +0 -0
- {primitive-0.2.59.dist-info → primitive-0.2.60.dist-info}/licenses/LICENSE.txt +0 -0
primitive/__about__.py
CHANGED
primitive/files/actions.py
CHANGED
@@ -124,15 +124,39 @@ class Files(BaseAction):
|
|
124
124
|
return result
|
125
125
|
|
126
126
|
@guard
|
127
|
-
def
|
127
|
+
def files(
|
128
|
+
self,
|
129
|
+
file_id: Optional[str] = None,
|
130
|
+
file_name: Optional[str] = None,
|
131
|
+
organization_id: Optional[str] = None,
|
132
|
+
organization_slug: Optional[str] = None,
|
133
|
+
):
|
128
134
|
query = gql(files_list)
|
129
135
|
|
130
136
|
filters = {}
|
137
|
+
if not organization_id and not organization_slug:
|
138
|
+
whoami_result = self.primitive.auth.whoami()
|
139
|
+
default_organization = whoami_result.data["whoami"]["defaultOrganization"]
|
140
|
+
organization_id = default_organization["id"]
|
141
|
+
logger.info(
|
142
|
+
f"Using default organization ID: {default_organization.get('slug')} ({organization_id})"
|
143
|
+
)
|
144
|
+
if organization_slug and not organization_id:
|
145
|
+
organization = self.primitive.organizations.get_organization(
|
146
|
+
slug=organization_slug
|
147
|
+
)
|
148
|
+
organization_id = organization.get("id")
|
149
|
+
|
150
|
+
if organization_id:
|
151
|
+
filters["organization"] = {"id": organization_id}
|
152
|
+
|
131
153
|
if file_id:
|
132
|
-
filters["id"] =
|
154
|
+
filters["id"] = file_id
|
155
|
+
if file_name:
|
156
|
+
filters["fileName"] = {"exact": file_name}
|
133
157
|
|
134
158
|
variables = {
|
135
|
-
"first":
|
159
|
+
"first": 25,
|
136
160
|
"filters": filters,
|
137
161
|
}
|
138
162
|
result = self.primitive.session.execute(
|
@@ -242,9 +266,9 @@ class Files(BaseAction):
|
|
242
266
|
file_id = pending_file_create.get("id")
|
243
267
|
parts_details = pending_file_create.get("partsDetails")
|
244
268
|
else:
|
245
|
-
|
269
|
+
file_result = self.files(file_id=file_id)
|
246
270
|
parts_details = (
|
247
|
-
|
271
|
+
file_result.data.get("files")
|
248
272
|
.get("edges")[0]
|
249
273
|
.get("node")
|
250
274
|
.get("partsDetails")
|
@@ -340,14 +364,56 @@ class Files(BaseAction):
|
|
340
364
|
"fileObject": (path.name, open(path, "rb")),
|
341
365
|
}
|
342
366
|
|
343
|
-
session = create_requests_session(self.primitive.host_config)
|
367
|
+
session = create_requests_session(host_config=self.primitive.host_config)
|
344
368
|
transport = self.primitive.host_config.get("transport")
|
345
369
|
url = f"{transport}://{self.primitive.host}/"
|
346
370
|
response = session.post(url, files=body)
|
347
371
|
return response
|
348
372
|
|
349
|
-
def get_presigned_url(self, file_pk: str):
|
373
|
+
def get_presigned_url(self, file_pk: str) -> str:
|
350
374
|
transport = self.primitive.host_config.get("transport")
|
351
375
|
host = self.primitive.host_config.get("host")
|
352
376
|
file_access_url = f"{transport}://{host}/files/{file_pk}/presigned-url/"
|
353
377
|
return file_access_url
|
378
|
+
|
379
|
+
def download_file(
|
380
|
+
self,
|
381
|
+
file_name: str = "",
|
382
|
+
file_id: str = "",
|
383
|
+
organization_id: str = "",
|
384
|
+
organization_slug: str = "",
|
385
|
+
output_path: Path = Path().cwd(),
|
386
|
+
) -> Path:
|
387
|
+
file_pk = None
|
388
|
+
|
389
|
+
files_result = self.primitive.files.files(
|
390
|
+
file_id=file_id,
|
391
|
+
file_name=file_name,
|
392
|
+
organization_id=organization_id,
|
393
|
+
organization_slug=organization_slug,
|
394
|
+
)
|
395
|
+
if files_data := files_result.data:
|
396
|
+
file = files_data["files"]["edges"][0]["node"]
|
397
|
+
file_pk = file["pk"]
|
398
|
+
file_name = file["fileName"]
|
399
|
+
|
400
|
+
if not file_pk:
|
401
|
+
raise Exception(
|
402
|
+
"File not found on remote server. Please check file name or file id"
|
403
|
+
)
|
404
|
+
|
405
|
+
session = create_requests_session(host_config=self.primitive.host_config)
|
406
|
+
transport = self.primitive.host_config.get("transport")
|
407
|
+
url = f"{transport}://{self.primitive.host}/files/{file_pk}/stream/"
|
408
|
+
|
409
|
+
downloaded_file = output_path / file_name
|
410
|
+
|
411
|
+
with session.get(url, stream=True) as response:
|
412
|
+
response.raise_for_status()
|
413
|
+
with open(downloaded_file, "wb") as partial_downloaded_file:
|
414
|
+
for chunk in response.iter_content(chunk_size=8192):
|
415
|
+
if chunk:
|
416
|
+
partial_downloaded_file.write(chunk)
|
417
|
+
partial_downloaded_file.flush()
|
418
|
+
|
419
|
+
return downloaded_file
|
primitive/files/commands.py
CHANGED
@@ -4,6 +4,8 @@ from pathlib import Path
|
|
4
4
|
|
5
5
|
import click
|
6
6
|
|
7
|
+
from primitive.files.ui import render_files_table
|
8
|
+
|
7
9
|
from ..utils.printer import print_result
|
8
10
|
|
9
11
|
if typing.TYPE_CHECKING:
|
@@ -22,7 +24,7 @@ def cli(context):
|
|
22
24
|
@click.argument("path", type=click.Path(exists=True))
|
23
25
|
@click.option("--public", "-p", help="Is this a Public file", is_flag=True)
|
24
26
|
@click.option("--key-prefix", "-k", help="Key Prefix", default="")
|
25
|
-
@click.option("--direct",
|
27
|
+
@click.option("--direct", help="direct", is_flag=True)
|
26
28
|
def file_upload_command(context, path, public, key_prefix, direct):
|
27
29
|
"""File Upload"""
|
28
30
|
primitive: Primitive = context.obj.get("PRIMITIVE")
|
@@ -36,8 +38,63 @@ def file_upload_command(context, path, public, key_prefix, direct):
|
|
36
38
|
path, is_public=public, key_prefix=key_prefix
|
37
39
|
)
|
38
40
|
try:
|
39
|
-
message = json.dumps(result.
|
41
|
+
message = json.dumps(result.json())
|
40
42
|
except AttributeError:
|
41
43
|
message = "File Upload Failed"
|
42
44
|
|
43
45
|
print_result(message=message, context=context)
|
46
|
+
|
47
|
+
|
48
|
+
@cli.command("download")
|
49
|
+
@click.pass_context
|
50
|
+
@click.option("--file-id", help="File ID", required=False)
|
51
|
+
@click.option("--file-name", help="File Name", required=False)
|
52
|
+
@click.option("--output", help="Output Path", required=False, type=click.Path())
|
53
|
+
@click.option("--organization-id", help="Organization ID", required=False)
|
54
|
+
@click.option("--organization", help="Organization Slug", required=False)
|
55
|
+
def file_download_command(
|
56
|
+
context,
|
57
|
+
file_id=None,
|
58
|
+
file_name=None,
|
59
|
+
output=None,
|
60
|
+
organization_id=None,
|
61
|
+
organization=None,
|
62
|
+
):
|
63
|
+
"""File Download"""
|
64
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
65
|
+
|
66
|
+
if not file_id and not file_name:
|
67
|
+
raise click.UsageError("Either --id or --file-name must be provided.")
|
68
|
+
|
69
|
+
if not output:
|
70
|
+
output = Path().cwd()
|
71
|
+
else:
|
72
|
+
output = Path(output)
|
73
|
+
|
74
|
+
downloaded_file = primitive.files.download_file(
|
75
|
+
output_path=output,
|
76
|
+
file_id=file_id,
|
77
|
+
file_name=file_name,
|
78
|
+
organization_id=organization_id,
|
79
|
+
organization_slug=organization,
|
80
|
+
)
|
81
|
+
print_result(message=f"File downloaded to {downloaded_file}", context=context)
|
82
|
+
|
83
|
+
|
84
|
+
@cli.command("list")
|
85
|
+
@click.pass_context
|
86
|
+
@click.option("--organization-id", help="Organization ID", required=False)
|
87
|
+
@click.option("--organization", help="Organization Slug", required=False)
|
88
|
+
def list_command(context, organization_id=None, organization=None):
|
89
|
+
"""List Files"""
|
90
|
+
primitive: Primitive = context.obj.get("PRIMITIVE")
|
91
|
+
files_result = primitive.files.files(
|
92
|
+
organization_id=organization_id, organization_slug=organization
|
93
|
+
)
|
94
|
+
|
95
|
+
files = [file.get("node") for file in files_result.data.get("files").get("edges")]
|
96
|
+
|
97
|
+
if context.obj["JSON"]:
|
98
|
+
print_result(message=files, context=context)
|
99
|
+
else:
|
100
|
+
render_files_table(files)
|
@@ -4,7 +4,11 @@ fragment FileFragment on File {
|
|
4
4
|
pk
|
5
5
|
createdAt
|
6
6
|
updatedAt
|
7
|
-
createdBy
|
7
|
+
createdBy {
|
8
|
+
id
|
9
|
+
pk
|
10
|
+
username
|
11
|
+
}
|
8
12
|
location
|
9
13
|
fileName
|
10
14
|
fileSize
|
@@ -13,6 +17,5 @@ fragment FileFragment on File {
|
|
13
17
|
isComplete
|
14
18
|
partsDetails
|
15
19
|
humanReadableMemorySize
|
16
|
-
contents
|
17
20
|
}
|
18
21
|
"""
|
primitive/files/ui.py
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
from rich.console import Console
|
2
|
+
from rich.table import Table
|
3
|
+
|
4
|
+
|
5
|
+
def render_files_table(file_list) -> None:
|
6
|
+
console = Console()
|
7
|
+
|
8
|
+
table = Table(show_header=True, header_style="bold #FFA800")
|
9
|
+
table.add_column("File Name")
|
10
|
+
table.add_column("File ID")
|
11
|
+
table.add_column("File Size (bytes)", justify="right")
|
12
|
+
|
13
|
+
for file in file_list:
|
14
|
+
file_name = file.get("fileName")
|
15
|
+
file_id = file.get("id")
|
16
|
+
file_size = file.get("fileSize")
|
17
|
+
|
18
|
+
table.add_row(
|
19
|
+
file_name,
|
20
|
+
file_id,
|
21
|
+
file_size,
|
22
|
+
)
|
23
|
+
|
24
|
+
console.print(table)
|
25
|
+
|
26
|
+
|
27
|
+
def file_status_string(file) -> str:
|
28
|
+
if file.get("isQuarantined"):
|
29
|
+
return "Quarantined"
|
30
|
+
if not file.get("isOnline"):
|
31
|
+
return "Offline"
|
32
|
+
if not file.get("isHealthy"):
|
33
|
+
return "Not healthy"
|
34
|
+
if not file.get("isAvailable"):
|
35
|
+
return "Not available"
|
36
|
+
else:
|
37
|
+
return "Available"
|
primitive/hardware/actions.py
CHANGED
@@ -740,10 +740,11 @@ class Hardware(BaseAction):
|
|
740
740
|
logger.exception(f"Error checking in children: {exception}")
|
741
741
|
|
742
742
|
def push_metrics(self):
|
743
|
-
self.primitive.messaging.
|
744
|
-
|
745
|
-
|
746
|
-
|
743
|
+
if self.primitive.messaging.ready:
|
744
|
+
self.primitive.messaging.send_message(
|
745
|
+
message_type=MESSAGE_TYPES.METRICS,
|
746
|
+
message=self.get_metrics(),
|
747
|
+
)
|
747
748
|
|
748
749
|
def get_metrics(self):
|
749
750
|
cpu_percent = psutil.cpu_percent(interval=1, percpu=False)
|
primitive/jobs/actions.py
CHANGED
primitive/monitor/actions.py
CHANGED
@@ -67,7 +67,7 @@ class Monitor(BaseAction):
|
|
67
67
|
# handles cleanup of old reservations
|
68
68
|
# obtains an active JobRun's ID
|
69
69
|
if not RUNNING_IN_CONTAINER:
|
70
|
-
self.primitive.hardware.push_metrics()
|
70
|
+
# self.primitive.hardware.push_metrics()
|
71
71
|
|
72
72
|
hardware = self.primitive.hardware.get_own_hardware_details()
|
73
73
|
# fetch the latest hardware and activeReservation details
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: primitive
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.60
|
4
4
|
Project-URL: Documentation, https://github.com//primitivecorp/primitive-cli#readme
|
5
5
|
Project-URL: Issues, https://github.com//primitivecorp/primitive-cli/issues
|
6
6
|
Project-URL: Source, https://github.com//primitivecorp/primitive-cli
|
@@ -1,4 +1,4 @@
|
|
1
|
-
primitive/__about__.py,sha256=
|
1
|
+
primitive/__about__.py,sha256=PQj7AICmnMMGLJ9kvGOHRMY1k1xLtWYcSN-xiyaE_qY,130
|
2
2
|
primitive/__init__.py,sha256=bwKdgggKNVssJFVPfKSxqFMz4IxSr54WWbmiZqTMPNI,106
|
3
3
|
primitive/cli.py,sha256=g7EtHI9MATAB0qQu5w-WzbXtxz_8zu8z5E7sETmMkKU,2509
|
4
4
|
primitive/client.py,sha256=gyZIj61qMtOi_s8y0WG3gDehGT-Ms3BtbDP2J_2lajU,3753
|
@@ -23,10 +23,11 @@ primitive/exec/actions.py,sha256=4d_TCjNDcVFoZ9Zw7ZuBa6hKMv2Xzm7_UX_8wcX1aSk,412
|
|
23
23
|
primitive/exec/commands.py,sha256=66LO2kkJC-ynNZQpUCXv4Ol15QoacdSZAHblePDcmLo,510
|
24
24
|
primitive/exec/interactive.py,sha256=TscY6s2ZysijidKPheq6y-fCErUVLS0zcdTW8XyFWGI,2435
|
25
25
|
primitive/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
|
-
primitive/files/actions.py,sha256=
|
27
|
-
primitive/files/commands.py,sha256
|
26
|
+
primitive/files/actions.py,sha256=tuf5PXgNrcxegfzC-CZ6r3iWBkQV9gxZpALU-hjyGpY,14865
|
27
|
+
primitive/files/commands.py,sha256=-U0ArpZXDWltmkELG2SYIOLbaiMC6Zv24X9zZ29aqCE,3021
|
28
|
+
primitive/files/ui.py,sha256=lYnfu6gnZ5f-C28wps_egVDz8tdjL5P4361uxpSyfvY,919
|
28
29
|
primitive/files/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
29
|
-
primitive/files/graphql/fragments.py,sha256=
|
30
|
+
primitive/files/graphql/fragments.py,sha256=h_Gfi1a3o1_tTJfvW_HUvWmeo3VSSMcj38ObcUv7X7c,253
|
30
31
|
primitive/files/graphql/mutations.py,sha256=Da_e6WSp-fsCYVE9A6SGkIQy9WDzjeQycNyHEn7vJqE,935
|
31
32
|
primitive/files/graphql/queries.py,sha256=_ky-IRz928sKeSJuqaggTPxV4CGgmho3OyaAFu1z7nw,397
|
32
33
|
primitive/git/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -39,7 +40,7 @@ primitive/graphql/relay.py,sha256=bmij2AjdpURQ6GGVCxwWhauF-r_SxuAU2oJ4sDbLxpI,72
|
|
39
40
|
primitive/graphql/sdk.py,sha256=dE4TD8KiTKw3Y0uiw5XrIcuZGqexE47eSlPaPD6jDGo,1545
|
40
41
|
primitive/graphql/utility_fragments.py,sha256=uIjwILC4QtWNyO5vu77VjQf_p0jvP3A9q_6zRq91zqs,303
|
41
42
|
primitive/hardware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
42
|
-
primitive/hardware/actions.py,sha256=
|
43
|
+
primitive/hardware/actions.py,sha256=4xswcLaHk4IhEwRK5Pw_rpEgn6XciT5K2apnHi8_cI4,29204
|
43
44
|
primitive/hardware/android.py,sha256=tu7pBPxWFrIwb_mm5CEdFFf1_veNDOKjOCQg13i_Lh4,2758
|
44
45
|
primitive/hardware/commands.py,sha256=lwO-cm3doGtuGvR30fib-nALJyNCScdCTXOVVbYVpkY,4604
|
45
46
|
primitive/hardware/ui.py,sha256=12rucuZ2s-w5R4bKyxON5dEbrdDnVf5sbj3K_nbdo44,2473
|
@@ -48,7 +49,7 @@ primitive/hardware/graphql/fragments.py,sha256=H315uv-ujOsZEbQR5tmstbRU_9OCa5SEr
|
|
48
49
|
primitive/hardware/graphql/mutations.py,sha256=wOKNJN-1x_DGxvdHt2Bm3AUqyW8P1lNPkxLIQThbXUg,1874
|
49
50
|
primitive/hardware/graphql/queries.py,sha256=I86uLuOSjHSph11Y5MVCYko5Js7hoiEZ-cEoPTc4J-k,1392
|
50
51
|
primitive/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
51
|
-
primitive/jobs/actions.py,sha256
|
52
|
+
primitive/jobs/actions.py,sha256=-IRNO7KM63cPAbGRNQycyFsugW9hAyg-TDuK0g5AiSw,6542
|
52
53
|
primitive/jobs/commands.py,sha256=MxPCkBEYW_eLNqgCRYeyj7ZcLOFAWfpVZlqDR2Y_S0o,830
|
53
54
|
primitive/jobs/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
55
|
primitive/jobs/graphql/fragments.py,sha256=rWZWxZs9ZWjWal0eiY_XPWUS7i7f3fwSM_w8ZvDs2JQ,614
|
@@ -56,7 +57,7 @@ primitive/jobs/graphql/mutations.py,sha256=8ASvCmwQh7cMeeiykOdYaYVryG8FRIuVF6v_J
|
|
56
57
|
primitive/jobs/graphql/queries.py,sha256=ZxNmm-WovytbggNuKRnwa0kc26T34_0yhqkoqx-2uj0,1736
|
57
58
|
primitive/messaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
58
59
|
primitive/messaging/provider.py,sha256=NCgl1KiV4Ow49Laz2grNGsP7Ij4vUUeorUjkhAKF1H4,4182
|
59
|
-
primitive/monitor/actions.py,sha256=
|
60
|
+
primitive/monitor/actions.py,sha256=AZOoNzASorvye5309h6BJbsup_jR8YunQ19EiG5SAQg,9643
|
60
61
|
primitive/monitor/commands.py,sha256=VDlEL_Qpm_ysHxug7VpI0cVAZ0ny6AS91Y58D7F1zkU,409
|
61
62
|
primitive/organizations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
62
63
|
primitive/organizations/actions.py,sha256=kVHOhG1oS2sI5p8uldSo5L-RUZsnG36eaulVuKLyZ-M,1863
|
@@ -98,8 +99,8 @@ primitive/utils/psutil.py,sha256=xa7ef435UL37jyjmUPbEqCO2ayQMpCs0HCrxVEvLcuM,763
|
|
98
99
|
primitive/utils/shell.py,sha256=Z4zxmOaSyGCrS0D6I436iQci-ewHLt4UxVg1CD9Serc,2171
|
99
100
|
primitive/utils/text.py,sha256=XiESMnlhjQ534xE2hMNf08WehE1SKaYFRNih0MmnK0k,829
|
100
101
|
primitive/utils/x509.py,sha256=HwHRPqakTHWd40ny-9O_yNknSL1Cxo50O0UCjXHFq04,3796
|
101
|
-
primitive-0.2.
|
102
|
-
primitive-0.2.
|
103
|
-
primitive-0.2.
|
104
|
-
primitive-0.2.
|
105
|
-
primitive-0.2.
|
102
|
+
primitive-0.2.60.dist-info/METADATA,sha256=8_ftdlVATEzZHXucRmr6BnzxWhjjCPNhGju0EnVFX9c,3540
|
103
|
+
primitive-0.2.60.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
104
|
+
primitive-0.2.60.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
|
105
|
+
primitive-0.2.60.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
|
106
|
+
primitive-0.2.60.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|