Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ protected SdkResolver() { }
public abstract partial class SdkResolverContext
{
protected SdkResolverContext() { }
public virtual System.Collections.Generic.IReadOnlyDictionary<string, string> 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 { } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ protected SdkResolver() { }
public abstract partial class SdkResolverContext
{
protected SdkResolverContext() { }
public virtual System.Collections.Generic.IReadOnlyDictionary<string, string> 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 { } }
Expand Down
3 changes: 2 additions & 1 deletion src/Build.UnitTests/BackEnd/MockSdkResolverService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Build.Construction;
using Microsoft.Build.Framework;
using System;
using System.Collections.Generic;

namespace Microsoft.Build.Engine.UnitTests.BackEnd
{
Expand All @@ -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<string, string> globalProperties)
{
return null;
}
Expand Down
58 changes: 47 additions & 11 deletions src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string>());

result.Success.ShouldBeFalse();
result.ShouldNotBeNull();
Expand Down Expand Up @@ -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<string, string>());

result.Path.ShouldBe("path");

Expand All @@ -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<string, string>());

result.Path.ShouldBe("resolverpath1");
_logger.Warnings.Select(i => i.Message).ShouldBe(new [] { "The SDK resolver \"MockSdkResolverThrows\" failed to run. EXMESSAGE" });
Expand All @@ -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<string, string>());

result.Path.ShouldBe("resolverpath1");
_logger.BuildMessageEvents.Select(i => i.Message).ShouldContain("MockSdkResolver1 running");
Expand All @@ -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<string, string>());

result.Path.ShouldBe("resolverpath2");

Expand All @@ -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<string, string>()).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<string, string>()).Path.ShouldBe(MockSdkResolverWithState.Expected);
}

[Fact]
Expand All @@ -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<string, string>()).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<string, string>()).Path.ShouldBe("resolverpath");
}

[Theory]
Expand Down Expand Up @@ -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<string, string>());
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<string, string>());
resolver.ResolvedCalls.Count.ShouldBe(1);
result.Path.ShouldBe("path");
result.Version.ShouldBe("1.0.0");
Expand All @@ -216,6 +216,42 @@ public void CachingWrapperShouldWarnWhenMultipleVersionsAreReferenced()
resolver.ResolvedCalls.Count.ShouldBe(1);
}

[Fact]
public void GlobalPropertiesAreAvailable()
{
Dictionary<string, string> expectedGlobalProperties = new Dictionary<string, string>
{
["Property1"] = "Value1",
["Property2"] = "Value2"
};

Dictionary<string, string> actualGlobalProperties = null;

var service = new CachingSdkResolverService();

service.InitializeForTests(
resolvers: new List <SdkResolver>
{
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;
Expand Down
17 changes: 15 additions & 2 deletions src/Build.UnitTests/InternalEngineHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,21 @@ internal class ConfigurableMockSdkResolver : SdkResolver
{
private readonly Dictionary<string, SdkResult> _resultMap;

private readonly Func<SdkReference, SdkResolverContext, SdkResultFactory, Framework.SdkResult> _resolveFunc;


public ConcurrentDictionary<string, int> ResolvedCalls { get; } = new ConcurrentDictionary<string, int>();

public ConfigurableMockSdkResolver(SdkResult result)
{
_resultMap = new Dictionary<string, SdkResult> { [result.SdkReference.Name] = result };
}

public ConfigurableMockSdkResolver(Func<SdkReference, SdkResolverContext, SdkResultFactory, Framework.SdkResult> resolveFunc)
{
_resolveFunc = resolveFunc;
}

public ConfigurableMockSdkResolver(Dictionary<string, SdkResult> resultMap)
{
_resultMap = resultMap;
Expand All @@ -54,10 +62,15 @@ public ConfigurableMockSdkResolver(Dictionary<string, SdkResult> 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;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<string, string> 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
{
Expand All @@ -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 &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -47,7 +48,7 @@ public virtual void InitializeComponent(IBuildComponentHost host)
public abstract void PacketReceived(int node, INodePacket packet);

/// <inheritdoc cref="ISdkResolverService.ResolveSdk"/>
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<string, string> globalProperties);

/// <inheritdoc cref="IBuildComponent.ShutdownComponent"/>
public virtual void ShutdownComponent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Build.Construction;
using Microsoft.Build.Framework;
using System;
using System.Collections.Generic;

namespace Microsoft.Build.BackEnd.SdkResolution
{
Expand Down Expand Up @@ -38,7 +39,8 @@ internal interface ISdkResolverService
/// <param name="sdkReferenceLocation">The <see cref="ElementLocation"/> of the element which referenced the SDK.</param>
/// <param name="solutionPath">The full path to the solution file, if any, that is resolving the SDK.</param>
/// <param name="projectPath">The full path to the project file that is resolving the SDK.</param>
/// <param name="globalProperties">The current global properties.</param>
/// <returns>An <see cref="SdkResult"/> containing information about the resolved SDK. If no resolver was able to resolve it, then <see cref="Framework.SdkResult.Success"/> == false. </returns>
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<string, string> globalProperties);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,15 @@ public override void PacketReceived(int node, INodePacket packet)
}

/// <inheritdoc cref="ISdkResolverService.ResolveSdk"/>
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<string, string> globalProperties)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would IReadOnlyDictionary make better sense?

{
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);
}

/// <summary>
Expand Down Expand Up @@ -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)
{
Expand Down
Loading