primitive 0.2.31__py3-none-any.whl → 0.2.32__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/agent/actions.py +0 -4
- primitive/agent/runner.py +41 -24
- primitive/jobs/actions.py +10 -0
- primitive/jobs/graphql/queries.py +7 -0
- primitive/utils/shell.py +3 -1
- {primitive-0.2.31.dist-info → primitive-0.2.32.dist-info}/METADATA +1 -1
- {primitive-0.2.31.dist-info → primitive-0.2.32.dist-info}/RECORD +11 -11
- {primitive-0.2.31.dist-info → primitive-0.2.32.dist-info}/WHEEL +0 -0
- {primitive-0.2.31.dist-info → primitive-0.2.32.dist-info}/entry_points.txt +0 -0
- {primitive-0.2.31.dist-info → primitive-0.2.32.dist-info}/licenses/LICENSE.txt +0 -0
primitive/__about__.py
CHANGED
primitive/agent/actions.py
CHANGED
@@ -100,10 +100,6 @@ class Agent(BaseAction):
|
|
100
100
|
# This should probably eventually be another daemon?
|
101
101
|
uploader.scan()
|
102
102
|
|
103
|
-
JobRun.objects.filter_by(
|
104
|
-
job_run_id=api_job_run.get("id"),
|
105
|
-
).delete()
|
106
|
-
|
107
103
|
sleep(5)
|
108
104
|
except KeyboardInterrupt:
|
109
105
|
logger.info("[agent] Stopping primitive agent...")
|
primitive/agent/runner.py
CHANGED
@@ -25,7 +25,11 @@ if typing.TYPE_CHECKING:
|
|
25
25
|
|
26
26
|
CHUNK_SIZE = 64 * 1024
|
27
27
|
ENV_VAR_LOOKUP_START = "_ENV_VAR_LOOKUP_START"
|
28
|
+
START_DELIMITER_SIZE = len(bytes(ENV_VAR_LOOKUP_START, encoding="utf-8"))
|
28
29
|
ENV_VAR_LOOKUP_END = "_ENV_VAR_LOOKUP_END"
|
30
|
+
END_DELIMITER_SIZE = len(bytes(ENV_VAR_LOOKUP_END, encoding="utf-8"))
|
31
|
+
|
32
|
+
assert CHUNK_SIZE > START_DELIMITER_SIZE + END_DELIMITER_SIZE
|
29
33
|
|
30
34
|
|
31
35
|
class Task(TypedDict):
|
@@ -132,6 +136,10 @@ class Runner:
|
|
132
136
|
|
133
137
|
# Setup initial process environment
|
134
138
|
self.initial_env = os.environ
|
139
|
+
self.initial_env = {
|
140
|
+
**self.initial_env,
|
141
|
+
**self.primitive.jobs.get_job_secrets_for_job_run(self.job_run["id"]),
|
142
|
+
}
|
135
143
|
self.initial_env["PRIMITIVE_GIT_SHA"] = str(self.job_run["gitCommit"]["sha"])
|
136
144
|
self.initial_env["PRIMITIVE_GIT_BRANCH"] = str(
|
137
145
|
self.job_run["gitCommit"]["branch"]
|
@@ -253,12 +261,7 @@ class Runner:
|
|
253
261
|
args = [
|
254
262
|
"/bin/bash",
|
255
263
|
"-c",
|
256
|
-
|
257
|
-
f"{cmd} "
|
258
|
-
f"&& stdbuf -oL echo && stdbuf -oL echo '{ENV_VAR_LOOKUP_START}' "
|
259
|
-
"&& env "
|
260
|
-
f"&& stdbuf -oL echo && echo '{ENV_VAR_LOOKUP_END}'"
|
261
|
-
),
|
264
|
+
f"{cmd} && echo -n '{ENV_VAR_LOOKUP_START}' && env && echo -n '{ENV_VAR_LOOKUP_END}'",
|
262
265
|
]
|
263
266
|
|
264
267
|
process = await asyncio.create_subprocess_exec(
|
@@ -302,28 +305,32 @@ class Runner:
|
|
302
305
|
async def log_cmd(self, process, stream, tags: Dict = {}) -> bool:
|
303
306
|
failure_detected = False
|
304
307
|
parse_environment = False
|
305
|
-
|
308
|
+
last_chunk_buffer = b""
|
309
|
+
environment_buffer = b""
|
306
310
|
while chunk := await stream.read(CHUNK_SIZE):
|
307
|
-
|
308
|
-
|
309
|
-
empty_chunk = len(processed_lines) == 0
|
310
|
-
|
311
|
-
if empty_chunk:
|
312
|
-
# Ignore the empty lines
|
311
|
+
if parse_environment:
|
312
|
+
environment_buffer += chunk
|
313
313
|
continue
|
314
|
-
|
315
|
-
|
314
|
+
|
315
|
+
# First, look for start delimiter in chunk
|
316
|
+
full_chunk = last_chunk_buffer + chunk
|
317
|
+
last_chunk_buffer = b""
|
318
|
+
start_index = full_chunk.find(bytes(ENV_VAR_LOOKUP_START, encoding="utf-8"))
|
319
|
+
|
320
|
+
if start_index != -1:
|
321
|
+
environment_buffer = full_chunk[start_index + START_DELIMITER_SIZE :]
|
322
|
+
processed_lines = await self.read_chunk(full_chunk[:start_index])
|
316
323
|
parse_environment = True
|
317
|
-
|
318
|
-
|
319
|
-
# Done reading environment variables
|
320
|
-
parse_environment = False
|
321
|
-
self.modified_env = env_to_dict(env_lines)
|
322
|
-
continue
|
324
|
+
else:
|
325
|
+
processed_lines = await self.read_chunk(full_chunk)
|
323
326
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
+
while (
|
328
|
+
len(last_chunk_buffer) < START_DELIMITER_SIZE
|
329
|
+
and len(processed_lines) > 0
|
330
|
+
):
|
331
|
+
last_chunk_buffer += bytes(
|
332
|
+
processed_lines.pop() + "\n", encoding="utf-8"
|
333
|
+
)
|
327
334
|
|
328
335
|
# Handle logging
|
329
336
|
parse_logs = self.job_settings["parseLogs"]
|
@@ -356,6 +363,16 @@ class Runner:
|
|
356
363
|
|
357
364
|
logger.bind(tag=tag).log(level.value, line)
|
358
365
|
|
366
|
+
start_index = environment_buffer.find(
|
367
|
+
bytes(ENV_VAR_LOOKUP_END, encoding="utf-8")
|
368
|
+
)
|
369
|
+
if parse_environment and start_index == -1:
|
370
|
+
logger.error("Environment variable buffer did not contain end delimiter")
|
371
|
+
failure_detected = True
|
372
|
+
return failure_detected
|
373
|
+
|
374
|
+
environment_buffer = environment_buffer[:start_index]
|
375
|
+
self.modified_env = env_to_dict(environment_buffer)
|
359
376
|
return failure_detected
|
360
377
|
|
361
378
|
async def read_chunk(self, chunk: bytes) -> List[str]:
|
primitive/jobs/actions.py
CHANGED
@@ -11,6 +11,7 @@ from .graphql.queries import (
|
|
11
11
|
job_run_query,
|
12
12
|
job_run_status_query,
|
13
13
|
job_runs_query,
|
14
|
+
job_secrets_for_job_run_query,
|
14
15
|
jobs_query,
|
15
16
|
)
|
16
17
|
|
@@ -163,3 +164,12 @@ class Jobs(BaseAction):
|
|
163
164
|
query, variable_values=variables, get_execution_result=True
|
164
165
|
)
|
165
166
|
return result
|
167
|
+
|
168
|
+
@guard
|
169
|
+
def get_job_secrets_for_job_run(self, id: str):
|
170
|
+
query = gql(job_secrets_for_job_run_query)
|
171
|
+
variables = {"jobRunId": id}
|
172
|
+
result = self.primitive.session.execute(
|
173
|
+
query, variable_values=variables, get_execution_result=True
|
174
|
+
)
|
175
|
+
return result.data["jobSecretsForJobRun"]
|
primitive/utils/shell.py
CHANGED
@@ -35,12 +35,14 @@ def add_path_to_shell(path: Path):
|
|
35
35
|
return True
|
36
36
|
|
37
37
|
|
38
|
-
def env_to_dict(env_vars: Union[str, List[str]]) -> Dict:
|
38
|
+
def env_to_dict(env_vars: Union[bytes, str, List[str]]) -> Dict:
|
39
39
|
lines = None
|
40
40
|
if isinstance(env_vars, list):
|
41
41
|
lines = env_vars
|
42
42
|
elif isinstance(env_vars, str):
|
43
43
|
lines = env_vars.splitlines()
|
44
|
+
elif isinstance(env_vars, bytes):
|
45
|
+
lines = env_vars.decode("utf-8").splitlines()
|
44
46
|
else:
|
45
47
|
raise ValueError("Unsupported type. Env_vars must be a list or a string")
|
46
48
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: primitive
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.32
|
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,11 +1,11 @@
|
|
1
|
-
primitive/__about__.py,sha256=
|
1
|
+
primitive/__about__.py,sha256=oC0l5fABhgagaC-_r-5QZ1VPn7hy8tdJID7wI0iTSow,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=h8WZVnQylVe0vbpuyC8YZHl2JyITSPC-1HbUcmrE5pc,3623
|
5
5
|
primitive/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
primitive/agent/actions.py,sha256=
|
6
|
+
primitive/agent/actions.py,sha256=JLnHCtu0AgeHRZccCc2I39mziLixmj9EKtKeYmvBE7A,3700
|
7
7
|
primitive/agent/commands.py,sha256=cK7d3OcN5Z65gQWVZFQ-Y9ddw9Pes4f9OVBpeMsj5sE,255
|
8
|
-
primitive/agent/runner.py,sha256=
|
8
|
+
primitive/agent/runner.py,sha256=e4HBhK16zuhTpKAdKsgoij6G4YjMTn9JQo2YTLRI8i8,15008
|
9
9
|
primitive/agent/uploader.py,sha256=ZzrzsajNBogwEC7mT6Ejy0h2Jd9axMYGzt9pbCvVMlk,3171
|
10
10
|
primitive/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
11
|
primitive/auth/actions.py,sha256=9NIEXJ1BNJutJs6AMMSjMN_ziONUAUhY_xHwojYJCLA,942
|
@@ -51,12 +51,12 @@ primitive/hardware/graphql/fragments.py,sha256=kI6qnTNjaEaUr-C6eD55COphtueVYbYOW
|
|
51
51
|
primitive/hardware/graphql/mutations.py,sha256=_4Hkbfik9Ron4T-meulu6T-9FR_BZjyPNwn745MPksU,1484
|
52
52
|
primitive/hardware/graphql/queries.py,sha256=I86uLuOSjHSph11Y5MVCYko5Js7hoiEZ-cEoPTc4J-k,1392
|
53
53
|
primitive/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
|
-
primitive/jobs/actions.py,sha256=
|
54
|
+
primitive/jobs/actions.py,sha256=Fx2cPc1x09nRasOVtjhPjNRJ-jNoi3RJhXqC3verD9s,5444
|
55
55
|
primitive/jobs/commands.py,sha256=MxPCkBEYW_eLNqgCRYeyj7ZcLOFAWfpVZlqDR2Y_S0o,830
|
56
56
|
primitive/jobs/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
57
|
primitive/jobs/graphql/fragments.py,sha256=pS6jXZ9yxvPKjKx50zpwzARJHYlg7NQLYCm1voiuCzI,642
|
58
58
|
primitive/jobs/graphql/mutations.py,sha256=8ASvCmwQh7cMeeiykOdYaYVryG8FRIuVF6v_J8JJZuw,219
|
59
|
-
primitive/jobs/graphql/queries.py,sha256=
|
59
|
+
primitive/jobs/graphql/queries.py,sha256=ZxNmm-WovytbggNuKRnwa0kc26T34_0yhqkoqx-2uj0,1736
|
60
60
|
primitive/monitor/actions.py,sha256=aYe5OfgCxhapXbcvz7vSlIMAcLOFRcAUWmdBZ8H7UWs,10889
|
61
61
|
primitive/monitor/commands.py,sha256=VDlEL_Qpm_ysHxug7VpI0cVAZ0ny6AS91Y58D7F1zkU,409
|
62
62
|
primitive/organizations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -94,10 +94,10 @@ primitive/utils/daemons.py,sha256=mSoSHitiGfS4KYAEK9sKsiv_YcACHKgY3qISnDpUUIE,10
|
|
94
94
|
primitive/utils/exceptions.py,sha256=DrYHTcCAJGC7cCUwOx_FmdlVLWRdpzvDvpLb82heppE,311
|
95
95
|
primitive/utils/memory_size.py,sha256=4xfha21kW82nFvOTtDFx9Jk2ZQoEhkfXii-PGNTpIUk,3058
|
96
96
|
primitive/utils/printer.py,sha256=f1XUpqi5dkTL3GWvYRUGlSwtj2IxU1q745T4Fxo7Tn4,370
|
97
|
-
primitive/utils/shell.py,sha256=
|
97
|
+
primitive/utils/shell.py,sha256=Z4zxmOaSyGCrS0D6I436iQci-ewHLt4UxVg1CD9Serc,2171
|
98
98
|
primitive/utils/text.py,sha256=XiESMnlhjQ534xE2hMNf08WehE1SKaYFRNih0MmnK0k,829
|
99
|
-
primitive-0.2.
|
100
|
-
primitive-0.2.
|
101
|
-
primitive-0.2.
|
102
|
-
primitive-0.2.
|
103
|
-
primitive-0.2.
|
99
|
+
primitive-0.2.32.dist-info/METADATA,sha256=z-2bverx3L8RAyVNxxYWBv_-3UjdTgfZbk_ety8Swlo,3569
|
100
|
+
primitive-0.2.32.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
101
|
+
primitive-0.2.32.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
|
102
|
+
primitive-0.2.32.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
|
103
|
+
primitive-0.2.32.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|