A proposal for "features/extras" packaging (Rust, Python, etc.) without subpackages

I just opened a GitHub Discussion over at the RPM project with the same title, but I wanted to cross-post it here for wider visibility. Any responses would probably be best left on GitHub, to keep things in one place.


This is me floating an idea I had for creating packages that have variable dependencies based on what features are requested, that doesn’t rely on creating a unique subpackage per feature definition. Any and all feedback, criticism, corrections, etc. welcome. Please poke as many holes in this as you can find. (Bonus points if you have an idea for how said hole can be plugged.)

The problem

IMHO the explosion of feature-subpackages creates distracting amounts of clutter in the package collection, as well as overly verbose package names (inserting the feature name into the package name for each feature provided), when all of those feature packages contain nothing other than unique Provides: and Requires: dependencies (no actual files), meaning there’d be no reason for the subpackages at all if the main package could express the necessary information.

An example

Take the rust-hyper package in Fedora 44. Like many Rust packages, it consists of a main package (rust-hyper-devel) that contains all of the files for the package, plus EIGHT subpackages for its various features.

The subpackages look like this:

$ for sub in default server http1 http2 client full capi tracing; \
  do name="rust-hyper+$sub-devel"; \
  echo "\n$name\n---------------"; \
  echo "===== Files"; rpm -ql $name; \
  echo "===== Provides"; rpm -q --provides $name; \
  echo "===== Requires"; (rpm -q --requires $name | grep -v rpmlib); \
  echo; done

rust-hyper+default-devel
---------------
===== Files
/usr/share/cargo/registry/hyper-1.11.0/Cargo.toml
===== Provides
crate(hyper/default) = 1.11.0
rust-hyper+default-devel = 1.11.0-1.fc44
===== Requires
cargo
crate(hyper) = 1.11.0

rust-hyper+server-devel
---------------
===== Files
/usr/share/cargo/registry/hyper-1.11.0/Cargo.toml
===== Provides
crate(hyper/server) = 1.11.0
rust-hyper+server-devel = 1.11.0-1.fc44
===== Requires
(crate(httpdate/default) >= 1.0.0 with crate(httpdate/default) < 2.0.0~)
(crate(pin-project-lite/default) >= 0.2.4 with crate(pin-project-lite/default) < 0.3.0~)
(crate(smallvec/const_generics) >= 1.12.0 with crate(smallvec/const_generics) < 2.0.0~)
(crate(smallvec/const_new) >= 1.12.0 with crate(smallvec/const_new) < 2.0.0~)
(crate(smallvec/default) >= 1.12.0 with crate(smallvec/default) < 2.0.0~)
cargo
crate(hyper) = 1.11.0

rust-hyper+http1-devel
---------------
===== Files
/usr/share/cargo/registry/hyper-1.11.0/Cargo.toml
===== Provides
crate(hyper/http1) = 1.11.0
rust-hyper+http1-devel = 1.11.0-1.fc44
===== Requires
(crate(atomic-waker/default) >= 1.1.2 with crate(atomic-waker/default) < 2.0.0~)
(crate(futures-channel/default) >= 0.3.0 with crate(futures-channel/default) < 0.4.0~)
(crate(futures-core/default) >= 0.3.31 with crate(futures-core/default) < 0.4.0~)
(crate(httparse/default) >= 1.9.0 with crate(httparse/default) < 2.0.0~)
(crate(itoa/default) >= 1.0.0 with crate(itoa/default) < 2.0.0~)
cargo
crate(hyper) = 1.11.0

rust-hyper+http2-devel
---------------
===== Files
/usr/share/cargo/registry/hyper-1.11.0/Cargo.toml
===== Provides
crate(hyper/http2) = 1.11.0
rust-hyper+http2-devel = 1.11.0-1.fc44
===== Requires
(crate(atomic-waker/default) >= 1.1.2 with crate(atomic-waker/default) < 2.0.0~)
(crate(futures-channel/default) >= 0.3.0 with crate(futures-channel/default) < 0.4.0~)
(crate(futures-core/default) >= 0.3.31 with crate(futures-core/default) < 0.4.0~)
(crate(h2/default) >= 0.4.14 with crate(h2/default) < 0.5.0~)
cargo
crate(hyper) = 1.11.0

