async Task <IEnumerable <IPackageSearchMetadata> > GetPackagesWithUpdatesAsync(string searchText, SearchFilter searchFilter, CancellationToken cancellationToken) { if (_context != null) { _installedPackages = await _context.GetInstalledPackagesAsync(); _context = null; } var packages = _installedPackages .GetEarliest() .Where(p => p.Id.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1) .OrderBy(p => p.Id); var latestItems = await TaskCombinators.ThrottledAsync( packages, (p, t) => _metadataProvider.GetLatestPackageMetadataAsync(p, searchFilter.IncludePrerelease, t), cancellationToken); var packagesWithUpdates = packages .Join(latestItems.Where(i => i != null), p => p.Id, m => m.Identity.Id, (p, m) => new { cv = p.Version, m = m }, StringComparer.OrdinalIgnoreCase) .Where(j => VersionComparer.VersionRelease.Compare(j.cv, j.m.Identity.Version) < 0) .Select(j => j.m); return(packagesWithUpdates); }
public override async Task <SearchResult <IPackageSearchMetadata> > ContinueSearchAsync(ContinuationToken continuationToken, CancellationToken cancellationToken) { var searchToken = continuationToken as FeedSearchContinuationToken; if (searchToken == null) { throw new InvalidOperationException("Invalid token"); } var packagesNeedingConsolidation = _installedPackages .GroupById() .Where(g => g.Count() > 1) .Select(g => new PackageIdentity(g.Key, g.Max())) .ToArray(); var packages = packagesNeedingConsolidation .Where(p => p.Id.IndexOf(searchToken.SearchString, StringComparison.OrdinalIgnoreCase) != -1) .OrderBy(p => p.Id) .Skip(searchToken.StartIndex) .Take(PageSize + 1) .ToArray(); var hasMoreItems = packages.Length > PageSize; if (hasMoreItems) { packages = packages.Take(packages.Length - 1).ToArray(); } var items = await TaskCombinators.ThrottledAsync( packages, (p, t) => _metadataProvider.GetPackageMetadataAsync(p, searchToken.SearchFilter.IncludePrerelease, t), cancellationToken); var result = SearchResult.FromItems(items.ToArray()); var loadingStatus = hasMoreItems ? LoadingStatus.Ready : packages.Length == 0 ? LoadingStatus.NoItemsFound : LoadingStatus.NoMoreItems; result.SourceSearchStatus = new Dictionary <string, LoadingStatus> { { "Consolidate", loadingStatus } }; if (hasMoreItems) { result.NextToken = new FeedSearchContinuationToken { SearchString = searchToken.SearchString, SearchFilter = searchToken.SearchFilter, StartIndex = searchToken.StartIndex + packages.Length }; } return(result); }
public override async Task <SearchResult <IPackageSearchMetadata> > ContinueSearchAsync(ContinuationToken continuationToken, CancellationToken cancellationToken) { var searchToken = continuationToken as FeedSearchContinuationToken; if (searchToken == null) { throw new InvalidOperationException("Invalid token"); } var packages = _installedPackages .GetLatest() .Where(p => p.Id.IndexOf(searchToken.SearchString, StringComparison.OrdinalIgnoreCase) != -1) .OrderBy(p => p.Id) .Skip(searchToken.StartIndex) .Take(PageSize + 1) .ToArray(); var hasMoreItems = packages.Length > PageSize; if (hasMoreItems) { packages = packages.Take(packages.Length - 1).ToArray(); } var items = await TaskCombinators.ThrottledAsync( packages, (p, t) => GetPackageMetadataAsync(p, searchToken.SearchFilter.IncludePrerelease, t), cancellationToken); // The packages were originally sorted which is important because we Skip and Take based on that sort // however the asynchronous execution has randomly reordered the set. So we need to resort. var result = SearchResult.FromItems(items.OrderBy(p => p.Identity.Id).ToArray()); var loadingStatus = hasMoreItems ? LoadingStatus.Ready : packages.Length == 0 ? LoadingStatus.NoItemsFound : LoadingStatus.NoMoreItems; result.SourceSearchStatus = new Dictionary <string, LoadingStatus> { { "Installed", loadingStatus } }; if (hasMoreItems) { result.NextToken = new FeedSearchContinuationToken { SearchString = searchToken.SearchString, SearchFilter = searchToken.SearchFilter, StartIndex = searchToken.StartIndex + packages.Length }; } return(result); }
/// <summary> /// Get the package metadata to see if RequireLicenseAcceptance is true /// </summary> private async Task <List <IPackageSearchMetadata> > GetPackageMetadataAsync( IEnumerable <SourceRepository> sources, IEnumerable <PackageIdentity> packages, CancellationToken token) { var results = new List <IPackageSearchMetadata>(); // local sources var localSources = new List <SourceRepository>(); localSources.Add(_packageManager.PackagesFolderSourceRepository); localSources.AddRange(_packageManager.GlobalPackageFolderRepositories); var allPackages = packages.ToArray(); using (var sourceCacheContext = new SourceCacheContext()) { // first check all the packages with local sources. var completed = (await TaskCombinators.ThrottledAsync( allPackages, (p, t) => GetPackageMetadataAsync(localSources, sourceCacheContext, p, t), token)).Where(metadata => metadata != null).ToArray(); results.AddRange(completed); if (completed.Length != allPackages.Length) { // get remaining package's metadata from remote repositories var remainingPackages = allPackages.Where(package => !completed.Any(pack => pack.Identity.Equals(package))); var remoteResults = (await TaskCombinators.ThrottledAsync( remainingPackages, (p, t) => GetPackageMetadataAsync(sources, sourceCacheContext, p, t), token)).Where(metadata => metadata != null).ToArray(); results.AddRange(remoteResults); } } // check if missing metadata for any package if (allPackages.Length != results.Count) { var package = allPackages.First(pkg => !results.Any(result => result.Identity.Equals(pkg))); throw new InvalidOperationException( string.Format("Unable to find metadata of {0}", package)); } return(results); }
public async Task <IEnumerable <IPackageSearchMetadata> > GetPackagesWithUpdatesAsync(string searchText, SearchFilter searchFilter, CancellationToken cancellationToken) { var packages = _installedPackages .Where(p => !p.IsAutoReferenced()) .GetEarliest() .Where(p => p.Id.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1) .OrderBy(p => p.Id); // Prefetch metadata for all installed packages var prefetch = await TaskCombinators.ThrottledAsync( packages, (p, t) => _metadataProvider.GetPackageMetadataListAsync(p.Id, searchFilter.IncludePrerelease, includeUnlisted: false, cancellationToken: t), cancellationToken); // Flatten the result list var prefetchedPackages = prefetch .Where(p => p != null) .SelectMany(p => p) .ToArray(); // Traverse all projects and determine packages with updates var packagesWithUpdates = new List <IPackageSearchMetadata>(); foreach (var project in _projects) { var installed = await project.GetInstalledPackagesAsync(cancellationToken); foreach (var installedPackage in installed) { var installedVersion = installedPackage.PackageIdentity.Version; var allowedVersions = installedPackage.AllowedVersions ?? VersionRange.All; // filter packages based on current package identity var allPackages = prefetchedPackages .Where(p => StringComparer.OrdinalIgnoreCase.Equals( p.Identity.Id, installedPackage.PackageIdentity.Id)) .ToArray(); // and allowed versions var allowedPackages = allPackages .Where(p => allowedVersions.Satisfies(p.Identity.Version)); // peek the highest available var highest = allowedPackages .OrderByDescending(e => e.Identity.Version, VersionComparer.VersionRelease) .FirstOrDefault(); if (highest != null && VersionComparer.VersionRelease.Compare(installedVersion, highest.Identity.Version) < 0) { packagesWithUpdates.Add(highest.WithVersions(ToVersionInfo(allPackages))); } } } // select the earliest package update candidates var uniquePackageIds = packagesWithUpdates .Select(p => p.Identity) .GetEarliest(); // get unique list of package metadata as similar updates may come from different projects var uniquePackages = uniquePackageIds .GroupJoin( packagesWithUpdates, id => id, p => p.Identity, (id, pl) => pl.First()); return(uniquePackages.ToArray()); }