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 <jan@janware.com>
This commit is contained in:
Jan Lindemann 2026-04-16 09:22:58 +02:00
commit d1df9f0ac7

View file

@ -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