Merge ~jugmac00/lpci:add-conda-build-plugin into lpci:main
- Git
- lp:~jugmac00/lpci
- add-conda-build-plugin
- Merge into main
Proposed by
Jürgen Gmach
Status: | Merged |
---|---|
Merged at revision: | aceb166cd84dde2d25ecfbb9571097b4ea300c5a |
Proposed branch: | ~jugmac00/lpci:add-conda-build-plugin |
Merge into: | lpci:main |
Diff against target: |
623 lines (+597/-1) 2 files modified
lpcraft/plugin/tests/test_plugins.py (+419/-0) lpcraft/plugins/plugins.py (+178/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jürgen Gmach | Approve | ||
Review via email:
|
Commit message
- Add conda build plugin
- Test existing recipe folder with missing meta.yaml
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lpcraft/plugin/tests/test_plugins.py b/lpcraft/plugin/tests/test_plugins.py |
2 | index fe7d930..e0ec098 100644 |
3 | --- a/lpcraft/plugin/tests/test_plugins.py |
4 | +++ b/lpcraft/plugin/tests/test_plugins.py |
5 | @@ -483,3 +483,422 @@ class TestPlugins(CommandBaseTestCase): |
6 | plugin_match[0].conda_channels, |
7 | ) |
8 | self.assertEqual(["PYTHON=3.8", "pip"], plugin_match[0].conda_packages) |
9 | + |
10 | + @patch("lpcraft.commands.run.get_provider") |
11 | + @patch("lpcraft.commands.run.get_host_architecture", return_value="amd64") |
12 | + def test_conda_build_plugin( |
13 | + self, mock_get_host_architecture, mock_get_provider |
14 | + ): |
15 | + launcher = Mock(spec=launch) |
16 | + provider = makeLXDProvider(lxd_launcher=launcher) |
17 | + mock_get_provider.return_value = provider |
18 | + execute_run = launcher.return_value.execute_run |
19 | + execute_run.return_value = subprocess.CompletedProcess([], 0) |
20 | + config = dedent( |
21 | + """ |
22 | + pipeline: |
23 | + - build |
24 | + |
25 | + jobs: |
26 | + build: |
27 | + series: focal |
28 | + architectures: amd64 |
29 | + plugin: conda-build |
30 | + build-target: info/recipe/parent |
31 | + conda-channels: |
32 | + - conda-forge |
33 | + conda-packages: |
34 | + - mamba |
35 | + - pip |
36 | + conda-python: 3.8 |
37 | + run: | |
38 | + pip install --upgrade pytest |
39 | + """ |
40 | + ) |
41 | + Path(".launchpad.yaml").write_text(config) |
42 | + Path("info/recipe/parent").mkdir(parents=True) |
43 | + Path("info/recipe/meta.yaml").touch() |
44 | + Path("info/recipe/parent/meta.yaml").touch() |
45 | + pre_run_command = dedent( |
46 | + """ |
47 | + if [ ! -d "$HOME/miniconda3" ]; then |
48 | + wget -O /tmp/miniconda.sh https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh |
49 | + chmod +x /tmp/miniconda.sh |
50 | + /tmp/miniconda.sh -b |
51 | + fi |
52 | + export PATH=$HOME/miniconda3/bin:$PATH |
53 | + conda remove --all -q -y -n $CONDA_ENV |
54 | + conda create -n $CONDA_ENV -q -y -c conda-forge -c defaults PYTHON=3.8 conda-build mamba pip |
55 | + source activate $CONDA_ENV |
56 | + """ # noqa:E501 |
57 | + ) |
58 | + run_command = dedent( |
59 | + """ |
60 | + export PATH=$HOME/miniconda3/bin:$PATH |
61 | + source activate $CONDA_ENV |
62 | + conda-build --no-anaconda-upload --output-folder dist -c conda-forge -c defaults info/recipe/parent |
63 | + pip install --upgrade pytest |
64 | + """ # noqa: E501 |
65 | + ) |
66 | + post_run_command = ( |
67 | + "export PATH=$HOME/miniconda3/bin:$PATH; " |
68 | + "source activate $CONDA_ENV; conda env export" |
69 | + ) |
70 | + |
71 | + self.run_command("run") |
72 | + |
73 | + self.assertEqual( |
74 | + [ |
75 | + call( |
76 | + ["apt", "update"], |
77 | + cwd=PosixPath("/root/lpcraft/project"), |
78 | + env={"CONDA_ENV": "lpci"}, |
79 | + stdout=ANY, |
80 | + stderr=ANY, |
81 | + ), |
82 | + call( |
83 | + [ |
84 | + "apt", |
85 | + "install", |
86 | + "-y", |
87 | + "git", |
88 | + "python3-dev", |
89 | + "python3-pip", |
90 | + "python3-venv", |
91 | + "wget", |
92 | + "automake", |
93 | + "build-essential", |
94 | + "cmake", |
95 | + "gcc", |
96 | + "g++", |
97 | + "libc++-dev", |
98 | + "libc6-dev", |
99 | + "libffi-dev", |
100 | + "libjpeg-dev", |
101 | + "libpng-dev", |
102 | + "libreadline-dev", |
103 | + "libsqlite3-dev", |
104 | + "libtool", |
105 | + "zlib1g-dev", |
106 | + ], |
107 | + cwd=PosixPath("/root/lpcraft/project"), |
108 | + env={"CONDA_ENV": "lpci"}, |
109 | + stdout=ANY, |
110 | + stderr=ANY, |
111 | + ), |
112 | + call( |
113 | + [ |
114 | + "bash", |
115 | + "--noprofile", |
116 | + "--norc", |
117 | + "-ec", |
118 | + pre_run_command, |
119 | + ], |
120 | + cwd=PosixPath("/root/lpcraft/project"), |
121 | + env={"CONDA_ENV": "lpci"}, |
122 | + stdout=ANY, |
123 | + stderr=ANY, |
124 | + ), |
125 | + call( |
126 | + [ |
127 | + "bash", |
128 | + "--noprofile", |
129 | + "--norc", |
130 | + "-ec", |
131 | + run_command, |
132 | + ], |
133 | + cwd=PosixPath("/root/lpcraft/project"), |
134 | + env={"CONDA_ENV": "lpci"}, |
135 | + stdout=ANY, |
136 | + stderr=ANY, |
137 | + ), |
138 | + call( |
139 | + [ |
140 | + "bash", |
141 | + "--noprofile", |
142 | + "--norc", |
143 | + "-ec", |
144 | + post_run_command, |
145 | + ], |
146 | + cwd=PosixPath("/root/lpcraft/project"), |
147 | + env={"CONDA_ENV": "lpci"}, |
148 | + stdout=ANY, |
149 | + stderr=ANY, |
150 | + ), |
151 | + ], |
152 | + execute_run.call_args_list, |
153 | + ) |
154 | + |
155 | + def test_conda_build_plugin_finds_recipe(self): |
156 | + config = dedent( |
157 | + """ |
158 | + pipeline: |
159 | + - build |
160 | + |
161 | + jobs: |
162 | + build: |
163 | + series: focal |
164 | + architectures: amd64 |
165 | + plugin: conda-build |
166 | + conda-channels: |
167 | + - conda-forge |
168 | + conda-packages: |
169 | + - mamba |
170 | + - pip |
171 | + conda-python: 3.8 |
172 | + run: | |
173 | + pip install --upgrade pytest |
174 | + """ |
175 | + ) |
176 | + config_path = Path(".launchpad.yaml") |
177 | + config_path.write_text(config) |
178 | + Path("include/fake_subdir").mkdir(parents=True) |
179 | + meta_yaml = Path("info/recipe/meta.yaml") |
180 | + meta_yaml.parent.mkdir(parents=True) |
181 | + meta_yaml.touch() |
182 | + config_obj = lpcraft.config.Config.load(config_path) |
183 | + self.assertEqual(config_obj.jobs["build"][0].plugin, "conda-build") |
184 | + pm = get_plugin_manager(config_obj.jobs["build"][0]) |
185 | + plugins = pm.get_plugins() |
186 | + plugin_match = [ |
187 | + _ for _ in plugins if _.__class__.__name__ == "CondaBuildPlugin" |
188 | + ] |
189 | + self.assertEqual("info/recipe", plugin_match[0].build_target) |
190 | + |
191 | + def test_conda_build_plugin_finds_recipe_with_fake_parent(self): |
192 | + config = dedent( |
193 | + """ |
194 | + pipeline: |
195 | + - build |
196 | + |
197 | + jobs: |
198 | + build: |
199 | + series: focal |
200 | + architectures: amd64 |
201 | + plugin: conda-build |
202 | + conda-channels: |
203 | + - conda-forge |
204 | + conda-packages: |
205 | + - mamba |
206 | + - pip |
207 | + conda-python: 3.8 |
208 | + run: | |
209 | + pip install --upgrade pytest |
210 | + """ |
211 | + ) |
212 | + config_path = Path(".launchpad.yaml") |
213 | + config_path.write_text(config) |
214 | + meta_yaml = Path("info/recipe/meta.yaml") |
215 | + meta_yaml.parent.mkdir(parents=True) |
216 | + parent_path = meta_yaml.parent.joinpath("parent") |
217 | + parent_path.mkdir() |
218 | + parent_path.joinpath("some_file.yaml").touch() |
219 | + meta_yaml.touch() |
220 | + config_obj = lpcraft.config.Config.load(config_path) |
221 | + self.assertEqual(config_obj.jobs["build"][0].plugin, "conda-build") |
222 | + pm = get_plugin_manager(config_obj.jobs["build"][0]) |
223 | + plugins = pm.get_plugins() |
224 | + plugin_match = [ |
225 | + _ for _ in plugins if _.__class__.__name__ == "CondaBuildPlugin" |
226 | + ] |
227 | + self.assertEqual("info/recipe", plugin_match[0].build_target) |
228 | + |
229 | + def test_conda_build_plugin_finds_parent_recipe(self): |
230 | + config = dedent( |
231 | + """ |
232 | + pipeline: |
233 | + - build |
234 | + |
235 | + jobs: |
236 | + build: |
237 | + series: focal |
238 | + architectures: amd64 |
239 | + plugin: conda-build |
240 | + conda-channels: |
241 | + - conda-forge |
242 | + conda-packages: |
243 | + - mamba |
244 | + - pip |
245 | + conda-python: 3.8 |
246 | + run: | |
247 | + pip install --upgrade pytest |
248 | + """ |
249 | + ) |
250 | + config_path = Path(".launchpad.yaml") |
251 | + config_path.write_text(config) |
252 | + Path("include/fake_subdir").mkdir(parents=True) |
253 | + meta_yaml = Path("info/recipe/meta.yaml") |
254 | + parent_meta_yaml = meta_yaml.parent.joinpath("parent/meta.yaml") |
255 | + parent_meta_yaml.parent.mkdir(parents=True) |
256 | + meta_yaml.touch() |
257 | + parent_meta_yaml.touch() |
258 | + config_obj = lpcraft.config.Config.load(config_path) |
259 | + self.assertEqual(config_obj.jobs["build"][0].plugin, "conda-build") |
260 | + pm = get_plugin_manager(config_obj.jobs["build"][0]) |
261 | + plugins = pm.get_plugins() |
262 | + plugin_match = [ |
263 | + _ for _ in plugins if _.__class__.__name__ == "CondaBuildPlugin" |
264 | + ] |
265 | + self.assertEqual("info/recipe/parent", plugin_match[0].build_target) |
266 | + |
267 | + def test_conda_build_plugin_uses_child_vars_with_parent_recipe(self): |
268 | + config = dedent( |
269 | + """ |
270 | + pipeline: |
271 | + - build |
272 | + |
273 | + jobs: |
274 | + build: |
275 | + series: focal |
276 | + architectures: amd64 |
277 | + plugin: conda-build |
278 | + conda-channels: |
279 | + - conda-forge |
280 | + conda-packages: |
281 | + - mamba |
282 | + - pip |
283 | + conda-python: 3.8 |
284 | + run: | |
285 | + pip install --upgrade pytest |
286 | + """ |
287 | + ) |
288 | + run_command = dedent( |
289 | + """ |
290 | + export PATH=$HOME/miniconda3/bin:$PATH |
291 | + source activate $CONDA_ENV |
292 | + conda-build --no-anaconda-upload --output-folder dist -c conda-forge -c defaults -m info/recipe/parent/conda_build_config.yaml -m info/recipe/conda_build_config.yaml info/recipe/parent |
293 | + pip install --upgrade pytest |
294 | + """ # noqa: E501 |
295 | + ) |
296 | + config_path = Path(".launchpad.yaml") |
297 | + config_path.write_text(config) |
298 | + Path("include/fake_subdir").mkdir(parents=True) |
299 | + meta_yaml = Path("info/recipe/meta.yaml") |
300 | + variant_config = meta_yaml.with_name("conda_build_config.yaml") |
301 | + parent_meta_yaml = meta_yaml.parent.joinpath("parent/meta.yaml") |
302 | + parent_variant_config = parent_meta_yaml.with_name( |
303 | + "conda_build_config.yaml" |
304 | + ) |
305 | + parent_meta_yaml.parent.mkdir(parents=True) |
306 | + meta_yaml.touch() |
307 | + variant_config.touch() |
308 | + parent_variant_config.touch() |
309 | + parent_meta_yaml.touch() |
310 | + config_obj = lpcraft.config.Config.load(config_path) |
311 | + self.assertEqual(config_obj.jobs["build"][0].plugin, "conda-build") |
312 | + pm = get_plugin_manager(config_obj.jobs["build"][0]) |
313 | + plugins = pm.get_plugins() |
314 | + plugin_match = [ |
315 | + _ for _ in plugins if _.__class__.__name__ == "CondaBuildPlugin" |
316 | + ] |
317 | + self.assertEqual( |
318 | + [parent_variant_config.as_posix(), variant_config.as_posix()], |
319 | + plugin_match[0].build_configs, |
320 | + ) |
321 | + self.assertEqual(run_command, plugin_match[0].lpcraft_execute_run()) |
322 | + |
323 | + def test_conda_build_plugin_renames_recipe_templates(self): |
324 | + config = dedent( |
325 | + """ |
326 | + pipeline: |
327 | + - build |
328 | + |
329 | + jobs: |
330 | + build: |
331 | + series: focal |
332 | + architectures: amd64 |
333 | + plugin: conda-build |
334 | + conda-channels: |
335 | + - conda-forge |
336 | + conda-packages: |
337 | + - mamba |
338 | + - pip |
339 | + conda-python: 3.8 |
340 | + run: | |
341 | + pip install --upgrade pytest |
342 | + """ |
343 | + ) |
344 | + config_path = Path(".launchpad.yaml") |
345 | + config_path.write_text(config) |
346 | + meta_yaml = Path("info/recipe/meta.yaml") |
347 | + template_meta_yaml = meta_yaml.with_name("meta.yaml.template") |
348 | + meta_yaml.parent.mkdir(parents=True) |
349 | + meta_yaml.touch() |
350 | + template_meta_yaml.touch() |
351 | + config_obj = lpcraft.config.Config.load(config_path) |
352 | + self.assertEqual(config_obj.jobs["build"][0].plugin, "conda-build") |
353 | + pm = get_plugin_manager(config_obj.jobs["build"][0]) |
354 | + plugins = pm.get_plugins() |
355 | + plugin_match = [ |
356 | + _ for _ in plugins if _.__class__.__name__ == "CondaBuildPlugin" |
357 | + ] |
358 | + self.assertEqual("info/recipe", plugin_match[0].build_target) |
359 | + self.assertFalse(template_meta_yaml.is_file()) |
360 | + |
361 | + def test_conda_build_plugin_raises_error_if_no_recipe(self): |
362 | + config = dedent( |
363 | + """ |
364 | + pipeline: |
365 | + - build |
366 | + |
367 | + jobs: |
368 | + build: |
369 | + series: focal |
370 | + architectures: amd64 |
371 | + plugin: conda-build |
372 | + conda-channels: |
373 | + - conda-forge |
374 | + conda-packages: |
375 | + - mamba |
376 | + - pip |
377 | + conda-python: 3.8 |
378 | + run: | |
379 | + pip install --upgrade pytest |
380 | + """ |
381 | + ) |
382 | + config_path = Path(".launchpad.yaml") |
383 | + config_path.write_text(config) |
384 | + config_obj = lpcraft.config.Config.load(config_path) |
385 | + self.assertRaisesRegex( |
386 | + RuntimeError, |
387 | + "No build target found", |
388 | + get_plugin_manager, |
389 | + config_obj.jobs["build"][0], |
390 | + ) |
391 | + |
392 | + def test_conda_build_plugin_raises_error_if_no_recipe_in_recipe_folder( |
393 | + self, |
394 | + ): |
395 | + config = dedent( |
396 | + """ |
397 | + pipeline: |
398 | + - build |
399 | + |
400 | + jobs: |
401 | + build: |
402 | + series: focal |
403 | + architectures: amd64 |
404 | + plugin: conda-build |
405 | + conda-channels: |
406 | + - conda-forge |
407 | + conda-packages: |
408 | + - mamba |
409 | + - pip |
410 | + conda-python: 3.8 |
411 | + run: | |
412 | + pip install --upgrade pytest |
413 | + """ |
414 | + ) |
415 | + config_path = Path(".launchpad.yaml") |
416 | + config_path.write_text(config) |
417 | + Path("include/fake_subdir").mkdir(parents=True) |
418 | + # there is a recipe folder, but no meta.yaml file |
419 | + meta_yaml = Path("info/recipe/") |
420 | + meta_yaml.mkdir(parents=True) |
421 | + config_obj = lpcraft.config.Config.load(config_path) |
422 | + self.assertRaisesRegex( |
423 | + RuntimeError, |
424 | + "No build target found", |
425 | + get_plugin_manager, |
426 | + config_obj.jobs["build"][0], |
427 | + ) |
428 | diff --git a/lpcraft/plugins/plugins.py b/lpcraft/plugins/plugins.py |
429 | index c114030..0797fba 100644 |
430 | --- a/lpcraft/plugins/plugins.py |
431 | +++ b/lpcraft/plugins/plugins.py |
432 | @@ -3,9 +3,15 @@ |
433 | |
434 | from __future__ import annotations # isort:skip |
435 | |
436 | -__all__ = ["ToxPlugin", "PyProjectBuildPlugin", "MiniCondaPlugin"] |
437 | +__all__ = [ |
438 | + "ToxPlugin", |
439 | + "PyProjectBuildPlugin", |
440 | + "MiniCondaPlugin", |
441 | + "CondaBuildPlugin", |
442 | +] |
443 | |
444 | import textwrap |
445 | +from pathlib import Path |
446 | from typing import TYPE_CHECKING, ClassVar, List, Optional, cast |
447 | |
448 | import pydantic |
449 | @@ -213,3 +219,174 @@ class MiniCondaPlugin(BasePlugin): |
450 | "export PATH=$HOME/miniconda3/bin:$PATH; " |
451 | f"source activate $CONDA_ENV; conda env export{run}" |
452 | ) |
453 | + |
454 | + |
455 | +@register(name="conda-build") |
456 | +class CondaBuildPlugin(MiniCondaPlugin): |
457 | + """Sets up `miniconda3` and performs a `conda-build` on a package. |
458 | + |
459 | + Usage: |
460 | + In `.launchpad.yaml`, create the following structure: |
461 | + |
462 | + .. code-block:: yaml |
463 | + |
464 | + jobs: |
465 | + myjob: |
466 | + plugin: conda-build |
467 | + build-target: info/recipe/parent |
468 | + conda-channels: |
469 | + - conda-forge |
470 | + - defaults |
471 | + conda-packages: |
472 | + - mamba |
473 | + - numpy=1.17 |
474 | + - scipy |
475 | + - pip |
476 | + conda-python: 3.8 |
477 | + run: | |
478 | + conda install .... |
479 | + pip install --upgrade pytest |
480 | + python -m build . |
481 | + """ |
482 | + |
483 | + class Config(MiniCondaPlugin.Config): |
484 | + build_target: Optional[StrictStr] |
485 | + conda_channels: Optional[List[StrictStr]] |
486 | + conda_packages: Optional[List[StrictStr]] |
487 | + conda_python: Optional[StrictStr] |
488 | + |
489 | + DEFAULT_CONDA_PACKAGES = ("conda-build",) |
490 | + |
491 | + def get_plugin_config(self) -> "CondaBuildPlugin.Config": |
492 | + return cast(CondaBuildPlugin.Config, self.config.plugin_config) |
493 | + |
494 | + @staticmethod |
495 | + def _has_recipe(dir_: Path) -> bool: |
496 | + return dir_.joinpath("meta.yaml").is_file() |
497 | + |
498 | + @staticmethod |
499 | + def _rename_recipe_template(dir_: Path) -> None: |
500 | + # XXX techalchemy 2022-04-01: conda packages which are already built |
501 | + # and subsequently downloaded from the anaconda repositories retain |
502 | + # the templated recipe, at `meta.yaml.template`, but place the |
503 | + # rendered template at `meta.yaml`. The rendered recipes contain |
504 | + # hardcoded paths for a specific build environment and, for our |
505 | + # purposes, are not reusable. We need to render new ones from the |
506 | + # original templates. |
507 | + template_path = dir_.joinpath("meta.yaml.template") |
508 | + if template_path.is_file(): |
509 | + template_path.replace(dir_ / "meta.yaml") |
510 | + |
511 | + def find_recipe(self) -> Path: |
512 | + def _find_recipe_dir(path: Path) -> Path: |
513 | + for subpath in path.iterdir(): |
514 | + if subpath.is_dir(): |
515 | + self._rename_recipe_template(subpath) |
516 | + if subpath.name == "recipe" and self._has_recipe(subpath): |
517 | + return subpath |
518 | + try: |
519 | + return _find_recipe_dir(subpath) |
520 | + except FileNotFoundError: |
521 | + continue |
522 | + raise FileNotFoundError |
523 | + |
524 | + return _find_recipe_dir(Path(".")) |
525 | + |
526 | + def find_build_target(self) -> str: |
527 | + def find_parents(pth: Path) -> Path: |
528 | + for parent in pth.iterdir(): |
529 | + if parent.is_dir(): |
530 | + self._rename_recipe_template(parent) |
531 | + if parent.name == "parent" and self._has_recipe(parent): |
532 | + return parent |
533 | + raise FileNotFoundError(pth.joinpath("meta.yaml")) |
534 | + |
535 | + try: |
536 | + recipe = self.find_recipe() |
537 | + except FileNotFoundError: |
538 | + raise RuntimeError("No build target found") |
539 | + try: |
540 | + # XXX techalchemy 2022-04-01: Some conda packages are built as |
541 | + # part of a parent package build process (e.g. `mkl-include` which |
542 | + # is built by `intel_repack`). If you acquire the child package |
543 | + # and attempt to build it (`mkl-include` in this case) it will |
544 | + # fail; you must build the parent instead if it exists |
545 | + return find_parents(recipe).as_posix() |
546 | + except FileNotFoundError: |
547 | + return recipe.as_posix() |
548 | + |
549 | + @property |
550 | + def build_configs(self) -> list[str]: |
551 | + try: |
552 | + recipe = self.find_recipe() |
553 | + except FileNotFoundError: |
554 | + return [] |
555 | + configs = sorted( |
556 | + recipe.glob("**/conda_build_config.yaml"), reverse=True |
557 | + ) |
558 | + return [_.as_posix() for _ in configs] |
559 | + |
560 | + @property |
561 | + def build_target(self) -> str: |
562 | + build_target = self.get_plugin_config().build_target |
563 | + if not build_target: |
564 | + return self.find_build_target() |
565 | + return build_target |
566 | + |
567 | + @hookimpl # type: ignore |
568 | + def lpcraft_set_environment(self) -> dict[str, str]: |
569 | + # XXX techalchemy 2022-04-01: mypy is struggling with the super() call |
570 | + rv: dict[str, str] = super().lpcraft_set_environment() |
571 | + return rv |
572 | + |
573 | + @hookimpl # type: ignore |
574 | + def lpcraft_execute_before_run(self) -> str: |
575 | + # XXX techalchemy 2022-04-01: mypy is struggling with the super() call |
576 | + rv: str = super().lpcraft_execute_before_run() |
577 | + return rv |
578 | + |
579 | + @hookimpl # type: ignore |
580 | + def lpcraft_execute_after_run(self) -> str: |
581 | + # XXX techalchemy 2022-04-01: mypy is struggling with the super() call |
582 | + rv: str = super().lpcraft_execute_after_run() |
583 | + return rv |
584 | + |
585 | + @hookimpl # type: ignore |
586 | + def lpcraft_install_packages(self) -> list[str]: |
587 | + # XXX techalchemy 2022-04-01: mypy is struggling with the super() call |
588 | + base_packages: list[str] = super().lpcraft_install_packages() |
589 | + base_packages.extend( |
590 | + [ |
591 | + "automake", |
592 | + "build-essential", |
593 | + "cmake", |
594 | + "gcc", |
595 | + "g++", |
596 | + "libc++-dev", |
597 | + "libc6-dev", |
598 | + "libffi-dev", |
599 | + "libjpeg-dev", |
600 | + "libpng-dev", |
601 | + "libreadline-dev", |
602 | + "libsqlite3-dev", |
603 | + "libtool", |
604 | + "zlib1g-dev", |
605 | + ] |
606 | + ) |
607 | + return base_packages |
608 | + |
609 | + @hookimpl # type: ignore |
610 | + def lpcraft_execute_run(self) -> str: |
611 | + conda_channels = " ".join(f"-c {_}" for _ in self.conda_channels) |
612 | + conda_channels = f" {conda_channels}" if conda_channels else "" |
613 | + configs = " ".join(f"-m {_}" for _ in self.build_configs) |
614 | + configs = f" {configs}" if configs else "" |
615 | + build_command = "conda-build --no-anaconda-upload --output-folder dist" |
616 | + run_command = self.config.run or "" |
617 | + return textwrap.dedent( |
618 | + f""" |
619 | + export PATH=$HOME/miniconda3/bin:$PATH |
620 | + source activate $CONDA_ENV |
621 | + {build_command}{conda_channels}{configs} {self.build_target} |
622 | + {run_command}""" |
623 | + ) |
self approve - implementation already approved via https:/ /code.launchpad .net/~techalche my/lpcraft/ +git/lpcraft/ +merge/ 423301
I only added one test to cover one previously uncovered line.