/// <summary> /// Installs a given package. /// </summary> /// <param name="fastPackageReference">A provider supplied identifier that specifies an exact package</param> /// <param name="request">An object passed in from the PackageManagement that contains functions that can be used to interact with its Provider</param> public void InstallPackage(string fastPackageReference, NuGetRequest request) { if (request == null){ throw new ArgumentNullException("request"); } request.Debug(Resources.Messages.DebugInfoCallMethod3, PackageProviderName, "InstallPackage", fastPackageReference); try { var pkgItem = request.GetPackageByFastpath(fastPackageReference); if (pkgItem == null) { request.WriteError(ErrorCategory.InvalidArgument, fastPackageReference, Constants.Messages.UnableToResolvePackage); return; } if ((pkgItem.PackageSource == null) || (pkgItem.PackageSource.Location == null) || (pkgItem.Package == null)) { request.Debug(Resources.Messages.VariableCheck, "PackageSource or PackageSource.Location or Package object", "null"); request.WriteError(ErrorCategory.ObjectNotFound, fastPackageReference, Constants.Messages.UnableToResolvePackage, pkgItem.Id); return; } request.Debug(Resources.Messages.VariableCheck, "Package version", pkgItem.Version); request.Debug(Resources.Messages.VariableCheck, "Request's Destination", request.Destination); // got this far, let's install the package we came here for. if (!NuGetClient.InstallOrDownloadPackageHelper(pkgItem, request, Constants.Install, (packageItem, progressTracker) => NuGetClient.InstallSinglePackage(packageItem, request, progressTracker))) { // package itself didn't install. Write error request.WriteError(ErrorCategory.InvalidResult, pkgItem.Id, Constants.Messages.PackageFailedInstallOrDownload, pkgItem.Id, CultureInfo.CurrentCulture.TextInfo.ToLower(Constants.Install)); return; } } catch (Exception ex) { ex.Dump(request); request.WriteError(ErrorCategory.InvalidOperation, fastPackageReference, ex.Message); } }
/// <summary> /// This is called when the user is adding (or updating) a package source /// /// If this PROVIDER doesn't support user-defined package sources, remove this method. /// </summary> /// <param name="name">The name of the package source. If this parameter is null or empty the PROVIDER should use the location as the name (if the PROVIDER actually stores names of package sources)</param> /// <param name="location">The location (ie, directory, URL, etc) of the package source. If this is null or empty, the PROVIDER should use the name as the location (if valid)</param> /// <param name="trusted">A boolean indicating that the user trusts this package source. Packages returned from this source should be marked as 'trusted'</param> /// <param name="request">An object passed in from the PackageManagement that contains functions that can be used to interact with its Provider</param> public void AddPackageSource(string name, string location, bool trusted, NuGetRequest request) { if (request == null){ throw new ArgumentNullException("request"); } try { request.Debug(string.Format(CultureInfo.InvariantCulture, "AddPackageSource - ProvidenName = '{0}', name='{1}', location='{2}', trusted='{3}'", PackageProviderName, name, location, trusted)); // Error out if a user does not provide package source Name if (string.IsNullOrWhiteSpace(name)) { request.WriteError(ErrorCategory.InvalidArgument, Constants.Parameters.Name, Constants.Messages.MissingRequiredParameter, Constants.Parameters.Name); return; } if (string.IsNullOrWhiteSpace(location)) { request.WriteError(ErrorCategory.InvalidArgument, Constants.Parameters.Location, Constants.Messages.MissingRequiredParameter, Constants.Parameters.Location); return; } request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, "GetOptionValue"); // if this is supposed to be an update, there will be a dynamic parameter set for IsUpdatePackageSource var isUpdate = request.GetOptionValue(Constants.Parameters.IsUpdate).IsTrue(); request.Debug(Resources.Messages.VariableCheck, "IsUpdate", isUpdate); // if your source supports credentials you get get them too: // string username =request.Username; // SecureString password = request.Password; // feel free to send back an error here if your provider requires credentials for package sources. // check first that we're not clobbering an existing source, unless this is an update request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "FindRegisteredSource -name'{0}'", name)); var src = request.FindRegisteredSource(name); if (src != null && !isUpdate) { // tell the user that there's one here already request.WriteError(ErrorCategory.InvalidArgument, name, Constants.Messages.PackageSourceExists, name); return; } // conversely, if it didn't find one, and it is an update, that's bad too: if (src == null && isUpdate) { // you can't find that package source? Tell that to the user request.WriteError(ErrorCategory.ObjectNotFound, name, Constants.Messages.UnableToResolveSource, name); return; } // ok, we know that we're ok to save this source // next we check if the location is valid (if we support that kind of thing) var validated = false; if (!request.SkipValidate.Value) { // the user has not opted to skip validating the package source location, so check if the source is valid validated = request.ValidateSourceLocation(location); if (!validated) { request.WriteError(ErrorCategory.InvalidData, name, Constants.Messages.SourceLocationNotValid, location); return; } request.Verbose(Resources.Messages.SuccessfullyValidated, name); } // it's good to check just before you actually write something to see if the user has cancelled the operation if (request.IsCanceled) { return; } // looking good -- store the package source. request.AddPackageSource(name, location, trusted, validated); // Yield the package source back to the caller. request.YieldPackageSource(name, location, trusted, true /*since we just registered it*/, validated); } catch (Exception e) { e.Dump(request); } }
/// <summary> /// Downloads a remote package file to a local location. /// </summary> /// <param name="fastPackageReference"></param> /// <param name="destLocation"></param> /// <param name="request">An object passed in from the PackageManagement that contains functions that can be used to interact with its Provider</param> public void DownloadPackage(string fastPackageReference, string destLocation, NuGetRequest request) { if (request == null){ throw new ArgumentNullException("request"); } request.Debug(Resources.Messages.DebugInfoCallMethod3, PackageProviderName, fastPackageReference, destLocation); try { var pkgItem = request.GetPackageByFastpath(fastPackageReference); if (pkgItem == null) { request.WriteError(ErrorCategory.InvalidArgument, fastPackageReference, Constants.Messages.UnableToResolvePackage); return; } NuGetClient.InstallOrDownloadPackageHelper(pkgItem, request, Constants.Download, (packageItem, progressTracker) => NuGetClient.DownloadSinglePackage(packageItem, request, destLocation, progressTracker)); } catch (Exception ex) { ex.Dump(request); request.WriteError(ErrorCategory.InvalidOperation, fastPackageReference, ex.Message); } }
/// <summary> /// Download a package from a file repository that matches the given version and name and install it on the local system. /// </summary> /// <param name="packageName">Package name</param> /// <param name="version">Package version</param> /// <param name="request">An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it </param> /// <param name="source">Package source</param> /// <param name="sourceFilePath">File source path pointing to the package to be installed</param> /// <returns>PackageItem object</returns> internal static PackageItem InstallPackageLocal( string packageName, string version, NuGetRequest request, PackageSource source, string sourceFilePath ) { request.Debug(Messages.DebugInfoCallMethod, "NuGetClient", "InstallPackageLocal"); string tempSourceFilePath = null; string tempSourceDirectory = null; string directoryToDeleteWhenFailed = String.Empty; bool needToDelete = false; try { string destinationFilePath = request.Destination; request.Verbose(string.Format(CultureInfo.InvariantCulture, "InstallPackageLocal' - name='{0}', version='{1}',destination='{2}'", packageName, version, destinationFilePath)); request.Debug(sourceFilePath); if (string.IsNullOrWhiteSpace(sourceFilePath)) { throw new ArgumentNullException(sourceFilePath); } if (!File.Exists(sourceFilePath)) { throw new FileNotFoundException(sourceFilePath); } //Create the destination directory if it does not exist if (!Directory.Exists(destinationFilePath)) { Directory.CreateDirectory(destinationFilePath); directoryToDeleteWhenFailed = destinationFilePath; } //Make a temp folder in the user appdata temp directory tempSourceFilePath = FileUtility.GetTempFileFullPath(fileExtension: NuGetConstant.PackageExtension); //Copy over the source file from the folder repository to the temp folder File.Copy(sourceFilePath, tempSourceFilePath, true); //Unzip it tempSourceDirectory = PackageUtility.DecompressFile(tempSourceFilePath); //Get a packge directory under the destination path to store the package string installedFolder = FileUtility.MakePackageDirectoryName(request.ExcludeVersion.Value, destinationFilePath, packageName, version); // if we did not set the directory before, then the destinationFilePath already exists, so we should not delete it if (string.IsNullOrWhiteSpace(directoryToDeleteWhenFailed)) { directoryToDeleteWhenFailed = installedFolder; } //File folder format of the Nuget packages looks like the following after installed: //Jquery.2.0.1 // - JQuery.2.0.1.nupkg // - contents and other stuff //Copy the unzipped files to under the package installed folder FileUtility.CopyDirectory(tempSourceDirectory, installedFolder, true); //Read the package manifest and return the package object string nuspec = Path.Combine(installedFolder, packageName) + NuGetConstant.ManifestExtension; PackageBase package = PackageUtility.ProcessNuspec(nuspec); var pkgItem = new PackageItem { Package = package, PackageSource = source, FastPath = request.MakeFastPath(source, package.Id, package.Version), FullPath = installedFolder }; // Delete the nuspec file //Get a package file path var nuspecFilePath = Path.Combine(installedFolder, packageName + NuGetConstant.ManifestExtension); if (File.Exists(nuspecFilePath)) { FileUtility.DeleteFile(nuspecFilePath, false); } request.Debug(Messages.DebugInfoReturnCall, "NuGetClient", "InstallPackageLocal"); return pkgItem; } catch (Exception ex) { needToDelete = true; // the warning will be package "packageName" failed to install ex.Dump(request); request.WriteError(ErrorCategory.InvalidResult, packageName, Constants.Messages.PackageFailedInstallOrDownload, packageName, CultureInfo.CurrentCulture.TextInfo.ToLower(Constants.Install)); throw; } finally { if (needToDelete && Directory.Exists(directoryToDeleteWhenFailed)) { FileUtility.DeleteDirectory(directoryToDeleteWhenFailed, true, isThrow: false); } FileUtility.DeleteFile(tempSourceFilePath, isThrow:false); FileUtility.DeleteDirectory(tempSourceDirectory, recursive: true, isThrow: false); } }
/// <summary> /// Returns the validated uri. Returns null if we cannot validate it /// </summary> /// <param name="query"></param> /// <param name="request"></param> /// <returns></returns> internal static Uri ValidateUri(Uri query, NuGetRequest request) { var client = request.ClientWithoutAcceptHeader; var response = PathUtility.GetHttpResponse(client, query.AbsoluteUri, (() => request.IsCanceled), ((msg, num) => request.Verbose(Resources.Messages.RetryingDownload, msg, num)), (msg) => request.Verbose(msg), (msg) => request.Debug(msg)); if (response == null) { return null; } // if response is not success, we need to check for redirection if (!response.IsSuccessStatusCode) { // Check for redirection (http status code 3xx) if (response.StatusCode == HttpStatusCode.MultipleChoices || response.StatusCode == HttpStatusCode.MovedPermanently || response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.SeeOther || response.StatusCode == HttpStatusCode.TemporaryRedirect) { // get the redirected direction string location = response.Headers.GetValues("Location").FirstOrDefault(); if (String.IsNullOrWhiteSpace(location)) { return null; } // make a new query based on location query = new Uri(location); } else { if (response.StatusCode == HttpStatusCode.Unauthorized) { request.WriteError(ErrorCategory.PermissionDenied, "ValidateUri", Resources.Messages.AccessPermissionDenied, query); } // other status code is wrong return null; } } else { query = new Uri(response.RequestMessage.RequestUri.AbsoluteUri); } //Making a query like: www.nuget.org/api/v2/FindPackagesById()?id='FoooBarr' to check the server available. //'FoooBarr' is an any random package id string queryUri = "FoooBarr".MakeFindPackageByIdQuery(PathUtility.UriCombine(query.AbsoluteUri, NuGetConstant.FindPackagesById)); response = PathUtility.GetHttpResponse(client, queryUri, (() => request.IsCanceled), ((msg, num) => request.Verbose(Resources.Messages.RetryingDownload, msg, num)), (msg) => request.Verbose(msg), (msg) => request.Debug(msg)); // The link is not valid if (response == null || !response.IsSuccessStatusCode) { return null; } return query; }
/// <summary> /// Returns the package dependencies of packageItem. We only return the dependencies that are not installed in the destination folder of request /// </summary> /// <param name="packageItem"></param> /// <param name="request"></param> private static IEnumerable<PackageItem> GetPackageDependenciesHelper(PackageItem packageItem, NuGetRequest request) { if (packageItem.Package.DependencySetList == null) { yield break; } foreach (var depSet in packageItem.Package.DependencySetList) { if (depSet.Dependencies == null) { continue; } foreach (var dep in depSet.Dependencies) { // Get the min dependencies version string minVersion = dep.DependencyVersion.MinVersion.ToStringSafe(); // Get the max dependencies version string maxVersion = dep.DependencyVersion.MaxVersion.ToStringSafe(); // check whether it is already installed at the destination if (request.GetInstalledPackages(dep.Id, null, minVersion, maxVersion, minInclusive: dep.DependencyVersion.IsMinInclusive, maxInclusive: dep.DependencyVersion.IsMaxInclusive, terminateFirstFound: true)) { request.Verbose(String.Format(CultureInfo.CurrentCulture, Messages.AlreadyInstalled, dep.Id)); // already have a dependency so move on continue; } // get all the packages that match this dependency var dependentPackageItem = request.GetPackageById(dep.Id, request, minimumVersion: minVersion, maximumVersion: maxVersion, minInclusive: dep.DependencyVersion.IsMinInclusive, maxInclusive: dep.DependencyVersion.IsMaxInclusive).ToArray(); if (dependentPackageItem.Length == 0) { request.WriteError(ErrorCategory.ObjectNotFound, dep.Id, Constants.Messages.UnableToFindDependencyPackage, dep.Id); break; } // Get the package that is the latest version yield return dependentPackageItem.OrderByDescending(each => each.Version).FirstOrDefault(); } } }
/// <summary> /// Download a package that matches the given version and name and install it on the local system. /// </summary> /// <param name="packageName">Package name</param> /// <param name="version">Package version</param> /// <param name="request">An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it </param> /// <param name="source">Package source</param> /// <param name="queryUrl">Full uri</param> /// <param name="packageHash">the hash of the package</param> /// <param name="packageHashAlgorithm">the hash algorithm of the package</param> /// <returns>PackageItem object</returns> internal static PackageItem InstallPackage( string packageName, string version, NuGetRequest request, PackageSource source, string queryUrl, string packageHash, string packageHashAlgorithm ) { request.Debug(Messages.DebugInfoCallMethod, "NuGetClient", "InstallPackage"); //If the destination folder does not exists, create it string destinationPath = request.Destination; request.Verbose(string.Format(CultureInfo.InvariantCulture, "InstallPackage' - name='{0}', version='{1}',destination='{2}'", packageName, version, destinationPath)); string directoryToDeleteWhenFailed = string.Empty; bool needToDelete = false; string installFullPath = string.Empty; try { if (!Directory.Exists(destinationPath)) { Directory.CreateDirectory(destinationPath); // delete the destinationPath later on if we fail to install and if destinationPath did not exist before directoryToDeleteWhenFailed = destinationPath; } //Create a folder under the destination path to hold the package string installDir = FileUtility.MakePackageDirectoryName(request.ExcludeVersion.Value, destinationPath, packageName, version); if (!Directory.Exists(installDir)) { Directory.CreateDirectory(installDir); // if directoryToDeleteWhenFailed is null then the destinationPath already exists before so we should not delete it if (String.IsNullOrWhiteSpace(directoryToDeleteWhenFailed)) { directoryToDeleteWhenFailed = installDir; } } //Get the package file name based on the version and id string fileName = FileUtility.MakePackageFileName(request.ExcludeVersion.Value, packageName, version); installFullPath = Path.Combine(installDir, fileName); //download to fetch the package DownloadPackage(packageName, version, installFullPath, queryUrl, request); // check that we have the file if (!File.Exists(installFullPath)) { needToDelete = true; request.WriteError(ErrorCategory.ResourceUnavailable, installFullPath, Constants.Messages.PackageFailedInstallOrDownload, packageName, CultureInfo.CurrentCulture.TextInfo.ToLower(Constants.Install)); return null; } #region verify hash //we don't enable checking for hash here because it seems like nuget provider does not //checks that there is hash. Otherwise we don't carry out the install if (string.IsNullOrWhiteSpace(packageHash) || string.IsNullOrWhiteSpace(packageHashAlgorithm)) { // delete the file downloaded. VIRUS!!! needToDelete = true; request.WriteError(ErrorCategory.SecurityError, packageName, Constants.Messages.HashNotFound, packageName); return null; } // Verify the hash using (FileStream stream = File.OpenRead(installFullPath)) { HashAlgorithm hashAlgorithm = null; switch (packageHashAlgorithm.ToLowerInvariant()) { case "sha256": hashAlgorithm = SHA256.Create(); break; case "md5": hashAlgorithm = MD5.Create(); break; case "sha512": // Flows to default case // default to sha512 algorithm default: hashAlgorithm = SHA512.Create(); break; } if (hashAlgorithm == null) { // delete the file downloaded. VIRUS!!! needToDelete = true; request.WriteError(ErrorCategory.SecurityError, packageHashAlgorithm, Constants.Messages.HashNotSupported, packageHashAlgorithm); return null; } // compute the hash byte[] computedHash = hashAlgorithm.ComputeHash(stream); // convert the original hash we got from the feed byte[] downloadedHash = Convert.FromBase64String(packageHash); // if they are not equal, just issue out verbose because there is a current bug in backend // where editing the published module will result in a package with a different hash than the one // provided on the feed if (!Enumerable.SequenceEqual(computedHash, downloadedHash)) { // delete the file downloaded. VIRUS!!! request.Verbose(Constants.Messages.HashNotMatch, packageName); } //parse the package var pkgItem = InstallPackageLocal(packageName, version, request, source, installFullPath); return pkgItem; } #endregion } catch (Exception e) { request.Debug(e.Message); needToDelete = true; } finally { if (needToDelete) { // if the directory exists just delete it because it will contains the file as well if (!String.IsNullOrWhiteSpace(directoryToDeleteWhenFailed) && Directory.Exists(directoryToDeleteWhenFailed)) { try { FileUtility.DeleteDirectory(directoryToDeleteWhenFailed, true, isThrow: false); } catch { } } // if for some reason, we can't delete the directory or if we don't need to delete the directory // then we have to delete installFullPath if (File.Exists(installFullPath)) { FileUtility.DeleteFile(installFullPath, isThrow: false); } } } return null; }
/// <summary> /// Install a single package. Also install any of its dependency if they are available (the dependency will be installed first). /// For dependencies, we will only get those that are not installed. /// Operation is either install or download /// installOrDownloadFunction is a function that takes in a packageitem and performs either install or download on it /// </summary> /// <param name="pkgItem"></param> /// <param name="request"></param> /// <param name="operation"></param> /// <param name="installOrDownloadFunction"></param> /// <returns></returns> internal static bool InstallOrDownloadPackageHelper(PackageItem pkgItem, NuGetRequest request, string operation, Func<PackageItem, bool> installOrDownloadFunction) { // pkgItem.Sources is the source that the user input. The request will try this source. request.OriginalSources = pkgItem.Sources; int progressId = 0; bool hasDependencyLoop = false; // Get the dependencies that are not already installed var dependencies = NuGetClient.GetPackageDependenciesToInstall(request, pkgItem, ref hasDependencyLoop).ToArray(); // If there is a dependency loop. Warn the user and don't install the package if (hasDependencyLoop) { // package itself didn't install. Report error request.WriteError(ErrorCategory.DeadlockDetected, pkgItem.Id, Constants.Messages.DependencyLoopDetected, pkgItem.Id); return false; } // request may get canceled if there is a package dependencies missing if (request.IsCanceled) { return false; } int n = 0; int numberOfDependencies = dependencies.Count(); // Start progress progressId = request.StartProgress(0, string.Format(CultureInfo.InvariantCulture, Messages.InstallingOrDownloadingPackage, operation, pkgItem.Id)); try { // check that this package has dependency and the user didn't want to skip dependencies if (numberOfDependencies > 0) { // let's install dependencies foreach (var dep in dependencies) { request.Progress(progressId, (n * 100 / (numberOfDependencies + 1)) + 1, string.Format(CultureInfo.InvariantCulture, Messages.InstallingOrDownloadingDependencyPackage, operation, dep.Id)); // Check that we successfully installed the dependency if (!installOrDownloadFunction(dep)) { request.WriteError(ErrorCategory.InvalidResult, dep.Id, Constants.Messages.DependentPackageFailedInstallOrDownload, dep.Id, CultureInfo.CurrentCulture.TextInfo.ToLower(operation)); return false; } n++; request.Progress(progressId, (n * 100 / (numberOfDependencies + 1)), string.Format(CultureInfo.InvariantCulture, Messages.InstalledOrDownloadedDependencyPackage, operation, dep.Id)); } } // Now let's install the main package if (installOrDownloadFunction(pkgItem)) { return true; } } catch (Exception ex) { ex.Dump(request); } finally { // Report that we have completed installing the package and its dependency this does not mean there are no errors. // Just that it's completed. request.CompleteProgress(progressId, false); } // package itself didn't install. Report error request.WriteError(ErrorCategory.InvalidResult, pkgItem.Id, Constants.Messages.PackageFailedInstallOrDownload, pkgItem.Id, CultureInfo.CurrentCulture.TextInfo.ToLower(operation)); return false; }
/// <summary> /// Download a single package to destination without checking for dependencies /// </summary> /// <param name="pkgItem"></param> /// <param name="request"></param> /// <param name="destLocation"></param> /// <returns></returns> internal static bool DownloadSinglePackage(PackageItem pkgItem, NuGetRequest request, string destLocation) { if (string.IsNullOrWhiteSpace(pkgItem.PackageFilename) || pkgItem.PackageSource == null || pkgItem.PackageSource.Location == null || (pkgItem.PackageSource.IsSourceAFile && pkgItem.Package == null)) { request.WriteError(ErrorCategory.ObjectNotFound, pkgItem.Id, Constants.Messages.UnableToResolvePackage, pkgItem.Id); return false; } // this is if the user says -force bool force = request.GetOptionValue("Force") != null; // combine the path and the file name destLocation = Path.Combine(destLocation, pkgItem.PackageFilename); // if the file already exists if (File.Exists(destLocation)) { // if no force, just return if (!force) { request.Verbose(Constants.Messages.SkippedDownloadedPackage, pkgItem.Id); request.YieldPackage(pkgItem, pkgItem.PackageSource.Name); return true; } // here we know it is forced, so delete FileUtility.DeleteFile(destLocation, isThrow: false); // if after we try delete, it is still there, tells the user we can't perform the action if (File.Exists(destLocation)) { request.WriteError(ErrorCategory.ResourceUnavailable, destLocation, Constants.Messages.UnableToOverwriteExistingFile, destLocation); return false; } } try { if (pkgItem.PackageSource.Repository.IsFile) { using (var input = File.OpenRead(pkgItem.Package.FullFilePath)) { using (var output = new FileStream(destLocation, FileMode.Create, FileAccess.Write, FileShare.Read)) { input.CopyTo(output); } } } else { //V2 download package protocol: //sample url: http://www.nuget.org/api/v2/package/jQuery/2.1.3 string append = String.Format(CultureInfo.InvariantCulture, "/package/{0}/{1}", pkgItem.Id, pkgItem.Version); string httpquery = PathUtility.UriCombine(pkgItem.PackageSource.Repository.Source, append); NuGetClient.DownloadPackage(pkgItem.Id, pkgItem.Version, destLocation, string.IsNullOrWhiteSpace(pkgItem.Package.ContentSrcUrl) ? httpquery : pkgItem.Package.ContentSrcUrl, request); } } catch (Exception ex) { ex.Dump(request); return false; } request.Verbose(Resources.Messages.SuccessfullyDownloaded, pkgItem.Id); request.YieldPackage(pkgItem, pkgItem.PackageSource.Name); return true; }
/// <summary> /// Returns the package dependencies of packageItem. We only return the dependencies that are not installed in the destination folder of request /// </summary> /// <param name="packageItem"></param> /// <param name="processedDependencies"></param> /// <param name="request"></param> private static IEnumerable<PackageItem> GetPackageDependenciesHelper(PackageItem packageItem, HashSet<string> processedDependencies, NuGetRequest request) { if (packageItem.Package.DependencySetList == null) { yield break; } bool force = request.GetOptionValue("Force") != null; foreach (var depSet in packageItem.Package.DependencySetList) { if (depSet.Dependencies == null) { continue; } foreach (var dep in depSet.Dependencies) { var depKey = string.Format(CultureInfo.InvariantCulture, "{0}!#!{1}", dep.Id, dep.DependencyVersion.ToStringSafe()); if (processedDependencies.Contains(depKey)) { continue; } // Get the min dependencies version string minVersion = dep.DependencyVersion.MinVersion.ToStringSafe(); // Get the max dependencies version string maxVersion = dep.DependencyVersion.MaxVersion.ToStringSafe(); if (!force) { bool installed = false; var installedPackages = request.InstalledPackages.Value; if (request.InstalledPackages.Value.Count() > 0) { // check the installedpackages options passed in foreach (var installedPackage in request.InstalledPackages.Value) { // if name not match, move on to the next entry if (!string.Equals(installedPackage.Id, dep.Id, StringComparison.OrdinalIgnoreCase)) { continue; } // if no version and if name matches, skip if (string.IsNullOrWhiteSpace(installedPackage.Version)) { // skip this dependency installed = true; break; } SemanticVersion packageVersion = new SemanticVersion(installedPackage.Version); // checks min and max if (request.MinAndMaxVersionMatched(packageVersion, minVersion, maxVersion, dep.DependencyVersion.IsMinInclusive, dep.DependencyVersion.IsMaxInclusive)) { // skip this dependency installed = true; break; } } } // check whether package is installed at destination. only used this option if installedpackages not passed in else if (request.GetInstalledPackages(dep.Id, null, minVersion, maxVersion, minInclusive: dep.DependencyVersion.IsMinInclusive, maxInclusive: dep.DependencyVersion.IsMaxInclusive, terminateFirstFound: true)) { installed = true; } if (installed) { // already processed this so don't need to do this next time processedDependencies.Add(dep.Id); request.Verbose(String.Format(CultureInfo.CurrentCulture, Messages.AlreadyInstalled, dep.Id)); // already have a dependency so move on continue; } } // get all the packages that match this dependency var dependentPackageItem = request.GetPackageById(dep.Id, request, minimumVersion: minVersion, maximumVersion: maxVersion, minInclusive: dep.DependencyVersion.IsMinInclusive, maxInclusive: dep.DependencyVersion.IsMaxInclusive).ToArray(); if (dependentPackageItem.Length == 0) { request.WriteError(ErrorCategory.ObjectNotFound, dep.Id, Constants.Messages.UnableToFindDependencyPackage, dep.Id); break; } // Get the package that is the latest version yield return dependentPackageItem.OrderByDescending(each => each.Version).FirstOrDefault(); processedDependencies.Add(depKey); } } }