| File: Remote\RemoteWalkContext.cs | Web Access |
| Project: src\nuget-client\src\NuGet.Core\NuGet.DependencyResolver.Core\NuGet.DependencyResolver.Core.csproj (NuGet.DependencyResolver.Core) |
// 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. using System; using System.Collections.Generic; using System.Threading.Tasks; using NuGet.Common; using NuGet.Configuration; using NuGet.LibraryModel; using NuGet.Protocol.Core.Types; namespace NuGet.DependencyResolver { public class RemoteWalkContext { public RemoteWalkContext(SourceCacheContext cacheContext, PackageSourceMapping packageSourceMapping, ILogger logger) { CacheContext = cacheContext ?? throw new ArgumentNullException(nameof(cacheContext)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); ProjectLibraryProviders = new List<IDependencyProvider>(); LocalLibraryProviders = new List<IRemoteDependencyProvider>(); RemoteLibraryProviders = new List<IRemoteDependencyProvider>(); PackageSourceMapping = packageSourceMapping ?? throw new ArgumentNullException(nameof(packageSourceMapping)); FindLibraryEntryCache = new TaskResultCache<LibraryRangeCacheKey, GraphItem<RemoteResolveResult>>(); ResolvePackageLibraryMatchCache = new TaskResultCache<LibraryRange, Tuple<LibraryRange, RemoteMatch>>(); LockFileLibraries = new Dictionary<LockFileCacheKey, IList<LibraryIdentity>>(); } public SourceCacheContext CacheContext { get; } public ILogger Logger { get; } public IList<IDependencyProvider> ProjectLibraryProviders { get; } public IList<IRemoteDependencyProvider> LocalLibraryProviders { get; } public IList<IRemoteDependencyProvider> RemoteLibraryProviders { get; } public PackageSourceMapping PackageSourceMapping { get; } /// <summary> /// Packages lock file libraries to be used while generating restore graph. /// </summary> public IDictionary<LockFileCacheKey, IList<LibraryIdentity>> LockFileLibraries { get; } /// <summary> /// Library entry cache. /// </summary> internal TaskResultCache<LibraryRangeCacheKey, GraphItem<RemoteResolveResult>> FindLibraryEntryCache { get; } internal TaskResultCache<LibraryRange, Tuple<LibraryRange, RemoteMatch>> ResolvePackageLibraryMatchCache { get; } /// <summary> /// True if this is a csproj or similar project. Xproj should be false. /// </summary> public bool IsMsBuildBased { get; set; } /// <summary> /// Applies source mapping pattern filtering for a given package /// </summary> /// <param name="libraryRange"></param> /// <returns>Returns a subset of sources when source mapping patterns are configured otherwise returns all the sources</returns> public IList<IRemoteDependencyProvider> FilterDependencyProvidersForLibrary(LibraryRange libraryRange) { if (libraryRange == default) throw new ArgumentNullException(nameof(libraryRange)); // filter package patterns if enabled if (PackageSourceMapping?.IsEnabled == true && libraryRange.TypeConstraintAllows(LibraryDependencyTarget.Package)) { IReadOnlyList<string> sources = PackageSourceMapping.GetConfiguredPackageSources(libraryRange.Name); if (sources.Count == 0) { return Array.Empty<IRemoteDependencyProvider>(); } // PERF: Avoid Linq in hot paths. var filteredLibraryProviders = new List<IRemoteDependencyProvider>(sources.Count); for (int i = 0; i < RemoteLibraryProviders.Count; ++i) { var current = RemoteLibraryProviders[i]; for (int j = 0; j < sources.Count; ++j) { if (StringComparer.OrdinalIgnoreCase.Equals(sources[j], current.Source.Name)) { filteredLibraryProviders.Add(current); break; } } } return filteredLibraryProviders; } return RemoteLibraryProviders; } /// <summary> /// Returns a list of unresolved remote matches. /// </summary> /// <remarks> /// The <see cref="FindLibraryEntryCache" /> is internal but the dependency resolver needs to know what packages were unresolved after walking the dependency graph. /// </remarks> /// <returns>A <see cref="HashSet{T}" /> containing the <see cref="RemoteMatch" /> objects representing unresolved packages.</returns> public async Task<HashSet<RemoteMatch>> GetUnresolvedRemoteMatchesAsync() { HashSet<RemoteMatch> packagesToInstall = new(); foreach (LibraryRangeCacheKey key in FindLibraryEntryCache.Keys.NoAllocEnumerate()) { if (!FindLibraryEntryCache.TryGetValue(key, out Task<GraphItem<RemoteResolveResult>>? task)) { continue; } GraphItem<RemoteResolveResult> item = await task; if (item.Key.Type == LibraryType.Unresolved || !RemoteLibraryProviders.Contains(item.Data.Match.Provider)) { continue; } packagesToInstall.Add(item.Data.Match); } return packagesToInstall; } } }