|
2 | 2 | Brew Artifact Provider |
3 | 3 | """ |
4 | 4 |
|
| 5 | +from collections.abc import Sequence |
| 6 | +from functools import cached_property |
| 7 | +from typing import Any, ClassVar, Optional |
| 8 | +from urllib.parse import urljoin |
| 9 | + |
| 10 | +import tmt.log |
5 | 11 | from tmt.steps.prepare.artifact.providers import provides_artifact_provider |
6 | | -from tmt.steps.prepare.artifact.providers.koji import KojiArtifactProvider |
| 12 | +from tmt.steps.prepare.artifact.providers.koji import ( |
| 13 | + KojiArtifactProvider, |
| 14 | + KojiBuild, |
| 15 | + KojiNvr, |
| 16 | + KojiTask, |
| 17 | +) |
7 | 18 |
|
8 | 19 |
|
9 | 20 | # ignore[type-arg]: TypeVar in provider registry annotations is |
10 | 21 | # puzzling for type checkers. And not a good idea in general, probably. |
11 | 22 | @provides_artifact_provider('brew') # type: ignore[arg-type] |
12 | | -class BrewProvider(KojiArtifactProvider): |
| 23 | +class BrewArtifactProvider(KojiArtifactProvider): |
13 | 24 | """ |
| 25 | + Provider for downloading artifacts from Brew builds. |
| 26 | +
|
14 | 27 | Brew builds are just a special case of Koji builds |
| 28 | +
|
| 29 | + .. note:: |
| 30 | +
|
| 31 | + Only RPMs are supported currently. |
| 32 | +
|
| 33 | + .. code-block:: python |
| 34 | +
|
| 35 | + provider = BrewArtifactProvider("brew.build:123456", logger) |
| 36 | + artifacts = provider.fetch_contents(guest, Path("/tmp")) |
15 | 37 | """ |
| 38 | + |
| 39 | + SUPPORTED_PREFIXES: ClassVar[tuple[str, ...]] = () |
| 40 | + |
| 41 | + def __new__(cls, raw_provider_id: str, logger: tmt.log.Logger) -> Any: |
| 42 | + """ |
| 43 | + Create a specific Brew provider based on the ``raw_provider_id`` prefix. |
| 44 | +
|
| 45 | + The supported providers are: |
| 46 | + :py:class:`BrewBuild`, |
| 47 | + :py:class:`BrewTask`, |
| 48 | + :py:class:`BrewNvr`. |
| 49 | +
|
| 50 | + :raises ValueError: If the prefix is not supported |
| 51 | + """ |
| 52 | + return cls._dispatch_subclass(raw_provider_id, cls._REGISTRY) |
| 53 | + |
| 54 | + def __init__(self, raw_provider_id: str, logger: tmt.log.Logger): |
| 55 | + super().__init__(raw_provider_id, logger) |
| 56 | + self._session = self._initialize_session( |
| 57 | + api_url="https://brewhub.engineering.redhat.com/brewhub", |
| 58 | + top_url="https://download.eng.bos.redhat.com/brew", |
| 59 | + ) |
| 60 | + |
| 61 | + @cached_property |
| 62 | + def build_provider(self) -> Optional['BrewBuild']: |
| 63 | + return self._make_build_provider(BrewBuild, "brew.build") |
| 64 | + |
| 65 | + def _rpm_url(self, rpm_meta: dict[str, str]) -> str: |
| 66 | + """Construct Brew RPM URL.""" |
| 67 | + name = rpm_meta["name"] |
| 68 | + version = rpm_meta["version"] |
| 69 | + release = rpm_meta["release"] |
| 70 | + arch = rpm_meta["arch"] |
| 71 | + assert self.build_info is not None |
| 72 | + volume = self.build_info["volume_name"] |
| 73 | + draft_suffix = f",draft_{self.build_id}" if self.build_info["draft"] else "" |
| 74 | + |
| 75 | + path = ( |
| 76 | + f"vol/{volume}/packages/{name}/{version}/" |
| 77 | + f"{release}{draft_suffix}/{arch}/" |
| 78 | + f"{name}-{version}-{release}.{arch}.rpm" |
| 79 | + ) |
| 80 | + |
| 81 | + return urljoin(self._top_url, path) |
| 82 | + |
| 83 | + |
| 84 | +@provides_artifact_provider("brew.build") # type: ignore[arg-type] |
| 85 | +class BrewBuild(BrewArtifactProvider, KojiBuild): |
| 86 | + pass |
| 87 | + |
| 88 | + |
| 89 | +@provides_artifact_provider("brew.task") # type: ignore[arg-type] |
| 90 | +class BrewTask(BrewArtifactProvider, KojiTask): |
| 91 | + pass |
| 92 | + |
| 93 | + |
| 94 | +@provides_artifact_provider("brew.nvr") # type: ignore[arg-type] |
| 95 | +class BrewNvr(BrewArtifactProvider, KojiNvr): |
| 96 | + pass |
| 97 | + |
| 98 | + |
| 99 | +BrewArtifactProvider._REGISTRY = { |
| 100 | + "brew.build": BrewBuild, |
| 101 | + "brew.task": BrewTask, |
| 102 | + "brew.nvr": BrewNvr, |
| 103 | +} |
| 104 | +BrewArtifactProvider.SUPPORTED_PREFIXES = tuple(BrewArtifactProvider._REGISTRY.keys()) |
0 commit comments