rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.28k stars 2.32k forks source link

cargo install: support installing dependencies #10156

Open dcsommer opened 2 years ago

dcsommer commented 2 years ago

Problem

Issue with cargo vendor + cargo install

(repo with repro steps here: https://github.com/dcsommer/cargo-vendor-install-issue)

I've found an issue with vendoring and installation of cargo subcommands related to semver compatibility checks. To recreate the issue:

  1. Vendor the dependencies using cargo vendor .cargo_vendor (this step is checked in for convenience, but feel free to delete the directory and recreate it)
  2. Attempt to install the subcommand (from repository root CWD): cargo install --locked --frozen --path .cargo_vendor/cargo-ndk/ --root bin

You get the following error message:

error: failed to select a version for the requirement `cargo_metadata = "^0.14.0"`
candidate versions found which didn't match: 0.14.1
location searched: directory source `/home/dcsommer/src/vendor-install-demo/.cargo_vendor` (which is replacing registry `crates-io`)
required by package `cargo-ndk v2.5.0 (/home/dcsommer/src/vendor-install-demo/.cargo_vendor/cargo-ndk)`
perhaps a crate was updated and forgotten to be re-vendored?

As 0.14.1 is compatible with the constraint ^0.14.0 per semver rules, this appears to be a bug with cargo install.

I've tested this with 1.57 and 1.53 and it repros on both, although the error message is one character different in 1.53 (it claims the requirement is cargo_metadata = "=0.14.0" rather than cargo_metadata = "^0.14.0").

Steps

  1. Set up a package with a dependency on a package you would like to cargo install. In the example repo, this dependency is cargo-ndk = 2.5
  2. Vendor dependencies using cargo vendor .cargo_vendor (this step is checked in for convenience, but feel free to delete the directory and recreate it)
  3. Attempt to install the subcommand (from repository root CWD): cargo install --locked --frozen --path .cargo_vendor/cargo-ndk/ --root bin

Possible Solution(s)

No response

Notes

Version

cargo 1.57.0 (b2e52d7ca 2021-10-21)
release: 1.57.0
commit-hash: b2e52d7cab0a286ee9fcc0c17510b1e72fcb53eb
commit-date: 2021-10-21
host: x86_64-unknown-linux-gnu
libgit2: 1.3.0 (sys:0.13.23 vendored)
libcurl: 7.79.1-DEV (sys:0.4.49+curl-7.79.1 vendored ssl:OpenSSL/1.1.1l)
os: Fedora 34 (ThirtyFour) [64-bit]
ehuss commented 2 years ago

Thanks for the report! I think there may be some confusion about how cargo install works (see #9289). When you pass the --path argument to .cargo_vendor/cargo-ndk/, it is looking for the lock file at .cargo_vendor/cargo-ndk/Cargo.lock. When it doesn't find one, it builds a new Cargo.lock just for that package.

However, due to the way cargo works, resolving Cargo.lock does not use source replacement (so it resolves using the latest versions from crates.io). That isn't really a supported use case, since there should always be a corresponding lock file when vendored.

cargo install isn't designed to install packages from dependencies, it is only designed to install standalone packages.

Also, thanks for creating the reproduction. However, it seems to be missing the Cargo.lock file, so I can't really test your specific example.

dcsommer commented 2 years ago

I've updated the repro repo to include the Cargo.lock file, so you should be able to reproduce now. It's interesting how omitting --frozen --locked allows the command to work (of course it defeats my intended goal to install from vendored dependencies).

KJTsanaktsidis commented 2 years ago

I'm getting the same confusing error (failed to select version for a requirement, with "candidate versions found which didn't match" suggesting a version which actually would match the requirement). My use case however is packaging up a Rust program into an RPM. The Fedora RPM infrastructure sets up a .cargo/config file which does the following to replace crates.io with a local directory:

[source.local-registry]
directory = "/usr/share/cargo/registry"

[source.crates-io]
registry = "https://crates.io"
replace-with = "local-registry"

However, when trying to run cargo build, I then get told the same thing:

error: failed to select a version for the requirement `serde = "^1.0"`
candidate versions found which didn't match: 1.0.134
location searched: directory source `/usr/share/cargo/registry` (which is replacing registry `crates-io`)
required by package `greetd_ipc v0.8.0 (/builddir/build/BUILD/greetd-0.8.0/greetd_ipc)`
perhaps a crate was updated and forgotten to be re-vendored?

and there really is a /usr/share/cargo/registry/serde-1.0.134 present.

KJTsanaktsidis commented 2 years ago

Never mind me, my issue was because there was a Cargo.lock file in a higher-level directory which locked a particular version of serde I didn't have in my local registry.