From d487bef1e0faf0be76c2aa4f2e3291c3c646b3ee Mon Sep 17 00:00:00 2001 From: Jeff Kluge Date: Thu, 16 Aug 2018 11:11:27 -0700 Subject: [PATCH] Add global properties to SdkResolverContext This will allow the NuGet SDK resolver to read the global property `NuGetInteractive` so it can prompt the user. --- .../net/Microsoft.Build.Framework.cs | 1 + .../netstandard/Microsoft.Build.Framework.cs | 1 + .../BackEnd/MockSdkResolverService.cs | 3 +- .../BackEnd/SdkResolverService_Tests.cs | 58 +++++++++++++++---- src/Build.UnitTests/InternalEngineHelpers.cs | 17 +++++- .../CachingSdkResolverService.cs | 7 ++- .../HostedSdkResolverServiceBase.cs | 3 +- .../SdkResolution/ISdkResolverService.cs | 4 +- .../MainNodeSdkResolverService.cs | 7 ++- .../OutOfProcNodeSdkResolverService.cs | 9 +-- .../SdkResolution/SdkResolverContext.cs | 6 +- .../SdkResolution/SdkResolverRequest.cs | 14 ++++- .../SdkResolution/SdkResolverService.cs | 4 +- src/Build/Evaluation/Evaluator.cs | 2 +- src/Framework/Sdk/SdkResolverContext.cs | 3 + 15 files changed, 105 insertions(+), 34 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..9e0af9e408f 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 System.Collections.Generic.IReadOnlyDictionary GlobalProperties { [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..7ffdc6221bc 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 System.Collections.Generic.IReadOnlyDictionary GlobalProperties { [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..3622a7f6d40 100644 --- a/src/Build.UnitTests/BackEnd/MockSdkResolverService.cs +++ b/src/Build.UnitTests/BackEnd/MockSdkResolverService.cs @@ -4,6 +4,7 @@ using Microsoft.Build.Construction; using Microsoft.Build.Framework; using System; +using System.Collections.Generic; namespace Microsoft.Build.Engine.UnitTests.BackEnd { @@ -19,7 +20,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, IDictionary globalProperties) { return null; } diff --git a/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs b/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs index 29737ab5b77..c92f7d874ec 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", new Dictionary()); 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", new Dictionary()); 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", new Dictionary()); 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", new Dictionary()); 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", new Dictionary()); 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", new Dictionary()).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", new Dictionary()).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", new Dictionary()).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", new Dictionary()).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", new Dictionary()); 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", new Dictionary()); resolver.ResolvedCalls.Count.ShouldBe(1); result.Path.ShouldBe("path"); result.Version.ShouldBe("1.0.0"); @@ -216,6 +216,42 @@ public void CachingWrapperShouldWarnWhenMultipleVersionsAreReferenced() resolver.ResolvedCalls.Count.ShouldBe(1); } + [Fact] + public void GlobalPropertiesAreAvailable() + { + Dictionary expectedGlobalProperties = new Dictionary + { + ["Property1"] = "Value1", + ["Property2"] = "Value2" + }; + + Dictionary actualGlobalProperties = null; + + var service = new CachingSdkResolverService(); + + service.InitializeForTests( + resolvers: new List + { + new SdkUtilities.ConfigurableMockSdkResolver((sdkRference, resolverContext, factory) => + { + actualGlobalProperties = resolverContext.GlobalProperties.ToDictionary(i => i.Key, i => i.Value); + + return null; + }) + }); + + service.ResolveSdk( + BuildEventContext.InvalidSubmissionId, + new SdkReference("foo", "1.0.0", null), + _loggingContext, + new MockElementLocation("file"), + "sln", + "projectPath", + expectedGlobalProperties); + + actualGlobalProperties.ShouldBe(expectedGlobalProperties); + } + private class MockLoaderStrategy : SdkResolverLoader { private readonly bool _includeErrorResolver; diff --git a/src/Build.UnitTests/InternalEngineHelpers.cs b/src/Build.UnitTests/InternalEngineHelpers.cs index a52318c2775..ac361d16b88 100644 --- a/src/Build.UnitTests/InternalEngineHelpers.cs +++ b/src/Build.UnitTests/InternalEngineHelpers.cs @@ -36,6 +36,9 @@ internal class ConfigurableMockSdkResolver : SdkResolver { private readonly Dictionary _resultMap; + private readonly Func _resolveFunc; + + public ConcurrentDictionary ResolvedCalls { get; } = new ConcurrentDictionary(); public ConfigurableMockSdkResolver(SdkResult result) @@ -43,6 +46,11 @@ public ConfigurableMockSdkResolver(SdkResult result) _resultMap = new Dictionary { [result.SdkReference.Name] = result }; } + public ConfigurableMockSdkResolver(Func resolveFunc) + { + _resolveFunc = resolveFunc; + } + public ConfigurableMockSdkResolver(Dictionary resultMap) { _resultMap = resultMap; @@ -54,10 +62,15 @@ public ConfigurableMockSdkResolver(Dictionary resultMap) 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) + return _resultMap.TryGetValue(sdkReference.Name, out var result1) + ? new SdkResult(sdkReference, result1.Path, result1.Version, null) : null; } } diff --git a/src/Build/BackEnd/Components/SdkResolution/CachingSdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/CachingSdkResolverService.cs index 778a5574c0e..47f1d656f0e 100644 --- a/src/Build/BackEnd/Components/SdkResolution/CachingSdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/CachingSdkResolverService.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Concurrent; +using System.Collections.Generic; using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.Collections; using Microsoft.Build.Construction; @@ -33,13 +34,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, IDictionary globalProperties) { 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, globalProperties); } else { @@ -53,7 +54,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, globalProperties)); } if (result != null && diff --git a/src/Build/BackEnd/Components/SdkResolution/HostedSdkResolverServiceBase.cs b/src/Build/BackEnd/Components/SdkResolution/HostedSdkResolverServiceBase.cs index 28239d074b6..cb43bbf3798 100644 --- a/src/Build/BackEnd/Components/SdkResolution/HostedSdkResolverServiceBase.cs +++ b/src/Build/BackEnd/Components/SdkResolution/HostedSdkResolverServiceBase.cs @@ -5,6 +5,7 @@ using Microsoft.Build.Construction; using Microsoft.Build.Framework; using System; +using System.Collections.Generic; using System.Threading; namespace Microsoft.Build.BackEnd.SdkResolution @@ -47,7 +48,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, IDictionary globalProperties); /// public virtual void ShutdownComponent() diff --git a/src/Build/BackEnd/Components/SdkResolution/ISdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/ISdkResolverService.cs index abdc64bcb03..1b1e30bd1dc 100644 --- a/src/Build/BackEnd/Components/SdkResolution/ISdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/ISdkResolverService.cs @@ -5,6 +5,7 @@ using Microsoft.Build.Construction; using Microsoft.Build.Framework; using System; +using System.Collections.Generic; namespace Microsoft.Build.BackEnd.SdkResolution { @@ -38,7 +39,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. + /// The current global properties. /// 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, IDictionary globalProperties); } } diff --git a/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs index 7d278b687f2..cdccd2c5dcb 100644 --- a/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs @@ -81,14 +81,15 @@ 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, IDictionary globalProperties) { ErrorUtilities.VerifyThrowInternalNull(sdk, nameof(sdk)); ErrorUtilities.VerifyThrowInternalNull(loggingContext, nameof(loggingContext)); ErrorUtilities.VerifyThrowInternalNull(sdkReferenceLocation, nameof(sdkReferenceLocation)); ErrorUtilities.VerifyThrowInternalLength(projectPath, nameof(projectPath)); + ErrorUtilities.VerifyThrowInternalNull(globalProperties, nameof(globalProperties)); - return _cachedSdkResolver.ResolveSdk(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath); + return _cachedSdkResolver.ResolveSdk(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath, globalProperties); } /// @@ -155,7 +156,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.GlobalProperties); } catch (Exception e) { diff --git a/src/Build/BackEnd/Components/SdkResolution/OutOfProcNodeSdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/OutOfProcNodeSdkResolverService.cs index 00f54cb830d..d45acb4a7e6 100644 --- a/src/Build/BackEnd/Components/SdkResolution/OutOfProcNodeSdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/OutOfProcNodeSdkResolverService.cs @@ -8,6 +8,7 @@ using Microsoft.Build.Shared; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Threading; namespace Microsoft.Build.BackEnd.SdkResolution @@ -61,14 +62,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, IDictionary globalProperties) { // 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, globalProperties); return new SdkResult(null, result.Path, result.Version, null); }); @@ -103,13 +104,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, IDictionary globalProperties) { // 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, globalProperties); SendPacket(packet); diff --git a/src/Build/BackEnd/Components/SdkResolution/SdkResolverContext.cs b/src/Build/BackEnd/Components/SdkResolution/SdkResolverContext.cs index 5c126c583a5..cfe3a982966 100644 --- a/src/Build/BackEnd/Components/SdkResolution/SdkResolverContext.cs +++ b/src/Build/BackEnd/Components/SdkResolution/SdkResolverContext.cs @@ -2,7 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; - +using System.Collections.Generic; +using System.Collections.ObjectModel; using SdkResolverContextBase = Microsoft.Build.Framework.SdkResolverContext; namespace Microsoft.Build.BackEnd.SdkResolution @@ -12,12 +13,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, IDictionary globalProperties) { Logger = logger; ProjectFilePath = projectFilePath; SolutionFilePath = solutionPath; MSBuildVersion = msBuildVersion; + GlobalProperties = new ReadOnlyDictionary(globalProperties); } } } diff --git a/src/Build/BackEnd/Components/SdkResolution/SdkResolverRequest.cs b/src/Build/BackEnd/Components/SdkResolution/SdkResolverRequest.cs index 54a7270555f..ded92f35c5e 100644 --- a/src/Build/BackEnd/Components/SdkResolution/SdkResolverRequest.cs +++ b/src/Build/BackEnd/Components/SdkResolution/SdkResolverRequest.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; +using System.Collections.Generic; using Microsoft.Build.Construction; using Microsoft.Build.Framework; @@ -20,13 +22,14 @@ internal sealed class SdkResolverRequest : INodePacket private string _solutionPath; private int _submissionId; private string _version; + private IDictionary _globalProperties; 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, IDictionary globalProperties) { _buildEventContext = buildEventContext; _submissionId = submissionId; @@ -36,12 +39,16 @@ private SdkResolverRequest(int submissionId, string name, string version, string _projectPath = projectPath; _solutionPath = solutionPath; _version = version; + _globalProperties = globalProperties; + } public BuildEventContext BuildEventContext => _buildEventContext; public ElementLocation ElementLocation => _elementLocation; + public IDictionary GlobalProperties => _globalProperties; + public string MinimumVersion => _minimumVersion; public string Name => _name; @@ -58,9 +65,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, IDictionary globalProperties) { - 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, globalProperties); } public static INodePacket FactoryForDeserialization(INodePacketTranslator translator) @@ -78,6 +85,7 @@ public void Translate(INodePacketTranslator translator) translator.Translate(ref _solutionPath); translator.Translate(ref _submissionId); translator.Translate(ref _version); + translator.TranslateDictionary(ref _globalProperties, capacity => new Dictionary(capacity, StringComparer.OrdinalIgnoreCase)); } } } diff --git a/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs index c0426eed607..a290c46f837 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, IDictionary globalProperties) { // 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, globalProperties) { State = GetResolverState(submissionId, sdkResolver) }; diff --git a/src/Build/Evaluation/Evaluator.cs b/src/Build/Evaluation/Evaluator.cs index 99a221f887f..79e8c38ac68 100644 --- a/src/Build/Evaluation/Evaluator.cs +++ b/src/Build/Evaluation/Evaluator.cs @@ -2132,7 +2132,7 @@ private void ExpandAndLoadImportsFromUnescapedImportExpressionConditioned( var projectPath = _data.GetProperty(ReservedPropertyNames.projectFullPath)?.EvaluatedValue; // 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, _data.GlobalPropertiesDictionary.ToDictionary()); if (!sdkResult.Success) { diff --git a/src/Framework/Sdk/SdkResolverContext.cs b/src/Framework/Sdk/SdkResolverContext.cs index 87987056c5b..f81487a1de7 100644 --- a/src/Framework/Sdk/SdkResolverContext.cs +++ b/src/Framework/Sdk/SdkResolverContext.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; namespace Microsoft.Build.Framework { @@ -10,6 +11,8 @@ namespace Microsoft.Build.Framework /// public abstract class SdkResolverContext { + public virtual IReadOnlyDictionary GlobalProperties { get; protected set; } + /// /// Logger to log real-time messages back to MSBuild. ///