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 runtime. packages be listed in NuGet.org? #7568

Open
richlander opened this issue Jun 27, 2022 · 9 comments
Open

Should runtime. packages be listed in NuGet.org? #7568

richlander opened this issue Jun 27, 2022 · 9 comments

Comments

@richlander
Copy link
Member

They are very noisy and not particularly useful.

https://www.nuget.org/packages?q=runtime.

At the same time, we want to ensure that we have good transparency for users.

What to do? Should we unlist these packages or keep them as-is?

I'll give you some context. The following is from a mail I sent today (to another party) on the same topic, which led to this question.

We started shipping .NET Core in 2016. You can think of the source code (at least structurally) as having remained constant since then but that we've tried a variety of approaches to building and publishing that source as binaries. All of those approaches are on display in NuGet.org. Package managers save everything to ensure continuity for consumers. That's a good thing, but it also can create a bit of a mess if there are multiple generations of technical schemes at play.

We ship the following distributions of of the .NET platform (and related packages):

  • Primary binary distribution of the .NET Runtime(s) and SDK
  • Regular packages
  • Special runtime packages (aka "runtime packs")

I'll briefly describe these. The primary binary distribution of the runtime and sdk is available at https://dotnet.microsoft.com/download/dotnet. This is similar to downloading node.js or OpenJDK. The only key difference is that .NET SDK includes much more in the box than the other two examples. That's not a flex, but just being objective. In fact, everything for JavaScript devs is in npm except the npm tool and node.js runtime/environment. All good.

We have regular packages. These are just like NPM or Maven packages. EntityFrameworkCore is a perfect example: https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.

You can even track that package back to source control. Check it out: https://nuget.info/packages/Microsoft.EntityFrameworkCore/7.0.0-preview.5.22302.2

image

That's this link: dotnet/efcore@01603c6

That means that the package was built from exactly that commit. There are ways to fake that out, but we don't do that. We ship that commit.

Note: I wish the commit in NPE was a link!

Let's get to runtime packs. This is where things get more interesting.

We had a LOT of runtime packages back when we first started. You can see a bunch of them at https://www.nuget.org/packages?q=runtime.. Most of those are abandoned now. You can see that in two ways: the last push was ages ago, and they have wonky version numbers (a lot are 4.x and we never shipped a .NET Core 4.x).

We should probably deprecate and/or unlist those packages. They are pure noise.

We do have relevant current patterns for these runtime packs. They provide the .NET implementation (in broad brushstrokes) for a given environment (like Linux x64).

https://www.nuget.org/packages?q=Microsoft.NETCoreApp.Runtime
https://www.nuget.org/packages?q=Microsoft.AspNetCore.App.Runtime

Those are the same except one is for the base runtime and the other is the web server, one layer up.

They are the same build of the product as is it at our download page, shared earlier.

The first is from: https://github.com/dotnet/runtime
The second is from: https://github.com/dotnet/aspnetcore

To make it more confusing, each of those repos builds their primary runtime deliverable, plus a bunch of associated packages.

In terms of scenarios, you download and install the product from the Microsoft download page when you want to have a globally installed product and develop or install multiple apps. We call this scenario "framework-dependent" since your app is dependent on a globally installed runtime/framework.

Some developers want to deploy the runtime with their app. We call that scenario self-contained. This is the scenario where those two categories of runtime packs are used. When you build your app, one or more of those runtime packages are downloaded and copied into your app. The local runtime on your machine is not used for that purpose (to copy into your app bin folder to make it self-contained). It's most obvious when you are on Windows x64 and wanting to build a self-contained app that will run on macOS Arm64, for example. You won't have that runtime on your machine, so it needs to be downloaded.

We also have a smaller set of runtime packs that are dependency of "regular packages".

For example, System.IO.Ports has a direct dependency on runtime.native.System.IO.Ports.

You can see this on the dependencies tab at https://www.nuget.org/packages/System.IO.Ports/7.0.0-preview.5.22301.12#dependencies-body-tab

The clue with all of these packs as being supported is a recent push or a recent version number, like 6.x or 7.x.

@tannergooding
Copy link
Member

tannergooding commented Jun 28, 2022

This is an area where I think improved NuGet support would be better.

These runtime.* packages are a "reserved" name (much like System.* is) and are using a largely undocumented feature around runtime.json -or- for tracking native dependencies separately. There are other libraries and packages, particularly those that support "native dependencies" which are using this feature anyways, despite a lack of support, because its the best thing available right now.

