nuget-extensions/nuget-commands/src.5.8/NuGetTeamCityListPackagesCommand.cs (142 lines of code) (raw):
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using JetBrains.TeamCity.NuGet.ExtendedCommands.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JetBrains.TeamCity.NuGetRunner;
using NuGet;
using NuGet.Commands;
using NuGet.Protocol.Core.Types;
namespace JetBrains.TeamCity.NuGet.ExtendedCommands
{
[Command("TeamCity.ListPackages", "Lists packages for given xml list of packages")]
public class NuGetTeamCityListPackagesCommand : ListCommandBase
{
[Option("Path to file containing package-version pairs to check for updates")]
public string Request { get; set; }
[Option("Path to file to write result of update check")]
public string Response { get; set; }
protected override void ExecuteCommandImpl()
{
if (string.IsNullOrEmpty(Request) || !File.Exists(Request))
{
var message = string.Format("Request file '{0}' was not found", Request);
System.Console.Error.WriteLine(message);
throw new CommandException(message);
}
if (string.IsNullOrEmpty(Response))
{
var message = string.Format("Response file {0} was not found", Response);
System.Console.Error.WriteLine(message);
throw new CommandException(message);
}
new AssemblyResolver(GetType().Assembly.GetAssemblyDirectory());
INuGetPackages reqs;
try
{
reqs = XmlSerializerHelper.Load<NuGetPackages>(Request);
reqs.ClearCheckResults();
}
catch (Exception e)
{
throw new CommandException("Invalid request file: {0}", e.Message);
}
ProcessRequests(reqs).ConfigureAwait(false).GetAwaiter().GetResult();
try
{
XmlSerializerHelper.Save(Response, (NuGetPackages) reqs);
}
catch (Exception e)
{
System.Console.Error.WriteLine("Unable to write response file: {0}", e.Message);
throw;
}
}
private async Task ProcessRequests(INuGetPackages reqs)
{
var sourceToRequest = reqs.Packages.GroupBy(x => x.Feed, Id, NuGetSourceComparer.Comparer);
foreach (var sourceRequest in sourceToRequest)
{
await ProcessPackageSource(sourceRequest.Key, sourceRequest.ToList());
}
}
private async Task ProcessPackageSource(INuGetSource source, List<INuGetPackage> request)
{
//todo: optimize query to return only required set of versions.
foreach (var req in new[]
{
new { Data = request.Where(x => x.VersionSpec == null && x.IncludePrerelease).ToArray(), FetchOption = PackageFetchOption.IncludeLatestAndPrerelease },
new { Data = request.Where(x => x.VersionSpec == null && !x.IncludePrerelease).ToArray(), FetchOption = PackageFetchOption.IncludeLatest },
new { Data = request.Where(x => x.VersionSpec != null).ToArray(), FetchOption = PackageFetchOption.IncludeAll }
})
{
try
{
await ProcessPackages(source, req.FetchOption, req.Data);
}
catch (FatalProtocolException e)
{
var message = e.InnerException?.Message ?? e.Message;
foreach (var pkg in req.Data)
pkg.AddError(message);
System.Console.Error.WriteLine("Failed to check package sources information for {0}: {1}", source, message);
System.Console.Out.WriteLine(e);
}
catch (Exception e)
{
string message;
var aggregateException = e as AggregateException;
if (aggregateException != null)
{
var ae = aggregateException;
ae.Flatten();
var stringBuilder = new StringBuilder();
foreach (var exception in ae.InnerExceptions)
stringBuilder.AppendLine(exception.Message);
message = stringBuilder.ToString();
}
else
message = e.Message;
foreach (var pkg in req.Data)
pkg.AddError(message);
System.Console.Error.WriteLine("Failed to check package sources information for {0}: {1}", source, message);
System.Console.Out.WriteLine(e);
}
}
}
private async Task ProcessPackages(INuGetSource source, PackageFetchOption fetchOptions, IEnumerable<INuGetPackage> package)
{
var packageToData =
package
.GroupBy(x => x.Id, Id, PACKAGE_ID_COMPARER)
.ToDictionary(x => x.Key, Id, PACKAGE_ID_COMPARER);
if (packageToData.Count == 0) return;
var count = 0;
foreach (var packageId in packageToData.Keys)
{
var versions = await GetAllPackagesAsync(source,
fetchOptions,
packageId);
foreach (var version in versions)
{
count++;
if (!packageToData.TryGetValue(packageId, out IGrouping<string, INuGetPackage> res)) break;
foreach (var r in res)
{
if (!r.VersionChecker(version)) continue;
r.AddEntry(new NuGetPackageEntry { Version = version.ToString() });
}
}
}
await System.Console.Out.WriteLineAsync($"Scanned {count} packages for source: {source}");
}
private static T Id<T>(T t)
{
return t;
}
private static readonly IEqualityComparer<string> PACKAGE_ID_COMPARER = StringComparer.InvariantCultureIgnoreCase;
}
}