Skip to content

Commit

Permalink
Remove extra layers of abstractions from IVsProjectAdapter, move Runt…
Browse files Browse the repository at this point in the history
…imeGraph specific methods from VSProject to LegacyPackageReferenceProject (#4732)
  • Loading branch information
nkolev92 authored Jul 22, 2022
1 parent c3760bb commit a3d3b5c
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,11 @@ private async Task<PackageSpec> GetPackageSpecAsync(ISettings settings)
AssetTargetFallbackUtility.ApplyFramework(projectTfi, packageTargetFallback, assetTargetFallback);

// Build up runtime information.
var runtimes = await _vsProjectAdapter.GetRuntimeIdentifiersAsync();
var supports = await _vsProjectAdapter.GetRuntimeSupportsAsync();

var runtimes = GetRuntimeIdentifiers(
GetPropertySafe(_vsProjectAdapter.BuildProperties, ProjectBuildProperties.RuntimeIdentifier),
GetPropertySafe(_vsProjectAdapter.BuildProperties, ProjectBuildProperties.RuntimeIdentifiers));
var supports = GetRuntimeSupports(GetPropertySafe(_vsProjectAdapter.BuildProperties, ProjectBuildProperties.RuntimeSupports));
var runtimeGraph = new RuntimeGraph(runtimes, supports);

// In legacy CSProj, we only have one target framework per project
Expand Down Expand Up @@ -446,6 +449,43 @@ private async Task<PackageSpec> GetPackageSpecAsync(ISettings settings)
};
}

internal static IEnumerable<RuntimeDescription> GetRuntimeIdentifiers(string unparsedRuntimeIdentifer, string unparsedRuntimeIdentifers)
{
var runtimes = Enumerable.Empty<string>();

if (unparsedRuntimeIdentifer != null)
{
runtimes = runtimes.Concat(new[] { unparsedRuntimeIdentifer });
}

if (unparsedRuntimeIdentifers != null)
{
runtimes = runtimes.Concat(unparsedRuntimeIdentifers.Split(';'));
}

runtimes = runtimes
.Select(x => x.Trim())
.Distinct(StringComparer.Ordinal)
.Where(x => !string.IsNullOrEmpty(x));

return runtimes
.Select(runtime => new RuntimeDescription(runtime));
}

internal static IEnumerable<CompatibilityProfile> GetRuntimeSupports(string unparsedRuntimeSupports)
{
if (unparsedRuntimeSupports == null)
{
return Enumerable.Empty<CompatibilityProfile>();
}

return unparsedRuntimeSupports
.Split(';')
.Select(x => x.Trim())
.Where(x => !string.IsNullOrEmpty(x))
.Select(support => new CompatibilityProfile(support));
}

/// <inheritdoc/>
protected override Task<PackageSpec> GetPackageSpecAsync(CancellationToken ct)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,55 +188,6 @@ public async Task<IEnumerable<string>> GetReferencedProjectsAsync()
return Enumerable.Empty<string>();
}

public async Task<IEnumerable<RuntimeDescription>> GetRuntimeIdentifiersAsync()
{
await _threadingService.JoinableTaskFactory.SwitchToMainThreadAsync();

var unparsedRuntimeIdentifer = BuildProperties.GetPropertyValue(
ProjectBuildProperties.RuntimeIdentifier);
var unparsedRuntimeIdentifers = BuildProperties.GetPropertyValue(
ProjectBuildProperties.RuntimeIdentifiers);

var runtimes = Enumerable.Empty<string>();

if (unparsedRuntimeIdentifer != null)
{
runtimes = runtimes.Concat(new[] { unparsedRuntimeIdentifer });
}

if (unparsedRuntimeIdentifers != null)
{
runtimes = runtimes.Concat(unparsedRuntimeIdentifers.Split(';'));
}

runtimes = runtimes
.Select(x => x.Trim())
.Distinct(StringComparer.Ordinal)
.Where(x => !string.IsNullOrEmpty(x));

return runtimes
.Select(runtime => new RuntimeDescription(runtime));
}

public async Task<IEnumerable<CompatibilityProfile>> GetRuntimeSupportsAsync()
{
await _threadingService.JoinableTaskFactory.SwitchToMainThreadAsync();

var unparsedRuntimeSupports = BuildProperties.GetPropertyValue(
ProjectBuildProperties.RuntimeSupports);

if (unparsedRuntimeSupports == null)
{
return Enumerable.Empty<CompatibilityProfile>();
}

return unparsedRuntimeSupports
.Split(';')
.Select(x => x.Trim())
.Where(x => !string.IsNullOrEmpty(x))
.Select(support => new CompatibilityProfile(support));
}

public async Task<NuGetFramework> GetTargetFrameworkAsync()
{
var frameworkString = await GetTargetFrameworkStringAsync();
Expand All @@ -249,16 +200,6 @@ public async Task<NuGetFramework> GetTargetFrameworkAsync()
return NuGetFramework.UnsupportedFramework;
}

public Task<string> GetPropertyValueAsync(string propertyName)
{
if (propertyName == null)
{
throw new ArgumentNullException(nameof(propertyName));
}

return BuildProperties.GetPropertyValueAsync(propertyName);
}

