From d1df9f0ac70395cb7b9d1bde716b06b8499e3bf4 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Thu, 16 Apr 2026 09:22:58 +0200 Subject: [PATCH] lib.Distro.install(): Treat URL arguments specially As of now, install() passes the "names" parameter on to _install(), which is expected to pass the list of package names on to the package manager for having it handle package download and installation. This commit makes it easier for Distro instances to support directly installing packages via an URL instead by providing a few callback methods to be overridden, in case the package manager doesn't handle package URLs the same way as package names. Signed-off-by: Jan Lindemann --- src/python/jw/pkg/lib/Distro.py | 38 ++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/python/jw/pkg/lib/Distro.py b/src/python/jw/pkg/lib/Distro.py index 05ca946f..c0f331b9 100644 --- a/src/python/jw/pkg/lib/Distro.py +++ b/src/python/jw/pkg/lib/Distro.py @@ -109,15 +109,51 @@ class Distro(abc.ABC): # -- install + # Pass names to the package manager @abc.abstractmethod async def _install(self, names: Iterable[str], only_update: bool) -> None: pass + # Default implementation assumes package manager can handle local files. + # Not true for all distros. Override if Distro knows better. + async def _install_local_files(self, paths: Iterable[str], only_update: bool) -> None: + await self._install(paths, only_update=only_update) + + # Download first and then install. Override if Distro knows better. + async def _install_urls(self, urls: Iterable[str], only_update: bool) -> None: + import tempfile + from .util import copy + with tempfile.TemporaryDirectory(prefix='jw-pkg-') as tmp: + paths: list[str] = [] + for url in urls: + paths.append(await copy(url, tmp)) + await self._install_local_files(paths, only_update=only_update) + + # Default implementation installs in two steps: + # - Download URLs into local directories and install + # - Pass names to package manager + # Override if Distro knows better. + async def _install_urls_and_names(self, packages: Iterable[str], only_update: bool) -> None: + urls: list[str] = [] + names: list[str] = [] + for package in packages: + if package[0] == '/': + urls.append('file://' + package) + continue + if package.find('://') != -1: + urls.append(package) + continue + names.append(package) + if urls: + await self._install_urls(urls, only_update=only_update) + if names: + await self._install(names, only_update=only_update) + async def install(self, names: Iterable[str], only_update: bool=False) -> None: if not names: log(WARNING, f'No packages specified for installation') return - return await self._install(names, only_update=only_update) + await self._install_urls_and_names(names, only_update=only_update) # -- delete