PowerShell/src/Microsoft.PackageManagement.NuGetProvider/NugetLightRequest.cs
PowerShell Team c748652c34 Copy all mapped files from [SD:725290]
commit 8cec8f150da7583b7af5efbe2853efee0179750c
2016-07-28 23:23:03 -07:00

1722 lines
73 KiB
C#

namespace Microsoft.PackageManagement.NuGetProvider
{
using System;
using System.Text;
using System.Net.Http;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using Resources;
using System.Security.Cryptography;
using System.Security;
using System.Runtime.InteropServices;
using System.Net;
using Microsoft.PackageManagement.Provider.Utility;
/// <summary>
/// This class drives the Request class that is an interface exposed from the PackageManagement Platform to the provider to use.
/// </summary>
public abstract class NuGetRequest : Request {
private static readonly Regex _regexFastPath = new Regex(@"\$(?<source>[\w,\+,\/,=]*)\\(?<id>[\w,\+,\/,=]*)\\(?<version>[\w,\+,\/,=]*)\\(?<sources>[\w,\+,\/,=]*)");
private static readonly byte[] _nugetBytes = Encoding.UTF8.GetBytes("NuGet");
private string _configurationFileLocation;
private XDocument _config;
internal readonly Lazy<bool> AllowPrereleaseVersions;
internal readonly Lazy<bool> AllVersions;
internal readonly Lazy<string> Contains;
internal readonly Lazy<bool> ExcludeVersion;
internal readonly Lazy<string[]> FilterOnTag;
internal readonly Lazy<string[]> Headers;
internal readonly Lazy<string> Scope;
internal readonly Lazy<PackageBase[]> InstalledPackages;
private static IDictionary<string, PackageSource> _registeredPackageSources;
private static IDictionary<string, PackageSource> _checkedUnregisteredPackageSources = new ConcurrentDictionary<string, PackageSource>();
private string _destinationPath = null;
internal Lazy<bool> SkipValidate; //??? Seems to be a design choice. Why let a user to decide?
// we cannot enable skipdepedencies because this will break downlevel psget which sets skipdependencies to true
//internal Lazy<bool> SkipDependencies;
//internal ImplictLazy<bool> ContinueOnFailure;
//internal ImplictLazy<bool> FindByCanonicalId;
private HttpClient _httpClient;
private HttpClient _httpClientWithoutAcceptHeader;
internal const string DefaultConfig = @"<?xml version=""1.0""?>
<configuration>
<packageSources>
</packageSources>
</configuration>";
/// <summary>
/// Ctor required by the PackageManagement Platform
/// </summary>
protected NuGetRequest() {
FilterOnTag = new Lazy<string[]>(() => (GetOptionValues("FilterOnTag") ?? new string[0]).ToArray());
Contains = new Lazy<string>(() => GetOptionValue("Contains"));
ExcludeVersion = new Lazy<bool>(() => GetOptionValue("ExcludeVersion").IsTrue());
AllowPrereleaseVersions = new Lazy<bool>(() => GetOptionValue("AllowPrereleaseVersions").IsTrue());
AllVersions = new Lazy<bool>(() => GetOptionValue("AllVersions").IsTrue());
SkipValidate = new Lazy<bool>(() => GetOptionValue("SkipValidate").IsTrue());
Scope = new Lazy<string>(() => GetOptionValue("Scope"));
//SkipDependencies = new Lazy<bool>(() => GetOptionValue("SkipDependencies").IsTrue());
//ContinueOnFailure = new ImplictLazy<bool>(() => GetOptionValue("ContinueOnFailure").IsTrue());
//FindByCanonicalId = new ImplictLazy<bool>(() => GetOptionValue("FindByCanonicalId").IsTrue());
Headers = new Lazy<string[]>(() => (GetOptionValues("Headers") ?? new string[0]).ToArray());
InstalledPackages = new Lazy<PackageBase[]>(() => (GetInstalledPackagesOptionValue()).ToArray());
}
// parse the list of installed packages
private IEnumerable<PackageBase> GetInstalledPackagesOptionValue()
{
// get possible installed packages
var installedPackages = GetOptionValues("InstalledPackages") ?? new string[0];
// parse the installed package options passed in
foreach (var installedPackage in installedPackages)
{
// we assume that the name passed in is something like jquery#1.2.5
string[] nameAndVersion = installedPackage.Split(new[] { "!#!" }, StringSplitOptions.None);
var package = new PackageBase();
// only name passed in, no version
if (nameAndVersion.Count() == 1)
{
package.Id = nameAndVersion[0];
yield return package;
}
else if (nameAndVersion.Count() == 2)
{
// this means there is version
SemanticVersion semVers = null;
try
{
// convert version to semvers
semVers = new SemanticVersion(nameAndVersion[1]);
}
catch
{
// not a valid version, ignores this entry
continue;
}
// set name and version of this installed packages
package.Id = nameAndVersion[0];
package.Version = semVers.Version.ToStringSafe();
yield return package;
}
}
}
/// <summary>
/// Package sources
/// </summary>
internal string[] OriginalSources {get; set;}
/// <summary>
/// Package installation location used by get-installedpackages.
/// </summary>
internal IEnumerable<string> InstalledPath
{
get
{
var path = GetOptionValue("Destination");
if (!string.IsNullOrWhiteSpace(path))
{
yield return Path.GetFullPath(path);
}
else
{
// If a user does not specify -destination, we will look into the default locations.
yield return AllUserDefaultInstallLocation;
yield return CurrentUserDefaultInstallLocation;
}
}
}
/// <summary>
/// Package destination path
/// </summary>
internal string Destination {
get {
if (_destinationPath != null)
{
return _destinationPath;
}
var path = GetOptionValue("Destination");
if (!string.IsNullOrWhiteSpace(path))
{
_destinationPath = Path.GetFullPath(path);
return _destinationPath;
}
// If a user does not give -destination for the install, we put the package under $env:USERPROFILE\nuget\packages folder
// or $env:programfiles\NuGet\Packages\ if you are an admin.
try
{
var scope = (Scope == null) ? null : Scope.Value;
scope = string.IsNullOrWhiteSpace(scope) ? Constants.AllUsers : scope;
string basePath;
if (scope.EqualsIgnoreCase(Constants.CurrentUser))
{
// Does not matter whether elevated or not
basePath = CurrentUserDefaultInstallLocation;
}
else if (ProviderServices.IsElevated)
{
//Scope=AllUser or No Scope but elevated
basePath = AllUserDefaultInstallLocation;
}
else
{
//Scope=AllUser but not elevated
WriteError(ErrorCategory.InvalidOperation, ErrorCategory.InvalidOperation.ToString(),
Constants.Messages.InstallRequiresCurrentUserScopeParameterForNonAdminUser, AllUserDefaultInstallLocation, CurrentUserDefaultInstallLocation);
return string.Empty;
}
if (!Directory.Exists(basePath))
{
Directory.CreateDirectory(basePath);
}
_destinationPath = basePath;
return basePath;
}
catch (Exception e)
{
e.Dump(this);
WriteError(ErrorCategory.InvalidArgument, "Destination", Constants.Messages.MissingRequiredParameter, "Destination");
return string.Empty;
}
}
}
internal string CurrentUserDefaultInstallLocation
{
get
{
#if CORECLR
return Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "PackageManagement", "NuGet", "Packages");
#else
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "PackageManagement", "NuGet", "Packages");
#endif
}
}
internal string AllUserDefaultInstallLocation
{
get
{
#if CORECLR
return Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles"), "NuGet", "Packages");
#else
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "NuGet", "Packages");
#endif
}
}
/// <summary>
/// Get the PackageItem object from the fast path
/// </summary>
/// <param name="fastPath"></param>
/// <returns></returns>
internal PackageItem GetPackageByFastpath(string fastPath) {
Debug(Resources.Messages.DebugInfoCallMethod3, "NuGetRequest", "GetPackageByFastpath", fastPath);
string sourceLocation;
string id;
string version;
string[] sources;
if (TryParseFastPath(fastPath, out sourceLocation, out id, out version, out sources)) {
var source = ResolvePackageSource(sourceLocation);
if (source.IsSourceAFile) {
return GetPackageByFilePath(sourceLocation);
}
// repository should not be null if source is not a file
if (source.Repository == null)
{
return null;
}
// Have to find package again to get possible dependencies
var pkg = source.Repository.FindPackage(id, new SemanticVersion(version), this);
// only finds the pkg if it is a file. so we don't return it here
// otherwise we make another download request
return new PackageItem {
FastPath = fastPath,
Package = pkg,
PackageSource = source,
Sources = sources
};
}
return null;
}
/// <summary>
/// Get a package object from the package manifest file
/// </summary>
/// <param name="filePath">package manifest file path</param>
/// <param name="packageName">package Id or Name</param>
/// <returns></returns>
internal PackageItem GetPackageByFilePath(string filePath, string packageName)
{
Debug(Resources.Messages.DebugInfoCallMethod3, "GetPackageByFilePath", filePath, packageName);
PackageBase package = null;
try {
if (NuGetPathUtility.IsManifest(filePath)) {
//.nuspec
package = PackageUtility.ProcessNuspec(filePath);
} else if (NuGetPathUtility.IsPackageFile(filePath)) {
//.nupkg or .zip
//The file name may contains version. ex: jQuery.2.1.1.nupkg
package = PackageUtility.DecompressFile(filePath, packageName);
} else {
Warning(Resources.Messages.InvalidFileExtension, filePath);
}
} catch (Exception ex) {
ex.Dump(this);
}
if (package == null) {
return null;
}
var source = ResolvePackageSource(filePath);
return new PackageItem {
FastPath = MakeFastPath(source, package.Id, package.Version),
PackageSource = source,
Package = package,
IsPackageFile = true,
FullPath = filePath,
};
}
/// <summary>
/// Get a package object from the package manifest file
/// </summary>
/// <param name="filePath">package manifest file path</param>
/// <returns></returns>
internal PackageItem GetPackageByFilePath(string filePath) {
Debug(Resources.Messages.DebugInfoCallMethod3, "NuGetRequest", "GetPackageByFilePath", filePath);
var packageName = Path.GetFileNameWithoutExtension(filePath);
var pkgItem = GetPackageByFilePath(filePath, packageName);
return pkgItem;
}
/// <summary>
/// Unregister the package source
/// </summary>
/// <param name="id">package source id or name</param>
internal void RemovePackageSource(string id) {
Debug(Resources.Messages.DebugInfoCallMethod3, "NuGetRequest", "RemovePackageSource", id);
var config = Config;
if (config == null) {
return;
}
try {
XElement configuration = config.ElementsNoNamespace("configuration").FirstOrDefault();
if (configuration == null)
{
return;
}
XElement packageSources = configuration.ElementsNoNamespace("packageSources").FirstOrDefault();
if (packageSources == null)
{
return;
}
var nodes = packageSources.Elements("add");
if (nodes == null) {
return;
}
foreach (XElement node in nodes) {
if (node.Attribute("key") != null && String.Equals(node.Attribute("key").Value, id, StringComparison.OrdinalIgnoreCase)) {
// remove itself
node.Remove();
Config = config;
Verbose(Resources.Messages.RemovedPackageSource, id);
break;
}
}
if (_registeredPackageSources.ContainsKey(id))
{
_registeredPackageSources.Remove(id);
}
if (_checkedUnregisteredPackageSources.ContainsKey(id))
{
_checkedUnregisteredPackageSources.Remove(id);
}
//var source = config.SelectNodes("/configuration/packageSources/add").Cast<XmlNode>().FirstOrDefault(node => String.Equals(node.Attributes["key"].Value, id, StringComparison.CurrentCultureIgnoreCase));
//if (source != null)
//{
// source.ParentNode.RemoveChild(source);
// Config = config;
// Verbose(Resources.Messages.RemovedPackageSource, id);
//}
} catch (Exception ex) {
ex.Dump(this);
}
}
/// <summary>
/// Register the package source
/// </summary>
/// <param name="name">package source name</param>
/// <param name="location">package source location</param>
/// <param name="isTrusted">is the source trusted</param>
/// <param name="isValidated">need validate before storing the information to config file</param>
internal void AddPackageSource(string name, string location, bool isTrusted, bool isValidated) {
Debug(Resources.Messages.DebugInfoCallMethod, "NuGetRequest", string.Format(CultureInfo.InvariantCulture, "AddPackageSource - name= {0}, location={1}", name, location));
try {
// here the source is already validated by the caller
var config = Config;
if (config == null) {
return;
}
XElement source = null;
XElement packageSources = null;
// Check whether there is an existing node with the same name
var configuration = config.ElementsNoNamespace("configuration").FirstOrDefault();
if (configuration != null)
{
packageSources = configuration.ElementsNoNamespace("packageSources").FirstOrDefault();
if (packageSources != null)
{
source = packageSources.Elements("add").FirstOrDefault(node =>
node.Attribute("key") != null && String.Equals(node.Attribute("key").Value, name, StringComparison.OrdinalIgnoreCase));
}
}
else
{
// create configuration node if it does not exist
configuration = new XElement("configuration");
// add that to the config
config.Add(configuration);
}
// There is no existing node with the same name. So we have to create one.
if (source == null)
{
// if packagesources is null we have to create that too
if (packageSources == null)
{
// create packagesources node
packageSources = new XElement("packageSources");
// add that to the config
configuration.Add(packageSources);
}
// Create new source
source = new XElement("add");
// Add that to packagesource
packageSources.Add(source);
}
// Now set the source node properties
source.SetAttributeValue("key", name);
source.SetAttributeValue("value", location);
if (isValidated)
{
source.SetAttributeValue("validated", true.ToString());
}
if (isTrusted)
{
source.SetAttributeValue("trusted", true.ToString());
}
// Write back to the config file
Config = config;
// Add or set the source node from the dictionary depends on whether it was there
if (_registeredPackageSources.ContainsKey(name))
{
var packageSource = _registeredPackageSources[name];
packageSource.Name = name;
packageSource.Location = location;
packageSource.Trusted = isTrusted;
packageSource.IsRegistered = true;
packageSource.IsValidated = isValidated;
}
else
{
_registeredPackageSources.Add(name, new PackageSource
{
Request = this,
Name = name,
Location = location,
Trusted = isTrusted,
IsRegistered = true,
IsValidated = isValidated,
});
}
} catch (Exception ex) {
ex.Dump(this);
}
}
/// <summary>
/// Check if the package source location is valid
/// </summary>
/// <param name="location"></param>
/// <returns></returns>
internal bool ValidateSourceLocation(string location) {
Debug(Resources.Messages.DebugInfoCallMethod3, "NuGetRequest", "ValidateSourceLocation", location);
//Handling http: or file: cases
if (Uri.IsWellFormedUriString(location, UriKind.Absolute)) {
return NuGetPathUtility.ValidateSourceUri(SupportedSchemes, new Uri(location), this);
}
try {
//UNC or local file
if (Directory.Exists(location) || File.Exists(location)) {
return true;
}
} catch {
}
return false;
}
/// <summary>
/// Supported package source schemes by this provider
/// </summary>
internal static IEnumerable<string> SupportedSchemes {
get {
return NuGetProvider.Features[Constants.Features.SupportedSchemes];
}
}
/// <summary>
/// Return the package source object
/// </summary>
/// <param name="name">The package source name to search for</param>
/// <returns>package source object</returns>
internal PackageSource FindRegisteredSource(string name) {
Debug(Resources.Messages.DebugInfoCallMethod3, "NuGetRequest", "FindRegisteredSource", name);
var srcs = RegisteredPackageSources;
if (srcs == null) {
return null;
}
if (srcs.ContainsKey(name)) {
return srcs[name];
}
var src = srcs.Values.FirstOrDefault(each => LocationCloseEnoughMatch(name, each.Location));
return src;
}
/// <summary>
/// Communicate to the PackageManagement platform about the package info
/// </summary>
/// <param name="packageReferences"></param>
/// <param name="searchKey"></param>
/// <returns></returns>
internal bool YieldPackages(IEnumerable<PackageItem> packageReferences, string searchKey) {
var foundPackage = false;
if (packageReferences == null) {
return false;
}
Debug(Resources.Messages.Iterating, searchKey);
IEnumerable<PackageItem> packageItems = packageReferences;
int count = 0;
foreach (var pkg in packageItems) {
foundPackage = true;
try {
if (!YieldPackage(pkg, searchKey)) {
break;
}
count++;
} catch (Exception e) {
e.Dump(this);
return false;
}
}
Verbose(Resources.Messages.TotalPackageYield, count, searchKey);
Debug(Resources.Messages.CompletedIterating, searchKey);
return foundPackage;
}
private string MakeTagId(PackageItem pkg)
{
if (pkg == null || pkg.Package == null)
{
return string.Empty;
}
// the tag id will look like this zlib#1.2.8.8#Jean-loup Gailly;Mark Adler
return string.Format(CultureInfo.CurrentCulture, "{0}#{1}", pkg.Package.Id, pkg.Package.Version.ToString());
}
/// <summary>
/// HttpClient with Accept-CharSet and Accept-Encoding Header
/// We want to reuse HttpClient
/// </summary>
internal HttpClient Client
{
get
{
if (_httpClient == null)
{
_httpClient = PathUtility.GetHttpClientHelper(CredentialUsername, CredentialPassword, WebProxy);
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Charset", "UTF-8");
// Request for gzip and deflate encoding to make the response lighter.
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Encoding", "gzip,deflate");
foreach (var header in Headers.Value)
{
// header is in the format "A=B" because OneGet doesn't support Dictionary parameters
if (!String.IsNullOrEmpty(header))
{
var headerSplit = header.Split(new string[] { "=" }, 2, StringSplitOptions.RemoveEmptyEntries);
// ignore wrong entries
if (headerSplit.Count() == 2)
{
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation(headerSplit[0], headerSplit[1]);
}
else
{
Warning(Messages.HeaderIgnored, header);
}
}
}
}
return _httpClient;
}
}
/// <summary>
/// HttpClient without any Accept header (this will only have User-Agent header)
/// </summary>
internal HttpClient ClientWithoutAcceptHeader
{
get
{
if (_httpClientWithoutAcceptHeader == null)
{
_httpClientWithoutAcceptHeader = PathUtility.GetHttpClientHelper(CredentialUsername, CredentialPassword, WebProxy);
}
return _httpClientWithoutAcceptHeader;
}
}
/// <summary>
/// Communicate to the PackageManagement platform about the package info
/// </summary>
/// <param name="pkg"></param>
/// <param name="searchKey"></param>
/// <param name="destinationPath"></param>
/// <returns></returns>
internal bool YieldPackage(PackageItem pkg, string searchKey, string destinationPath=null)
{
try
{
if (YieldSoftwareIdentity(pkg.FastPath, pkg.Package.Id, pkg.Package.Version.ToString(), "semver", pkg.Package.Summary, pkg.PackageSource.Name, searchKey, pkg.FullPath, pkg.PackageFilename) != null)
{
if (pkg.Package.DependencySetList != null)
{
//iterate thru the dependencies and add them to the software identity.
foreach (PackageDependencySet depSet in pkg.Package.DependencySetList)
{
foreach (var dep in depSet.Dependencies)
{
AddDependency(NuGetConstant.ProviderName, dep.Id, dep.DependencyVersion.ToStringSafe(), null, null);
}
}
}
// downlevel machine does not have AddTagId interface in request object so it will return null
// hence we can't check it here.
AddTagId(MakeTagId(pkg));
// if we need to report installation location, add a payload and add directory to that
if (!string.IsNullOrWhiteSpace(destinationPath))
{
string payload = AddPayload();
if (string.IsNullOrWhiteSpace(payload))
{
return false;
}
AddDirectory(payload, Path.GetFileName(destinationPath), Path.GetDirectoryName(destinationPath), null, true);
}
if (AddMetadata(pkg.FastPath, "copyright", pkg.Package.Copyright) == null) {
return false;
}
if (AddMetadata(pkg.FastPath, "description", pkg.Package.Description) == null) {
return false;
}
if (AddMetadata(pkg.FastPath, "licenseNames", pkg.Package.LicenseNames) == null)
{
return false;
}
if (AddMetadata(pkg.FastPath, "requireLicenseAcceptance", pkg.Package.RequireLicenseAcceptance.ToString()) == null)
{
return false;
}
if (AddMetadata(pkg.FastPath, "language", pkg.Package.Language) == null) {
return false;
}
if (AddMetadata(pkg.FastPath, "releaseNotes", pkg.Package.ReleaseNotes) == null) {
return false;
}
if (AddMetadata(pkg.FastPath, "isLatestVersion", pkg.Package.IsLatestVersion.ToString()) == null)
{
return false;
}
if (AddMetadata(pkg.FastPath, "isAbsoluteLatestVersion", pkg.Package.IsAbsoluteLatestVersion.ToString()) == null)
{
return false;
}
if (pkg.Package.MinClientVersion != null && AddMetadata(pkg.FastPath, "minClientVersion", pkg.Package.MinClientVersion.ToString()) == null)
{
return false;
}
if (pkg.Package.VersionDownloadCount != -1)
{
if (AddMetadata(pkg.FastPath, "versionDownloadCount", pkg.Package.VersionDownloadCount.ToString(CultureInfo.CurrentCulture)) == null)
{
return false;
}
}
if (pkg.Package.DownloadCount != -1)
{
if (AddMetadata(pkg.FastPath, "downloadCount", pkg.Package.DownloadCount.ToString(CultureInfo.CurrentCulture)) == null)
{
return false;
}
}
if (pkg.Package.PackageSize != -1)
{
if (AddMetadata(pkg.FastPath, "packageSize", pkg.Package.PackageSize.ToString(CultureInfo.CurrentCulture)) == null)
{
return false;
}
}
if (pkg.Package.Published != null) {
if (AddMetadata(pkg.FastPath, "published", pkg.Package.Published.ToString()) == null) {
return false;
}
}
if (pkg.Package.Created != null)
{
if (AddMetadata(pkg.FastPath, "created", pkg.Package.Created.ToString()) == null)
{
return false;
}
}
if (pkg.Package.LastEdited != null)
{
if (AddMetadata(pkg.FastPath, "lastEdited", pkg.Package.LastEdited.ToString()) == null)
{
return false;
}
}
if (pkg.Package.LastUpdated != null)
{
if (AddMetadata(pkg.FastPath, "lastUpdated", pkg.Package.LastUpdated.ToString()) == null)
{
return false;
}
}
if (AddMetadata(pkg.FastPath, "tags", pkg.Package.Tags) == null) {
return false;
}
if (AddMetadata(pkg.FastPath, "title", pkg.Package.Title) == null) {
return false;
}
if (AddMetadata(pkg.FastPath, "developmentDependency", pkg.Package.DevelopmentDependency.ToString()) == null) {
return false;
}
if (AddMetadata(pkg.FastPath, "FromTrustedSource", pkg.PackageSource.Trusted.ToString()) == null) {
return false;
}
if (pkg.Package.LicenseUrl != null && !String.IsNullOrWhiteSpace(pkg.Package.LicenseUrl.ToString()))
{
if (AddLink(pkg.Package.LicenseUrl, "license", null, null, null, null, null) == null) {
return false;
}
}
if (pkg.Package.ProjectUrl != null && !String.IsNullOrWhiteSpace(pkg.Package.ProjectUrl.ToString()))
{
if (AddLink(pkg.Package.ProjectUrl, "project", null, null, null, null, null) == null) {
return false;
}
}
if (pkg.Package.ReportAbuseUrl != null && !String.IsNullOrWhiteSpace(pkg.Package.ReportAbuseUrl.ToString()))
{
if (AddLink(pkg.Package.ReportAbuseUrl, "abuse", null, null, null, null, null) == null) {
return false;
}
}
if (pkg.Package.IconUrl != null && !String.IsNullOrWhiteSpace(pkg.Package.IconUrl.ToString()))
{
if (AddLink(pkg.Package.IconUrl, "icon", null, null, null, null, null) == null) {
return false;
}
}
if (pkg.Package.GalleryDetailsUrl != null && !String.IsNullOrWhiteSpace(pkg.Package.GalleryDetailsUrl.ToString()))
{
if (AddLink(pkg.Package.GalleryDetailsUrl, "galleryDetails", null, null, null, null, null) == null)
{
return false;
}
}
if (pkg.Package.LicenseReportUrl != null && !String.IsNullOrWhiteSpace(pkg.Package.LicenseReportUrl.ToString()))
{
if (AddLink(pkg.Package.LicenseReportUrl, "licenseReport", null, null, null, null, null) == null)
{
return false;
}
}
if (pkg.Package.Authors.Any(author => AddEntity(author.Trim(), author.Trim(), "author", null) == null)) {
return false;
}
if (pkg.Package.Owners.Any(owner => AddEntity(owner.Trim(), owner.Trim(), "owner", null) == null)) {
return false;
}
var pkgBase = pkg.Package as PackageBase;
if (pkgBase != null)
{
if (pkgBase.AdditionalProperties != null)
{
foreach (var property in pkgBase.AdditionalProperties)
{
if (AddMetadata(pkg.FastPath, property.Key, property.Value) == null)
{
return false;
}
}
}
}
} else {
return false;
}
} catch (Exception e) {
e.Dump(this);
return false;
}
return true;
}
internal bool MinAndMaxVersionMatched(SemanticVersion packageVersion, string minimumVersion, string maximumVersion, bool minInclusive, bool maxInclusive)
{
if (!string.IsNullOrWhiteSpace(minimumVersion))
{
// Check whether we are checking for min inclusive version
if (minInclusive)
{
// version too small, not what we are looking for
if (packageVersion < new SemanticVersion(minimumVersion))
{
return false;
}
}
else
{
if (packageVersion <= new SemanticVersion(minimumVersion))
{
return false;
}
}
}
if (!string.IsNullOrWhiteSpace(maximumVersion))
{
// Check whether we are checking for max inclusive version
if (maxInclusive)
{
// version too big, not what we are looking for
if (packageVersion > new SemanticVersion(maximumVersion))
{
return false;
}
}
else
{
if (packageVersion >= new SemanticVersion(maximumVersion))
{
return false;
}
}
}
return true;
}
/// <summary>
/// Search in the destination of the request to checks whether the package name is installed.
/// Returns true if at least 1 package is installed
/// </summary>
/// <param name="name"></param>
/// <param name="requiredVersion"></param>
/// <param name="minimumVersion"></param>
/// <param name="maximumVersion"></param>
/// <param name="minInclusive"></param>
/// <param name="maxInclusive"></param>
/// <param name="terminateFirstFound"></param>
/// <returns></returns>
internal bool GetInstalledPackages(string name, string requiredVersion, string minimumVersion, string maximumVersion, bool minInclusive = true, bool maxInclusive = true, bool terminateFirstFound = false)
{
try
{
bool found = false;
var paths = InstalledPath.Where(Directory.Exists).ToArray();
// if directory does not exist then just return false
if (!paths.Any())
{
return false;
}
// look in the destination directory for directories that contain *.nupkg & .nuspec files.
var subdirs = paths.SelectMany(Directory.EnumerateDirectories);
foreach (var subdir in subdirs)
{
//reset the flag when we begin a folder
var isDup = false;
var nupkgs = Directory.EnumerateFiles(subdir, "*.nupkg", SearchOption.TopDirectoryOnly).Union(
Directory.EnumerateFiles(subdir, "*.nuspec", SearchOption.TopDirectoryOnly));
foreach (var pkgFile in nupkgs)
{
if (isDup)
{
continue;
}
//As the package name has to be in the installed file path, check if it is true
if (!String.IsNullOrWhiteSpace(name) && !NuGetProvider.IsNameMatch(name, pkgFile))
{
//not the right package
continue;
}
//unpack the package
var existFileName = Path.GetFileNameWithoutExtension(pkgFile);
var pkgItem = GetPackageByFilePath(pkgFile, existFileName);
if (pkgItem != null && pkgItem.IsInstalled)
{
//A user does not provide any package name in the commandeline, return them all
if (string.IsNullOrWhiteSpace(name))
{
isDup = true;
if (!YieldPackage(pkgItem, existFileName))
{
return found;
}
}
else
{
//check if the version matches
if (!string.IsNullOrWhiteSpace(requiredVersion))
{
if (pkgItem.Package.Version != new SemanticVersion(requiredVersion))
{
continue;
}
}
else
{
// if min and max version not matched
if (!MinAndMaxVersionMatched(pkgItem.Package.Version, minimumVersion, maximumVersion, minInclusive, maxInclusive))
{
continue;
}
if (terminateFirstFound)
{
// if we are searching for a name and terminatefirstfound is set to true, then returns here
return true;
}
}
//found the match
isDup = true;
YieldPackage(pkgItem, existFileName);
found = true;
} //end of else
} //end of if (pkgItem...)
} //end of foreach
}//end of foreach subfolder
return found;
}
catch (Exception ex)
{
ex.Dump(this);
return false;
}
}
/// <summary>
/// Get the package based on given package id
/// </summary>
/// <param name="name">Package id or name</param>
/// <param name="requiredVersion"></param>
/// <param name="minimumVersion"></param>
/// <param name="maximumVersion"></param>
/// <param name="maxInclusive"></param>
/// <param name="minInclusive"></param>
/// <param name="request"></param>
/// <returns></returns>
internal IEnumerable<PackageItem> GetPackageById(string name, NuGetRequest request, string requiredVersion = null,
string minimumVersion = null, string maximumVersion = null, bool minInclusive = true, bool maxInclusive = true) {
if (String.IsNullOrWhiteSpace(name))
{
return Enumerable.Empty<PackageItem>();
}
return SelectedSources.AsParallel().WithMergeOptions(ParallelMergeOptions.NotBuffered).SelectMany(source => GetPackageById(source, name, request, requiredVersion, minimumVersion, maximumVersion, minInclusive, maxInclusive));
}
/// <summary>
/// Encrypting a path containing package source location, id, version and source
/// </summary>
/// <param name="source">package source</param>
/// <param name="id">package id</param>
/// <param name="version">package version</param>
/// <returns></returns>
internal string MakeFastPath(PackageSource source, string id, string version) {
return String.Format(CultureInfo.InvariantCulture, @"${0}\{1}\{2}\{3}", source.Serialized, id.ToBase64(), version.ToBase64(), (Sources ?? new string[0]).Select(each => each.ToBase64()).SafeAggregate((current, each) => current + "|" + each));
}
/// <summary>
/// Return all registered package sources
/// </summary>
internal IEnumerable<PackageSource> SelectedSources {
get {
if (IsCanceled) {
yield break;
}
//get sources from user's input
var sources = (OriginalSources ?? Enumerable.Empty<string>()).Union(PackageSources ?? Enumerable.Empty<string>()).ToArray();
//get sources from config file that registered earlier
var pkgSources = RegisteredPackageSources;
Debug(Resources.Messages.RegisteredSources, pkgSources.Count, NuGetConstant.ProviderName);
//If a user does not provider -source, we use the registered ones
if (sources.Length == 0) {
// return them all.
foreach (var src in pkgSources.Values) {
Debug(src.Name);
// set the request of the registered one to the current request because it may have additional information like credential
src.Request = this;
yield return src;
}
yield break;
}
// otherwise, return package sources that match the items given.
foreach (var src in sources)
{
// Check whether we've already processed this item before
if (_checkedUnregisteredPackageSources.ContainsKey(src))
{
_checkedUnregisteredPackageSources[src].Request = this;
yield return _checkedUnregisteredPackageSources[src];
continue;
}
// check to see if we have a source with either that name
// or that URI first.
if (pkgSources.ContainsKey(src))
{
Debug(Resources.Messages.FoundRegisteredSource, src, NuGetConstant.ProviderName);
_checkedUnregisteredPackageSources.Add(src, pkgSources[src]);
pkgSources[src].Request = this;
yield return pkgSources[src];
continue;
}
var srcLoc = src;
var found = false;
foreach (var byLoc in pkgSources.Values)
{
// srcLoc does not match byLoc.Location, try to check for srcLoc with "/" appended at the end
if (!string.Equals(byLoc.Location, srcLoc, StringComparison.OrdinalIgnoreCase)
&& !string.Equals(byLoc.Location, string.Concat(srcLoc, "/"), StringComparison.OrdinalIgnoreCase)
&& !string.Equals(string.Concat(byLoc.Location, "/"), srcLoc, StringComparison.OrdinalIgnoreCase))
{
continue;
}
// in this case, do not store the srcLoc into the dictionary, otherwise, the provider may resolve http://www.nuget.org/api/v2 to some source with location
// http://www.nuget.org/api/v2/ and oneget will raise an error (it thinks we are dishonest :()
byLoc.Location = srcLoc;
// set request of byloc to this because this request may have credential information
byLoc.Request = this;
yield return byLoc;
found = true;
}
if (found)
{
continue;
}
Debug(Resources.Messages.NotFoundRegisteredSource, src, NuGetConstant.ProviderName);
// doesn't look like we have this as a source.
if (Uri.IsWellFormedUriString(src, UriKind.Absolute))
{
// we have been passed in an URI
var srcUri = new Uri(src);
if (SupportedSchemes.Contains(srcUri.Scheme.ToLower()))
{
// it's one of our supported uri types.
var isValidated = false;
if (!SkipValidate.Value)
{
try{
isValidated = NuGetPathUtility.ValidateSourceUri(SupportedSchemes, srcUri, this);
}
catch (Exception ex)
{
ex.Dump(this);
}
}
if (SkipValidate.Value || isValidated)
{
Debug(Resources.Messages.SuccessfullyValidated, src);
yield return new PackageSource
{
Request = this,
Location = srcUri.ToString(),
Name = srcUri.ToString(),
Trusted = false,
IsRegistered = false,
IsValidated = isValidated,
};
continue;
}
Warning(Constants.Messages.UnableToResolveSource, src);
continue;
}
// Not a valid location?
Warning(Constants.Messages.UnableToResolveSource, src);
continue;
}
// is it a file path?
if (Directory.Exists(src))
{
Debug(Resources.Messages.SourceIsADirectory, src);
PackageSource newSource = new PackageSource
{
Request = this,
Location = src,
Name = src,
Trusted = true,
IsRegistered = false,
IsValidated = true,
};
_checkedUnregisteredPackageSources.Add(src, newSource);
yield return newSource;
}
else
{
// Not a valid location?
Warning(Constants.Messages.UnableToResolveSource, src);
}
}
}
}
private XDocument Config {
get {
if (_config == null)
{
Debug(Resources.Messages.LoadingConfigurationFile, ConfigurationFileLocation);
XDocument doc = null;
try{
using (FileStream fs = new FileStream(ConfigurationFileLocation, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
// load the xdocument from the file stream
doc = XmlUtility.LoadSafe(fs, ignoreWhiteSpace: true);
}
Debug(Resources.Messages.LoadedConfigurationFile, ConfigurationFileLocation);
if (doc.Root != null && doc.Root.Name != null && String.Equals(doc.Root.Name.LocalName, "configuration", StringComparison.OrdinalIgnoreCase)) {
_config = doc;
return _config;
}
Warning(Resources.Messages.MissingConfigurationElement, ConfigurationFileLocation);
}
catch (Exception e)
{
// a bad xml doc or a folder gets deleted somehow
Warning(e.Message);
//string dir = Path.GetDirectoryName(ConfigurationFileLocation);
//if (dir != null && !Directory.Exists(dir))
//{
// Debug(Resources.Messages.CreateDirectory, dir);
// Directory.CreateDirectory(dir);
//}
//Debug(Resources.Messages.UseDefaultConfig);
//_config.Load(new MemoryStream((byte[])Encoding.UTF8.GetBytes(DefaultConfig)));
}
}
return _config;
}
set {
if (value == null) {
Debug(Resources.Messages.SettingConfigurationToNull);
return;
}
_config = value;
Verbose(Resources.Messages.SavingConfigurationWithFile, ConfigurationFileLocation);
var stringBuilder = new System.Text.StringBuilder();
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = false,
Indent = true,
NewLineOnAttributes = true,
NamespaceHandling = NamespaceHandling.OmitDuplicates
};
using (var xmlWriter = XmlWriter.Create(stringBuilder, settings))
{
_config.Save(xmlWriter);
File.WriteAllText(ConfigurationFileLocation, _config.ToString());
}
}
}
private string ConfigurationFileLocation {
get {
if (String.IsNullOrWhiteSpace(_configurationFileLocation))
{
// get the value from the request
var path = GetOptionValue("ConfigFile");
if (!String.IsNullOrWhiteSpace(path))
{
_configurationFileLocation = path;
if (!File.Exists(_configurationFileLocation))
{
WriteError(ErrorCategory.InvalidArgument, _configurationFileLocation, Resources.Messages.FileNotFound);
}
} else {
var appdataFolder = Environment.GetEnvironmentVariable("appdata");
_configurationFileLocation = Path.Combine(appdataFolder, "NuGet", NuGetConstant.SettingsFileName);
//create directory if does not exist
string dir = Path.GetDirectoryName(_configurationFileLocation);
if (dir != null && !Directory.Exists(dir))
{
Debug(Resources.Messages.CreateDirectory, dir);
Directory.CreateDirectory(dir);
}
//create place holder config file
if (!File.Exists(_configurationFileLocation))
{
Debug(Resources.Messages.CreateFile, _configurationFileLocation);
File.WriteAllText(_configurationFileLocation, DefaultConfig);
}
}
}
return _configurationFileLocation;
}
}
private IDictionary<string, PackageSource> RegisteredPackageSources
{
get {
if (_registeredPackageSources == null)
{
_registeredPackageSources = new ConcurrentDictionary<string, PackageSource>(StringComparer.OrdinalIgnoreCase);
try
{
Debug(Resources.Messages.DebugInfoCallMethod3, "NuGetRequest", "RegisteredPackageSources", ConfigurationFileLocation);
var config = Config;
if (config != null)
{
// get the configuration node
var configuration = config.ElementsNoNamespace("configuration").FirstOrDefault();
if (configuration != null)
{
// get the packageSources node
var packageSources = configuration.ElementsNoNamespace("packageSources").FirstOrDefault();
if (packageSources != null)
{
_registeredPackageSources = packageSources.Elements("add")
.Where(each => each.Attribute("key") != null && each.Attribute("value") != null)
.ToDictionaryNicely(each => each.Attribute("key").Value, each =>
new PackageSource
{
Request = this,
Name = each.Attribute("key").Value,
Location = each.Attribute("value").Value,
Trusted = each.Attribute("trusted") != null && each.Attribute("trusted").Value.IsTrue(),
IsRegistered = true,
IsValidated = each.Attribute("validated") != null && each.Attribute("validated").Value.IsTrue(),
}, StringComparer.OrdinalIgnoreCase);
}
}
}
}
catch (Exception)
{
_registeredPackageSources = new ConcurrentDictionary<string, PackageSource>();
}
}
return _registeredPackageSources;
}
}
private IEnumerable<PackageItem> GetPackageById(PackageSource source,
string name,
NuGetRequest request,
string requiredVersion = null,
string minimumVersion = null,
string maximumVersion = null,
bool minInclusive = true,
bool maxInclusive = true) {
try {
Debug(Resources.Messages.DebugInfoCallMethod3, "NuGetRequest", "GetPackageById", name);
// source should be attached to a repository
if (source.Repository == null)
{
return Enumerable.Empty<PackageItem>();
}
// otherwise fall back to traditional behavior
var pkgs = source.Repository.FindPackagesById(name, request);
// if required version not specified then don't use unlisted version
// unlisted version is the one that has published year as 1900
if (string.IsNullOrWhiteSpace(requiredVersion))
{
pkgs = pkgs.Where(pkg => pkg.Published.HasValue && pkg.Published.Value.Year > 1900);
}
if (AllVersions.Value){
//Display versions from lastest to oldest
pkgs = (from p in pkgs select p).OrderByDescending(x => x.Version);
}
//A user does not provide version info, we choose the latest
if (!AllVersions.Value && (String.IsNullOrWhiteSpace(requiredVersion) && String.IsNullOrWhiteSpace(minimumVersion) && String.IsNullOrWhiteSpace(maximumVersion)))
{
if (AllowPrereleaseVersions.Value || source.Repository.IsFile) {
//Handling something like Json.NET 7.0.1-beta3 as well as local repository
pkgs = from p in pkgs
group p by p.Id
into newGroup
select newGroup.Aggregate((current, next) => (next.Version > current.Version) ? next : current);
} else {
pkgs = from p in pkgs where p.IsLatestVersion select p;
}
}
pkgs = FilterOnContains(pkgs);
pkgs = FilterOnTags(pkgs);
var results = FilterOnVersion(pkgs, requiredVersion, minimumVersion, maximumVersion, minInclusive, maxInclusive)
.Select(pkg => new PackageItem {
Package = pkg,
PackageSource = source,
FastPath = MakeFastPath(source, pkg.Id, pkg.Version.ToString())
});
return results;
} catch (Exception e) {
e.Dump(this);
return Enumerable.Empty<PackageItem>();
}
}
private PackageSource ResolvePackageSource(string nameOrLocation) {
Debug(Resources.Messages.DebugInfoCallMethod3, "NuGetRequest", "ResolvePackageSource", nameOrLocation);
if (IsCanceled) {
return null;
}
var source = FindRegisteredSource(nameOrLocation);
if (source != null) {
Debug(Resources.Messages.FoundRegisteredSource, nameOrLocation, NuGetConstant.ProviderName);
return source;
}
Debug(Resources.Messages.NotFoundRegisteredSource, nameOrLocation, NuGetConstant.ProviderName);
try {
// is the given value a filename?
if (File.Exists(nameOrLocation)) {
Debug(Resources.Messages.SourceIsAFilePath, nameOrLocation);
return new PackageSource() {
Request = this,
IsRegistered = false,
IsValidated = true,
Location = nameOrLocation,
Name = nameOrLocation,
Trusted = true,
};
}
} catch {
}
try {
// is the given value a directory?
if (Directory.Exists(nameOrLocation)) {
Debug(Resources.Messages.SourceIsADirectory, nameOrLocation);
return new PackageSource() {
Request = this,
IsRegistered = false,
IsValidated = true,
Location = nameOrLocation,
Name = nameOrLocation,
Trusted = true,
};
}
} catch {
}
if (Uri.IsWellFormedUriString(nameOrLocation, UriKind.Absolute)) {
var uri = new Uri(nameOrLocation, UriKind.Absolute);
if (!SupportedSchemes.Contains(uri.Scheme.ToLowerInvariant())) {
WriteError(ErrorCategory.InvalidArgument, uri.ToString(), Constants.Messages.UriSchemeNotSupported, uri);
return null;
}
// this is an URI, and it looks like one type that we support
if (SkipValidate.Value || NuGetPathUtility.ValidateSourceUri(SupportedSchemes, uri, this)) {
var uriSource = new PackageSource {
Request = this,
IsRegistered = false,
IsValidated = !SkipValidate.Value,
Location = nameOrLocation,
Name = nameOrLocation,
Trusted = false,
};
return uriSource;
}
}
WriteError(ErrorCategory.InvalidArgument, nameOrLocation, Constants.Messages.UnableToResolveSource, nameOrLocation);
return null;
}
private bool TryParseFastPath(string fastPath, out string source, out string id, out string version, out string[] sources)
{
var match = _regexFastPath.Match(fastPath);
source = match.Success ? match.Groups["source"].Value.FromBase64() : null;
id = match.Success ? match.Groups["id"].Value.FromBase64() : null;
version = match.Success ? match.Groups["version"].Value.FromBase64() : null;
var srcs = match.Success ? match.Groups["sources"].Value : string.Empty;
sources = srcs.Split('|').Select(each => each.FromBase64()).Where(each => !string.IsNullOrWhiteSpace(each)).ToArray();
return match.Success;
}
private bool LocationCloseEnoughMatch(string givenLocation, string knownLocation) {
if (givenLocation.Equals(knownLocation, StringComparison.OrdinalIgnoreCase)) {
return true;
}
// make trailing slashes consistent
if (givenLocation.TrimEnd('/').Equals(knownLocation.TrimEnd('/'), StringComparison.OrdinalIgnoreCase)) {
return true;
}
// and trailing backslashes
if (givenLocation.TrimEnd('\\').Equals(knownLocation.TrimEnd('\\'), StringComparison.OrdinalIgnoreCase)) {
return true;
}
return false;
}
private IEnumerable<IPackage> FilterOnVersion(IEnumerable<IPackage> pkgs, string requiredVersion, string minimumVersion, string maximumVersion, bool minInclusive = true, bool maxInclusive = true) {
if (!String.IsNullOrWhiteSpace(requiredVersion))
{
pkgs = pkgs.Where(each => each.Version == new SemanticVersion(requiredVersion));
} else {
if (!String.IsNullOrWhiteSpace(minimumVersion))
{
// if minInclusive, then use >= else use >
if (minInclusive)
{
pkgs = pkgs.Where(each => each.Version >= new SemanticVersion(minimumVersion));
}
else
{
pkgs = pkgs.Where(each => each.Version > new SemanticVersion(minimumVersion));
}
}
if (!String.IsNullOrWhiteSpace(maximumVersion))
{
// if maxInclusive, then use < else use <=
if (maxInclusive)
{
pkgs = pkgs.Where(each => each.Version <= new SemanticVersion(maximumVersion));
}
else
{
pkgs = pkgs.Where(each => each.Version < new SemanticVersion(maximumVersion));
}
}
}
return pkgs;
}
private IEnumerable<IPackage> FilterOnName(IEnumerable<IPackage> pkgs, string searchTerm, bool useWildCard)
{
if (useWildCard)
{
// Applying the wildcard pattern matching
const WildcardOptions wildcardOptions = WildcardOptions.CultureInvariant | WildcardOptions.IgnoreCase;
var wildcardPattern = new WildcardPattern(searchTerm, wildcardOptions);
return pkgs.Where(p => wildcardPattern.IsMatch(p.Id));
} else {
return pkgs.Where(each => each.Id.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) > -1);
}
}
internal IEnumerable<IPackage> FilterOnTags(IEnumerable<IPackage> pkgs)
{
if (FilterOnTag == null || FilterOnTag.Value.Length == 0)
{
return pkgs;
}
//Tags should be performed as *AND* intead of *OR"
//For example -FilterOnTag:{ "A", "B"}, the returned package should have both A and B.
return pkgs.Where(pkg => FilterOnTag.Value.All(
tagFromUser =>
{
if (string.IsNullOrWhiteSpace(pkg.Tags))
{
// return all packages if a package has no tags.
return true;
}
var tagArray = pkg.Tags.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
return tagArray.Any(tagFromPackage => tagFromPackage.EqualsIgnoreCase(tagFromUser));
}
));
}
private IEnumerable<IPackage> FilterOnContains(IEnumerable<IPackage> pkgs) {
if (string.IsNullOrWhiteSpace(Contains.Value))
{
return pkgs;
}
return pkgs.Where(each => each.Description.IndexOf(Contains.Value, StringComparison.OrdinalIgnoreCase) > -1 ||
each.Id.IndexOf(Contains.Value, StringComparison.OrdinalIgnoreCase) > -1);
}
internal IEnumerable<PackageItem> SearchForPackages(string name)
{
var sources = SelectedSources.AsParallel().WithMergeOptions(ParallelMergeOptions.NotBuffered);
return sources.SelectMany(source => SearchForPackages(source, name));
}
/// <summary>
/// Search the entire repository for the packages
/// </summary>
/// <param name="source">Package Source</param>
/// <param name="name">Package name</param>
/// <returns></returns>
private IEnumerable<PackageItem> SearchForPackages(PackageSource source, string name)
{
try
{
Debug(Resources.Messages.DebugInfoCallMethod3, "NuGetRequest", "SearchForPackages", name);
// no repository found then returns nothing
if (source.Repository == null)
{
return Enumerable.Empty<PackageItem>();
}
var isNameContainsWildCard = false;
var searchTerm = Contains.Value ?? string.Empty;
// Deal with two cases here:
// 1. The package name contains wildcards like "Find-Package -name JQ*". We search based on the name.
// 2. A user does not provide the Name parameter,
// A user provides name with wildcards. We will use name as the SearchTerm while Contains and Tag will be used
// for filtering on the results.
if (!String.IsNullOrWhiteSpace(name) && WildcardPattern.ContainsWildcardCharacters(name))
{
isNameContainsWildCard = true;
// NuGet does not support PowerShell/POSIX style wildcards and supports only '*' in searchTerm
// Replace the range from '[' - to ']' with * and ? with * then wildcard pattern is applied on the results
var tempName = name;
var squareBracketPattern = Regex.Escape("[") + "(.*?)]";
foreach (Match match in Regex.Matches(tempName, squareBracketPattern)) {
tempName = tempName.Replace(match.Value, "*");
}
//As the nuget does not support wildcard, we remove '?', '*' wildcards from the search string, and then
//looking for the longest string in the given string as a keyword for the searching in the repository.
//A sample case will be something like find-package sql*Compact*.
//When the AllVersions property exists, the query like the following containing the wildcards does not work. We need to remove the wild cards and
//replace it with the longest string searhc.
//http://www.powershellgallery.com/api/v2/Search()?$orderby=DownloadCount%20desc,Id&searchTerm='tsdprovi*'&targetFramework=''&includePrerelease=false
if ((!String.IsNullOrWhiteSpace(name) && source.Location.IndexOf("powershellgallery.com", StringComparison.OrdinalIgnoreCase) == -1)
|| (AllVersions.Value))
{
//get rid of wildcard and search the longest string in the given name for nuget.org
tempName = tempName.Split('?', '*').OrderBy(namePart => namePart.Length).Last();
}
//Deal with a case when a user type Find-Package *
if (String.Equals(tempName, "*", StringComparison.OrdinalIgnoreCase)) {
//We use '' instead of "*" because searchterm='*' does not return the entire repository.
tempName = string.Empty;
}
searchTerm = tempName;
}
// Add the Tags for the search.
if (FilterOnTag != null)
{
// E.g. searchTerm = "tag:dscresource_xFirefox tag:command_Start-Process"
searchTerm = FilterOnTag.Value.Where(tag => !string.IsNullOrWhiteSpace(tag)).Aggregate(searchTerm, (current, tag) => current + " tag:" + tag);
}
Verbose(Resources.Messages.SearchingRepository, source.Repository.Source, searchTerm);
// Handling case where a user does not provide Name parameter
var pkgs = source.Repository.Search(searchTerm, this);
if (!String.IsNullOrWhiteSpace(name))
{
//Filter on the results. This is needed because we replace [...] regex in the searchterm at the begining of this method.
pkgs = FilterOnName(pkgs, name, isNameContainsWildCard);
}
pkgs = FilterOnContains(pkgs);
var pkgsItem = pkgs.Select(pkg => new PackageItem
{
Package = pkg,
PackageSource = source,
FastPath = MakeFastPath(source, pkg.Id, pkg.Version.ToString())
});
return pkgsItem;
}
catch (Exception e)
{
e.Dump(this);
Warning(e.Message);
return Enumerable.Empty<PackageItem>();
}
}
}
}