Skip to content

Commit 3f4b531

Browse files
committed
Add preparedepends
1 parent 22ab926 commit 3f4b531

3 files changed

Lines changed: 136 additions & 102 deletions

File tree

docs/recipe-format.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,29 @@ For example, `build:autotools` and `libvncserver>=0.9.13` are valid dependency s
209209

210210
**Dependencies declared in the `makedepends` field are only satisfied during the build process, not at install time** — see the [`installdepends`](#installdepends-field) below for declaring install-time dependencies.
211211

212+
#### `preparedepends` field
213+
214+
<table>
215+
<tr>
216+
<th>Required?</th>
217+
<td>No, defaults to <code>()</code></th>
218+
</tr>
219+
<tr>
220+
<th>Type</th>
221+
<td>Array of dependency specifications (strings)</td>
222+
</tr>
223+
</table>
224+
225+
The list of Debian, Toltec or Entware packages that are needed to prepare this package.
226+
Dependency specifications have the following format: `[host:|build:]package-name`.
227+
For example, `build:autotools` and `libvncserver>=0.9.13` are valid dependency specifications.
228+
229+
*Build-type dependencies* (prefixed with `build:`) are packages from Debian to install in the container’s root system before the recipe’s build script is executed.
230+
231+
*Host-type dependencies* (prefixed with `host:`) are packages from Toltec or Entware to install in the container’s `$SYSROOT` before the recipe’s build script is executed. The packages are offline-installed (i.e., none of their [install scripts](#install-section) are executed).
232+
233+
**Dependencies declared in the `preparedepends` field are only satisfied during the prepare process, not at install time** — see the [`installdepends`](#installdepends-field) below for declaring install-time dependencies.
234+
212235
#### `pkgnames` field
213236

214237
<table>

toltec/builder.py

Lines changed: 110 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from . import hooks
1616
from . import bash, util, ipk
1717
from .recipe import RecipeBundle, Recipe, Package
18-
from .version import DependencyKind
18+
from .version import Dependency, DependencyKind
1919

2020
logger = logging.getLogger(__name__)
2121

@@ -112,9 +112,7 @@ def post_build(self, recipe: Recipe, src_dir: str) -> None:
112112
"""
113113

114114
@util.hook
115-
def post_package(
116-
self, package: Package, src_dir: str, pkg_dir: str
117-
) -> None:
115+
def post_package(self, package: Package, src_dir: str, pkg_dir: str) -> None:
118116
"""
119117
Triggered after part of the artifacts from a build have been copied
120118
in place to the packaging directory.
@@ -195,9 +193,7 @@ def _make_arch(
195193
base_pkg_dir = os.path.join(build_dir, "pkg")
196194
os.makedirs(base_pkg_dir, exist_ok=True)
197195

198-
for package in (
199-
packages if packages is not None else recipe.packages.values()
200-
):
196+
for package in packages if packages is not None else recipe.packages.values():
201197
pkg_dir = os.path.join(base_pkg_dir, package.name)
202198
os.makedirs(pkg_dir, exist_ok=True)
203199

@@ -227,9 +223,7 @@ def _fetch_sources(
227223

228224
if self.URL_REGEX.match(source.url) is None:
229225
# Get source file from the recipe’s directory
230-
_ = shutil.copy2(
231-
os.path.join(recipe.path, source.url), local_path
232-
)
226+
_ = shutil.copy2(os.path.join(recipe.path, source.url), local_path)
233227
else:
234228
# Fetch source file from the network
235229
req = requests.get(source.url, timeout=(3.05, 300))
@@ -261,69 +255,28 @@ def _fetch_sources(
261255
local_path,
262256
)
263257

264-
def _prepare(self, recipe: Recipe, src_dir: str) -> None:
265-
"""Prepare source files before building."""
266-
if not recipe.prepare:
267-
logger.debug("Skipping prepare (nothing to do)")
268-
return
269-
270-
logger.info("Preparing source files")
271-
mount_src = "/src"
272-
uid = os.getuid()
273-
gid = os.getgid()
274-
logs = bash.run_script_in_container(
275-
self.docker,
276-
image=self.IMAGE_PREFIX + "toolchain:v4.0",
277-
mounts=[
278-
docker.types.Mount(
279-
type="bind",
280-
source=os.path.abspath(src_dir),
281-
target=mount_src,
282-
),
283-
],
284-
variables={
285-
"srcdir": mount_src,
286-
},
287-
script="\n".join(
288-
[
289-
f'cd "{mount_src}"',
290-
recipe.prepare,
291-
f"chown -R {uid}:{gid} {mount_src}",
292-
]
293-
),
294-
)
295-
bash.pipe_logs(logger, logs, "prepare()")
296-
297-
# pylint: disable=too-many-locals
298-
def _build(self, recipe: Recipe, src_dir: str) -> None:
299-
"""Build artifacts for a recipe."""
300-
if not recipe.build:
301-
logger.debug("Skipping build (nothing to do)")
302-
return
303-
304-
logger.info("Building artifacts")
305-
306-
# Set fixed atime and mtime for all the source files
307-
epoch = int(recipe.timestamp.timestamp())
308-
309-
for filename in util.list_tree(src_dir):
310-
os.utime(filename, (epoch, epoch))
311-
312-
mount_src = "/src"
313-
repo_src = "/repo"
314-
uid = os.getuid()
315-
gid = os.getgid()
258+
def _run_script( # pylint: disable=R0913, R0917, R0914
259+
self,
260+
script: list[str],
261+
arch: str = "rmall",
262+
image: str = "toolchain:v4.0",
263+
dependencies: set[Dependency] | None = None,
264+
mounts: list[docker.types.Mount] | None = None,
265+
variables: bash.Variables | None = None,
266+
) -> bash.LogGenerator:
267+
"""Run a recipe script in a container"""
316268
pre_script: list[str] = []
317269

318270
# Install required dependencies
319271
build_deps: list[str] = []
320272
host_deps: list[str] = []
321273

322-
for dep in recipe.makedepends:
323-
if dep.kind == DependencyKind.BUILD:
324-
build_deps.append(dep.package)
325-
elif dep.kind == DependencyKind.HOST:
326-
host_deps.append(dep.package)
274+
if dependencies is not None:
275+
for dep in dependencies:
276+
if dep.kind == DependencyKind.BUILD:
277+
build_deps.append(dep.package)
278+
elif dep.kind == DependencyKind.HOST:
279+
host_deps.append(dep.package)
327280

328281
if build_deps:
329282
pre_script.extend(
@@ -338,25 +291,16 @@ def _build(self, recipe: Recipe, src_dir: str) -> None:
338291
)
339292
)
340293

294+
is_aarch64 = arch.startswith("rmpp")
341295
if host_deps:
342296
opkg_conf_path = (
343297
"$SYSROOT_AARCH64/etc/opkg/opkg.conf"
344-
if recipe.arch.startswith("rmpp")
298+
if is_aarch64
345299
else "$SYSROOT/etc/opkg/opkg.conf"
346300
)
347-
opkg_exec = (
348-
"opkg-aarch64" if recipe.arch.startswith("rmpp") else "opkg"
349-
)
350-
opkg_arch = (
351-
"aarch64-3.10"
352-
if recipe.arch.startswith("rmpp")
353-
else "armv7-3.2"
354-
)
355-
opkg_src = (
356-
"aarch64-k3.10"
357-
if recipe.arch.startswith("rmpp")
358-
else "armv7sf-k3.2"
359-
)
301+
opkg_exec = "opkg-aarch64" if is_aarch64 else "opkg"
302+
opkg_arch = "aarch64-3.10" if is_aarch64 else "armv7-3.2"
303+
opkg_src = "aarch64-k3.10" if is_aarch64 else "armv7sf-k3.2"
360304

361305
pre_script.extend(
362306
(
@@ -370,11 +314,11 @@ def _build(self, recipe: Recipe, src_dir: str) -> None:
370314
)
371315
)
372316

373-
if recipe.arch != "rmall":
317+
if arch != "rmall":
374318
pre_script.extend(
375319
(
376-
f'echo -n "arch {recipe.arch} 250',
377-
f"src/gz toltec-{recipe.arch} file:///repo/{recipe.arch}",
320+
f'echo -n "arch {arch} 250',
321+
f"src/gz toltec-{arch} file:///repo/{arch}",
378322
f'" >> "{opkg_conf_path}"',
379323
)
380324
)
@@ -388,12 +332,88 @@ def _build(self, recipe: Recipe, src_dir: str) -> None:
388332
)
389333
)
390334

391-
if recipe.arch.startswith("rmpp"):
392-
pre_script.append(("source /opt/x-tools/switch-aarch64.sh"))
335+
if is_aarch64:
336+
pre_script.append(
337+
(
338+
"if [ -f /opt/x-tools/switch-aarch64.sh ]; then"
339+
+ "source /opt/x-tools/switch-aarch64.sh;"
340+
+ "fi"
341+
)
342+
)
393343

394-
logs = bash.run_script_in_container(
344+
return bash.run_script_in_container(
395345
self.docker,
396-
image=self.IMAGE_PREFIX + recipe.image,
346+
image=self.IMAGE_PREFIX + image,
347+
mounts=mounts or [],
348+
variables=variables or {},
349+
script="\n".join(
350+
[
351+
*pre_script,
352+
*script,
353+
]
354+
),
355+
)
356+
357+
def _prepare(self, recipe: Recipe, src_dir: str) -> None:
358+
"""Prepare source files before building."""
359+
if not recipe.prepare:
360+
logger.debug("Skipping prepare (nothing to do)")
361+
return
362+
363+
logger.info("Preparing source files")
364+
mount_src = "/src"
365+
uid = os.getuid()
366+
gid = os.getgid()
367+
logs = self._run_script(
368+
[
369+
f'cd "{mount_src}"',
370+
recipe.prepare,
371+
f"chown -R {uid}:{gid} {mount_src}",
372+
],
373+
image=recipe.image,
374+
arch=recipe.arch,
375+
dependencies=recipe.preparedepends,
376+
mounts=[
377+
docker.types.Mount(
378+
type="bind",
379+
source=os.path.abspath(src_dir),
380+
target=mount_src,
381+
),
382+
],
383+
variables={
384+
"srcdir": mount_src,
385+
},
386+
)
387+
bash.pipe_logs(logger, logs, "prepare()")
388+
389+
# pylint: disable=too-many-locals
390+
def _build(self, recipe: Recipe, src_dir: str) -> None:
391+
"""Build artifacts for a recipe."""
392+
if not recipe.build:
393+
logger.debug("Skipping build (nothing to do)")
394+
return
395+
396+
logger.info("Building artifacts")
397+
398+
# Set fixed atime and mtime for all the source files
399+
epoch = int(recipe.timestamp.timestamp())
400+
401+
for filename in util.list_tree(src_dir):
402+
os.utime(filename, (epoch, epoch))
403+
404+
mount_src = "/src"
405+
repo_src = "/repo"
406+
uid = os.getuid()
407+
gid = os.getgid()
408+
409+
logs = self._run_script(
410+
[
411+
f'cd "{mount_src}"',
412+
recipe.build,
413+
f"chown -R {uid}:{gid} {mount_src} {repo_src}",
414+
],
415+
arch=recipe.arch,
416+
dependencies=recipe.makedepends,
397417
mounts=[
398418
docker.types.Mount(
399419
type="bind",
@@ -409,14 +429,6 @@ def _build(self, recipe: Recipe, src_dir: str) -> None:
409429
variables={
410430
"srcdir": mount_src,
411431
},
412-
script="\n".join(
413-
(
414-
*pre_script,
415-
f'cd "{mount_src}"',
416-
recipe.build,
417-
f"chown -R {uid}:{gid} {mount_src} {repo_src}",
418-
)
419-
),
420432
)
421433
bash.pipe_logs(logger, logs, "build()")
422434

@@ -437,9 +449,7 @@ def _package(self, package: Package, src_dir: str, pkg_dir: str) -> None:
437449
for filename in util.list_tree(pkg_dir):
438450
logger.debug(
439451
" - %s",
440-
os.path.normpath(
441-
os.path.join("/", os.path.relpath(filename, pkg_dir))
442-
),
452+
os.path.normpath(os.path.join("/", os.path.relpath(filename, pkg_dir))),
443453
)
444454

445455
@staticmethod
@@ -484,9 +494,7 @@ def _archive(package: Package, pkg_dir: str, ar_path: str) -> None:
484494
)
485495

486496
for step in ("pre", "post"):
487-
if getattr(package, step + "upgrade") or getattr(
488-
package, step + "remove"
489-
):
497+
if getattr(package, step + "upgrade") or getattr(package, step + "remove"):
490498
script = script_header
491499

492500
for action in ("upgrade", "remove"):

toltec/recipe.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class Recipe: # pylint: disable=too-many-instance-attributes
6969
# Set of packages that are needed to build this recipe
7070
makedepends: set[Dependency]
7171

72+
# Set of packages that are needed to prepare this recipe
73+
preparedepends: set[Dependency]
74+
7275
# Full name and email address of this recipe’s maintainer
7376
maintainer: str
7477

0 commit comments

Comments
 (0)