Ideally, NuGet would have first class support for these types of "sub-packages" and would have a more general way to de-list them by default while still allowing them to be searched. e.g. runtime.native.System.IO.Ports should still resolve to and bubble up System.IO.Ports itself and users should be encouraged to use that package as the primary. One could imagine this extending to other types of native packages (such as libClang: NuGet/Home#10571) to even more "framework-like" concepts such as Roslyn, where while you can reference individual packages like Microsoft.CodeAnalysis.Common most users probably want something like Microsoft.CodeAnalysis.CSharp instead. This would fit well with the model of "one package per assembly", which matches the default of "one package per project", while pushing users towards doing the "right thing" intended by the authors for primary scenarios.

@richlander
Copy link
Member Author

+100

Soft RID-specific dependencies would be awesome. Like, if I'm doing win-x64, I don't download linux-x64 dependent packages.

For clarity, the following packages doesn't use that feature, right?

https://www.nuget.org/packages?q=Microsoft.NETCoreApp.Runtime
https://www.nuget.org/packages?q=Microsoft.AspNetCore.App.Runtime

It's System.IO.Ports that does. Yes?

@tannergooding
Copy link
Member

tannergooding commented Jun 28, 2022

For System.IO.Ports (https://www.nuget.org/packages/System.IO.Ports) it looks to be a primarily agnostic package that contains both runtimes/unix and runtimes/win. It references runtime.native.System.IO.Ports which is also agnostic and which is actually empty. The latter then pulls in all of the runtime.*.runtime.native.System.IO.Ports sub-packages which are "rid-specific" as direct dependencies, so you "always" download these even for platforms that don't need them.

Microsoft.NETCore.App.Runtime.win-x64 (https://www.nuget.org/packages/Microsoft.NETCore.App.Runtime.win-x64) itself is a "rid-specific". It only contain files for runtimes/win-x64/*. If you referenced this package directly it wouldn't work for say linux-x64 and may not be the best choice for win10, depending. I don't see a "meta-package" that pulls it in so I'm unsure how its meant to be consumed or brought in.

Microsoft.NETCore.DotNetAppHost (https://www.nuget.org/packages/Microsoft.NETCore.DotNetAppHost) is an agnostic package that is empty except for a runtime.json. The json file references the various runtime.*.Microsoft.NETCore.DotNetAppHost packages for each support RID (*). The respective runtime.*.Microsoft.NETCore.DotNetAppHost packages are then "rid-specific". By referencing the main package you only download the dependencies necessary for your "target rid". If you're targeting win-x64, you won't download linux-x64 or osx-x64

@joelverhagen
Copy link
Member

We on NuGet.org have thought somewhat about this problem and, I believe, the core issue extends beyond runtime.* packages. I would say generally packages that the author never intends users to depend on directly are a special category which we have no metadata or property to describe today, in NuGet's domain model.

For example, a package like Microsoft.NETCore.Platforms has very little reason to be depended on directly so showing it in search results is not very interesting most of the time (at least in the VS PM UI, Browse tab).

Generally, NuGet.org's current approach is that certain default views filter some "implementation detail" packages out. This has effect in a couple of places:

  • We have a "deny list" of package IDs that are filtered out of the default search results (search with empty string query, https://www.nuget.org/packages). IIRC the runtime.* packages are in this list. However the moment you search runtime they do show up since it's no longer the default search results.
  • We filter out these packages from this report: https://www.nuget.org/stats/packages. But they can be seen with the "show all packages" checkbox.

So, in short, there is some notion already in NuGet.org that some packages are not as interesting as other for list views.

The being said, I strongly believe that any listed package should be visible if you search for the package ID. So if someone searches runtime.native.System.Net.Http they should see that package at the top because it is listed.

For a search of less than the exact package ID (like runtime) I think it's very subjective about where (or if) the runtime.* packages should appear in the result list. We could design an A/B experiment to evaluate the impact of hiding some of these "uninteresting" packages but it's not clear to me yet that it's worth the effort. We haven't received much feedback about this issue to warrant a larger investment.

We do have a way to "transfer popularity" (https://docs.microsoft.com/en-us/nuget/nuget-org/deprecate-packages#transfer-popularity-to-a-newer-package) of packages on NuGet.org which essentially moves download counts from an old package to a new package for search ranking purpose. This feature could reasonably be extended to completely nullify the download counts on a package making it appear at the bottom of the search results unless an exact match is found.

It's up to the package owners whether they want to mark a package as listed. However, unlisting a package may signal the wrong intent: it might make user's think it's deprecated or should not be used for any reason.

Ideally, NuGet would have first class support for these types of "sub-packages" and would have a more general way to de-list them by default while still allowing them to be searched. e.g. runtime.native.System.IO.Ports should still resolve to and bubble up System.IO.Ports itself and users should be encouraged to use that package as the primary.

@tannergooding, yeah this makes a lot of sense. This will immediately become complex with transitivity but I think it's a feature request worth proposing over on NuGet/Home. For anyone interesting, feel free to use our proposal process: to structure the conversation: https://github.com/NuGet/Home/tree/dev/meta#nuget-proposal-process.

I think there is some overlap here in the .Core or .Abstractions variants of non-BCL packages. Consider Microsoft.Extensions.Logging.Abstractions and Microsoft.Extensions.Logging. Is the former a "sub-package" of the latter? Perhaps. If the package author wants Microsoft.Extensions.Logging to be the package most package consumers install, they'll be fighting our ranking algorithm because Microsoft.Extensions.Logging.Abstractions will always have greater than or equal to the number of downloads (which is our proxy for popularity, a key ranking component) due to the dependency. So maybe this feature idea would help with that.

I think to prioritize such a feature we would need to understand the impact of not implementing this feature (i.e. status quo). Are there users getting confused and using these packages directly? Are there package searches which causing users pain because they are crowded with uninteresting packages?

@richlander
Copy link
Member Author

There are at least three topics here (some which are overlapping):

  • What to do with the EOL runtime packages. The deprecate feature doesn't make obvious sense because they are not the target of a PackageReference.
  • Better experience for runtime.json style packages. Isn't runtime.json the metadata you are looking for?
  • How best to model parent/child package relationships?

The problems with runtime packages today is searching on them is effectively useless. I was searching on them and the results are not meaningful.

This conversation started because a researcher asked me about it. It raises a bigger question of how we offer transparency on runtime packages. It would be awesome if these packages were easy to inspect but not noisy. They are this fully separate category and scenario of packages on NuGet.org.

For example, it would be good if dotnet publish told you which package it downloaded for you (in some reasonable way) and then you could inspect it in the NuGet gallery. That would be a good supply chain measure.

I am can write up some proposals.

@jkotas
Copy link
Member

jkotas commented Jun 28, 2022

Better experience for runtime.json style packages. Isn't runtime.json the metadata you are looking for?

The runtime.json packages are "packages with native dependencies".

The "runtime" searches are just a tip of the iceberg. The searching problem should be solved for the most common cases already as @joelverhagen explained. I do not think that it makes sense to further optimize searching experience for runtime.json packages as they exist today. We should rather focus on the end-to-end experience for packages with native dependencies in .NET. NuGet/Home#9631 has an example of what this may involve.

I think to prioritize such a feature we would need to understand the impact of not implementing this feature (i.e. status quo)

For packages with native dependencies: The interop with native code (OS or 3rd party libraries written in C/C++) has always been a .NET strength. The impact of not implementing this feature is erosion of this strength.

@joelverhagen
Copy link
Member

Another existing feature that we could consider using here with some thought would be packaged types. Currently .net tools, templates, SDK packages all use a special package type, which means that you can get a filtered view on nuget.org and can search within that.

We would need to make sure it plays nice with restore. But this is the point of package types. A .nuspec field that allows package authors to declare a special case for their package that exceeds or is somehow different than a standard dependency package.

@lambdageek
Copy link
Member

/cc @directhex @steveisok

@richlander
Copy link
Member Author

I'm still playing with the idea of switching to RID-specific apps by default (for .NET 8): dotnet/sdk#23540. It occurs to me that if we made that change, that enabling restore of just one RID slice would enable fundamental improvements as a default experience (for apps that have RID-specific dependencies). In short, the restore code (on the client and server) would be significantly less.

I like the idea of a new package type, at least in theory. The challenge is thinking through how a package would approach that. How would they adopt that w/rt servicing existing users. We need to thread the needle on that one. The compatibility constraints are pretty significant:.

These are the ideal requirements for a package that wants to participate:

  • Name doesn't change.
  • Transitions to having no RID-specific content in the main package (no extra content to download).
  • Existing users are not affected (restore downloads the same content as before).

If we cannot satisfy those requirements, it is a tough sell.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants