From 282ce453879b0e7cee126cd2d723ce29b212e1ae Mon Sep 17 00:00:00 2001 From: Goutham Annem Date: Wed, 22 Jul 2026 22:34:20 -0700 Subject: [PATCH] feat(images): add apt_sources_mirror() chainable method for Debian builds Add a new chainable method `apt_sources_mirror(url)` to the `Image` class that inserts a `sed` command before `apt-get update` to swap the default Debian mirror URL (http://deb.debian.org/debian) with a user-supplied URL. The command handles both Debian 12+ (debian.sources format) and older Debian releases (sources.list format) via a fallback OR expression. Closes #5374 --- src/_bentoml_sdk/images.py | 30 ++++++++++++++++++++++++++ tests/unit/_bentoml_sdk/test_images.py | 20 +++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/_bentoml_sdk/images.py b/src/_bentoml_sdk/images.py index b2ede77d76f..50ea524daab 100644 --- a/src/_bentoml_sdk/images.py +++ b/src/_bentoml_sdk/images.py @@ -147,6 +147,36 @@ def python_packages(self, *packages: str) -> t.Self: self._after_pip_install = True return self + def apt_sources_mirror(self, url: str) -> t.Self: + """Swap the Debian apt mirror URL before running apt-get. Supports chaining call. + + This is useful for users in regions where the default Debian mirrors are slow. + The command tries both the Debian 12+ format (``debian.sources``) and the + legacy ``sources.list`` format so it works across Debian releases. + + Example: + + .. code-block:: python + + image = ( + Image("debian:latest") + .apt_sources_mirror("https://mirrors.tuna.tsinghua.edu.cn/debian") + .system_packages("curl") + ) + + Args: + url: The mirror URL to use, e.g. ``https://mirrors.tuna.tsinghua.edu.cn/debian``. + + Returns: + The current :class:`Image` instance (chainable). + """ + sed_cmd = ( + f"sed -i 's|http://deb.debian.org/debian|{url}|g'" + " /etc/apt/sources.list.d/debian.sources 2>/dev/null ||" + f" sed -i 's|http://deb.debian.org/debian|{url}|g' /etc/apt/sources.list" + ) + return self.run(sed_cmd) + def run(self, command: str) -> t.Self: """Add a command to the image. Supports chaining call. diff --git a/tests/unit/_bentoml_sdk/test_images.py b/tests/unit/_bentoml_sdk/test_images.py index f73ec0d418a..b5ddd1a0c53 100644 --- a/tests/unit/_bentoml_sdk/test_images.py +++ b/tests/unit/_bentoml_sdk/test_images.py @@ -3,6 +3,26 @@ from _bentoml_sdk.images import Image +def test_apt_sources_mirror_inserts_sed_command() -> None: + mirror = "https://mirrors.tuna.tsinghua.edu.cn/debian" + image = Image(distro="debian") + image.apt_sources_mirror(mirror) + + # The sed command should be the last entry added to pre-pip commands + assert image.commands[-1] == ( + f"sed -i 's|http://deb.debian.org/debian|{mirror}|g'" + " /etc/apt/sources.list.d/debian.sources 2>/dev/null ||" + f" sed -i 's|http://deb.debian.org/debian|{mirror}|g' /etc/apt/sources.list" + ) + + +def test_apt_sources_mirror_is_chainable() -> None: + mirror = "https://mirrors.tuna.tsinghua.edu.cn/debian" + image = Image(distro="debian") + result = image.apt_sources_mirror(mirror) + assert result is image + + def test_image_system_packages_are_shell_quoted() -> None: image = Image(distro="debian")