Skip to content

Commit e0ad637

Browse files
simoncozensm4rc1e
authored andcommitted
Set up and build in own venv if requested
1 parent ecf213c commit e0ad637

File tree

1 file changed

+79
-18
lines changed

1 file changed

+79
-18
lines changed

Lib/gftools/packager/build.py

Lines changed: 79 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import subprocess
77
import tempfile
88
from pathlib import Path
9-
from typing import List, Optional
9+
from typing import Dict, List
10+
from venv import EnvBuilder
1011

1112
import git
1213
import yaml
@@ -130,6 +131,52 @@ def __init__(
130131
self.progressbar = None
131132
self.source_dir = tempfile.TemporaryDirectory()
132133

134+
def setup_venv(self, source_dir: Path):
135+
venv_task = self.progressbar.add_task(
136+
"[yellow]Setup venv", total=100, visible=False
137+
)
138+
self.progressbar.update(
139+
venv_task,
140+
description="[yellow] Setting up venv for " + self.name + "...",
141+
completed=0,
142+
visible=True,
143+
)
144+
if (source_dir / "Makefile").exists:
145+
with contextlib.chdir(source_dir):
146+
rc = self.run_command_with_callback(
147+
["make", "venv"],
148+
lambda line: self.progressbar.update(venv_task, advance=1),
149+
)
150+
elif (source_dir / "requirements.txt").exists:
151+
builder = EnvBuilder(system_site_packages=True, with_pip=True)
152+
builder.create(str(source_dir / "venv"))
153+
self.progressbar.update(venv_task, completed=10)
154+
with contextlib.chdir(source_dir):
155+
rc = self.run_command_with_callback(
156+
["venv/bin/pip", "install", "-r", "requirements.txt"],
157+
lambda line: self.progressbar.update(venv_task, advance=1),
158+
)
159+
else:
160+
raise ValueError(
161+
"--their-venv was provided but no Makefile or requirements.txt upstream"
162+
)
163+
if rc != 0:
164+
self.progressbar.console.print(
165+
"[red]Error setting up venv for " + self.name
166+
)
167+
raise ValueError("Venv setup failed")
168+
self.progressbar.remove_task(venv_task)
169+
170+
def local_overrides(
171+
self, upstream: Path, downstream: Path, overrides: Dict[str, str]
172+
):
173+
for source, dest in overrides.items():
174+
if (downstream / source).exists():
175+
dest_path = upstream / dest
176+
os.makedirs(dest_path.parent, exist_ok=True)
177+
self.progressbar.console.print("[grey]Using our " + source)
178+
shutil.copy(downstream / source, dest_path)
179+
133180
def build(self):
134181
with Progress(
135182
progress.TimeElapsedColumn(),
@@ -142,16 +189,19 @@ def build(self):
142189
with tempfile.TemporaryDirectory() as source_dir:
143190
source_dir = Path(source_dir)
144191
self.clone_source(source_dir)
145-
# Do we have our own local config.yaml?
146-
if (self.family_path / "config.yaml").exists():
147-
# If so, copy it over
148-
os.makedirs(source_dir / "sources", exist_ok=True)
149-
shutil.copy(
150-
self.family_path / "config.yaml", source_dir / "sources"
151-
)
192+
self.local_overrides(
193+
source_dir,
194+
self.family_path,
195+
{
196+
"config.yaml": "sources/config.yaml",
197+
"requirements.txt": "requirements.txt",
198+
},
199+
)
152200

153201
if not (source_dir / "sources").exists():
154202
raise ValueError(f"Could not find sources directory in {self.name}")
203+
if self.their_venv:
204+
self.setup_venv(source_dir)
155205

156206
# Locate the config.yaml file or first source
157207
arg = find_config_yaml(source_dir)
@@ -164,14 +214,18 @@ def build(self):
164214
arg = sources[0]
165215

166216
with contextlib.chdir(source_dir):
167-
buildcmd = ["gftools-builder", str(arg)]
217+
if self.their_venv:
218+
buildcmd = ["venv/bin/gftools-builder", str(arg)]
219+
else:
220+
buildcmd = ["gftools-builder", str(arg)]
168221
self.run_build_command(buildcmd)
169222
self.copy_files()
170223

171-
def run_build_command(self, buildcmd):
172-
build_task = self.progressbar.add_task("[green]Build " + self.name, total=1)
224+
def run_command_with_callback(self, cmd, callback):
173225
process = subprocess.Popen(
174-
buildcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
226+
cmd,
227+
stdout=subprocess.PIPE,
228+
stderr=subprocess.PIPE,
175229
)
176230
sel = selectors.DefaultSelector()
177231
sel.register(process.stdout, selectors.EVENT_READ)
@@ -185,12 +239,8 @@ def run_build_command(self, buildcmd):
185239
if not line:
186240
ok = False
187241
break
188-
if key.fileobj is process.stdout and (
189-
m := re.match(r"^\[(\d+)/(\d+)\]", line.decode("utf8"))
190-
):
191-
self.progressbar.update(
192-
build_task, completed=int(m.group(1)), total=int(m.group(2))
193-
)
242+
if key.fileobj is process.stdout:
243+
callback(line)
194244
elif key.fileobj is process.stderr:
195245
stderrlines.append(line)
196246
else:
@@ -201,7 +251,18 @@ def run_build_command(self, buildcmd):
201251
self.progressbar.console.print(line.decode("utf-8"), end="")
202252
for line in stderrlines:
203253
self.progressbar.console.print("[red]" + line.decode("utf8"), end="")
254+
return rc
255+
256+
def run_build_command(self, buildcmd):
257+
build_task = self.progressbar.add_task("[green]Build " + self.name, total=1)
258+
259+
def progress_callback(line):
260+
if m := re.match(r"^\[(\d+)/(\d+)\]", line.decode("utf8")):
261+
self.progressbar.update(
262+
build_task, completed=int(m.group(1)), total=int(m.group(2))
263+
)
204264

265+
if self.run_command_with_callback(buildcmd, progress_callback) != 0:
205266
self.progressbar.console.print("[red]Error building " + self.name)
206267
raise ValueError("Build failed")
207268
else:

0 commit comments

Comments
 (0)