rust-lang / cargo

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

`cargo info` reads local crate instead of crates.io when running from the crate directory #14810

Open ia0 opened 6 days ago

ia0 commented 6 days ago

Problem

I naively expected that cargo info would always show information from crates.io (as its documentation suggests). However, it seems that cargo info foo-bar would not show information from crates.io if running from the directory of crate foo-bar itself. One has to explicitly pass --registry=crates-io to obtain information from crates.io.

Steps

  1. Go to some directory with a Cargo.toml file.
  2. Run cargo info foo-bar (where foo-bar is the package.name value in the Cargo.toml file).

Expected: It will contact crates.io and show information from there.

Actual: It reads and show information from the local crate.

Possible Solution(s)

Either update the documentation to mention that local crate is favored. Or always fetch from crates.io.

Notes

cargo help info shows:

NAME
       cargo-info — Display information about a package in the registry. Default registry is crates.io

DESCRIPTION
       This command displays information about a package in the registry. It fetches data from the package’s
       Cargo.toml file and presents it in a human-readable format.

It mentions things like package (something published on crates.io) and crates.io. It doesn't say that it will read the local file system.

Version

cargo 1.84.0-nightly (e75214ea4 2024-10-25)
release: 1.84.0-nightly
commit-hash: e75214ea4936d2f2c909a71a1237042cc0e14b07
commit-date: 2024-10-25
host: x86_64-unknown-linux-gnu
libgit2: 1.8.1 (sys:0.19.0 vendored)
libcurl: 8.9.0-DEV (sys:0.4.74+curl-8.9.0 vendored ssl:OpenSSL/1.1.1w)
ssl: OpenSSL 1.1.1w  11 Sep 2023
os: Debian n/a (rodete) [64-bit]
epage commented 6 days ago

@Rustin170506 unsure how to word the documentation besides just not saying where its coming from.

ia0 commented 6 days ago

Then I'm assuming the intent is to prefer the local crate if it exists. That's already good to know, because then I know I can always specify --registry=crates-io in shell functions that should work regardless of context (like in which directory it runs from), since the semantics of my shell function is to get the info from crates.io.

epage commented 6 days ago

Yes, it was intentional though I don't remember why we chose that behavior.

Another aspect dependent on your local project is what version is shown. It will prefer versions in your lockfile (and maybe also versions compatible with your MSRV?). This is purely meant to be a UX command and tries to give the information that can be assumed to be most helpful for the user.

I can always specify --registry=crates-io in shell functions that should work regardless of context (like in which directory it runs from), since the semantics of my shell function is to get the info from crates.io.

If you are parsing the output, understand that the output is not a stable format intended for programmatic use. We can change pretty much anything about it without it being a breaking change.

ia0 commented 6 days ago

Another aspect dependent on your local project is what version is shown. It will prefer versions in your lockfile (and maybe also versions compatible with your MSRV?). This is purely meant to be a UX command and tries to give the information that can be assumed to be most helpful for the user.

Ok, that would be an issue. However, with some quick testing, it seems that using --registry=crates-io will always get the latest (I guess non-prerelease) version from crates.io, which is the behavior I want.

If you are parsing the output, understand that the output is not a stable format intended for programmatic use. We can change pretty much anything about it without it being a breaking change.

Yes, this is fine by me. I checked for a --porcelain flag and didn't find one, so I assumed this can break in the future. My build is hermetic, so I just need to check for breakage when I update my toolchain. Also, I used to use cargo search before cargo info, so that's still an improvement:

-cargo search "$name" | sed -n '1s/^'"$name"' = "\([0-9.]*\)".*$/\1/p'
+cargo info --registry=crates-io -q "$name" | sed -n 's/^version: //p'
Rustin170506 commented 9 hours ago

Yes, it was intentional though I don't remember why we chose that behavior.

https://github.com/Rustin170506/cargo-information/issues/60

Rustin170506 commented 8 hours ago

@Rustin170506 unsure how to word the documentation besides just not saying where its coming from.

How about this?

NAME
       cargo-info — Display information about a package in the registry or a local crate. Default registry is crates.io

DESCRIPTION
       This command displays information about a package in the registry or a local crate. It fetches data from the package’s
       Cargo.toml file and presents it in a human-readable format.
ia0 commented 8 hours ago

Yes, it was intentional though I don't remember why we chose that behavior.

Rustin170506/cargo-information#60

Thanks for the link! But this doesn't really contain a rationale for the current behavior though. Even https://github.com/Rustin170506/cargo-information/pull/66 doesn't. It seems the history was (AFAICT):

The closest thing I found to a rationale is https://github.com/Rustin170506/cargo-information/pull/66#discussion_r1425395683 but I'm not sure I interpret it correctly (I'm interpreting it as "we don't want to contact crates.io with a crate name if it happens to not have been published yet").

Is it possible to point to the rationale (if my archeology skills are failing) or document it here (otherwise)?

epage commented 8 hours ago

@Rustin170506 unsure how to word the documentation besides just not saying where its coming from.

How about this?

NAME cargo-info — Display information about a package in the registry or a local crate. Default registry is crates.io

DESCRIPTION This command displays information about a package in the registry or a local crate. It fetches data from the package’s Cargo.toml file and presents it in a human-readable format.

I think we should probably be more brief in the NAME than that.

Also iirc, we support a PackageIdSpec, the only difference is what a bare <pkgname> does, so the command can show a dependency from anywhere. This is really a matter of defaults for the spec parameter.

ia0 commented 7 hours ago

Actually, the documentation of spec is correct, so what about simplifying the name and description by removing mentions of the registry?

NAME
       cargo-info — Display information about a package

DESCRIPTION
       This command displays information about a package. It fetches data from the package’s Cargo.toml file and
       presents it in a human-readable format.

The user would then have to read further the documentation of spec:

OPTIONS
   Info Options
       spec
           Fetch information about the specified package. The spec can be a package ID, see cargo-pkgid(1) for the SPEC format. If the specified package is part of the current workspace, information from the local Cargo.toml
           file will be displayed. If the Cargo.lock file does not exist, it will be created. If no version is specified, the appropriate version will be selected based on the Minimum Supported Rust Version (MSRV).

If we want, we can modify the description to say that what is meant by "the package" is contextual and depends on whether the package is part of the current workspace. But I don't think this is needed.

epage commented 7 hours ago

Seems fine with me