[Pkg-rust-maintainers] Bug#1034939: Bug#1034939: librust-<crate>-<semver>-dev: missing Breaks+Replaces for librust-mio-dev when upgrading from bullseye

Fabian Grünbichler fabian at gruenbichler.email
Sat Apr 29 15:54:18 BST 2023


On Fri, Apr 28, 2023 at 08:42:07PM +0100, Peter Green wrote:
> On 28/04/2023 18:58, Fabian Grünbichler wrote:
> > I see no practical issue with 2 meaning we can't have multiple semver
> > suffix packages variants of a single crate installed - having the
> > unversioned and one semver suffix package in one suite at any given time
> > should already be the exception, having more than that should be even
> > more rare,
> 
> In an ideal world I would agree, the transition from semver
> "n" to semver "n+1" would be complete before the transition
> from semver "n+1" to semver "n+2" starts.
> 
> I've certainly seen cases where that didn't happen though.
> clap springs to mind as a currently ongoing one where we
> have versions 2, 3 and 4 of clap in bookworm and clap 2
> still has more users than clap 3 and 4 combined.

in the archive, yes. in one transitive build dep tree that requires them
to be co-installed?

there are only a few crates that come my mind that bump that often and
are that widely used that we might run into it. clap ticks the first
box, but since it's mainly used by binaries directly (it's for argument
parsing after all ;)). nom would be a realistic use case where a big
project might transitively pull in 3 versions at some point (we
currently have 3.x, 4.x and 7.x (unversioned) in the archive, but 3.x
and 4.x seem to be cruft and removable.

I did a quick check (obviously, this is only a point-in-time snapshot!),
right now we have rust binaries with the following 18 semver suffix
dependencies in their transitive build dep tree in unstable (according
to X-Cargo-Built-Using):

rust-ahash-0.7 (= 0.7.6-11)
rust-arrayvec-0.5 (= 0.5.2-2)
rust-blake2b-simd-0.5 (= 0.5.11-1)
rust-block-buffer-0.9 (= 0.9.0-1)
rust-cfg-if-0.1 (= 0.1.10-2)
rust-clap-2 (= 2.34.0-3)
rust-clap-3 (= 3.2.23-4)
rust-digest-0.9 (= 0.9.0-2)
rust-env-logger-0.7 (= 0.7.1-3)
rust-foreign-types-0.3 (= 0.3.2-1)
rust-foreign-types-shared-0.1 (= 0.1.1-1)
rust-md-5 (= 0.10.1-1)
rust-mio-0.6 (= 0.6.23-2)
rust-semver-0.9 (= 0.9.0-3)
rust-semver-parser-0.7 (= 0.7.0-1)
rust-sha-1-0.9 (= 0.9.8-1)
rust-sha2-0.9 (= 0.9.9-2)
rust-sha3-0.9 (= 0.9.1-1)

of these, only three are (transitively) depended on in both semver
suffix and unversioned variants by any one package according to
X-Cargo-Built-Using:

rust-cfg-if is used in two versions by:
 qwertone
 alacritty
 bat
 fd-find
 libslirp-helper
 rust-code-analysis-cli
 sniffglue

rust-mio by:
 alacritty
 libslirp-helper

rust-semver by:
 grcov
 rusty-tags

keep in mind that this possible misses some additional dependency trees
that are not resulting in any binary crate binary packages (e.g.,
packaging efforts that are not yet finished).

> >and there should be no need to have them *installed* at the
> >same time since these packages are only used as build deps.
> 
> More than one semver of the same crate can be used in the same
> build process. Also collapse_features means that crates often end
> up in the transitive build-dependency graph of a package even
> though they are not actually used in the build.
> 
> I feel this is the kind of thing that would rarely cause problems,
> but when it does cause problems they would be of the
> "painted into a corner" type that are very difficult to deal with.

well, dealing with boils down to either:
- delay the crate update until more users of the outdated version have
  upgraded upstream and we can drop an old version
- write the patches for doing that upgrade and submit them upstream
- fork the oldest version in Debian to give a new name and patch its
  users (meh)
- manually dropping the Breaks+Replaces after ensuring that the
  offending combination of versions doesn't exist in the archive anymore

the first two are valid options IMHO, and decrufting an old version
before introducing a second old version into the archive seems desirable
in almost all cases that I can think of, regardless of whether it is
*needed* or not.

that being said - I now did some practical tests:
- install librust-mio-dev from bullseye
- install librust-mio-extras-dev from bookworm (which depends on
  mio 0.6)

now do a regular dist-upgrade, no problem, since librust-mio-dev gets
unpacked first (old files for 0.6.23 gone) and only then
librust-mio-0.6-dev gets unpacked (new files for 0.6.23 are not
conflicting) - that might just be luck though? or the Breaks guiding
the ordering, even though technically it only ensures that the broken
package is deconfigured, not that it is upgraded?

I see no practical difference when repeating the experiment with
librust-mio-0.6-dev patched + bumped to switch the B+R to
librust-mio-dev (<< 0.6.24~), the upgrade works just as fine.

with Replaces + Conflicts on librust-mio-0.6.23-dev, the upgrade works
as well. attempting to install the librust-mio-dev package from bullseye
then removes the librust-mio-0.6-dev package cause of the conflicts, as
desired and expected. the same is true with the current package from
bookworm as well as with the Breaks+Replaces patched variant, cause of
the Breaks.

unless there is a reason to avoid the Conflicts - like some corner case
where Conflicts might trigger APT to do the wrong thing? - I'd be
inclined to switch debcargo (and all the "broken" semver suffix packages
that might trigger the issue when upgrading from bullseye to bookworm)
to change the Breaks to a Conflicts -> the same set of packages should
be "not coinstallable" as a result AFAICT but the Replaces should then
actually count and make dpkg less unhappy as a result.

policy also says the following about "Conflicts":

"in conjunction with Provides when only one package providing a given
virtual facility can be unpacked at a time (see Virtual packages -
Provides),"

if we see "provide source of crate in version X" as the provided virtual
facility, then this kinda matches ;) there can only be one package
providing librust-foobar-X-Y-Z-dev *installed* at any given time.

using plain `dpkg -i` instead of `apt dist-upgrade --with-sources ..`
does cause the following issue when attempting to install bookworm
librust-mio-dev and conflict-variant of librust-mio-0.6-dev while having
librust-mio-dev from bullseye installed:

Selecting previously unselected package librust-mio-0.6-dev:amd64.
dpkg: regarding .../librust-mio-0.6-dev_0.6.23-3_amd64.deb containing librust-mio-0.6-dev:amd64:
 librust-mio-0.6-dev conflicts with librust-mio-0.6.23-dev
  librust-mio-dev:amd64 provides librust-mio-0.6.23-dev and is present and installed.

dpkg: error processing archive ./librust-mio-0.6-dev_0.6.23-3_amd64.deb (--install):
 conflicting packages - not installing librust-mio-0.6-dev:amd64

but the higher level packaging tools calling dpkg should never trigger
this combination, so that seems fine to me. similarly, dpkg --install or
--unpack without --auto-deconfigure errors out cause of the Breaks.

I do wonder if the whole issue can even occur in practice with APT (or
aptitude), or if it's just the "technically wrong" kind of bug, and only
triggers when calling dpkg manually with `--auto-deconfigure`?



More information about the Pkg-rust-maintainers mailing list