protected override int LockedExecute(CancellationToken cancellationToken) { if (OutputPaths.Length > Packages.Length) { throw new Exception("More OutputPaths specified than packages. Exiting."); } string destinationDir = Target ?? Directory.GetCurrentDirectory(); Installation destinationInstallation = new Installation(destinationDir); List <IPackageRepository> repositories = new List <IPackageRepository>(); if (Repository == null) { repositories.AddRange(PackageManagerSettings.Current.Repositories.Where(p => p.IsEnabled).Select(s => s.Manager).ToList()); } else { repositories.AddRange(Repository.Select(s => PackageRepositoryHelpers.DetermineRepositoryType(s))); } List <PackageDef> PackagesToDownload = PackageActionHelpers.GatherPackagesAndDependencyDefs(destinationInstallation, PackageReferences, Packages, Version, Architecture, OS, repositories, ForceInstall, InstallDependencies, false, false); if (PackagesToDownload == null) { return(2); } if (!DryRun) { // If OutputPaths are specified, download the specified packages to those locations before downloading the remaining files // Place the remaining files in the same location as the last named location for (int i = 0; i < OutputPaths.Length; i++) { var outputPath = OutputPaths[i]; var packageName = Packages[i]; var package = PackagesToDownload.First(p => p.Name == packageName || (p.PackageSource is FilePackageDefSource s && s.PackageFilePath == Path.GetFullPath(packageName))); string filename = null; // Treat path as a directory if it ends with '/' if (outputPath.EndsWith("/") || outputPath.EndsWith(Path.DirectorySeparatorChar.ToString())) { Directory.CreateDirectory(outputPath); } if (Directory.Exists(outputPath)) { destinationDir = outputPath; } // Otherwise, treat it as a full path else { var file = new FileInfo(outputPath); destinationDir = file.DirectoryName; Directory.CreateDirectory(destinationDir); filename = file.FullName; } PackageActionHelpers.DownloadPackages(destinationDir, new List <PackageDef>() { package }, new List <string>() { filename }); PackagesToDownload.Remove(package); } // Download the remaining packages PackageActionHelpers.DownloadPackages(destinationDir, PackagesToDownload); } else { log.Info("Dry run completed. Specified packages are available."); } DownloadedPackages = PackagesToDownload; return(0); }
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); }