using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
namespace OpenTap.Package
{
///
/// Exception thrown when ImageSpecifier.Resolve fails.
///
public class ImageResolveException : AggregateException
{
internal ImageSpecifier Image { get; }
internal ImmutableArray InstalledPackages { get; }
internal ImageResolution Result { get; }
internal ImageResolveException(ImageResolution result, ImageSpecifier image,
ImmutableArray installedPackages)
{
Result = result;
Image = image;
InstalledPackages = installedPackages;
}
///
/// The description of the resolution error.
///
public override string Message => ToString();
///
/// Convert the resolution error to a string
///
///
public override string ToString()
{
var unsatisfiedDependencies = new List();
if (Result is FailedImageResolution fir && fir.resolveProblems is not GenericResolutionProblem)
{
return fir.ToString();
}
foreach (var pkg in InstalledPackages)
{
if (!pkg.Dependencies.All(dep => isSatisfied(dep, InstalledPackages)))
unsatisfiedDependencies.Add(pkg);
}
if (unsatisfiedDependencies.Any())
{
var sb = new StringBuilder();
var namePadding = unsatisfiedDependencies.Max(n => n.Name.Length);
foreach (var sat in unsatisfiedDependencies)
{
var missingDeps = sat.Dependencies.Where(dep => !isSatisfied(dep, InstalledPackages)).ToArray();
missingDeps = missingDeps.Where(m =>
this.Image.Packages.Where(p => p.Name == m.Name)
.All(requested => !m.Version.IsSatisfiedBy(requested.Version))).ToArray();
if (missingDeps.Any())
{
string missingMsg = string.Join(" and ",
missingDeps.Select(pkg => $"{pkg.Name}:{pkg.Version}"));
sb.AppendLine($"{sat.Name.PadRight(namePadding)} missing {missingMsg}");
}
}
return $"{sb} ({Image} from {string.Join(", ", Image.Repositories)})";
}
return Result.ToString();
}
static bool isSatisfied(PackageDependency dep, IEnumerable InstalledPackages)
{
foreach (var i in InstalledPackages)
{
if (i.Name == dep.Name)
{
if (dep.Version.IsSatisfiedBy(i.Version.AsExactSpecifier()))
return true;
}
}
return false;
}
///
/// Dependency graph specified in Dot notation
///
[Obsolete("This will always be null.")]
public string DotGraph { get; private set; }
}
}