| File: Utility\AddPackageCommandUtility.cs | Web Access |
| Project: 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.Commands; 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="ignoreMinPublishAge">Whether to ignore the minimum publish age configured on package sources</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, bool ignoreMinPublishAge, 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, ignoreMinPublishAge, 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="ignoreMinPublishAge">Whether to ignore the minimum publish age configured on the package source</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, bool ignoreMinPublishAge, 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 ); if (!ignoreMinPublishAge && source.MinPublishAge > TimeSpan.Zero && packages != null) { var packagesWithPublishDates = packages.ToList(); IPackageSearchMetadata packageWithoutPublishDate = packagesWithPublishDates.FirstOrDefault(package => package.Published == null); if (packageWithoutPublishDate != null) { throw new CommandException(Messages.Error_PackagePublishDateMissing( source.Name, packageId, packageWithoutPublishDate.Identity.Version.ToNormalizedString())); } DateTimeOffset publishCutoff = DateTimeOffset.UtcNow - source.MinPublishAge; packages = packagesWithPublishDates.Where(package => package.Published <= publishCutoff); } return packages?.Max(package => package.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); return EvaluateSources(requestedSources, settings); } } /// <summary> /// Returns package sources with their configured settings, including credentials and minimum publish age. /// </summary> /// <param name="requestedSources">Sources to match</param> /// <param name="settings">Settings containing the source configuration</param> /// <returns>Return a list of configured package sources</returns> public static List<PackageSource> EvaluateSources(IList<PackageSource> requestedSources, ISettings settings) { 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; } } }