mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Remove unused NugetCore code
This commit is contained in:
@@ -1,101 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class ConfigurationDefaults
|
||||
{
|
||||
private ISettings _settingsManager = NullSettings.Instance;
|
||||
private const string ConfigurationDefaultsFile = "NuGetDefaults.config";
|
||||
private static readonly ConfigurationDefaults _instance = InitializeInstance();
|
||||
|
||||
private bool _defaultPackageSourceInitialized;
|
||||
private List<PackageSource> _defaultPackageSources;
|
||||
private string _defaultPushSource;
|
||||
|
||||
private static ConfigurationDefaults InitializeInstance()
|
||||
{
|
||||
var baseDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "NuGet");
|
||||
PhysicalFileSystem fileSystem = new PhysicalFileSystem(baseDirectory);
|
||||
return new ConfigurationDefaults(fileSystem, ConfigurationDefaultsFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An internal constructor MAINLY INTENDED FOR TESTING THE CLASS. But, the product code is only expected to use the static Instance property
|
||||
/// Only catches FileNotFoundException. Will throw all exceptions including other IOExceptions and XmlExceptions for invalid xml and so on
|
||||
/// </summary>
|
||||
/// <param name="fileSystem"></param>
|
||||
/// <param name="path"></param>
|
||||
internal ConfigurationDefaults(IFileSystem fileSystem, string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (fileSystem.FileExists(path))
|
||||
{
|
||||
_settingsManager = new Settings(fileSystem, path);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
}
|
||||
|
||||
// Intentionally, we don't catch all IOExceptions, XmlException or other file related exceptions like UnAuthorizedAccessException
|
||||
// This way, administrator will become aware of the failures when the ConfigurationDefaults file is not valid or permissions are not set properly
|
||||
}
|
||||
|
||||
public static ConfigurationDefaults Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<PackageSource> DefaultPackageSources
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_defaultPackageSources == null)
|
||||
{
|
||||
_defaultPackageSources = new List<PackageSource>();
|
||||
IList<SettingValue> disabledPackageSources = _settingsManager.GetSettingValues("disabledPackageSources", isPath: false);
|
||||
IList<SettingValue> packageSources = _settingsManager.GetSettingValues("packageSources", isPath: false);
|
||||
|
||||
foreach (var settingValue in packageSources)
|
||||
{
|
||||
// In a SettingValue representing a package source, the Key represents the name of the package source and the Value its source
|
||||
_defaultPackageSources.Add(new PackageSource(settingValue.Value,
|
||||
settingValue.Key,
|
||||
isEnabled: !disabledPackageSources.Any<SettingValue>(p => p.Key.Equals(settingValue.Key, StringComparison.CurrentCultureIgnoreCase)),
|
||||
isOfficial: true));
|
||||
}
|
||||
}
|
||||
return _defaultPackageSources;
|
||||
}
|
||||
}
|
||||
|
||||
public string DefaultPushSource
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_defaultPushSource == null && !_defaultPackageSourceInitialized)
|
||||
{
|
||||
_defaultPackageSourceInitialized = true;
|
||||
_defaultPushSource = _settingsManager.GetConfigValue("DefaultPushSource");
|
||||
}
|
||||
return _defaultPushSource;
|
||||
}
|
||||
}
|
||||
|
||||
public string DefaultPackageRestoreConsent
|
||||
{
|
||||
get
|
||||
{
|
||||
return _settingsManager.GetValue("packageRestore", "enabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public interface ISettings
|
||||
{
|
||||
string GetValue(string section, string key);
|
||||
string GetValue(string section, string key, bool isPath);
|
||||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is the best fit for this internal class")]
|
||||
IList<KeyValuePair<string, string>> GetValues(string section);
|
||||
|
||||
IList<SettingValue> GetSettingValues(string section, bool isPath);
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is the best fit for this internal class")]
|
||||
IList<KeyValuePair<string, string>> GetNestedValues(string section, string key);
|
||||
|
||||
void SetValue(string section, string key, string value);
|
||||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is the best fit for this internal class")]
|
||||
void SetValues(string section, IList<KeyValuePair<string, string>> values);
|
||||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is the best fit for this internal class")]
|
||||
void SetNestedValues(string section, string key, IList<KeyValuePair<string, string>> values);
|
||||
|
||||
bool DeleteValue(string section, string key);
|
||||
bool DeleteSection(string section);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using NuGet.Resources;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class NullSettings : ISettings
|
||||
{
|
||||
private static readonly NullSettings _settings = new NullSettings();
|
||||
|
||||
public static NullSettings Instance
|
||||
{
|
||||
get { return _settings; }
|
||||
}
|
||||
|
||||
public string GetValue(string section, string key)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public string GetValue(string section, string key, bool isPath)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public IList<KeyValuePair<string, string>> GetValues(string section)
|
||||
{
|
||||
return new List<KeyValuePair<string, string>>().AsReadOnly();
|
||||
}
|
||||
|
||||
public IList<SettingValue> GetSettingValues(string section, bool isPath)
|
||||
{
|
||||
return new List<SettingValue>().AsReadOnly();
|
||||
}
|
||||
|
||||
public IList<KeyValuePair<string, string>> GetNestedValues(string section, string key)
|
||||
{
|
||||
return new List<KeyValuePair<string, string>>().AsReadOnly();
|
||||
}
|
||||
|
||||
public void SetValue(string section, string key, string value)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.InvalidNullSettingsOperation, "SetValue"));
|
||||
}
|
||||
|
||||
public void SetValues(string section, IList<KeyValuePair<string, string>> values)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.InvalidNullSettingsOperation, "SetValues"));
|
||||
}
|
||||
|
||||
public void SetNestedValues(string section, string key, IList<KeyValuePair<string, string>> values)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.InvalidNullSettingsOperation, "SetNestedValues"));
|
||||
}
|
||||
|
||||
public bool DeleteValue(string section, string key)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.InvalidNullSettingsOperation, "DeleteValue"));
|
||||
}
|
||||
|
||||
public bool DeleteSection(string section)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.InvalidNullSettingsOperation, "DeleteSection"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class SettingValue
|
||||
{
|
||||
public SettingValue(string key, string value, bool isMachineWide, int priority = 0)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
IsMachineWide = isMachineWide;
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
public string Key { get; private set; }
|
||||
|
||||
public string Value { get; private set; }
|
||||
|
||||
public bool IsMachineWide { get; private set; }
|
||||
|
||||
// The priority of this setting in the nuget.config hierarchy. Bigger number means higher priority.
|
||||
public int Priority { get; private set; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var rhs = obj as SettingValue;
|
||||
if (rhs == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return rhs.Key == Key &&
|
||||
rhs.Value == Value &&
|
||||
rhs.IsMachineWide == rhs.IsMachineWide;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Tuple.Create(Key, Value, IsMachineWide).GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,746 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using NuGet.Resources;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class Settings : ISettings
|
||||
{
|
||||
private readonly XDocument _config;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly string _fileName;
|
||||
|
||||
// next config file to read if any
|
||||
private Settings _next;
|
||||
|
||||
private readonly bool _isMachineWideSettings;
|
||||
|
||||
// The priority of this setting file
|
||||
private int _priority;
|
||||
|
||||
public Settings(IFileSystem fileSystem)
|
||||
: this(fileSystem, Constants.SettingsFileName, false)
|
||||
{
|
||||
}
|
||||
|
||||
public Settings(IFileSystem fileSystem, string fileName)
|
||||
: this(fileSystem, fileName, false)
|
||||
{
|
||||
}
|
||||
|
||||
public Settings(IFileSystem fileSystem, string fileName, bool isMachineWideSettings)
|
||||
{
|
||||
if (fileSystem == null)
|
||||
{
|
||||
throw new ArgumentNullException("fileSystem");
|
||||
}
|
||||
if (String.IsNullOrEmpty(fileName))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "fileName");
|
||||
}
|
||||
_fileSystem = fileSystem;
|
||||
_fileName = fileName;
|
||||
XDocument conf = null;
|
||||
ExecuteSynchronized(() => conf = XmlUtility.GetOrCreateDocument("configuration", _fileSystem, _fileName));
|
||||
_config = conf;
|
||||
_isMachineWideSettings = isMachineWideSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating whether this file is a machine wide settings file. A machine wide settings
|
||||
/// file will not be modified.
|
||||
/// </summary>
|
||||
public bool IsMachineWideSettings
|
||||
{
|
||||
get { return _isMachineWideSettings; }
|
||||
}
|
||||
|
||||
public string ConfigFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.IsPathRooted(_fileName) ?
|
||||
_fileName :
|
||||
Path.GetFullPath(Path.Combine(_fileSystem.Root, _fileName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads user settings from the NuGet configuration files. The method walks the directory
|
||||
/// tree in <paramref name="fileSystem"/> up to its root, and reads each NuGet.config file
|
||||
/// it finds in the directories. It then reads the user specific settings,
|
||||
/// which is file <paramref name="configFileName"/>
|
||||
/// in <paramref name="fileSystem"/> if <paramref name="configFileName"/> is not null,
|
||||
/// If <paramref name="configFileName"/> is null, the user specific settings file is
|
||||
/// %AppData%\NuGet\NuGet.config.
|
||||
/// After that, the machine wide settings files are added.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, if <paramref name="fileSystem"/> is c:\dir1\dir2, <paramref name="configFileName"/>
|
||||
/// is "userConfig.file", the files loaded are (in the order that they are loaded):
|
||||
/// c:\dir1\dir2\nuget.config
|
||||
/// c:\dir1\nuget.config
|
||||
/// c:\nuget.config
|
||||
/// c:\dir1\dir2\userConfig.file
|
||||
/// machine wide settings (e.g. c:\programdata\NuGet\Config\*.config)
|
||||
/// </remarks>
|
||||
/// <param name="fileSystem">The file system to walk to find configuration files.
|
||||
/// Can be null.</param>
|
||||
/// <param name="configFileName">The user specified configuration file.</param>
|
||||
/// <param name="machineWideSettings">The machine wide settings. If it's not null, the
|
||||
/// settings files in the machine wide settings are added after the user sepcific
|
||||
/// config file.</param>
|
||||
/// <returns>The settings object loaded.</returns>
|
||||
public static ISettings LoadDefaultSettings(
|
||||
IFileSystem fileSystem,
|
||||
string configFileName,
|
||||
IMachineWideSettings machineWideSettings)
|
||||
{
|
||||
// Walk up the tree to find a config file; also look in .nuget subdirectories
|
||||
var validSettingFiles = new List<Settings>();
|
||||
if (fileSystem != null)
|
||||
{
|
||||
validSettingFiles.AddRange(
|
||||
GetSettingsFileNames(fileSystem)
|
||||
.Select(f => ReadSettings(fileSystem, f))
|
||||
.Where(f => f != null));
|
||||
}
|
||||
|
||||
LoadUserSpecificSettings(validSettingFiles, fileSystem, configFileName);
|
||||
|
||||
if (machineWideSettings != null)
|
||||
{
|
||||
validSettingFiles.AddRange(
|
||||
machineWideSettings.Settings.Select(
|
||||
s => new Settings(s._fileSystem, s._fileName, s._isMachineWideSettings)));
|
||||
}
|
||||
|
||||
if (validSettingFiles.IsEmpty())
|
||||
{
|
||||
// This means we've failed to load all config files and also failed to load or create the one in %AppData%
|
||||
// Work Item 1531: If the config file is malformed and the constructor throws, NuGet fails to load in VS.
|
||||
// Returning a null instance prevents us from silently failing and also from picking up the wrong config
|
||||
return NullSettings.Instance;
|
||||
}
|
||||
|
||||
validSettingFiles[0]._priority = validSettingFiles.Count;
|
||||
|
||||
// if multiple setting files were loaded, chain them in a linked list
|
||||
for (int i = 1; i < validSettingFiles.Count; ++i)
|
||||
{
|
||||
validSettingFiles[i]._next = validSettingFiles[i - 1];
|
||||
validSettingFiles[i]._priority = validSettingFiles[i - 1]._priority - 1;
|
||||
}
|
||||
|
||||
// return the linked list head. Typicall, it's either the config file in %ProgramData%\NuGet\Config,
|
||||
// or the user specific config (%APPDATA%\NuGet\nuget.config) if there are no machine
|
||||
// wide config files. The head file is the one we want to read first, while the user specific config
|
||||
// is the one that we want to write to.
|
||||
// TODO: add UI to allow specifying which one to write to
|
||||
return validSettingFiles.Last();
|
||||
}
|
||||
|
||||
private static void LoadUserSpecificSettings(
|
||||
List<Settings> validSettingFiles,
|
||||
IFileSystem fileSystem,
|
||||
string configFileName)
|
||||
{
|
||||
// for the default location, allow case where file does not exist, in which case it'll end
|
||||
// up being created if needed
|
||||
Settings appDataSettings = null;
|
||||
if (configFileName == null)
|
||||
{
|
||||
// load %AppData%\NuGet\NuGet.config
|
||||
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
if (!String.IsNullOrEmpty(appDataPath))
|
||||
{
|
||||
var defaultSettingsFilePath = Path.Combine(
|
||||
appDataPath, "NuGet", Constants.SettingsFileName);
|
||||
|
||||
// Since defaultSettingsFilePath is a full path, so it doesn't matter what value is
|
||||
// used as root for the PhysicalFileSystem.
|
||||
appDataSettings = ReadSettings(
|
||||
fileSystem ?? new PhysicalFileSystem(@"c:\"),
|
||||
defaultSettingsFilePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!fileSystem.FileExists(configFileName))
|
||||
{
|
||||
string message = String.Format(CultureInfo.CurrentCulture,
|
||||
NuGetResources.FileDoesNotExit,
|
||||
fileSystem.GetFullPath(configFileName));
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
appDataSettings = ReadSettings(fileSystem, configFileName);
|
||||
}
|
||||
|
||||
if (appDataSettings != null)
|
||||
{
|
||||
validSettingFiles.Add(appDataSettings);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the machine wide settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, if <paramref name="paths"/> is {"IDE", "Version", "SKU" }, then
|
||||
/// the files loaded are (in the order that they are loaded):
|
||||
/// %programdata%\NuGet\Config\IDE\Version\SKU\*.config
|
||||
/// %programdata%\NuGet\Config\IDE\Version\*.config
|
||||
/// %programdata%\NuGet\Config\IDE\*.config
|
||||
/// %programdata%\NuGet\Config\*.config
|
||||
/// </remarks>
|
||||
/// <param name="fileSystem">The file system in which the settings files are read.</param>
|
||||
/// <param name="paths">The additional paths under which to look for settings files.</param>
|
||||
/// <returns>The list of settings read.</returns>
|
||||
public static IEnumerable<Settings> LoadMachineWideSettings(
|
||||
IFileSystem fileSystem,
|
||||
params string[] paths)
|
||||
{
|
||||
List<Settings> settingFiles = new List<Settings>();
|
||||
string basePath = @"NuGet\Config";
|
||||
string combinedPath = Path.Combine(paths);
|
||||
|
||||
while (true)
|
||||
{
|
||||
string directory = Path.Combine(basePath, combinedPath);
|
||||
|
||||
// load setting files in directory
|
||||
foreach (var file in fileSystem.GetFiles(directory, "*.config"))
|
||||
{
|
||||
var settings = ReadSettings(fileSystem, file, true);
|
||||
if (settings != null)
|
||||
{
|
||||
settingFiles.Add(settings);
|
||||
}
|
||||
}
|
||||
|
||||
if (combinedPath.Length == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
int index = combinedPath.LastIndexOf(Path.DirectorySeparatorChar);
|
||||
if (index < 0)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
combinedPath = combinedPath.Substring(0, index);
|
||||
}
|
||||
|
||||
return settingFiles;
|
||||
}
|
||||
|
||||
public string GetValue(string section, string key)
|
||||
{
|
||||
return GetValue(section, key, isPath: false);
|
||||
}
|
||||
|
||||
public string GetValue(string section, string key, bool isPath)
|
||||
{
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(key))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "key");
|
||||
}
|
||||
|
||||
XElement element = null;
|
||||
string ret = null;
|
||||
|
||||
var curr = this;
|
||||
while (curr != null)
|
||||
{
|
||||
XElement newElement = curr.GetValueInternal(section, key, element);
|
||||
if (!object.ReferenceEquals(element, newElement))
|
||||
{
|
||||
element = newElement;
|
||||
|
||||
// we need to evaluate using current Settings in case value needs path transformation
|
||||
ret = curr.ElementToValue(element, isPath);
|
||||
}
|
||||
curr = curr._next;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static string ResolvePath(string configDirectory, string value)
|
||||
{
|
||||
// Three cases for when Path.IsRooted(value) is true:
|
||||
// 1- C:\folder\file
|
||||
// 2- \\share\folder\file
|
||||
// 3- \folder\file
|
||||
// In the first two cases, we want to honor the fully qualified path
|
||||
// In the last case, we want to return X:\folder\file with X: drive where config file is located.
|
||||
// However, Path.Combine(path1, path2) always returns path2 when Path.IsRooted(path2) == true (which is current case)
|
||||
var root = Path.GetPathRoot(value);
|
||||
// this corresponds to 3rd case
|
||||
if (root != null && root.Length == 1 && (root[0] == Path.DirectorySeparatorChar || value[0] == Path.AltDirectorySeparatorChar))
|
||||
{
|
||||
return Path.Combine(Path.GetPathRoot(configDirectory), value.Substring(1));
|
||||
}
|
||||
return Path.Combine(configDirectory, value);
|
||||
}
|
||||
|
||||
private string ElementToValue(XElement element, bool isPath)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Return the optional value which if not there will be null;
|
||||
string value = element.GetOptionalAttributeValue("value");
|
||||
if (!isPath || String.IsNullOrEmpty(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return _fileSystem.GetFullPath(ResolvePath(Path.GetDirectoryName(ConfigFilePath), value));
|
||||
}
|
||||
|
||||
private XElement GetValueInternal(string section, string key, XElement curr)
|
||||
{
|
||||
// Get the section and return curr if it doesn't exist
|
||||
var sectionElement = GetSection(_config.Root, section);
|
||||
if (sectionElement == null)
|
||||
{
|
||||
return curr;
|
||||
}
|
||||
|
||||
// Get the add element that matches the key and return curr if it doesn't exist
|
||||
return FindElementByKey(sectionElement, key, curr);
|
||||
}
|
||||
|
||||
public IList<KeyValuePair<string, string>> GetValues(string section)
|
||||
{
|
||||
return GetValues(section, isPath: false);
|
||||
}
|
||||
|
||||
private IList<KeyValuePair<string, string>> GetValues(string section, bool isPath)
|
||||
{
|
||||
var values = GetSettingValues(section, isPath);
|
||||
return values.Select(v => new KeyValuePair<string, string>(v.Key, v.Value)).ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
public IList<SettingValue> GetSettingValues(string section, bool isPath)
|
||||
{
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
|
||||
var settingValues = new List<SettingValue>();
|
||||
var curr = this;
|
||||
while (curr != null)
|
||||
{
|
||||
curr.PopulateValues(section, settingValues, isPath);
|
||||
curr = curr._next;
|
||||
}
|
||||
|
||||
return settingValues.AsReadOnly();
|
||||
}
|
||||
|
||||
private void PopulateValues(string section, List<SettingValue> current, bool isPath)
|
||||
{
|
||||
var sectionElement = GetSection(_config.Root, section);
|
||||
if (sectionElement != null)
|
||||
{
|
||||
ReadSection(sectionElement, current, isPath);
|
||||
}
|
||||
}
|
||||
|
||||
public IList<KeyValuePair<string, string>> GetNestedValues(string section, string key)
|
||||
{
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(key))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "key");
|
||||
}
|
||||
|
||||
var values = new List<SettingValue>();
|
||||
var curr = this;
|
||||
while (curr != null)
|
||||
{
|
||||
curr.PopulateNestedValues(section, key, values);
|
||||
curr = curr._next;
|
||||
}
|
||||
|
||||
return values.Select(v => new KeyValuePair<string, string>(v.Key, v.Value)).ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
private void PopulateNestedValues(string section, string key, List<SettingValue> current)
|
||||
{
|
||||
var sectionElement = GetSection(_config.Root, section);
|
||||
if (sectionElement == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var subSection = GetSection(sectionElement, key);
|
||||
if (subSection == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ReadSection(subSection, current, isPath: false);
|
||||
}
|
||||
|
||||
public void SetValue(string section, string key, string value)
|
||||
{
|
||||
// machine wide settings cannot be changed.
|
||||
if (IsMachineWideSettings)
|
||||
{
|
||||
if (_next == null)
|
||||
{
|
||||
throw new InvalidOperationException(NuGetResources.Error_NoWritableConfig);
|
||||
}
|
||||
|
||||
_next.SetValue(section, key, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
var sectionElement = GetOrCreateSection(_config.Root, section);
|
||||
SetValueInternal(sectionElement, key, value);
|
||||
Save();
|
||||
}
|
||||
|
||||
public void SetValues(string section, IList<KeyValuePair<string, string>> values)
|
||||
{
|
||||
// machine wide settings cannot be changed.
|
||||
if (IsMachineWideSettings)
|
||||
{
|
||||
if (_next == null)
|
||||
{
|
||||
throw new InvalidOperationException(NuGetResources.Error_NoWritableConfig);
|
||||
}
|
||||
|
||||
_next.SetValues(section, values);
|
||||
return;
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
if (values == null)
|
||||
{
|
||||
throw new ArgumentNullException("values");
|
||||
}
|
||||
|
||||
var sectionElement = GetOrCreateSection(_config.Root, section);
|
||||
foreach (var kvp in values)
|
||||
{
|
||||
SetValueInternal(sectionElement, kvp.Key, kvp.Value);
|
||||
}
|
||||
Save();
|
||||
}
|
||||
|
||||
public void SetNestedValues(string section, string key, IList<KeyValuePair<string, string>> values)
|
||||
{
|
||||
// machine wide settings cannot be changed.
|
||||
if (IsMachineWideSettings)
|
||||
{
|
||||
if (_next == null)
|
||||
{
|
||||
throw new InvalidOperationException(NuGetResources.Error_NoWritableConfig);
|
||||
}
|
||||
|
||||
_next.SetNestedValues(section, key, values);
|
||||
return;
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
if (values == null)
|
||||
{
|
||||
throw new ArgumentNullException("values");
|
||||
}
|
||||
|
||||
var sectionElement = GetOrCreateSection(_config.Root, section);
|
||||
var element = GetOrCreateSection(sectionElement, key);
|
||||
|
||||
foreach (var kvp in values)
|
||||
{
|
||||
SetValueInternal(element, kvp.Key, kvp.Value);
|
||||
}
|
||||
Save();
|
||||
}
|
||||
|
||||
private void SetValueInternal(XElement sectionElement, string key, string value)
|
||||
{
|
||||
if (String.IsNullOrEmpty(key))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "key");
|
||||
}
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
var element = FindElementByKey(sectionElement, key, null);
|
||||
if (element != null)
|
||||
{
|
||||
element.SetAttributeValue("value", value);
|
||||
Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
sectionElement.AddIndented(new XElement("add",
|
||||
new XAttribute("key", key),
|
||||
new XAttribute("value", value)));
|
||||
}
|
||||
}
|
||||
|
||||
public bool DeleteValue(string section, string key)
|
||||
{
|
||||
// machine wide settings cannot be changed.
|
||||
if (IsMachineWideSettings)
|
||||
{
|
||||
if (_next == null)
|
||||
{
|
||||
throw new InvalidOperationException(NuGetResources.Error_NoWritableConfig);
|
||||
}
|
||||
|
||||
return _next.DeleteValue(section, key);
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
if (String.IsNullOrEmpty(key))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "key");
|
||||
}
|
||||
|
||||
var sectionElement = GetSection(_config.Root, section);
|
||||
if (sectionElement == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var elementToDelete = FindElementByKey(sectionElement, key, null);
|
||||
if (elementToDelete == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
elementToDelete.RemoveIndented();
|
||||
Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DeleteSection(string section)
|
||||
{
|
||||
// machine wide settings cannot be changed.
|
||||
if (IsMachineWideSettings)
|
||||
{
|
||||
if (_next == null)
|
||||
{
|
||||
throw new InvalidOperationException(NuGetResources.Error_NoWritableConfig);
|
||||
}
|
||||
|
||||
return _next.DeleteSection(section);
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
|
||||
var sectionElement = GetSection(_config.Root, section);
|
||||
if (sectionElement == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sectionElement.RemoveIndented();
|
||||
Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ReadSection(XContainer sectionElement, ICollection<SettingValue> values, bool isPath)
|
||||
{
|
||||
var elements = sectionElement.Elements();
|
||||
|
||||
foreach (var element in elements)
|
||||
{
|
||||
string elementName = element.Name.LocalName;
|
||||
if (elementName.Equals("add", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var v = ReadValue(element, isPath);
|
||||
values.Add(new SettingValue(v.Key, v.Value, _isMachineWideSettings, _priority));
|
||||
}
|
||||
else if (elementName.Equals("clear", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
values.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
ExecuteSynchronized(() => _fileSystem.AddFile(_fileName, _config.Save));
|
||||
}
|
||||
|
||||
// When isPath is true, then the setting value is checked to see if it can be interpreted
|
||||
// as relative path. If it can, the returned value will be the full path of the relative path.
|
||||
// If it cannot be interpreted as relative path, the value is returned as-is.
|
||||
private KeyValuePair<string, string> ReadValue(XElement element, bool isPath)
|
||||
{
|
||||
var keyAttribute = element.Attribute("key");
|
||||
var valueAttribute = element.Attribute("value");
|
||||
|
||||
if (keyAttribute == null || String.IsNullOrEmpty(keyAttribute.Value) || valueAttribute == null)
|
||||
{
|
||||
throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, NuGetResources.UserSettings_UnableToParseConfigFile, ConfigFilePath));
|
||||
}
|
||||
|
||||
var value = valueAttribute.Value;
|
||||
Uri uri;
|
||||
if (isPath && Uri.TryCreate(value, UriKind.Relative, out uri))
|
||||
{
|
||||
string configDirectory = Path.GetDirectoryName(ConfigFilePath);
|
||||
value = _fileSystem.GetFullPath(Path.Combine(configDirectory, value));
|
||||
}
|
||||
|
||||
return new KeyValuePair<string, string>(keyAttribute.Value, value);
|
||||
}
|
||||
|
||||
private static XElement GetSection(XElement parentElement, string section)
|
||||
{
|
||||
section = XmlConvert.EncodeLocalName(section);
|
||||
return parentElement.Element(section);
|
||||
}
|
||||
|
||||
private static XElement GetOrCreateSection(XElement parentElement, string sectionName)
|
||||
{
|
||||
sectionName = XmlConvert.EncodeLocalName(sectionName);
|
||||
var section = parentElement.Element(sectionName);
|
||||
if (section == null)
|
||||
{
|
||||
section = new XElement(sectionName);
|
||||
parentElement.AddIndented(section);
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
private static XElement FindElementByKey(XElement sectionElement, string key, XElement curr)
|
||||
{
|
||||
XElement result = curr;
|
||||
foreach (var element in sectionElement.Elements())
|
||||
{
|
||||
string elementName = element.Name.LocalName;
|
||||
if (elementName.Equals("clear", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
else if (elementName.Equals("add", StringComparison.OrdinalIgnoreCase) &&
|
||||
element.GetOptionalAttributeValue("key").Equals(key, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result = element;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Order is most significant (e.g. applied last) to least significant (applied first)
|
||||
/// ex:
|
||||
/// c:\foo\nuget.config
|
||||
/// c:\nuget.config
|
||||
/// </remarks>
|
||||
private static IEnumerable<string> GetSettingsFileNames(IFileSystem fileSystem)
|
||||
{
|
||||
// for dirs obtained by walking up the tree, only consider setting files that already exist.
|
||||
// otherwise we'd end up creating them.
|
||||
foreach (var dir in GetSettingsFilePaths(fileSystem))
|
||||
{
|
||||
string fileName = Path.Combine(dir, Constants.SettingsFileName);
|
||||
if (fileSystem.FileExists(fileName))
|
||||
{
|
||||
yield return fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetSettingsFilePaths(IFileSystem fileSystem)
|
||||
{
|
||||
string root = fileSystem.Root;
|
||||
while (root != null)
|
||||
{
|
||||
yield return root;
|
||||
root = Path.GetDirectoryName(root);
|
||||
}
|
||||
}
|
||||
|
||||
private static Settings ReadSettings(IFileSystem fileSystem, string settingsPath)
|
||||
{
|
||||
return ReadSettings(fileSystem, settingsPath, false);
|
||||
}
|
||||
|
||||
private static Settings ReadSettings(IFileSystem fileSystem, string settingsPath, bool isMachineWideSettings)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new Settings(fileSystem, settingsPath, isMachineWideSettings);
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrap all IO operations on setting files with this function to avoid file-in-use errors
|
||||
/// </summary>
|
||||
private void ExecuteSynchronized(Action ioOperation)
|
||||
{
|
||||
var fileName = _fileSystem.GetFullPath(_fileName);
|
||||
|
||||
// Global: ensure mutex is honored across TS sessions
|
||||
using (var mutex = new Mutex(false, "Global\\" + EncryptionUtility.GenerateUniqueToken(fileName)))
|
||||
{
|
||||
var owner = false;
|
||||
try
|
||||
{
|
||||
// operations on NuGet.config should be very short lived
|
||||
owner = mutex.WaitOne(TimeSpan.FromMinutes(1));
|
||||
// decision here is to proceed even if we were not able to get mutex ownership
|
||||
// and let the potential IO errors bubble up. Reasoning is that failure to get
|
||||
// ownership probably means faulty hardware and in this case it's better to report
|
||||
// back than hang
|
||||
ioOperation();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (owner)
|
||||
{
|
||||
mutex.ReleaseMutex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using NuGet.Resources;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class SettingsCredentialProvider : ICredentialProvider
|
||||
{
|
||||
private readonly ICredentialProvider _credentialProvider;
|
||||
private readonly IPackageSourceProvider _packageSourceProvider;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public SettingsCredentialProvider(ICredentialProvider credentialProvider, IPackageSourceProvider packageSourceProvider)
|
||||
: this(credentialProvider, packageSourceProvider, NullLogger.Instance)
|
||||
{
|
||||
}
|
||||
|
||||
public SettingsCredentialProvider(ICredentialProvider credentialProvider, IPackageSourceProvider packageSourceProvider, ILogger logger)
|
||||
{
|
||||
if (credentialProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException("credentialProvider");
|
||||
}
|
||||
|
||||
if (packageSourceProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException("packageSourceProvider");
|
||||
}
|
||||
|
||||
_credentialProvider = credentialProvider;
|
||||
_packageSourceProvider = packageSourceProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public ICredentials GetCredentials(Uri uri, IWebProxy proxy, CredentialType credentialType, bool retrying)
|
||||
{
|
||||
NetworkCredential credentials;
|
||||
// If we are retrying, the stored credentials must be invalid.
|
||||
if (!retrying && (credentialType == CredentialType.RequestCredentials) && TryGetCredentials(uri, out credentials))
|
||||
{
|
||||
_logger.Log(MessageLevel.Info, NuGetResources.SettingsCredentials_UsingSavedCredentials, credentials.UserName);
|
||||
return credentials;
|
||||
}
|
||||
return _credentialProvider.GetCredentials(uri, proxy, credentialType, retrying);
|
||||
}
|
||||
|
||||
private bool TryGetCredentials(Uri uri, out NetworkCredential configurationCredentials)
|
||||
{
|
||||
var source = _packageSourceProvider.LoadPackageSources().FirstOrDefault(p =>
|
||||
{
|
||||
Uri sourceUri;
|
||||
return !String.IsNullOrEmpty(p.UserName)
|
||||
&& !String.IsNullOrEmpty(p.Password)
|
||||
&& Uri.TryCreate(p.Source, UriKind.Absolute, out sourceUri)
|
||||
&& UriUtility.UriStartsWith(sourceUri, uri);
|
||||
});
|
||||
if (source == null)
|
||||
{
|
||||
// The source is not in the config file
|
||||
configurationCredentials = null;
|
||||
return false;
|
||||
}
|
||||
configurationCredentials = new NetworkCredential(source.UserName, source.Password);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
internal static class CredentialProviderExtensions
|
||||
{
|
||||
private static readonly string[] _authenticationSchemes = new[] { "Basic", "NTLM", "Negotiate" };
|
||||
|
||||
internal static ICredentials GetCredentials(this ICredentialProvider provider, WebRequest request, CredentialType credentialType, bool retrying = false)
|
||||
{
|
||||
return provider.GetCredentials(request.RequestUri, request.Proxy, credentialType, retrying);
|
||||
}
|
||||
|
||||
internal static ICredentials AsCredentialCache(this ICredentials credentials, Uri uri)
|
||||
{
|
||||
// No credentials then bail
|
||||
if (credentials == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Do nothing with default credentials
|
||||
if (credentials == CredentialCache.DefaultCredentials ||
|
||||
credentials == CredentialCache.DefaultNetworkCredentials)
|
||||
{
|
||||
return credentials;
|
||||
}
|
||||
|
||||
// If this isn't a NetworkCredential then leave it alone
|
||||
var networkCredentials = credentials as NetworkCredential;
|
||||
if (networkCredentials == null)
|
||||
{
|
||||
return credentials;
|
||||
}
|
||||
|
||||
// Set this up for each authentication scheme we support
|
||||
// The reason we're using a credential cache is so that the HttpWebRequest will forward our
|
||||
// credentials if there happened to be any redirects in the chain of requests.
|
||||
var cache = new CredentialCache();
|
||||
foreach (var scheme in _authenticationSchemes)
|
||||
{
|
||||
cache.Add(uri, scheme, networkCredentials);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public static class SettingsExtensions
|
||||
{
|
||||
private const string ConfigSection = "config";
|
||||
|
||||
public static string GetRepositoryPath(this ISettings settings)
|
||||
{
|
||||
string path = settings.GetValue(ConfigSection, "repositoryPath", isPath: true);
|
||||
if (!String.IsNullOrEmpty(path))
|
||||
{
|
||||
path = path.Replace('/', System.IO.Path.DirectorySeparatorChar);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string GetDecryptedValue(this ISettings settings, string section, string key, bool isPath = false)
|
||||
{
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(key))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "key");
|
||||
}
|
||||
|
||||
var encryptedString = settings.GetValue(section, key, isPath);
|
||||
if (encryptedString == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (String.IsNullOrEmpty(encryptedString))
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
return EncryptionUtility.DecryptString(encryptedString);
|
||||
}
|
||||
|
||||
public static void SetEncryptedValue(this ISettings settings, string section, string key, string value)
|
||||
{
|
||||
if (String.IsNullOrEmpty(section))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "section");
|
||||
}
|
||||
if (String.IsNullOrEmpty(key))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "key");
|
||||
}
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(value))
|
||||
{
|
||||
settings.SetValue(section, key, String.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
var encryptedString = EncryptionUtility.EncryptString(value);
|
||||
settings.SetValue(section, key, encryptedString);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a config value for the specified key
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings instance to retrieve </param>
|
||||
/// <param name="key">The key to look up</param>
|
||||
/// <param name="decrypt">Determines if the retrieved value needs to be decrypted.</param>
|
||||
/// <param name="isPath">Determines if the retrieved value is returned as a path.</param>
|
||||
/// <returns>Null if the key was not found, value from config otherwise.</returns>
|
||||
public static string GetConfigValue(this ISettings settings, string key, bool decrypt = false, bool isPath = false)
|
||||
{
|
||||
return decrypt ?
|
||||
settings.GetDecryptedValue(ConfigSection, key, isPath) :
|
||||
settings.GetValue(ConfigSection, key, isPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a config value in the setting.
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings instance to store the key-value in.</param>
|
||||
/// <param name="key">The key to store.</param>
|
||||
/// <param name="value">The value to store.</param>
|
||||
/// <param name="encrypt">Determines if the value needs to be encrypted prior to storing.</param>
|
||||
public static void SetConfigValue(this ISettings settings, string key, string value, bool encrypt = false)
|
||||
{
|
||||
if (encrypt == true)
|
||||
{
|
||||
settings.SetEncryptedValue(ConfigSection, key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.SetValue(ConfigSection, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a config value from settings
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings instance to delete the key from.</param>
|
||||
/// <param name="key">The key to delete.</param>
|
||||
/// <returns>True if the value was deleted, false otherwise.</returns>
|
||||
public static bool DeleteConfigValue(this ISettings settings, string key)
|
||||
{
|
||||
return settings.DeleteValue(ConfigSection, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
internal class CredentialStore : ICredentialCache
|
||||
{
|
||||
private readonly ConcurrentDictionary<Uri, ICredentials> _credentialCache = new ConcurrentDictionary<Uri, ICredentials>();
|
||||
|
||||
private static readonly CredentialStore _instance = new CredentialStore();
|
||||
|
||||
public static CredentialStore Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public ICredentials GetCredentials(Uri uri)
|
||||
{
|
||||
Uri rootUri = GetRootUri(uri);
|
||||
|
||||
ICredentials credentials;
|
||||
if (_credentialCache.TryGetValue(uri, out credentials) ||
|
||||
_credentialCache.TryGetValue(rootUri, out credentials))
|
||||
{
|
||||
return credentials;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Add(Uri uri, ICredentials credentials)
|
||||
{
|
||||
Uri rootUri = GetRootUri(uri);
|
||||
_credentialCache.TryAdd(uri, credentials);
|
||||
_credentialCache.AddOrUpdate(rootUri, credentials, (u, c) => credentials);
|
||||
}
|
||||
|
||||
internal static Uri GetRootUri(Uri uri)
|
||||
{
|
||||
return new Uri(uri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace NuGet
|
||||
{
|
||||
public enum CredentialType
|
||||
{
|
||||
ProxyCredentials,
|
||||
RequestCredentials
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class HttpClient : IHttpClient
|
||||
{
|
||||
public event EventHandler<ProgressEventArgs> ProgressAvailable = delegate { };
|
||||
public event EventHandler<WebRequestEventArgs> SendingRequest = delegate { };
|
||||
|
||||
private static ICredentialProvider _credentialProvider;
|
||||
private Uri _uri;
|
||||
|
||||
public HttpClient(Uri uri)
|
||||
{
|
||||
if (uri == null)
|
||||
{
|
||||
throw new ArgumentNullException("uri");
|
||||
}
|
||||
|
||||
_uri = uri;
|
||||
}
|
||||
|
||||
public string UserAgent
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public virtual Uri Uri
|
||||
{
|
||||
get
|
||||
{
|
||||
return _uri;
|
||||
}
|
||||
set
|
||||
{
|
||||
_uri = value;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Uri OriginalUri
|
||||
{
|
||||
get { return _uri; }
|
||||
}
|
||||
|
||||
public string Method
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string ContentType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool AcceptCompression
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool DisableBuffering
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
// TODO: Get rid of this. Horrid to have static properties like this especially in a code path that does not look thread safe.
|
||||
public static ICredentialProvider DefaultCredentialProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
return _credentialProvider ?? NullCredentialProvider.Instance;
|
||||
}
|
||||
set
|
||||
{
|
||||
_credentialProvider = value;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual WebResponse GetResponse()
|
||||
{
|
||||
Func<WebRequest> webRequestFactory = () =>
|
||||
{
|
||||
WebRequest request = WebRequest.Create(Uri);
|
||||
InitializeRequestProperties(request);
|
||||
return request;
|
||||
};
|
||||
|
||||
var requestHelper = new RequestHelper(
|
||||
webRequestFactory,
|
||||
RaiseSendingRequest,
|
||||
ProxyCache.Instance,
|
||||
CredentialStore.Instance,
|
||||
DefaultCredentialProvider,
|
||||
DisableBuffering);
|
||||
return requestHelper.GetResponse();
|
||||
}
|
||||
|
||||
public void InitializeRequest(WebRequest request)
|
||||
{
|
||||
// TODO: Clean this up. This is no longer used with the move to WCF 5.6.1, changes to the request are not applied to the actual request.
|
||||
|
||||
// Setup the request properties like content type and compression
|
||||
InitializeRequestProperties(request);
|
||||
|
||||
// Use credentials from the cache if any for this uri
|
||||
TrySetCredentialsAndProxy(request);
|
||||
|
||||
// Give clients a chance to examine/modify the request object before the request actually goes out.
|
||||
RaiseSendingRequest(request);
|
||||
}
|
||||
|
||||
private void TrySetCredentialsAndProxy(WebRequest request)
|
||||
{
|
||||
// Used the cached credentials and proxy we have
|
||||
request.Credentials = CredentialStore.Instance.GetCredentials(Uri);
|
||||
request.Proxy = ProxyCache.Instance.GetProxy(Uri);
|
||||
STSAuthHelper.PrepareSTSRequest(request);
|
||||
}
|
||||
|
||||
private void InitializeRequestProperties(WebRequest request)
|
||||
{
|
||||
var httpRequest = request as HttpWebRequest;
|
||||
if (httpRequest != null)
|
||||
{
|
||||
httpRequest.UserAgent = UserAgent ?? HttpUtility.CreateUserAgentString("NuGet");
|
||||
httpRequest.CookieContainer = new CookieContainer();
|
||||
if (AcceptCompression)
|
||||
{
|
||||
httpRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
|
||||
}
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(ContentType))
|
||||
{
|
||||
request.ContentType = ContentType;
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(Method))
|
||||
{
|
||||
request.Method = Method;
|
||||
}
|
||||
}
|
||||
|
||||
public void DownloadData(Stream targetStream)
|
||||
{
|
||||
const int ChunkSize = 1024 * 4; // 4KB
|
||||
|
||||
using (var response = GetResponse())
|
||||
{
|
||||
// Total response length
|
||||
int length = (int)response.ContentLength;
|
||||
using (Stream stream = response.GetResponseStream())
|
||||
{
|
||||
// in some circumstances, the Content-Length response header is missing, resulting in
|
||||
// the ContentLength = -1. In which case, we copy the whole stream and do not report progress.
|
||||
if (length < 0)
|
||||
{
|
||||
stream.CopyTo(targetStream);
|
||||
|
||||
// reporting fake progress as 100%
|
||||
OnProgressAvailable(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We read the response stream chunk by chunk (each chunk is 4KB).
|
||||
// After reading each chunk, we report the progress based on the total number bytes read so far.
|
||||
int totalReadSoFar = 0;
|
||||
byte[] buffer = new byte[ChunkSize];
|
||||
while (totalReadSoFar < length)
|
||||
{
|
||||
int bytesRead = stream.Read(buffer, 0, Math.Min(length - totalReadSoFar, ChunkSize));
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetStream.Write(buffer, 0, bytesRead);
|
||||
|
||||
totalReadSoFar += bytesRead;
|
||||
OnProgressAvailable((totalReadSoFar * 100) / length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProgressAvailable(int percentage)
|
||||
{
|
||||
ProgressAvailable(this, new ProgressEventArgs(percentage));
|
||||
}
|
||||
|
||||
private void RaiseSendingRequest(WebRequest webRequest)
|
||||
{
|
||||
SendingRequest(this, new WebRequestEventArgs(webRequest));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public static class HttpUtility
|
||||
{
|
||||
private const string UserAgentTemplate = "{0}/{1} ({2})";
|
||||
private const string UserAgentWithHostTemplate = "{0}/{1} ({2}, {3})";
|
||||
private const string ProjectGuidsHeader = "NuGet-ProjectGuids";
|
||||
|
||||
public static string CreateUserAgentString(string client)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
throw new ArgumentNullException("client");
|
||||
}
|
||||
|
||||
var version = typeof(HttpUtility).Assembly.GetName().Version;
|
||||
return String.Format(CultureInfo.InvariantCulture, UserAgentTemplate, client, version, Environment.OSVersion);
|
||||
}
|
||||
|
||||
public static string CreateUserAgentString(string client, string host)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
throw new ArgumentNullException("client");
|
||||
}
|
||||
|
||||
if (host == null)
|
||||
{
|
||||
throw new ArgumentNullException("host");
|
||||
}
|
||||
|
||||
var version = typeof(HttpUtility).Assembly.GetName().Version;
|
||||
return String.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
UserAgentWithHostTemplate,
|
||||
client,
|
||||
version /* NuGetnuget version */,
|
||||
Environment.OSVersion /* OS version */,
|
||||
host /* VS SKU + version */);
|
||||
}
|
||||
|
||||
public static void SetUserAgent(WebRequest request, string userAgent, string projectGuids = null)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException("request");
|
||||
}
|
||||
|
||||
if (userAgent == null)
|
||||
{
|
||||
throw new ArgumentNullException("userAgent");
|
||||
}
|
||||
|
||||
var httpRequest = request as HttpWebRequest;
|
||||
if (httpRequest != null)
|
||||
{
|
||||
httpRequest.UserAgent = userAgent;
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Headers[HttpRequestHeader.UserAgent] = userAgent;
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(projectGuids))
|
||||
{
|
||||
request.Headers[ProjectGuidsHeader] = projectGuids;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this Request instance may be reused from the previous request.
|
||||
// thus we clear the header to avoid sending project types of the previous request, if any
|
||||
request.Headers.Remove(ProjectGuidsHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public interface ICredentialCache
|
||||
{
|
||||
void Add(Uri uri, ICredentials credentials);
|
||||
ICredentials GetCredentials(Uri uri);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface represents the basic interface that one needs to implement in order to
|
||||
/// support repository authentication.
|
||||
/// </summary>
|
||||
public interface ICredentialProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns CredentialState state that let's the consumer know if ICredentials
|
||||
/// were discovered by the ICredentialProvider. The credentials argument is then
|
||||
/// populated with the discovered valid credentials that can be used for the given Uri.
|
||||
/// The proxy instance if passed will be used to ensure that the request goes through the proxy
|
||||
/// to ensure successful connection to the destination Uri.
|
||||
/// </summary>
|
||||
ICredentials GetCredentials(Uri uri, IWebProxy proxy, CredentialType credentialType, bool retrying);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public interface IHttpClient : IHttpClientEvents
|
||||
{
|
||||
string UserAgent
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
Uri Uri
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
Uri OriginalUri
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
bool AcceptCompression
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This is expensive")]
|
||||
WebResponse GetResponse();
|
||||
void InitializeRequest(WebRequest request);
|
||||
void DownloadData(Stream targetStream);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public interface IHttpClientEvents : IProgressProvider
|
||||
{
|
||||
event EventHandler<WebRequestEventArgs> SendingRequest;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
// For unit testing
|
||||
public interface IHttpWebResponse : IDisposable
|
||||
{
|
||||
HttpStatusCode StatusCode { get; }
|
||||
Uri ResponseUri { get; }
|
||||
string AuthType { get; }
|
||||
NameValueCollection Headers { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public interface IProxyCache
|
||||
{
|
||||
void Add(IWebProxy proxy);
|
||||
IWebProxy GetProxy(Uri uri);
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
/// <remarks>
|
||||
/// Based on the blog post by Travis Illig at http://www.paraesthesia.com/archive/2009/12/16/posting-multipartform-data-using-.net-webrequest.aspx
|
||||
/// </remarks>
|
||||
public class MultipartWebRequest
|
||||
{
|
||||
private const string FormDataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n";
|
||||
private const string FileTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n";
|
||||
private readonly Dictionary<string, string> _formData;
|
||||
|
||||
private readonly List<PostFileData> _files;
|
||||
|
||||
public MultipartWebRequest()
|
||||
: this(new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
}
|
||||
|
||||
public MultipartWebRequest(Dictionary<string, string> formData)
|
||||
{
|
||||
_formData = formData;
|
||||
_files = new List<PostFileData>();
|
||||
}
|
||||
|
||||
public void AddFormData(string key, string value)
|
||||
{
|
||||
_formData.Add(key, value);
|
||||
}
|
||||
|
||||
public void AddFile(Func<Stream> fileFactory, string fieldName, long length, string contentType = "application/octet-stream")
|
||||
{
|
||||
_files.Add(new PostFileData
|
||||
{
|
||||
FileFactory = fileFactory,
|
||||
FieldName = fieldName,
|
||||
ContentType = contentType,
|
||||
ContentLength = length
|
||||
});
|
||||
}
|
||||
|
||||
public void CreateMultipartRequest(WebRequest request)
|
||||
{
|
||||
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture);
|
||||
request.ContentType = "multipart/form-data; boundary=" + boundary;
|
||||
request.ContentLength = CalculateContentLength(boundary);
|
||||
|
||||
using (Stream stream = request.GetRequestStream())
|
||||
{
|
||||
foreach (var item in _formData)
|
||||
{
|
||||
string header = String.Format(CultureInfo.InvariantCulture, FormDataTemplate, boundary, item.Key, item.Value);
|
||||
byte[] headerBytes = Encoding.UTF8.GetBytes(header);
|
||||
stream.Write(headerBytes, 0, headerBytes.Length);
|
||||
}
|
||||
|
||||
byte[] newlineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
|
||||
foreach (var file in _files)
|
||||
{
|
||||
string header = String.Format(CultureInfo.InvariantCulture, FileTemplate, boundary, file.FieldName, file.FieldName, file.ContentType);
|
||||
byte[] headerBytes = Encoding.UTF8.GetBytes(header);
|
||||
stream.Write(headerBytes, 0, headerBytes.Length);
|
||||
|
||||
Stream fileStream = file.FileFactory();
|
||||
fileStream.CopyTo(stream, bufferSize: 4 * 1024);
|
||||
fileStream.Close();
|
||||
stream.Write(newlineBytes, 0, newlineBytes.Length);
|
||||
}
|
||||
|
||||
string trailer = String.Format(CultureInfo.InvariantCulture, "--{0}--", boundary);
|
||||
byte[] trailerBytes = Encoding.UTF8.GetBytes(trailer);
|
||||
stream.Write(trailerBytes, 0, trailerBytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private long CalculateContentLength(string boundary)
|
||||
{
|
||||
long totalContentLength = 0;
|
||||
|
||||
foreach (var item in _formData)
|
||||
{
|
||||
string header = String.Format(CultureInfo.InvariantCulture, FormDataTemplate, boundary, item.Key, item.Value);
|
||||
byte[] headerBytes = Encoding.UTF8.GetBytes(header);
|
||||
|
||||
totalContentLength += headerBytes.Length;
|
||||
}
|
||||
|
||||
byte[] newlineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
|
||||
foreach (var file in _files)
|
||||
{
|
||||
string header = String.Format(CultureInfo.InvariantCulture, FileTemplate, boundary, file.FieldName, file.FieldName, file.ContentType);
|
||||
byte[] headerBytes = Encoding.UTF8.GetBytes(header);
|
||||
|
||||
totalContentLength += headerBytes.Length;
|
||||
totalContentLength += file.ContentLength;
|
||||
totalContentLength += newlineBytes.Length;
|
||||
}
|
||||
|
||||
string trailer = String.Format(CultureInfo.InvariantCulture, "--{0}--", boundary);
|
||||
byte[] trailerBytes = Encoding.UTF8.GetBytes(trailer);
|
||||
|
||||
totalContentLength += trailerBytes.Length;
|
||||
|
||||
return totalContentLength;
|
||||
}
|
||||
|
||||
private sealed class PostFileData
|
||||
{
|
||||
public Func<Stream> FileFactory { get; set; }
|
||||
|
||||
public string ContentType { get; set; }
|
||||
|
||||
public string FieldName { get; set; }
|
||||
|
||||
public long ContentLength { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class NullCredentialProvider : ICredentialProvider
|
||||
{
|
||||
private static readonly NullCredentialProvider _instance = new NullCredentialProvider();
|
||||
|
||||
public static ICredentialProvider Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private NullCredentialProvider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ICredentials GetCredentials(Uri uri, IWebProxy proxy, CredentialType credentialType, bool retrying)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
internal class ProxyCache : IProxyCache
|
||||
{
|
||||
private const string HostKey = "http_proxy";
|
||||
private const string UserKey = "http_proxy.user";
|
||||
private const string PasswordKey = "http_proxy.password";
|
||||
|
||||
/// <summary>
|
||||
/// Capture the default System Proxy so that it can be re-used by the IProxyFinder
|
||||
/// because we can't rely on WebRequest.DefaultWebProxy since someone can modify the DefaultWebProxy
|
||||
/// property and we can't tell if it was modified and if we are still using System Proxy Settings or not.
|
||||
/// One limitation of this method is that it does not look at the config file to get the defined proxy
|
||||
/// settings.
|
||||
/// </summary>
|
||||
private static readonly IWebProxy _originalSystemProxy = WebRequest.GetSystemWebProxy();
|
||||
|
||||
private readonly ConcurrentDictionary<Uri, WebProxy> _cache = new ConcurrentDictionary<Uri, WebProxy>();
|
||||
|
||||
#if BOOTSTRAPPER
|
||||
// Temporarily commenting these out until we can figure out a nicer way of doing this in the bootstrapper.
|
||||
|
||||
private static readonly Lazy<ProxyCache> _instance = new Lazy<ProxyCache>(() => new ProxyCache());
|
||||
public ProxyCache()
|
||||
{
|
||||
|
||||
}
|
||||
#else
|
||||
// It's not likely that http proxy settings are set in machine wide settings,
|
||||
// so not passing machine wide settings to Settings.LoadDefaultSettings() should be fine.
|
||||
private static readonly Lazy<ProxyCache> _instance = new Lazy<ProxyCache>(() => new ProxyCache(Settings.LoadDefaultSettings(fileSystem: null, configFileName: null, machineWideSettings: null ), new EnvironmentVariableWrapper()));
|
||||
|
||||
private readonly ISettings _settings;
|
||||
private readonly IEnvironmentVariableReader _environment;
|
||||
|
||||
public ProxyCache(ISettings settings, IEnvironmentVariableReader environment)
|
||||
{
|
||||
_settings = settings;
|
||||
_environment = environment;
|
||||
}
|
||||
#endif
|
||||
|
||||
internal static ProxyCache Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public IWebProxy GetProxy(Uri uri)
|
||||
{
|
||||
#if !BOOTSTRAPPER
|
||||
// Check if the user has configured proxy details in settings or in the environment.
|
||||
WebProxy configuredProxy = GetUserConfiguredProxy();
|
||||
if (configuredProxy != null)
|
||||
{
|
||||
// If a proxy was cached, it means the stored credentials are incorrect. Use the cached one in this case.
|
||||
WebProxy actualProxy;
|
||||
if (_cache.TryGetValue(configuredProxy.Address, out actualProxy))
|
||||
{
|
||||
return actualProxy;
|
||||
}
|
||||
return configuredProxy;
|
||||
}
|
||||
#endif
|
||||
if (!IsSystemProxySet(uri))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
WebProxy systemProxy = GetSystemProxy(uri);
|
||||
|
||||
WebProxy effectiveProxy;
|
||||
// See if we have a proxy instance cached for this proxy address
|
||||
if (_cache.TryGetValue(systemProxy.Address, out effectiveProxy))
|
||||
{
|
||||
return effectiveProxy;
|
||||
}
|
||||
|
||||
return systemProxy;
|
||||
}
|
||||
|
||||
#if !BOOTSTRAPPER
|
||||
internal WebProxy GetUserConfiguredProxy()
|
||||
{
|
||||
// Try reading from the settings. The values are stored as 3 config values http_proxy, http_proxy_user, http_proxy_password
|
||||
var host = _settings.GetConfigValue(HostKey);
|
||||
if (!String.IsNullOrEmpty(host))
|
||||
{
|
||||
// The host is the minimal value we need to assume a user configured proxy.
|
||||
var webProxy = new WebProxy(host);
|
||||
string userName = _settings.GetConfigValue(UserKey);
|
||||
string password = _settings.GetConfigValue(PasswordKey, decrypt: true);
|
||||
|
||||
if (!String.IsNullOrEmpty(userName) && !String.IsNullOrEmpty(password))
|
||||
{
|
||||
webProxy.Credentials = new NetworkCredential(userName, password);
|
||||
}
|
||||
return webProxy;
|
||||
}
|
||||
|
||||
// Next try reading from the environment variable http_proxy. This would be specified as http://<username>:<password>@proxy.com
|
||||
host = _environment.GetEnvironmentVariable(HostKey);
|
||||
Uri uri;
|
||||
if (!String.IsNullOrEmpty(host) && Uri.TryCreate(host, UriKind.Absolute, out uri))
|
||||
{
|
||||
var webProxy = new WebProxy(uri.GetComponents(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped));
|
||||
if (!String.IsNullOrEmpty(uri.UserInfo))
|
||||
{
|
||||
var credentials = uri.UserInfo.Split(':');
|
||||
if (credentials.Length > 1)
|
||||
{
|
||||
webProxy.Credentials = new NetworkCredential(userName: credentials[0], password: credentials[1]);
|
||||
}
|
||||
}
|
||||
return webProxy;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
public void Add(IWebProxy proxy)
|
||||
{
|
||||
var webProxy = proxy as WebProxy;
|
||||
if (webProxy != null)
|
||||
{
|
||||
_cache.TryAdd(webProxy.Address, webProxy);
|
||||
}
|
||||
}
|
||||
|
||||
private static WebProxy GetSystemProxy(Uri uri)
|
||||
{
|
||||
// WebRequest.DefaultWebProxy seems to be more capable in terms of getting the default
|
||||
// proxy settings instead of the WebRequest.GetSystemProxy()
|
||||
var proxyUri = _originalSystemProxy.GetProxy(uri);
|
||||
return new WebProxy(proxyUri);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true or false if connecting through a proxy server
|
||||
/// </summary>
|
||||
/// <param name="uri"></param>
|
||||
/// <returns></returns>
|
||||
private static bool IsSystemProxySet(Uri uri)
|
||||
{
|
||||
// The reason for not calling the GetSystemProxy is because the object
|
||||
// that will be returned is no longer going to be the proxy that is set by the settings
|
||||
// on the users machine only the Address is going to be the same.
|
||||
// Not sure why the .NET team did not want to expose all of the useful settings like
|
||||
// ByPass list and other settings that we can't get because of it.
|
||||
// Anyway the reason why we need the DefaultWebProxy is to see if the uri that we are
|
||||
// getting the proxy for to should be bypassed or not. If it should be bypassed then
|
||||
// return that we don't need a proxy and we should try to connect directly.
|
||||
IWebProxy proxy = WebRequest.DefaultWebProxy;
|
||||
if (proxy != null)
|
||||
{
|
||||
Uri proxyUri = proxy.GetProxy(uri);
|
||||
if (proxyUri != null)
|
||||
{
|
||||
Uri proxyAddress = new Uri(proxyUri.AbsoluteUri);
|
||||
if (String.Equals(proxyAddress.AbsoluteUri, uri.AbsoluteUri))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool bypassUri = proxy.IsBypassed(uri);
|
||||
if (bypassUri)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
proxy = new WebProxy(proxyAddress);
|
||||
}
|
||||
}
|
||||
|
||||
return proxy != null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using NuGet.Resources;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
/// <summary>
|
||||
/// This class should be used when ever you are using a link that is actually
|
||||
/// redirecting to the destination link that you want to use as the data source.
|
||||
/// A good example of that is a link that forwards like the current nuget link
|
||||
/// that is configured as a default location for nuget packages.
|
||||
/// </summary>
|
||||
public class RedirectedHttpClient : HttpClient
|
||||
{
|
||||
private const string RedirectedClientCacheKey = "RedirectedHttpClient|";
|
||||
private readonly Uri _originalUri;
|
||||
private readonly MemoryCache _memoryCache;
|
||||
|
||||
public RedirectedHttpClient(Uri uri)
|
||||
: this(uri, MemoryCache.Instance)
|
||||
{
|
||||
}
|
||||
|
||||
public RedirectedHttpClient(Uri uri, MemoryCache memoryCache)
|
||||
: base(uri)
|
||||
{
|
||||
_originalUri = uri;
|
||||
_memoryCache = memoryCache;
|
||||
}
|
||||
|
||||
public override WebResponse GetResponse()
|
||||
{
|
||||
return CachedClient.GetResponse();
|
||||
}
|
||||
|
||||
public override Uri Uri
|
||||
{
|
||||
get
|
||||
{
|
||||
return CachedClient.Uri;
|
||||
}
|
||||
}
|
||||
|
||||
public override Uri OriginalUri
|
||||
{
|
||||
get
|
||||
{
|
||||
return _originalUri;
|
||||
}
|
||||
}
|
||||
|
||||
internal IHttpClient CachedClient
|
||||
{
|
||||
get
|
||||
{
|
||||
string cacheKey = GetCacheKey();
|
||||
// Reset the IHttpClient instance if we catch an Exception so that
|
||||
// subsequent requests are able to try and create it again in case there
|
||||
// was some issue with authentication or some other request related configuration
|
||||
// If we don't do it here then the exception is always thrown as soon as we
|
||||
// try to access the cached value property since it's backed up by Lazy<T>.
|
||||
try
|
||||
{
|
||||
return _memoryCache.GetOrAdd(cacheKey, EnsureClient, TimeSpan.FromHours(1));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Re-initialize the cache and throw the exception so that we can
|
||||
// see what happened.
|
||||
_memoryCache.Remove(cacheKey);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetCacheKey()
|
||||
{
|
||||
return RedirectedClientCacheKey + _originalUri.OriginalString;
|
||||
}
|
||||
|
||||
protected internal virtual IHttpClient EnsureClient()
|
||||
{
|
||||
var originalClient = new HttpClient(_originalUri);
|
||||
return new HttpClient(GetResponseUri(originalClient));
|
||||
}
|
||||
|
||||
private Uri GetResponseUri(HttpClient client)
|
||||
{
|
||||
using (WebResponse response = client.GetResponse())
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format(CultureInfo.CurrentCulture,
|
||||
NuGetResources.UnableToResolveUri,
|
||||
Uri));
|
||||
}
|
||||
|
||||
return response.ResponseUri;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
namespace NuGet
|
||||
{
|
||||
/// <summary>
|
||||
/// Set of known context values to be used in calls to HttpUtility.CreateUserAgentString
|
||||
/// </summary>
|
||||
public static class RepositoryOperationNames
|
||||
{
|
||||
public static readonly string OperationHeaderName = "NuGet-Operation";
|
||||
public static readonly string DependentPackageHeaderName = "NuGet-DependentPackage";
|
||||
public static readonly string DependentPackageVersionHeaderName = "NuGet-DependentPackageVersion";
|
||||
public static readonly string PackageId = "NuGet-PackageId";
|
||||
public static readonly string PackageVersion = "NuGet-PackageVersion";
|
||||
|
||||
public static readonly string Update = "Update";
|
||||
public static readonly string Install = "Install";
|
||||
public static readonly string Restore = "Restore";
|
||||
public static readonly string Mirror = "Mirror";
|
||||
public static readonly string Reinstall = "Reinstall";
|
||||
}
|
||||
}
|
||||
@@ -1,351 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Net;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is used to keep sending requests until a response code that doesn't require
|
||||
/// authentication happens or if the request requires authentication and
|
||||
/// the user has stopped trying to enter them (i.e. they hit cancel when they are prompted).
|
||||
/// </summary>
|
||||
internal class RequestHelper
|
||||
{
|
||||
private Func<WebRequest> _createRequest;
|
||||
private Action<WebRequest> _prepareRequest;
|
||||
private IProxyCache _proxyCache;
|
||||
private ICredentialCache _credentialCache;
|
||||
private ICredentialProvider _credentialProvider;
|
||||
|
||||
HttpWebRequest _previousRequest;
|
||||
IHttpWebResponse _previousResponse;
|
||||
HttpStatusCode? _previousStatusCode;
|
||||
int _credentialsRetryCount;
|
||||
bool _usingSTSAuth;
|
||||
bool _continueIfFailed;
|
||||
int _proxyCredentialsRetryCount;
|
||||
bool _basicAuthIsUsedInPreviousRequest;
|
||||
bool _disableBuffering;
|
||||
|
||||
public RequestHelper(Func<WebRequest> createRequest,
|
||||
Action<WebRequest> prepareRequest,
|
||||
IProxyCache proxyCache,
|
||||
ICredentialCache credentialCache,
|
||||
ICredentialProvider credentialProvider,
|
||||
bool disableBuffering)
|
||||
{
|
||||
_createRequest = createRequest;
|
||||
_prepareRequest = prepareRequest;
|
||||
_proxyCache = proxyCache;
|
||||
_credentialCache = credentialCache;
|
||||
_credentialProvider = credentialProvider;
|
||||
_disableBuffering = disableBuffering;
|
||||
}
|
||||
|
||||
public WebResponse GetResponse()
|
||||
{
|
||||
_previousRequest = null;
|
||||
_previousResponse = null;
|
||||
_previousStatusCode = null;
|
||||
_usingSTSAuth = false;
|
||||
_continueIfFailed = true;
|
||||
_proxyCredentialsRetryCount = 0;
|
||||
_credentialsRetryCount = 0;
|
||||
int failureCount = 0;
|
||||
const int MaxFailureCount = 10;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Create the request
|
||||
var request = (HttpWebRequest)_createRequest();
|
||||
ConfigureRequest(request);
|
||||
|
||||
try
|
||||
{
|
||||
if (_disableBuffering)
|
||||
{
|
||||
request.AllowWriteStreamBuffering = false;
|
||||
|
||||
// When buffering is disabled, we need to add the Authorization header
|
||||
// for basic authentication by ourselves.
|
||||
bool basicAuth = _previousResponse != null &&
|
||||
_previousResponse.AuthType != null &&
|
||||
_previousResponse.AuthType.IndexOf("Basic", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var networkCredentials = request.Credentials.GetCredential(request.RequestUri, "Basic");
|
||||
if (networkCredentials != null && basicAuth)
|
||||
{
|
||||
string authInfo = networkCredentials.UserName + ":" + networkCredentials.Password;
|
||||
authInfo = Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(authInfo));
|
||||
request.Headers["Authorization"] = "Basic " + authInfo;
|
||||
_basicAuthIsUsedInPreviousRequest = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the request, we do something like write to the request stream
|
||||
// which needs to happen last before the request goes out
|
||||
_prepareRequest(request);
|
||||
|
||||
// Shim and replace this request if needed for v3
|
||||
WebResponse response = HttpShim.Instance.ShimWebRequest(request);
|
||||
|
||||
// Cache the proxy and credentials
|
||||
_proxyCache.Add(request.Proxy);
|
||||
|
||||
ICredentials credentials = request.Credentials;
|
||||
_credentialCache.Add(request.RequestUri, credentials);
|
||||
_credentialCache.Add(response.ResponseUri, credentials);
|
||||
|
||||
return response;
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
++failureCount;
|
||||
if (failureCount >= MaxFailureCount)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
using (IHttpWebResponse response = GetResponse(ex.Response))
|
||||
{
|
||||
if (response == null &&
|
||||
ex.Status != WebExceptionStatus.SecureChannelFailure)
|
||||
{
|
||||
// No response, something went wrong so just rethrow
|
||||
throw;
|
||||
}
|
||||
|
||||
// Special case https connections that might require authentication
|
||||
if (ex.Status == WebExceptionStatus.SecureChannelFailure)
|
||||
{
|
||||
if (_continueIfFailed)
|
||||
{
|
||||
// Act like we got a 401 so that we prompt for credentials on the next request
|
||||
_previousStatusCode = HttpStatusCode.Unauthorized;
|
||||
continue;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
// If we were trying to authenticate the proxy or the request and succeeded, cache the result.
|
||||
if (_previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired &&
|
||||
response.StatusCode != HttpStatusCode.ProxyAuthenticationRequired)
|
||||
{
|
||||
_proxyCache.Add(request.Proxy);
|
||||
}
|
||||
else if (_previousStatusCode == HttpStatusCode.Unauthorized &&
|
||||
response.StatusCode != HttpStatusCode.Unauthorized)
|
||||
{
|
||||
_credentialCache.Add(request.RequestUri, request.Credentials);
|
||||
_credentialCache.Add(response.ResponseUri, request.Credentials);
|
||||
}
|
||||
|
||||
_usingSTSAuth = STSAuthHelper.TryRetrieveSTSToken(request.RequestUri, response);
|
||||
|
||||
if (!IsAuthenticationResponse(response) || !_continueIfFailed)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
if (!EnvironmentUtility.IsNet45Installed &&
|
||||
request.AllowWriteStreamBuffering == false &&
|
||||
response.AuthType != null &&
|
||||
IsNtlmOrKerberos(response.AuthType))
|
||||
{
|
||||
// integrated windows authentication does not work when buffering is
|
||||
// disabled on .net 4.0.
|
||||
throw;
|
||||
}
|
||||
|
||||
_previousRequest = request;
|
||||
_previousResponse = response;
|
||||
_previousStatusCode = _previousResponse.StatusCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureRequest(HttpWebRequest request)
|
||||
{
|
||||
request.Proxy = _proxyCache.GetProxy(request.RequestUri);
|
||||
if (request.Proxy != null && request.Proxy.Credentials == null)
|
||||
{
|
||||
request.Proxy.Credentials = CredentialCache.DefaultCredentials;
|
||||
}
|
||||
|
||||
if (_previousResponse == null || ShouldKeepAliveBeUsedInRequest(_previousRequest, _previousResponse))
|
||||
{
|
||||
// Try to use the cached credentials (if any, for the first request)
|
||||
request.Credentials = _credentialCache.GetCredentials(request.RequestUri);
|
||||
|
||||
// If there are no cached credentials, use the default ones
|
||||
if (request.Credentials == null)
|
||||
{
|
||||
request.UseDefaultCredentials = true;
|
||||
}
|
||||
}
|
||||
else if (_previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired)
|
||||
{
|
||||
request.Proxy.Credentials = _credentialProvider.GetCredentials(
|
||||
request, CredentialType.ProxyCredentials, retrying: _proxyCredentialsRetryCount > 0);
|
||||
_continueIfFailed = request.Proxy.Credentials != null;
|
||||
_proxyCredentialsRetryCount++;
|
||||
}
|
||||
else if (_previousStatusCode == HttpStatusCode.Unauthorized)
|
||||
{
|
||||
SetCredentialsOnAuthorizationError(request);
|
||||
}
|
||||
|
||||
SetKeepAliveHeaders(request, _previousResponse);
|
||||
if (_usingSTSAuth)
|
||||
{
|
||||
// Add request headers if the server requires STS based auth.
|
||||
STSAuthHelper.PrepareSTSRequest(request);
|
||||
}
|
||||
|
||||
// Wrap the credentials in a CredentialCache in case there is a redirect
|
||||
// and credentials need to be kept around.
|
||||
request.Credentials = request.Credentials.AsCredentialCache(request.RequestUri);
|
||||
}
|
||||
|
||||
private void SetCredentialsOnAuthorizationError(HttpWebRequest request)
|
||||
{
|
||||
if (_usingSTSAuth)
|
||||
{
|
||||
// If we are using STS, the auth's being performed by a request header.
|
||||
// We do not need to ask the user for credentials at this point.
|
||||
return;
|
||||
}
|
||||
|
||||
// When buffering is disabled, we need to handle basic auth ourselves.
|
||||
bool basicAuth = _previousResponse.AuthType != null &&
|
||||
_previousResponse.AuthType.IndexOf("Basic", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
if (_disableBuffering && basicAuth && !_basicAuthIsUsedInPreviousRequest)
|
||||
{
|
||||
// The basic auth credentials were not sent in the last request.
|
||||
// We need to try with cached credentials in this request.
|
||||
request.Credentials = _credentialCache.GetCredentials(request.RequestUri);
|
||||
}
|
||||
|
||||
if (request.Credentials == null)
|
||||
{
|
||||
request.Credentials = _credentialProvider.GetCredentials(
|
||||
request, CredentialType.RequestCredentials, retrying: _credentialsRetryCount > 0);
|
||||
}
|
||||
|
||||
_continueIfFailed = request.Credentials != null;
|
||||
_credentialsRetryCount++;
|
||||
}
|
||||
|
||||
private static IHttpWebResponse GetResponse(WebResponse response)
|
||||
{
|
||||
var httpWebResponse = response as IHttpWebResponse;
|
||||
if (httpWebResponse == null)
|
||||
{
|
||||
var webResponse = response as HttpWebResponse;
|
||||
if (webResponse == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new HttpWebResponseWrapper(webResponse);
|
||||
}
|
||||
|
||||
return httpWebResponse;
|
||||
}
|
||||
|
||||
private static bool IsAuthenticationResponse(IHttpWebResponse response)
|
||||
{
|
||||
return response.StatusCode == HttpStatusCode.Unauthorized ||
|
||||
response.StatusCode == HttpStatusCode.ProxyAuthenticationRequired;
|
||||
}
|
||||
|
||||
private static void SetKeepAliveHeaders(HttpWebRequest request, IHttpWebResponse previousResponse)
|
||||
{
|
||||
// KeepAlive is required for NTLM and Kerberos authentication. If we've never been authenticated or are using a different auth, we
|
||||
// should not require KeepAlive.
|
||||
// REVIEW: The WWW-Authenticate header is tricky to parse so a Equals might not be correct.
|
||||
if (previousResponse == null ||
|
||||
!IsNtlmOrKerberos(previousResponse.AuthType))
|
||||
{
|
||||
// This is to work around the "The underlying connection was closed: An unexpected error occurred on a receive."
|
||||
// exception.
|
||||
request.KeepAlive = false;
|
||||
request.ProtocolVersion = HttpVersion.Version10;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldKeepAliveBeUsedInRequest(HttpWebRequest request, IHttpWebResponse response)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException("request");
|
||||
}
|
||||
|
||||
if (response == null)
|
||||
{
|
||||
throw new ArgumentNullException("response");
|
||||
}
|
||||
|
||||
return !request.KeepAlive && IsNtlmOrKerberos(response.AuthType);
|
||||
}
|
||||
|
||||
private static bool IsNtlmOrKerberos(string authType)
|
||||
{
|
||||
if (String.IsNullOrEmpty(authType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return authType.IndexOf("NTLM", StringComparison.OrdinalIgnoreCase) != -1
|
||||
|| authType.IndexOf("Kerberos", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
}
|
||||
|
||||
private class HttpWebResponseWrapper : IHttpWebResponse
|
||||
{
|
||||
private readonly HttpWebResponse _response;
|
||||
public HttpWebResponseWrapper(HttpWebResponse response)
|
||||
{
|
||||
_response = response;
|
||||
}
|
||||
|
||||
public string AuthType
|
||||
{
|
||||
get
|
||||
{
|
||||
return _response.Headers[HttpResponseHeader.WwwAuthenticate];
|
||||
}
|
||||
}
|
||||
|
||||
public HttpStatusCode StatusCode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _response.StatusCode;
|
||||
}
|
||||
}
|
||||
|
||||
public Uri ResponseUri
|
||||
{
|
||||
get
|
||||
{
|
||||
return _response.ResponseUri;
|
||||
}
|
||||
}
|
||||
|
||||
public NameValueCollection Headers
|
||||
{
|
||||
get
|
||||
{
|
||||
return _response.Headers;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_response != null)
|
||||
{
|
||||
_response.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Security;
|
||||
using System.Text;
|
||||
using NuGet.Resources;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public static class STSAuthHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Response header that specifies the WSTrust13 Windows Transport endpoint.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO: Is there a way to discover this \ negotiate this endpoint?
|
||||
/// </remarks>
|
||||
private const string STSEndPointHeader = "X-NuGet-STS-EndPoint";
|
||||
|
||||
/// <summary>
|
||||
/// Response header that specifies the realm to authenticate for. In most cases this would be the gallery we are going up against.
|
||||
/// </summary>
|
||||
private const string STSRealmHeader = "X-NuGet-STS-Realm";
|
||||
|
||||
/// <summary>
|
||||
/// Request header that contains the SAML token.
|
||||
/// </summary>
|
||||
private const string STSTokenHeader = "X-NuGet-STS-Token";
|
||||
|
||||
/// <summary>
|
||||
/// Adds the SAML token as a header to the request if it is already cached for this host.
|
||||
/// </summary>
|
||||
public static void PrepareSTSRequest(WebRequest request)
|
||||
{
|
||||
string cacheKey = GetCacheKey(request.RequestUri);
|
||||
string token;
|
||||
if (MemoryCache.Instance.TryGetValue(cacheKey, out token))
|
||||
{
|
||||
request.Headers[STSTokenHeader] = EncodeHeader(token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to retrieve a SAML token if the response indicates that server requires STS-based auth.
|
||||
/// </summary>
|
||||
/// <param name="requestUri">The feed URI we were connecting to.</param>
|
||||
/// <param name="response">The 401 response we receieved from the server.</param>
|
||||
/// <returns>True if we were able to successfully retrieve a SAML token from the STS specified in the response headers.</returns>
|
||||
public static bool TryRetrieveSTSToken(Uri requestUri, IHttpWebResponse response)
|
||||
{
|
||||
if (response.StatusCode != HttpStatusCode.Unauthorized)
|
||||
{
|
||||
// We only care to do STS auth if the server returned a 401
|
||||
return false;
|
||||
}
|
||||
|
||||
string endPoint = GetSTSEndPoint(response);
|
||||
string realm = response.Headers[STSRealmHeader];
|
||||
if (String.IsNullOrEmpty(endPoint) || String.IsNullOrEmpty(realm))
|
||||
{
|
||||
// The server does not conform to our STS-auth requirements.
|
||||
return false;
|
||||
}
|
||||
|
||||
string cacheKey = GetCacheKey(requestUri);
|
||||
|
||||
// TODO: We need to figure out a way to cache the token for the duration of the token's validity (which is available as part of it's result).
|
||||
MemoryCache.Instance.GetOrAdd(cacheKey,
|
||||
() => GetSTSToken(requestUri, endPoint, realm),
|
||||
TimeSpan.FromMinutes(30),
|
||||
absoluteExpiration: true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string GetSTSToken(Uri requestUri, string endPoint, string appliesTo)
|
||||
{
|
||||
var typeProvider = WIFTypeProvider.GetWIFTypes();
|
||||
if (typeProvider == null)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.UnableToLocateWIF, requestUri));
|
||||
}
|
||||
|
||||
var binding = new WS2007HttpBinding(SecurityMode.Transport);
|
||||
dynamic factory = Activator.CreateInstance(typeProvider.ChannelFactory, binding, endPoint);
|
||||
factory.TrustVersion = TrustVersion.WSTrust13;
|
||||
|
||||
// Check if we can create 4.5 types.
|
||||
dynamic rst = Activator.CreateInstance(typeProvider.RequestSecurityToken);
|
||||
rst.RequestType = GetFieldValue<string>(typeProvider.RequestTypes, "Issue");
|
||||
rst.KeyType = GetFieldValue<string>(typeProvider.KeyTypes, "Bearer");
|
||||
|
||||
// Dynamic verifies the type of the instance so we cannot use it to assign a value for this property.
|
||||
var endPointAddress = Activator.CreateInstance(typeProvider.EndPoint, appliesTo);
|
||||
SetProperty(rst, "AppliesTo", endPointAddress);
|
||||
|
||||
dynamic channel = factory.CreateChannel();
|
||||
dynamic securityToken = channel.Issue(rst);
|
||||
return securityToken.TokenXml.OuterXml;
|
||||
}
|
||||
|
||||
private static void SetProperty(object instance, string propertyName, object value)
|
||||
{
|
||||
var type = instance.GetType();
|
||||
var property = type.GetProperty(propertyName);
|
||||
|
||||
var propertySetter = property.GetSetMethod();
|
||||
propertySetter.Invoke(instance, new[] { value });
|
||||
}
|
||||
|
||||
private static TVal GetFieldValue<TVal>(Type type, string fieldName)
|
||||
{
|
||||
return (TVal)type.GetField(fieldName).GetValue(obj: null);
|
||||
}
|
||||
|
||||
private static string GetSTSEndPoint(IHttpWebResponse response)
|
||||
{
|
||||
return response.Headers[STSEndPointHeader].SafeTrim();
|
||||
}
|
||||
|
||||
private static string GetCacheKey(Uri requestUri)
|
||||
{
|
||||
return STSTokenHeader + "|" + requestUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
|
||||
}
|
||||
|
||||
private static string EncodeHeader(string token)
|
||||
{
|
||||
return Convert.ToBase64String(Encoding.UTF8.GetBytes(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Services.Client;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
/// <summary>
|
||||
/// HttpShim is a singleton that provides an event OnWebRequest for modifying WebRequests before they
|
||||
/// are executed.
|
||||
/// </summary>
|
||||
public sealed class HttpShim
|
||||
{
|
||||
private static HttpShim _instance;
|
||||
private Func<DataServiceClientRequestMessageArgs, DataServiceClientRequestMessage> _dataServiceHandler;
|
||||
private Func<WebRequest, WebResponse> _webHandler;
|
||||
|
||||
internal HttpShim()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Static instance of the shim.
|
||||
/// </summary>
|
||||
public static HttpShim Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new HttpShim();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
internal WebResponse ShimWebRequest(WebRequest request)
|
||||
{
|
||||
WebResponse response = null;
|
||||
|
||||
InitializeRequest(request);
|
||||
|
||||
if (_webHandler != null)
|
||||
{
|
||||
response = _webHandler(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = request.GetResponse();
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
internal DataServiceClientRequestMessage ShimDataServiceRequest(DataServiceClientRequestMessageArgs args)
|
||||
{
|
||||
DataServiceClientRequestMessage message = null;
|
||||
|
||||
if (_dataServiceHandler != null)
|
||||
{
|
||||
message = _dataServiceHandler(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
message = new HttpWebRequestMessage(args);
|
||||
}
|
||||
|
||||
// apply proxy and credential settings on the core web request
|
||||
InitializeMessage(message);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
public void SetWebRequestHandler(Func<WebRequest, WebResponse> handler)
|
||||
{
|
||||
_webHandler = handler;
|
||||
}
|
||||
|
||||
public void SetDataServiceRequestHandler(Func<DataServiceClientRequestMessageArgs, DataServiceClientRequestMessage> handler)
|
||||
{
|
||||
_dataServiceHandler = handler;
|
||||
}
|
||||
|
||||
public void ClearHandlers()
|
||||
{
|
||||
_dataServiceHandler = null;
|
||||
_webHandler = null;
|
||||
}
|
||||
|
||||
// apply proxy settings and credentials here since they can no longer be applied from the context event
|
||||
private static void InitializeMessage(DataServiceClientRequestMessage message)
|
||||
{
|
||||
IShimWebRequest webRequestMessage = message as IShimWebRequest;
|
||||
HttpWebRequestMessage httpMessage = message as HttpWebRequestMessage;
|
||||
|
||||
if (httpMessage != null)
|
||||
{
|
||||
InitializeRequest(httpMessage.HttpWebRequest);
|
||||
}
|
||||
else if (webRequestMessage != null)
|
||||
{
|
||||
InitializeRequest(webRequestMessage.Request);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitializeRequest(WebRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetCredentialsAndProxy(request);
|
||||
InitializeRequestProperties(request);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// ignore failures here, that can be caused by GetResponse having already been called
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetCredentialsAndProxy(WebRequest request)
|
||||
{
|
||||
// Used the cached credentials and proxy we have
|
||||
if (request.Credentials == null)
|
||||
{
|
||||
request.Credentials = CredentialStore.Instance.GetCredentials(request.RequestUri);
|
||||
}
|
||||
|
||||
if (request.Proxy == null)
|
||||
{
|
||||
request.Proxy = ProxyCache.Instance.GetProxy(request.RequestUri);
|
||||
}
|
||||
|
||||
STSAuthHelper.PrepareSTSRequest(request);
|
||||
}
|
||||
|
||||
private static void InitializeRequestProperties(WebRequest request)
|
||||
{
|
||||
var httpRequest = request as HttpWebRequest;
|
||||
if (httpRequest != null)
|
||||
{
|
||||
httpRequest.UserAgent = HttpUtility.CreateUserAgentString("NuGet Shim");
|
||||
httpRequest.CookieContainer = new CookieContainer();
|
||||
httpRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public interface IShimController : IDisposable
|
||||
{
|
||||
void Enable(IPackageSourceProvider sourceProvider);
|
||||
|
||||
void UpdateSources();
|
||||
|
||||
void Disable();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the IShimController instance for the v3 client.
|
||||
/// </summary>
|
||||
public interface IShimControllerProvider : IDisposable
|
||||
{
|
||||
IShimController Controller { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public interface IShimWebRequest
|
||||
{
|
||||
HttpWebRequest Request { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
using Microsoft.Data.OData;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Services.Client;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class ShimDataRequestMessage : IODataRequestMessage
|
||||
{
|
||||
|
||||
public HttpWebRequest WebRequest { get; private set; }
|
||||
|
||||
private SendingRequest2EventArgs _args;
|
||||
|
||||
public ShimDataRequestMessage(SendingRequest2EventArgs args)
|
||||
{
|
||||
_args = args;
|
||||
|
||||
WebRequest = ShimWebHelpers.AddHeaders(HttpWebRequest.CreateHttp(_args.RequestMessage.Url), _args.RequestMessage.Headers);
|
||||
|
||||
WebRequest.Method = _args.RequestMessage.Method;
|
||||
}
|
||||
|
||||
public ShimDataRequestMessage(DataServiceClientRequestMessageArgs args)
|
||||
{
|
||||
WebRequest = ShimWebHelpers.AddHeaders(HttpWebRequest.CreateHttp(args.RequestUri), args.Headers);
|
||||
|
||||
WebRequest.Method = args.Method;
|
||||
}
|
||||
|
||||
public string GetHeader(string headerName)
|
||||
{
|
||||
return WebRequest.Headers.Get(headerName);
|
||||
}
|
||||
|
||||
public Stream GetStream()
|
||||
{
|
||||
return WebRequest.GetRequestStream();
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<string, string>> Headers
|
||||
{
|
||||
get
|
||||
{
|
||||
List<KeyValuePair<string, string>> headers = new List<KeyValuePair<string, string>>();
|
||||
|
||||
foreach(var header in WebRequest.Headers.AllKeys)
|
||||
{
|
||||
headers.Add(new KeyValuePair<string, string>(header, WebRequest.Headers.Get(header)));
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHeader(string headerName, string headerValue)
|
||||
{
|
||||
if (StringComparer.OrdinalIgnoreCase.Equals(headerName, "Content-Length"))
|
||||
{
|
||||
WebRequest.ContentLength = long.Parse(headerValue, CultureInfo.InvariantCulture.NumberFormat);
|
||||
}
|
||||
else
|
||||
{
|
||||
WebRequest.Headers.Set(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
|
||||
public Uri Url
|
||||
{
|
||||
get
|
||||
{
|
||||
return WebRequest.RequestUri;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string Method
|
||||
{
|
||||
get
|
||||
{
|
||||
return WebRequest.Method;
|
||||
}
|
||||
set
|
||||
{
|
||||
WebRequest.Method = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public static class ShimWebHelpers
|
||||
{
|
||||
|
||||
public static HttpWebRequest AddHeaders(HttpWebRequest response, IEnumerable<KeyValuePair<string, string>> headers)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
{
|
||||
if (StringComparer.OrdinalIgnoreCase.Equals(header.Key, "accept"))
|
||||
{
|
||||
response.Accept = header.Value;
|
||||
}
|
||||
else if (StringComparer.OrdinalIgnoreCase.Equals(header.Key, "user-agent"))
|
||||
{
|
||||
response.UserAgent = header.Value;
|
||||
}
|
||||
else if (StringComparer.OrdinalIgnoreCase.Equals(header.Key, "content-type"))
|
||||
{
|
||||
response.ContentType = header.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.Headers.Set(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public static HttpWebRequest AddHeaders(HttpWebRequest response, IDictionary<string, string> headers)
|
||||
{
|
||||
return AddHeaders(response, headers.AsEnumerable());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
internal abstract class WIFTypeProvider
|
||||
{
|
||||
public abstract Type ChannelFactory { get; }
|
||||
|
||||
public abstract Type RequestSecurityToken { get; }
|
||||
|
||||
public abstract Type EndPoint { get; }
|
||||
|
||||
public abstract Type RequestTypes { get; }
|
||||
|
||||
public abstract Type KeyTypes { get; }
|
||||
|
||||
protected abstract string AssemblyName { get; }
|
||||
|
||||
public static WIFTypeProvider GetWIFTypes()
|
||||
{
|
||||
// First attempt to look up the 4.5 types
|
||||
WIFTypeProvider wifProvider = new WIFTypes45();
|
||||
if (wifProvider.ChannelFactory != null)
|
||||
{
|
||||
return wifProvider;
|
||||
}
|
||||
|
||||
// We could be on 4.0 with the SDK \ WIF Runtime installed.
|
||||
wifProvider = new WIFTypes40();
|
||||
if (wifProvider.ChannelFactory != null)
|
||||
{
|
||||
return wifProvider;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected string QualifyTypeName(string typeName)
|
||||
{
|
||||
return typeName + ',' + AssemblyName;
|
||||
}
|
||||
|
||||
private sealed class WIFTypes40 : WIFTypeProvider
|
||||
{
|
||||
public override Type ChannelFactory
|
||||
{
|
||||
get
|
||||
{
|
||||
string typeName = QualifyTypeName("Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory");
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
public override Type RequestSecurityToken
|
||||
{
|
||||
get
|
||||
{
|
||||
string typeName = QualifyTypeName("Microsoft.IdentityModel.Protocols.WSTrust.RequestSecurityToken");
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
public override Type EndPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(System.ServiceModel.EndpointAddress);
|
||||
}
|
||||
}
|
||||
|
||||
public override Type RequestTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
string typeName = QualifyTypeName("Microsoft.IdentityModel.SecurityTokenService.RequestTypes");
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
public override Type KeyTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
string typeName = QualifyTypeName("Microsoft.IdentityModel.SecurityTokenService.KeyTypes");
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
protected override string AssemblyName
|
||||
{
|
||||
get { return "Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; }
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class WIFTypes45 : WIFTypeProvider
|
||||
{
|
||||
public override Type ChannelFactory
|
||||
{
|
||||
get
|
||||
{
|
||||
return Type.GetType("System.ServiceModel.Security.WSTrustChannelFactory, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
|
||||
}
|
||||
}
|
||||
|
||||
public override Type RequestSecurityToken
|
||||
{
|
||||
get
|
||||
{
|
||||
string typeName = QualifyTypeName("System.IdentityModel.Protocols.WSTrust.RequestSecurityToken");
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
public override Type EndPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
string typeName = QualifyTypeName("System.IdentityModel.Protocols.WSTrust.EndpointReference");
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
public override Type RequestTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
string typeName = QualifyTypeName("System.IdentityModel.Protocols.WSTrust.RequestTypes");
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
public override Type KeyTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
string typeName = QualifyTypeName("System.IdentityModel.Protocols.WSTrust.KeyTypes");
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
protected override string AssemblyName
|
||||
{
|
||||
get { return "System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public interface IMachineWideSettings
|
||||
{
|
||||
IEnumerable<Settings> Settings { get; }
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
<PackageReference Include="System.ServiceModel.Federation" Version="4.8.1" />
|
||||
<PackageReference Include="System.IO.Packaging" Version="5.0.0" />
|
||||
<PackageReference Include="System.Diagnostics.Tracing" Version="4.3.0" />
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="5.0.0" />
|
||||
<PackageReference Include="SimpleWeakEventListener" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Data.Services.Client" Version="5.8.4" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
|
||||
@@ -1,501 +0,0 @@
|
||||
using NuGet.Resources;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Services.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
[DataServiceKey("Id", "Version")]
|
||||
[EntityPropertyMapping("LastUpdated", SyndicationItemProperty.Updated, SyndicationTextContentKind.Plaintext, keepInContent: false)]
|
||||
[EntityPropertyMapping("Id", SyndicationItemProperty.Title, SyndicationTextContentKind.Plaintext, keepInContent: false)]
|
||||
[EntityPropertyMapping("Authors", SyndicationItemProperty.AuthorName, SyndicationTextContentKind.Plaintext, keepInContent: false)]
|
||||
[EntityPropertyMapping("Summary", SyndicationItemProperty.Summary, SyndicationTextContentKind.Plaintext, keepInContent: false)]
|
||||
[CLSCompliant(false)]
|
||||
public class DataServicePackage : IPackage
|
||||
{
|
||||
private IHashProvider _hashProvider;
|
||||
private bool _usingMachineCache;
|
||||
private string _licenseNames;
|
||||
internal IPackage _package;
|
||||
|
||||
public string Id
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Version
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Authors
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Owners
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Uri IconUrl
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Uri LicenseUrl
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Uri ProjectUrl
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Uri ReportAbuseUrl
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Uri GalleryDetailsUrl
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string LicenseNames
|
||||
{
|
||||
get { return _licenseNames; }
|
||||
set
|
||||
{
|
||||
_licenseNames = value;
|
||||
LicenseNameCollection =
|
||||
String.IsNullOrEmpty(value) ? new string[0] : value.Split(';').ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<string> LicenseNameCollection { get; private set; }
|
||||
|
||||
public Uri LicenseReportUrl { get; set; }
|
||||
|
||||
public Uri DownloadUrl
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool Listed
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public DateTimeOffset? Published
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public DateTimeOffset LastUpdated
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int DownloadCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool RequireLicenseAcceptance
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool DevelopmentDependency
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Summary
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string ReleaseNotes
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Language
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Tags
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Dependencies
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string PackageHash
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string PackageHashAlgorithm
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool IsLatestVersion
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool IsAbsoluteLatestVersion
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Copyright
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string MinClientVersion
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private string OldHash { get; set; }
|
||||
|
||||
private IPackage Package
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsurePackage(MachineCache.Default);
|
||||
return _package;
|
||||
}
|
||||
}
|
||||
|
||||
internal PackageDownloader Downloader { get; set; }
|
||||
|
||||
internal IHashProvider HashProvider
|
||||
{
|
||||
get { return _hashProvider ?? new CryptoHashProvider(PackageHashAlgorithm); }
|
||||
set { _hashProvider = value; }
|
||||
}
|
||||
|
||||
bool IPackage.Listed
|
||||
{
|
||||
get
|
||||
{
|
||||
return Listed;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<string> IPackageMetadata.Authors
|
||||
{
|
||||
get
|
||||
{
|
||||
if (String.IsNullOrEmpty(Authors))
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
return Authors.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<string> IPackageMetadata.Owners
|
||||
{
|
||||
get
|
||||
{
|
||||
if (String.IsNullOrEmpty(Owners))
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
return Owners.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<PackageDependencySet> DependencySets
|
||||
{
|
||||
get
|
||||
{
|
||||
if (String.IsNullOrEmpty(Dependencies))
|
||||
{
|
||||
return Enumerable.Empty<PackageDependencySet>();
|
||||
}
|
||||
|
||||
return ParseDependencySet(Dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<PackageReferenceSet> PackageAssemblyReferences
|
||||
{
|
||||
get
|
||||
{
|
||||
return Package.PackageAssemblyReferences;
|
||||
}
|
||||
}
|
||||
|
||||
SemanticVersion IPackageName.Version
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Version != null)
|
||||
{
|
||||
return new SemanticVersion(Version);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Version IPackageMetadata.MinClientVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!String.IsNullOrEmpty(MinClientVersion))
|
||||
{
|
||||
return new Version(MinClientVersion);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IPackageAssemblyReference> AssemblyReferences
|
||||
{
|
||||
get
|
||||
{
|
||||
return Package.AssemblyReferences;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<FrameworkAssemblyReference> FrameworkAssemblies
|
||||
{
|
||||
get
|
||||
{
|
||||
return Package.FrameworkAssemblies;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<FrameworkName> GetSupportedFrameworks()
|
||||
{
|
||||
return Package.GetSupportedFrameworks();
|
||||
}
|
||||
|
||||
public IEnumerable<IPackageFile> GetFiles()
|
||||
{
|
||||
return Package.GetFiles();
|
||||
}
|
||||
|
||||
public Stream GetStream()
|
||||
{
|
||||
return Package.GetStream();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.GetFullName();
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
|
||||
internal void EnsurePackage(IPackageCacheRepository cacheRepository)
|
||||
{
|
||||
// OData caches instances of DataServicePackage while updating their property values. As a result,
|
||||
// the ZipPackage that we downloaded may no longer be valid (as indicated by a newer hash).
|
||||
// When using MachineCache, once we've verified that the hashes match (which happens the first time around),
|
||||
// we'll simply verify the file exists between successive calls.
|
||||
IPackageMetadata packageMetadata = this;
|
||||
if (_package == null ||
|
||||
(_package is OptimizedZipPackage && !((OptimizedZipPackage)_package).IsValid) ||
|
||||
!String.Equals(OldHash, PackageHash, StringComparison.OrdinalIgnoreCase) ||
|
||||
(_usingMachineCache && !cacheRepository.Exists(Id, packageMetadata.Version)))
|
||||
{
|
||||
IPackage newPackage = null;
|
||||
bool inMemOnly = false;
|
||||
bool isValid = false;
|
||||
|
||||
// If the package exists in the cache and has the correct hash then use it. Otherwise download it.
|
||||
if (TryGetPackage(cacheRepository, packageMetadata, out newPackage) && MatchPackageHash(newPackage))
|
||||
{
|
||||
isValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We either do not have a package available locally or they are invalid. Download the package from the server.
|
||||
if (cacheRepository.InvokeOnPackage(packageMetadata.Id, packageMetadata.Version,
|
||||
(stream) => Downloader.DownloadPackage(DownloadUrl, this, stream)))
|
||||
{
|
||||
newPackage = cacheRepository.FindPackage(packageMetadata.Id, packageMetadata.Version);
|
||||
Debug.Assert(newPackage != null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this can happen when access to the %LocalAppData% directory is blocked, e.g. on Windows Azure Web Site build
|
||||
using (var targetStream = new MemoryStream())
|
||||
{
|
||||
Downloader.DownloadPackage(DownloadUrl, this, targetStream);
|
||||
targetStream.Seek(0, SeekOrigin.Begin);
|
||||
newPackage = new ZipPackage(targetStream);
|
||||
}
|
||||
|
||||
inMemOnly = true;
|
||||
}
|
||||
|
||||
// Because of CDN caching, the hash returned in odata feed
|
||||
// can be out of sync with the hash of the file itself.
|
||||
// So for now, we cannot call MatchPackageHash(newPackage) to
|
||||
// validate that the file downloaded has the right hash.
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
// apply the changes if the package hash was valid
|
||||
if (isValid)
|
||||
{
|
||||
_package = newPackage;
|
||||
|
||||
// Use the id and version from the nuspec incase they were different in format or casing
|
||||
Id = _package.Id;
|
||||
Version = _package.Version.ToString();
|
||||
|
||||
// Make a note that the backing store for the ZipPackage is the machine cache.
|
||||
_usingMachineCache = !inMemOnly;
|
||||
|
||||
OldHash = PackageHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ensure package must end with a valid package, since we cannot load one we must throw.
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
|
||||
NuGetResources.Error_InvalidPackage, Version, Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the given package matches PackageHash
|
||||
/// </summary>
|
||||
private bool MatchPackageHash(IPackage package)
|
||||
{
|
||||
return package != null && package.GetHash(HashProvider).Equals(PackageHash, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static List<PackageDependencySet> ParseDependencySet(string value)
|
||||
{
|
||||
var dependencySets = new List<PackageDependencySet>();
|
||||
|
||||
var dependencies = value.Split('|').Select(ParseDependency).ToList();
|
||||
|
||||
// group the dependencies by target framework
|
||||
var groups = dependencies.GroupBy(d => d.Item3);
|
||||
|
||||
dependencySets.AddRange(
|
||||
groups.Select(g => new PackageDependencySet(
|
||||
g.Key, // target framework
|
||||
g.Where(pair => !String.IsNullOrEmpty(pair.Item1)) // the Id is empty when a group is empty.
|
||||
.Select(pair => new PackageDependency(pair.Item1, pair.Item2))))); // dependencies by that target framework
|
||||
return dependencySets;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a dependency from the feed in the format:
|
||||
/// id or id:versionSpec, or id:versionSpec:targetFramework
|
||||
/// </summary>
|
||||
private static Tuple<string, IVersionSpec, FrameworkName> ParseDependency(string value)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// IMPORTANT: Do not pass StringSplitOptions.RemoveEmptyEntries to this method, because it will break
|
||||
// if the version spec is null, for in that case, the Dependencies string sent down is "<id>::<target framework>".
|
||||
// We do want to preserve the second empty element after the split.
|
||||
string[] tokens = value.Trim().Split(new[] { ':' });
|
||||
|
||||
if (tokens.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Trim the id
|
||||
string id = tokens[0].Trim();
|
||||
|
||||
IVersionSpec versionSpec = null;
|
||||
if (tokens.Length > 1)
|
||||
{
|
||||
// Attempt to parse the version
|
||||
VersionUtility.TryParseVersionSpec(tokens[1], out versionSpec);
|
||||
}
|
||||
|
||||
var targetFramework = (tokens.Length > 2 && !String.IsNullOrEmpty(tokens[2]))
|
||||
? VersionUtility.ParseFrameworkName(tokens[2])
|
||||
: null;
|
||||
|
||||
return Tuple.Create(id, versionSpec, targetFramework);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to return null if any error occurred while trying to find the package.")]
|
||||
private static bool TryGetPackage(IPackageRepository repository, IPackageMetadata packageMetadata, out IPackage package)
|
||||
{
|
||||
try
|
||||
{
|
||||
package = repository.FindPackage(packageMetadata.Id, packageMetadata.Version);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If the package in the repository is corrupted then return null
|
||||
package = null;
|
||||
}
|
||||
return package != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class PackageRestoreConsent
|
||||
{
|
||||
private const string EnvironmentVariableName = "EnableNuGetPackageRestore";
|
||||
private const string PackageRestoreSection = "packageRestore";
|
||||
private const string PackageRestoreConsentKey = "enabled";
|
||||
|
||||
// the key to enable/disable automatic package restore during build.
|
||||
private const string PackageRestoreAutomaticKey = "automatic";
|
||||
|
||||
private readonly ISettings _settings;
|
||||
private readonly IEnvironmentVariableReader _environmentReader;
|
||||
private readonly ConfigurationDefaults _configurationDefaults;
|
||||
|
||||
public PackageRestoreConsent(ISettings settings)
|
||||
: this(settings, new EnvironmentVariableWrapper())
|
||||
{
|
||||
}
|
||||
|
||||
public PackageRestoreConsent(ISettings settings, IEnvironmentVariableReader environmentReader)
|
||||
: this(settings, environmentReader, ConfigurationDefaults.Instance)
|
||||
{
|
||||
}
|
||||
|
||||
public PackageRestoreConsent(ISettings settings, IEnvironmentVariableReader environmentReader, ConfigurationDefaults configurationDefaults)
|
||||
{
|
||||
if (settings == null)
|
||||
{
|
||||
throw new ArgumentNullException("settings");
|
||||
}
|
||||
|
||||
if (environmentReader == null)
|
||||
{
|
||||
throw new ArgumentNullException("environmentReader");
|
||||
}
|
||||
|
||||
if (configurationDefaults == null)
|
||||
{
|
||||
throw new ArgumentNullException("configurationDefaults");
|
||||
}
|
||||
|
||||
_settings = settings;
|
||||
_environmentReader = environmentReader;
|
||||
_configurationDefaults = configurationDefaults;
|
||||
}
|
||||
|
||||
public bool IsGranted
|
||||
{
|
||||
get
|
||||
{
|
||||
string envValue = _environmentReader.GetEnvironmentVariable(EnvironmentVariableName).SafeTrim();
|
||||
return IsGrantedInSettings || IsSet(envValue);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGrantedInSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
string settingsValue = _settings.GetValue(PackageRestoreSection, PackageRestoreConsentKey);
|
||||
if (String.IsNullOrWhiteSpace(settingsValue))
|
||||
{
|
||||
settingsValue = _configurationDefaults.DefaultPackageRestoreConsent;
|
||||
}
|
||||
settingsValue = settingsValue.SafeTrim();
|
||||
|
||||
if (String.IsNullOrEmpty(settingsValue))
|
||||
{
|
||||
// default value of user consent is true.
|
||||
return true;
|
||||
}
|
||||
|
||||
return IsSet(settingsValue);
|
||||
}
|
||||
set
|
||||
{
|
||||
_settings.SetValue(PackageRestoreSection, PackageRestoreConsentKey, value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAutomatic
|
||||
{
|
||||
get
|
||||
{
|
||||
string settingsValue = _settings.GetValue(PackageRestoreSection, PackageRestoreAutomaticKey);
|
||||
if (String.IsNullOrWhiteSpace(settingsValue))
|
||||
{
|
||||
return IsGrantedInSettings;
|
||||
}
|
||||
settingsValue = settingsValue.SafeTrim();
|
||||
return IsSet(settingsValue);
|
||||
}
|
||||
set
|
||||
{
|
||||
_settings.SetValue(PackageRestoreSection, PackageRestoreAutomaticKey, value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsSet(string value)
|
||||
{
|
||||
bool boolResult;
|
||||
int intResult;
|
||||
return ((Boolean.TryParse(value, out boolResult) && boolResult) ||
|
||||
(Int32.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out intResult) && (intResult == 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public interface IPackageSourceProvider
|
||||
{
|
||||
IEnumerable<PackageSource> LoadPackageSources();
|
||||
|
||||
event EventHandler PackageSourcesSaved;
|
||||
void SavePackageSources(IEnumerable<PackageSource> sources);
|
||||
void DisablePackageSource(PackageSource source);
|
||||
bool IsPackageSourceEnabled(PackageSource source);
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
[DataContract]
|
||||
public class PackageSource : IEquatable<PackageSource>
|
||||
{
|
||||
private readonly int _hashCode;
|
||||
|
||||
[DataMember]
|
||||
public string Name { get; private set; }
|
||||
|
||||
[DataMember]
|
||||
public string Source { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This does not represent just the NuGet Official Feed alone
|
||||
/// It may also represent a Default Package Source set by Configuration Defaults
|
||||
/// </summary>
|
||||
public bool IsOfficial { get; set; }
|
||||
|
||||
public bool IsMachineWide { get; set; }
|
||||
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
public string UserName { get; set; }
|
||||
|
||||
public string Password { get; set; }
|
||||
|
||||
public bool IsPasswordClearText { get; set; }
|
||||
|
||||
public bool IsPersistable
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public PackageSource(string source) :
|
||||
this(source, source, isEnabled: true)
|
||||
{
|
||||
}
|
||||
|
||||
public PackageSource(string source, string name) :
|
||||
this(source, name, isEnabled: true)
|
||||
{
|
||||
}
|
||||
|
||||
public PackageSource(string source, string name, bool isEnabled)
|
||||
: this(source, name, isEnabled, isOfficial: false)
|
||||
{
|
||||
}
|
||||
|
||||
public PackageSource(
|
||||
string source,
|
||||
string name,
|
||||
bool isEnabled,
|
||||
bool isOfficial,
|
||||
bool isPersistable = true)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException("name");
|
||||
}
|
||||
|
||||
Name = name;
|
||||
Source = source;
|
||||
IsEnabled = isEnabled;
|
||||
IsOfficial = isOfficial;
|
||||
IsPersistable = isPersistable;
|
||||
_hashCode = Name.ToUpperInvariant().GetHashCode() * 3137 + Source.ToUpperInvariant().GetHashCode();
|
||||
}
|
||||
|
||||
public bool Equals(PackageSource other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Name.Equals(other.Name, StringComparison.CurrentCultureIgnoreCase) &&
|
||||
Source.Equals(other.Source, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var source = obj as PackageSource;
|
||||
if (source != null)
|
||||
{
|
||||
return Equals(source);
|
||||
}
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name + " [" + Source + "]";
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _hashCode;
|
||||
}
|
||||
|
||||
public PackageSource Clone()
|
||||
{
|
||||
return new PackageSource(Source, Name, IsEnabled, IsOfficial, IsPersistable) { UserName = UserName, Password = Password, IsPasswordClearText = IsPasswordClearText, IsMachineWide = IsMachineWide };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,384 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class PackageSourceProvider : IPackageSourceProvider
|
||||
{
|
||||
private const string PackageSourcesSectionName = "packageSources";
|
||||
private const string DisabledPackageSourcesSectionName = "disabledPackageSources";
|
||||
private const string CredentialsSectionName = "packageSourceCredentials";
|
||||
private const string UsernameToken = "Username";
|
||||
private const string PasswordToken = "Password";
|
||||
private const string ClearTextPasswordToken = "ClearTextPassword";
|
||||
private readonly ISettings _settingsManager;
|
||||
private readonly IEnumerable<PackageSource> _providerDefaultSources;
|
||||
private readonly IDictionary<PackageSource, PackageSource> _migratePackageSources;
|
||||
private readonly IEnumerable<PackageSource> _configurationDefaultSources;
|
||||
private IEnvironmentVariableReader _environment;
|
||||
|
||||
public PackageSourceProvider(ISettings settingsManager)
|
||||
: this(settingsManager, providerDefaultSources: null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new PackageSourceProvider instance.
|
||||
/// </summary>
|
||||
/// <param name="settingsManager">Specifies the settings file to use to read package sources.</param>
|
||||
/// <param name="providerDefaultSources">Specifies the default sources to be used as per the PackageSourceProvider. These are always loaded
|
||||
/// Default Feeds from PackageSourceProvider are generally the feeds from the NuGet Client like the NuGetOfficialFeed from the Visual Studio client for NuGet</param>
|
||||
public PackageSourceProvider(ISettings settingsManager, IEnumerable<PackageSource> providerDefaultSources)
|
||||
: this(settingsManager, providerDefaultSources, migratePackageSources: null)
|
||||
{
|
||||
}
|
||||
|
||||
public PackageSourceProvider(
|
||||
ISettings settingsManager,
|
||||
IEnumerable<PackageSource> providerDefaultSources,
|
||||
IDictionary<PackageSource, PackageSource> migratePackageSources)
|
||||
: this(settingsManager, providerDefaultSources, migratePackageSources, ConfigurationDefaults.Instance.DefaultPackageSources, new EnvironmentVariableWrapper())
|
||||
{
|
||||
}
|
||||
|
||||
internal PackageSourceProvider(
|
||||
ISettings settingsManager,
|
||||
IEnumerable<PackageSource> providerDefaultSources,
|
||||
IDictionary<PackageSource, PackageSource> migratePackageSources,
|
||||
IEnumerable<PackageSource> configurationDefaultSources,
|
||||
IEnvironmentVariableReader environment)
|
||||
{
|
||||
if (settingsManager == null)
|
||||
{
|
||||
throw new ArgumentNullException("settingsManager");
|
||||
}
|
||||
_settingsManager = settingsManager;
|
||||
_providerDefaultSources = providerDefaultSources ?? Enumerable.Empty<PackageSource>();
|
||||
_migratePackageSources = migratePackageSources;
|
||||
_configurationDefaultSources = configurationDefaultSources ?? Enumerable.Empty<PackageSource>();
|
||||
_environment = environment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns PackageSources if specified in the config file. Else returns the default sources specified in the constructor.
|
||||
/// If no default values were specified, returns an empty sequence.
|
||||
/// </summary>
|
||||
public IEnumerable<PackageSource> LoadPackageSources()
|
||||
{
|
||||
var sources = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var settingsValue = new List<SettingValue>();
|
||||
IList<SettingValue> values = _settingsManager.GetSettingValues(PackageSourcesSectionName, isPath: true);
|
||||
var machineWideSourcesCount = 0;
|
||||
|
||||
if (!values.IsEmpty())
|
||||
{
|
||||
var machineWideSources = new List<SettingValue>();
|
||||
|
||||
// remove duplicate sources. Pick the one with the highest priority.
|
||||
// note that Reverse() is needed because items in 'values' is in
|
||||
// ascending priority order.
|
||||
foreach (var settingValue in values.Reverse())
|
||||
{
|
||||
if (!sources.Contains(settingValue.Key))
|
||||
{
|
||||
if (settingValue.IsMachineWide)
|
||||
{
|
||||
machineWideSources.Add(settingValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
settingsValue.Add(settingValue);
|
||||
}
|
||||
|
||||
sources.Add(settingValue.Key);
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the the list to be backward compatible
|
||||
settingsValue.Reverse();
|
||||
machineWideSourcesCount = machineWideSources.Count;
|
||||
|
||||
// Add machine wide sources at the end
|
||||
settingsValue.AddRange(machineWideSources);
|
||||
}
|
||||
|
||||
var loadedPackageSources = new List<PackageSource>();
|
||||
if (!settingsValue.IsEmpty())
|
||||
{
|
||||
// get list of disabled packages
|
||||
var disabledSources = (_settingsManager.GetSettingValues(DisabledPackageSourcesSectionName, isPath: false) ?? Enumerable.Empty<SettingValue>())
|
||||
.ToDictionary(s => s.Key, StringComparer.CurrentCultureIgnoreCase);
|
||||
loadedPackageSources = settingsValue.
|
||||
Select(p =>
|
||||
{
|
||||
string name = p.Key;
|
||||
string src = p.Value;
|
||||
PackageSourceCredential creds = ReadCredential(name);
|
||||
|
||||
bool isEnabled = true;
|
||||
SettingValue disabledSource;
|
||||
if (disabledSources.TryGetValue(name, out disabledSource) &&
|
||||
disabledSource.Priority >= p.Priority)
|
||||
{
|
||||
isEnabled = false;
|
||||
}
|
||||
|
||||
return new PackageSource(src, name, isEnabled)
|
||||
{
|
||||
UserName = creds != null ? creds.Username : null,
|
||||
Password = creds != null ? creds.Password : null,
|
||||
IsPasswordClearText = creds != null && creds.IsPasswordClearText,
|
||||
IsMachineWide = p.IsMachineWide
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
if (_migratePackageSources != null)
|
||||
{
|
||||
MigrateSources(loadedPackageSources);
|
||||
}
|
||||
}
|
||||
|
||||
SetDefaultPackageSources(loadedPackageSources, machineWideSourcesCount);
|
||||
|
||||
return loadedPackageSources;
|
||||
}
|
||||
|
||||
private PackageSourceCredential ReadCredential(string sourceName)
|
||||
{
|
||||
PackageSourceCredential environmentCredentials = ReadCredentialFromEnvironment(sourceName);
|
||||
|
||||
if (environmentCredentials != null)
|
||||
{
|
||||
return environmentCredentials;
|
||||
}
|
||||
|
||||
var values = _settingsManager.GetNestedValues(CredentialsSectionName, sourceName);
|
||||
if (!values.IsEmpty())
|
||||
{
|
||||
string userName = values.FirstOrDefault(k => k.Key.Equals(UsernameToken, StringComparison.OrdinalIgnoreCase)).Value;
|
||||
|
||||
if (!String.IsNullOrEmpty(userName))
|
||||
{
|
||||
string encryptedPassword = values.FirstOrDefault(k => k.Key.Equals(PasswordToken, StringComparison.OrdinalIgnoreCase)).Value;
|
||||
if (!String.IsNullOrEmpty(encryptedPassword))
|
||||
{
|
||||
return new PackageSourceCredential(userName, EncryptionUtility.DecryptString(encryptedPassword), isPasswordClearText: false);
|
||||
}
|
||||
|
||||
string clearTextPassword = values.FirstOrDefault(k => k.Key.Equals(ClearTextPasswordToken, StringComparison.Ordinal)).Value;
|
||||
if (!String.IsNullOrEmpty(clearTextPassword))
|
||||
{
|
||||
return new PackageSourceCredential(userName, clearTextPassword, isPasswordClearText: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private PackageSourceCredential ReadCredentialFromEnvironment(string sourceName)
|
||||
{
|
||||
string rawCredentials = _environment.GetEnvironmentVariable("NuGetPackageSourceCredentials_" + sourceName);
|
||||
if (string.IsNullOrEmpty(rawCredentials))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var match = Regex.Match(rawCredentials.Trim(), @"^Username=(?<user>.*?);\s*Password=(?<pass>.*?)$", RegexOptions.IgnoreCase);
|
||||
if (!match.Success)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PackageSourceCredential(match.Groups["user"].Value, match.Groups["pass"].Value, true);
|
||||
}
|
||||
|
||||
private void MigrateSources(List<PackageSource> loadedPackageSources)
|
||||
{
|
||||
bool hasChanges = false;
|
||||
List<PackageSource> packageSourcesToBeRemoved = new List<PackageSource>();
|
||||
|
||||
// doing migration
|
||||
for (int i = 0; i < loadedPackageSources.Count; i++)
|
||||
{
|
||||
PackageSource ps = loadedPackageSources[i];
|
||||
PackageSource targetPackageSource;
|
||||
if (_migratePackageSources.TryGetValue(ps, out targetPackageSource))
|
||||
{
|
||||
if (loadedPackageSources.Any(p => p.Equals(targetPackageSource)))
|
||||
{
|
||||
packageSourcesToBeRemoved.Add(loadedPackageSources[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
loadedPackageSources[i] = targetPackageSource.Clone();
|
||||
// make sure we preserve the IsEnabled property when migrating package sources
|
||||
loadedPackageSources[i].IsEnabled = ps.IsEnabled;
|
||||
}
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (PackageSource packageSource in packageSourcesToBeRemoved)
|
||||
{
|
||||
loadedPackageSources.Remove(packageSource);
|
||||
}
|
||||
|
||||
if (hasChanges)
|
||||
{
|
||||
SavePackageSources(loadedPackageSources);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDefaultPackageSources(List<PackageSource> loadedPackageSources, int machineWideSourcesCount)
|
||||
{
|
||||
// There are 4 different cases to consider for default package sources
|
||||
// Case 1. Default Package Source is already present matching both feed source and the feed name
|
||||
// Case 2. Default Package Source is already present matching feed source but with a different feed name. DO NOTHING
|
||||
// Case 3. Default Package Source is not present, but there is another feed source with the same feed name. Override that feed entirely
|
||||
// Case 4. Default Package Source is not present, simply, add it
|
||||
|
||||
IEnumerable<PackageSource> allDefaultPackageSources = _configurationDefaultSources;
|
||||
|
||||
if (allDefaultPackageSources.IsEmpty<PackageSource>())
|
||||
{
|
||||
// Update provider default sources and use provider default sources since _configurationDefaultSources is empty
|
||||
UpdateProviderDefaultSources(loadedPackageSources);
|
||||
allDefaultPackageSources = _providerDefaultSources;
|
||||
}
|
||||
|
||||
var defaultPackageSourcesToBeAdded = new List<PackageSource>();
|
||||
foreach (PackageSource packageSource in allDefaultPackageSources)
|
||||
{
|
||||
int sourceMatchingIndex = loadedPackageSources.FindIndex(p => p.Source.Equals(packageSource.Source, StringComparison.OrdinalIgnoreCase));
|
||||
if (sourceMatchingIndex != -1)
|
||||
{
|
||||
if (loadedPackageSources[sourceMatchingIndex].Name.Equals(packageSource.Name, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
// Case 1: Both the feed name and source matches. DO NOTHING except set IsOfficial to true
|
||||
loadedPackageSources[sourceMatchingIndex].IsOfficial = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case 2: Only feed source matches but name is different. DO NOTHING
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int nameMatchingIndex = loadedPackageSources.FindIndex(p => p.Name.Equals(packageSource.Name, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (nameMatchingIndex != -1)
|
||||
{
|
||||
// Case 3: Only feed name matches but source is different. Override it entirely
|
||||
loadedPackageSources[nameMatchingIndex] = packageSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Case 4: Default package source is not present. Add it to the temp list. Later, the temp listed is inserted above the machine wide sources
|
||||
defaultPackageSourcesToBeAdded.Add(packageSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
loadedPackageSources.InsertRange(loadedPackageSources.Count - machineWideSourcesCount, defaultPackageSourcesToBeAdded);
|
||||
}
|
||||
|
||||
private void UpdateProviderDefaultSources(List<PackageSource> loadedSources)
|
||||
{
|
||||
// If there are NO other non-machine wide sources, providerDefaultSource should be enabled
|
||||
bool areProviderDefaultSourcesEnabled = loadedSources.Count == 0 || loadedSources.Where(p => !p.IsMachineWide).Count() == 0;
|
||||
|
||||
foreach (PackageSource packageSource in _providerDefaultSources)
|
||||
{
|
||||
packageSource.IsEnabled = areProviderDefaultSourcesEnabled;
|
||||
packageSource.IsOfficial = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void SavePackageSources(IEnumerable<PackageSource> sources)
|
||||
{
|
||||
// clear the old values
|
||||
_settingsManager.DeleteSection(PackageSourcesSectionName);
|
||||
|
||||
// and write the new ones
|
||||
_settingsManager.SetValues(
|
||||
PackageSourcesSectionName,
|
||||
sources.Where(p => !p.IsMachineWide && p.IsPersistable)
|
||||
.Select(p => new KeyValuePair<string, string>(p.Name, p.Source))
|
||||
.ToList());
|
||||
|
||||
// overwrite new values for the <disabledPackageSources> section
|
||||
_settingsManager.DeleteSection(DisabledPackageSourcesSectionName);
|
||||
|
||||
_settingsManager.SetValues(
|
||||
DisabledPackageSourcesSectionName,
|
||||
sources.Where(p => !p.IsEnabled).Select(p => new KeyValuePair<string, string>(p.Name, "true")).ToList());
|
||||
|
||||
// Overwrite the <packageSourceCredentials> section
|
||||
_settingsManager.DeleteSection(CredentialsSectionName);
|
||||
|
||||
var sourceWithCredentials = sources.Where(s => !String.IsNullOrEmpty(s.UserName) && !String.IsNullOrEmpty(s.Password));
|
||||
foreach (var source in sourceWithCredentials)
|
||||
{
|
||||
_settingsManager.SetNestedValues(CredentialsSectionName, source.Name, new[] {
|
||||
new KeyValuePair<string, string>(UsernameToken, source.UserName),
|
||||
ReadPasswordValues(source)
|
||||
});
|
||||
}
|
||||
|
||||
if (PackageSourcesSaved != null)
|
||||
{
|
||||
PackageSourcesSaved(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private static KeyValuePair<string, string> ReadPasswordValues(PackageSource source)
|
||||
{
|
||||
string passwordToken = source.IsPasswordClearText ? ClearTextPasswordToken : PasswordToken;
|
||||
string passwordValue = source.IsPasswordClearText ? source.Password : EncryptionUtility.EncryptString(source.Password);
|
||||
|
||||
return new KeyValuePair<string, string>(passwordToken, passwordValue);
|
||||
}
|
||||
|
||||
public void DisablePackageSource(PackageSource source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
|
||||
_settingsManager.SetValue(DisabledPackageSourcesSectionName, source.Name, "true");
|
||||
}
|
||||
|
||||
public bool IsPackageSourceEnabled(PackageSource source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
|
||||
string value = _settingsManager.GetValue(DisabledPackageSourcesSectionName, source.Name);
|
||||
|
||||
// It doesn't matter what value it is.
|
||||
// As long as the package source name is persisted in the <disabledPackageSources> section, the source is disabled.
|
||||
return String.IsNullOrEmpty(value);
|
||||
}
|
||||
|
||||
private class PackageSourceCredential
|
||||
{
|
||||
public string Username { get; private set; }
|
||||
|
||||
public string Password { get; private set; }
|
||||
|
||||
public bool IsPasswordClearText { get; private set; }
|
||||
|
||||
public PackageSourceCredential(string username, string password, bool isPasswordClearText)
|
||||
{
|
||||
Username = username;
|
||||
Password = password;
|
||||
IsPasswordClearText = isPasswordClearText;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler PackageSourcesSaved;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public static class PackageSourceProviderExtensions
|
||||
{
|
||||
public static AggregateRepository CreateAggregateRepository(
|
||||
this IPackageSourceProvider provider,
|
||||
IPackageRepositoryFactory factory,
|
||||
bool ignoreFailingRepositories)
|
||||
{
|
||||
return new AggregateRepository(
|
||||
factory,
|
||||
provider.GetEnabledPackageSources().Select(s => s.Source),
|
||||
ignoreFailingRepositories);
|
||||
}
|
||||
|
||||
public static IPackageRepository CreatePriorityPackageRepository(
|
||||
this IPackageSourceProvider provider,
|
||||
IPackageRepositoryFactory factory,
|
||||
IPackageRepository primaryRepository)
|
||||
{
|
||||
var nonActivePackageSources = provider.GetEnabledPackageSources()
|
||||
.Where(s => !s.Source.Equals(primaryRepository.Source, StringComparison.OrdinalIgnoreCase))
|
||||
.ToArray();
|
||||
|
||||
if (nonActivePackageSources.Length == 0)
|
||||
{
|
||||
return primaryRepository;
|
||||
}
|
||||
|
||||
var fallbackRepository = AggregateRepository.Create(factory, sources: nonActivePackageSources, ignoreFailingRepositories: true);
|
||||
|
||||
return new PriorityPackageRepository(primaryRepository, fallbackRepository);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a package source by either Name or Source.
|
||||
/// </summary>
|
||||
public static string ResolveSource(this IPackageSourceProvider provider, string value)
|
||||
{
|
||||
var resolvedSource = (from source in provider.GetEnabledPackageSources()
|
||||
where source.Name.Equals(value, StringComparison.CurrentCultureIgnoreCase) || source.Source.Equals(value, StringComparison.OrdinalIgnoreCase)
|
||||
select source.Source
|
||||
).FirstOrDefault();
|
||||
|
||||
return resolvedSource ?? value;
|
||||
}
|
||||
|
||||
public static IEnumerable<PackageSource> GetEnabledPackageSources(this IPackageSourceProvider provider)
|
||||
{
|
||||
return provider.LoadPackageSources().Where(p => p.IsEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyTitle("NuGet.Core")]
|
||||
[assembly: AssemblyDescription("NuGet.Core is the core framework assembly for NuGet that the rest of NuGet builds upon.")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
[assembly: InternalsVisibleTo("NuGet.Test")]
|
||||
[assembly: InternalsVisibleTo("NuGet.Test.Utility")]
|
||||
[assembly: InternalsVisibleTo("NuGet.Test.Integration")]
|
||||
[assembly: InternalsVisibleTo("NuGet.VisualStudio.Test")]
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<package>
|
||||
<metadata>
|
||||
<id>$id$</id>
|
||||
<version>$version$</version>
|
||||
<description>$description$</description>
|
||||
<authors>.NET Foundation</authors>
|
||||
<owners>$author$</owners>
|
||||
<licenseUrl>http://nuget.codeplex.com/license</licenseUrl>
|
||||
<projectUrl>http://nuget.codeplex.com</projectUrl>
|
||||
<copyright>$copyright$</copyright>
|
||||
<tags>nuget</tags>
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.Web.Xdt" version="2.1.0" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -1,330 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class AggregateRepository : PackageRepositoryBase, IPackageLookup, IDependencyResolver, IServiceBasedRepository, ICloneableRepository, IOperationAwareRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// When the ignore flag is set up, this collection keeps track of failing repositories so that the AggregateRepository
|
||||
/// does not query them again.
|
||||
/// </summary>
|
||||
private readonly ConcurrentBag<IPackageRepository> _failingRepositories = new ConcurrentBag<IPackageRepository>();
|
||||
private readonly IEnumerable<IPackageRepository> _repositories;
|
||||
private readonly Lazy<bool> _supportsPrereleasePackages;
|
||||
|
||||
private const string SourceValue = "(Aggregate source)";
|
||||
private ILogger _logger;
|
||||
|
||||
public override string Source
|
||||
{
|
||||
get { return SourceValue; }
|
||||
}
|
||||
|
||||
public ILogger Logger
|
||||
{
|
||||
get { return _logger ?? NullLogger.Instance; }
|
||||
set { _logger = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if dependency resolution is performed serially on a per-repository basis. The first repository that has a compatible dependency
|
||||
/// regardless of version would win if this property is true.
|
||||
/// </summary>
|
||||
public bool ResolveDependenciesVertically { get; set; }
|
||||
|
||||
public bool IgnoreFailingRepositories { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// Iterating over Repositories returned by this property may throw regardless of IgnoreFailingRepositories.
|
||||
/// </remarks>
|
||||
public IEnumerable<IPackageRepository> Repositories
|
||||
{
|
||||
get { return _repositories; }
|
||||
}
|
||||
|
||||
public override bool SupportsPrereleasePackages
|
||||
{
|
||||
get
|
||||
{
|
||||
return _supportsPrereleasePackages.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public AggregateRepository(IEnumerable<IPackageRepository> repositories)
|
||||
{
|
||||
if (repositories == null)
|
||||
{
|
||||
throw new ArgumentNullException("repositories");
|
||||
}
|
||||
_repositories = Flatten(repositories);
|
||||
|
||||
Func<IPackageRepository, bool> supportsPrereleasePackages = Wrap(r => r.SupportsPrereleasePackages, defaultValue: true);
|
||||
_supportsPrereleasePackages = new Lazy<bool>(() => _repositories.All(supportsPrereleasePackages));
|
||||
IgnoreFailingRepositories = true;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to suppress any exception that we may encounter.")]
|
||||
public AggregateRepository(IPackageRepositoryFactory repositoryFactory, IEnumerable<string> packageSources, bool ignoreFailingRepositories)
|
||||
{
|
||||
IgnoreFailingRepositories = ignoreFailingRepositories;
|
||||
Func<string, IPackageRepository> createRepository = repositoryFactory.CreateRepository;
|
||||
if (ignoreFailingRepositories)
|
||||
{
|
||||
createRepository = (source) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return repositoryFactory.CreateRepository(source);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_repositories = (from source in packageSources
|
||||
let repository = createRepository(source)
|
||||
where repository != null
|
||||
select repository).ToArray();
|
||||
|
||||
Func<IPackageRepository, bool> supportsPrereleasePackages = Wrap(r => r.SupportsPrereleasePackages, defaultValue: true);
|
||||
_supportsPrereleasePackages = new Lazy<bool>(() => _repositories.All(supportsPrereleasePackages));
|
||||
}
|
||||
|
||||
public override IQueryable<IPackage> GetPackages()
|
||||
{
|
||||
// We need to follow this pattern in all AggregateRepository methods to ensure it suppresses exceptions that may occur if the Ignore flag is set. Oh how I despise my code.
|
||||
var defaultResult = Enumerable.Empty<IPackage>().AsQueryable();
|
||||
Func<IPackageRepository, IQueryable<IPackage>> getPackages = Wrap(r => r.GetPackages(), defaultResult);
|
||||
return CreateAggregateQuery(Repositories.Select(getPackages));
|
||||
}
|
||||
|
||||
public IPackage FindPackage(string packageId, SemanticVersion version)
|
||||
{
|
||||
// When we're looking for an exact package, we can optimize but searching each
|
||||
// repository one by one until we find the package that matches.
|
||||
Func<IPackageRepository, IPackage> findPackage = Wrap(r => r.FindPackage(packageId, version));
|
||||
return Repositories.Select(findPackage)
|
||||
.FirstOrDefault(p => p != null);
|
||||
}
|
||||
|
||||
public bool Exists(string packageId, SemanticVersion version)
|
||||
{
|
||||
// When we're looking for an exact package, we can optimize but searching each
|
||||
// repository one by one until we find the package that matches.
|
||||
Func<IPackageRepository, bool> exists = Wrap(r => r.Exists(packageId, version));
|
||||
return Repositories.Any(exists);
|
||||
}
|
||||
|
||||
public IPackage ResolveDependency(PackageDependency dependency, IPackageConstraintProvider constraintProvider, bool allowPrereleaseVersions, bool preferListedPackages, DependencyVersion dependencyVersion)
|
||||
{
|
||||
if (ResolveDependenciesVertically)
|
||||
{
|
||||
Func<IPackageRepository, IPackage> resolveDependency = Wrap(
|
||||
r => DependencyResolveUtility.ResolveDependency(r, dependency, constraintProvider, allowPrereleaseVersions, preferListedPackages, dependencyVersion));
|
||||
|
||||
return Repositories.Select(r => Task.Factory.StartNew(() => resolveDependency(r)))
|
||||
.ToArray()
|
||||
.WhenAny(package => package != null);
|
||||
}
|
||||
return DependencyResolveUtility.ResolveDependencyCore(this, dependency, constraintProvider, allowPrereleaseVersions, preferListedPackages, dependencyVersion);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to suppress any exception that we may encounter.")]
|
||||
private Func<IPackageRepository, T> Wrap<T>(Func<IPackageRepository, T> factory, T defaultValue = default(T))
|
||||
{
|
||||
if (IgnoreFailingRepositories)
|
||||
{
|
||||
return repository =>
|
||||
{
|
||||
if (_failingRepositories.Contains(repository))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return factory(repository);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogRepository(repository, ex);
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
public void LogRepository(IPackageRepository repository, Exception ex)
|
||||
{
|
||||
_failingRepositories.Add(repository);
|
||||
Logger.Log(MessageLevel.Warning, ExceptionUtility.Unwrap(ex).Message);
|
||||
}
|
||||
|
||||
public IQueryable<IPackage> Search(string searchTerm, IEnumerable<string> targetFrameworks, bool allowPrereleaseVersions, bool includeDelisted)
|
||||
{
|
||||
return CreateAggregateQuery(Repositories.Select(r => r.Search(searchTerm, targetFrameworks, allowPrereleaseVersions, includeDelisted)));
|
||||
}
|
||||
|
||||
public IPackageRepository Clone()
|
||||
{
|
||||
return new AggregateRepository(Repositories.Select(PackageRepositoryExtensions.Clone));
|
||||
}
|
||||
|
||||
private AggregateQuery<IPackage> CreateAggregateQuery(IEnumerable<IQueryable<IPackage>> queries)
|
||||
{
|
||||
return new AggregateQuery<IPackage>(queries,
|
||||
PackageEqualityComparer.IdAndVersion,
|
||||
Logger,
|
||||
IgnoreFailingRepositories);
|
||||
}
|
||||
|
||||
internal static IEnumerable<IPackageRepository> Flatten(IEnumerable<IPackageRepository> repositories)
|
||||
{
|
||||
return repositories.SelectMany(repository =>
|
||||
{
|
||||
var aggrgeateRepository = repository as AggregateRepository;
|
||||
if (aggrgeateRepository != null)
|
||||
{
|
||||
return aggrgeateRepository.Repositories.ToArray();
|
||||
}
|
||||
return new[] { repository };
|
||||
});
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to suppress any exception that we may encounter.")]
|
||||
public IEnumerable<IPackage> FindPackagesById(string packageId)
|
||||
{
|
||||
var tasks = _repositories.Select(p => Task.Factory.StartNew(state => p.FindPackagesById(packageId), p)).ToArray();
|
||||
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
if (!IgnoreFailingRepositories)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
var allPackages = new List<IPackage>();
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
LogRepository((IPackageRepository)task.AsyncState, task.Exception);
|
||||
}
|
||||
else if (task.Result != null)
|
||||
{
|
||||
allPackages.AddRange(task.Result);
|
||||
}
|
||||
}
|
||||
return allPackages;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to suppress any exception that we may encounter.")]
|
||||
public IEnumerable<IPackage> GetUpdates(
|
||||
IEnumerable<IPackageName> packages,
|
||||
bool includePrerelease,
|
||||
bool includeAllVersions,
|
||||
IEnumerable<FrameworkName> targetFrameworks,
|
||||
IEnumerable<IVersionSpec> versionConstraints)
|
||||
{
|
||||
// GetUpdatesCore returns all updates. We'll allow the extension method to determine if we need to collapse based on allVersion.
|
||||
var tasks = _repositories.Select(p => Task.Factory.StartNew(state => p.GetUpdates(packages, includePrerelease, includeAllVersions, targetFrameworks, versionConstraints), p)).ToArray();
|
||||
|
||||
try
|
||||
{
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
if (!IgnoreFailingRepositories)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
var allPackages = new HashSet<IPackage>(PackageEqualityComparer.IdAndVersion);
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
LogRepository((IPackageRepository)task.AsyncState, task.Exception);
|
||||
}
|
||||
else if (task.Result != null)
|
||||
{
|
||||
allPackages.AddRange(task.Result);
|
||||
}
|
||||
}
|
||||
if (includeAllVersions)
|
||||
{
|
||||
// If we return all packages, sort them by Id and Version to make the sequence predictable.
|
||||
return allPackages.OrderBy(p => p.Id, StringComparer.OrdinalIgnoreCase)
|
||||
.ThenBy(p => p.Version);
|
||||
}
|
||||
|
||||
return allPackages.CollapseById();
|
||||
}
|
||||
|
||||
public IDisposable StartOperation(string operation, string mainPackageId, string mainPackageVersion)
|
||||
{
|
||||
return DisposableAction.All(
|
||||
Repositories.Select(r => r.StartOperation(operation, mainPackageId, mainPackageVersion)));
|
||||
}
|
||||
|
||||
public static IPackageRepository Create(
|
||||
IPackageRepositoryFactory factory,
|
||||
IList<PackageSource> sources,
|
||||
bool ignoreFailingRepositories)
|
||||
{
|
||||
if (sources.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (sources.Count == 1)
|
||||
{
|
||||
// optimization: if there is only one package source, create a direct repository out of it.
|
||||
return factory.CreateRepository(sources[0].Source);
|
||||
}
|
||||
|
||||
Func<string, IPackageRepository> createRepository = factory.CreateRepository;
|
||||
|
||||
if (ignoreFailingRepositories)
|
||||
{
|
||||
createRepository = (source) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return factory.CreateRepository(source);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var repositories = from source in sources
|
||||
let repository = createRepository(source.Source)
|
||||
where repository != null
|
||||
select repository;
|
||||
|
||||
return new AggregateRepository(repositories)
|
||||
{
|
||||
IgnoreFailingRepositories = ignoreFailingRepositories
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Services.Client;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
[CLSCompliant(false)]
|
||||
public class DataServiceContextWrapper : IDataServiceContext
|
||||
{
|
||||
private const string MetadataKey = "DataServiceMetadata|";
|
||||
private static readonly MethodInfo _executeMethodInfo = typeof(DataServiceContext).GetMethod("Execute", new[] { typeof(Uri) });
|
||||
private readonly DataServiceContext _context;
|
||||
private readonly Uri _metadataUri;
|
||||
|
||||
public DataServiceContextWrapper(Uri serviceRoot)
|
||||
{
|
||||
if (serviceRoot == null)
|
||||
{
|
||||
throw new ArgumentNullException("serviceRoot");
|
||||
}
|
||||
|
||||
_context = new DataServiceContext(serviceRoot)
|
||||
{
|
||||
MergeOption = MergeOption.NoTracking
|
||||
};
|
||||
|
||||
_metadataUri = _context.GetMetadataUri();
|
||||
|
||||
AttachEvents();
|
||||
}
|
||||
|
||||
private DataServiceClientRequestMessage ShimWebRequests(DataServiceClientRequestMessageArgs args)
|
||||
{
|
||||
// Shim the requests if needed
|
||||
return HttpShim.Instance.ShimDataServiceRequest(args);
|
||||
}
|
||||
|
||||
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
|
||||
{
|
||||
if (managerType == typeof(Func<DataServiceClientRequestMessage, DataServiceClientRequestMessageArgs>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachEvents()
|
||||
{
|
||||
_context.Configurations.RequestPipeline.OnMessageCreating += ShimWebRequests;
|
||||
}
|
||||
|
||||
//private void DetachEvents()
|
||||
//{
|
||||
// _context.Configurations.RequestPipeline.OnMessageCreating -= ShimWebRequests;
|
||||
//}
|
||||
|
||||
//public void Dispose()
|
||||
//{
|
||||
// DetachEvents();
|
||||
//}
|
||||
|
||||
public Uri BaseUri
|
||||
{
|
||||
get
|
||||
{
|
||||
return _context.BaseUri;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<SendingRequest2EventArgs> SendingRequest
|
||||
{
|
||||
add
|
||||
{
|
||||
_context.SendingRequest2 += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_context.SendingRequest2 -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ReadingWritingEntityEventArgs> ReadingEntity
|
||||
{
|
||||
add
|
||||
{
|
||||
_context.ReadingEntity += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_context.ReadingEntity -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IgnoreMissingProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return _context.IgnoreMissingProperties;
|
||||
}
|
||||
set
|
||||
{
|
||||
_context.IgnoreMissingProperties = value;
|
||||
}
|
||||
}
|
||||
|
||||
private DataServiceMetadata ServiceMetadata
|
||||
{
|
||||
get
|
||||
{
|
||||
return MemoryCache.Instance.GetOrAdd(GetServiceMetadataKey(), () => GetDataServiceMetadata(_metadataUri), TimeSpan.FromMinutes(15));
|
||||
}
|
||||
}
|
||||
|
||||
public IDataServiceQuery<T> CreateQuery<T>(string entitySetName, IDictionary<string, object> queryOptions)
|
||||
{
|
||||
var query = _context.CreateQuery<T>(entitySetName);
|
||||
foreach (var pair in queryOptions)
|
||||
{
|
||||
query = query.AddQueryOption(pair.Key, pair.Value);
|
||||
}
|
||||
return new DataServiceQueryWrapper<T>(this, query);
|
||||
}
|
||||
|
||||
public IDataServiceQuery<T> CreateQuery<T>(string entitySetName)
|
||||
{
|
||||
return new DataServiceQueryWrapper<T>(this, _context.CreateQuery<T>(entitySetName));
|
||||
}
|
||||
|
||||
public IEnumerable<T> Execute<T>(Type elementType, DataServiceQueryContinuation continuation)
|
||||
{
|
||||
// Get the generic execute method
|
||||
MethodInfo executeMethod = _executeMethodInfo.MakeGenericMethod(elementType);
|
||||
|
||||
// Get the results from the continuation
|
||||
return (IEnumerable<T>)executeMethod.Invoke(_context, new object[] { continuation.NextLinkUri });
|
||||
}
|
||||
|
||||
public IEnumerable<T> ExecuteBatch<T>(DataServiceRequest request)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
//return _context.ExecuteBatch(request)
|
||||
// .Cast<QueryOperationResponse>()
|
||||
// .SelectMany(o => o.Cast<T>());
|
||||
}
|
||||
|
||||
public bool SupportsServiceMethod(string methodName)
|
||||
{
|
||||
return ServiceMetadata != null && ServiceMetadata.SupportedMethodNames.Contains(methodName);
|
||||
}
|
||||
|
||||
public bool SupportsProperty(string propertyName)
|
||||
{
|
||||
return ServiceMetadata != null && ServiceMetadata.SupportedProperties.Contains(propertyName);
|
||||
}
|
||||
|
||||
internal sealed class DataServiceMetadata
|
||||
{
|
||||
public HashSet<string> SupportedMethodNames { get; set; }
|
||||
|
||||
public HashSet<string> SupportedProperties { get; set; }
|
||||
}
|
||||
|
||||
private string GetServiceMetadataKey()
|
||||
{
|
||||
return MetadataKey + _metadataUri.OriginalString;
|
||||
}
|
||||
|
||||
private static DataServiceMetadata GetDataServiceMetadata(Uri metadataUri)
|
||||
{
|
||||
if (metadataUri == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make a request to the metadata uri and get the schema
|
||||
var client = new HttpClient(metadataUri);
|
||||
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
client.DownloadData(stream);
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return ExtractMetadataFromSchema(stream);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "If the docuument is in fails to parse in any way, we want to not fail.")]
|
||||
internal static DataServiceMetadata ExtractMetadataFromSchema(Stream schemaStream)
|
||||
{
|
||||
if (schemaStream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
XDocument schemaDocument;
|
||||
|
||||
try
|
||||
{
|
||||
schemaDocument = XmlUtility.LoadSafe(schemaStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If the schema is malformed (for some reason) then just return empty list
|
||||
return null;
|
||||
}
|
||||
|
||||
return ExtractMetadataInternal(schemaDocument);
|
||||
}
|
||||
|
||||
private static DataServiceMetadata ExtractMetadataInternal(XDocument schemaDocument)
|
||||
{
|
||||
// Get all entity containers
|
||||
var entityContainers = from e in schemaDocument.Descendants()
|
||||
where e.Name.LocalName == "EntityContainer"
|
||||
select e;
|
||||
|
||||
// Find the entity container with the Packages entity set
|
||||
var result = (from e in entityContainers
|
||||
let entitySet = e.Elements().FirstOrDefault(el => el.Name.LocalName == "EntitySet")
|
||||
let name = entitySet != null ? entitySet.Attribute("Name").Value : null
|
||||
where name != null && name.Equals("Packages", StringComparison.OrdinalIgnoreCase)
|
||||
select new { Container = e, EntitySet = entitySet }).FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var packageEntityContainer = result.Container;
|
||||
var packageEntityTypeAttribute = result.EntitySet.Attribute("EntityType");
|
||||
string packageEntityName = null;
|
||||
if (packageEntityTypeAttribute != null)
|
||||
{
|
||||
packageEntityName = packageEntityTypeAttribute.Value;
|
||||
}
|
||||
|
||||
var metadata = new DataServiceMetadata
|
||||
{
|
||||
SupportedMethodNames = new HashSet<string>(
|
||||
from e in packageEntityContainer.Elements()
|
||||
where e.Name.LocalName == "FunctionImport"
|
||||
select e.Attribute("Name").Value, StringComparer.OrdinalIgnoreCase),
|
||||
SupportedProperties = new HashSet<string>(ExtractSupportedProperties(schemaDocument, packageEntityName),
|
||||
StringComparer.OrdinalIgnoreCase)
|
||||
};
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> ExtractSupportedProperties(XDocument schemaDocument, string packageEntityName)
|
||||
{
|
||||
// The name is listed in the entity set listing as <EntitySet Name="Packages" EntityType="Gallery.Infrastructure.FeedModels.PublishedPackage" />
|
||||
// We need to extract the name portion to look up the entity type <EntityType Name="PublishedPackage"
|
||||
packageEntityName = TrimNamespace(packageEntityName);
|
||||
|
||||
var packageEntity = (from e in schemaDocument.Descendants()
|
||||
where e.Name.LocalName == "EntityType"
|
||||
let attribute = e.Attribute("Name")
|
||||
where attribute != null && attribute.Value.Equals(packageEntityName, StringComparison.OrdinalIgnoreCase)
|
||||
select e).FirstOrDefault();
|
||||
|
||||
if (packageEntity != null)
|
||||
{
|
||||
return from e in packageEntity.Elements()
|
||||
where e.Name.LocalName == "Property"
|
||||
select e.Attribute("Name").Value;
|
||||
}
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
private static string TrimNamespace(string packageEntityName)
|
||||
{
|
||||
int lastIndex = packageEntityName.LastIndexOf('.');
|
||||
if (lastIndex > 0 && lastIndex < packageEntityName.Length)
|
||||
{
|
||||
packageEntityName = packageEntityName.Substring(lastIndex + 1);
|
||||
}
|
||||
return packageEntityName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,492 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data.Services.Client;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Windows;
|
||||
using MissingFrom.Net;
|
||||
using NuGet.Resources;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
|
||||
public class DataServicePackageRepository :
|
||||
PackageRepositoryBase,
|
||||
IHttpClientEvents,
|
||||
IServiceBasedRepository,
|
||||
ICloneableRepository,
|
||||
ICultureAwareRepository,
|
||||
IOperationAwareRepository,
|
||||
IPackageLookup,
|
||||
ILatestPackageLookup
|
||||
{
|
||||
private const string FindPackagesByIdSvcMethod = "FindPackagesById";
|
||||
private const string PackageServiceEntitySetName = "Packages";
|
||||
private const string SearchSvcMethod = "Search";
|
||||
private const string GetUpdatesSvcMethod = "GetUpdates";
|
||||
|
||||
private IDataServiceContext _context;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly PackageDownloader _packageDownloader;
|
||||
private CultureInfo _culture;
|
||||
private Tuple<string, string, string> _currentOperation;
|
||||
private event EventHandler<WebRequestEventArgs> _sendingRequest;
|
||||
private WeakEventManager manager = new WeakEventManager();
|
||||
|
||||
public DataServicePackageRepository(Uri serviceRoot)
|
||||
: this(new HttpClient(serviceRoot))
|
||||
{
|
||||
}
|
||||
|
||||
public DataServicePackageRepository(IHttpClient client)
|
||||
: this(client, new PackageDownloader())
|
||||
{
|
||||
}
|
||||
|
||||
public DataServicePackageRepository(IHttpClient client, PackageDownloader packageDownloader)
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
throw new ArgumentNullException("client");
|
||||
}
|
||||
if (packageDownloader == null)
|
||||
{
|
||||
throw new ArgumentNullException("packageDownloader");
|
||||
}
|
||||
|
||||
_httpClient = client;
|
||||
_httpClient.AcceptCompression = true;
|
||||
|
||||
_packageDownloader = packageDownloader;
|
||||
|
||||
if (EnvironmentUtility.RunningFromCommandLine || EnvironmentUtility.IsMonoRuntime)
|
||||
{
|
||||
_packageDownloader.SendingRequest += OnPackageDownloaderSendingRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
// weak event pattern
|
||||
manager.AddWeakEventListener<PackageDownloader, WebRequestEventArgs>(
|
||||
_packageDownloader,
|
||||
nameof(_packageDownloader.SendingRequest),
|
||||
OnPackageDownloaderSendingRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPackageDownloaderSendingRequest(object sender, WebRequestEventArgs e)
|
||||
{
|
||||
// add headers for the metric service
|
||||
if (_currentOperation != null)
|
||||
{
|
||||
string operation = _currentOperation.Item1;
|
||||
string mainPackageId = _currentOperation.Item2;
|
||||
string mainPackageVersion = _currentOperation.Item3;
|
||||
|
||||
if (!String.IsNullOrEmpty(mainPackageId) && !String.IsNullOrEmpty(_packageDownloader.CurrentDownloadPackageId))
|
||||
{
|
||||
if (!mainPackageId.Equals(_packageDownloader.CurrentDownloadPackageId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
operation = operation + "-Dependency";
|
||||
}
|
||||
}
|
||||
|
||||
// add the id and version to the headers
|
||||
if (!String.IsNullOrEmpty(_packageDownloader.CurrentDownloadPackageId) && !String.IsNullOrEmpty(_packageDownloader.CurrentDownloadPackageVersion))
|
||||
{
|
||||
e.Request.Headers[RepositoryOperationNames.PackageId] = _packageDownloader.CurrentDownloadPackageId;
|
||||
e.Request.Headers[RepositoryOperationNames.PackageVersion] = _packageDownloader.CurrentDownloadPackageVersion;
|
||||
}
|
||||
|
||||
e.Request.Headers[RepositoryOperationNames.OperationHeaderName] = operation;
|
||||
|
||||
if (!operation.Equals(_currentOperation.Item1, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
e.Request.Headers[RepositoryOperationNames.DependentPackageHeaderName] = mainPackageId;
|
||||
if (!String.IsNullOrEmpty(mainPackageVersion))
|
||||
{
|
||||
e.Request.Headers[RepositoryOperationNames.DependentPackageVersionHeaderName] = mainPackageVersion;
|
||||
}
|
||||
}
|
||||
|
||||
RaiseSendingRequest(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Just forward calls to the package downloader
|
||||
public event EventHandler<ProgressEventArgs> ProgressAvailable
|
||||
{
|
||||
add
|
||||
{
|
||||
_packageDownloader.ProgressAvailable += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_packageDownloader.ProgressAvailable -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<WebRequestEventArgs> SendingRequest
|
||||
{
|
||||
add
|
||||
{
|
||||
_packageDownloader.SendingRequest += value;
|
||||
_httpClient.SendingRequest += value;
|
||||
_sendingRequest += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_packageDownloader.SendingRequest -= value;
|
||||
_httpClient.SendingRequest -= value;
|
||||
_sendingRequest -= value;
|
||||
}
|
||||
}
|
||||
|
||||
public CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_culture == null)
|
||||
{
|
||||
// TODO: Technically, if this is a remote server, we have to return the culture of the server
|
||||
// instead of invariant culture. However, there is no trivial way to retrieve the server's culture,
|
||||
// So temporarily use Invariant culture here.
|
||||
_culture = _httpClient.Uri.IsLoopback ? CultureInfo.CurrentCulture : CultureInfo.InvariantCulture;
|
||||
}
|
||||
return _culture;
|
||||
}
|
||||
}
|
||||
|
||||
// Do NOT delete this property. It is used by the functional test.
|
||||
public PackageDownloader PackageDownloader
|
||||
{
|
||||
get { return _packageDownloader; }
|
||||
}
|
||||
|
||||
public override string Source
|
||||
{
|
||||
get
|
||||
{
|
||||
return _httpClient.Uri.OriginalString;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SupportsPrereleasePackages
|
||||
{
|
||||
get
|
||||
{
|
||||
return Context.SupportsProperty("IsAbsoluteLatestVersion");
|
||||
}
|
||||
}
|
||||
|
||||
// Don't initialize the Context at the constructor time so that
|
||||
// we don't make a web request if we are not going to actually use it
|
||||
// since getting the Uri property of the RedirectedHttpClient will
|
||||
// trigger that functionality.
|
||||
internal IDataServiceContext Context
|
||||
{
|
||||
private get
|
||||
{
|
||||
if (_context == null)
|
||||
{
|
||||
_context = new DataServiceContextWrapper(_httpClient.Uri);
|
||||
_context.SendingRequest += OnSendingRequest;
|
||||
_context.ReadingEntity += OnReadingEntity;
|
||||
_context.IgnoreMissingProperties = true;
|
||||
}
|
||||
return _context;
|
||||
}
|
||||
set
|
||||
{
|
||||
_context = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReadingEntity(object sender, ReadingWritingEntityEventArgs e)
|
||||
{
|
||||
var package = (DataServicePackage)e.Entity;
|
||||
|
||||
var downloadUri = e.Data.Element(e.Data.Name.Namespace.GetName("content"))
|
||||
.Attribute(System.Xml.Linq.XName.Get("src")).Value;
|
||||
package.DownloadUrl = new Uri(downloadUri);
|
||||
package.Downloader = _packageDownloader;
|
||||
}
|
||||
|
||||
private void OnSendingRequest(object sender, SendingRequest2EventArgs e)
|
||||
{
|
||||
var shimRequest = new ShimDataRequestMessage(e);
|
||||
|
||||
// Initialize the request
|
||||
_httpClient.InitializeRequest(shimRequest.WebRequest);
|
||||
|
||||
|
||||
RaiseSendingRequest(new WebRequestEventArgs(shimRequest.WebRequest));
|
||||
}
|
||||
|
||||
private void RaiseSendingRequest(WebRequestEventArgs e)
|
||||
{
|
||||
if (_sendingRequest != null)
|
||||
{
|
||||
_sendingRequest(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
public override IQueryable<IPackage> GetPackages()
|
||||
{
|
||||
// REVIEW: Is it ok to assume that the package entity set is called packages?
|
||||
return new SmartDataServiceQuery<DataServicePackage>(Context, PackageServiceEntitySetName);
|
||||
}
|
||||
|
||||
public IQueryable<IPackage> Search(string searchTerm, IEnumerable<string> targetFrameworks, bool allowPrereleaseVersions, bool includeDelisted)
|
||||
{
|
||||
if (!Context.SupportsServiceMethod(SearchSvcMethod))
|
||||
{
|
||||
// If there's no search method then we can't filter by target framework
|
||||
var q = GetPackages()
|
||||
.Find(searchTerm)
|
||||
.FilterByPrerelease(allowPrereleaseVersions);
|
||||
|
||||
// filter out delisted packages if includeDelisted is false.
|
||||
if (includeDelisted == false)
|
||||
{
|
||||
q = q.Where(p => p.IsListed());
|
||||
}
|
||||
|
||||
return q.AsQueryable();
|
||||
}
|
||||
|
||||
// Create a '|' separated string of framework names
|
||||
string targetFrameworkString = String.Join("|", targetFrameworks);
|
||||
|
||||
var searchParameters = new Dictionary<string, object> {
|
||||
{ "searchTerm", "'" + UrlEncodeOdataParameter(searchTerm) + "'" },
|
||||
{ "targetFramework", "'" + UrlEncodeOdataParameter(targetFrameworkString) + "'" },
|
||||
};
|
||||
|
||||
if (SupportsPrereleasePackages)
|
||||
{
|
||||
searchParameters.Add("includePrerelease", ToLowerCaseString(allowPrereleaseVersions));
|
||||
}
|
||||
|
||||
if (includeDelisted)
|
||||
{
|
||||
searchParameters.Add("includeDelisted", "true");
|
||||
}
|
||||
|
||||
// Create a query for the search service method
|
||||
var query = Context.CreateQuery<DataServicePackage>(SearchSvcMethod, searchParameters);
|
||||
return new SmartDataServiceQuery<DataServicePackage>(Context, query);
|
||||
}
|
||||
|
||||
public bool Exists(string packageId, SemanticVersion version)
|
||||
{
|
||||
IQueryable<DataServicePackage> query = Context.CreateQuery<DataServicePackage>(PackageServiceEntitySetName).AsQueryable();
|
||||
|
||||
foreach (string versionString in version.GetComparableVersionStrings())
|
||||
{
|
||||
try
|
||||
{
|
||||
var packages = query.Where(p => p.Id == packageId && p.Version == versionString)
|
||||
.Select(p => p.Id) // since we only want to check for existence, no need to get all attributes
|
||||
.ToArray();
|
||||
|
||||
if (packages.Length == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (DataServiceQueryException)
|
||||
{
|
||||
// DataServiceQuery exception will occur when the (id, version)
|
||||
// combination doesn't exist.
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IPackage FindPackage(string packageId, SemanticVersion version)
|
||||
{
|
||||
IQueryable<DataServicePackage> query = Context.CreateQuery<DataServicePackage>(PackageServiceEntitySetName).AsQueryable();
|
||||
|
||||
foreach (string versionString in version.GetComparableVersionStrings())
|
||||
{
|
||||
try
|
||||
{
|
||||
var packages = query.Where(p => p.Id == packageId && p.Version == versionString).ToArray();
|
||||
Debug.Assert(packages == null || packages.Length <= 1);
|
||||
if (packages.Length != 0)
|
||||
{
|
||||
return packages[0];
|
||||
}
|
||||
}
|
||||
catch (DataServiceQueryException)
|
||||
{
|
||||
// DataServiceQuery exception will occur when the (id, version)
|
||||
// combination doesn't exist.
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<IPackage> FindPackagesById(string packageId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Context.SupportsServiceMethod(FindPackagesByIdSvcMethod))
|
||||
{
|
||||
// If there's no search method then we can't filter by target framework
|
||||
return PackageRepositoryExtensions.FindPackagesByIdCore(this, packageId);
|
||||
}
|
||||
|
||||
var serviceParameters = new Dictionary<string, object> {
|
||||
{ "id", "'" + UrlEncodeOdataParameter(packageId) + "'" }
|
||||
};
|
||||
|
||||
// Create a query for the search service method
|
||||
var query = Context.CreateQuery<DataServicePackage>(FindPackagesByIdSvcMethod, serviceParameters);
|
||||
return new SmartDataServiceQuery<DataServicePackage>(Context, query);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = string.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
NuGetResources.ErrorLoadingPackages,
|
||||
_httpClient.OriginalUri,
|
||||
ex.Message);
|
||||
throw new InvalidOperationException(message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IPackage> GetUpdates(
|
||||
IEnumerable<IPackageName> packages,
|
||||
bool includePrerelease,
|
||||
bool includeAllVersions,
|
||||
IEnumerable<FrameworkName> targetFrameworks,
|
||||
IEnumerable<IVersionSpec> versionConstraints)
|
||||
{
|
||||
if (!Context.SupportsServiceMethod(GetUpdatesSvcMethod))
|
||||
{
|
||||
// If there's no search method then we can't filter by target framework
|
||||
return PackageRepositoryExtensions.GetUpdatesCore(this, packages, includePrerelease, includeAllVersions, targetFrameworks, versionConstraints);
|
||||
}
|
||||
|
||||
// Pipe all the things!
|
||||
string ids = String.Join("|", packages.Select(p => p.Id));
|
||||
string versions = String.Join("|", packages.Select(p => p.Version.ToString()));
|
||||
string targetFrameworksValue = targetFrameworks.IsEmpty() ? "" : String.Join("|", targetFrameworks.Select(VersionUtility.GetShortFrameworkName));
|
||||
string versionConstraintsValue = versionConstraints.IsEmpty() ? "" : String.Join("|", versionConstraints.Select(v => v == null ? "" : v.ToString()));
|
||||
|
||||
var serviceParameters = new Dictionary<string, object> {
|
||||
{ "packageIds", "'" + ids + "'" },
|
||||
{ "versions", "'" + versions + "'" },
|
||||
{ "includePrerelease", ToLowerCaseString(includePrerelease) },
|
||||
{ "includeAllVersions", ToLowerCaseString(includeAllVersions) },
|
||||
{ "targetFrameworks", "'" + UrlEncodeOdataParameter(targetFrameworksValue) + "'" },
|
||||
{ "versionConstraints", "'" + UrlEncodeOdataParameter(versionConstraintsValue) + "'" }
|
||||
};
|
||||
|
||||
var query = Context.CreateQuery<DataServicePackage>(GetUpdatesSvcMethod, serviceParameters);
|
||||
return new SmartDataServiceQuery<DataServicePackage>(Context, query);
|
||||
}
|
||||
|
||||
public IPackageRepository Clone()
|
||||
{
|
||||
return new DataServicePackageRepository(_httpClient, _packageDownloader);
|
||||
}
|
||||
|
||||
public IDisposable StartOperation(string operation, string mainPackageId, string mainPackageVersion)
|
||||
{
|
||||
Tuple<string, string, string> oldOperation = _currentOperation;
|
||||
_currentOperation = Tuple.Create(operation, mainPackageId, mainPackageVersion);
|
||||
return new DisposableAction(() =>
|
||||
{
|
||||
_currentOperation = oldOperation;
|
||||
});
|
||||
}
|
||||
|
||||
public bool TryFindLatestPackageById(string id, out SemanticVersion latestVersion)
|
||||
{
|
||||
latestVersion = null;
|
||||
|
||||
try
|
||||
{
|
||||
var serviceParameters = new Dictionary<string, object> {
|
||||
{ "id", "'" + UrlEncodeOdataParameter(id) + "'" }
|
||||
};
|
||||
|
||||
// Create a query for the search service method
|
||||
var query = Context.CreateQuery<DataServicePackage>(FindPackagesByIdSvcMethod, serviceParameters);
|
||||
var packages = (IQueryable<DataServicePackage>)query.AsQueryable();
|
||||
|
||||
var latestPackage = packages.Where(p => p.IsLatestVersion)
|
||||
.Select(p => new { p.Id, p.Version })
|
||||
.FirstOrDefault();
|
||||
|
||||
if (latestPackage != null)
|
||||
{
|
||||
latestVersion = new SemanticVersion(latestPackage.Version);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (DataServiceQueryException)
|
||||
{
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryFindLatestPackageById(string id, bool includePrerelease, out IPackage package)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serviceParameters = new Dictionary<string, object> {
|
||||
{ "id", "'" + UrlEncodeOdataParameter(id) + "'" }
|
||||
};
|
||||
|
||||
// Create a query for the search service method
|
||||
var query = Context.CreateQuery<DataServicePackage>(FindPackagesByIdSvcMethod, serviceParameters);
|
||||
var packages = (IQueryable<DataServicePackage>)query.AsQueryable();
|
||||
|
||||
if (includePrerelease)
|
||||
{
|
||||
package = packages.Where(p => p.IsAbsoluteLatestVersion).OrderByDescending(p => p.Version).FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
package = packages.Where(p => p.IsLatestVersion).OrderByDescending(p => p.Version).FirstOrDefault();
|
||||
}
|
||||
|
||||
return package != null;
|
||||
}
|
||||
catch (DataServiceQueryException)
|
||||
{
|
||||
package = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string UrlEncodeOdataParameter(string value)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(value))
|
||||
{
|
||||
// OData requires that a single quote MUST be escaped as 2 single quotes.
|
||||
// In .NET 4.5, Uri.EscapeDataString() escapes single quote as %27. Thus we must replace %27 with 2 single quotes.
|
||||
// In .NET 4.0, Uri.EscapeDataString() doesn't escape single quote. Thus we must replace it with 2 single quotes.
|
||||
return Uri.EscapeDataString(value).Replace("'", "''").Replace("%27", "''");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "OData expects a lower case value.")]
|
||||
private static string ToLowerCaseString(bool value)
|
||||
{
|
||||
return value.ToString().ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Services.Client;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Xml.Linq;
|
||||
using NuGet.Resources;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
[CLSCompliant(false)]
|
||||
public class DataServiceQueryWrapper<T> : IDataServiceQuery<T>
|
||||
{
|
||||
/// <remarks>
|
||||
/// Corresponds to the default value of "maxQueryString" in system.webserver.
|
||||
/// </remarks>
|
||||
private const int MaxUrlLength = 2048;
|
||||
|
||||
private readonly DataServiceQuery _query;
|
||||
private readonly IDataServiceContext _context;
|
||||
private readonly Type _concreteType;
|
||||
|
||||
public DataServiceQueryWrapper(IDataServiceContext context, DataServiceQuery query)
|
||||
: this(context, query, typeof(T))
|
||||
{
|
||||
}
|
||||
|
||||
public DataServiceQueryWrapper(IDataServiceContext context, DataServiceQuery query, Type concreteType)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException("context");
|
||||
}
|
||||
|
||||
if (query == null)
|
||||
{
|
||||
throw new ArgumentNullException("query");
|
||||
}
|
||||
|
||||
_context = context;
|
||||
_query = query;
|
||||
_concreteType = concreteType;
|
||||
}
|
||||
|
||||
public bool RequiresBatch(Expression expression)
|
||||
{
|
||||
// Absolute uri returns the escaped url that would be sent to the server. Escaping exapnds the value and IIS uses this escaped query to determine if the
|
||||
// query is of acceptable length.
|
||||
string requestUri = GetRequestUri(expression).AbsoluteUri;
|
||||
return requestUri.Length >= MaxUrlLength;
|
||||
}
|
||||
|
||||
public DataServiceRequest GetRequest(Expression expression)
|
||||
{
|
||||
return (DataServiceRequest)_query.Provider.CreateQuery(GetInnerExpression(expression));
|
||||
}
|
||||
|
||||
public virtual Uri GetRequestUri(Expression expression)
|
||||
{
|
||||
return GetRequest(expression).RequestUri;
|
||||
}
|
||||
|
||||
public TResult Execute<TResult>(Expression expression)
|
||||
{
|
||||
return Execute(() => _query.Provider.Execute<TResult>(GetInnerExpression(expression)));
|
||||
}
|
||||
|
||||
public object Execute(Expression expression)
|
||||
{
|
||||
return Execute(() => _query.Provider.Execute(GetInnerExpression(expression)));
|
||||
}
|
||||
|
||||
public IDataServiceQuery<TElement> CreateQuery<TElement>(Expression expression)
|
||||
{
|
||||
expression = GetInnerExpression(expression);
|
||||
|
||||
var query = (DataServiceQuery)_query.Provider.CreateQuery<TElement>(expression);
|
||||
|
||||
return new DataServiceQueryWrapper<TElement>(_context, query, typeof(T));
|
||||
}
|
||||
|
||||
public IQueryable<T> AsQueryable()
|
||||
{
|
||||
return (IQueryable<T>)_query;
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetAll().GetEnumerator();
|
||||
}
|
||||
|
||||
private IEnumerable<T> GetAll()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
//DataServiceQuery fixedQuery = _query;
|
||||
|
||||
//// Hack for WCF 5.6.1 to avoid using the interface
|
||||
//if (typeof(T) == typeof(IPackage))
|
||||
//{
|
||||
// fixedQuery = (DataServiceQuery)_query.Provider.CreateQuery<DataServicePackage>(_query.Expression).Cast<DataServicePackage>();
|
||||
//}
|
||||
|
||||
|
||||
//IEnumerable results = Execute(fixedQuery.Execute);
|
||||
|
||||
//DataServiceQueryContinuation continuation;
|
||||
//do
|
||||
//{
|
||||
// lock (_context)
|
||||
// {
|
||||
// foreach (T item in results)
|
||||
// {
|
||||
// yield return item;
|
||||
// }
|
||||
// }
|
||||
|
||||
// continuation = ((QueryOperationResponse)results).GetContinuation();
|
||||
|
||||
// if (continuation != null)
|
||||
// {
|
||||
// results = _context.Execute<T>(_concreteType, continuation);
|
||||
// }
|
||||
|
||||
//} while (continuation != null);
|
||||
}
|
||||
|
||||
private Expression GetInnerExpression(Expression expression)
|
||||
{
|
||||
return QueryableUtility.ReplaceQueryableExpression(_query, expression);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _query.ToString();
|
||||
}
|
||||
|
||||
private TResult Execute<TResult>(Func<TResult> action)
|
||||
{
|
||||
try
|
||||
{
|
||||
return action();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
string message = ExtractMessageFromClientException(exception);
|
||||
if (!String.IsNullOrEmpty(message))
|
||||
{
|
||||
throw new InvalidOperationException(message, exception);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(
|
||||
String.Format(CultureInfo.CurrentCulture,
|
||||
NuGetResources.InvalidFeed,
|
||||
_context.BaseUri), exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ExtractMessageFromClientException(Exception exception)
|
||||
{
|
||||
var dataServiceQueryException = exception as DataServiceQueryException;
|
||||
if (dataServiceQueryException != null && dataServiceQueryException.InnerException != null)
|
||||
{
|
||||
var dataServiceClientException = dataServiceQueryException.InnerException as DataServiceClientException;
|
||||
XDocument document;
|
||||
if (dataServiceQueryException != null &&
|
||||
XmlUtility.TryParseDocument(dataServiceClientException.Message, out document) &&
|
||||
document.Root.Name.LocalName.Equals("error", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return document.Root.GetOptionalElementValue("message");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,282 +0,0 @@
|
||||
using NuGet.Resources;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Threading;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
/// <summary>
|
||||
/// The machine cache represents a location on the machine where packages are cached. It is a specific implementation of a local repository and can be used as such.
|
||||
/// NOTE: this is a shared location, and as such all IO operations need to be properly serialized
|
||||
/// </summary>
|
||||
public class MachineCache : LocalPackageRepository, IPackageCacheRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum number of packages that can live in this cache.
|
||||
/// </summary>
|
||||
private const int MaxPackages = 200;
|
||||
|
||||
private const string NuGetCachePathEnvironmentVariable = "NuGetCachePath";
|
||||
|
||||
private static readonly Lazy<MachineCache> _instance = new Lazy<MachineCache>(() => CreateDefault(GetCachePath));
|
||||
|
||||
internal MachineCache(IFileSystem fileSystem)
|
||||
: base(new DefaultPackagePathResolver(fileSystem), fileSystem, enableCaching: false)
|
||||
{
|
||||
}
|
||||
|
||||
public static MachineCache Default
|
||||
{
|
||||
get { return _instance.Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Machine Cache instance, assigns it to the instance variable and returns it.
|
||||
/// </summary>
|
||||
internal static MachineCache CreateDefault(Func<string> getCachePath)
|
||||
{
|
||||
IFileSystem fileSystem;
|
||||
try
|
||||
{
|
||||
string path = getCachePath();
|
||||
if (String.IsNullOrEmpty(path))
|
||||
{
|
||||
// If we don't get a path, use a null file system to make the cache object do nothing
|
||||
// This can happen when there is no LocalApplicationData folder
|
||||
fileSystem = NullFileSystem.Instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileSystem = new PhysicalFileSystem(path);
|
||||
}
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
// We are unable to access the special directory. Create a machine cache using an empty file system
|
||||
fileSystem = NullFileSystem.Instance;
|
||||
}
|
||||
return new MachineCache(fileSystem);
|
||||
}
|
||||
|
||||
public override void AddPackage(IPackage package)
|
||||
{
|
||||
// If we exceed the package count then clear the cache.
|
||||
var files = GetPackageFiles().ToList();
|
||||
if (files.Count >= MaxPackages)
|
||||
{
|
||||
// It's expensive to hit the file system to get the last accessed date for files
|
||||
// To reduce this cost from occuring frequently, we'll purge packages in batches allowing for a 20% buffer.
|
||||
var filesToDelete = files.OrderBy(FileSystem.GetLastAccessed)
|
||||
.Take(files.Count - (int)(0.8 * MaxPackages))
|
||||
.ToList();
|
||||
TryClear(filesToDelete);
|
||||
}
|
||||
|
||||
string path = GetPackageFilePath(package);
|
||||
TryAct(() =>
|
||||
{
|
||||
// we want to do this in the TryAct, i.e. in the mutex
|
||||
// for cases where package was added to cache by another process
|
||||
if (FileSystem.FileExists(path))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
string tmp = GetTempFile(path);
|
||||
using (var stream = package.GetStream())
|
||||
{
|
||||
FileSystem.AddFile(tmp, stream);
|
||||
}
|
||||
FileSystem.MoveFile(tmp, path);
|
||||
return true;
|
||||
}, path);
|
||||
}
|
||||
|
||||
// Unfortunately, there are many locations that query directly the filesystem to
|
||||
// assess if a package is present in the cache instead of calling into MachineCache.Exists
|
||||
// To guard against file in use issues, we create the cache entry with a tmp name and
|
||||
// rename when the file is ready for consumption.
|
||||
private static string GetTempFile(string filename)
|
||||
{
|
||||
return filename + ".tmp";
|
||||
}
|
||||
|
||||
public override bool Exists(string packageId, SemanticVersion version)
|
||||
{
|
||||
string packagePath = GetPackageFilePath(packageId, version);
|
||||
return TryAct(() => FileSystem.FileExists(packagePath), packagePath);
|
||||
}
|
||||
|
||||
public bool InvokeOnPackage(string packageId, SemanticVersion version, Action<Stream> action)
|
||||
{
|
||||
if (FileSystem is NullFileSystem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string packagePath = GetPackageFilePath(packageId, version);
|
||||
return TryAct(() =>
|
||||
{
|
||||
string tmp = GetTempFile(packagePath);
|
||||
using (var stream = FileSystem.CreateFile(tmp))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
action(stream);
|
||||
|
||||
// After downloading a package, check if it is an empty package
|
||||
// If so, do not store it in the machine cache
|
||||
if (stream == null || stream.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// fix up the package name if the nuspec gives the version in a different format
|
||||
// this allows versions to be normalized on the server while still supporting legacy formats for package restore
|
||||
IPackage package = OpenPackage(FileSystem.GetFullPath(tmp));
|
||||
|
||||
// for legacy support the package name needs to match the nuspec
|
||||
// Ex: owin.1.0.0.nupkg -> Owin.1.0.nupkg
|
||||
packagePath = GetPackageFilePath(package.Id, package.Version);
|
||||
|
||||
FileSystem.DeleteFile(packagePath);
|
||||
FileSystem.MoveFile(tmp, packagePath);
|
||||
|
||||
return true;
|
||||
}, packagePath);
|
||||
}
|
||||
|
||||
protected override IPackage OpenPackage(string path)
|
||||
{
|
||||
OptimizedZipPackage package;
|
||||
try
|
||||
{
|
||||
package = new OptimizedZipPackage(FileSystem, path);
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, NuGetResources.ErrorReadingPackage, path), ex);
|
||||
}
|
||||
|
||||
return package;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
TryClear(GetPackageFiles().ToList());
|
||||
}
|
||||
|
||||
private void TryClear(IEnumerable<string> files)
|
||||
{
|
||||
foreach (var packageFile in files)
|
||||
{
|
||||
TryAct(() =>
|
||||
{
|
||||
FileSystem.DeleteFileSafe(packageFile);
|
||||
return true;
|
||||
}, packageFile);
|
||||
}
|
||||
}
|
||||
|
||||
protected override string GetPackageFilePath(IPackage package)
|
||||
{
|
||||
return Path.GetFileName(base.GetPackageFilePath(package));
|
||||
}
|
||||
|
||||
protected override string GetPackageFilePath(string id, SemanticVersion version)
|
||||
{
|
||||
return Path.GetFileName(base.GetPackageFilePath(id, version));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the cache path to use for NuGet.exe. By default, NuGet caches files under %LocalAppData%\NuGet\Cache.
|
||||
/// This path can be overridden by specifying a value in the NuGetCachePath environment variable.
|
||||
/// </summary>
|
||||
internal static string GetCachePath()
|
||||
{
|
||||
return GetCachePath(Environment.GetEnvironmentVariable, Environment.GetFolderPath);
|
||||
}
|
||||
|
||||
internal static string GetCachePath(Func<string, string> getEnvironmentVariable, Func<System.Environment.SpecialFolder, string> getFolderPath)
|
||||
{
|
||||
string cacheOverride = getEnvironmentVariable(NuGetCachePathEnvironmentVariable);
|
||||
if (!String.IsNullOrEmpty(cacheOverride))
|
||||
{
|
||||
return cacheOverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
string localAppDataPath = getFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
if (String.IsNullOrEmpty(localAppDataPath))
|
||||
{
|
||||
// there's a bug on Windows Azure Web Sites environment where calling through the Environment.GetFolderPath()
|
||||
// will returns empty string, but the environment variable will return the correct value
|
||||
localAppDataPath = getEnvironmentVariable("LocalAppData");
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(localAppDataPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Path.Combine(localAppDataPath, "NuGet", "Cache");
|
||||
}
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// We use this method instead of the "safe" methods in FileSystem because it attempts to retry multiple times with delays.
|
||||
/// In our case, if we are unable to perform IO over the machine cache, we want to quit trying immediately.
|
||||
/// </remarks>
|
||||
private bool TryAct(Func<bool> action, string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Global: machine cache is per user across TS sessions
|
||||
var mutexName = "Global\\" + EncryptionUtility.GenerateUniqueToken(FileSystem.GetFullPath(path) ?? path);
|
||||
using (var mutex = new Mutex(false, mutexName))
|
||||
{
|
||||
bool owner = false;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
owner = mutex.WaitOne(TimeSpan.FromMinutes(3));
|
||||
// ideally we should throw an exception here if !owner such as
|
||||
// throw new TimeoutException(string.Format("Timeout waiting for Machine Cache mutex for {0}", fullPath));
|
||||
// we decided against it: machine cache operations being "best effort" basis.
|
||||
// this may cause "File in use" exceptions for long lasting operations such as downloading a large package on
|
||||
// a slow network connection
|
||||
}
|
||||
catch (AbandonedMutexException)
|
||||
{
|
||||
// TODO: consider logging a warning; abandonning a mutex is an indication something wrong is going on
|
||||
owner = true; // now mine
|
||||
}
|
||||
|
||||
return action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (owner)
|
||||
{
|
||||
mutex.ReleaseMutex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
// Do nothing if this fails.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class PackageRepositoryFactory : IPackageRepositoryFactory
|
||||
{
|
||||
private static readonly PackageRepositoryFactory _default = new PackageRepositoryFactory();
|
||||
private static readonly Func<Uri, IHttpClient> _defaultHttpClientFactory = u => new RedirectedHttpClient(u);
|
||||
private Func<Uri, IHttpClient> _httpClientFactory;
|
||||
|
||||
public static PackageRepositoryFactory Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return _default;
|
||||
}
|
||||
}
|
||||
|
||||
public Func<Uri, IHttpClient> HttpClientFactory
|
||||
{
|
||||
get { return _httpClientFactory ?? _defaultHttpClientFactory; }
|
||||
set { _httpClientFactory = value; }
|
||||
}
|
||||
|
||||
public virtual IPackageRepository CreateRepository(string packageSource)
|
||||
{
|
||||
if (packageSource == null)
|
||||
{
|
||||
throw new ArgumentNullException("packageSource");
|
||||
}
|
||||
|
||||
Uri uri = new Uri(packageSource);
|
||||
if (uri.IsFile)
|
||||
{
|
||||
return new LocalPackageRepository(uri.LocalPath);
|
||||
}
|
||||
|
||||
var client = HttpClientFactory(uri);
|
||||
|
||||
// Make sure we get resolve any fwlinks before creating the repository
|
||||
return new DataServicePackageRepository(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,328 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using NuGet.Resources;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class PackageServer
|
||||
{
|
||||
private const string ServiceEndpoint = "/api/v2/package";
|
||||
private const string ApiKeyHeader = "X-NuGet-ApiKey";
|
||||
private const int MaxRediretionCount = 20;
|
||||
|
||||
private Lazy<Uri> _baseUri;
|
||||
private readonly string _source;
|
||||
private readonly string _userAgent;
|
||||
|
||||
public event EventHandler<WebRequestEventArgs> SendingRequest = delegate { };
|
||||
|
||||
public PackageServer(string source, string userAgent)
|
||||
{
|
||||
if (String.IsNullOrEmpty(source))
|
||||
{
|
||||
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "source");
|
||||
}
|
||||
_source = source;
|
||||
_userAgent = userAgent;
|
||||
_baseUri = new Lazy<Uri>(ResolveBaseUrl);
|
||||
}
|
||||
|
||||
public string Source
|
||||
{
|
||||
get { return _source; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a package to the Source.
|
||||
/// </summary>
|
||||
/// <param name="apiKey">API key to be used to push the package.</param>
|
||||
/// <param name="package">The package to be pushed.</param>
|
||||
/// <param name="timeout">Time in milliseconds to timeout the server request.</param>
|
||||
/// <param name="disableBuffering">Indicates if HttpWebRequest buffering should be disabled.</param>
|
||||
public void PushPackage(string apiKey, IPackage package, long packageSize, int timeout, bool disableBuffering)
|
||||
{
|
||||
var sourceUri = new Uri(Source);
|
||||
if (sourceUri.IsFile)
|
||||
{
|
||||
PushPackageToFileSystem(
|
||||
new PhysicalFileSystem(sourceUri.LocalPath),
|
||||
package);
|
||||
}
|
||||
else
|
||||
{
|
||||
PushPackageToServer(apiKey, package.GetStream, packageSize, timeout, disableBuffering);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a package to the server that is represented by the stream.
|
||||
/// </summary>
|
||||
/// <param name="apiKey">API key to be used to push the package.</param>
|
||||
/// <param name="packageStreamFactory">A delegate which can be used to open a stream for the package file.</param>
|
||||
/// <param name="contentLength">Size of the package to be pushed.</param>
|
||||
/// <param name="timeout">Time in milliseconds to timeout the server request.</param>
|
||||
/// <param name="disableBuffering">Disable buffering.</param>
|
||||
private void PushPackageToServer(
|
||||
string apiKey,
|
||||
Func<Stream> packageStreamFactory,
|
||||
long packageSize,
|
||||
int timeout,
|
||||
bool disableBuffering)
|
||||
{
|
||||
int redirectionCount = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
HttpClient client = GetClient("", "PUT", "application/octet-stream");
|
||||
client.DisableBuffering = disableBuffering;
|
||||
|
||||
client.SendingRequest += (sender, e) =>
|
||||
{
|
||||
SendingRequest(this, e);
|
||||
var request = (HttpWebRequest)e.Request;
|
||||
|
||||
// Set the timeout
|
||||
if (timeout <= 0)
|
||||
{
|
||||
timeout = request.ReadWriteTimeout; // Default to 5 minutes if the value is invalid.
|
||||
}
|
||||
|
||||
request.Timeout = timeout;
|
||||
request.ReadWriteTimeout = timeout;
|
||||
if (!String.IsNullOrEmpty(apiKey))
|
||||
{
|
||||
request.Headers.Add(ApiKeyHeader, apiKey);
|
||||
}
|
||||
|
||||
var multiPartRequest = new MultipartWebRequest();
|
||||
multiPartRequest.AddFile(packageStreamFactory, "package", packageSize);
|
||||
|
||||
multiPartRequest.CreateMultipartRequest(request);
|
||||
};
|
||||
|
||||
// When AllowWriteStreamBuffering is set to false, redirection will not be handled
|
||||
// automatically by HttpWebRequest. So we need to check redirect status code and
|
||||
// update _baseUri and retry if redirection happens.
|
||||
if (EnsureSuccessfulResponse(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
++redirectionCount;
|
||||
if (redirectionCount > MaxRediretionCount)
|
||||
{
|
||||
throw new WebException(NuGetResources.Error_TooManyRedirections);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a package to a FileSystem.
|
||||
/// </summary>
|
||||
/// <param name="fileSystem">The FileSystem that the package is pushed to.</param>
|
||||
/// <param name="package">The package to be pushed.</param>
|
||||
private static void PushPackageToFileSystem(IFileSystem fileSystem, IPackage package)
|
||||
{
|
||||
var pathResolver = new DefaultPackagePathResolver(fileSystem);
|
||||
var packageFileName = pathResolver.GetPackageFileName(package);
|
||||
using (var stream = package.GetStream())
|
||||
{
|
||||
fileSystem.AddFile(packageFileName, stream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a package from the Source.
|
||||
/// </summary>
|
||||
/// <param name="apiKey">API key to be used to delete the package.</param>
|
||||
/// <param name="packageId">The package Id.</param>
|
||||
/// <param name="packageVersion">The package version.</param>
|
||||
public void DeletePackage(string apiKey, string packageId, string packageVersion)
|
||||
{
|
||||
var sourceUri = new Uri(Source);
|
||||
if (sourceUri.IsFile)
|
||||
{
|
||||
DeletePackageFromFileSystem(
|
||||
new PhysicalFileSystem(sourceUri.LocalPath),
|
||||
packageId,
|
||||
packageVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeletePackageFromServer(apiKey, packageId, packageVersion);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a package from the server represented by the Source.
|
||||
/// </summary>
|
||||
/// <param name="apiKey">API key to be used to delete the package.</param>
|
||||
/// <param name="packageId">The package Id.</param>
|
||||
/// <param name="packageVersion">The package Id.</param>
|
||||
private void DeletePackageFromServer(string apiKey, string packageId, string packageVersion)
|
||||
{
|
||||
// Review: Do these values need to be encoded in any way?
|
||||
var url = String.Join("/", packageId, packageVersion);
|
||||
HttpClient client = GetClient(url, "DELETE", "text/html");
|
||||
|
||||
client.SendingRequest += (sender, e) =>
|
||||
{
|
||||
SendingRequest(this, e);
|
||||
var request = (HttpWebRequest)e.Request;
|
||||
request.Headers.Add(ApiKeyHeader, apiKey);
|
||||
};
|
||||
EnsureSuccessfulResponse(client);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a package from a FileSystem.
|
||||
/// </summary>
|
||||
/// <param name="fileSystem">The FileSystem where the specified package is deleted.</param>
|
||||
/// <param name="packageId">The package Id.</param>
|
||||
/// <param name="packageVersion">The package Id.</param>
|
||||
private static void DeletePackageFromFileSystem(IFileSystem fileSystem, string packageId, string packageVersion)
|
||||
{
|
||||
var pathResolver = new DefaultPackagePathResolver(fileSystem);
|
||||
var packageFileName = pathResolver.GetPackageFileName(packageId, new SemanticVersion(packageVersion));
|
||||
fileSystem.DeleteFile(packageFileName);
|
||||
}
|
||||
|
||||
private HttpClient GetClient(string path, string method, string contentType)
|
||||
{
|
||||
var baseUrl = _baseUri.Value;
|
||||
Uri requestUri = GetServiceEndpointUrl(baseUrl, path);
|
||||
|
||||
var client = new HttpClient(requestUri)
|
||||
{
|
||||
ContentType = contentType,
|
||||
Method = method
|
||||
};
|
||||
|
||||
if (!String.IsNullOrEmpty(_userAgent))
|
||||
{
|
||||
client.UserAgent = HttpUtility.CreateUserAgentString(_userAgent);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
internal static Uri GetServiceEndpointUrl(Uri baseUrl, string path)
|
||||
{
|
||||
Uri requestUri;
|
||||
if (String.IsNullOrEmpty(baseUrl.AbsolutePath.TrimStart('/')))
|
||||
{
|
||||
// If there's no host portion specified, append the url to the client.
|
||||
requestUri = new Uri(baseUrl, ServiceEndpoint + '/' + path);
|
||||
}
|
||||
else
|
||||
{
|
||||
requestUri = new Uri(baseUrl, path);
|
||||
}
|
||||
return requestUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that success response is received.
|
||||
/// </summary>
|
||||
/// <param name="client">The client that is making the request.</param>
|
||||
/// <param name="expectedStatusCode">The exected status code.</param>
|
||||
/// <returns>True if success response is received; false if redirection response is received.
|
||||
/// In this case, _baseUri will be updated to be the new redirected Uri and the requrest
|
||||
/// should be retried.</returns>
|
||||
private bool EnsureSuccessfulResponse(HttpClient client, HttpStatusCode? expectedStatusCode = null)
|
||||
{
|
||||
HttpWebResponse response = null;
|
||||
try
|
||||
{
|
||||
response = (HttpWebResponse)client.GetResponse();
|
||||
if (response != null &&
|
||||
((expectedStatusCode.HasValue && expectedStatusCode.Value != response.StatusCode) ||
|
||||
|
||||
// If expected status code isn't provided, just look for anything 400 (Client Errors) or higher (incl. 500-series, Server Errors)
|
||||
// 100-series is protocol changes, 200-series is success, 300-series is redirect.
|
||||
(!expectedStatusCode.HasValue && (int)response.StatusCode >= 400)))
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.PackageServerError, response.StatusDescription, String.Empty));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
if (e.Response == null)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
response = (HttpWebResponse)e.Response;
|
||||
|
||||
// Check if the error is caused by redirection
|
||||
if (response.StatusCode == HttpStatusCode.MultipleChoices ||
|
||||
response.StatusCode == HttpStatusCode.MovedPermanently ||
|
||||
response.StatusCode == HttpStatusCode.Found ||
|
||||
response.StatusCode == HttpStatusCode.SeeOther ||
|
||||
response.StatusCode == HttpStatusCode.TemporaryRedirect)
|
||||
{
|
||||
var location = response.Headers["Location"];
|
||||
Uri newUri;
|
||||
if (!Uri.TryCreate(client.Uri, location, out newUri))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
_baseUri = new Lazy<Uri>(() => newUri);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expectedStatusCode != response.StatusCode)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, NuGetResources.PackageServerError, response.StatusDescription, e.Message), e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (response != null)
|
||||
{
|
||||
response.Close();
|
||||
response = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Uri ResolveBaseUrl()
|
||||
{
|
||||
Uri uri;
|
||||
|
||||
try
|
||||
{
|
||||
var client = new RedirectedHttpClient(new Uri(Source));
|
||||
uri = client.Uri;
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
var response = (HttpWebResponse)ex.Response;
|
||||
if (response == null)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
uri = response.ResponseUri;
|
||||
}
|
||||
|
||||
return EnsureTrailingSlash(uri);
|
||||
}
|
||||
|
||||
private static Uri EnsureTrailingSlash(Uri uri)
|
||||
{
|
||||
string value = uri.OriginalString;
|
||||
if (!value.EndsWith("/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
value += "/";
|
||||
}
|
||||
return new Uri(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public static class EncryptionUtility
|
||||
{
|
||||
private static readonly byte[] _entropyBytes = Encoding.UTF8.GetBytes("NuGet");
|
||||
|
||||
internal static string EncryptString(string value)
|
||||
{
|
||||
var decryptedByteArray = Encoding.UTF8.GetBytes(value);
|
||||
var encryptedByteArray = ProtectedData.Protect(decryptedByteArray, _entropyBytes, DataProtectionScope.CurrentUser);
|
||||
var encryptedString = Convert.ToBase64String(encryptedByteArray);
|
||||
return encryptedString;
|
||||
}
|
||||
|
||||
internal static string DecryptString(string encryptedString)
|
||||
{
|
||||
var encryptedByteArray = Convert.FromBase64String(encryptedString);
|
||||
var decryptedByteArray = ProtectedData.Unprotect(encryptedByteArray, _entropyBytes, DataProtectionScope.CurrentUser);
|
||||
return Encoding.UTF8.GetString(decryptedByteArray);
|
||||
}
|
||||
|
||||
public static string GenerateUniqueToken(string caseInsensitiveKey)
|
||||
{
|
||||
// SHA256 is case sensitive; given that our key is case insensitive, we upper case it
|
||||
var pathBytes = Encoding.UTF8.GetBytes(caseInsensitiveKey.ToUpperInvariant());
|
||||
var hashProvider = new CryptoHashProvider("SHA256");
|
||||
|
||||
return Convert.ToBase64String(hashProvider.CalculateHash(pathBytes)).ToUpperInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using NuGet.Resources;
|
||||
|
||||
namespace NuGet
|
||||
{
|
||||
public class PackageDownloader : IHttpClientEvents
|
||||
{
|
||||
private const string DefaultUserAgentClient = "NuGet Core";
|
||||
|
||||
public event EventHandler<ProgressEventArgs> ProgressAvailable = delegate { };
|
||||
public event EventHandler<WebRequestEventArgs> SendingRequest = delegate { };
|
||||
|
||||
public string CurrentDownloadPackageId
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string CurrentDownloadPackageVersion
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public virtual void DownloadPackage(Uri uri, IPackageMetadata package, Stream targetStream)
|
||||
{
|
||||
if (uri == null)
|
||||
{
|
||||
throw new ArgumentNullException("uri");
|
||||
}
|
||||
|
||||
var downloadClient = new HttpClient(uri)
|
||||
{
|
||||
UserAgent = HttpUtility.CreateUserAgentString(DefaultUserAgentClient)
|
||||
};
|
||||
DownloadPackage(downloadClient, package, targetStream);
|
||||
}
|
||||
|
||||
public void DownloadPackage(IHttpClient downloadClient, IPackageName package, Stream targetStream)
|
||||
{
|
||||
if (downloadClient == null)
|
||||
{
|
||||
throw new ArgumentNullException("downloadClient");
|
||||
}
|
||||
|
||||
if (targetStream == null)
|
||||
{
|
||||
throw new ArgumentNullException("targetStream");
|
||||
}
|
||||
|
||||
// Get the operation display text
|
||||
string operation = String.Format(CultureInfo.CurrentCulture, NuGetResources.DownloadProgressStatus, package.Id, package.Version);
|
||||
CurrentDownloadPackageId = package.Id;
|
||||
CurrentDownloadPackageVersion = package.Version.ToString();
|
||||
|
||||
EventHandler<ProgressEventArgs> progressAvailableHandler = (sender, e) =>
|
||||
{
|
||||
OnPackageDownloadProgress(new ProgressEventArgs(operation, e.PercentComplete));
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
downloadClient.ProgressAvailable += progressAvailableHandler;
|
||||
downloadClient.SendingRequest += OnSendingRequest;
|
||||
|
||||
downloadClient.DownloadData(targetStream);
|
||||
}
|
||||
finally
|
||||
{
|
||||
downloadClient.ProgressAvailable -= progressAvailableHandler;
|
||||
downloadClient.SendingRequest -= OnSendingRequest;
|
||||
CurrentDownloadPackageId = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPackageDownloadProgress(ProgressEventArgs e)
|
||||
{
|
||||
ProgressAvailable(this, e);
|
||||
}
|
||||
|
||||
private void OnSendingRequest(object sender, WebRequestEventArgs webRequestArgs)
|
||||
{
|
||||
SendingRequest(this, webRequestArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user