rust-hyper+client-devel
---------------
===== Files
/usr/share/cargo/registry/hyper-1.11.0/Cargo.toml
===== Provides
crate(hyper/client) = 1.11.0
rust-hyper+client-devel = 1.11.0-1.fc44
===== Requires
(crate(pin-project-lite/default) >= 0.2.4 with crate(pin-project-lite/default) < 0.3.0~)
(crate(smallvec/const_generics) >= 1.12.0 with crate(smallvec/const_generics) < 2.0.0~)
(crate(smallvec/const_new) >= 1.12.0 with crate(smallvec/const_new) < 2.0.0~)
(crate(smallvec/default) >= 1.12.0 with crate(smallvec/default) < 2.0.0~)
(crate(want/default) >= 0.3.0 with crate(want/default) < 0.4.0~)
cargo
crate(hyper) = 1.11.0

rust-hyper+full-devel
---------------
===== Files
/usr/share/cargo/registry/hyper-1.11.0/Cargo.toml
===== Provides
crate(hyper/full) = 1.11.0
rust-hyper+full-devel = 1.11.0-1.fc44
===== Requires
cargo
crate(hyper) = 1.11.0
crate(hyper/client) = 1.11.0
crate(hyper/http1) = 1.11.0
crate(hyper/http2) = 1.11.0
crate(hyper/server) = 1.11.0

rust-hyper+capi-devel
---------------
===== Files
/usr/share/cargo/registry/hyper-1.11.0/Cargo.toml
===== Provides
crate(hyper/capi) = 1.11.0
rust-hyper+capi-devel = 1.11.0-1.fc44
===== Requires
cargo
crate(hyper) = 1.11.0

rust-hyper+tracing-devel
---------------
===== Files
/usr/share/cargo/registry/hyper-1.11.0/Cargo.toml
===== Provides
crate(hyper/tracing) = 1.11.0
rust-hyper+tracing-devel = 1.11.0-1.fc44
===== Requires
(crate(tracing) >= 0.1.0 with crate(tracing) < 0.2.0~)
(crate(tracing/std) >= 0.1.0 with crate(tracing/std) < 0.2.0~)
cargo
crate(hyper) = 1.11.0

The proposal

What I would propose, instead of the current glut of subpackages, is a way of defining dependencies “for” only specific Provides:. All of the various feature Provides: (crate(hyper/server), crate(hyper/default), etc.) would be defined on the main package, instead of in subpackages, and the dependencies for each Provides: would be set as Requires: conditional on a specific Provides:.

So, for example, the .spec syntax, wrapped for readability, might be (and this is of course subject to change, it’s just an example of one possible format — also, in reality these Requires: would be created by the Rust build tooling, only the Provides: for the feature crates would be defined in the .spec file, in place of the current subpackages):

Provides: crate(hyper/server) = 1.11.0
Requires: (crate(httpdate/default) >= 1.0.0
           with crate(httpdate/default) < 2.0.0~)
          for crate(hyper/server)
Requires: (crate(pin-project-lite/default) >= 0.2.4
           with crate(pin-project-lite/default) < 0.3.0~)
          for crate(hyper/server)
Requires: (crate(smallvec/const_generics) >= 1.12.0
           with crate(smallvec/const_generics) < 2.0.0~)
          for crate(hyper/server)
Requires: (crate(smallvec/const_new) >= 1.12.0
           with crate(smallvec/const_new) < 2.0.0~)
          for crate(hyper/server)
Requires: (crate(smallvec/default) >= 1.12.0
           with crate(smallvec/default) < 2.0.0~)
          for crate(hyper/server)

Provides: crate(hyper/client) = 1.11.0
Requires: (crate(pin-project-lite/default) >= 0.2.4
           with crate(pin-project-lite/default) < 0.3.0~)
          for crate(hyper/client)
Requires: (crate(smallvec/const_generics) >= 1.12.0
           with crate(smallvec/const_generics) < 2.0.0~)
          for crate(hyper/client)
