From 3c469a85beb7af36178e4f34c4a14df51aed5c60 Mon Sep 17 00:00:00 2001 From: Osvaldo Calles Date: Mon, 7 Nov 2022 18:05:22 -0800 Subject: [PATCH 1/3] Add output PackageDependenciesDesignTime to cache assets file - ResolvePackageDependencies only when EmitLegacyAssetsFileItem is true - Removing all the conditions that depend on EmitLegacyAssetsFileItems since there is case when this variable is false. - Get PackageDefinitions from Assets fileA dd output PackageDependenciesDesignTime to cache file - Remove call to task PreprocessPackageDependenciesDesignTime - Use _compileTimeTarget.Name instead of frameworkAlias - Delete PreprocessPackageDependenciesDesignTime task entirely - combine GetPackageDefinitions() with the loop - Add basic unit-tests for PackageDependenciesDesignTime --- src/Tasks/Common/MetadataKeys.cs | 3 + .../GivenAResolvePackageDependenciesTask.cs | 45 +- ...WantToGetDependenciesViaDesignTimeBuild.cs | 399 ------------------ .../CollectSDKReferencesDesignTime.cs | 27 +- ...PreprocessPackageDependenciesDesignTime.cs | 172 -------- .../ResolvePackageAssets.cs | 141 ++++++- .../ResolvePackageDependencies.cs | 50 +-- ...rosoft.PackageDependencyResolution.targets | 27 +- 8 files changed, 194 insertions(+), 670 deletions(-) delete mode 100644 src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenThatWeWantToGetDependenciesViaDesignTimeBuild.cs delete mode 100644 src/Tasks/Microsoft.NET.Build.Tasks/PreprocessPackageDependenciesDesignTime.cs diff --git a/src/Tasks/Common/MetadataKeys.cs b/src/Tasks/Common/MetadataKeys.cs index ee3d946bca4f..9e2d95a1db2f 100644 --- a/src/Tasks/Common/MetadataKeys.cs +++ b/src/Tasks/Common/MetadataKeys.cs @@ -141,5 +141,8 @@ internal static class MetadataKeys public const string XmlFilePath = "XmlFilePath"; public const string PdbExtension = ".pdb"; public const string PdbFilePath = "PdbFilePath"; + + // Dependencies design time + public const string Resolved = "Resolved"; } } diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAResolvePackageDependenciesTask.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAResolvePackageDependenciesTask.cs index 9d078eb466e3..bbacf673e4d8 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAResolvePackageDependenciesTask.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAResolvePackageDependenciesTask.cs @@ -21,9 +21,9 @@ public class GivenAResolvePackageDependenciesTask [Theory] [MemberData(nameof(ItemCounts))] - public void ItRaisesLockFileToMSBuildItems(string projectName, int[] counts, bool emitLegacyAssetsFileItems) + public void ItRaisesLockFileToMSBuildItems(string projectName, int[] counts) { - var task = GetExecutedTaskFromPrefix(projectName, out _, emitLegacyAssetsFileItems); + var task = GetExecutedTaskFromPrefix(projectName, out _); task.PackageDefinitions .Count().Should().Be(counts[0]); task.FileDefinitions .Count().Should().Be(counts[1]); @@ -40,36 +40,16 @@ public static IEnumerable ItemCounts { new object[] { "dotnet.new", - new int[] { 110, 2536, 1, 846, 73 }, - true - }, - new object[] { - "dotnet.new", - new int[] { 110, 0, 0, 846, 0 }, - false - }, - new object[] { - "simple.dependencies", - new int[] { 113, 2613, 1, 878, 94 }, - true + new int[] { 110, 2536, 1, 845, 75 }, }, new object[] { "simple.dependencies", - new int[] { 113, 0, 0, 878, 0 }, - false + new int[] { 113, 2613, 1, 877, 96 }, }, }; } } - [Fact] - public void ItOmitsLegacyItemsByDefault() - { - var task = new ResolvePackageDependencies(); - - task.EmitLegacyAssetsFileItems.Should().Be(false); - } - [Theory] [InlineData("dotnet.new")] [InlineData("simple.dependencies")] @@ -584,8 +564,7 @@ public void ItAddsAnalyzerMetadataAndFileDependencies() { ProjectAssetsFile = lockFile.Path, ProjectPath = null, - ProjectLanguage = projectLanguage, // set language - EmitLegacyAssetsFileItems = true + ProjectLanguage = projectLanguage // set language }; task.Execute().Should().BeTrue(); @@ -669,8 +648,7 @@ public void ItFiltersAnalyzersByProjectLanguage() { ProjectAssetsFile = lockFile.Path, ProjectPath = null, - ProjectLanguage = projectLanguage, // set language - EmitLegacyAssetsFileItems = true + ProjectLanguage = projectLanguage // set language }; task.Execute().Should().BeTrue(); @@ -839,19 +817,19 @@ public void ItDoesNotThrowOnCrossTargetingWithTargetPlatforms() GetExecutedTaskFromContents(lockFileContent, out _); // Task should not fail on matching framework names } - private static ResolvePackageDependencies GetExecutedTaskFromPrefix(string lockFilePrefix, out LockFile lockFile, bool emitLegacyAssetsFileItems = true, string target = null) + private static ResolvePackageDependencies GetExecutedTaskFromPrefix(string lockFilePrefix, out LockFile lockFile, string target = null) { lockFile = TestLockFiles.GetLockFile(lockFilePrefix); - return GetExecutedTask(lockFile, emitLegacyAssetsFileItems, target); + return GetExecutedTask(lockFile, target); } - private static ResolvePackageDependencies GetExecutedTaskFromContents(string lockFileContents, out LockFile lockFile, bool emitLegacyAssetsFileItems = true, string target = null) + private static ResolvePackageDependencies GetExecutedTaskFromContents(string lockFileContents, out LockFile lockFile, string target = null) { lockFile = TestLockFiles.CreateLockFile(lockFileContents); - return GetExecutedTask(lockFile, emitLegacyAssetsFileItems, target); + return GetExecutedTask(lockFile, target); } - private static ResolvePackageDependencies GetExecutedTask(LockFile lockFile, bool emitLegacyAssetsFileItems, string target) + private static ResolvePackageDependencies GetExecutedTask(LockFile lockFile, string target) { var resolver = new MockPackageResolver(_packageRoot); @@ -860,7 +838,6 @@ private static ResolvePackageDependencies GetExecutedTask(LockFile lockFile, boo ProjectAssetsFile = lockFile.Path, ProjectPath = _projectPath, ProjectLanguage = null, - EmitLegacyAssetsFileItems = emitLegacyAssetsFileItems, TargetFramework = target }; diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenThatWeWantToGetDependenciesViaDesignTimeBuild.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenThatWeWantToGetDependenciesViaDesignTimeBuild.cs deleted file mode 100644 index 84e2088d439a..000000000000 --- a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenThatWeWantToGetDependenciesViaDesignTimeBuild.cs +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using Microsoft.Build.Framework; -using Xunit; - -namespace Microsoft.NET.Build.Tasks.UnitTests -{ - public class GivenThatWeWantToGetDependenciesViaDesignTimeBuild - { - [Fact] - public void ItShouldNotReturnPackagesWithUnknownTypes() - { - var task = new PreprocessPackageDependenciesDesignTime - { - TargetFramework = "net45", - DefaultImplicitPackages = string.Empty, - PackageDefinitions = new ITaskItem[] - { - new MockTaskItem( - itemSpec: "mockPackageNoType/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageNoType" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some path" } - }), - new MockTaskItem( - itemSpec: "mockPackageUnknown/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageUnknown" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some resolved path" }, - { MetadataKeys.Type, "qqqq" } - }) - }, - PackageDependencies = new ITaskItem[] - { - new MockTaskItem( - itemSpec: "mockPackageNoType/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "mockPackageUnknown/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }) - } - }; - - Assert.True(task.Execute()); - - Assert.Empty(task.PackageDependenciesDesignTime); - } - - [Fact] - public void ItShouldReturnUnresolvedPackageDependenciesWithTypePackage() - { - var task = new PreprocessPackageDependenciesDesignTime - { - TargetFramework = "net45", - DefaultImplicitPackages = string.Empty, - PackageDefinitions = new ITaskItem[] - { - new MockTaskItem( - itemSpec: "mockPackageUnresolved/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageUnresolved" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "" }, - { MetadataKeys.Type, "Unresolved" }, - { MetadataKeys.DiagnosticLevel, "Warning" } - }) - }, - PackageDependencies = new ITaskItem[] - { - new MockTaskItem( - itemSpec: "mockPackageUnresolved/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }) - } - }; - - Assert.True(task.Execute()); - - var item = Assert.Single(task.PackageDependenciesDesignTime); - - Assert.Equal("mockPackageUnresolved/1.0.0", item.ItemSpec); - Assert.Equal("mockPackageUnresolved", item.GetMetadata(MetadataKeys.Name)); - Assert.Equal("1.0.0", item.GetMetadata(MetadataKeys.Version)); - Assert.Equal("some path", item.GetMetadata(MetadataKeys.Path)); - Assert.Equal("", item.GetMetadata(MetadataKeys.ResolvedPath)); - Assert.Equal("Warning", item.GetMetadata(MetadataKeys.DiagnosticLevel)); - Assert.False(item.GetBooleanMetadata(MetadataKeys.IsImplicitlyDefined)); - Assert.False(item.GetBooleanMetadata(PreprocessPackageDependenciesDesignTime.ResolvedMetadata)); - } - - [Fact] - public void ItShouldIdentifyDefaultImplicitPackages() - { - var task = new PreprocessPackageDependenciesDesignTime - { - TargetFramework = "net45", - DefaultImplicitPackages = "DefaultImplicit", - PackageDefinitions = new ITaskItem[] - { - new MockTaskItem( - itemSpec: "DefaultImplicit/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "DefaultImplicit" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "" }, - { MetadataKeys.Type, "Package" } - }) - }, - PackageDependencies = new ITaskItem[] - { - new MockTaskItem( - itemSpec: "DefaultImplicit/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }) - } - }; - - Assert.True(task.Execute()); - - var item = Assert.Single(task.PackageDependenciesDesignTime); - - Assert.Equal("DefaultImplicit/1.0.0", item.ItemSpec); - Assert.True(item.GetBooleanMetadata(MetadataKeys.IsImplicitlyDefined)); - } - - [Fact] - public void ItShouldIgnoreAllDependenciesWithTypeNotEqualToPackageOrUnresolved() - { - var task = new PreprocessPackageDependenciesDesignTime - { - TargetFramework = "net45", - DefaultImplicitPackages = string.Empty, - PackageDefinitions = new ITaskItem[] { - new MockTaskItem( - itemSpec: "mockPackageExternalProject/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageExternalProject" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some path" }, - { MetadataKeys.Type, "ExternalProject" } - }), - new MockTaskItem( - itemSpec: "mockPackageProject/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageProject" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some resolved path" }, - { MetadataKeys.Type, "Project" } - }), - new MockTaskItem( - itemSpec: "mockPackageContent/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageContent" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some resolved path" }, - { MetadataKeys.Type, "Content" } - }), - new MockTaskItem( - itemSpec: "mockPackageAssembly/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageAssembly" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some resolved path" }, - { MetadataKeys.Type, "Assembly" } - }), - new MockTaskItem( - itemSpec: "mockPackageFrameworkAssembly/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageFrameworkAssembly" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some resolved path" }, - { MetadataKeys.Type, "FrameworkAssembly" } - }), - new MockTaskItem( - itemSpec: "mockPackageDiagnostic/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageDiagnostic" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some resolved path" }, - { MetadataKeys.Type, "Diagnostic" } - }), - new MockTaskItem( - itemSpec: "mockPackageWinmd/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageWinmd" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some resolved path" }, - { MetadataKeys.Type, "Winmd" } - }), - new MockTaskItem( - itemSpec: "mockPackageReference/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "mockPackageReference" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some resolved path" }, - { MetadataKeys.Type, "Reference" } - }) - }, - PackageDependencies = new ITaskItem[] { - new MockTaskItem( - itemSpec: "mockPackageExternalProject/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "mockPackageProject/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "mockPackageContent/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "mockPackageAssembly/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "mockPackageFrameworkAssembly/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "mockPackageDiagnostic/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "mockPackageWinmd/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "mockPackageReference/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }) - } - }; - - Assert.True(task.Execute()); - - Assert.Empty(task.PackageDependenciesDesignTime); - } - - [Fact] - public void ItShouldOnlyReturnPackagesInTheSpecifiedTarget() - { - var task = new PreprocessPackageDependenciesDesignTime - { - TargetFramework = "net45", - DefaultImplicitPackages = string.Empty, - PackageDefinitions = new ITaskItem[] { - new MockTaskItem( - itemSpec: "Package1/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "Package1" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "" }, - { MetadataKeys.Type, "Package" } - }), - new MockTaskItem( - itemSpec: "Package2/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "Package2" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "" }, - { MetadataKeys.Type, "Package" } - }) - }, - PackageDependencies = new ITaskItem[] { - new MockTaskItem( - itemSpec: "Package1/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "Package2/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net46" } - }) - } - }; - - Assert.True(task.Execute()); - - var item = Assert.Single(task.PackageDependenciesDesignTime); - - Assert.Equal("Package1/1.0.0", item.ItemSpec); - } - - [Fact] - public void ItShouldOnlyReturnTopLevelPackages() - { - var task = new PreprocessPackageDependenciesDesignTime - { - TargetFramework = "net45", - DefaultImplicitPackages = string.Empty, - PackageDefinitions = new ITaskItem[] { - new MockTaskItem( - itemSpec: "Package1/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "Package1" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "" }, - { MetadataKeys.Type, "Package" } - }), - new MockTaskItem( - itemSpec: "ChildPackage1/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.Name, "ChildPackage1" }, - { MetadataKeys.Version, "1.0.0" }, - { MetadataKeys.Path, "some path" }, - { MetadataKeys.ResolvedPath, "some resolved path" }, - { MetadataKeys.Type, "Package" } - }) - }, - PackageDependencies = new ITaskItem[] { - new MockTaskItem( - itemSpec: "Package1/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" } - }), - new MockTaskItem( - itemSpec: "ChildPackage1/1.0.0", - metadata: new Dictionary - { - { MetadataKeys.ParentTarget, "net45" }, - { MetadataKeys.ParentPackage, "Package1/1.0.0" } - }) - } - }; - - Assert.True(task.Execute()); - - var item = Assert.Single(task.PackageDependenciesDesignTime); - - Assert.Equal("Package1/1.0.0", item.ItemSpec); - } - } -} diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/CollectSDKReferencesDesignTime.cs b/src/Tasks/Microsoft.NET.Build.Tasks/CollectSDKReferencesDesignTime.cs index 30a1d7f7a726..3f009bfde6ba 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/CollectSDKReferencesDesignTime.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/CollectSDKReferencesDesignTime.cs @@ -34,8 +34,7 @@ public class CollectSDKReferencesDesignTime : TaskBase protected override void ExecuteCore() { - ImplicitPackageReferences = - PreprocessPackageDependenciesDesignTime.GetImplicitPackageReferences(DefaultImplicitPackages); + ImplicitPackageReferences = GetImplicitPackageReferences(DefaultImplicitPackages); var sdkDesignTimeList = new List(SdkReferences); sdkDesignTimeList.AddRange(GetImplicitPackageReferences()); @@ -43,6 +42,28 @@ protected override void ExecuteCore() SDKReferencesDesignTime = sdkDesignTimeList.ToArray(); } + internal static HashSet GetImplicitPackageReferences(string defaultImplicitPackages) + { + var implicitPackageReferences = new HashSet(StringComparer.OrdinalIgnoreCase); + if (string.IsNullOrEmpty(defaultImplicitPackages)) + { + return implicitPackageReferences; + } + + var packageNames = defaultImplicitPackages.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + if (packageNames.Length == 0) + { + return implicitPackageReferences; + } + + foreach (var packageReference in packageNames) + { + implicitPackageReferences.Add(packageReference); + } + + return implicitPackageReferences; + } + private IEnumerable GetImplicitPackageReferences() { var implicitPackages = new List(); @@ -74,4 +95,4 @@ private IEnumerable GetImplicitPackageReferences() return implicitPackages; } } -} \ No newline at end of file +} diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/PreprocessPackageDependenciesDesignTime.cs b/src/Tasks/Microsoft.NET.Build.Tasks/PreprocessPackageDependenciesDesignTime.cs deleted file mode 100644 index 2592cda63698..000000000000 --- a/src/Tasks/Microsoft.NET.Build.Tasks/PreprocessPackageDependenciesDesignTime.cs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. 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.Framework; -using Microsoft.Build.Utilities; - -namespace Microsoft.NET.Build.Tasks -{ - /// - /// Filters and projects items produced by for consumption by - /// the dependencies tree, via design-time builds. - /// - /// - /// Only top-level package references are retained (i.e. those referenced directly by the project, not - /// those only brought in transitively). - /// - /// Only package references applicable to are retained. - /// - /// Changes to the implementation of this class must be coordinated with PackageRuleHandler - /// in the dotnet/project-system repo. - /// - public class PreprocessPackageDependenciesDesignTime : TaskBase - { - public const string ResolvedMetadata = "Resolved"; - - /// - /// Information about each package in the project, with metadata: - /// - Name = "MetadataExtractor" - /// - Path = "metadataextractor/1.0.0" - /// - ResolvedPath = "C:\Users\drnoakes\.nuget\packages\metadataextractor\1.0.0" - /// - Type = "package" - /// - Version = "2.3.0" - /// - DiagnosticLevel = "" - /// - [Required] - public ITaskItem[] PackageDefinitions { get; set; } - - /// - /// Items with metadata "ParentTarget" and "ParentPackage", which allows determining the hierarchy of package references. - /// - [Required] - public ITaskItem[] PackageDependencies { get; set; } - - /// - /// Eg: "Microsoft.NETCore.App;NETStandard.Library" - /// - [Required] - public string DefaultImplicitPackages { get; set; } - - /// - /// The TargetFramework, which may be an alias - /// Eg: "netcoreapp3.1", "net5.0-windows", etc. - /// Only packages targeting this framework will be returned. - /// - [Required] - public string TargetFramework { get; set; } - - [Output] - public ITaskItem[] PackageDependenciesDesignTime { get; private set; } - - protected override void ExecuteCore() - { - var implicitPackageReferences = GetImplicitPackageReferences(DefaultImplicitPackages); - - // We have two types of data: - // - // 1) "PackageDependencies" which place a package in a given target/hierarchy - // 2) "PackageDefinitions" which provide general metadata about a package - // - // First, we scan PackageDependencies to build the set of packages in our target. - - var allowItemSpecs = new HashSet(StringComparer.OrdinalIgnoreCase); - - foreach (var dependency in PackageDependencies) - { - if (dependency.HasMetadataValue(MetadataKeys.ParentPackage)) - { - // ignore non-top-level packages (those with ParentPackage) - continue; - } - - var target = dependency.GetMetadata(MetadataKeys.ParentTarget); - - if (!StringComparer.OrdinalIgnoreCase.Equals(target, TargetFramework)) - { - // skip dependencies for other targets - continue; - } - - allowItemSpecs.Add(dependency.ItemSpec); - } - - // Second, find PackageDefinitions that match our allowed item specs - - var outputItems = new List(allowItemSpecs.Count); - - foreach (var packageDef in PackageDefinitions) - { - if (!allowItemSpecs.Contains(packageDef.ItemSpec)) - { - // We are not interested in this definition (not top-level, or wrong target) - continue; - } - - var dependencyType = GetDependencyType(packageDef.GetMetadata(MetadataKeys.Type)); - - if (dependencyType == DependencyType.Package || - dependencyType == DependencyType.Unresolved) - { - var name = packageDef.GetMetadata(MetadataKeys.Name); - - if (string.IsNullOrEmpty(name)) - { - // Name is required - continue; - } - - var version = packageDef.GetMetadata(MetadataKeys.Version) ?? string.Empty; - var resolvedPath = packageDef.GetMetadata(MetadataKeys.ResolvedPath); - var resolved = !string.IsNullOrEmpty(resolvedPath); - var path = (resolved - ? resolvedPath - : packageDef.GetMetadata(MetadataKeys.Path)) ?? string.Empty; - var isImplicitlyDefined = implicitPackageReferences.Contains(name); - var diagnosticLevel = packageDef.GetMetadata(MetadataKeys.DiagnosticLevel) ?? string.Empty; - - var outputItem = new TaskItem(packageDef.ItemSpec); - outputItem.SetMetadata(MetadataKeys.Name, name); - outputItem.SetMetadata(MetadataKeys.Version, version); - outputItem.SetMetadata(MetadataKeys.Path, path); - outputItem.SetMetadata(MetadataKeys.IsImplicitlyDefined, isImplicitlyDefined.ToString()); - outputItem.SetMetadata(MetadataKeys.DiagnosticLevel, diagnosticLevel); - outputItem.SetMetadata(ResolvedMetadata, resolved.ToString()); - - outputItems.Add(outputItem); - } - } - - PackageDependenciesDesignTime = outputItems.ToArray(); - } - - internal static HashSet GetImplicitPackageReferences(string defaultImplicitPackages) - { - var implicitPackageReferences = new HashSet(StringComparer.OrdinalIgnoreCase); - if (string.IsNullOrEmpty(defaultImplicitPackages)) - { - return implicitPackageReferences; - } - - var packageNames = defaultImplicitPackages.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - if (packageNames.Length == 0) - { - return implicitPackageReferences; - } - - foreach (var packageReference in packageNames) - { - implicitPackageReferences.Add(packageReference); - } - - return implicitPackageReferences; - } - - private static DependencyType GetDependencyType(string dependencyTypeString) - { - Enum.TryParse(dependencyTypeString, ignoreCase: true, out DependencyType dependencyType); - return dependencyType; - } - } -} diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs index 48ee5d280c58..74e1e19b2415 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs @@ -8,10 +8,12 @@ using System.Linq; using System.Security.Cryptography; using System.Text; +using System.Xml.Linq; using Microsoft.Build.Evaluation; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using NuGet.Common; +using NuGet.Frameworks; using NuGet.ProjectModel; using NuGet.Versioning; @@ -27,6 +29,8 @@ namespace Microsoft.NET.Build.Tasks /// public sealed class ResolvePackageAssets : TaskBase { + #region Input Items + /// /// Path to assets.json. /// @@ -160,6 +164,15 @@ public sealed class ResolvePackageAssets : TaskBase /// public bool DesignTimeBuild { get; set; } + /// + /// Eg: "Microsoft.NETCore.App;NETStandard.Library" + /// + [Required] + public string DefaultImplicitPackages { get; set; } + + #endregion + + #region Output Items /// /// Full paths to assemblies from packages to pass to compiler as analyzers. /// @@ -233,6 +246,17 @@ public sealed class ResolvePackageAssets : TaskBase [Output] public ITaskItem[] PackageDependencies { get; private set; } + /// + /// Filters and projects items produced by for consumption by + /// the dependencies tree, via design-time builds. + /// + /// + /// Changes to the implementation of output must be coordinated with PackageRuleHandler + /// in the dotnet/project-system repo. + /// + [Output] + public ITaskItem[] PackageDependenciesDesignTime { get; private set; } + /// /// List of symbol files (.pdb) related to NuGet packages. /// @@ -251,6 +275,8 @@ public sealed class ResolvePackageAssets : TaskBase [Output] public ITaskItem[] ReferenceDocumentationFiles { get; private set; } + #endregion + /// /// Messages from the assets file. /// These are logged directly and therefore not returned to the targets (note private here). @@ -304,7 +330,7 @@ public sealed class ResolvePackageAssets : TaskBase //////////////////////////////////////////////////////////////////////////////////////////////////// private const int CacheFormatSignature = ('P' << 0) | ('K' << 8) | ('G' << 16) | ('A' << 24); - private const int CacheFormatVersion = 11; + private const int CacheFormatVersion = 12; private static readonly Encoding TextEncoding = Encoding.UTF8; private const int SettingsHashLength = 256 / 8; private HashAlgorithm CreateSettingsHash() => SHA256.Create(); @@ -336,6 +362,7 @@ private void ReadItemGroups() FrameworkReferences = reader.ReadItemGroup(); NativeLibraries = reader.ReadItemGroup(); PackageDependencies = reader.ReadItemGroup(); + PackageDependenciesDesignTime = reader.ReadItemGroup(); PackageFolders = reader.ReadItemGroup(); ReferenceDocumentationFiles = reader.ReadItemGroup(); ResourceAssemblies = reader.ReadItemGroup(); @@ -694,7 +721,6 @@ public CacheWriter(ResolvePackageAssets task) _lockFile = new LockFileCache(task).GetLockFile(task.ProjectAssetsFile); _packageResolver = NuGetPackageResolver.CreateResolver(_lockFile); - // If we are doing a design-time build, we do not want to fail the build if we can't find the // target framework and/or runtime identifier in the assets file. This is because the design-time // build needs to succeed in order to get the right information in order to run a restore in order @@ -816,6 +842,7 @@ private void WriteItemGroups() WriteItemGroup(WriteFrameworkReferences); WriteItemGroup(WriteNativeLibraries); WriteItemGroup(WritePackageDependencies); + WriteItemGroup(WritePackageDependenciesDesignTime); WriteItemGroup(WritePackageFolders); WriteItemGroup(WriteReferenceDocumentationFiles); WriteItemGroup(WriteResourceAssemblies); @@ -1166,17 +1193,13 @@ private void WriteDebugItems( foreach (string fileExtension in relatedExtensions.Split(RelatedPropertySeparator)) { - if (fileExtension.ToLower() == extension) + if (StringComparer.InvariantCulture.Equals(fileExtension, extension)) { string xmlFilePath = Path.ChangeExtension(itemSpec, fileExtension); if (File.Exists(xmlFilePath)) { WriteItem(xmlFilePath, library); } - else - { - _task.Log.LogWarning(Strings.AssetsFileNotFound, xmlFilePath); - } } } } @@ -1414,6 +1437,110 @@ private void WritePackageDependencies() } } + private void WritePackageDependenciesDesignTime() + { + var implicitPackageReferences = CollectSDKReferencesDesignTime.GetImplicitPackageReferences(_task.DefaultImplicitPackages); + + // Scan PackageDependencies to build the set of packages in our target. + var allowItemSpecs = GetPackageDependencies(); + + foreach (var package in _lockFile.Libraries) + { + var packageVersion = package.Version.ToNormalizedString(); + string packageId = $"{package.Name}/{packageVersion}"; + + // Find PackageDefinitions that match our allowed item specs + if (string.IsNullOrEmpty(package.Name) || !allowItemSpecs.Contains(packageId)) + { + // Only include packages from the allow list. + // This excludes transitive packages and those from other targets. + continue; + } + + var dependencyType = GetDependencyType(package.Type); + + if (dependencyType == DependencyType.Package || + dependencyType == DependencyType.Unresolved) + { + WriteItem(packageId); + WriteMetadata(MetadataKeys.Name, package.Name); + + var version = packageVersion ?? string.Empty; + WriteMetadata(MetadataKeys.Version, version); + + var isImplicitlyDefined = implicitPackageReferences.Contains(package.Name); + WriteMetadata(MetadataKeys.IsImplicitlyDefined, isImplicitlyDefined.ToString()); + + string resolvedPackagePath = _packageResolver.GetPackageDirectory(package.Name, package.Version); + var resolvedPath = resolvedPackagePath ?? string.Empty; + var resolved = !string.IsNullOrEmpty(resolvedPath); + WriteMetadata(MetadataKeys.Resolved, resolved.ToString()); + + string itemPath = package.Path ?? string.Empty; + var path = (resolved + ? resolvedPath + : itemPath) ?? string.Empty; + WriteMetadata(MetadataKeys.Path, path); + + string itemDiagnosticLevel = GetPackageDiagnosticLevel(package); + var diagnosticLevel = itemDiagnosticLevel ?? string.Empty; + WriteMetadata(MetadataKeys.DiagnosticLevel, diagnosticLevel); + } + } + + HashSet GetPackageDependencies() + { + HashSet projectFileDependencies = _lockFile.GetProjectFileDependencySet(_compileTimeTarget.Name); + + HashSet results = new(StringComparer.OrdinalIgnoreCase); + + foreach (var package in _compileTimeTarget.Libraries) + { + if (projectFileDependencies.Contains(package.Name)) + { + string itemSpec = GetPackageId(package); + + bool added = results.Add(itemSpec); + + Debug.Assert(added); + } + } + + return results; + } + + static string GetPackageId(LockFileTargetLibrary package) => $"{package.Name}/{package.Version.ToNormalizedString()}"; + + string GetPackageDiagnosticLevel(LockFileLibrary package) + { + string target = _task.TargetFramework ?? ""; + + var messages = _lockFile.LogMessages.Where(log => + log.LibraryId == package.Name && + log.TargetGraphs.Any(tg => + { + var parsedTargetGraph = NuGetFramework.Parse(tg); + var alias = _lockFile.PackageSpec.TargetFrameworks + .FirstOrDefault(tf => tf.FrameworkName == parsedTargetGraph) + ?.TargetAlias ?? tg; + return alias == target; + })); + + if (!messages.Any()) + { + return string.Empty; + } + + return messages.Max(log => log.Level).ToString(); + } + + static DependencyType GetDependencyType(string dependencyTypeString) + { + Enum.TryParse(dependencyTypeString, ignoreCase: true, out DependencyType dependencyType); + return dependencyType; + } + } + private void WriteResourceAssemblies() { WriteItems( diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageDependencies.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageDependencies.cs index be6e7e20b3da..7785c24105db 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageDependencies.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageDependencies.cs @@ -16,11 +16,11 @@ namespace Microsoft.NET.Build.Tasks /// Raises Nuget LockFile representation to MSBuild items and resolves /// assets specified in the lock file. /// + /// + /// Only called for backwards compatability, when ResolvePackageDependencies is true. + /// public sealed class ResolvePackageDependencies : TaskBase { - /// - /// Only used if is . - /// private readonly Dictionary _fileTypes = new Dictionary(StringComparer.OrdinalIgnoreCase); private HashSet _projectFileDependencies; @@ -37,7 +37,6 @@ public sealed class ResolvePackageDependencies : TaskBase /// /// All the targets in the lock file. - /// Only populated if is . /// [Output] public ITaskItem[] TargetDefinitions @@ -56,7 +55,6 @@ public ITaskItem[] PackageDefinitions /// /// All the files in the lock file. - /// Only populated if is . /// [Output] public ITaskItem[] FileDefinitions @@ -77,7 +75,6 @@ public ITaskItem[] PackageDependencies /// /// All the dependencies between files and packages, labeled by the group containing /// the file (e.g. CompileTimeAssembly, RuntimeAssembly, etc.). - /// Only populated if is . /// [Output] public ITaskItem[] FileDependencies @@ -114,12 +111,6 @@ public string ProjectLanguage get; set; } - /// - /// Setting this property restores pre-16.7 behaviour of populating , - /// and outputs. - /// - public bool EmitLegacyAssetsFileItems { get; set; } = false; - public string TargetFramework { get; set; } #endregion @@ -195,11 +186,6 @@ private void GetPackageAndFileDefinitions() _packageDefinitions.Add(item); - if (!EmitLegacyAssetsFileItems) - { - continue; - } - foreach (var file in package.Files) { if (NuGetUtils.IsPlaceholderFile(file)) @@ -276,18 +262,15 @@ private void RaiseLockFileTargets() { foreach (var target in LockFile.Targets) { - if (EmitLegacyAssetsFileItems) - { - TaskItem item = new TaskItem(target.Name); - item.SetMetadata(MetadataKeys.RuntimeIdentifier, target.RuntimeIdentifier ?? string.Empty); - item.SetMetadata(MetadataKeys.TargetFramework, TargetFramework); - item.SetMetadata(MetadataKeys.TargetFrameworkMoniker, target.TargetFramework.DotNetFrameworkName); - item.SetMetadata(MetadataKeys.FrameworkName, target.TargetFramework.Framework); - item.SetMetadata(MetadataKeys.FrameworkVersion, target.TargetFramework.Version.ToString()); - item.SetMetadata(MetadataKeys.Type, "target"); - - _targetDefinitions.Add(item); - } + TaskItem item = new TaskItem(target.Name); + item.SetMetadata(MetadataKeys.RuntimeIdentifier, target.RuntimeIdentifier ?? string.Empty); + item.SetMetadata(MetadataKeys.TargetFramework, TargetFramework); + item.SetMetadata(MetadataKeys.TargetFrameworkMoniker, target.TargetFramework.DotNetFrameworkName); + item.SetMetadata(MetadataKeys.FrameworkName, target.TargetFramework.Framework); + item.SetMetadata(MetadataKeys.FrameworkVersion, target.TargetFramework.Version.ToString()); + item.SetMetadata(MetadataKeys.Type, "target"); + + _targetDefinitions.Add(item); // raise each library in the target GetPackageAndFileDependencies(target); @@ -323,11 +306,8 @@ private void GetPackageAndFileDependencies(LockFileTarget target) // get sub package dependencies GetPackageDependencies(package, target.Name, resolvedPackageVersions, transitiveProjectRefs); - if (EmitLegacyAssetsFileItems) - { - // get file dependencies on this package - GetFileDependencies(package, target.Name); - } + // get file dependencies on this package + GetFileDependencies(package, target.Name); } } @@ -375,7 +355,7 @@ private void GetFileDependencies(LockFileTargetLibrary package, string targetNam string filePath = entry.Item1; IDictionary properties = entry.Item2; - if (NuGetUtils.IsPlaceholderFile(filePath) || !EmitLegacyAssetsFileItems) + if (NuGetUtils.IsPlaceholderFile(filePath)) { continue; } diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.PackageDependencyResolution.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.PackageDependencyResolution.targets index 2456989cbf34..dc048fde8e68 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.PackageDependencyResolution.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.PackageDependencyResolution.targets @@ -192,18 +192,17 @@ Copyright (c) .NET Foundation. All rights reserved. RuntimeIdentifier="$(RuntimeIdentifier)" Condition=" '$(DesignTimeBuild)' != 'true'"/> + + ContinueOnError="ErrorAndContinue" + Condition="'$(EmitLegacyAssetsFileItems)' == 'true'"> - - @@ -290,7 +289,8 @@ Copyright (c) .NET Foundation. All rights reserved. SatelliteResourceLanguages="$(SatelliteResourceLanguages)" DesignTimeBuild="$(DesignTimeBuild)" ContinueOnError="$(ContinueOnError)" - PackageReferences="@(PackageReference)"> + PackageReferences="@(PackageReference)" + DefaultImplicitPackages= "$(DefaultImplicitPackages)"> @@ -309,6 +309,7 @@ Copyright (c) .NET Foundation. All rights reserved. + @@ -339,23 +340,9 @@ Copyright (c) .NET Foundation. All rights reserved. ============================================================ --> - - - - - - - - - + DependsOnTargets="ResolvePackageAssets;RunResolvePackageDependencies;ResolveAssemblyReferencesDesignTime" />