Created
January 22, 2017 20:34
-
-
Save emgarten/d2fe22d0cb28d110c23f13980a441770 to your computer and use it in GitHub Desktop.
Find all packages on nuget.org that depend on the target package id.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using NuGet.CatalogReader; | |
using NuGet.Common; | |
using NuGet.Packaging.Core; | |
using NuGet.Protocol; | |
using NuGet.Protocol.Core.Types; | |
namespace ConsoleApp | |
{ | |
/// <summary> | |
/// Add this code to a new console app. | |
/// Install-Package https://www.nuget.org/packages/NuGet.CatalogReader/1.2.0 | |
/// | |
/// This script finds all packages that depend on the given package id. | |
/// For nuget.org this script runs through all 88K ids which may take | |
/// some time. To check multiple packages this script could be modified to | |
/// create an index of all dependencies for easy look up later. | |
/// </summary> | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
// Find all packages that depend on this package. | |
var targetId = "NuGet.Versioning"; | |
FindParentPackagesAsync(targetId).Wait(); | |
} | |
static async Task FindParentPackagesAsync(string targetId) | |
{ | |
var parents = new HashSet<PackageIdentity>(); | |
var feed = new Uri("https://api.nuget.org/v3/index.json"); | |
var repository = Repository.Factory.GetCoreV3(feed.AbsoluteUri, FeedType.HttpV3); | |
var dependencyInfo = await repository.GetResourceAsync<DependencyInfoResource>(); | |
var threads = 8; | |
ServicePointManager.DefaultConnectionLimit = 64; | |
using (var catalog = new CatalogReader(feed, TimeSpan.FromHours(4))) | |
{ | |
// Read the v3 feed. | |
Console.WriteLine($"Reading {feed.AbsoluteUri}"); | |
// Find all unique ids | |
var ids = (await catalog.GetFlattenedEntriesAsync()) | |
.Select(e => e.Id) | |
.Distinct(StringComparer.OrdinalIgnoreCase) | |
.OrderBy(s => s, StringComparer.OrdinalIgnoreCase) | |
.ToArray(); | |
var tasks = new Dictionary<Task<IEnumerable<RemoteSourceDependencyInfo>>, string>(); | |
// Loop through all ids found in the feed. | |
for (int i = 0; i < ids.Length; i++) | |
{ | |
// Throttle | |
if (tasks.Count == threads) | |
{ | |
await CompleteTaskAsync(targetId, parents, tasks); | |
} | |
var id = ids[i]; | |
// Get dependencies for all versions of the package. | |
var task = Task.Run(async () => await dependencyInfo.ResolvePackages(id, NullLogger.Instance, CancellationToken.None)); | |
tasks.Add(task, id); | |
Console.WriteLine($"[{i}] Checking {id}"); | |
} | |
// Wait for all tasks to complete | |
while (tasks.Count > 0) | |
{ | |
await CompleteTaskAsync(targetId, parents, tasks); | |
} | |
} | |
Console.WriteLine("=======[Parent packages]======="); | |
foreach (var parent in parents.Select(e => e.Id) | |
.Distinct(StringComparer.OrdinalIgnoreCase) | |
.OrderBy(s => s, StringComparer.OrdinalIgnoreCase)) | |
{ | |
Console.WriteLine($"{parent} -> {targetId}"); | |
} | |
} | |
// Read the result | |
private static async Task CompleteTaskAsync(string targetId, | |
HashSet<PackageIdentity> parents, | |
Dictionary<Task<IEnumerable<RemoteSourceDependencyInfo>>, string> tasks) | |
{ | |
var task = await Task.WhenAny(tasks.Keys); | |
var packageId = tasks[task]; | |
tasks.Remove(task); | |
var packages = Enumerable.Empty<RemoteSourceDependencyInfo>(); | |
try | |
{ | |
packages = task.Result; | |
} | |
catch (Exception ex) | |
{ | |
// Ignore errors due to invalid packages on the feed. | |
Console.WriteLine($"Feed error: {packageId} {ex.Message}"); | |
} | |
parents.UnionWith(GetParents(packages, targetId)); | |
} | |
// Find all packages which depend on the target package. | |
static IEnumerable<PackageIdentity> GetParents(IEnumerable<RemoteSourceDependencyInfo> packageInfos, | |
string targetId) | |
{ | |
return packageInfos.Where(packageInfo => packageInfo.DependencyGroups.Any(group => | |
group.Packages.Any(e => targetId.Equals(e.Id, StringComparison.OrdinalIgnoreCase)))) | |
.Select(e => e.Identity); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment