Skip to content

Commit 6696507

Browse files
committed
Refactoring of inner workings of NuGetSearchService.
- Split one big method into multiple smaller. - Simplify conditions for continuing search on next page. - Fix loading single package (method FindLatestVersionAsync) when local filtering applies.
1 parent 16be307 commit 6696507

File tree

1 file changed

+92
-70
lines changed

1 file changed

+92
-70
lines changed

src/PackageManager.NuGet/Services/NuGetSearchService.cs

Lines changed: 92 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using NuGet.Common;
1111
using NuGet.Protocol;
1212
using NuGet.Protocol.Core.Types;
13-
using NuGet.Versioning;
1413
using PackageManager.Logging;
1514
using PackageManager.Models;
1615

@@ -61,29 +60,11 @@ private SearchOptions EnsureOptions(SearchOptions options)
6160
return options;
6261
}
6362

64-
private Task<IEnumerable<IPackageSearchMetadata>> SearchAsync(PackageSearchResource search, string searchText, SearchOptions options, CancellationToken cancellationToken)
65-
=> search.SearchAsync(searchText, new SearchFilter(options.IsPrereleaseIncluded), options.PageIndex * options.PageSize, options.PageSize, nuGetLog, cancellationToken);
66-
6763
public async Task<IEnumerable<IPackage>> SearchAsync(IEnumerable<IPackageSource> packageSources, string searchText, SearchOptions options = default, CancellationToken cancellationToken = default)
6864
{
69-
NuGetSearchTerm term = new NuGetSearchTerm();
70-
term.Id.Add(searchText);
65+
var (feedTerm, localTerm) = PrepareSearchTerms(searchText);
7166

72-
queryTransformer.Transform(term);
73-
term.Id.Remove(searchText);
74-
75-
NuGetSearchTerm lateTerm = null;
76-
if (term.IsEmpty())
77-
{
78-
term.Id.Add(searchText);
79-
}
80-
else
81-
{
82-
lateTerm = term.Clone();
83-
lateTerm.Id.Add(searchText);
84-
}
85-
86-
log.Debug($"Searching - user text:'{searchText}'; target query:'{term}'.");
67+
log.Debug($"Searching - user text:'{searchText}'; feed query:'{feedTerm}'.");
8768

8869
options = EnsureOptions(options);
8970

@@ -96,7 +77,6 @@ public async Task<IEnumerable<IPackage>> SearchAsync(IEnumerable<IPackageSource>
9677
{
9778
log.Debug($"Loading page '{options.PageIndex}'.");
9879

99-
bool hasItems = false;
10080
foreach (IPackageSource packageSource in sources)
10181
{
10282
log.Debug($"Searching in '{packageSource.Uri}'.");
@@ -106,60 +86,15 @@ public async Task<IEnumerable<IPackage>> SearchAsync(IEnumerable<IPackageSource>
10686
if (search == null)
10787
{
10888
log.Debug($"Source skipped, because it doesn't provide '{nameof(PackageSearchResource)}'.");
109-
continue;
110-
}
111-
112-
NuGetSearchTerm localTerm = null;
113-
bool clearLateTerm = false;
114-
if (search is LocalPackageSearchResource)
115-
{
116-
// Searching a feed from folder.
117-
localTerm = term;
118-
term = new NuGetSearchTerm();
119-
120-
if (lateTerm == null)
121-
{
122-
lateTerm = localTerm;
123-
clearLateTerm = true;
124-
}
125-
}
126-
127-
int sourceSearchPackageCount = 0;
128-
foreach (IPackageSearchMetadata package in await SearchAsync(search, term.ToString(), options, cancellationToken))
129-
{
130-
log.Debug($"Found '{package.Identity}'.");
13189

132-
hasItems = true;
133-
if (result.Count >= options.PageSize)
134-
break;
135-
136-
if (lateTerm != null && !lateTerm.IsMatched(package))
137-
{
138-
log.Debug($"Package skipped by late search term '{lateTerm}'.");
139-
continue;
140-
}
141-
142-
await AddPackageAsync(result, repository, package, options.IsPrereleaseIncluded, cancellationToken);
143-
sourceSearchPackageCount++;
90+
sourcesToSkip.Add(packageSource);
91+
continue;
14492
}
14593

146-
// If package source reached end, skip it from next probing.
147-
if (sourceSearchPackageCount < options.PageSize)
94+
if (!await ApplyLocalResourceSearchAsync(result, repository, search, feedTerm, localTerm, options, cancellationToken))
14895
sourcesToSkip.Add(packageSource);
149-
150-
if (localTerm != null)
151-
{
152-
term = localTerm;
153-
localTerm = null;
154-
155-
if (clearLateTerm)
156-
lateTerm = null;
157-
}
15896
}
15997

160-
if (!hasItems)
161-
break;
162-
16398
options = new SearchOptions()
16499
{
165100
PageIndex = options.PageIndex + 1,
@@ -168,12 +103,99 @@ public async Task<IEnumerable<IPackage>> SearchAsync(IEnumerable<IPackageSource>
168103

169104
foreach (IPackageSource source in sourcesToSkip)
170105
sources.Remove(source);
106+
107+
if (sources.Count == 0)
108+
break;
171109
}
172110

173111
log.Debug($"Search completed. Found '{result.Count}' items.");
174112
return result;
175113
}
176114

115+
/// <summary>
116+
/// Prepares instance of terms for filtering in feed and in-app.
117+
/// </summary>
118+
/// <remarks>
119+
/// localTerm should always have all search terms.
120+
/// </remarks>
121+
private (NuGetSearchTerm feedTerm, NuGetSearchTerm localTerm) PrepareSearchTerms(string searchText)
122+
{
123+
NuGetSearchTerm feedTerm = new NuGetSearchTerm();
124+
feedTerm.Id.Add(searchText);
125+
126+
queryTransformer.Transform(feedTerm);
127+
feedTerm.Id.Remove(searchText);
128+
129+
NuGetSearchTerm localTerm = null;
130+
if (feedTerm.IsEmpty())
131+
{
132+
feedTerm.Id.Add(searchText);
133+
}
134+
else
135+
{
136+
localTerm = feedTerm.Clone();
137+
localTerm.Id.Add(searchText);
138+
}
139+
140+
return (feedTerm, localTerm);
141+
}
142+
143+
/// <summary>
144+
/// Tries to apply special conditions for looking in local folder feed.
145+
/// </summary>
146+
/// <returns><c>true</c> if search reached the end of the feed; <c>false</c> otherwise.</returns>
147+
private Task<bool> ApplyLocalResourceSearchAsync(List<IPackage> result, SourceRepository repository, PackageSearchResource search, NuGetSearchTerm feedTerm, NuGetSearchTerm localTerm, SearchOptions options, CancellationToken cancellationToken)
148+
{
149+
if (search is LocalPackageSearchResource)
150+
{
151+
// Searching a feed from folder. Look for all packages and then filter in-app.
152+
if (localTerm == null)
153+
localTerm = feedTerm;
154+
155+
feedTerm = new NuGetSearchTerm();
156+
}
157+
158+
return ApplySearchAsync(result, repository, search, feedTerm, localTerm, options, cancellationToken);
159+
}
160+
161+
/// <summary>
162+
/// Execute search on <paramref name="search"/>.
163+
/// </summary>
164+
/// <returns><c>true</c> if search reached the end of the feed; <c>false</c> otherwise.</returns>
165+
private async Task<bool> ApplySearchAsync(List<IPackage> result, SourceRepository repository, PackageSearchResource search, NuGetSearchTerm feedTerm, NuGetSearchTerm localTerm, SearchOptions options, CancellationToken cancellationToken)
166+
{
167+
if (localTerm != null && options.PageSize == 1)
168+
options.PageSize = 10;
169+
170+
int sourceSearchPackageCount = 0;
171+
foreach (IPackageSearchMetadata package in await SearchAsync(search, feedTerm.ToString(), options, cancellationToken))
172+
{
173+
sourceSearchPackageCount++;
174+
175+
log.Debug($"Found '{package.Identity}'.");
176+
177+
if (result.Count >= options.PageSize)
178+
break;
179+
180+
if (localTerm != null && !localTerm.IsMatched(package))
181+
{
182+
log.Debug($"Package skipped by late search term '{localTerm}'.");
183+
continue;
184+
}
185+
186+
await AddPackageAsync(result, repository, package, options.IsPrereleaseIncluded, cancellationToken);
187+
}
188+
189+
// If package source reached end, skip it from next probing.
190+
if (sourceSearchPackageCount < options.PageSize)
191+
return false;
192+
193+
return true;
194+
}
195+
196+
private Task<IEnumerable<IPackageSearchMetadata>> SearchAsync(PackageSearchResource search, string searchText, SearchOptions options, CancellationToken cancellationToken)
197+
=> search.SearchAsync(searchText, new SearchFilter(options.IsPrereleaseIncluded), options.PageIndex * options.PageSize, options.PageSize, nuGetLog, cancellationToken);
198+
177199
private async Task AddPackageAsync(List<IPackage> result, SourceRepository repository, IPackageSearchMetadata package, bool isPrereleaseIncluded, CancellationToken cancellationToken)
178200
{
179201
NuGetPackageFilterResult filterResult = await filter.IsPassedAsync(repository, package, cancellationToken);

0 commit comments

Comments
 (0)