# rpmdistro-repoquery: a cross-distribution repoquery tool ## Introduction Whether you're a packager, system administrator, or a user of Fedora, CentOS Stream, or their derivatives (RHEL, AlmaLinux, Rocky Linux etc.), you might already be familiar with `dnf repoquery`. It allows querying the repositories configured on the system for information about packages available, whether or not they are currently installed on the local machine. This is great, within limits: for instance, on Fedora, you can query packages built for stable and branched Fedora releases, and, if you install `fedora-repos-rawhide`, packages in the development branch. Sufficient care must be used to make sure you don't, for instance, enable repos meant for different Fedora releases by default and thus accidentally upgrade the running system. Enter [`rpmdistro-repoquery`](https://pagure.io/rpmdistro-repoquery): it comes with a set of repos for different RPM-based distributions, but instead of putting them in `/etc/yum.repos.d` with the repositories meant for actual use, put them in `/usr/share/rpmdistro-repoquery` (or, if you so choose, you can clone the repository and use definitions that come in the checkout). DNF is then invoked with a custom configuration file and a custom cache location that points at one of the repos for one of the distributions rather than the default location. The various distributions supported come with the relevant repositories enabled by default; some have additional repositories that need to be enabled explicitly (e.g. source repos are off by default; CentOS Stream configurations come with additional repos for SIG packages that are off by default). This opens up a lot of use cases; I highlight some of them below. (The primary author of this tool, [Neal Gompa](https://fedoraproject.org/wiki/User:Ngompa), works on a lot of RPM-based Linux distributions; I got involved to use it in `ebranch`). ## Real-life use cases ### Quickly seeing if a CentOS Stream update has made it to the mirrors In Fedora, updates go through [Bodhi](https://bodhi.fedoraproject.org), and once they are marked `testing` or `stable` that means there is a compose containing those updates, and they tend to hit mirrors shortly after. In CentOS Stream, the situation is more complicated, as the QA process is not visible to the public. Take `clang` for example: given a [commit](https://gitlab.com/redhat/centos-stream/rpms/clang/-/commit/9bfb2774ee5b40164ef1f148e0b88385931f2a93), and a matching [Koji build](https://kojihub.stream.centos.org/koji/buildinfo?buildID=29815) on January 27th, can we be sure this is pushed out to the mirrors? It turns out, as of Feb 9, it's not in the mirrors yet: ``` ❯ rpmdistro-repoquery centos-stream 9 clang 2>/dev/null clang-0:14.0.0-1.el9.i686 clang-0:14.0.0-1.el9.x86_64 clang-0:14.0.5-1.el9.i686 clang-0:14.0.5-1.el9.x86_64 clang-0:14.0.6-1.el9.i686 clang-0:14.0.6-1.el9.x86_64 clang-0:15.0.1-2.el9.i686 clang-0:15.0.1-2.el9.x86_64 clang-0:15.0.7-2.el9.i686 clang-0:15.0.7-2.el9.x86_64 ``` ### Comparing what is packaged in different distributions Scenario: you use / manage a heterogeneous fleet of different distributions. You want to find out if all the packages you need are available (because you might need to package what's missing) Let's see if [myrepos](https://src.fedoraproject.org/rpms/myrepos) is available on openSUSE Tumbleweed (the rolling distribution): ``` [fedora-toolbox:37] $ rpm -q myrepos myrepos-1.20180726-14.fc37.noarch [fedora-toolbox:37] $ rpmdistro-repoquery opensuse-tumbleweed 0 myrepos opensuse-tumbleweed-oss 3.2 MB/s | 73 MB 00:22 Last metadata expiration check: 0:00:27 ago on Fri Feb 10 14:37:31 2023. [fedora-toolbox:37] $ rpmdistro-repoquery opensuse-tumbleweed 0 /usr/bin/mr Last metadata expiration check: 0:01:16 ago on Fri Feb 10 14:37:31 2023. mr-0:1.20180726-1.9.noarch ``` Searching by the Fedora package name yields nothing, but in this case searching by the binary (since those are in the RPM metadata) shows a match: `myrepos` is available, but you'll need a different package name in your configuration management. ### ebranch This is a special case of the former: [ebranch](https://pagure.io/epel/ebranch) is a tool for branching Fedora packages for EPEL. Given that CentOS Stream (and its downstreams, such as Red Hat Enterprise Linux, AlmaLinux and Rocky Linux) only carries the subset of Fedora packages that Red Hat is committed to supporting, EPEL provides a way for the community to maintain additional packages built against RHEL (or CentOS Stream). A major problem here is dealing with dependency hell: a missing package might have several missing dependencies, which in turn have more missing dependencies... Getting [retsnoop in EPEL 9](https://bodhi.fedoraproject.org/updates/FEDORA-EPEL-2022-103282f5c3) involves branching 189 packages in total! `ebranch` utilizes `rpmdistro-repoquery` to compare what is available in Rawhide (`rpmdistro-repoquery fedora rawhide`) with what is available in CentOS Stream + EPEL (`rpmdistro-repoquery centos-stream-legacy 8` and `rpmdistro-repoquery centos-stream 9`) to build up a transitive closure of missing dependencies and report on any dependency loops. `ebranch` also computes a chain build order for the missing dependencies, grouping packages that can be built in parallel. ### Checking the impact of a soname bump Fedora's [updates policy for stable releases](https://docs.fedoraproject.org/en-US/fesco/Updates_Policy/#stable-releases) and EPEL's [incompatible upgrades policy](https://docs.fedoraproject.org/en-US/epel/epel-policy-incompatible-upgrades/) both discourage ABI-breaking updates, but sometimes they are necessary, as in the case of [libkdumpfile](https://lists.fedoraproject.org/archives/list/epel-devel@lists.fedoraproject.org/thread/5DCGRHG5COBSCZXMECIFWEBDYAEMMRNZ/) in EPEL. With `rpmdistro-repoquery`, finding the delta between any two distribution releases that it supports is trivial: ``` [michel@f37-packaging ~]$ comm <(rpmdistro-repoquery fedora rawhide -- provides libkdumpfile 2>/dev/null) <(rpmdistro-repoquery centos-stream 9 --provides libkdumpfile 2>/dev/null) libaddrxlat.so.2()(64bit) libaddrxlat.so.2(LIBADDRXLAT_0)(64bit) libaddrxlat.so.3 libaddrxlat.so.3()(64bit) libaddrxlat.so.3(LIBADDRXLAT_0) libaddrxlat.so.3(LIBADDRXLAT_0)(64bit) libkdumpfile = 0.4.1-5.el9 libkdumpfile = 0.5.0-3.fc38 libkdumpfile(x86-32) = 0.5.0-3.fc38 libkdumpfile(x86-64) = 0.4.1-5.el9 libkdumpfile(x86-64) = 0.5.0-3.fc38 libkdumpfile.so.10 libkdumpfile.so.10()(64bit) libkdumpfile.so.10(LIBKDUMPFILE_0) libkdumpfile.so.10(LIBKDUMPFILE_0)(64bit) libkdumpfile.so.9()(64bit) libkdumpfile.so.9(LIBKDUMPFILE_0)(64bit) ``` And likewise, finding the blast radius of said update: ``` [michel@f37-packaging ~]$ rpmdistro-repoquery centos-stream 9 -- whatrequires "libaddrxlat.so.2()(64bit)" Last metadata expiration check: 0:12:30 ago on Wed Feb 8 11:02:35 2023. libkdumpfile-devel-0:0.4.1-5.el9.x86_64 libkdumpfile-util-0:0.4.1-5.el9.x86_64 python3-libkdumpfile-0:0.4.1-5.el9.x86_64 [michel@f37-packaging ~]$ rpmdistro-repoquery centos-stream 9 -- whatrequires "libkdumpfile.so.9()(64bit)" Last metadata expiration check: 0:12:40 ago on Wed Feb 8 11:02:35 2023. drgn-0:0.0.22-1.el9.x86_64 libkdumpfile-devel-0:0.4.1-5.el9.x86_64 libkdumpfile-util-0:0.4.1-5.el9.x86_64 python3-libkdumpfile-0:0.4.1-5.el9.x86_64 [michel@f37-packaging ~]$ rpmdistro-repoquery centos-stream-legacy 8 -- whatrequires "libaddrxlat.so.2()(64bit)" Last metadata expiration check: 0:00:08 ago on Wed Feb 8 11:15:35 2023. libkdumpfile-devel-0:0.4.1-5.el8.x86_64 libkdumpfile-util-0:0.4.1-5.el8.x86_64 python3-libkdumpfile-0:0.4.1-5.el8.x86_64 [michel@f37-packaging ~]$ rpmdistro-repoquery centos-stream-legacy 8 -- whatrequires "libkdumpfile.so.9()(64bit)" Last metadata expiration check: 0:00:16 ago on Wed Feb 8 11:15:35 2023. drgn-0:0.0.22-1.el8.x86_64 libkdumpfile-devel-0:0.4.1-5.el8.x86_64 libkdumpfile-util-0:0.4.1-5.el8.x86_64 python3-libkdumpfile-0:0.4.1-5.el8.x86_64 ``` ### Building OS images [mkosi](https://github.com/systemd/mkosi) is a tool for generating OS images; currently it contains the logic for different distributions (e.g. [Fedora](https://github.com/systemd/mkosi/blob/main/mkosi/distributions/fedora.py), [Centos](https://github.com/systemd/mkosi/blob/main/mkosi/distributions/centos.py)), but this makes it hard to e.g. build an image for CentOS SIGs such as [Hyperscale](https://sigs.centos.org/hyperscale/). With [Daan De Meyer's refactor](https://pagure.io/rpmdistro-repoquery/pull-request/9) `rpmdistro-repoquery`'s repo files can now be reused by `mkosi` so in the future, tailoring what repositories are used to build an OS image should be much easier. ## Conclusion The contributors for this tool have found it very useful in our Linux distribution work, and we hope this article can help introduce it to others who likewise find it useful. Please try it yourself - on Fedora, and on any CentOS Stream or derivatives with [EPEL](https://docs.fedoraproject.org/en-US/epel/#_quickstart) enabled, simply do: `sudo dnf install rpmdistro-repoquery` If the distro you want to work with is not supported, [pull requests](https://pagure.io/rpmdistro-repoquery/pull-requests) are welcome! Likewise with [suggestions or requests](https://pagure.io/rpmdistro-repoquery/issues). If you want to package rpmdistro-repoquery in a different distribution, feel free to use [the Fedora packaging](https://src.fedoraproject.org/rpms/rpmdistro-repoquery) as reference.