/// <summary> /// Instantiates a new dependency resolver. /// </summary> /// <param name="packages">The packages to resolve dependencies for.</param> /// <param name="tapInstallation">The tap installation containing installed packages.</param> /// <param name="repositories">The repositories to use for resolving dependencies</param> public DependencyResolver(Installation tapInstallation, IEnumerable <PackageDef> packages, List <IPackageRepository> repositories) { InstalledPackages = new Dictionary <string, PackageDef>(); foreach (var pkg in tapInstallation.GetPackages()) { InstalledPackages[pkg.Name] = pkg; } resolve(repositories, packages); }
internal static List <PackageDef> GatherPackagesAndDependencyDefs(Installation installation, PackageSpecifier[] pkgRefs, string[] packageNames, string Version, CpuArchitecture arch, string OS, List <IPackageRepository> repositories, bool force, bool includeDependencies, bool askToIncludeDependencies, bool noDowngrade) { List <PackageDef> gatheredPackages = new List <PackageDef>(); List <PackageSpecifier> packages = new List <PackageSpecifier>(); if (pkgRefs != null) { packages = pkgRefs.ToList(); } else { if (packageNames == null) { throw new Exception("No packages specified."); } foreach (string packageName in packageNames) { var version = Version; if (Path.GetExtension(packageName).ToLower().EndsWith("tappackages")) { var tempDir = Path.GetTempPath(); var bundleFiles = PluginInstaller.UnpackPackage(packageName, tempDir); var packagesInBundle = bundleFiles.Select(PackageDef.FromPackage); // A packages file may contain the several variants of the same package, try to select one based on OS and Architecture foreach (IGrouping <string, PackageDef> grp in packagesInBundle.GroupBy(p => p.Name)) { var selected = grp.ToList(); if (selected.Count == 1) { gatheredPackages.Add(selected.First()); continue; } if (!string.IsNullOrEmpty(OS)) { selected = selected.Where(p => p.OS.ToLower().Split(',').Any(OS.ToLower().Contains)).ToList(); if (selected.Count == 1) { gatheredPackages.Add(selected.First()); log.Debug("TapPackages file contains packages for several operating systems. Picking only the one for {0}.", OS); continue; } } if (arch != CpuArchitecture.Unspecified) { selected = selected.Where(p => ArchitectureHelper.CompatibleWith(arch, p.Architecture)).ToList(); if (selected.Count == 1) { gatheredPackages.Add(selected.First()); log.Debug("TapPackages file contains packages for several CPU architectures. Picking only the one for {0}.", arch); continue; } } throw new Exception("TapPackages file contains multiple variants of the same package. Unable to autoselect a suitable one."); } } else if (string.IsNullOrWhiteSpace(packageName) == false) { packages.Add(new PackageSpecifier(packageName, VersionSpecifier.Parse(version ?? ""), arch, OS)); } } } foreach (var packageReference in packages) { var installedPackages = installation.GetPackages(); Stopwatch timer = Stopwatch.StartNew(); if (File.Exists(packageReference.Name)) { var package = PackageDef.FromPackage(packageReference.Name); if (noDowngrade) { var installedPackage = installedPackages.FirstOrDefault(p => p.Name == package.Name); if (installedPackage != null && installedPackage.Version.CompareTo(package.Version) >= 0) { log.Info($"The same or a newer version of package '{package.Name}' in already installed."); continue; } } gatheredPackages.Add(package); log.Debug(timer, "Found package {0} locally.", packageReference.Name); } else { PackageDef package = PackageActionHelpers.FindPackage(packageReference, force, installation, repositories); if (noDowngrade) { var installedPackage = installedPackages.FirstOrDefault(p => p.Name == package.Name); if (installedPackage != null && installedPackage.Version.CompareTo(package.Version) >= 0) { log.Info($"The same or a newer version of package '{package.Name}' in already installed."); continue; } } if (PackageCacheHelper.PackageIsFromCache(package)) { log.Debug(timer, "Found package {0} version {1} in local cache", package.Name, package.Version); } else { log.Debug(timer, "Found package {0} version {1}", package.Name, package.Version); } gatheredPackages.Add(package); } } if (gatheredPackages.All(p => p.IsBundle())) { // If we are just installing bundles, we can assume that dependencies should also be installed includeDependencies = true; } log.Debug("Resolving dependencies."); var resolver = new DependencyResolver(installation, gatheredPackages, repositories); if (resolver.UnknownDependencies.Any()) { foreach (var dep in resolver.UnknownDependencies) { string message = string.Format("A package dependency named '{0}' with a version compatible with {1} could not be found in any repository.", dep.Name, dep.Version); if (force) { log.Warning(message); log.Warning("Continuing without downloading dependencies. Plugins will likely not work as expected.", dep.Name); } else { log.Error(message); } } if (!force) { log.Info("To download package dependencies despite the conflicts, use the --force option."); return(null); } } else if (resolver.MissingDependencies.Any()) { string dependencyArgsHint = ""; if (!includeDependencies) { dependencyArgsHint = $" (use --dependencies to also get these)"; } if (resolver.MissingDependencies.Count > 1) { log.Info("{0} required dependencies are currently not installed{1}.", resolver.MissingDependencies.Count, dependencyArgsHint); } else { log.Info("A required dependency is currently not installed{0}.", dependencyArgsHint); } if (includeDependencies) { //log.Debug($"Currently set to download dependencies quietly."); foreach (var package in resolver.MissingDependencies) { log.Debug("Adding dependency {0} {1}", package.Name, package.Version); gatheredPackages.Insert(0, package); } } else if (askToIncludeDependencies) { var pkgs = new List <DepRequest>(); foreach (var package in resolver.MissingDependencies) { // Handle each package at a time. DepRequest req = null; pkgs.Add(req = new DepRequest { PackageName = package.Name, message = string.Format("Add dependency {0} {1} ?", package.Name, package.Version), Response = DepResponse.Add }); UserInput.Request(req, true); } foreach (var pkg in resolver.MissingDependencies) { var res = pkgs.FirstOrDefault(r => r.PackageName == pkg.Name); if ((res != null) && res.Response == DepResponse.Add) { gatheredPackages.Insert(0, pkg); } } } } return(gatheredPackages); }
public static Issue CheckDependencies(Installation installation, IEnumerable <string> newPackages, LogEventType severity = LogEventType.Error) { return(checkPackages(installation.GetPackages(), newPackages.Select(Path.GetFullPath).ToArray(), severity)); }
private void GetPackageInfo(PackageDef package, List <PackageVersion> packageVersions, Installation installation) { var allPackages = installation.GetPackages(); var latestVersion = packageVersions?.Max(p => p.Version); var packageInstalled = allPackages.Contains(package); if (!packageInstalled) { allPackages.Add(package); } var tree = DependencyAnalyzer.BuildAnalyzerContext(allPackages); var issues = tree.GetIssues(package); ParseDescription(package.Description); // Get similar releases to get available platforms and architectures var similarReleases = packageVersions.Where(x => x.Version.Major == package.Version.Major && x.Version.Minor == package.Version.Minor).ToList(); AddWritePair("Package Name", package.Name); AddWritePair("Group", package.Group); var installedVersion = installation.GetPackages().Where(x => x.Name == package.Name)?.FirstOrDefault()?.Version; var installedString = installedVersion == null ? "(not installed)" : $"({installedVersion} installed)"; AddWritePair("Version", $"{package.Version} {installedString}"); if (latestVersion != null && installedVersion != null && latestVersion != installedVersion) { AddWritePair("Newest Version in Repository", $"{latestVersion}"); } AddWritePair("Compatible Architectures", string.Join(Environment.NewLine, similarReleases.Select(x => x.Architecture).Distinct())); AddWritePair("Compatible Platforms", string.Join(Environment.NewLine, similarReleases.Select(x => x.OS).Distinct())); if (packageInstalled == false) { AddWritePair("Compatibility Issues", issues.Any() ? $"{(string.Join(Environment.NewLine, issues.Select(x => $"{x.PackageName} - {x.IssueType.ToString()}")))}" : "none"); } AddWritePair("Owner", package.Owner); var licenseString = (package.LicenseRequired ?? "").Replace("&", " and ").Replace("|", " or "); AddWritePair("License Required", licenseString); AddWritePair("SourceUrl", package.SourceUrl); if (package.PackageSource is IRepositoryPackageDefSource repoPkg) { AddWritePair("Repository", repoPkg.RepositoryUrl); } AddWritePair("Package Type", package.FileType); AddWritePair("Package Class", package.Class); var tags = package.Tags?.Split(new string[] { " ", "," }, StringSplitOptions.RemoveEmptyEntries); if (tags?.Length > 0) { AddWritePair("Package Tags", string.Join(" ", tags)); } if (package.Dependencies.Count > 0) { AddWritePair("Dependencies", string.Join(Environment.NewLine, package.Dependencies.Select(x => x.Name))); } foreach (var(key, value) in SubTags) { AddWritePair(key, value); } AddWritePair("Description", Description); if (IncludeFiles) { if (package.Files.Count > 0) { AddWritePair("Files", string.Join(Environment.NewLine, package.Files.Select(x => x.RelativeDestinationPath.Replace("\\", "/")))); } } if (IncludePlugins) { var plugins = package.Files.Select(x => x.Plugins); var sb = new StringBuilder(); foreach (var plugin in plugins) { foreach (var p in plugin) { var name = p.Name; var desc = p.Description; sb.Append(!string.IsNullOrWhiteSpace(desc) ? $"{name} ({desc}){Environment.NewLine}" : $"{name}{Environment.NewLine}"); } } AddWritePair("Plugins", sb.ToString()); } WritePairs(); }
private PackageDef GetPackageDef(Installation targetInstallation) { // Try a number of methods to obtain the PackageDef in order of precedence var packageRef = new PackageSpecifier(Name, VersionSpecifier.Parse(Version ?? ""), Architecture, OS); PackageDef package; // a relative or absolute file path if (File.Exists(Name)) { package = PackageDef.FromPackage(Name); if (package != null) { Offline = true; return(package); } } // a currently installed package package = targetInstallation.GetPackages().FirstOrDefault(p => p.Name == Name && versionSpec.IsCompatible(p.Version)); if (package != null) { return(package); } if (Offline == false) { try { // a release from repositories package = repositories.SelectMany(x => x.GetPackages(packageRef)) .FindMax(p => p.Version); if (package != null) { return(package); } } catch (System.Net.WebException e) { // not connected to the internet log.Error(e.Message); log.Warning("Could not connect to repository. Showing results for local install"); DisableHttpRepositories(); package = repositories.SelectMany(x => x.GetPackages(packageRef)) .FindMax(p => p.Version); if (package != null) { return(package); } } } if (!string.IsNullOrWhiteSpace(Version)) { log.Warning($"{Name} version {Version} not found."); } if (Offline == false && string.IsNullOrWhiteSpace(Version)) { // a prerelease from repositories packageRef = new PackageSpecifier(Name, VersionSpecifier.Parse("any"), Architecture, OS); package = repositories.SelectMany(x => x.GetPackages(packageRef)) .FindMax(p => p.Version); } return(package); }