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; } } }