Home: Floating version patterns like '1.*` are treated as ranges without a max, `1.*` is [1.*, )

Created on 20 Apr 2017  路  9Comments  路  Source: NuGet/Home

  1. Create a NETCore/NETStandard project (PackageReference).
  2. Have it depend on a package (say NuGetPlayLib) that has versions 1.1.0,1.2.0,1.3.0,2.0.0
  3. Now edit the csproj file to make the dependency on "1.*"
    <ItemGroup> <PackageReference Include="NuGetPlayLib" Version="1.*" /> </ItemGroup>
  4. Remove the versions 1.* from the feeds
  5. Restore package dependencies for the project

Expected: It should throw an error as it would have if the dependency was specified as:
<ItemGroup> <PackageReference Include="NuGetPlayLib" Version="[1.0.0, 2.0.0)" /> </ItemGroup>
Actual: It resolves to version 2.0.0

Restore Icebox ByDesign DCR

Most helpful comment

Wow... that's completely awkward. Docs say:

A floating or wildcard dependency version is specified with the * wildcard, as with 6.0.. This version specification says "use the latest 6.0.x version"; 4. means "use the latest 4.x version."

In reality, 4.* means [4.*, ). That's a bummer as if package sources don't have any versions with Major=4 at all - NuGet will happily resolve 5.0.0 or whatever is available there next.

But even [4.0.0, 4.1.0) (assuming it resolves to the highest applicable version) does not solve the issue: 4.1.0-prerelease.label matches that range as well. Therefore, taking the explanations in this thread into account, the correct range to specify what is expected from 4.* by most people would be [4.0.0, 4.1.0-0).

How many people would write it correctly from the first time? And what is the point in having 4.* implemented as it is now, namely [4.*, )? To be honest, I struggle to find a real case when I'd like version 5.0.0 to match reference 4.* silently.

All 9 comments

Users can specify [1.*, 2.0.0) to enforce an upper bound.

A floating range is treated as two ranges currently.

  1. The allowed bounds
  2. A preferred version within those bounds

In the case of 1.* the preferred range is 1.MAXINT, the nearest version to that will be used. Versions below the bounds of [1.0.0, ) will be considered errors.

I find this non-intuitive. The 1.* seems like it should match to just 1.MAXINT. Was there a requirement to match to the nearest version if the pattern match doesn't happen? I find the usecase a bit weird.

The wildcard is matched to what's highest the feed first, and then acts like a normal range afterwards. So if the feed has 1.1.0,1.2.0,1.3.0,2.0.0 and you look for 1.* Then it's effectively turned to 1.3 without a maximum.

Like @emgarten mentioned then - if you have [1.*, 2.0) then it's effectively turned to [1.3, 2.0) which gives you the clamped range you were looking for.

However there is a problem if a wildcard automatically adds a maximum.

Let's say you have project Q that uses library A and B, and A and B use package X. If A says X 1.4 is ideal, and B says X 2.2 is ideal, then Q gets X 2.2 which is the lowest matching package in the intersection of ranges.

But if a wildcard also implies a maximum and A says X 1.* is ideal, and B says X 2.* is ideal, then Q will get a restore error because the ranges [1.3, 2.0) and [2.0, 3.0) have no intersection.

The major version might not seem so bad, but you'd have the same problem with any non-identical wildcard... 1.5.* and 1.6.* will exclude each other, but 1.5.4 and 1.6.1 will happily select 1.6.1 for you.

That said - I do think this is a case where you should get the "under-versioning" warning. Just like if I say 1.3 is ideal and restore ends up handing me 2.0 I'll get a warning, if I say 1.* is ideal and restore ends up with 2.0 I should get that same warning.

@lodejard I see 2 issues with the current behavior using wild card:

  1. The semantic is non intuitive. The range using braces already works right now. So if somebody wants a particular behavior like no upper bound, then they can go with no upper bound. E.g [1.0.0,]
    What will 1.* regular expression mean? Can it ever mean 2.x?
    Also since [1.0.0, 2.0.0) will never match to 2.0.0 even if there are no packages with version 1.x.x, we should have similar behavior for the *
  1. If we limit 1.* to mean less than 2 equivalent to [1.0.0,2.0.0), then this also enables one to constrain the dependency range to the same major version.
    E.g
    1.* = [1.0.0,2)
    1.3.* = [1.3.0, 1.4.0)

Wow... that's completely awkward. Docs say:

A floating or wildcard dependency version is specified with the * wildcard, as with 6.0.. This version specification says "use the latest 6.0.x version"; 4. means "use the latest 4.x version."

In reality, 4.* means [4.*, ). That's a bummer as if package sources don't have any versions with Major=4 at all - NuGet will happily resolve 5.0.0 or whatever is available there next.

But even [4.0.0, 4.1.0) (assuming it resolves to the highest applicable version) does not solve the issue: 4.1.0-prerelease.label matches that range as well. Therefore, taking the explanations in this thread into account, the correct range to specify what is expected from 4.* by most people would be [4.0.0, 4.1.0-0).

How many people would write it correctly from the first time? And what is the point in having 4.* implemented as it is now, namely [4.*, )? To be honest, I struggle to find a real case when I'd like version 5.0.0 to match reference 4.* silently.

In fact, even the last one is not right because of #912 as it won't consider pre-release versions if there is at least one version without pre-release label (i.e. 4.0.1-rc won't be considered if there is 4.0.0 present in the feed). Complete bummer, seems not possible to do at all. [4.0.0-*, 4.1.0-0) does not work either.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

livarcocc picture livarcocc  路  3Comments

blackcity picture blackcity  路  3Comments

skofman1 picture skofman1  路  3Comments

dotMorten picture dotMorten  路  3Comments

jainaashish picture jainaashish  路  3Comments