Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should publishes with versions only differing in metadata be allowed? #1059

Open
sfackler opened this issue Sep 15, 2017 · 13 comments
Open

Should publishes with versions only differing in metadata be allowed? #1059

sfackler opened this issue Sep 15, 2017 · 13 comments
Labels
A-backend A-versions C-bug Category: unintended, undesired behavior

Comments

@sfackler
Copy link
Member

sfackler commented Sep 15, 2017

For example, https://crates.io/crates/openssl-src has 110.0.0 and 110.0.0+1.1.0f, which are semver-equivalent since build metadata doesn't affect the actual version. It seems like this probably shouldn't be allowed?

@mbrubeck
Copy link
Contributor

mbrubeck commented Sep 15, 2017

Some previous discussion in dtolnay/semver#107

@carols10cents
Copy link
Member

carols10cents commented Sep 20, 2017

Sure sounds like we should be disallowing versions like these that only differ in build metadata....

@carols10cents carols10cents added A-backend A-versions C-bug Category: unintended, undesired behavior labels Sep 20, 2017
@jeikabu
Copy link

jeikabu commented Dec 6, 2018

Looks like I fell victim to this.

I'd been using semver metadata only to discover it doesn't work as expected. Rather than getting rid of metadata support it would make sense to let them be semver equivalent. Whether some attempt is made to parse and make sense of the metadata is a convention that could be developed separately. Until then taking the most recent would be the "least surprising".

To me the primary use case is crates that have some external, non-crate dependency and you want to mirror it's semver version. "sys" crates fall in this category. I have a crate that corresponds to NNG 1.1.1. Being able to version my crate as 1.1.1 instead of some unrelated version scheme that requires mapping between the two is the simplest. If I need to alter crate contents in some way (e.g. packaging or documentation- some non-API-breaking change) 1.1.1+SOMETHING would make the most sense.

As it is, if you have a crate versioned 0.1.0+XYZ and you then publish/yank 0.1.0 the crate is "yanked" even when there's a semver-equivalent crate available, 0.1.0+3.

bors added a commit to rust-lang/cargo that referenced this issue Apr 1, 2019
Warn on version req with metadata.

Metadata in a version requirement (such as `1.0.0+1234`) is ignored. This adds a warning that it will be ignored.

On crates.io I found about 5 crates, plus a few dozen google-* crates (presumably all created by the same person) which have dependencies of this form.

See discussion at #6504 (comment). cc rust-lang/crates.io#1059 for ongoing discussion about what to do about publishing such versions.
@sgrif
Copy link
Contributor

sgrif commented Aug 15, 2019

I really do think this just boils down to a bug in semver. Build metadata is ignored for precedence, but that does not mean it's ignored for equality. To me this implies that if two versions differ only in metadata, we may select one at random to treat as the "latest version", but they are still different versions, and should be treated as such both by crates.io and Cargo. I laid out some further reasoning in dtolnay/semver#107 (comment)

@pietroalbini
Copy link
Member

pietroalbini commented Aug 15, 2019

The ordering being the same is not going to be changed as far as I can see, and that makes any possible use of releases with the same version but different metadata practically impossible.

If the contents of the two releases with different metadata are the same there is not really a point of having two releases, and if it's different users that don't check specifically for either version are going to get a random release, which is plain bad and unexpected for everyone.

Based on that I'd like to see publishing releases with the same version but different metadata blocked on new uploads, regardless of what Cargo does. Blocking metadata completly is not needed, as there are still valid uses for it (for example the google-* crates use metadata to let users know at a glance when the bindings were automatically generated).

Maybe we should look for active crates that are consistently using metadata today and ask them for feeback?

@jackgerrits
Copy link

jackgerrits commented Jan 30, 2020

I've just hit this, I have a sys crate and the version tracks the version of the bound library. I had to do a follow up release to fix an issue with the docs.rs build. I am not able to increment the version number as then the versions would be out of sync. I used the metadata to indicate it was an updated version. However, now I am not able to depend on the lib:

error: failed to verify the checksum of `vowpalwabbit-sys v8.8.0`

I tried yanking the original versions and only kept the latest post release but this did not seem to help.

https://crates.io/crates/vowpalwabbit-sys

@jtgeibel
Copy link
Member

jtgeibel commented Jan 30, 2020

@jackgerrits So I don't think this is a long-term solution, but I have an idea of something that may be interesting to test. Would you try pushing several versions of your crate to staging.crates.io in the opposite order?

It would be interesting to see what happens server and client side. In particular, I expect that cargo will pick the first matching row in the index, and that by publishing +post3 first cargo will always grab it. It's probably still not possible to access the other versions, but at least it would give us a way to modify the index without really removing any metadata tracked by the index.

So that's my short term idea. We could reorder the lines in the index, an act that in theory is a noop but in practice will hopefully fix things for your crate. A bit longer term, we could error or warn in cargo when using a +. But in your case, any such warning would be too late, as you had already published 8.8.0. Long term, I'm not really sure what the solution is. I haven't yet had a chance to re-read this thread and the linked semver thread.

@carols10cents
Copy link
Member

carols10cents commented Jan 31, 2020

I'm going to lay out my current thoughts of what the actual behavior of interacting with build metadata should be, ideally:

  1. Publishing of crate versions that differ only in build metadata should be allowed, to support the sys crate use case. That is, I should be able to publish a-sys v1.0.0-whatever and a-sys v1.0.0-somethingelse.

  2. When Cargo.lock contains a version with build metadata, it should always download the exact same version, including the same build metadata. That is, if I have a Cargo.lock that contains a-sys v1.0.0-whatever, I should always get a-sys v1.0.0-whatever even if a-sys v1.0.0-somethingelse also exists.

  3. When Cargo is resolving versions from Cargo.toml without a Cargo.lock or when doing a cargo update, if a version is specified with build metadata in Cargo.toml it should always get that exact version? That is, if I specify a-sys = { version = "1.0.0-whatever" }, I should always get exactly 1.0.0-whatever? (I'm not sure this is expected behavior or not, I could also see expecting the behavior in the next item)

  4. When Cargo is resolving versions from Cargo.toml without a Cargo.lock or when doing a cargo update, if a version is specified WITHOUT build metadata in Cargo.toml it should always get the semver compatible version published most recently. That is, if I specify a = { version = "1.0.0" } and a-sys v1.0.0-whatever was published and then a-sys v1.0.0-somethingelse was published, I should always get a-sys v1.0.0-somethingelse.

I think the biggest problem right now is that 2. is not happening, as detailed in rust-lang/cargo#7180. I don't think this is a problem in crates.io, it's only a problem in cargo.

So I think this issue can be closed because the answer to the title is "yes, publishes with versions only differing in metadata should be allowed".

Am I missing anything?

@carols10cents
Copy link
Member

carols10cents commented Jan 31, 2020

When we discussed this in the crates.io team meeting, we were wondering what other package managers do. I just tested npm, and it strips build metadata completely on publish.

Experiment 1:

  • Publish a package with version 1.0.0
  • Attempt to publish version 1.0.0+something
  • Publish is rejected because +something is removed and 1.0.0 already exists

Experiment 2:

  • Publish a package with version 1.0.1+something
  • Publish succeeds with version 1.0.1 because +something is removed

https://www.npmjs.com/package/@carols10cents/foo

@carols10cents
Copy link
Member

carols10cents commented Jan 31, 2020

Rubygems doesn't support specifying build metadata at all: rubygems/bundler#6972

@ehuss
Copy link
Contributor

ehuss commented Jan 31, 2020

Overall, I think my preference would be to have crates.io not allow multiple versions that differ only in metadata. Whether or not the metadata is displayed on crates.io is another question, though I don't know if it matters too much.


Some other behaviors:

NuGet seems to display, but otherwise ignore metadata (https://github.com/NuGet/Home/wiki/SemVer-2.0.0-support#package-identity).

Go modules seem to mostly ignore metadata? When I use a requirement with metadata, it just seems to get removed.

Julia's Pkg doesn't error, but it looks like it might randomly pick based on metadata (or the latest one?). Regardless, it does not appear to be working correctly.

Python doesn't follow semver, but has a similar concept (https://www.python.org/dev/peps/pep-0440/#local-version-identifiers). They are not intended for public repositories, and it looks like cannot be used in a "version specifier" (semver version requirement).

@sgrif
Copy link
Contributor

sgrif commented Jan 31, 2020

I can certainly see why so many other package managers would ignore or forbid metadata, since it could definitely cause problems based on the semver spec

Build metadata MUST be ignored when determining version precedence. Thus two versions that differ only in the build metadata, have the same precedence. Examples: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85.

This implies that if versions 1.0.0, 1.0.0+foo and 1.0.0+bar exist, the versionreq 1.0.0 can match any of them. The spec is unfortunately never mentions metadata WRT equality, but I would assume that defaults to two versions with differing metadata are not equal.

If we do decide to forbid publishing versions that differ only in metadata, we still have the issue of what should we do with those versions that exist today?

@dwijnand
Copy link
Member

dwijnand commented Jan 31, 2020

The spec is unfortunately never mentions metadata WRT equality, but I would assume that defaults to two versions with differing metadata are not equal.

We explored this in dtolnay/semver#108 (comment) 😄

I have a sys crate and the version tracks the version of the bound library. I had to do a follow up release to fix an issue with the docs.rs build. I am not able to increment the version number as then the versions would be out of sync. I used the metadata to indicate it was an updated version. However, now I am not able to depend on the lib

Btw, the closest thing to an "official" answer about this use case is:

how transitive dependencies are tracked is a matter for tooling, not semver. Semver provides a standard means for labeling nodes in a dependency graph, not how to mange the entire graph.

(semver/semver#169 (comment))

😕

bors added a commit to rust-lang/cargo that referenced this issue May 10, 2021
Bump index cache version to deal with semver metadata version mismatch.

#9467 has uncovered an issue with how versions are handled in the index cache.  When using a debug build of Cargo, it may panic due to the [cache contents changing](https://github.com/rust-lang/cargo/blob/5c455130b6001c7f54e872e161c27f6e996aff1f/src/cargo/sources/registry/index.rs#L606-L619).  The particular problem I am running into is that the index has an entry for `openssl-src 110.0.0` and `110.0.0+1.1.0f`. This is due to an issue with crates.io where it allows publishing multiple versions with the same metadata (rust-lang/crates.io#1059).  Cargos before #9467 would populate the index cache with two entries, both with version `110.0.0`.  Afterwards, there are two separate entries (`110.0.0` and `110.0.0+1.1.0f`).

The change here is to bump the index cache version so that new versions of cargo will clear the cache, and won't trigger the assertion.

This may be a bit of a heavy-handed solution, as I think this only affects debug builds of cargo.  However, I instantly started running into this problem, so I suspect it will be a real annoyance for anyone developing cargo. Happy to discuss other possible solutions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-backend A-versions C-bug Category: unintended, undesired behavior
Projects
None yet
Development

No branches or pull requests

10 participants