From 2fc7b8b5f7fba42ab11b1c8ba742f0ba30d1a215 Mon Sep 17 00:00:00 2001 From: Jeff Kluge Date: Thu, 16 Aug 2018 13:57:36 -0700 Subject: [PATCH] Add Interactive property to SdkResolverContext Defaults to false. Currently only set to `true` if the global property `NuGetInteractive` is set to "true". In 16.0, we should add an `/interactive` command-line argument which sets this instead. --- .../net/Microsoft.Build.Framework.cs | 1 + .../netstandard/Microsoft.Build.Framework.cs | 1 + .../BackEnd/MockSdkResolverService.cs | 2 +- .../BackEnd/SdkResolverService_Tests.cs | 54 +++++++++++++++---- src/Build.UnitTests/InternalEngineHelpers.cs | 13 +++++ .../CachingSdkResolverService.cs | 6 +-- .../HostedSdkResolverServiceBase.cs | 2 +- .../SdkResolution/ISdkResolverService.cs | 3 +- .../MainNodeSdkResolverService.cs | 6 +-- .../OutOfProcNodeSdkResolverService.cs | 8 +-- .../SdkResolution/SdkResolverContext.cs | 3 +- .../SdkResolution/SdkResolverRequest.cs | 11 ++-- .../SdkResolution/SdkResolverService.cs | 4 +- src/Build/Evaluation/Evaluator.cs | 6 ++- src/Framework/Sdk/SdkResolverContext.cs | 5 ++ 15 files changed, 94 insertions(+), 31 deletions(-) diff --git a/ref/Microsoft.Build.Framework/net/Microsoft.Build.Framework.cs b/ref/Microsoft.Build.Framework/net/Microsoft.Build.Framework.cs index 7573ba8d729..586c3cf4caf 100644 --- a/ref/Microsoft.Build.Framework/net/Microsoft.Build.Framework.cs +++ b/ref/Microsoft.Build.Framework/net/Microsoft.Build.Framework.cs @@ -453,6 +453,7 @@ protected SdkResolver() { } public abstract partial class SdkResolverContext { protected SdkResolverContext() { } + public virtual bool Interactive { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]protected set { } } public virtual Microsoft.Build.Framework.SdkLogger Logger { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]protected set { } } public virtual System.Version MSBuildVersion { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]protected set { } } public virtual string ProjectFilePath { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]protected set { } } diff --git a/ref/Microsoft.Build.Framework/netstandard/Microsoft.Build.Framework.cs b/ref/Microsoft.Build.Framework/netstandard/Microsoft.Build.Framework.cs index 97c77884c5d..5cb28a98f80 100644 --- a/ref/Microsoft.Build.Framework/netstandard/Microsoft.Build.Framework.cs +++ b/ref/Microsoft.Build.Framework/netstandard/Microsoft.Build.Framework.cs @@ -452,6 +452,7 @@ protected SdkResolver() { } public abstract partial class SdkResolverContext { protected SdkResolverContext() { } + public virtual bool Interactive { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]protected set { } } public virtual Microsoft.Build.Framework.SdkLogger Logger { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]protected set { } } public virtual System.Version MSBuildVersion { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]protected set { } } public virtual string ProjectFilePath { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]protected set { } } diff --git a/src/Build.UnitTests/BackEnd/MockSdkResolverService.cs b/src/Build.UnitTests/BackEnd/MockSdkResolverService.cs index 9de57c096b4..f3cfd1a2cb6 100644 --- a/src/Build.UnitTests/BackEnd/MockSdkResolverService.cs +++ b/src/Build.UnitTests/BackEnd/MockSdkResolverService.cs @@ -19,7 +19,7 @@ public void ClearCaches() { } - public Build.BackEnd.SdkResolution.SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) + public Build.BackEnd.SdkResolution.SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive) { return null; } diff --git a/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs b/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs index 29737ab5b77..cc7b795561f 100644 --- a/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs +++ b/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs @@ -40,7 +40,7 @@ public void AssertAllResolverErrorsLoggedWhenSdkNotResolved() SdkReference sdk = new SdkReference("notfound", "referencedVersion", "minimumVersion"); - var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath"); + var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false); result.Success.ShouldBeFalse(); result.ShouldNotBeNull(); @@ -73,7 +73,7 @@ public void AssertResolutionWarnsIfResolvedVersionIsDifferentFromReferencedVersi )) }); - var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath"); + var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false); result.Path.ShouldBe("path"); @@ -88,7 +88,7 @@ public void AssertErrorLoggedWhenResolverThrows() SdkReference sdk = new SdkReference("1sdkName", "version1", "minimumVersion"); - var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath"); + var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false); result.Path.ShouldBe("resolverpath1"); _logger.Warnings.Select(i => i.Message).ShouldBe(new [] { "The SDK resolver \"MockSdkResolverThrows\" failed to run. EXMESSAGE" }); @@ -101,7 +101,7 @@ public void AssertFirstResolverCanResolve() SdkReference sdk = new SdkReference("1sdkName", "referencedVersion", "minimumVersion"); - var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath"); + var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false); result.Path.ShouldBe("resolverpath1"); _logger.BuildMessageEvents.Select(i => i.Message).ShouldContain("MockSdkResolver1 running"); @@ -116,7 +116,7 @@ public void AssertFirstResolverErrorsSupressedWhenResolved() // be logged because MockSdkResolver2 will succeed. SdkReference sdk = new SdkReference("2sdkName", "version2", "minimumVersion"); - var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath"); + var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false); result.Path.ShouldBe("resolverpath2"); @@ -139,10 +139,10 @@ public void AssertResolverHasStatePreserved() SdkReference sdk = new SdkReference("othersdk", "1.0", "minimumVersion"); // First call should not know state - SdkResolverService.Instance.ResolveSdk(submissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath").Path.ShouldBe("resolverpath"); + SdkResolverService.Instance.ResolveSdk(submissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false).Path.ShouldBe("resolverpath"); // Second call should have received state - SdkResolverService.Instance.ResolveSdk(submissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath").Path.ShouldBe(MockSdkResolverWithState.Expected); + SdkResolverService.Instance.ResolveSdk(submissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false).Path.ShouldBe(MockSdkResolverWithState.Expected); } [Fact] @@ -155,10 +155,10 @@ public void AssertResolverStateNotPreserved() SdkReference sdk = new SdkReference("othersdk", "1.0", "minimumVersion"); // First call should not know state - SdkResolverService.Instance.ResolveSdk(submissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath").Path.ShouldBe("resolverpath"); + SdkResolverService.Instance.ResolveSdk(submissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false).Path.ShouldBe("resolverpath"); // Second call should have received state - SdkResolverService.Instance.ResolveSdk(submissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath").Path.ShouldBe("resolverpath"); + SdkResolverService.Instance.ResolveSdk(submissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false).Path.ShouldBe("resolverpath"); } [Theory] @@ -199,13 +199,13 @@ public void CachingWrapperShouldWarnWhenMultipleVersionsAreReferenced() resolver }); - var result = service.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath"); + var result = service.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false); resolver.ResolvedCalls.Count.ShouldBe(1); result.Path.ShouldBe("path"); result.Version.ShouldBe("1.0.0"); _logger.WarningCount.ShouldBe(0); - result = service.ResolveSdk(BuildEventContext.InvalidSubmissionId, new SdkReference("foo", "2.0.0", null), _loggingContext, new MockElementLocation("file"), "sln", "projectPath"); + result = service.ResolveSdk(BuildEventContext.InvalidSubmissionId, new SdkReference("foo", "2.0.0", null), _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false); resolver.ResolvedCalls.Count.ShouldBe(1); result.Path.ShouldBe("path"); result.Version.ShouldBe("1.0.0"); @@ -216,6 +216,38 @@ public void CachingWrapperShouldWarnWhenMultipleVersionsAreReferenced() resolver.ResolvedCalls.Count.ShouldBe(1); } + [Fact] + public void InteractiveIsSetForResolverContext() + { + // Start with interactive false + bool interactive = false; + + var service = new CachingSdkResolverService(); + + service.InitializeForTests( + resolvers: new List + { + new SdkUtilities.ConfigurableMockSdkResolver((sdkRference, resolverContext, factory) => + { + interactive = resolverContext.Interactive; + + return null; + }) + }); + + service.ResolveSdk( + BuildEventContext.InvalidSubmissionId, + new SdkReference("foo", "1.0.0", null), + _loggingContext, + new MockElementLocation("file"), + "sln", + "projectPath", + // Pass along interactive and expect it to be received in the SdkResolverContext + interactive: true); + + interactive.ShouldBeTrue(); + } + private class MockLoaderStrategy : SdkResolverLoader { private readonly bool _includeErrorResolver; diff --git a/src/Build.UnitTests/InternalEngineHelpers.cs b/src/Build.UnitTests/InternalEngineHelpers.cs index a52318c2775..74717d25628 100644 --- a/src/Build.UnitTests/InternalEngineHelpers.cs +++ b/src/Build.UnitTests/InternalEngineHelpers.cs @@ -35,6 +35,7 @@ public static ProjectOptions CreateProjectOptionsWithResolver(SdkResolver resolv internal class ConfigurableMockSdkResolver : SdkResolver { private readonly Dictionary _resultMap; + private readonly Func _resolveFunc; public ConcurrentDictionary ResolvedCalls { get; } = new ConcurrentDictionary(); @@ -48,18 +49,30 @@ public ConfigurableMockSdkResolver(Dictionary resultMap) _resultMap = resultMap; } + public ConfigurableMockSdkResolver(Func resolveFunc) + { + _resolveFunc = resolveFunc; + } + public override string Name => nameof(ConfigurableMockSdkResolver); public override int Priority => int.MaxValue; public override Framework.SdkResult Resolve(SdkReference sdkReference, SdkResolverContext resolverContext, SdkResultFactory factory) { + if (_resolveFunc != null) + { + return _resolveFunc(sdkReference, resolverContext, factory); + } + ResolvedCalls.AddOrUpdate(sdkReference.Name, k => 1, (k, c) => c + 1); return _resultMap.TryGetValue(sdkReference.Name, out var result) ? new SdkResult(sdkReference, result.Path, result.Version, null) : null; } + + } internal class FileBasedMockSdkResolver : SdkResolver diff --git a/src/Build/BackEnd/Components/SdkResolution/CachingSdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/CachingSdkResolverService.cs index 778a5574c0e..5716804136e 100644 --- a/src/Build/BackEnd/Components/SdkResolution/CachingSdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/CachingSdkResolverService.cs @@ -33,13 +33,13 @@ public override void ClearCaches() _cache.Clear(); } - public override SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) + public override SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive) { SdkResult result; if (Traits.Instance.EscapeHatches.DisableSdkResolutionCache) { - result = base.ResolveSdk(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath); + result = base.ResolveSdk(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath, interactive); } else { @@ -53,7 +53,7 @@ public override SdkResult ResolveSdk(int submissionId, SdkReference sdk, Logging */ result = cached.GetOrAdd( sdk.Name, - key => base.ResolveSdk(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath)); + key => base.ResolveSdk(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath, interactive)); } if (result != null && diff --git a/src/Build/BackEnd/Components/SdkResolution/HostedSdkResolverServiceBase.cs b/src/Build/BackEnd/Components/SdkResolution/HostedSdkResolverServiceBase.cs index 28239d074b6..ee567903f54 100644 --- a/src/Build/BackEnd/Components/SdkResolution/HostedSdkResolverServiceBase.cs +++ b/src/Build/BackEnd/Components/SdkResolution/HostedSdkResolverServiceBase.cs @@ -47,7 +47,7 @@ public virtual void InitializeComponent(IBuildComponentHost host) public abstract void PacketReceived(int node, INodePacket packet); /// - public abstract SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath); + public abstract SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive); /// public virtual void ShutdownComponent() diff --git a/src/Build/BackEnd/Components/SdkResolution/ISdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/ISdkResolverService.cs index abdc64bcb03..b36a25189e2 100644 --- a/src/Build/BackEnd/Components/SdkResolution/ISdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/ISdkResolverService.cs @@ -38,7 +38,8 @@ internal interface ISdkResolverService /// The of the element which referenced the SDK. /// The full path to the solution file, if any, that is resolving the SDK. /// The full path to the project file that is resolving the SDK. + /// Indicates whether or not the resolver is allowed to be interactive. /// An containing information about the resolved SDK. If no resolver was able to resolve it, then == false. - SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath); + SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive); } } diff --git a/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs index 7d278b687f2..c4457ffd3ed 100644 --- a/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs @@ -81,14 +81,14 @@ public override void PacketReceived(int node, INodePacket packet) } /// - public override SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) + public override SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive) { ErrorUtilities.VerifyThrowInternalNull(sdk, nameof(sdk)); ErrorUtilities.VerifyThrowInternalNull(loggingContext, nameof(loggingContext)); ErrorUtilities.VerifyThrowInternalNull(sdkReferenceLocation, nameof(sdkReferenceLocation)); ErrorUtilities.VerifyThrowInternalLength(projectPath, nameof(projectPath)); - return _cachedSdkResolver.ResolveSdk(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath); + return _cachedSdkResolver.ResolveSdk(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath, interactive); } /// @@ -155,7 +155,7 @@ private void ProcessRequests() ILoggingService loggingService = Host.GetComponent(BuildComponentType.LoggingService) as ILoggingService; // This call is usually cached so is very fast but can take longer for a new SDK that is downloaded. Other queued threads for different SDKs will complete sooner and continue on which unblocks evaluations - response = ResolveSdk(request.SubmissionId, sdkReference, new EvaluationLoggingContext(loggingService, request.BuildEventContext, request.ProjectPath), request.ElementLocation, request.SolutionPath, request.ProjectPath); + response = ResolveSdk(request.SubmissionId, sdkReference, new EvaluationLoggingContext(loggingService, request.BuildEventContext, request.ProjectPath), request.ElementLocation, request.SolutionPath, request.ProjectPath, request.Interactive); } catch (Exception e) { diff --git a/src/Build/BackEnd/Components/SdkResolution/OutOfProcNodeSdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/OutOfProcNodeSdkResolverService.cs index 00f54cb830d..36c1f8d2696 100644 --- a/src/Build/BackEnd/Components/SdkResolution/OutOfProcNodeSdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/OutOfProcNodeSdkResolverService.cs @@ -61,14 +61,14 @@ public override void PacketReceived(int node, INodePacket packet) } /// - public override SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) + public override SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive) { // Get a cached response if possible, otherwise send the request var sdkResult = _responseCache.GetOrAdd( sdk.Name, key => { - var result = RequestSdkPathFromMainNode(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath); + var result = RequestSdkPathFromMainNode(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath, interactive); return new SdkResult(null, result.Path, result.Version, null); }); @@ -103,13 +103,13 @@ private void HandleResponse(SdkResult response) _responseReceivedEvent.Set(); } - private SdkResult RequestSdkPathFromMainNode(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) + private SdkResult RequestSdkPathFromMainNode(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive) { // Clear out the last response for good measure _lastResponse = null; // Create the SdkResolverRequest packet to send - INodePacket packet = SdkResolverRequest.Create(submissionId, sdk, loggingContext.BuildEventContext, sdkReferenceLocation, solutionPath, projectPath); + INodePacket packet = SdkResolverRequest.Create(submissionId, sdk, loggingContext.BuildEventContext, sdkReferenceLocation, solutionPath, projectPath, interactive); SendPacket(packet); diff --git a/src/Build/BackEnd/Components/SdkResolution/SdkResolverContext.cs b/src/Build/BackEnd/Components/SdkResolution/SdkResolverContext.cs index 5c126c583a5..5ed8a6aaf4c 100644 --- a/src/Build/BackEnd/Components/SdkResolution/SdkResolverContext.cs +++ b/src/Build/BackEnd/Components/SdkResolution/SdkResolverContext.cs @@ -12,12 +12,13 @@ namespace Microsoft.Build.BackEnd.SdkResolution /// internal sealed class SdkResolverContext : SdkResolverContextBase { - public SdkResolverContext(Framework.SdkLogger logger, string projectFilePath, string solutionPath, Version msBuildVersion) + public SdkResolverContext(Framework.SdkLogger logger, string projectFilePath, string solutionPath, Version msBuildVersion, bool interactive) { Logger = logger; ProjectFilePath = projectFilePath; SolutionFilePath = solutionPath; MSBuildVersion = msBuildVersion; + Interactive = interactive; } } } diff --git a/src/Build/BackEnd/Components/SdkResolution/SdkResolverRequest.cs b/src/Build/BackEnd/Components/SdkResolution/SdkResolverRequest.cs index 54a7270555f..db038420881 100644 --- a/src/Build/BackEnd/Components/SdkResolution/SdkResolverRequest.cs +++ b/src/Build/BackEnd/Components/SdkResolution/SdkResolverRequest.cs @@ -20,13 +20,14 @@ internal sealed class SdkResolverRequest : INodePacket private string _solutionPath; private int _submissionId; private string _version; + private bool _interactive; public SdkResolverRequest(INodePacketTranslator translator) { Translate(translator); } - private SdkResolverRequest(int submissionId, string name, string version, string minimumVersion, BuildEventContext buildEventContext, ElementLocation elementLocation, string solutionPath, string projectPath) + private SdkResolverRequest(int submissionId, string name, string version, string minimumVersion, BuildEventContext buildEventContext, ElementLocation elementLocation, string solutionPath, string projectPath, bool interactive) { _buildEventContext = buildEventContext; _submissionId = submissionId; @@ -36,12 +37,15 @@ private SdkResolverRequest(int submissionId, string name, string version, string _projectPath = projectPath; _solutionPath = solutionPath; _version = version; + _interactive = interactive; } public BuildEventContext BuildEventContext => _buildEventContext; public ElementLocation ElementLocation => _elementLocation; + public bool Interactive => _interactive; + public string MinimumVersion => _minimumVersion; public string Name => _name; @@ -58,9 +62,9 @@ private SdkResolverRequest(int submissionId, string name, string version, string public string Version => _version; - public static SdkResolverRequest Create(int submissionId, SdkReference sdkReference, BuildEventContext buildEventContext, ElementLocation elementLocation, string solutionPath, string projectPath) + public static SdkResolverRequest Create(int submissionId, SdkReference sdkReference, BuildEventContext buildEventContext, ElementLocation elementLocation, string solutionPath, string projectPath, bool interactive) { - return new SdkResolverRequest(submissionId, sdkReference.Name, sdkReference.Version, sdkReference.MinimumVersion, buildEventContext, elementLocation, solutionPath, projectPath); + return new SdkResolverRequest(submissionId, sdkReference.Name, sdkReference.Version, sdkReference.MinimumVersion, buildEventContext, elementLocation, solutionPath, projectPath, interactive); } public static INodePacket FactoryForDeserialization(INodePacketTranslator translator) @@ -78,6 +82,7 @@ public void Translate(INodePacketTranslator translator) translator.Translate(ref _solutionPath); translator.Translate(ref _submissionId); translator.Translate(ref _version); + translator.Translate(ref _interactive); } } } diff --git a/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs index c0426eed607..158555f4f41 100644 --- a/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs @@ -87,7 +87,7 @@ public virtual void ClearCaches() } /// - public virtual SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) + public virtual SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive) { // Lazy initialize the SDK resolvers if (_resolvers == null) @@ -104,7 +104,7 @@ public virtual SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingC foreach (SdkResolver sdkResolver in _resolvers) { - SdkResolverContext context = new SdkResolverContext(buildEngineLogger, projectPath, solutionPath, ProjectCollection.Version) + SdkResolverContext context = new SdkResolverContext(buildEngineLogger, projectPath, solutionPath, ProjectCollection.Version, interactive) { State = GetResolverState(submissionId, sdkResolver) }; diff --git a/src/Build/Evaluation/Evaluator.cs b/src/Build/Evaluation/Evaluator.cs index 99a221f887f..1e023335b28 100644 --- a/src/Build/Evaluation/Evaluator.cs +++ b/src/Build/Evaluation/Evaluator.cs @@ -2131,8 +2131,12 @@ private void ExpandAndLoadImportsFromUnescapedImportExpressionConditioned( if (solutionPath == "*Undefined*") solutionPath = null; var projectPath = _data.GetProperty(ReservedPropertyNames.projectFullPath)?.EvaluatedValue; + // We currently only support the global property "NuGetInteractive" to allow SDK resolvers to be interactive. + // In the future we should add an /interactive command-line argument and pipe that through to here instead. + var interactive = String.Equals("true", _data.GetProperty("NuGetInteractive")?.EvaluatedValue, StringComparison.OrdinalIgnoreCase); + // Combine SDK path with the "project" relative path - sdkResult = _sdkResolverService.ResolveSdk(_submissionId, importElement.ParsedSdkReference, _evaluationLoggingContext, importElement.Location, solutionPath, projectPath); + sdkResult = _sdkResolverService.ResolveSdk(_submissionId, importElement.ParsedSdkReference, _evaluationLoggingContext, importElement.Location, solutionPath, projectPath, interactive); if (!sdkResult.Success) { diff --git a/src/Framework/Sdk/SdkResolverContext.cs b/src/Framework/Sdk/SdkResolverContext.cs index 87987056c5b..1cb1260c30d 100644 --- a/src/Framework/Sdk/SdkResolverContext.cs +++ b/src/Framework/Sdk/SdkResolverContext.cs @@ -10,6 +10,11 @@ namespace Microsoft.Build.Framework /// public abstract class SdkResolverContext { + /// + /// Gets a value indicating if the resolver is allowed to be interactive. + /// + public virtual bool Interactive { get; protected set; } + /// /// Logger to log real-time messages back to MSBuild. ///