MoaidHathot / dotnet.nvim

.NET Neovim plugin for improving the .NET dev experience in Neovim, written completely in Lua
MIT License
88 stars 6 forks source link

Custom nuget sources do not work #7

Open marcinjahn opened 2 months ago

marcinjahn commented 2 months ago

In my project, I have Nuget.config with a custom nuget packages source specified. This plugin does not seem to respect that and searches for packages only in the nuget.org source.

NWVi commented 2 months ago

I took a quick look at the code and looks like this is the relevant function: https://github.com/MoaidHathot/dotnet.nvim/blob/6ce9918d3154e000f49a392a93d0ba9905238e3e/lua/dotnet/ui/windows/nuget-reference.lua#L16C10-L16C10

From my understanding of how nuget works, it should be possible to do something like this:

  1. dotnet nuget list source to get a list of available nuget sources
  2. Check the Service Index for that source i.e https://api.nuget.org/v3/index.json for nuget.org for the SearchQueryService resource.
  3. The @id field will be the base url, which we then can use to query available packages.

We could then loop over all the query-able sources and search by changing the url line to:

local url = baseUrl .. 'q=' .. name .. '&prerelease=true'

Though I'm not entirely sure how we should handle private nuget sources that require credentials. :thinking:

I based my suggestion on the documentation for how Search works in the Nuget Server API documentation: https://learn.microsoft.com/en-us/nuget/api/search-query-service-resource

Edit: It also seems like it's possible to search for packages using the dotnet cli if you have a version newer than 8.0.2 https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-package-search

MoaidHathot commented 2 months ago

@NWVi, thank you for the deep dive. You are correct in that the biggest issue is the credentials. the dotnet CLI could help but I don't want to lock this extension to .NET SDK 8.0.2+. In addition I observed that dotnet package search can be a bit slow sometimes (needing further research)

I think we have a few options:

In how I see it, the proper solution will probably be to combine the two approaches- if .NET SDK 8.0.2+ exists use dotnet package search, otherwise, if a private feed is detected using dotnet nuget list source, try acquiring an access token using an authentication callback. We can also let the user configure the actual method dotnet_cli, manual_auth, auto (or something similar)

What do you think?

NWVi commented 2 months ago

@MoaidHathot I like the idea of letting the user configure what to use for searching. I don't think we have to lock the plugin to only be compatible with 8.0.2xx+ versions of the .NET SDK, and can simply check the dotnet version to determine if dotnet package search can be used.

I'm taking a stab at using dotnet package search if the user has a dotnet version newer than 8.0.2xx, and have found that the response from dotnet package search has way fewer attributes than the registry response, even with the detailed verbosity.

packages = {
  {
      description = "Json.NET is a popular high-performance JSON framework for .NET",
      id = "Newtonsoft.Json",
      latestVersion = "13.0.3",
      owners = "dotnetfoundation, jamesnk, newtonsoft",
      projectUrl = "https://www.newtonsoft.com/json",
      totalDownloads = 5047192850,
  },
 {
    -- another package
 },
}

Noticeably the authors and tiles are missing, further more seeing available package versions are seem to only be included when using the --exact-match flag.

MoaidHathot commented 2 months ago

@NWVi, I did some more digging and from what I can see, dotnet package search forwards the request to the "old" Nuget client shipped via NuGet.CommandLine.XPlat.dll. This DLL is downloadable via Nuget and is part of the NuGet.Client repo. Theoretically, we can use that instead of relying on a specific version of the .NET SDK, and that should resolve the issue you pointed out where some of the data is not shown in the default dotnet CLI printer.

I need to test this further but that begs the question how to ship this DLL with a pure Lua extension. We can just bundle it as a binary with the lua files or we can download it when the plugin is installed, although that complicate things further. I'm new to authoring neovim extensions so I'm wondering what is the best practice here and what other lua-based neovim extensions do.

Regarding the callback option that we can provide to users; it has more depth into it since we don't really know which authentication/authorization methods their private feed uses so they basically have to configure the Curl command in their callbacks.

MoaidHathot commented 2 months ago

I tried playing with NuGet.CommandLine.XPlat.dll. The auto-authentication works, but it doesn't show all of the information if --exact-match is not provided, so that isn't an issue with the default printer of dotnet package search but of the XPlat version of the Nuget CLI client.

Furthermore, NuGet.CommandLine.XPlat.dll is distributed only for .NET 8+ which isn't ideal. I'll try to dig even more into the Xplat implementation, if we are lucky it could have a dependency on other binaries that we can use. I'll also try checking whether there is a technical reason for locking it into .NET 8. I'll open an issue for the Nuge team about targeting earlier .NET versions.

MoaidHathot commented 2 months ago

Apparently, .NET Core 3.1 was supported as a target up until version 6.5.1. I'll look deeper, we might be able to build a custom version of the latest DLL that targets .NET Core 3.1 and that output more information

MoaidHathot commented 2 months ago

Another update- I forked the Nuget.Client project that hosts NuGet.CommandLine.XPlat.dll and was able to build a new DLL with a few customization. I'm thinking about publishing the customized version (with a different name) as a dotnet tool so that we won't have to bundle it with the extension but require it via a tool-manifest instead.

There is still work to be done, but that is the gist of it. What do you think? I would be happier if we could find a better, simpler approach.

MoaidHathot commented 2 months ago

I'm also playing with NuGet.Commands which targets .NET Standard and provide the same APIs. It seems to be working, although authentication can be a bit slow