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);
        }
        public async Task <SearchResult <IPackageSearchMetadata> > SearchAsync(string searchText, SearchFilter filter, CancellationToken cancellationToken)
        {
            var searchTasks = TaskCombinators.ObserveErrorsAsync(
                _sourceRepositories,
                r => r.PackageSource.Name,
                (r, t) => r.SearchAsync(searchText, filter, PageSize, t),
                LogError,
                cancellationToken);

            return(await WaitForCompletionOrBailOutAsync(searchText, searchTasks, cancellationToken));
        }
        /// <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 <SearchResult <IPackageSearchMetadata> > ContinueSearchAsync(ContinuationToken continuationToken, CancellationToken cancellationToken)
        {
            var searchToken = continuationToken as AggregatedContinuationToken;

            if (searchToken?.SourceSearchCursors == null)
            {
                throw new InvalidOperationException("Invalid token");
            }

            var searchTokens = _sourceRepositories
                               .Join(searchToken.SourceSearchCursors,
                                     r => r.PackageSource.Name,
                                     c => c.Key,
                                     (r, c) => new { Repository = r, NextToken = c.Value });

            var searchTasks = TaskCombinators.ObserveErrorsAsync(
                searchTokens,
                j => j.Repository.PackageSource.Name,
                (j, t) => j.Repository.SearchAsync(j.NextToken, PageSize, t),
                LogError,
                cancellationToken);

            return(await WaitForCompletionOrBailOutAsync(searchToken.SearchString, searchTasks, cancellationToken));
        }
Exemple #7
0
        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());
        }