private static Dictionary<NuGetFramework, HashSet<NuGetFramework>> GetTable(IEnumerable<NuGetFramework> frameworks, IFrameworkNameProvider mappings, IFrameworkCompatibilityProvider compat) { // get the distinct set of frameworks, ignoring all special frameworks like Any, and Unsupported var input = new HashSet<NuGetFramework>(frameworks.Where(f => f.IsSpecificFramework), NuGetFramework.Comparer); var table = new Dictionary<NuGetFramework, HashSet<NuGetFramework>>(NuGetFramework.Comparer); foreach (var framework in input) { var compatFrameworks = new HashSet<NuGetFramework>(NuGetFramework.Comparer); table.Add(framework, compatFrameworks); foreach (var testFramework in input) { if (compat.IsCompatible(framework, testFramework)) { compatFrameworks.Add(testFramework); } } } return table; }
internal static bool IsCompatible( NetPortableProfileTable table, IFrameworkCompatibilityProvider compatibilityProvider, IFrameworkNameProvider nameProvider, FrameworkName projectFrameworkName, FrameworkName packageTargetFrameworkName) { if (projectFrameworkName == null) { return(true); } var projectNuGetFramework = GetNuGetFramework( table, nameProvider, projectFrameworkName); var packageTargetNuGetFramework = GetNuGetFramework( table, nameProvider, packageTargetFrameworkName); var isCompatible = compatibilityProvider.IsCompatible( projectNuGetFramework, packageTargetNuGetFramework); // Fallback to legacy portable compatibility logic if both: // a) the modern compatibility code returns false // b) the package framework is portable if (!isCompatible && packageTargetFrameworkName.IsPortableFramework()) { return(IsPortableLibraryCompatible(table, projectFrameworkName, packageTargetFrameworkName)); } return(isCompatible); }
private NuGetFramework GetNearestInternal(NuGetFramework framework, IEnumerable <NuGetFramework> possibleFrameworks) { NuGetFramework nearest = null; // Unsupported frameworks always lose, throw them out unless it's all we were given if (possibleFrameworks.Any(e => e != NuGetFramework.UnsupportedFramework)) { possibleFrameworks = possibleFrameworks.Where(e => e != NuGetFramework.UnsupportedFramework); } // Try exact matches first nearest = possibleFrameworks.Where(f => _fullComparer.Equals(framework, f)).FirstOrDefault(); if (nearest == null) { // Elimate non-compatible frameworks var compatible = possibleFrameworks.Where(f => _compat.IsCompatible(framework, f)); // Remove lower versions of compatible frameworks var reduced = ReduceUpwards(compatible); bool isNet6Era = framework.IsNet5Era && framework.Version.Major >= 6; // Reduce to the same framework name if possible, with an exception for Xamarin, MonoAndroid and Tizen when net6.0+ if (reduced.Count() > 1 && reduced.Any(f => _fwNameComparer.Equals(f, framework))) { reduced = reduced.Where(f => { if (isNet6Era && framework.HasPlatform && ( f.Framework.StartsWith("xamarin.", StringComparison.OrdinalIgnoreCase) || f.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.MonoAndroid, StringComparison.OrdinalIgnoreCase) || f.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.Tizen, StringComparison.OrdinalIgnoreCase) )) { return(true); } else { return(_fwNameComparer.Equals(f, framework)); } }); } // PCL reduce if (reduced.Count() > 1) { // if we have a pcl and non-pcl mix, throw out the pcls if (reduced.Any(f => f.IsPCL) && reduced.Any(f => !f.IsPCL)) { reduced = reduced.Where(f => !f.IsPCL); } else if (reduced.All(f => f.IsPCL)) { // decide between PCLs if (framework.IsPCL) { reduced = GetNearestPCLtoPCL(framework, reduced); } else { reduced = GetNearestNonPCLtoPCL(framework, reduced); } if (reduced.Count() > 1) { // For scenarios where we are unable to decide between PCLs, choose the PCL with the // least frameworks. Less frameworks means less compatibility which means it is nearer to the target. reduced = new NuGetFramework[] { GetBestPCL(reduced) }; } } } // Packages based framework reduce, only if the project is not packages based if (reduced.Count() > 1 && !framework.IsPackageBased && reduced.Any(f => f.IsPackageBased) && reduced.Any(f => !f.IsPackageBased)) { // If we have a packages based and non-packages based mix, throw out the packages based frameworks. // This situation is unlikely but it could happen with framework mappings that do not provide // a relationship between the frameworks and the compatible packages based frameworks. // Ex: net46, dotnet -> net46 reduced = reduced.Where(f => !f.IsPackageBased); } // Profile reduce if (reduced.Count() > 1 && !reduced.Any(f => f.IsPCL)) { // Prefer the same framework and profile if (framework.HasProfile) { var sameProfile = reduced.Where(f => _fwNameComparer.Equals(framework, f) && StringComparer.OrdinalIgnoreCase.Equals(framework.Profile, f.Profile)); if (sameProfile.Any()) { reduced = sameProfile; } } // Prefer frameworks without profiles if (reduced.Count() > 1 && reduced.Any(f => f.HasProfile) && reduced.Any(f => !f.HasProfile)) { reduced = reduced.Where(f => !f.HasProfile); } } // Platforms reduce if (reduced.Count() > 1 && framework.HasPlatform) { if (!isNet6Era || reduced.Any(f => _fwNameComparer.Equals(framework, f) && f.Version.Major >= 6)) { // Prefer the highest framework version, likely to be the non-platform specific option. reduced = reduced.Where(f => _fwNameComparer.Equals(framework, f)).GroupBy(f => f.Version).OrderByDescending(f => f.Key).First(); } else if (isNet6Era && reduced.Any(f => { return(f.Framework.StartsWith("xamarin.", StringComparison.OrdinalIgnoreCase) || f.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.MonoAndroid, StringComparison.OrdinalIgnoreCase) || f.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.Tizen, StringComparison.OrdinalIgnoreCase)); })) { // We have a special case for *some* Xamarin-related frameworks here. For specific precedence rules, please see: // https://github.com/dotnet/designs/blob/main/accepted/2021/net6.0-tfms/net6.0-tfms.md#compatibility-rules reduced = reduced.GroupBy(f => f.Framework).OrderByDescending(f => f.Key).First(f => { NuGetFramework first = f.First(); return(first.Framework.StartsWith("xamarin.", StringComparison.OrdinalIgnoreCase) || first.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.MonoAndroid, StringComparison.OrdinalIgnoreCase) || first.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.Tizen, StringComparison.OrdinalIgnoreCase)); }); } } // if we have reduced down to a single framework, use that if (reduced.Count() == 1) { nearest = reduced.Single(); } // this should be a very rare occurrence // at this point we are unable to decide between the remaining frameworks in any useful way // just take the first one by rev alphabetical order if we can't narrow it down at all if (nearest == null && reduced.Any()) { // Sort by precedence rules, then by name in the case of a tie nearest = reduced .OrderBy(f => f, new FrameworkPrecedenceSorter(_mappings, false)) .ThenByDescending(f => f, new NuGetFrameworkSorter()) .ThenBy(f => f.GetHashCode()) .First(); } } return(nearest); }
/// <summary> /// Returns the nearest matching framework that is compatible. /// </summary> /// <param name="framework">Project target framework</param> /// <param name="possibleFrameworks">Possible frameworks to narrow down</param> /// <returns>Nearest compatible framework. If no frameworks are compatible null is returned.</returns> public NuGetFramework GetNearest(NuGetFramework framework, IEnumerable <NuGetFramework> possibleFrameworks) { NuGetFramework nearest = null; // Unsupported frameworks always lose, throw them out unless it's all we were given if (possibleFrameworks.Any(e => e != NuGetFramework.UnsupportedFramework)) { possibleFrameworks = possibleFrameworks.Where(e => e != NuGetFramework.UnsupportedFramework); } // Try exact matches first nearest = possibleFrameworks.Where(f => _fullComparer.Equals(framework, f)).FirstOrDefault(); if (nearest == null) { // Elimate non-compatible frameworks var compatible = possibleFrameworks.Where(f => _compat.IsCompatible(framework, f)); // Remove lower versions of compatible frameworks var reduced = ReduceUpwards(compatible); // Reduce to the same framework name if possible if (reduced.Count() > 1 && reduced.Any(f => _fwNameComparer.Equals(f, framework))) { reduced = reduced.Where(f => _fwNameComparer.Equals(f, framework)); } // PCL reduce if (reduced.Count() > 1) { // if we have a pcl and non-pcl mix, throw out the pcls if (reduced.Any(f => f.IsPCL) && reduced.Any(f => !f.IsPCL)) { reduced = reduced.Where(f => !f.IsPCL); } else if (reduced.All(f => f.IsPCL)) { // decide between PCLs if (framework.IsPCL) { reduced = GetNearestPCLtoPCL(framework, reduced); } else { reduced = GetNearestNonPCLtoPCL(framework, reduced); } if (reduced.Count() > 1) { // For scenarios where we are unable to decide between PCLs, choose the PCL with the // least frameworks. Less frameworks means less compatibility which means it is nearer to the target. reduced = new NuGetFramework[] { GetBestPCL(reduced) }; } } } // Profile reduce if (reduced.Count() > 1 && !reduced.Any(f => f.IsPCL)) { // Prefer the same framework and profile if (framework.HasProfile) { var sameProfile = reduced.Where(f => _fwNameComparer.Equals(framework, f) && StringComparer.OrdinalIgnoreCase.Equals(framework.Profile, f.Profile)); if (sameProfile.Any()) { reduced = sameProfile; } } // Prefer frameworks without profiles if (reduced.Count() > 1 && reduced.Any(f => f.HasProfile) && reduced.Any(f => !f.HasProfile)) { reduced = reduced.Where(f => !f.HasProfile); } } // if we have reduced down to a single framework, use that if (reduced.Count() == 1) { nearest = reduced.Single(); } // this should be a very rare occurrence // at this point we are unable to decide between the remaining frameworks in any useful way // just take the first one by rev alphabetical order if we can't narrow it down at all if (nearest == null && reduced.Any()) { // Sort by precedence rules, then by name in the case of a tie nearest = reduced.OrderBy(f => f, new FrameworkPrecedenceSorter(_mappings)) .ThenByDescending(f => f, new NuGetFrameworkSorter()) .ThenBy(f => f.GetHashCode()) .First(); } } return(nearest); }
/// <summary> /// Возвращает список совместимых элементов. /// </summary> /// <param name="reader">Интерфейс для чтения метаданных пакета.</param> /// <param name="items">Список элементов для выборки.</param> /// <param name="targetFramework">Версия совместимого фреймворка.</param> /// <param name="compatibilityProvider">Провайдер для проверки совместимости фреймворков.</param> private static FrameworkSpecificGroup GetCompatibleItems(PackageReaderBase reader, IList<FrameworkSpecificGroup> items, NuGetFramework targetFramework, IFrameworkCompatibilityProvider compatibilityProvider) { // Из пакета выбираются файлы с TargetFramework, который // является наиболее новым и совместимым с указанным var compatibleItems = items .OrderByDescending(i => i.TargetFramework, NuGetFrameworkComparer) .FirstOrDefault(i => NuGetFrameworkComparer.Compare(i.TargetFramework, targetFramework) <= 0 && compatibilityProvider.IsCompatible(targetFramework, i.TargetFramework)); if (compatibleItems == null) { var portableFramework = reader.GetSupportedFrameworks().FirstOrDefault(i => string.Equals(i.Framework, ".NETPortable", StringComparison.OrdinalIgnoreCase)); if (portableFramework != null && compatibilityProvider.IsCompatible(targetFramework, portableFramework)) { compatibleItems = items.FirstOrDefault(i => NuGetFrameworkComparer.Compare(i.TargetFramework, portableFramework) == 0); } } return compatibleItems; }
public bool IsCompatible(Framework project, Framework package) { return(_compatibilityProvider.IsCompatible( project.NuGetFramework, package.NuGetFramework)); }
/// <summary> /// Returns the nearest matching framework that is compatible. /// </summary> /// <param name="framework">Project target framework</param> /// <param name="possibleFrameworks">Possible frameworks to narrow down</param> /// <returns>Nearest compatible framework. If no frameworks are compatible null is returned.</returns> public NuGetFramework GetNearest(NuGetFramework framework, IEnumerable <NuGetFramework> possibleFrameworks) { NuGetFramework nearest = null; // Unsupported frameworks always lose, throw them out unless it's all we were given if (possibleFrameworks.Any(e => e != NuGetFramework.UnsupportedFramework)) { possibleFrameworks = possibleFrameworks.Where(e => e != NuGetFramework.UnsupportedFramework); } // Try exact matches first nearest = possibleFrameworks.Where(f => _fullComparer.Equals(framework, f)).FirstOrDefault(); if (nearest == null) { // Elimate non-compatible frameworks IEnumerable <NuGetFramework> compatible = possibleFrameworks.Where(f => _compat.IsCompatible(framework, f)); // Remove lower versions of compatible frameworks IEnumerable <NuGetFramework> reduced = ReduceUpwards(compatible); // Reduce to the same framework name if possible if (reduced.Count() > 1 && reduced.Any(f => _fwNameComparer.Equals(f, framework))) { reduced = reduced.Where(f => _fwNameComparer.Equals(f, framework)); } // PCL reduce if (reduced.Count() > 1) { // if we have a pcl and non-pcl mix, throw out the pcls if (reduced.Any(f => f.IsPCL) && reduced.Any(f => !f.IsPCL)) { reduced = reduced.Where(f => !f.IsPCL); } else if (reduced.All(f => f.IsPCL)) { // decide between PCLs if (framework.IsPCL) { reduced = GetNearestPCLtoPCL(framework, reduced); } else { reduced = GetNearestNonPCLtoPCL(framework, reduced); } if (reduced.Count() > 1) { // For scenarios where we are unable to decide between PCLs, choose the PCL with the // least frameworks. Less frameworks means less compatibility which means it is nearer to the target. reduced = OrderPCL(reduced).Take(1); } } } // Profile reduce if (reduced.Count() > 1 && !reduced.Any(f => f.IsPCL)) { // Prefer frameworks without profiles // TODO: should we try to match against the profile of the input framework? if (reduced.Any(f => f.HasProfile) && reduced.Any(f => !f.HasProfile)) { reduced = reduced.Where(f => !f.HasProfile); } } Debug.Assert(reduced.Count() < 2, "Unable to find the nearest framework: " + String.Join(", ", reduced)); // if we have reduced down to a single framework, use that if (reduced.Count() == 1) { nearest = reduced.Single(); } // this should be a very rare occurrence // at this point we are unable to decide between the remaining frameworks in any useful way // just take the first one by rev alphabetical order if we can't narrow it down at all if (nearest != null && reduced.Any()) { nearest = reduced.OrderByDescending(f => f.Framework, StringComparer.OrdinalIgnoreCase).ThenBy(f => f.GetHashCode()).First(); } } return(nearest); }