public async Task<IEnumerable<(string ItemId, string[] ItemMetadata)>> GetBuildItemInformationAsync(string itemName, params string[] metadataNames)
{
if (itemName == null)
Expand Down
10 changes: 0 additions & 10 deletions src/NuGet.Clients/NuGet.VisualStudio.Common/IVsProjectAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,6 @@ public interface IVsProjectAdapter

Task<IEnumerable<string>> GetReferencedProjectsAsync();

/// <summary>
/// Project's runtime identifiers. Should never be null but can be an empty sequence.
/// </summary>
Task<IEnumerable<RuntimeDescription>> GetRuntimeIdentifiersAsync();

/// <summary>
/// Project's supports (a.k.a guardrails). Should never be null but can be an empty sequence.
/// </summary>
Task<IEnumerable<CompatibilityProfile>> GetRuntimeSupportsAsync();

/// <summary>
/// Project's target framework
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,6 @@ internal static Mock<IVsProjectAdapter> CreateProjectAdapter(Mock<IProjectBuildP
.SetupGet(x => x.ProjectName)
.Returns("TestProject");

projectAdapter
.Setup(x => x.GetRuntimeIdentifiersAsync())
.ReturnsAsync(Enumerable.Empty<RuntimeDescription>);

projectAdapter
.Setup(x => x.GetRuntimeSupportsAsync())
.ReturnsAsync(Enumerable.Empty<CompatibilityProfile>);

projectAdapter
.Setup(x => x.Version)
.Returns("1.0.0");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,6 @@ public async Task GetPackageSpecsAsync_WithDefaultVersion_Succeeds()
.VerifyGet(x => x.Version, Times.AtLeastOnce);
Mock.Get(projectAdapter)
.VerifyGet(x => x.ProjectName, Times.AtLeastOnce);
Mock.Get(projectAdapter)
.Verify(x => x.GetRuntimeIdentifiersAsync(), Times.AtLeastOnce);
Mock.Get(projectAdapter)
.Verify(x => x.GetRuntimeSupportsAsync(), Times.AtLeastOnce);
Mock.Get(projectAdapter)
.VerifyGet(x => x.FullProjectPath, Times.AtLeastOnce);
Mock.Get(projectAdapter)
Expand Down Expand Up @@ -1457,6 +1453,83 @@ await SimpleTestPackageUtility.CreateFullPackageAsync(
}
}

[Theory]
[InlineData(null,null,null, 0, 0)]
[InlineData("win-x64", null, null, 1, 0)]
[InlineData("win-x64", "win-x86", null, 2, 0)]
[InlineData("win-x64", "win-x86;win-x64", null, 2, 0)]
[InlineData("win-x64", "win-x86;win-x64", "win", 2, 1)]
public async Task GetPackageSpecsAsync_WithRuntimeIdentifiers_GeneratesRuntimeGraph(string runtimeIdentifier, string runtimeIdentifiers, string runtimeSupports, int runtimeCount, int supportsCount)
{
await NuGetUIThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
// Arrange
using (var testDirectory = TestDirectory.Create())
{
var projectBuildProperties = new Mock<IProjectBuildProperties>();
var projectAdapter = CreateProjectAdapter(testDirectory, projectBuildProperties);

projectBuildProperties
.Setup(x => x.GetPropertyValue(It.Is<string>(x => x.Equals(ProjectBuildProperties.RuntimeIdentifier))))
.Returns(runtimeIdentifier);

projectBuildProperties
.Setup(x => x.GetPropertyValue(It.Is<string>(x => x.Equals(ProjectBuildProperties.RuntimeIdentifiers))))
.Returns(runtimeIdentifiers);

projectBuildProperties
.Setup(x => x.GetPropertyValue(It.Is<string>(x => x.Equals(ProjectBuildProperties.RuntimeSupports))))
.Returns(runtimeSupports);

var projectServices = new TestProjectSystemServices();

var testProject = new LegacyPackageReferenceProject(
projectAdapter,
Guid.NewGuid().ToString(),
projectServices,
_threadingService);

var settings = NullSettings.Instance;
var testDependencyGraphCacheContext = new DependencyGraphCacheContext(NullLogger.Instance, settings);

// Act
var packageSpecs = await testProject.GetPackageSpecsAsync(testDependencyGraphCacheContext);

// Assert
Assert.NotNull(packageSpecs);
var actualRestoreSpec = packageSpecs.Single();
SpecValidationUtility.ValidateProjectSpec(actualRestoreSpec);

// Assert runtime graph
actualRestoreSpec.RuntimeGraph.Runtimes.Count.Should().Be(runtimeCount);
actualRestoreSpec.RuntimeGraph.Supports.Count.Should().Be(supportsCount);

// Verify
projectBuildProperties.VerifyAll();
}
}

[Theory]
[InlineData(null, null, "")]
[InlineData("win-x64", null, "win-x64")]
[InlineData("win-x64", "win-x64", "win-x64")]
[InlineData(null, "win-x64", "win-x64")]
[InlineData("win-x86", "win-x64", "win-x86;win-x64")]
public void GetRuntimeIdentifiers_WithVariousInputs(string runtimeIdentifier, string runtimeIdentifiers, string expected)
{
var actual = LegacyPackageReferenceProject.GetRuntimeIdentifiers(runtimeIdentifier, runtimeIdentifiers);
Assert.Equal(expected, string.Join(";", actual.Select(e => e.RuntimeIdentifier)));
}

[Theory]
[InlineData(null, "")]
[InlineData("net46.app;win8.app", "net46.app;win8.app")]
[InlineData("net46.app;win10.app;net46.app;win10.app", "net46.app;win10.app;net46.app;win10.app")]
public void GetRuntimeSupports_WithVariousInputs(string runtimeSupports, string expected)
{
var actual = LegacyPackageReferenceProject.GetRuntimeSupports(runtimeSupports);
Assert.Equal(expected, string.Join(";", actual.Select(e => e.Name.ToString())));
}

private LegacyPackageReferenceProject CreateLegacyPackageReferenceProject(TestDirectory testDirectory, string range)
{
return ProjectFactories.CreateLegacyPackageReferenceProject(testDirectory, Guid.NewGuid().ToString(), range, _threadingService);
Expand Down

0 comments on commit a3d3b5c

Please sign in to comment.