This commit is contained in:
2025-07-29 11:09:34 +05:00
commit e91bd99572
5 changed files with 1055 additions and 0 deletions

240
Program.cs Normal file
View File

@ -0,0 +1,240 @@
using NuGet.Configuration;
using NuGet.Frameworks;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Resolver;
using NuGet.Versioning;
using NuGet.Common;
class Program
{
static async Task<int> Main(string[] args)
{
if (args.Length == 0 || args.Contains("--help") || args.Contains("-h"))
{
Console.WriteLine("Утилита для скачивания NuGet пакетов с зависимостями");
Console.WriteLine();
Console.WriteLine("Использование:");
Console.WriteLine(" dotnet run -- --package-id <ID> [опции]");
Console.WriteLine();
Console.WriteLine("Опции:");
Console.WriteLine(" --package-id <ID> ID пакета для скачивания (обязательный)");
Console.WriteLine(" --version <VERSION> Версия пакета (по умолчанию последняя стабильная)");
Console.WriteLine(" --framework <FRAME> Целевой framework (по умолчанию netstandard2.0)");
Console.WriteLine(" --output-dir <DIR> Папка для сохранения пакетов (по умолчанию ./nuget-packages)");
Console.WriteLine(" --source <URL> Источник NuGet (по умолчанию https://api.nuget.org/v3/index.json)");
Console.WriteLine();
Console.WriteLine("Примеры:");
Console.WriteLine(" dotnet run -- --package-id Npgsql --framework netstandard2.0");
Console.WriteLine(" dotnet run -- --package-id Npgsql --version 7.0.6 --output-dir ./my-packages");
return 0;
}
string? packageId = null;
string? version = null;
string framework = "netstandard2.0";
string outputDir = "./nuget-packages";
string source = "https://api.nuget.org/v3/index.json";
for (int i = 0; i < args.Length; i++)
{
switch (args[i])
{
case "--package-id":
if (i + 1 < args.Length) packageId = args[++i];
break;
case "--version":
if (i + 1 < args.Length) version = args[++i];
break;
case "--framework":
if (i + 1 < args.Length) framework = args[++i];
break;
case "--output-dir":
if (i + 1 < args.Length) outputDir = args[++i];
break;
case "--source":
if (i + 1 < args.Length) source = args[++i];
break;
case "--help":
case "-h":
Console.WriteLine("Использование: dotnet run -- --package-id <ID> [опции]");
Console.WriteLine();
Console.WriteLine("Опции:");
Console.WriteLine(" --package-id <ID> ID пакета для скачивания (обязательный)");
Console.WriteLine(" --version <VERSION> Версия пакета (по умолчанию последняя стабильная)");
Console.WriteLine(" --framework <FRAME> Целевой framework (по умолчанию netstandard2.0)");
Console.WriteLine(" --output-dir <DIR> Папка для сохранения пакетов (по умолчанию ./nuget-packages)");
Console.WriteLine(" --source <URL> Источник NuGet (по умолчанию https://api.nuget.org/v3/index.json)");
Console.WriteLine();
Console.WriteLine("Примеры:");
Console.WriteLine(" dotnet run -- --package-id Npgsql --framework netstandard2.0");
Console.WriteLine(" dotnet run -- --package-id Npgsql --version 7.0.6 --output-dir ./my-packages");
return 0;
}
}
if (string.IsNullOrEmpty(packageId))
{
Console.WriteLine("Ошибка: --package-id обязателен");
return 1;
}
await DownloadPackageWithDependencies(packageId, version, framework, outputDir, source);
return 0;
}
static async Task DownloadPackageWithDependencies(string packageId, string? version, string framework, string outputDir, string source)
{
try
{
Console.WriteLine($"Скачивание пакета {packageId} с зависимостями...");
Console.WriteLine($"Framework: {framework}");
Console.WriteLine($"Источник: {source}");
Console.WriteLine($"Папка назначения: {outputDir}");
// Создаем папку назначения
Directory.CreateDirectory(outputDir);
// Настраиваем источник пакетов
var settings = Settings.LoadDefaultSettings(null);
var sourceRepository = Repository.Factory.GetCoreV3(source);
var resource = await sourceRepository.GetResourceAsync<FindPackageByIdResource>();
// Определяем версию пакета
NuGetVersion packageVersion;
if (string.IsNullOrEmpty(version))
{
var versions = await resource.GetAllVersionsAsync(packageId, new SourceCacheContext(), NullLogger.Instance, CancellationToken.None);
packageVersion = versions.Where(v => !v.IsPrerelease).Max() ?? throw new InvalidOperationException($"Не найдена стабильная версия для пакета {packageId}");
Console.WriteLine($"Выбрана версия: {packageVersion}");
}
else
{
packageVersion = NuGetVersion.Parse(version);
}
// Создаем framework
var nugetFramework = NuGetFramework.Parse(framework);
// Собираем все зависимости
var packagesToDownload = new HashSet<PackageIdentity>();
var processedPackages = new HashSet<string>();
await CollectDependencies(packageId, packageVersion, nugetFramework, packagesToDownload, processedPackages, sourceRepository);
Console.WriteLine($"Найдено пакетов для скачивания: {packagesToDownload.Count}");
foreach (var package in packagesToDownload)
{
Console.WriteLine($" - {package.Id} {package.Version}");
}
// Скачиваем все пакеты
var cacheContext = new SourceCacheContext();
var downloadResource = await sourceRepository.GetResourceAsync<DownloadResource>();
foreach (var package in packagesToDownload)
{
await DownloadPackage(package, downloadResource, cacheContext, outputDir);
}
Console.WriteLine($"Все пакеты успешно скачаны в папку: {outputDir}");
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка: {ex.Message}");
Environment.Exit(1);
}
}
static async Task CollectDependencies(string packageId, NuGetVersion version, NuGetFramework framework,
HashSet<PackageIdentity> packagesToDownload, HashSet<string> processedPackages, SourceRepository sourceRepository)
{
var packageIdentity = new PackageIdentity(packageId, version);
var packageKey = $"{packageId}.{version}";
if (processedPackages.Contains(packageKey))
return;
processedPackages.Add(packageKey);
packagesToDownload.Add(packageIdentity);
try
{
// Получаем зависимости через PackageReader
var downloadResource = await sourceRepository.GetResourceAsync<DownloadResource>();
var cacheContext = new SourceCacheContext();
var downloadResult = await downloadResource.GetDownloadResourceResultAsync(
packageIdentity,
new PackageDownloadContext(cacheContext),
Path.GetTempPath(),
NullLogger.Instance,
CancellationToken.None);
if (downloadResult.Status == DownloadResourceResultStatus.Available)
{
using var packageReader = new PackageArchiveReader(downloadResult.PackageStream);
var nuspecReader = packageReader.NuspecReader;
var dependencyGroups = nuspecReader.GetDependencyGroups();
// Находим подходящую группу зависимостей для нашего framework
var dependencyGroup = dependencyGroups
.FirstOrDefault(dg => dg.TargetFramework == null || dg.TargetFramework == framework);
if (dependencyGroup != null)
{
Console.WriteLine($" Найдено зависимостей для {packageId}: {dependencyGroup.Packages.Count()}");
foreach (var dependency in dependencyGroup.Packages)
{
// Получаем версию зависимости
var dependencyVersion = dependency.VersionRange?.MinVersion ?? dependency.VersionRange?.MaxVersion;
if (dependencyVersion != null)
{
Console.WriteLine($" Зависимость: {dependency.Id} {dependencyVersion}");
await CollectDependencies(dependency.Id, dependencyVersion, framework, packagesToDownload, processedPackages, sourceRepository);
}
}
}
else
{
Console.WriteLine($" Нет зависимостей для {packageId} в framework {framework}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Предупреждение: Не удалось получить зависимости для {packageId} {version}: {ex.Message}");
}
}
static async Task DownloadPackage(PackageIdentity packageIdentity, DownloadResource downloadResource,
SourceCacheContext cacheContext, string outputDir)
{
Console.WriteLine($"Скачивание пакета: {packageIdentity.Id} {packageIdentity.Version}");
var downloadResult = await downloadResource.GetDownloadResourceResultAsync(
packageIdentity,
new PackageDownloadContext(cacheContext),
Path.GetTempPath(),
NullLogger.Instance,
CancellationToken.None);
if (downloadResult.Status == DownloadResourceResultStatus.Available)
{
var packagePath = Path.Combine(outputDir, $"{packageIdentity.Id}.{packageIdentity.Version}.nupkg");
using (var packageStream = downloadResult.PackageStream)
using (var fileStream = File.Create(packagePath))
{
await packageStream.CopyToAsync(fileStream);
}
Console.WriteLine($" ✓ Скачан: {packagePath}");
}
else
{
Console.WriteLine($" ✗ Ошибка скачивания: {packageIdentity.Id} {packageIdentity.Version}");
}
}
}