Merge pull request #859 from aleksijuvani/nuget-cache
Use NuGet package cache instead of the API if possible
This commit is contained in:
commit
2edb25de33
@ -232,6 +232,8 @@
|
||||
m.value_openedfilename = fname
|
||||
m.value_openedfilemode = mode
|
||||
return {
|
||||
read = function()
|
||||
end,
|
||||
close = function()
|
||||
m.value_closedfile = true
|
||||
end
|
||||
|
@ -38,84 +38,110 @@
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Given a package string, returns a table containing "verbatimVersion",
|
||||
-- "version" and for C# packages, "packageEntries".
|
||||
--
|
||||
|
||||
function nuget2010.packageAPIInfo(prj, package)
|
||||
local id = nuget2010.packageId(package)
|
||||
local version = nuget2010.packageVersion(package)
|
||||
local id = nuget2010.packageId(package)
|
||||
local version = nuget2010.packageVersion(package)
|
||||
|
||||
if not packageSourceInfos[prj.nugetsource] then
|
||||
local packageSourceInfo = {}
|
||||
-- It's possible that NuGet already has this package in its cache. In
|
||||
-- that case we can examine the nuspec file and the file listing
|
||||
-- locally.
|
||||
|
||||
printf("Examining NuGet package source '%s'...", prj.nugetsource)
|
||||
io.flush()
|
||||
local function examinePackageFromCache()
|
||||
-- It should be possible to implement this for platforms other than
|
||||
-- Windows, but we'll need to figure out where the NuGet cache is on
|
||||
-- these platforms (or if they even have one).
|
||||
|
||||
local response, err, code = http.get(prj.nugetsource)
|
||||
|
||||
if err ~= "OK" then
|
||||
p.error("NuGet API error (%d)\n%s", code, err)
|
||||
if not os.ishost("windows") then
|
||||
return
|
||||
end
|
||||
|
||||
response, err = json.decode(response)
|
||||
local cachePath = path.translate(path.join(os.getenv("userprofile"), ".nuget/packages", id))
|
||||
|
||||
if not response then
|
||||
p.error("Failed to decode NuGet API response (%s)", err)
|
||||
end
|
||||
|
||||
if not response.resources then
|
||||
p.error("Failed to understand NuGet API response (no resources in response)", id)
|
||||
end
|
||||
|
||||
local packageDisplayMetadataUriTemplate, catalog
|
||||
|
||||
for _, resource in ipairs(response.resources) do
|
||||
if not resource["@id"] then
|
||||
p.error("Failed to understand NuGet API response (no resource['@id'])")
|
||||
end
|
||||
|
||||
if not resource["@type"] then
|
||||
p.error("Failed to understand NuGet API response (no resource['@type'])")
|
||||
end
|
||||
|
||||
if resource["@type"]:find("PackageDisplayMetadataUriTemplate") == 1 then
|
||||
packageDisplayMetadataUriTemplate = resource
|
||||
end
|
||||
|
||||
if resource["@type"]:find("Catalog") == 1 then
|
||||
catalog = resource
|
||||
end
|
||||
end
|
||||
|
||||
if not packageDisplayMetadataUriTemplate then
|
||||
p.error("Failed to understand NuGet API response (no PackageDisplayMetadataUriTemplate resource)")
|
||||
end
|
||||
|
||||
if not catalog then
|
||||
if prj.nugetsource == "https://api.nuget.org/v3/index.json" then
|
||||
p.error("Failed to understand NuGet API response (no Catalog resource)")
|
||||
else
|
||||
p.error("Package source is not a NuGet gallery - non-gallery sources are currently unsupported", prj.nugetsource, prj.name)
|
||||
end
|
||||
end
|
||||
|
||||
packageSourceInfo.packageDisplayMetadataUriTemplate = packageDisplayMetadataUriTemplate
|
||||
packageSourceInfo.catalog = catalog
|
||||
|
||||
packageSourceInfos[prj.nugetsource] = packageSourceInfo
|
||||
end
|
||||
|
||||
if not packageAPIInfos[package] then
|
||||
if os.isdir(cachePath) then
|
||||
local packageAPIInfo = {}
|
||||
|
||||
printf("Examining NuGet package '%s'...", id)
|
||||
printf("Examining cached NuGet package '%s'...", id)
|
||||
io.flush()
|
||||
|
||||
local response, err, code = http.get(packageSourceInfos[prj.nugetsource].packageDisplayMetadataUriTemplate["@id"]:gsub("{id%-lower}", id:lower()))
|
||||
local versionPath = path.translate(path.join(cachePath, version))
|
||||
|
||||
local nuspecPath = path.translate(path.join(versionPath, id .. ".nuspec"))
|
||||
|
||||
if not os.isfile(nuspecPath) then
|
||||
return
|
||||
end
|
||||
|
||||
local nuspec = io.readfile(nuspecPath)
|
||||
|
||||
if not nuspec then
|
||||
return
|
||||
end
|
||||
|
||||
packageAPIInfo.verbatimVersion = nuspec:match("<version>(.+)</version>")
|
||||
packageAPIInfo.version = version
|
||||
|
||||
if not packageAPIInfo.verbatimVersion then
|
||||
return
|
||||
end
|
||||
|
||||
if p.project.isdotnet(prj) then
|
||||
-- Using the local file listing for "packageEntries" might
|
||||
-- not exactly match what we would get from the API but this
|
||||
-- doesn't matter. At the moment of writing, we're only
|
||||
-- interested in knowing what DLL files the package
|
||||
-- contains.
|
||||
|
||||
packageAPIInfo.packageEntries = {}
|
||||
|
||||
for _, file in ipairs(os.matchfiles(path.translate(path.join(versionPath, "**")))) do
|
||||
local extension = path.getextension(file)
|
||||
|
||||
if extension ~= ".nupkg" and extension ~= ".sha512" then
|
||||
table.insert(packageAPIInfo.packageEntries, path.translate(path.getrelative(versionPath, file)))
|
||||
end
|
||||
end
|
||||
|
||||
if #packageAPIInfo.packageEntries == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if nuspec:match("<frameworkAssemblies>(.+)</frameworkAssemblies>") then
|
||||
p.warn("NuGet package '%s' may depend on .NET Framework assemblies - package dependencies are currently unimplemented", id)
|
||||
end
|
||||
end
|
||||
|
||||
if nuspec:match("<dependencies>(.+)</dependencies>") then
|
||||
p.warn("NuGet package '%s' may depend on other packages - package dependencies are currently unimplemented", id)
|
||||
end
|
||||
|
||||
packageAPIInfos[package] = packageAPIInfo
|
||||
end
|
||||
end
|
||||
|
||||
if not packageAPIInfos[package] then
|
||||
examinePackageFromCache()
|
||||
end
|
||||
|
||||
-- If we didn't find the package from the cache, use the NuGet API
|
||||
-- instead.
|
||||
|
||||
if not packageAPIInfos[package] then
|
||||
if not packageSourceInfos[prj.nugetsource] then
|
||||
local packageSourceInfo = {}
|
||||
|
||||
printf("Examining NuGet package source '%s'...", prj.nugetsource)
|
||||
io.flush()
|
||||
|
||||
local response, err, code = http.get(prj.nugetsource)
|
||||
|
||||
if err ~= "OK" then
|
||||
if code == 404 then
|
||||
p.error("NuGet package '%s' for project '%s' couldn't be found in the repository", id, prj.name)
|
||||
else
|
||||
p.error("NuGet API error (%d)\n%s", code, err)
|
||||
end
|
||||
p.error("NuGet API error (%d)\n%s", code, err)
|
||||
end
|
||||
|
||||
response, err = json.decode(response)
|
||||
@ -124,10 +150,73 @@
|
||||
p.error("Failed to decode NuGet API response (%s)", err)
|
||||
end
|
||||
|
||||
if not response.items or #response.items == 0 then
|
||||
p.error("Failed to understand NuGet API response (no pages for package '%s')", id)
|
||||
if not response.resources then
|
||||
p.error("Failed to understand NuGet API response (no resources in response)", id)
|
||||
end
|
||||
|
||||
local packageDisplayMetadataUriTemplate, catalog
|
||||
|
||||
for _, resource in ipairs(response.resources) do
|
||||
if not resource["@id"] then
|
||||
p.error("Failed to understand NuGet API response (no resource['@id'])")
|
||||
end
|
||||
|
||||
if not resource["@type"] then
|
||||
p.error("Failed to understand NuGet API response (no resource['@type'])")
|
||||
end
|
||||
|
||||
if resource["@type"]:find("PackageDisplayMetadataUriTemplate") == 1 then
|
||||
packageDisplayMetadataUriTemplate = resource
|
||||
end
|
||||
|
||||
if resource["@type"]:find("Catalog") == 1 then
|
||||
catalog = resource
|
||||
end
|
||||
end
|
||||
|
||||
if not packageDisplayMetadataUriTemplate then
|
||||
p.error("Failed to understand NuGet API response (no PackageDisplayMetadataUriTemplate resource)")
|
||||
end
|
||||
|
||||
if not catalog then
|
||||
if prj.nugetsource == "https://api.nuget.org/v3/index.json" then
|
||||
p.error("Failed to understand NuGet API response (no Catalog resource)")
|
||||
else
|
||||
p.error("Package source is not a NuGet gallery - non-gallery sources are currently unsupported", prj.nugetsource, prj.name)
|
||||
end
|
||||
end
|
||||
|
||||
packageSourceInfo.packageDisplayMetadataUriTemplate = packageDisplayMetadataUriTemplate
|
||||
packageSourceInfo.catalog = catalog
|
||||
|
||||
packageSourceInfos[prj.nugetsource] = packageSourceInfo
|
||||
end
|
||||
|
||||
local packageAPIInfo = {}
|
||||
|
||||
printf("Examining NuGet package '%s'...", id)
|
||||
io.flush()
|
||||
|
||||
local response, err, code = http.get(packageSourceInfos[prj.nugetsource].packageDisplayMetadataUriTemplate["@id"]:gsub("{id%-lower}", id:lower()))
|
||||
|
||||
if err ~= "OK" then
|
||||
if code == 404 then
|
||||
p.error("NuGet package '%s' for project '%s' couldn't be found in the repository", id, prj.name)
|
||||
else
|
||||
p.error("NuGet API error (%d)\n%s", code, err)
|
||||
end
|
||||
end
|
||||
|
||||
response, err = json.decode(response)
|
||||
|
||||
if not response then
|
||||
p.error("Failed to decode NuGet API response (%s)", err)
|
||||
end
|
||||
|
||||
if not response.items or #response.items == 0 then
|
||||
p.error("Failed to understand NuGet API response (no pages for package '%s')", id)
|
||||
end
|
||||
|
||||
local items = {}
|
||||
|
||||
for _, page in ipairs(response.items) do
|
||||
@ -140,79 +229,79 @@
|
||||
end
|
||||
end
|
||||
|
||||
local versions = {}
|
||||
local versions = {}
|
||||
|
||||
for _, item in ipairs(items) do
|
||||
if not item.catalogEntry then
|
||||
p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry)", id)
|
||||
end
|
||||
|
||||
if not item.catalogEntry.version then
|
||||
p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry.version)", id)
|
||||
end
|
||||
|
||||
if not item.catalogEntry["@id"] then
|
||||
p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry['@id'])", id)
|
||||
end
|
||||
|
||||
table.insert(versions, item.catalogEntry.version)
|
||||
if not item.catalogEntry then
|
||||
p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry)", id)
|
||||
end
|
||||
|
||||
if not table.contains(versions, version) then
|
||||
local options = table.translate(versions, function(value) return "'" .. value .. "'" end)
|
||||
options = table.concat(options, ", ")
|
||||
|
||||
p.error("'%s' is not a valid version for NuGet package '%s' (options are: %s)", version, id, options)
|
||||
if not item.catalogEntry.version then
|
||||
p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry.version)", id)
|
||||
end
|
||||
|
||||
if not item.catalogEntry["@id"] then
|
||||
p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry['@id'])", id)
|
||||
end
|
||||
|
||||
table.insert(versions, item.catalogEntry.version)
|
||||
end
|
||||
|
||||
if not table.contains(versions, version) then
|
||||
local options = table.translate(versions, function(value) return "'" .. value .. "'" end)
|
||||
options = table.concat(options, ", ")
|
||||
|
||||
p.error("'%s' is not a valid version for NuGet package '%s' (options are: %s)", version, id, options)
|
||||
end
|
||||
|
||||
for _, item in ipairs(items) do
|
||||
if item.catalogEntry.version == version then
|
||||
local response, err, code = http.get(item.catalogEntry["@id"])
|
||||
if item.catalogEntry.version == version then
|
||||
local response, err, code = http.get(item.catalogEntry["@id"])
|
||||
|
||||
if err ~= "OK" then
|
||||
if code == 404 then
|
||||
if err ~= "OK" then
|
||||
if code == 404 then
|
||||
p.error("NuGet package '%s' version '%s' couldn't be found in the repository even though the API reported that it exists", id, version)
|
||||
else
|
||||
p.error("NuGet API error (%d)\n%s", code, err)
|
||||
end
|
||||
else
|
||||
p.error("NuGet API error (%d)\n%s", code, err)
|
||||
end
|
||||
end
|
||||
|
||||
response, err = json.decode(response)
|
||||
response, err = json.decode(response)
|
||||
|
||||
if not response then
|
||||
p.error("Failed to decode NuGet API response (%s)", err)
|
||||
end
|
||||
if not response then
|
||||
p.error("Failed to decode NuGet API response (%s)", err)
|
||||
end
|
||||
|
||||
if not response.verbatimVersion and not response.version then
|
||||
p.error("Failed to understand NuGet API response (package '%s' version '%s' has no verbatimVersion or version)", id, version)
|
||||
end
|
||||
if not response.verbatimVersion and not response.version then
|
||||
p.error("Failed to understand NuGet API response (package '%s' version '%s' has no verbatimVersion or version)", id, version)
|
||||
end
|
||||
|
||||
packageAPIInfo.verbatimVersion = response.verbatimVersion
|
||||
packageAPIInfo.version = response.version
|
||||
packageAPIInfo.verbatimVersion = response.verbatimVersion
|
||||
packageAPIInfo.version = response.version
|
||||
|
||||
-- C++ packages don't have this, but C# packages have a
|
||||
-- packageEntries field that lists all the files in the
|
||||
-- package. We need to look at this to figure out what
|
||||
-- DLLs to reference in the project file.
|
||||
-- C++ packages don't have this, but C# packages have a
|
||||
-- packageEntries field that lists all the files in the
|
||||
-- package. We need to look at this to figure out what
|
||||
-- DLLs to reference in the project file.
|
||||
|
||||
if prj.language == "C#" and not response.packageEntries then
|
||||
if prj.language == "C#" and not response.packageEntries then
|
||||
p.error("NuGet package '%s' version '%s' has no file listing. This package might be too old to be using this API or it might be a C++ package instead of a .NET Framework package.", id, response.version)
|
||||
end
|
||||
|
||||
if prj.language == "C#" then
|
||||
packageAPIInfo.packageEntries = {}
|
||||
|
||||
for _, item in ipairs(response.packageEntries) do
|
||||
if not item.fullName then
|
||||
p.error("Failed to understand NuGet API response (package '%s' version '%s' packageEntry has no fullName)", id, version)
|
||||
end
|
||||
|
||||
table.insert(packageAPIInfo.packageEntries, path.translate(item.fullName))
|
||||
end
|
||||
|
||||
if prj.language == "C#" then
|
||||
packageAPIInfo.packageEntries = {}
|
||||
|
||||
for _, item in ipairs(response.packageEntries) do
|
||||
if not item.fullName then
|
||||
p.error("Failed to understand NuGet API response (package '%s' version '%s' packageEntry has no fullName)", id, version)
|
||||
end
|
||||
|
||||
table.insert(packageAPIInfo.packageEntries, path.translate(item.fullName))
|
||||
end
|
||||
|
||||
if #packageAPIInfo.packageEntries == 0 then
|
||||
p.error("NuGet package '%s' file listing is empty", id)
|
||||
end
|
||||
if #packageAPIInfo.packageEntries == 0 then
|
||||
p.error("NuGet package '%s' file listing is empty", id)
|
||||
end
|
||||
|
||||
if response.frameworkAssemblyGroup then
|
||||
p.warn("NuGet package '%s' may depend on .NET Framework assemblies - package dependencies are currently unimplemented", id)
|
||||
@ -221,15 +310,15 @@
|
||||
|
||||
if response.dependencyGroups then
|
||||
p.warn("NuGet package '%s' may depend on other packages - package dependencies are currently unimplemented", id)
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
packageAPIInfos[package] = packageAPIInfo
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
packageAPIInfos[package] = packageAPIInfo
|
||||
end
|
||||
|
||||
return packageAPIInfos[package]
|
||||
end
|
||||
|
||||
@ -240,15 +329,15 @@
|
||||
|
||||
function nuget2010.generatePackagesConfig(prj)
|
||||
if #prj.nuget > 0 then
|
||||
p.w('<?xml version="1.0" encoding="utf-8"?>')
|
||||
p.push('<packages>')
|
||||
p.w('<?xml version="1.0" encoding="utf-8"?>')
|
||||
p.push('<packages>')
|
||||
|
||||
for _, package in ipairs(prj.nuget) do
|
||||
p.x('<package id="%s" version="%s" targetFramework="%s" />', nuget2010.packageId(package), nuget2010.packageVersion(package), nuget2010.packageFramework(prj))
|
||||
end
|
||||
end
|
||||
|
||||
p.pop('</packages>')
|
||||
end
|
||||
p.pop('</packages>')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user