Skip to content

Commit 53d7e75

Browse files
committed
feat(py): add apt_base() factory for cross-toolchain apt sharing
1 parent 2674b23 commit 53d7e75

3 files changed

Lines changed: 69 additions & 0 deletions

File tree

dsls/harmont-py/harmont/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from ._envelope import dump_registry_json
3535
from ._step import Step, scratch, wait
3636
from ._target import clear_target_cache, target # noqa: F401 clear_target_cache used by tests
37+
from ._toolchain import apt_base
3738
from ._typing import BaseImage, Dep, Target
3839
from .cache import (
3940
CacheCompose,
@@ -140,6 +141,7 @@ def sh(
140141
"Pipeline",
141142
"Step",
142143
"Target",
144+
"apt_base",
143145
"cmake",
144146
"compose",
145147
"composer",

dsls/harmont-py/harmont/_toolchain.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,18 @@ def make_install_chain(
7777
label=f":{lang_tag}: {install_tag}",
7878
cache=install_cache,
7979
)
80+
81+
82+
def apt_base(
83+
*,
84+
packages: tuple[str, ...],
85+
image: str | None = None,
86+
label: str = ":apt: base",
87+
) -> Step:
88+
"""Create a standalone apt-base step sharable across toolchains via ``base=``."""
89+
return scratch().sh(
90+
apt_install_cmd(packages),
91+
label=label,
92+
image=image,
93+
cache=CacheTTL(duration=APT_TTL),
94+
)

dsls/harmont-py/tests/test_toolchain_compose.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,55 @@ def test_mixed_pipeline_compiles():
8282
)
8383
assert p["version"] == "0"
8484
assert len(p["graph"]["nodes"]) > 0
85+
86+
87+
def _step_by_substring(p: dict, needle: str) -> dict:
88+
for n in p["graph"]["nodes"]:
89+
if needle in (n["step"].get("cmd") or ""):
90+
return n["step"]
91+
msg = f"no command step containing {needle!r}"
92+
raise AssertionError(msg)
93+
94+
95+
def test_apt_base_shared_across_toolchains():
96+
"""Single apt-base feeds both rust and python toolchains."""
97+
base = hm.apt_base(
98+
packages=(
99+
"curl",
100+
"ca-certificates",
101+
"build-essential",
102+
"pkg-config",
103+
"libssl-dev",
104+
"python3",
105+
"python3-venv",
106+
),
107+
)
108+
rust = hm.rust(path=".", base=base)
109+
py = hm.py.uv(path="dsls/harmont-py", base=base)
110+
p = hm.pipeline(
111+
rust.build(),
112+
py.test(),
113+
default_image="ubuntu:24.04",
114+
)
115+
cmds = _cmds(p)
116+
assert len([c for c in cmds if "apt-get install" in c]) == 1
117+
assert any("sh.rustup.rs" in c for c in cmds)
118+
assert any("uv" in c for c in cmds)
119+
120+
121+
def test_apt_base_default_label():
122+
base = hm.apt_base(packages=("curl",))
123+
assert base.label == ":apt: base"
124+
125+
126+
def test_apt_base_custom_image():
127+
base = hm.apt_base(packages=("curl",), image="debian:bookworm")
128+
rust = hm.rust(path=".", base=base)
129+
p = hm.pipeline(rust.build(), default_image="ubuntu:24.04")
130+
apt_step = _step_by_substring(p, "apt-get install")
131+
assert apt_step.get("image") == "debian:bookworm"
132+
133+
134+
def test_apt_base_custom_label():
135+
base = hm.apt_base(packages=("curl",), label=":lock: deps")
136+
assert base.label == ":lock: deps"

0 commit comments

Comments
 (0)