-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Speed up incremental package asset resolution (#2020)
Whenever project.assets.json changes (or more rarely, a setting influencing ResolvePackageAssets changes), write out a binary cache file for the next incremental build. The file has only the items that used by the build and they are written in a format that can be deserialized to MSBuild ITaskItem[] with minimal time and allocation. On top of that, we merge ReportAssetsLogMessages into ResolvePackageAssets, which allows for project.assets.json to not be read at all if it has not changed. However, design time build still uses old ReportAssetsLogMessages like old ResolvePackageDepdencies. Fixing the design time perf will be done separately in coordination with project system. In order to ensure consistent behavior between incremental builds and full builds, and to ensure maximal test coverage of cache reading and writing, a full build will write out the cache and then read from it as an incremental build would.
- Loading branch information
Showing
11 changed files
with
862 additions
and
268 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAResolvePackageAssetsTask.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// 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 FluentAssertions; | ||
using Microsoft.Build.Framework; | ||
using System; | ||
using System.Linq; | ||
using System.Reflection; | ||
using Xunit; | ||
|
||
namespace Microsoft.NET.Build.Tasks.UnitTests | ||
{ | ||
public class GivenAResolvePackageAssetsTask | ||
{ | ||
[Fact] | ||
public void ItHashesAllParameters() | ||
{ | ||
var inputProperties = typeof(ResolvePackageAssets) | ||
.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public) | ||
.Where(p => !p.IsDefined(typeof(OutputAttribute))) | ||
.OrderBy(p => p.Name, StringComparer.Ordinal); | ||
|
||
var requiredProperties = inputProperties | ||
.Where(p => p.IsDefined(typeof(RequiredAttribute))); | ||
|
||
var task = new ResolvePackageAssets(); | ||
|
||
// Initialize all required properties as a genuine task invocation would. We do this | ||
// because HashSettings need not defend against required parameters being null. | ||
foreach (var property in requiredProperties) | ||
{ | ||
property.PropertyType.Should().Be( | ||
typeof(string), | ||
because: $"this test hasn't been updated to handle non-string required task parameters like {property.Name}"); | ||
|
||
property.SetValue(task, "_"); | ||
} | ||
|
||
byte[] oldHash; | ||
try | ||
{ | ||
oldHash = task.HashSettings(); | ||
} | ||
catch (ArgumentNullException) | ||
{ | ||
Assert.True( | ||
false, | ||
"HashSettings is likely not correctly handling null value of one or more optional task parameters"); | ||
|
||
throw; // unreachable | ||
} | ||
|
||
foreach (var property in inputProperties) | ||
{ | ||
switch (property.PropertyType) | ||
{ | ||
case var t when t == typeof(bool): | ||
property.SetValue(task, true); | ||
break; | ||
|
||
case var t when t == typeof(string): | ||
property.SetValue(task, property.Name); | ||
break; | ||
|
||
default: | ||
Assert.True(false, $"{property.Name} is not a bool or string. Update the test code to handle that."); | ||
throw null; // unreachable | ||
} | ||
|
||
byte[] newHash = task.HashSettings(); | ||
newHash.Should().NotBeEquivalentTo( | ||
oldHash, | ||
because: $"{property.Name} should be included in hash."); | ||
|
||
oldHash = newHash; | ||
} | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.