diff --git a/src/Paket.Core/Dependencies/NuGet.fs b/src/Paket.Core/Dependencies/NuGet.fs index d322946b27..2cb1dcc182 100644 --- a/src/Paket.Core/Dependencies/NuGet.fs +++ b/src/Paket.Core/Dependencies/NuGet.fs @@ -380,6 +380,8 @@ let GetAnalyzerFiles targetFolder = getFilesMatching targetFolder "*.dll" "analy let tryNuGetV3 (auth, nugetV3Url, package:PackageName) = NuGetV3.findVersionsForPackage(nugetV3Url, auth, package) +let tryNugetV3Search (auth, nugetV3Url, package:PackageName) = + NuGetV3.findVersionForPackageFromSearch(nugetV3Url, auth, package) let rec private getPackageDetails alternativeProjectRoot root force (parameters:GetPackageDetailsParameters) : Async = let sources = parameters.Package.Sources @@ -624,8 +626,15 @@ let GetVersions force alternativeProjectRoot root (parameters:GetPackageVersions return v2Feeds | NuGetV3 source -> - let! versionsAPI = NuGetV3.getNuGetV3Resource source NuGetV3.AllVersionsAPI - return [ getVersionsCached "V3" tryNuGetV3 (nugetSource, source.Authentication, versionsAPI, packageName) ] + + let! allVersionApi = NuGetV3.tryGetNuGetV3Resource source NuGetV3.AllVersionsAPI + match allVersionApi with + | Some api -> + return [ getVersionsCached "V3" tryNuGetV3 (nugetSource, source.Authentication, api, packageName) ] + | None -> + let! searchApi = NuGetV3.getNuGetV3Resource source NuGetV3.SearchQueryService + return [ getVersionsCached "V3" tryNugetV3Search (nugetSource, source.Authentication, searchApi, packageName) ] + | LocalNuGet(path,Some _) -> return [ NuGetLocal.getAllVersionsFromLocalPath (true, path, packageName, alternativeProjectRoot, root) ] | LocalNuGet(path,None) -> @@ -648,6 +657,7 @@ let GetVersions force alternativeProjectRoot root (parameters:GetPackageVersions |> Async.Parallel let! result = versionResponse + let allResults = result |> Array.zip sources diff --git a/src/Paket.Core/Dependencies/NuGetV3.fs b/src/Paket.Core/Dependencies/NuGetV3.fs index 019481c631..a7ed2c1bd9 100644 --- a/src/Paket.Core/Dependencies/NuGetV3.fs +++ b/src/Paket.Core/Dependencies/NuGetV3.fs @@ -39,18 +39,21 @@ type NugetV3SourceRootJSON = type NugetV3ResourceType = | AutoComplete | AllVersionsAPI + | SearchQueryService | PackageIndex - static member All = [ AutoComplete; AllVersionsAPI; PackageIndex ] + static member All = [ AutoComplete; AllVersionsAPI; PackageIndex; SearchQueryService ] member this.AsString = match this with | AutoComplete -> "SearchAutoCompleteService" | AllVersionsAPI -> "PackageBaseAddress" + | SearchQueryService -> "SearchQueryService" | PackageIndex -> "RegistrationsBaseUrl" member this.AcceptedVersions = match this with | AutoComplete -> ([ "3.0.0-rc"; "3.0.0-beta" ] |> List.map (SemVer.Parse >> Some)) @ [None] - | AllVersionsAPI -> [ Some (SemVer.Parse "3.0.0") ] @ [None] + | AllVersionsAPI + | SearchQueryService -> [ Some (SemVer.Parse "3.0.0") ] @ [None] // prefer 3.6.0 as it includes semver packages. | PackageIndex -> ([ "3.6.0"; "3.4.0"; "3.0.0-rc"; "3.0.0-beta" ] |> List.map (SemVer.Parse >> Some)) @ [None] @@ -59,7 +62,7 @@ type ResourceIndex = Map let private nugetV3Resources = System.Collections.Concurrent.ConcurrentDictionary>() let private rnd = Random() -let getNuGetV3Resource (source : NuGetV3Source) (resourceType : NugetV3ResourceType) : Async = +let tryGetNuGetV3Resource (source : NuGetV3Source) (resourceType : NugetV3ResourceType) : Async = let key = source let getResourcesRaw () = async { @@ -140,10 +143,17 @@ let getNuGetV3Resource (source : NuGetV3Source) (resourceType : NugetV3ResourceT async { let t = nugetV3Resources.GetOrAdd(key, (fun _ -> getResourcesRaw())) let! res = t |> Async.AwaitTask - return - match res.TryFind resourceType with - | Some s -> s - | None -> failwithf "could not find an %s endpoint for %s" (resourceType.ToString()) source.Url + return res.TryFind resourceType + + } + +let getNuGetV3Resource (source : NuGetV3Source) (resourceType : NugetV3ResourceType) : Async = + async { + match! tryGetNuGetV3Resource source resourceType with + | Some s -> return s + | None -> + failwithf "could not find an %s endpoint for %s" (resourceType.ToString()) source.Url + return Unchecked.defaultof } /// [omit] @@ -156,6 +166,22 @@ type JSONVersionData = { Data : string [] Versions : string [] } +/// [omit] +type JSONSearchResultVersion = { + [] + Id: string + Version: string +} + +/// [omit] +type JSONSearchResult = { + Id: string + Versions: JSONSearchResultVersion [] +} + +/// [omit] +type JSONSearchData = { Data: JSONSearchResult[] } + /// [omit] type JSONRootData = { Resources : JSONResource [] } @@ -477,6 +503,8 @@ let extractAutoCompleteVersions(response:string) = let extractVersions(response:string) = JsonConvert.DeserializeObject(response).Versions +let extractSearchVersion(response:string) = + JsonConvert.DeserializeObject(response) let internal findAutoCompleteVersionsForPackage(v3Url, auth, packageName:Domain.PackageName, includingPrereleases, maxResults) = async { @@ -502,6 +530,25 @@ let FindAutoCompleteVersionsForPackage(nugetURL, auth, package, includingPrerele return raw } +let internal findVersionForPackageFromSearch(v3Url, auth, packageName:Domain.PackageName) = + let url = $"{v3Url}?q={packageName.Name}&semVerLevel=2.0.0&prerelease=true" + NuGetRequestGetVersions.ofSimpleFunc url (fun _ -> + async { + let! response = safeGetFromUrl(auth,url,acceptJson) // NuGet is showing old versions first + return + response + |> SafeWebResult.map (fun text -> + let versions = extractSearchVersion text + let entry = + versions.Data + |> Seq.tryFind(fun x -> String.Equals(x.Id, packageName.Name, StringComparison.OrdinalIgnoreCase)) + |> Option.map (fun x -> x.Versions |> Array.map _.Version) + |> Option.defaultValue [||] + + let result = SemVer.SortVersions entry + result + ) + }) let internal findVersionsForPackage(v3Url, auth, packageName:Domain.PackageName) = // Comment from http://api.nuget.org/v3/index.json