File: Utility\AddPackageCommandUtility.cs
Web Access
Project: src\src\nuget-client\src\NuGet.Core\NuGet.CommandLine.XPlat\NuGet.CommandLine.XPlat.csproj (NuGet.CommandLine.XPlat)
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#nullable disable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NuGet.Common;
using NuGet.Configuration;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;

namespace NuGet.CommandLine.XPlat.Utility
{
    internal static class AddPackageCommandUtility
    {
        /// <summary>
        /// Return the latest version available in the sources
        /// </summary>
        /// <param name="sources">Sources to look at</param>
        /// <param name="logger">Logger</param>
        /// <param name="packageId">Package to look for</param>
        /// <param name="prerelease">Whether to include prerelease versions</param>
        /// <param name="cancellationToken"></param>
        /// <returns>Return the latest version available from multiple sources and if no version is found returns null.</returns>

        public static async Task<NuGetVersion> GetLatestVersionFromSourcesAsync(IList<PackageSource> sources, ILogger logger, string packageId, bool prerelease, CancellationToken cancellationToken)
        {
            var maxTasks = Environment.ProcessorCount;
            var tasks = new List<Task<NuGetVersion>>();
            var latestReleaseList = new List<NuGetVersion>();

            foreach (var source in sources)
            {
                tasks.Add(Task.Run(() => GetLatestVersionFromSourceAsync(source, logger, packageId, prerelease, cancellationToken)));
                if (maxTasks <= tasks.Count)
                {
                    var finishedTask = await Task.WhenAny(tasks);
                    tasks.Remove(finishedTask);
                    latestReleaseList.Add(await finishedTask);
                }
            }

            await Task.WhenAll(tasks);

            foreach (var t in tasks)
            {
                var result = await t;
                if (result != null)
                {
                    latestReleaseList.Add(result);
                }
            }

            return latestReleaseList.Max();
        }

        /// <summary>
        /// Return the latest version of the source
        /// </summary>
        /// <param name="source">Source to look at</param>
        /// <param name="logger">Logger</param>
        /// <param name="packageId">Package to look for</param>
        /// <param name="prerelease">Whether to include prerelease versions</param>
        /// <param name="cancellationToken"></param>
        /// <returns>Returns the latest version available from a source or a null if non is found.</returns>
        public static async Task<NuGetVersion> GetLatestVersionFromSourceAsync(PackageSource source, ILogger logger, string packageId, bool prerelease, CancellationToken cancellationToken)
        {
            SourceRepository repository = Repository.Factory.GetCoreV3(source);
            PackageMetadataResource resource = await repository.GetResourceAsync<PackageMetadataResource>(cancellationToken);

            using (var cache = new SourceCacheContext())
            {
                IEnumerable<IPackageSearchMetadata> packages = await resource.GetMetadataAsync(
                    packageId,
                    includePrerelease: prerelease,
                    includeUnlisted: false,
                    cache,
                    logger,
                    CancellationToken.None
                );

                return packages?.Max(x => x.Identity.Version);
            }
        }

        /// <summary>
        /// Returns the PackageSource with its credentials if available
        /// </summary>
        /// <param name="requestedSources">Sources to match</param>
        /// <param name="configFilePaths">Config to use for credentials</param>
        /// <returns>Return a list of package sources</returns>
        public static List<PackageSource> EvaluateSources(IList<PackageSource> requestedSources, IList<string> configFilePaths)
        {
            using (var settingsLoadingContext = new SettingsLoadingContext())
            {
                ISettings settings = Settings.LoadImmutableSettingsGivenConfigPaths(configFilePaths, settingsLoadingContext);
                var packageSources = new List<PackageSource>();

                var packageSourceProvider = new PackageSourceProvider(settings);
                IEnumerable<PackageSource> packageProviderSources = packageSourceProvider.LoadPackageSources();

                for (int i = 0; i < requestedSources.Count; i++)
                {
                    PackageSource matchedSource = packageProviderSources.FirstOrDefault(e => e.Source == requestedSources[i].Source);
                    if (matchedSource == null)
                    {
                        packageSources.Add(requestedSources[i]);
                    }
                    else
                    {
                        packageSources.Add(matchedSource);
                    }
                }

                return packageSources;
            }
        }
    }
}