cargo-outdated icon indicating copy to clipboard operation
cargo-outdated copied to clipboard

Cargo outdated doing invalid resolution of crates

Open twirrim opened this issue 1 year ago • 3 comments

If I get a chance later, I'll dig in to cargo outdated to see how it's doing the crate resolution logic, but it's doing something strange. Minimal repro case in a Cargo.toml:

[package]
name = "outfail"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
refinery = { version = "0.8", features = ["rusqlite"]}
rusqlite = { version = "0.29", features = ["bundled"] }

Note that we're pinning rusqlite to version 0.29. cargo build will compile quite happily.

Cargo outdated throws an error tying in to the libsqlite-sys crate:

error: failed to select a version for `libsqlite3-sys`.
    ... required by package `rusqlite v0.23.0`
    ... which satisfies dependency `rusqlite = ">=0.23, <=0.29"` of package `refinery-core v0.8.11`
    ... which satisfies dependency `refinery-core = "^0.8.11"` of package `refinery v0.8.11`
    ... which satisfies dependency `refinery = "^0.8.11"` of package `outfail v0.1.0 (/tmp/user/1000/cargo-outdatedYiSfTo)`
versions that meet the requirements `^0.18.0` are: 0.18.0

the package `libsqlite3-sys` links to the native library `sqlite3`, but it conflicts with a previous package which links to `sqlite3` as well:
package `libsqlite3-sys v0.27.0`
    ... which satisfies dependency `libsqlite3-sys = "^0.27.0"` of package `rusqlite v0.30.0`
    ... which satisfies dependency `rusqlite = "^0.30.0"` of package `outfail v0.1.0 (/tmp/user/1000/cargo-outdatedYiSfTo)`
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the links ='libsqlite3-sys' value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.

failed to select a version for `libsqlite3-sys` which could resolve this conflict

For reasons I'm not clear on, that second block is suggesting I have rusqlite pinned to version ^0.30.0, when you can see from the Cargo.toml it's set to 0.29. Looking at upstream refinery-core at the time of writing/release: https://github.com/rust-db/refinery/blob/0118f0101b0e171498f965bf26e20d9b2072c4ff/refinery_core/Cargo.toml#L33 that's showing what we see in the resolver output ">= 0.23, <= 0.29".

Switching Cargo.toml to use that version range for rusqlite still returns the same message, erroneously claiming pinned to ^0.30.0.

twirrim avatar Dec 11 '23 17:12 twirrim

FWIW we get the same error when running cargo outdated in PRQL:

https://github.com/PRQL/prql, latest commit is 67453ae1

max-sixty avatar Jul 25 '24 18:07 max-sixty

currently, this same error is reported even for cargo-outdated itself!

$ cargo run -- outdated
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.44s
     Running `target/debug/cargo-outdated outdated`
error: failed to select a version for `libgit2-sys`.
    ... required by package `git2 v0.20.0`
    ... which satisfies dependency `git2 = "^0.20"` of package `git2-curl v0.21.0`
    ... which satisfies dependency `git2-curl = "^0.21.0"` of package `cargo-outdated v0.16.0 (/tmp/cargo-outdated2cwvVt)`
versions that meet the requirements `^0.18.0` are: 0.18.0+1.9.0

the package `libgit2-sys` links to the native library `git2`, but it conflicts with a previous package which links to `git2` as well:
package `libgit2-sys v0.17.0+1.8.1`
    ... which satisfies dependency `libgit2-sys = "^0.17.0"` of package `cargo v0.85.0`
    ... which satisfies dependency `cargo = "^0.85.0"` of package `cargo-outdated v0.16.0 (/tmp/cargo-outdated2cwvVt)`
Only one package in the dependency graph may specify the same links value. This helps ensure that only one copy of a native library is linked in the final binary. Try to adjust your dependencies so that only one package uses the `links = "git2"` value. For more information, see https://doc.rust-lang.org/cargo/reference/resolver.html#links.

failed to select a version for `libgit2-sys` which could resolve this conflict

i belive this is because we create a new temporary manifest with the latest published version of each crate and then try cargo update on it. if you change the version of git2-curl to 0.21.0 in cargo-outdated/Cargo.toml you will get the same resolution error as above.

as a workaround, you can choose to exclude the problematic crates. again for cargo-outdated:

$ cargo run -- outdated --exclude git2-curl
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.52s
     Running `target/debug/cargo-outdated outdated --exclude git2-curl`
Name                                                 Project        Compat         Latest         Kind         Platform
----                                                 -------        ------         ------         ----         --------
annotate-snippets->unicode-width                     0.1.14         0.2.0          0.2.0          Normal       ---
anstream->anstyle-wincon                             3.0.6          3.0.7          3.0.7          Normal       cfg(windows)
...

could cargo-outdated catch this error in some way and re-run with the problematic crate automatically excluded?

sornas avatar Jan 23 '25 10:01 sornas

the error is returned by https://docs.rs/cargo/0.84.0/cargo/ops/fn.update_lockfile.html at https://github.com/kbknapp/cargo-outdated/blob/45db3a99f4d249e15f96ce8efb775ac2ecf6eefd/src/cargo_ops/temp_project.rs#L219-L225

unfortunately it is a string in a anyhow::Result, and i would say that parsing the error string is probably not a good idea. maybe we could make it more clear where the error is coming from and some alternatives for the user? the way it's presented makes it look like a bug in cargo-outdated which i wouldn't say it is.

sornas avatar Jan 23 '25 17:01 sornas