primitive 0.1.47__py3-none-any.whl → 0.1.49__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 +1 -2
- primitive/agent/process.py +8 -1
- primitive/agent/provision.py +50 -0
- primitive/agent/runner.py +46 -5
- {primitive-0.1.47.dist-info → primitive-0.1.49.dist-info}/METADATA +1 -1
- {primitive-0.1.47.dist-info → primitive-0.1.49.dist-info}/RECORD +10 -9
- {primitive-0.1.47.dist-info → primitive-0.1.49.dist-info}/WHEEL +0 -0
- {primitive-0.1.47.dist-info → primitive-0.1.49.dist-info}/entry_points.txt +0 -0
- {primitive-0.1.47.dist-info → primitive-0.1.49.dist-info}/licenses/LICENSE.txt +0 -0
primitive/__about__.py
CHANGED
primitive/agent/actions.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import sys
|
2
|
-
import shutil
|
3
2
|
from time import sleep
|
4
3
|
from primitive.utils.actions import BaseAction
|
5
4
|
from loguru import logger
|
@@ -130,7 +129,7 @@ class Agent(BaseAction):
|
|
130
129
|
runner.execute()
|
131
130
|
|
132
131
|
# Clean up
|
133
|
-
shutil.rmtree(path=downloaded_git_repository_dir)
|
132
|
+
# shutil.rmtree(path=downloaded_git_repository_dir)
|
134
133
|
|
135
134
|
sleep(5)
|
136
135
|
except KeyboardInterrupt:
|
primitive/agent/process.py
CHANGED
@@ -8,9 +8,11 @@ class Process:
|
|
8
8
|
def __init__(
|
9
9
|
self,
|
10
10
|
cmd,
|
11
|
+
env,
|
11
12
|
workdir: str = ".",
|
12
13
|
):
|
13
14
|
self.cmd = shlex.split(cmd)
|
15
|
+
self.env = env
|
14
16
|
self.workdir = workdir
|
15
17
|
self.process = None
|
16
18
|
self.stdout_thread = None
|
@@ -22,7 +24,12 @@ class Process:
|
|
22
24
|
logger.info(f"cmd: {self.cmd}")
|
23
25
|
logger.info(f"workdir: {self.workdir}")
|
24
26
|
self.process = Popen(
|
25
|
-
self.cmd,
|
27
|
+
self.cmd,
|
28
|
+
env=self.env,
|
29
|
+
cwd=self.workdir,
|
30
|
+
stdout=PIPE,
|
31
|
+
stderr=PIPE,
|
32
|
+
text=True,
|
26
33
|
)
|
27
34
|
|
28
35
|
# Function to read and log output from a pipe
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import sys
|
2
|
+
from subprocess import Popen, PIPE
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Dict
|
5
|
+
|
6
|
+
|
7
|
+
class ProvisionPython:
|
8
|
+
def __init__(self, source_dir: Path, requirements_path: Path):
|
9
|
+
self.source_dir = source_dir
|
10
|
+
self.requirements_path = requirements_path
|
11
|
+
|
12
|
+
def create_env(self) -> Dict:
|
13
|
+
cmd = f"{sys.executable} -m ensurepip"
|
14
|
+
proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True, text=True)
|
15
|
+
proc.wait()
|
16
|
+
|
17
|
+
cmd = f"{sys.executable} -m pip install virtualenv"
|
18
|
+
proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True, text=True)
|
19
|
+
proc.wait()
|
20
|
+
|
21
|
+
cmd = f"{sys.executable} -m virtualenv {self.source_dir / "venv"}"
|
22
|
+
proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True, text=True)
|
23
|
+
proc.wait()
|
24
|
+
|
25
|
+
cmd = f"source {self.source_dir / "venv" / "bin" / "activate"} && env"
|
26
|
+
proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True, text=True)
|
27
|
+
proc.wait()
|
28
|
+
|
29
|
+
# Read the output and decode it
|
30
|
+
output, _ = proc.communicate()
|
31
|
+
|
32
|
+
# Split the output into lines and parse it into a dictionary
|
33
|
+
env_vars = {}
|
34
|
+
|
35
|
+
for line in output.splitlines():
|
36
|
+
key, value = line.split("=", 1)
|
37
|
+
env_vars[key] = value
|
38
|
+
|
39
|
+
cmd = f"python -m pip install -r {self.requirements_path}"
|
40
|
+
proc = Popen(
|
41
|
+
cmd,
|
42
|
+
env=env_vars,
|
43
|
+
stdout=PIPE,
|
44
|
+
stderr=PIPE,
|
45
|
+
shell=True,
|
46
|
+
text=True,
|
47
|
+
)
|
48
|
+
proc.wait()
|
49
|
+
|
50
|
+
return env_vars
|
primitive/agent/runner.py
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
import yaml
|
2
2
|
import sys
|
3
3
|
import typing
|
4
|
+
import os
|
4
5
|
from time import sleep
|
5
|
-
from typing import TypedDict, Iterable, List
|
6
|
+
from typing import TypedDict, Iterable, List, Optional, Dict
|
6
7
|
from pathlib import Path, PurePath
|
7
8
|
from loguru import logger
|
8
9
|
from .process import Process
|
10
|
+
from .provision import ProvisionPython
|
9
11
|
from ..utils.cache import get_artifacts_cache
|
10
12
|
from ..utils.files import find_files_for_extension
|
11
13
|
|
@@ -32,6 +34,7 @@ class JobStep(TypedDict):
|
|
32
34
|
|
33
35
|
class JobDescription(TypedDict):
|
34
36
|
name: str
|
37
|
+
provision: str
|
35
38
|
steps: List[JobStep]
|
36
39
|
|
37
40
|
|
@@ -92,15 +95,29 @@ class AgentRunner:
|
|
92
95
|
logger.info(f"Executing {self.job_slug} job")
|
93
96
|
self.primitive.jobs.job_run_update(self.job_id, status="request_in_progress")
|
94
97
|
|
98
|
+
# Initial environment is the system env
|
99
|
+
environment = os.environ
|
100
|
+
if "provision" in self.job:
|
101
|
+
logger.info(f"Provisioning for {self.job['provision']} environment")
|
102
|
+
environment = self.provision()
|
103
|
+
|
104
|
+
if not environment:
|
105
|
+
self.conclude("failure")
|
106
|
+
return
|
107
|
+
|
95
108
|
conclusion = None
|
96
109
|
total_errors = 0
|
97
110
|
for step in self.steps():
|
98
111
|
logger.info(f"Beginning step {step['name']}")
|
99
112
|
|
100
113
|
# Define step proc
|
101
|
-
logger.info(f"first cmd: {step[
|
102
|
-
logger.info(f"first workdir: {Path(self.source_dir / step[
|
103
|
-
proc = Process(
|
114
|
+
logger.info(f"first cmd: {step['cmd']}")
|
115
|
+
logger.info(f"first workdir: {Path(self.source_dir / step['workdir'])}")
|
116
|
+
proc = Process(
|
117
|
+
step["cmd"],
|
118
|
+
workdir=Path(self.source_dir / step["workdir"]),
|
119
|
+
env=environment,
|
120
|
+
)
|
104
121
|
|
105
122
|
# Try to start
|
106
123
|
try:
|
@@ -114,7 +131,14 @@ class AgentRunner:
|
|
114
131
|
while proc.is_running():
|
115
132
|
status = self.primitive.jobs.get_job_status(self.job_id)
|
116
133
|
|
117
|
-
|
134
|
+
status_value = status["jobRun"]["status"]
|
135
|
+
|
136
|
+
# TODO: Should probably use request_cancelled or something
|
137
|
+
# once we change it, we'll have to call conclude w/ cancelled status
|
138
|
+
if status_value == "completed":
|
139
|
+
logger.warning("Job cancelled by user")
|
140
|
+
proc.terminate()
|
141
|
+
return
|
118
142
|
|
119
143
|
sleep(5)
|
120
144
|
|
@@ -136,6 +160,9 @@ class AgentRunner:
|
|
136
160
|
logger.error(f"Job failed with {total_errors} errors.")
|
137
161
|
conclusion = "failure"
|
138
162
|
|
163
|
+
self.conclude(conclusion)
|
164
|
+
|
165
|
+
def conclude(self, conclusion: str) -> None:
|
139
166
|
self.primitive.jobs.job_run_update(
|
140
167
|
self.job_id, status="request_completed", conclusion=conclusion
|
141
168
|
)
|
@@ -143,6 +170,20 @@ class AgentRunner:
|
|
143
170
|
logger.info(f"Completed {self.job_slug} job")
|
144
171
|
logger.remove(self.logger_handle)
|
145
172
|
|
173
|
+
def provision(self) -> Optional[Dict]:
|
174
|
+
match self.job["provision"]:
|
175
|
+
case "python":
|
176
|
+
requirements_glob = self.source_dir.rglob("requirements.txt")
|
177
|
+
|
178
|
+
requirements_path = next(requirements_glob, None)
|
179
|
+
|
180
|
+
if not requirements_path:
|
181
|
+
logger.error("Unable to locate requirements.txt")
|
182
|
+
return None
|
183
|
+
|
184
|
+
prov = ProvisionPython(self.source_dir, requirements_path)
|
185
|
+
return prov.create_env()
|
186
|
+
|
146
187
|
def collect_artifacts(self, step: JobStep) -> None:
|
147
188
|
# str(PurePath(file_path).relative_to(Path(source))
|
148
189
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: primitive
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.49
|
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,12 @@
|
|
1
|
-
primitive/__about__.py,sha256=
|
1
|
+
primitive/__about__.py,sha256=aO6YNrTRSljxoBea_ti6ZOsiQThBvDI_TcvwjL4xAjQ,130
|
2
2
|
primitive/__init__.py,sha256=bwKdgggKNVssJFVPfKSxqFMz4IxSr54WWbmiZqTMPNI,106
|
3
3
|
primitive/cli.py,sha256=VQPSewC6ouGdEG9W1gllawGJTydpOY0Lzg7LURXcqQg,2374
|
4
4
|
primitive/client.py,sha256=vSJkifx450czuLvu0f2o-viSCC0p2f1UicA-2P5cJAw,2188
|
5
|
-
primitive/agent/actions.py,sha256=
|
5
|
+
primitive/agent/actions.py,sha256=R5ZvXD75H5XWdTvpmL5PDoSYnj7MCcfaDNQC0cqW-FU,5477
|
6
6
|
primitive/agent/commands.py,sha256=-dVDilELfkGfbZB7qfEPs77Dm1oT62qJj4tsIk4KoxI,254
|
7
|
-
primitive/agent/process.py,sha256=
|
8
|
-
primitive/agent/
|
7
|
+
primitive/agent/process.py,sha256=rbRB8MOxhTtMax-182Cwy_KP2I1fPyXLiu9p_GIE15Y,2451
|
8
|
+
primitive/agent/provision.py,sha256=L0N0uxyhToK4yklYO4exdlJRUk3SpK5h4DJ9egB35w4,1531
|
9
|
+
primitive/agent/runner.py,sha256=tYjzQyfd1rEAmkBQ5C8ghryR2weH9J0hTXSPS5ijapM,6490
|
9
10
|
primitive/agent/uploader.py,sha256=ngbynmQzxKVNMp7VWkTWW7vZIN_rnnRzYC6OAL21n1k,1378
|
10
11
|
primitive/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
12
|
primitive/auth/actions.py,sha256=2vZEC3LLAXj6eBBmt_2OEDEcBIb3uLkkNjgbZTIaQsY,1095
|
@@ -45,8 +46,8 @@ primitive/utils/memory_size.py,sha256=4xfha21kW82nFvOTtDFx9Jk2ZQoEhkfXii-PGNTpIU
|
|
45
46
|
primitive/utils/printer.py,sha256=f1XUpqi5dkTL3GWvYRUGlSwtj2IxU1q745T4Fxo7Tn4,370
|
46
47
|
primitive/utils/shell.py,sha256=-7UjQaBqSGHzEEyX8pNjeYFFP0P3lVnDV0OkgPz1qHU,1050
|
47
48
|
primitive/utils/verible.py,sha256=r7c_hfqvL0UicMmIzK3Cy_BfZI1ZpcfBeLqKEWFWqJo,2252
|
48
|
-
primitive-0.1.
|
49
|
-
primitive-0.1.
|
50
|
-
primitive-0.1.
|
51
|
-
primitive-0.1.
|
52
|
-
primitive-0.1.
|
49
|
+
primitive-0.1.49.dist-info/METADATA,sha256=Jc5CpG79Qfsp2IhMbRdrcm_Lg_RxUOLLOoqs2HaHJ8E,3782
|
50
|
+
primitive-0.1.49.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
51
|
+
primitive-0.1.49.dist-info/entry_points.txt,sha256=p1K8DMCWka5FqLlqP1sPek5Uovy9jq8u51gUsP-z334,48
|
52
|
+
primitive-0.1.49.dist-info/licenses/LICENSE.txt,sha256=B8kmQMJ2sxYygjCLBk770uacaMci4mPSoJJ8WoDBY_c,1098
|
53
|
+
primitive-0.1.49.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|