@@ -63,10 +63,9 @@ public override Task<FindResults> FindVersionAsync(string packageName, string ve
6363 } ) ;
6464 var filterBuilder = queryBuilder . FilterBuilder ;
6565
66- // We need to explicitly add 'Id eq <packageName>' whenever $filter is used, otherwise arbitrary results are returned.
67- filterBuilder . AddCriterion ( $ "Id eq '{ packageName } '") ;
68- filterBuilder . AddCriterion ( $ "NormalizedVersion eq '{ packageName } '") ;
69-
66+ // We need to explicitly add 'Id eq <packageName>' whenever $filter is used, otherwise arbitrary results are returned.
67+ filterBuilder . AddCriterion ( $ "Id eq '{ packageName } '") ;
68+ filterBuilder . AddCriterion ( $ "NormalizedVersion eq '{ version } '") ;
7069 var requestUrl = $ "{ Repository . Uri } /FindPackagesById()?{ queryBuilder . BuildQueryString ( ) } ";
7170 string response = HttpRequestCallAsync ( requestUrl , debugMsgs , out ErrorRecord errRecord ) ;
7271 FindResults findResponse = new FindResults ( stringResponse : new string [ ] { response } , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ;
@@ -87,13 +86,46 @@ public override Task<FindResults> FindVersionAsync(string packageName, string ve
8786 public override Task < FindResults > FindVersionGlobbingAsync ( string packageName , VersionRange versionRange , bool includePrerelease , ResourceType type , bool getOnlyLatest , ConcurrentQueue < ErrorRecord > errorMsgs , ConcurrentQueue < string > warningMsgs , ConcurrentQueue < string > debugMsgs , ConcurrentQueue < string > verboseMsgs )
8887 {
8988 debugMsgs . Enqueue ( "In NuGetServerAPICalls::FindVersionGlobbingAsync()" ) ;
90- FindResults findResponse = FindVersionGlobbing ( packageName , versionRange , includePrerelease , type , getOnlyLatest , out ErrorRecord errRecord ) ;
89+ List < string > responses = new List < string > ( ) ;
90+ int skip = 0 ;
91+
92+ var initialResponse = FindVersionGlobbingAsync ( packageName , versionRange , includePrerelease , skip , getOnlyLatest , debugMsgs , out ErrorRecord errRecord ) ;
9193 if ( errRecord != null )
9294 {
9395 errorMsgs . Enqueue ( errRecord ) ;
96+ return Task . FromResult ( new FindResults ( stringResponse : responses . ToArray ( ) , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ) ;
9497 }
9598
96- return Task . FromResult ( findResponse ) ;
99+ responses . Add ( initialResponse ) ;
100+
101+ if ( ! getOnlyLatest )
102+ {
103+ int initialCount = GetCountFromResponse ( initialResponse , out errRecord ) ;
104+ if ( errRecord != null )
105+ {
106+ errorMsgs . Enqueue ( errRecord ) ;
107+ return Task . FromResult ( new FindResults ( stringResponse : responses . ToArray ( ) , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ) ;
108+ }
109+
110+ int count = ( int ) Math . Ceiling ( ( double ) initialCount / 100 ) - 1 ;
111+
112+ while ( count > 0 )
113+ {
114+ // skip 100
115+ skip += 100 ;
116+ var tmpResponse = FindVersionGlobbingAsync ( packageName , versionRange , includePrerelease , skip , getOnlyLatest , debugMsgs , out errRecord ) ;
117+ if ( errRecord != null )
118+ {
119+ errorMsgs . Enqueue ( errRecord ) ;
120+ return Task . FromResult ( new FindResults ( stringResponse : responses . ToArray ( ) , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ) ;
121+ }
122+
123+ responses . Add ( tmpResponse ) ;
124+ count -- ;
125+ }
126+ }
127+
128+ return Task . FromResult ( new FindResults ( stringResponse : responses . ToArray ( ) , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ) ;
97129 }
98130 /// <summary>
99131 /// Find method which allows for searching for all packages from a repository and returns latest version for each.
@@ -122,7 +154,7 @@ public override FindResults FindAll(bool includePrerelease, ResourceType type, o
122154 return new FindResults ( stringResponse : responses . ToArray ( ) , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ;
123155 }
124156
125- int count = initialCount / 6000 ;
157+ int count = ( int ) Math . Ceiling ( ( double ) initialCount / 6000 ) - 1 ;
126158 // if more than 100 count, loop and add response to list
127159 while ( count > 0 )
128160 {
@@ -166,7 +198,7 @@ public override FindResults FindTags(string[] tags, bool includePrerelease, Reso
166198 return new FindResults ( stringResponse : responses . ToArray ( ) , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ;
167199 }
168200
169- int count = initialCount / 100 ;
201+ int count = ( int ) Math . Ceiling ( ( double ) initialCount / 100 ) - 1 ;
170202 // if more than 100 count, loop and add response to list
171203 while ( count > 0 )
172204 {
@@ -238,7 +270,19 @@ public override FindResults FindName(string packageName, bool includePrerelease,
238270 public override Task < FindResults > FindNameAsync ( string packageName , bool includePrerelease , ResourceType type , ConcurrentQueue < ErrorRecord > errorMsgs , ConcurrentQueue < string > warningMsgs , ConcurrentQueue < string > debugMsgs , ConcurrentQueue < string > verboseMsgs )
239271 {
240272 debugMsgs . Enqueue ( "In NuGetServerAPICalls::FindNameAsync()" ) ;
241- FindResults findResponse = FindName ( packageName , includePrerelease , type , out ErrorRecord errRecord ) ;
273+ var queryBuilder = new NuGetV2QueryBuilder ( new Dictionary < string , string > {
274+ { "id" , $ "'{ packageName } '" } ,
275+ } ) ;
276+ var filterBuilder = queryBuilder . FilterBuilder ;
277+
278+ filterBuilder . AddCriterion ( includePrerelease ? "IsAbsoluteLatestVersion" : "IsLatestVersion" ) ;
279+
280+ // We need to explicitly add 'Id eq <packageName>' whenever $filter is used, otherwise arbitrary results are returned.
281+ filterBuilder . AddCriterion ( $ "Id eq '{ packageName } '") ;
282+
283+ var requestUrl = $ "{ Repository . Uri } /FindPackagesById()?{ queryBuilder . BuildQueryString ( ) } ";
284+ string response = HttpRequestCallAsync ( requestUrl , debugMsgs , out ErrorRecord errRecord ) ;
285+ FindResults findResponse = new FindResults ( stringResponse : new string [ ] { response } , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ;
242286 if ( errRecord != null )
243287 {
244288 errorMsgs . Enqueue ( errRecord ) ;
@@ -310,7 +354,7 @@ public override FindResults FindNameGlobbing(string packageName, bool includePre
310354 return new FindResults ( stringResponse : responses . ToArray ( ) , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ;
311355 }
312356
313- int count = initialCount / 100 ;
357+ int count = ( int ) Math . Ceiling ( ( double ) initialCount / 100 ) - 1 ;
314358 // if more than 100 count, loop and add response to list
315359 while ( count > 0 )
316360 {
@@ -355,7 +399,7 @@ public override FindResults FindNameGlobbingWithTag(string packageName, string[]
355399 return new FindResults ( stringResponse : responses . ToArray ( ) , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ;
356400 }
357401
358- int count = initialCount / 100 ;
402+ int count = ( int ) Math . Ceiling ( ( double ) initialCount / 100 ) - 1 ;
359403 // if more than 100 count, loop and add response to list
360404 while ( count > 0 )
361405 {
@@ -404,7 +448,7 @@ public override FindResults FindVersionGlobbing(string packageName, VersionRange
404448 return new FindResults ( stringResponse : responses . ToArray ( ) , hashtableResponse : emptyHashResponses , responseType : FindResponseType ) ;
405449 }
406450
407- int count = initialCount / 100 ;
451+ int count = ( int ) Math . Ceiling ( ( double ) initialCount / 100 ) - 1 ;
408452
409453 while ( count > 0 )
410454 {
@@ -521,7 +565,19 @@ public override Stream InstallPackage(string packageName, string packageVersion,
521565 public override Task < Stream > InstallPackageAsync ( string packageName , string packageVersion , bool includePrerelease , ConcurrentQueue < ErrorRecord > errorMsgs , ConcurrentQueue < string > warningMsgs , ConcurrentQueue < string > debugMsgs , ConcurrentQueue < string > verboseMsgs )
522566 {
523567 debugMsgs . Enqueue ( "In NuGetServerAPICalls::InstallPackageAsync()" ) ;
524- Stream results = InstallPackage ( packageName , packageVersion , includePrerelease , out ErrorRecord errRecord ) ;
568+ Stream results = new MemoryStream ( ) ;
569+ if ( string . IsNullOrEmpty ( packageVersion ) )
570+ {
571+ errorMsgs . Enqueue ( new ErrorRecord (
572+ exception : new ArgumentNullException ( $ "Package version could not be found for { packageName } ") ,
573+ "PackageVersionNullOrEmptyError" ,
574+ ErrorCategory . InvalidArgument ,
575+ _cmdletPassedIn ) ) ;
576+
577+ return Task . FromResult ( results ) ;
578+ }
579+
580+ results = InstallVersionAsync ( packageName , packageVersion , debugMsgs , out ErrorRecord errRecord ) ;
525581 if ( errRecord != null )
526582 {
527583 errorMsgs . Enqueue ( errRecord ) ;
@@ -628,6 +684,55 @@ private HttpContent HttpRequestCallForContent(string requestUrl, out ErrorRecord
628684 return content ;
629685 }
630686
687+ /// <summary>
688+ /// Helper method that makes the HTTP request for install APIs on worker threads; enqueues diagnostics instead of writing to cmdlet streams.
689+ /// </summary>
690+ private HttpContent HttpRequestCallForContentAsync ( string requestUrl , ConcurrentQueue < string > debugMsgs , out ErrorRecord errRecord )
691+ {
692+ debugMsgs . Enqueue ( "In NuGetServerAPICalls::HttpRequestCallForContentAsync()" ) ;
693+ errRecord = null ;
694+ HttpContent content = null ;
695+
696+ try
697+ {
698+ debugMsgs . Enqueue ( $ "Request url is: '{ requestUrl } '") ;
699+ HttpRequestMessage request = new HttpRequestMessage ( HttpMethod . Get , requestUrl ) ;
700+
701+ content = SendRequestForContentAsync ( request , _sessionClient ) . GetAwaiter ( ) . GetResult ( ) ;
702+ }
703+ catch ( HttpRequestException e )
704+ {
705+ errRecord = new ErrorRecord (
706+ exception : e ,
707+ "HttpRequestFailure" ,
708+ ErrorCategory . ConnectionError ,
709+ this ) ;
710+ }
711+ catch ( ArgumentNullException e )
712+ {
713+ errRecord = new ErrorRecord (
714+ exception : e ,
715+ "HttpRequestFailure" ,
716+ ErrorCategory . InvalidData ,
717+ this ) ;
718+ }
719+ catch ( InvalidOperationException e )
720+ {
721+ errRecord = new ErrorRecord (
722+ exception : e ,
723+ "HttpRequestFailure" ,
724+ ErrorCategory . InvalidOperation ,
725+ this ) ;
726+ }
727+
728+ if ( string . IsNullOrEmpty ( content ? . ToString ( ) ) )
729+ {
730+ debugMsgs . Enqueue ( "Response is empty" ) ;
731+ }
732+
733+ return content ;
734+ }
735+
631736 /// <summary>
632737 /// Helper method that makes the HTTP request for the NuGet server protocol url passed in for async find APIs.
633738 /// This helper writes diagnostics to the provided debug queue and avoids cmdlet stream writes.
@@ -912,6 +1017,25 @@ private string FindNameGlobbingWithTag(string packageName, string[] tags, bool i
9121017 private string FindVersionGlobbing ( string packageName , VersionRange versionRange , bool includePrerelease , int skip , bool getOnlyLatest , out ErrorRecord errRecord )
9131018 {
9141019 _cmdletPassedIn . WriteDebug ( "In NuGetServerAPICalls::FindVersionGlobbing()" ) ;
1020+ var requestUrl = GetVersionGlobbingRequestUrl ( packageName , versionRange , includePrerelease , skip , getOnlyLatest ) ;
1021+ return HttpRequestCall ( requestUrl , out errRecord ) ;
1022+ }
1023+
1024+ /// <summary>
1025+ /// Worker-thread counterpart of FindVersionGlobbing(); enqueues diagnostics instead of writing to cmdlet streams.
1026+ /// </summary>
1027+ private string FindVersionGlobbingAsync ( string packageName , VersionRange versionRange , bool includePrerelease , int skip , bool getOnlyLatest , ConcurrentQueue < string > debugMsgs , out ErrorRecord errRecord )
1028+ {
1029+ debugMsgs . Enqueue ( "In NuGetServerAPICalls::FindVersionGlobbingAsync()" ) ;
1030+ var requestUrl = GetVersionGlobbingRequestUrl ( packageName , versionRange , includePrerelease , skip , getOnlyLatest ) ;
1031+ return HttpRequestCallAsync ( requestUrl , debugMsgs , out errRecord ) ;
1032+ }
1033+
1034+ /// <summary>
1035+ /// Builds the FindPackagesById() request url for version-globbing searches.
1036+ /// </summary>
1037+ private string GetVersionGlobbingRequestUrl ( string packageName , VersionRange versionRange , bool includePrerelease , int skip , bool getOnlyLatest )
1038+ {
9151039 //https://www.powershellgallery.com/api/v2//FindPackagesById()?id='blah'&includePrerelease=false&$filter= NormalizedVersion gt '1.0.0' and NormalizedVersion lt '2.2.5' and substringof('PSModule', Tags) eq true
9161040 //https://www.powershellgallery.com/api/v2//FindPackagesById()?id='PowerShellGet'&includePrerelease=false&$filter= NormalizedVersion gt '1.1.1' and NormalizedVersion lt '2.2.5'
9171041 // NormalizedVersion doesn't include trailing zeroes
@@ -980,9 +1104,7 @@ private string FindVersionGlobbing(string packageName, VersionRange versionRange
9801104 // We need to explicitly add 'Id eq <packageName>' whenever $filter is used, otherwise arbitrary results are returned.
9811105 filterBuilder . AddCriterion ( $ "Id eq '{ packageName } '") ;
9821106
983- var requestUrl = $ "{ Repository . Uri } /FindPackagesById()?{ queryBuilder . BuildQueryString ( ) } ";
984-
985- return HttpRequestCall ( requestUrl , out errRecord ) ;
1107+ return $ "{ Repository . Uri } /FindPackagesById()?{ queryBuilder . BuildQueryString ( ) } ";
9861108 }
9871109
9881110 /// <summary>
@@ -1040,6 +1162,29 @@ private Stream InstallVersion(string packageName, string version, out ErrorRecor
10401162 return response . ReadAsStreamAsync ( ) . Result ;
10411163 }
10421164
1165+ /// <summary>
1166+ /// Worker-thread counterpart of InstallVersion(); enqueues diagnostics instead of writing to cmdlet streams.
1167+ /// </summary>
1168+ private Stream InstallVersionAsync ( string packageName , string version , ConcurrentQueue < string > debugMsgs , out ErrorRecord errRecord )
1169+ {
1170+ debugMsgs . Enqueue ( "In NuGetServerAPICalls::InstallVersionAsync()" ) ;
1171+ var requestUrl = $ "{ Repository . Uri } /Packages(Id='{ packageName } ',Version='{ version } ')/Download";
1172+ var response = HttpRequestCallForContentAsync ( requestUrl , debugMsgs , out errRecord ) ;
1173+
1174+ if ( response is null )
1175+ {
1176+ errRecord = new ErrorRecord (
1177+ new Exception ( $ "No content was returned by repository '{ Repository . Name } '") ,
1178+ "InstallFailureContentNullNuGetServer" ,
1179+ ErrorCategory . InvalidResult ,
1180+ this ) ;
1181+
1182+ return null ;
1183+ }
1184+
1185+ return response . ReadAsStreamAsync ( ) . Result ;
1186+ }
1187+
10431188 /// <summary>
10441189 /// Helper method that makes gets 'count' property from http response string.
10451190 /// The count property is used to determine the number of total results found (for pagination).
0 commit comments