Requires: (crate(smallvec/const_new) >= 1.12.0
           with crate(smallvec/const_new) < 2.0.0~)
          for crate(hyper/client)
Requires: (crate(smallvec/default) >= 1.12.0
           with crate(smallvec/default) < 2.0.0~)
          for crate(hyper/client)
Requires: (crate(want/default) >= 0.3.0
           with crate(want/default) < 0.4.0~)
          for crate(hyper/client)

Provides: crate(hyper/full) = 1.11.0
Requires: crate(hyper/client) = 1.11.0 for crate(hyper/full)
Requires: crate(hyper/http1) = 1.11.0 for crate(hyper/full)
Requires: crate(hyper/http2) = 1.11.0 for crate(hyper/full)
Requires: crate(hyper/server) = 1.11.0 for crate(hyper/full)

The idea is that, installing the package rust-hyper-devel-1.11.0-1.fc44.noarch either by package name or via its crate(hyper) Provides: would install the package files, and pull in the unconditional Requires: (the ones without for %{some_provide} conditions) as dependencies.

Installing, or using as a dependency, one of the crate(hyper/foo) provides, would also pull in any Requires: listed as for crate(hyper/foo).

Open questions

  1. Is this remotely workable, from an RPM package definition / database perspective? (Obviously it would require new features developed for both RPM and DNF5, but does it seem possible to write that code within the current codebase / APIs?)

  2. Is this remotely implementable, in the Rust or Python build tooling? (Since the Provides: for extras subpackages are autogenerated based on the packaging metadata, that tooling would need to be able to generate conditional Requires: ... for metadata instead.)

  3. Are there any feature/extra packages that contain files other than the %ghost copy of their package definition? For example, source files that are unique to the feature in question?

    If so, that would probably torpedo this, but I think the answer is “No”. Even if such files could theoretically exist (in terms of the native package definition), I don’t believe our current tooling has any means of expressing that kind of relationship. The complete set of source files is included in the main package. (I believe. PLEASE correct me if I’m wrong!)

  4. Would the conditional Requires: ... for dependency definitions be sufficient for this to work, or would the RPM definition of “installed” need to change to separately track individual Provides:?

    Currently if a package is installed, it’s assumed that all of its Provides: are available, and all of its Requires: are installed (or RPM flags the package as missing dependencies). But for these packages, having the physical package installed means that not all Provides: will necessarily be “active”, and so not all of their Requires: ... for dependencies will necessarily be installed. A conditional Requires: ... for %{some_provide} only needs to be installed if there’s some installed package that Requires: %{some_provide}.

    So, would it be sufficient to have the Requires: ... for dependencies only activate when the Provides: is activated as a dependency (or an explicit request, like sudo dnf install %{some_provide}), or would the RPM database need to track which Provides: of a given package have been installed, and which have not? (Or is there some other way of making this work?)

  5. Perhaps the most important question, as it makes the others moot if the answer is no: Would there be any interest in migrating some future Fedora / RHEL release’s Rust, Python, etc. packaging to use these features, instead of the current glut-o’-subpackages setup?

1 Like

Speaking for the Rust packaging tooling - we keep it backwards compatible with RHEL 9, so it would be a veeeeery long time until we could even look at implementing this.

That said, I’m not sure why you think the current setup is a problem per se? It’s not as if people run dnf repoquery and prepare for a thrilling read …

Primarily, because of this:

