diff --git a/NuGet.sln b/NuGet.sln index fa083edf30c..7433d46c73a 100644 --- a/NuGet.sln +++ b/NuGet.sln @@ -624,7 +624,7 @@ Global {50E33DA2-AF14-486D-81B8-BD8409744A38} = {08F523EC-3C2A-4A00-A54C-2E54C5AC856B} {23725516-0A6E-48F9-A148-B5E3FA515B13} = {00CE0FBE-DA5A-4AD8-B0D6-04ECE6B04F0D} {5039C2F9-CAD9-4162-849C-5EF7E3CE03D9} = {01BC4531-1E25-48D7-A8FD-A47D6FEC47FB} - {3DB4EDE3-B57B-498C-9EA9-A8BF8D9D4B2B} = {01BC4531-1E25-48D7-A8FD-A47D6FEC47FB} + {3DB4EDE3-B57B-498C-9EA9-A8BF8D9D4B2B} = {7323F93B-D141-4001-BB9E-7AF14031143E} {6157BF46-D371-4126-A7F1-ED6E23F77ACD} = {01BC4531-1E25-48D7-A8FD-A47D6FEC47FB} {9EA84487-C70C-420C-9674-75CF19F43757} = {01BC4531-1E25-48D7-A8FD-A47D6FEC47FB} {F7837EEB-1B49-482F-8722-EB35BA0937CC} = {01BC4531-1E25-48D7-A8FD-A47D6FEC47FB} diff --git a/runTests.ps1 b/runTests.ps1 index 80f0f78e5ce..60515972e67 100644 --- a/runTests.ps1 +++ b/runTests.ps1 @@ -87,9 +87,9 @@ Invoke-BuildStep 'Cleaning package cache' { -skip:(-not $CI) ` -ev +BuildErrors -Invoke-BuildStep 'Running /t:RestoreVS15' { +Invoke-BuildStep 'Running /t:RestoreVS' { - & $MSBuildExe build\build.proj /t:RestoreVS15 /p:Configuration=$Configuration /p:ReleaseLabel=$ReleaseLabel /p:BuildNumber=$BuildNumber /v:m /m:1 + & $MSBuildExe build\build.proj /t:RestoreVS /p:Configuration=$Configuration /p:ReleaseLabel=$ReleaseLabel /p:BuildNumber=$BuildNumber /v:m /m:1 if (-not $?) { diff --git a/src/NuGet.Clients/NuGet.CommandLine/Commands/Command.cs b/src/NuGet.Clients/NuGet.CommandLine/Commands/Command.cs index 228dc9c2ae2..a176ed81484 100644 --- a/src/NuGet.Clients/NuGet.CommandLine/Commands/Command.cs +++ b/src/NuGet.Clients/NuGet.CommandLine/Commands/Command.cs @@ -15,6 +15,7 @@ using NuGet.Credentials; using NuGet.Protocol; using NuGet.Protocol.Core.Types; +using NuGet.Protocol.Plugins; namespace NuGet.CommandLine { @@ -78,7 +79,8 @@ public string CurrentDirectory protected internal CoreV2.NuGet.IPackageRepositoryFactory RepositoryFactory { get; set; } - private Lazy MsBuildToolset { + private Lazy MsBuildToolset + { get { if (_defaultMsBuildToolset == null) @@ -211,7 +213,7 @@ private async Task> GetCredentialProvidersAsync var pluginProviders = new PluginCredentialProviderBuilder(extensionLocator, Settings, Console) .BuildAll(Verbosity.ToString()) .ToList(); - var securePluginProviders = await (new SecurePluginCredentialProviderBuilder(pluginManager: PluginManager.Instance, canShowDialog: true, logger: Console)).BuildAllAsync(); + var securePluginProviders = await (new SecurePluginCredentialProviderBuilder(PluginManager.Instance, canShowDialog: true, logger: Console)).BuildAllAsync(); providers.Add(new CredentialProviderAdapter(new SettingsCredentialProvider(SourceProvider, Console))); providers.AddRange(securePluginProviders); diff --git a/src/NuGet.Clients/NuGet.PackageManagement.PowerShellCmdlets/NuGet.PackageManagement.PowerShellCmdlets.csproj b/src/NuGet.Clients/NuGet.PackageManagement.PowerShellCmdlets/NuGet.PackageManagement.PowerShellCmdlets.csproj index c5c68e06bd2..e9e3a2f3554 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.PowerShellCmdlets/NuGet.PackageManagement.PowerShellCmdlets.csproj +++ b/src/NuGet.Clients/NuGet.PackageManagement.PowerShellCmdlets/NuGet.PackageManagement.PowerShellCmdlets.csproj @@ -1,4 +1,4 @@ - + @@ -77,10 +77,7 @@ - - {e5556bc6-a7fd-4d8e-8a7d-7648df1d7471} - NuGet.VisualStudio - + diff --git a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/DefaultVSCredentialServiceProvider.cs b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/DefaultVSCredentialServiceProvider.cs index 849ab7d8a14..3926f925886 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/DefaultVSCredentialServiceProvider.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/DefaultVSCredentialServiceProvider.cs @@ -11,7 +11,7 @@ using NuGet.Common; using NuGet.Credentials; using NuGet.ProjectManagement; -using NuGet.Protocol.Core.Types; +using NuGet.Protocol.Plugins; using NuGet.VisualStudio; using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; @@ -150,4 +150,4 @@ private void LogCredentialProviderError(Exception exception, string failureMessa exception); } } -} +} \ No newline at end of file diff --git a/src/NuGet.Core/NuGet.Credentials/DefaultCredentialServiceUtility.cs b/src/NuGet.Core/NuGet.Credentials/DefaultCredentialServiceUtility.cs index 0c76f14afca..5415e2bbf66 100644 --- a/src/NuGet.Core/NuGet.Credentials/DefaultCredentialServiceUtility.cs +++ b/src/NuGet.Core/NuGet.Credentials/DefaultCredentialServiceUtility.cs @@ -8,7 +8,7 @@ using NuGet.Common; using NuGet.Configuration; using NuGet.Protocol; -using NuGet.Protocol.Core.Types; +using NuGet.Protocol.Plugins; namespace NuGet.Credentials { @@ -45,6 +45,5 @@ private static async Task> GetCredentialProvide } return providers; } - } -} +} \ No newline at end of file diff --git a/src/NuGet.Core/NuGet.Credentials/SecurePluginCredentialProvider.cs b/src/NuGet.Core/NuGet.Credentials/SecurePluginCredentialProvider.cs index 6b4622d4c44..d620d44814a 100644 --- a/src/NuGet.Core/NuGet.Credentials/SecurePluginCredentialProvider.cs +++ b/src/NuGet.Core/NuGet.Credentials/SecurePluginCredentialProvider.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; @@ -41,7 +40,6 @@ public sealed class SecurePluginCredentialProvider : ICredentialProvider // We use this to avoid needlessly instantiating plugins if they don't support authentication. private bool _isAnAuthenticationPlugin = true; - /// /// Create a credential provider based on provided plugin /// @@ -89,34 +87,42 @@ public async Task GetAsync(Uri uri, IWebProxy proxy, Credent return taskResponse; } - var creationResult = await _pluginManager.TryGetSourceAgnosticPluginAsync(_discoveredPlugin, OperationClaim.Authentication, cancellationToken); + Tuple result = await _pluginManager.TryGetSourceAgnosticPluginAsync(_discoveredPlugin, OperationClaim.Authentication, cancellationToken); + + bool wasSomethingCreated = result.Item1; - if (creationResult.Item1) // status of the source creation + if (wasSomethingCreated) { - var plugin = creationResult.Item2; // plugin creation result - if (!string.IsNullOrEmpty(plugin.Message)) + PluginCreationResult creationResult = result.Item2; + + if (!string.IsNullOrEmpty(creationResult.Message)) { // There is a potential here for double logging as the CredentialService itself catches the exceptions and tries to log it. - // In reality the logger in the Credential Service will be null because the first request always comes from a resource provider (ServiceIndex provider) - _logger.LogError(plugin.Message); + // In reality the logger in the Credential Service will be null because the first request always comes from a resource provider (ServiceIndex provider). + _logger.LogError(creationResult.Message); + + if (creationResult.Exception != null) + { + _logger.LogDebug(creationResult.Exception.ToString()); + } _isAnAuthenticationPlugin = false; - throw new PluginException(plugin.Message); // Throwing here will block authentication and ensure that the complete operation fails + throw new PluginException(creationResult.Message, creationResult.Exception); // Throwing here will block authentication and ensure that the complete operation fails. } - _isAnAuthenticationPlugin = plugin.Claims.Contains(OperationClaim.Authentication); + _isAnAuthenticationPlugin = creationResult.Claims.Contains(OperationClaim.Authentication); if (_isAnAuthenticationPlugin) { - AddOrUpdateLogger(plugin.Plugin); - await SetPluginLogLevelAsync(plugin, _logger, cancellationToken); + AddOrUpdateLogger(creationResult.Plugin); + await SetPluginLogLevelAsync(creationResult, _logger, cancellationToken); if (proxy != null) { - await SetProxyCredentialsToPlugin(uri, proxy, plugin, cancellationToken); + await SetProxyCredentialsToPlugin(uri, proxy, creationResult, cancellationToken); } var request = new GetAuthenticationCredentialsRequest(uri, isRetry, nonInteractive, _canShowDialog); - var credentialResponse = await plugin.Plugin.Connection.SendRequestAndReceiveResponseAsync( + var credentialResponse = await creationResult.Plugin.Connection.SendRequestAndReceiveResponseAsync( MessageMethod.GetAuthenticationCredentials, request, cancellationToken); @@ -124,13 +130,11 @@ public async Task GetAsync(Uri uri, IWebProxy proxy, Credent { _logger.LogWarning( string.Format( - CultureInfo.CurrentCulture, - Resources.SecurePluginWarning_UseInteractiveOption) - ); + CultureInfo.CurrentCulture, + Resources.SecurePluginWarning_UseInteractiveOption)); } taskResponse = GetAuthenticationCredentialsResponseToCredentialResponse(credentialResponse); - } } else @@ -214,4 +218,4 @@ private static CredentialResponse GetAuthenticationCredentialsResponseToCredenti return taskResponse; } } -} +} \ No newline at end of file diff --git a/src/NuGet.Core/NuGet.Protocol/Plugins/PluginCreationResult.cs b/src/NuGet.Core/NuGet.Protocol/Plugins/PluginCreationResult.cs index 0a57f1689ec..e330a666036 100644 --- a/src/NuGet.Core/NuGet.Protocol/Plugins/PluginCreationResult.cs +++ b/src/NuGet.Core/NuGet.Protocol/Plugins/PluginCreationResult.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -21,6 +21,11 @@ public sealed class PluginCreationResult /// public string Message { get; } + /// + /// Gets the exception caught. May be null. + /// + public Exception Exception { get; } + /// /// Gets a plugin. /// @@ -77,5 +82,24 @@ public PluginCreationResult(string message) Message = message; } + + /// + /// Instantiates a new class. + /// + /// A message why a plugin could not be created. + /// An exception. + /// Thrown if + /// is either null or an empty string. + /// Thrown if is null. + public PluginCreationResult(string message, Exception exception) + : this(message) + { + if (exception == null) + { + throw new ArgumentNullException(nameof(exception)); + } + + Exception = exception; + } } } \ No newline at end of file diff --git a/src/NuGet.Core/NuGet.Protocol/Plugins/PluginFactory.cs b/src/NuGet.Core/NuGet.Protocol/Plugins/PluginFactory.cs index 17c8db82cd9..5536d124bb6 100644 --- a/src/NuGet.Core/NuGet.Protocol/Plugins/PluginFactory.cs +++ b/src/NuGet.Core/NuGet.Protocol/Plugins/PluginFactory.cs @@ -391,7 +391,7 @@ private void OnPluginProcessExited(object sender, EventArgs e, string pluginId, } } - private void SendCloseRequest(IPlugin plugin) + private static void SendCloseRequest(IPlugin plugin) { var message = plugin.Connection.MessageDispatcher.CreateMessage( MessageType.Request, diff --git a/src/NuGet.Core/NuGet.Protocol/Plugins/PluginManager.cs b/src/NuGet.Core/NuGet.Protocol/Plugins/PluginManager.cs index 37232543512..40167827d2d 100644 --- a/src/NuGet.Core/NuGet.Protocol/Plugins/PluginManager.cs +++ b/src/NuGet.Core/NuGet.Protocol/Plugins/PluginManager.cs @@ -13,10 +13,10 @@ using NuGet.Common; using NuGet.Configuration; using NuGet.Packaging; -using NuGet.Protocol.Plugins; +using NuGet.Protocol.Core.Types; using NuGet.Shared; -namespace NuGet.Protocol.Core.Types +namespace NuGet.Protocol.Plugins { /// /// A plugin manager. This manages all the live plugins and their operation claims. @@ -24,8 +24,8 @@ namespace NuGet.Protocol.Core.Types /// public sealed class PluginManager : IPluginManager, IDisposable { - private static readonly Lazy Lazy = new Lazy(() => new PluginManager()); - public static IPluginManager Instance => Lazy.Value; + private static readonly Lazy _lazy = new Lazy(() => new PluginManager()); + public static IPluginManager Instance => _lazy.Value; private ConnectionOptions _connectionOptions; private Lazy _discoverer; @@ -36,7 +36,7 @@ public sealed class PluginManager : IPluginManager, IDisposable private string _rawPluginPaths; private static Lazy _currentProcessId = new Lazy(GetCurrentProcessId); - private Lazy _pluginsCacheDirectory = new Lazy(() => SettingsUtility.GetPluginsCacheFolder()); + private Lazy _pluginsCacheDirectoryPath; /// /// Gets an environment variable reader. @@ -49,29 +49,21 @@ private PluginManager() Initialize( new EnvironmentVariableWrapper(), new Lazy(InitializeDiscoverer), - (TimeSpan idleTimeout) => new PluginFactory(idleTimeout)); + (TimeSpan idleTimeout) => new PluginFactory(idleTimeout), + new Lazy(() => SettingsUtility.GetPluginsCacheFolder())); } - /// - /// Creates a new plugin manager - /// - /// This is public to facilitate unit testing. This should not be called from product code - /// An environment variable reader. - /// A lazy plugin discoverer. - /// A plugin factory creator. - /// Thrown if is null. - /// Thrown if - /// is null. - /// Thrown if - /// is null. - public PluginManager(IEnvironmentVariableReader reader, + internal PluginManager( + IEnvironmentVariableReader reader, Lazy pluginDiscoverer, - Func pluginFactoryCreator) + Func pluginFactoryCreator, + Lazy pluginsCacheDirectoryPath) { Initialize( reader, pluginDiscoverer, - pluginFactoryCreator); + pluginFactoryCreator, + pluginsCacheDirectoryPath); } /// @@ -202,7 +194,7 @@ private async Task> TryCreatePluginAsync( CancellationToken cancellationToken) { PluginCreationResult pluginCreationResult = null; - var cacheEntry = new PluginCacheEntry(_pluginsCacheDirectory.Value, result.PluginFile.Path, requestKey.PackageSourceRepository); + var cacheEntry = new PluginCacheEntry(_pluginsCacheDirectoryPath.Value, result.PluginFile.Path, requestKey.PackageSourceRepository); return await ConcurrencyUtilities.ExecuteWithFileLockedAsync( cacheEntry.CacheFileName, @@ -225,13 +217,13 @@ private async Task> TryCreatePluginAsync( // We still make the GetOperationClaims call even if we have the operation claims cached. This is a way to self-update the cache. var operationClaims = await _pluginOperationClaims.GetOrAdd( - requestKey, - key => new Lazy>>(() => - GetPluginOperationClaimsAsync( - plugin, - packageSourceRepository, - serviceIndex, - cancellationToken))).Value; + requestKey, + key => new Lazy>>(() => + GetPluginOperationClaimsAsync( + plugin, + packageSourceRepository, + serviceIndex, + cancellationToken))).Value; if (!EqualityUtility.SequenceEqualWithNullCheck(operationClaims, cacheEntry.OperationClaims)) { @@ -251,12 +243,12 @@ private async Task> TryCreatePluginAsync( } catch (Exception e) { - // Have a clear error message when the plugin creation fails. pluginCreationResult = new PluginCreationResult( string.Format(CultureInfo.CurrentCulture, - Strings.Plugin_ProblemStartingPlugin, - result.PluginFile.Path, - e.Message)); + Strings.Plugin_ProblemStartingPlugin, + result.PluginFile.Path, + e.Message), + e); } } return new Tuple(pluginCreationResult != null, pluginCreationResult); @@ -268,9 +260,9 @@ private async Task> TryCreatePluginAsync( private async Task> PerformOneTimePluginInitializationAsync(IPlugin plugin, CancellationToken cancellationToken) { var utilities = _pluginUtilities.GetOrAdd( - plugin.Id, - path => new Lazy( - () => new PluginMulticlientUtilities())); + plugin.Id, + path => new Lazy( + () => new PluginMulticlientUtilities())); await utilities.Value.DoOncePerPluginLifetimeAsync( MessageMethod.MonitorNuGetProcessExit.ToString(), @@ -284,15 +276,18 @@ await utilities.Value.DoOncePerPluginLifetimeAsync( MessageMethod.Initialize.ToString(), () => InitializePluginAsync(plugin, _connectionOptions.RequestTimeout, cancellationToken), cancellationToken); + return utilities; } private void Initialize(IEnvironmentVariableReader reader, Lazy pluginDiscoverer, - Func pluginFactoryCreator) + Func pluginFactoryCreator, + Lazy pluginsCacheDirectoryPath) { EnvironmentVariableReader = reader ?? throw new ArgumentNullException(nameof(reader)); _discoverer = pluginDiscoverer ?? throw new ArgumentNullException(nameof(pluginDiscoverer)); + _pluginsCacheDirectoryPath = pluginsCacheDirectoryPath ?? throw new ArgumentNullException(nameof(pluginsCacheDirectoryPath)); if (pluginFactoryCreator == null) { diff --git a/src/NuGet.Core/NuGet.Protocol/Properties/AssemblyInfo.cs b/src/NuGet.Core/NuGet.Protocol/Properties/AssemblyInfo.cs index f4af1d93a4a..fec189bd53a 100644 --- a/src/NuGet.Core/NuGet.Protocol/Properties/AssemblyInfo.cs +++ b/src/NuGet.Core/NuGet.Protocol/Properties/AssemblyInfo.cs @@ -7,9 +7,11 @@ [assembly: CLSCompliant(true)] #if SIGNED_BUILD +[assembly: InternalsVisibleTo("NuGet.Credentials.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] [assembly: InternalsVisibleTo("NuGet.Protocol.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] #else +[assembly: InternalsVisibleTo("NuGet.Credentials.Test")] [assembly: InternalsVisibleTo("NuGet.Protocol.Tests")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] #endif \ No newline at end of file diff --git a/src/NuGet.Core/NuGet.Protocol/Providers/PluginResourceProvider.cs b/src/NuGet.Core/NuGet.Protocol/Providers/PluginResourceProvider.cs index f7383156784..4f10f77487c 100644 --- a/src/NuGet.Core/NuGet.Protocol/Providers/PluginResourceProvider.cs +++ b/src/NuGet.Core/NuGet.Protocol/Providers/PluginResourceProvider.cs @@ -2,18 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json.Linq; -using NuGet.Common; -using NuGet.Packaging; using NuGet.Protocol.Plugins; -using NuGet.Shared; namespace NuGet.Protocol.Core.Types { @@ -23,7 +15,6 @@ namespace NuGet.Protocol.Core.Types /// This is unsealed only to facilitate testing. public class PluginResourceProvider : ResourceProvider { - private readonly IPluginManager _pluginManager; public PluginResourceProvider() : this(PluginManager.Instance) diff --git a/src/NuGet.Core/NuGet.Protocol/Strings.Designer.cs b/src/NuGet.Core/NuGet.Protocol/Strings.Designer.cs index f33ed778076..007c7cc4340 100644 --- a/src/NuGet.Core/NuGet.Protocol/Strings.Designer.cs +++ b/src/NuGet.Core/NuGet.Protocol/Strings.Designer.cs @@ -781,7 +781,7 @@ internal static string Plugin_PackageDownloadFailed { } /// - /// Looks up a localized string similar to Problem starting the plugin '{0}'. {1}. + /// Looks up a localized string similar to Problem starting the plugin '{0}'. {1}. /// internal static string Plugin_ProblemStartingPlugin { get { diff --git a/src/NuGet.Core/NuGet.Protocol/Strings.resx b/src/NuGet.Core/NuGet.Protocol/Strings.resx index 72bc903a1f4..7041fb58171 100644 --- a/src/NuGet.Core/NuGet.Protocol/Strings.resx +++ b/src/NuGet.Core/NuGet.Protocol/Strings.resx @@ -1,4 +1,4 @@ - +