public void VersionRangeSet_CombineTwoRanges(string expected, string rangeA, string rangeB) { // Arrange var a = VersionRange.Parse(rangeA); var b = VersionRange.Parse(rangeB); // Act var ranges = new List <VersionRange>() { a, b }; var combined = VersionRange.Combine(ranges); var rangesRev = new List <VersionRange>() { b, a }; var combinedRev = VersionRange.Combine(rangesRev); // Assert Assert.Equal(expected, combined.ToNormalizedString()); // Verify the order has no effect Assert.Equal(expected, combinedRev.ToNormalizedString()); }
public void VersionRangeSet_CombineEmptyRangeList() { // Arrange var ranges = new List <VersionRange>() { }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal(VersionRange.None.ToNormalizedString(), combined.ToNormalizedString()); }
public void VersionRangeSet_SpecialCaseRangeCombine_NonePlusOne() { // Arrange var ranges = new List <VersionRange>() { VersionRange.None, VersionRange.Parse("[1.0.0]") }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal("[1.0.0, 1.0.0]", combined.ToNormalizedString()); }
public void VersionRangeSet_SpecialCaseRangeCombine_NoneAll() { // Arrange var ranges = new List <VersionRange>() { VersionRange.None, VersionRange.All }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal(VersionRange.All.ToNormalizedString(), combined.ToNormalizedString()); }
public void VersionRangeSet_CombineSingleRangeList() { // Arrange var a = VersionRange.Parse("[1.0.0, )"); var ranges = new List <VersionRange>() { a }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal(a.ToNormalizedString(), combined.ToNormalizedString()); }
public void VersionRangeSet_SpecialCaseRangeCombine_AllStablePlusStable() { // Arrange var stable = new VersionRange(new NuGetVersion("1.0.0"), true, new NuGetVersion("2.0.0"), true); var ranges = new List <VersionRange>() { VersionRange.AllStable, stable }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal(VersionRange.AllStable.ToNormalizedString(), combined.ToNormalizedString()); }
public void VersionRangeSet_SpecialCaseRangeCombine_Nones() { // Arrange var ranges = new List <VersionRange>() { VersionRange.None, VersionRange.None, VersionRange.None }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal(VersionRange.None.ToNormalizedString(), combined.ToNormalizedString()); Assert.False(combined.IncludePrerelease); }
public void VersionRangeSet_SpecialCaseRangeCombine_AllStablePlusPre() { // Arrange var pre = new VersionRange(new NuGetVersion("1.0.0"), true, new NuGetVersion("2.0.0"), true, includePrerelease: true); var ranges = new List <VersionRange>() { VersionRange.AllStable, pre }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal(VersionRange.All.ToNormalizedString(), combined.ToNormalizedString()); Assert.True(combined.IncludePrerelease); }
public void VersionRangeSet_SpecialCaseRangeCombine_All() { // Arrange var ranges = new List <VersionRange>() { VersionRange.AllStable, VersionRange.All, VersionRange.AllFloating, VersionRange.AllStableFloating, VersionRange.None }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal(VersionRange.All.ToNormalizedString(), combined.ToNormalizedString()); Assert.True(combined.IncludePrerelease); }
private static List <SourcePackageDependencyInfo> InnerPruneImpossiblePackages(List <SourcePackageDependencyInfo> packages, ISet <string> mustKeep) { if (packages.Count == 0) { return(packages); } var dependencyRangesByPackageId = new Dictionary <string, IList <VersionRange> >(StringComparer.OrdinalIgnoreCase); // (1) Adds all package Ids including leaf nodes that have no dependencies foreach (var package in packages) { if (!dependencyRangesByPackageId.ContainsKey(package.Id)) { dependencyRangesByPackageId.Add(package.Id, new List <VersionRange>()); } } // (2) Create a look-up of every dependency that refers to a particular package Id foreach (var package in packages) { foreach (var dependency in package?.Dependencies) { IList <VersionRange> dependencyVersionRanges; if (dependencyRangesByPackageId.TryGetValue(dependency.Id, out dependencyVersionRanges)) { dependencyVersionRanges.Add(dependency.VersionRange); } } } // (3) Per package Id combine all the dependency ranges into a wider 'worst-case' range var dependencyByPackageId = new Dictionary <string, VersionRange>(StringComparer.OrdinalIgnoreCase); foreach (var item in dependencyRangesByPackageId) { dependencyByPackageId.Add(item.Key, VersionRange.Combine(item.Value)); } // (4) Remove any packages that fall out side of the worst case range while making sure not to remove the packages we must keep var result = packages.Where( package => dependencyByPackageId[package.Id].Satisfies(package.Version) || mustKeep.Contains(package.Id)) .ToList(); return(result); }
public void VersionRangeSet_RemoveEmptyRanges() { // Arrange var ranges = new List <VersionRange>() { VersionRange.None, VersionRange.Parse("(5.0.0, 5.0.0)"), VersionRange.Parse("(3.0.0-alpha, 3.0.0-alpha)"), VersionRange.Parse("[1.0.0, 2.0.0]") }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal("[1.0.0, 2.0.0]", combined.ToNormalizedString()); }
public void VersionRangeSet_SpecialCaseRangeCombine_All() { // Arrange var ranges = new List <VersionRange>() { #pragma warning disable CS0618 // Type or member is obsolete VersionRange.AllStable, VersionRange.All, VersionRange.AllFloating, VersionRange.AllStableFloating, VersionRange.None #pragma warning restore CS0618 // Type or member is obsolete }; // Act var combined = VersionRange.Combine(ranges); // Assert Assert.Equal(VersionRange.All.ToNormalizedString(), combined.ToNormalizedString()); }
private VersionRange NeededRange(VersionRange alreadySearched, VersionRange possibleSubSet) { if (alreadySearched == null || _versionRangeComparer.Equals(alreadySearched, EmptyRange)) { return(possibleSubSet); } if (_versionRangeComparer.Equals(possibleSubSet, EmptyRange)) { return(EmptyRange); } // full overlap scenarios if (possibleSubSet.IsSubSetOrEqualTo(alreadySearched)) { return(EmptyRange); } else if (possibleSubSet.IsSubSetOrEqualTo(alreadySearched)) { return(possibleSubSet); } // we need a partial range // [ ] // [ ] if (possibleSubSet.HasLowerBound && alreadySearched.Satisfies(possibleSubSet.MinVersion)) { // already searched the lower set return(new VersionRange(possibleSubSet.MinVersion, possibleSubSet.IsMinInclusive, alreadySearched.MaxVersion, alreadySearched.IsMaxInclusive, possibleSubSet.IncludePrerelease || alreadySearched.IncludePrerelease)); } else if (possibleSubSet.HasUpperBound && alreadySearched.Satisfies(possibleSubSet.MaxVersion)) { // already searched the higher set return(new VersionRange(alreadySearched.MinVersion, alreadySearched.IsMinInclusive, possibleSubSet.MaxVersion, possibleSubSet.IsMaxInclusive, possibleSubSet.IncludePrerelease || alreadySearched.IncludePrerelease)); } else { // TODO: improve this return(VersionRange.Combine(new VersionRange[] { alreadySearched, possibleSubSet })); } }
public void VersionRangeSet_CombineMultipleRanges() { // Arrange var ranges = new List <VersionRange>() { VersionRange.Parse("[1.0.0]"), VersionRange.Parse("[2.0.0]"), VersionRange.Parse("[3.0.0]"), VersionRange.Parse("[4.0.0-beta-1]"), VersionRange.Parse("[5.0.1-rc4]"), }; // Act var combined = VersionRange.Combine(ranges); ranges.Reverse(); // Assert Assert.Equal("[1.0.0, 5.0.1-rc4]", combined.ToNormalizedString()); }
/// <summary> /// Recursive package dependency info gather /// </summary> private async Task <IEnumerable <PackageDependencyInfo> > Seek(NuGet.Packaging.Core.PackageDependency target, NuGetFramework projectFramework, bool includePrerelease, IEnumerable <string> parents, CancellationToken token) { // check if we are cancelled token.ThrowIfCancellationRequested(); List <PackageDependencyInfo> results = new List <PackageDependencyInfo>(); // circular dependency check protection if (!parents.Contains(target.Id, StringComparer.OrdinalIgnoreCase)) { await Ensure(target, projectFramework, includePrerelease, token); var packages = Get(target, includePrerelease); results.AddRange(packages); // combine all version ranges found for an id into a single range var toSeek = packages.SelectMany(g => g.Dependencies).GroupBy(d => d.Id, StringComparer.OrdinalIgnoreCase) .OrderBy(d => d.Key) .Select(g => new NuGet.Packaging.Core.PackageDependency(g.Key, VersionRange.Combine(g.Select(d => d.VersionRange)))); // recurse Stack <Task <IEnumerable <PackageDependencyInfo> > > tasks = new Stack <Task <IEnumerable <PackageDependencyInfo> > >(); foreach (NuGet.Packaging.Core.PackageDependency dep in toSeek) { // run tasks on another thread var task = Task.Run(async() => await Seek(dep, projectFramework, includePrerelease, parents.Concat(new string[] { target.Id }), token)); tasks.Push(task); } // add child dep results foreach (var task in tasks) { results.AddRange(await task); } } return(results); }
// Thread safe fetch for the target only, no child dependencies private async Task Ensure(NuGet.Packaging.Core.PackageDependency target, NuGetFramework projectFramework, bool includePrerelease, CancellationToken token) { object lockObj = _lockObjsById.GetOrAdd(target.Id, new object()); // lock per package Id lock (lockObj) { VersionRange alreadySearched = null; if (!_rangeSearched.TryGetValue(target.Id, out alreadySearched)) { alreadySearched = EmptyRange; } if (alreadySearched == null || !target.VersionRange.IsSubSetOrEqualTo(alreadySearched)) { // find what we haven't checked already var needed = NeededRange(alreadySearched, target.VersionRange); // adjust prerelease, is this needed? needed = ModifyRange(needed, includePrerelease); if (!_versionRangeComparer.Equals(needed, EmptyRange)) { // server search IEnumerable <IPackage> repoPackages = null; if (_useFindById) { // Ranges fail in some cases for local repos, to work around this just collect every // version of the package to filter later repoPackages = V2Client.FindPackagesById(target.Id); } else { // DataService Repository repoPackages = V2Client.FindPackages(target.Id, GetVersionSpec(needed), includePrerelease, false); } List <VersionRange> currentRanges = new List <VersionRange>(); currentRanges.Add(target.VersionRange); if (alreadySearched != null) { currentRanges.Add(alreadySearched); } // update the already searched range VersionRange combined = null; if (_useFindById) { // for local repos we found all possible versions combined = VersionRange.All; } else { // for non-local repos find the real range combined = VersionRange.Combine(currentRanges); } _rangeSearched.AddOrUpdate(target.Id, combined, (k, v) => combined); HashSet <PackageDependencyInfo> foundPackages = null; // add everything to found if (!_found.TryGetValue(target.Id, out foundPackages)) { foundPackages = new HashSet <PackageDependencyInfo>(PackageIdentity.Comparer); _found.TryAdd(target.Id, foundPackages); } // add current packages to found IEnumerable <PackageDependencyInfo> packageVersions = repoPackages.Select(p => CreateDependencyInfo(p, projectFramework)); foundPackages.UnionWith(packageVersions); } } } }