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

feat(nuget): add download option to source and implement repository_url #1781

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions lua/mason-core/installer/managers/nuget.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,48 @@ local Result = require "mason-core.result"
local installer = require "mason-core.installer"
local log = require "mason-core.log"
local platform = require "mason-core.platform"
local fetch = require "mason-core.fetch"

local M = {}

---@async
---@param package string
---@param version string
---@param repository_url string
---@nodiscard
function M.install(package, version)
function M.install(package, version, repository_url)
log.fmt_debug("nuget: install %s %s", package, version)
local ctx = installer.context()
ctx.stdio_sink.stdout(("Installing nuget package %s@%s…\n"):format(package, version))
return ctx.spawn.dotnet {
local args = {
"tool",
"update",
"--tool-path",
".",
{ "--version", version },
package,
}

if repository_url then
table.insert(args, { "--add-source", repository_url })
end

table.insert(args, package)

return ctx.spawn.dotnet(args)
end

---@alias NugetIndexResource { '@id': string, '@type': string}
---@alias NugetIndexFile { version: string, resources: NugetIndexResource[]}

---@async
---@param repository_url string
---@return Result # Result<NugetIndexFile>
function M.fetch_nuget_endpoint(repository_url)
return fetch(repository_url, {
headers = {
Accept = "application/json",
},
}):map_catching(vim.json.decode)
end

---@param bin string
Expand Down
1 change: 1 addition & 0 deletions lua/mason-core/installer/managers/std.lua
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ local unpack_by_filename = _.cond {
{ _.matches "%.tar%.zst$", untar_zst },
{ _.matches "%.zip$", unzip },
{ _.matches "%.vsix$", unzip },
{ _.matches "%.nupkg$", unzip },
{ _.matches "%.gz$", gunzip },
{ _.T, _.compose(Result.success, _.format "%q doesn't need unpacking.") },
}
Expand Down
76 changes: 67 additions & 9 deletions lua/mason-core/installer/registry/providers/nuget.lua
Original file line number Diff line number Diff line change
@@ -1,25 +1,83 @@
local Result = require "mason-core.result"
local common = require "mason-core.installer.managers.common"
local util = require "mason-core.installer.registry.util"
local expr = require "mason-core.installer.registry.expr"
local nuget = require "mason-core.installer.managers.nuget"
local _ = require "mason-core.functional"

local M = {}

---@param source RegistryPackageSource
---@class NugetPackageSource : RegistryPackageSource
---@field download FileDownloadSpec

---@param source NugetPackageSource
---@param purl Purl
function M.parse(source, purl)
---@class ParsedNugetSource : ParsedPackageSource
local parsed_source = {
package = purl.name,
version = purl.version,
}
return Result.try(function (try)
local repository_url = _.path({ "qualifiers", "repository_url" }, purl)

local download_item = nil
if source.download then

if not repository_url then
-- if not set we need to provide repository url because we need it for
-- download url discovery
repository_url = "https://api.nuget.org/v3/index.json"
end

local index_file = try(nuget.fetch_nuget_endpoint(repository_url))

local resource = vim.iter(index_file.resources)
:find(function (v)
return v['@type'] == 'PackageBaseAddress/3.0.0'
end)

assert(resource, "could not get PackageBaseAddress resource from nuget index file")

local package_base_address = resource["@id"]
local package_lowercase = purl.name:lower()

local nupkg_download_url = string.format("%s%s/%s/%s.%s.nupkg",
package_base_address,
package_lowercase,
purl.version,
package_lowercase,
purl.version)

local expr_ctx = { version = purl.version }

---@type FileDownloadSpec
local download_spec = try(util.coalesce_by_target(try(expr.tbl_interpolate(source.download, expr_ctx)), {}))

download_item = {
download_url = nupkg_download_url,
out_file = download_spec.file
}
end

---@class ParsedNugetSource : ParsedPackageSource
---@field download? DownloadItem
---@field repository_url string Custom repository URL to pull from
local parsed_source = {
package = purl.name,
version = purl.version,
download = download_item,
repository_url = repository_url
}

return Result.success(parsed_source)
return parsed_source
end)
end

---@async
---@param ctx InstallContext
---@param source ParsedNugetSource
function M.install(ctx, source)
local nuget = require "mason-core.installer.managers.nuget"
return nuget.install(source.package, source.version)
if source.download then
return common.download_files(ctx, {source.download})
else
return nuget.install(source.package, source.version, source.repository_url)
end
end

---@async
Expand Down
6 changes: 3 additions & 3 deletions tests/fixtures/purl-test-suite-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,13 @@
},
{
"description": "nuget names are case sensitive",
"purl": "pkg:Nuget/[email protected]",
"canonical_purl": "pkg:nuget/[email protected]",
"purl": "pkg:Nuget/[email protected]?repository_url=https://api.nuget.org/v3/index.json",
"canonical_purl": "pkg:nuget/[email protected]?repository_url=https://api.nuget.org/v3/index.json",
"type": "nuget",
"namespace": null,
"name": "EnterpriseLibrary.Common",
"version": "6.0.1304",
"qualifiers": null,
"qualifiers": { "repository_url": "https://api.nuget.org/v3/index.json" },
"subpath": null,
"is_invalid": false
},
Expand Down
6 changes: 4 additions & 2 deletions tests/mason-core/installer/registry/providers/nuget_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ local stub = require "luassert.stub"

---@param overrides Purl
local function purl(overrides)
local purl = Purl.parse("pkg:nuget/[email protected]"):get_or_throw()
local purl = Purl.parse("pkg:nuget/[email protected]?repository_url=https://api.nuget.org/v3/index.json"):get_or_throw()
if not overrides then
return purl
end
Expand All @@ -19,6 +19,7 @@ describe("nuget provider :: parsing", function()
Result.success {
package = "package",
version = "2.2.0",
repository_url = "https://api.nuget.org/v3/index.json"
},
nuget.parse({}, purl())
)
Expand All @@ -35,11 +36,12 @@ describe("nuget provider :: installing", function()
return nuget.install(ctx, {
package = "package",
version = "1.5.0",
repository_url = "https://api.nuget.org/v3/index.json"
})
end)

assert.is_true(result:is_success())
assert.spy(manager.install).was_called(1)
assert.spy(manager.install).was_called_with("package", "1.5.0")
assert.spy(manager.install).was_called_with("package", "1.5.0", "https://api.nuget.org/v3/index.json")
end)
end)