$ sudo dnf search hyper
Matched fields: name, summary
 erlang-hyper.x86_64	An implementation of the HyperLogLog algorithm in Erlang
 hyperestraier-devel.i686	Libraries and Header files for Hyper Estraier
 hyperestraier-devel.x86_64	Libraries and Header files for Hyper Estraier
 hyperestraier-java.x86_64	Hyper Estraier library for Java
 hyperestraier-perl.x86_64	Hyper Estraier library for Perl
 hyperhdr-common.x86_64	LUT files for hyperhdr
 hyperkitty-doc.noarch	Documentation for hyperkitty
 hyperrogue-data.noarch	Data for hyperrogue
 hyperv-daemons.x86_64	Hyper-V daemons suite
 hyperv-daemons-license.noarch	License of the Hyper-V daemons suite
 hyperv-tools.noarch	Tools for Hyper-V guests
 hypervfcopyd.x86_64	Hyper-V FCOPY daemon
 hypervkvpd.x86_64	Hyper-V key value pair (KVP) daemon
 hypervvssd.x86_64	Hyper-V VSS daemon
 imagefactory-plugins-HyperV.noarch	Cloud plugin for HyperV
 python-hyperframe-doc.noarch	Documentation for python-hyperframe
 python-hyperlink-doc.noarch	Documentation for python-hyperlink
 python3-hypercorn.noarch	ASGI Server based on Hyper libraries and inspired by Gunicorn
 python3-hypercorn+h3.noarch	Metapackage for python3-hypercorn: h3 extras
 python3-hypercorn+trio.noarch	Metapackage for python3-hypercorn: trio extras
 python3-mailman-hyperkitty.noarch	Mailman archiver plugin for HyperKitty
 ruby-hyperestraier.x86_64	Hyper Estraier Library for Ruby
 rust-hyper-rustls+default-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+http1-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+http2-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+log-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+logging-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+native-tokio-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+ring-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+rustls-native-certs-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+tls12-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+webpki-roots-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls+webpki-tokio-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+acceptor-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+default-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+http1-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+http2-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+log-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+logging-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+native-tokio-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+rustls-native-certs-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+tls12-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+tokio-runtime-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+webpki-roots-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24+webpki-tokio-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.24-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+acceptor-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+default-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+http1-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+http2-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+log-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+logging-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+native-tokio-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+ring-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+rustls-native-certs-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+tls12-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+tokio-runtime-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+webpki-roots-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25+webpki-tokio-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-rustls0.25-devel.noarch	Rustls+hyper integration for pure rust HTTPS
 rust-hyper-timeout+default-devel.noarch	Connect, read and write timeout aware connector to be used with hyper Client
 rust-hyper-timeout-devel.noarch	Connect, read and write timeout aware connector to be used with hyper Client
 rust-hyper-tls+alpn-devel.noarch	Default TLS implementation for use with hyper
 rust-hyper-tls+default-devel.noarch	Default TLS implementation for use with hyper
 rust-hyper-tls-devel.noarch	Default TLS implementation for use with hyper
 rust-hyper-tls0.5+default-devel.noarch	Default TLS implementation for use with hyper
 rust-hyper-tls0.5-devel.noarch	Default TLS implementation for use with hyper
 rust-hyper-util+client-devel.noarch	Hyper utilities
 rust-hyper-util+client-legacy-devel.noarch	Hyper utilities
 rust-hyper-util+client-pool-devel.noarch	Hyper utilities
 rust-hyper-util+client-proxy-devel.noarch	Hyper utilities
 rust-hyper-util+client-proxy-system-devel.noarch	Hyper utilities
 rust-hyper-util+default-devel.noarch	Hyper utilities
 rust-hyper-util+full-devel.noarch	Hyper utilities
 rust-hyper-util+http1-devel.noarch	Hyper utilities
 rust-hyper-util+http2-devel.noarch	Hyper utilities
 rust-hyper-util+server-auto-devel.noarch	Hyper utilities
 rust-hyper-util+server-devel.noarch	Hyper utilities
 rust-hyper-util+server-graceful-devel.noarch	Hyper utilities
 rust-hyper-util+service-devel.noarch	Hyper utilities
 rust-hyper-util+tokio-devel.noarch	Hyper utilities
 rust-hyper-util+tracing-devel.noarch	Hyper utilities
 rust-hyper-util-devel.noarch	Hyper utilities
 rust-hyperlocal+client-devel.noarch	Hyper bindings for Unix domain sockets
 rust-hyperlocal+default-devel.noarch	Hyper bindings for Unix domain sockets
 rust-hyperlocal+http-body-util-devel.noarch	Hyper bindings for Unix domain sockets
 rust-hyperlocal+hyper-util-devel.noarch	Hyper bindings for Unix domain sockets
 rust-hyperlocal+server-devel.noarch	Hyper bindings for Unix domain sockets
 rust-hyperlocal+tower-service-devel.noarch	Hyper bindings for Unix domain sockets
 rust-hyperlocal-devel.noarch	Hyper bindings for Unix domain sockets
 rust-supports-hyperlinks+default-devel.noarch	Detects whether a terminal supports rendering hyperlinks
 rust-supports-hyperlinks-devel.noarch	Detects whether a terminal supports rendering hyperlinks
 texlive-footnotehyper.noarch	A hyperref aware footnote environment
 texlive-hyper.noarch	Hypertext cross referencing
 texlive-hypernat.noarch	Allow hyperref and natbib to work together
 texlive-hyperref.noarch	Extensive support for hypertext in LaTeX
 texlive-luahyperbolic.noarch	Hyperbolic geometry in the Poincare disk model
 texlive-pxjahyper.noarch	Hyperref support for pLaTeX
Matched fields: name
 atkinson-hyperlegible-mono-fonts.noarch	Monospace typeface made for low-vision legibility
 atkinson-hyperlegible-next-fonts.noarch	Second-gen font family made for low-vision legibility
 hyperestraier.i686	A full-text search system
 hyperestraier.x86_64	A full-text search system
 hyperfine.x86_64	Command-line benchmarking tool
 hyperhdr.x86_64	Ambient lighting
 hyperkitty.noarch	A web interface to access GNU Mailman v3 archives
 hyperrogue.x86_64	An SDL roguelike in a non-euclidean world
 python3-hyperframe.noarch	HTTP/2 framing layer for Python
 python3-hyperlink.noarch	A featureful, immutable, and correct URL for Python
 rust-hyper+capi-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper+client-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper+default-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper+ffi-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper+full-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper+http1-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper+http2-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper+server-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper+tracing-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper-devel.noarch	Protective and efficient HTTP library for all
 rust-hyper0.14+backports-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+client-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+default-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+deprecated-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+ffi-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+full-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+h2-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+http1-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+http2-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+libc-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+runtime-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+server-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+socket2-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+stream-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14+tcp-devel.noarch	Fast and correct HTTP library
 rust-hyper0.14-devel.noarch	Fast and correct HTTP library
 rust-metrics-exporter-prometheus+_hyper-client-devel.noarch	Metrics-compatible exporter for sending metrics to Prometheus
 rust-metrics-exporter-prometheus+_hyper-server-devel.noarch	Metrics-compatible exporter for sending metrics to Prometheus
 rust-metrics-exporter-prometheus+hyper-devel.noarch	Metrics-compatible exporter for sending metrics to Prometheus
 rust-metrics-exporter-prometheus+hyper-rustls-devel.noarch	Metrics-compatible exporter for sending metrics to Prometheus
 rust-metrics-exporter-prometheus+hyper-util-devel.noarch	Metrics-compatible exporter for sending metrics to Prometheus
 rust-reqwest0.11+hyper-rustls-devel.noarch	Higher level HTTP client library
 rust-reqwest0.11+hyper-tls-devel.noarch	Higher level HTTP client library
 rust-yansi+hyperlink-devel.noarch	Dead simple ANSI terminal color painting library
 texlive-hyperbar.noarch	Add interactive Barcode fields to PDF forms
 texlive-hyperxmp.x86_64	Embed XMP metadata within a LaTeX document
 xen-hypervisor.x86_64	Libraries for Xen tools
Matched fields: summary
 cutecom.x86_64	A graphical serial terminal, like minicom or Hyperterminal on Windows
 incus-client.x86_64	Container hypervisor based on LXC - Client
 incus-selinux.noarch	Container hypervisor based on LXC - SELinux policy
 incus-tools.x86_64	Container hypervisor based on LXC - Extra Tools
 libvirt-daemon-driver-ch.x86_64	Cloud-Hypervisor driver plugin for libvirtd daemon
 perl-Sys-Virt.x86_64	Represent and manage a libvirt hypervisor connection
 python3-npyscreen.noarch	Writing user interfaces without all that ugly mucking about in hyperspace
 python3-optuna.noarch	A hyperparameter optimization framework
 scotch.i686	Graph, mesh and hypergraph partitioning library
 scotch.x86_64	Graph, mesh and hypergraph partitioning library
 texlive-arabi-add.noarch	Using hyperref and bookmark packages with arabic and farsi languages
 texlive-atkinson.noarch	Support for the Atkinson Hyperlegible family of fonts
 texlive-aurl.noarch	Extends the hyperref package with a mechanism for hyperlinked URLs abbreviated with prefixes
 texlive-bookmark.noarch	A new bookmark (outline) organization for hyperref
 texlive-breakurl.noarch	Line-breakable \url-like links in hyperref when compiling via dvips/ps2pdf
 texlive-convbkmk.noarch	Correct platex/uplatex bookmarks in PDF created with hyperref
 texlive-cooltooltips.noarch	Associate a pop-up window and tooltip with PDF hyperlinks
 texlive-doi.noarch	Create correct hyperlinks for DOI numbers
 texlive-endnotes-hy.noarch	Patches the endnotes package to create hypertext links to the correct anchors
 texlive-gmiflink.noarch	Simplify usage of \hypertarget and \hyperlink
 texlive-href-ul.noarch	Underscored LaTeX hyperlinks
 texlive-hrefhide.noarch	Suppress hyper links when printing
 texlive-hycolor.noarch	Implements colour for packages hyperref and bookmark
 texlive-hypdestopt.noarch	Hyperref destination optimizer
 texlive-hypdoc.noarch	Hyper extensions for doc.sty
 texlive-hypdvips.noarch	Hyperref extensions for use with dvips
 texlive-intopdf.noarch	Embed non-PDF files into PDF with hyperlink
 texlive-knowledge.noarch	Displaying, hyperlinking, and indexing notions in a document
 texlive-linkedthm.noarch	Hyperlinked theorem-proof environments for LaTeX
 texlive-morehype.noarch	Hypertext tools for use with LaTeX
 texlive-orcidlink.noarch	Insert hyperlinked ORCiD logo
 texlive-pdfpc-movie.noarch	Pdfpc viewer-compatible hyperlinks to movies
 texlive-spelatex.noarch	Create PDF documents with hyperlinks to audiofragments
 texlive-uri.noarch	Hyperlinks for a wide range of URIs
 vectorscan.x86_64	A portable fork of hyperscan, used as a high performance pcre replacement

Those results would be roughly at least 50% shorter if not for all the rust feature subpackages. And if you’re unlucky enough to do an even more generic search (like sudo dnf search default), you’re in for a world of hurt.

Not to mention, the DNF5 devs keep wanting to make the search output use the smartcols library, like many of the other commands’ output, and that would mean that every package name would take up the width of the longest package name. (I think that’s a terrible idea regardless, but given that they want to do it subpackage names like rust-tikv-jemallocator+unprefixed_malloc_on_supported_platforms-devel.noarch — yes, that is real — are a major formatting headache.)

I think it would be easier to improve “dnf search” output (maybe deduplicate / tree-structure by source package name?) - and you could implement it a decade earlier. :slight_smile:

I mean, dnf search is only one example. There’s also the installed package count on systems that pull in rust sources. For example, on my main workstation:

# I still have an /etc/cron.daily/ job to dump a list of
# installed packages into /var/log/rpmpkgs
$ wc -l /var/log/rpmpkgs
11155 /var/log/rpmpkgs

$ grep -v '^rust.*\+.*-devel' /var/log/rpmpkgs |wc -l
9886

$ echo $(( 11155 - 9886 ))
1269

More than 10% of my installed packages exist solely to define dependencies.

but … ~why~ would you do this? :grimacing:

And about once every month or two, I have to manually uninstall all of the feature subpackages for some rust package, because the package updated in a way that removed a feature, so sudo dnf upgrade breaks.

Why would I install Rust feature subpackages? As builddeps, to make some fedpkg local build work on my machine.

To be honest, fedpkg local is just setting yourself up for a world of pain, and I would strongly recommend against using it (in general, not just for Rust packages) …

Hey, if Rust packages are only meant to be installed on build systems, then moving them all out of the main package collection and into a separate repo would work for me! But I expect that idea will get even less traction than my proposal above.

To borrow the RHEL term for this - if we can make "rust-*-devel" packages “buildroot only”, that would be one way to “solve” this, yes …