Skip to content

Commit 2cab49a

Browse files
olstakhdfederm
andauthored
Add ability to ignore build files in packages (#125)
* Add ability to skip packages * Rename the property to ignore build files * Update minor version * Add default list of packages that can be trimmed * Fixes --------- Co-authored-by: David Federman <dfederm@microsoft.com> Co-authored-by: David Federman <david.federman@outlook.com>
1 parent 2bf0696 commit 2cab49a

8 files changed

Lines changed: 134 additions & 9 deletions

File tree

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ You can turn off specific docxml related warnings and errors while defaulting Re
5454

5555
Note: To get better results, enable the [`IDE0005`](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0005) unnecessary `using` rule. This avoids the C# compiler seeing a false positive assembly usage from unneeded `using` directives causing it to miss a removable dependency. See also the note for why IDE0005 code analysis rule requires `<GenerateDocumentationFile>` property to be enabled. Documentation generation is also required for accuracy of used references detection (based on https://github.com/dotnet/roslyn/issues/66188).
5656

57+
Packages are prevented from being trimmed if they contain build files, as there's no reliable way to determine whether it's safe to do so. You can explicitly ignore specific packages' build files and cause them to be solely judged based on whther the libraries are used by adding the package to the `ReferenceTrimmerIgnorePackageBuildFiles` item on a project level, or in `Directory.Build.props`.
58+
59+
Example:
60+
```xml
61+
<ItemGroup>
62+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging.Abstractions" />
63+
</ItemGroup>
64+
```
65+
A default set of `ReferenceTrimmerIgnorePackageBuildFiles` items is already included for well-known package, notably various `Microsoft.Extensions.*` packages.
66+
5767
### C++ (.vcxproj projects)
5868
ReferenceTrimmer for C++ is an MSBuild [distributed logger](https://learn.microsoft.com/en-us/visualstudio/msbuild/logging-in-a-multi-processor-environment?view=vs-2022). It writes guidance to the MSBuild stdout stream (not to the MSBuild internal logger at this time) and writes `ReferenceTrimmerUnusedMSVCLibraries.json.log` to the build working directory.
5969

src/Package/build/ReferenceTrimmer.props

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,42 @@
2222
</Link>
2323
</ItemDefinitionGroup>
2424

25+
<ItemGroup>
26+
<!--
27+
List of commonly used packages that contain build files that are not consequential, but they're preventing the reference from being trimmed.
28+
-->
29+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Caching.Abstractions" />
30+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Caching.Memory" />
31+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Configuration" />
32+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Configuration.Abstractions" />
33+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Configuration.Binder" />
34+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Configuration.CommandLine" />
35+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
36+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Configuration.FileExtensions" />
37+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Configuration.Json" />
38+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Configuration.UserSecrets" />
39+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.DependencyInjection" />
40+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
41+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.DependencyModel" />
42+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Diagnostics" />
43+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Diagnostics.Abstractions" />
44+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.FileProviders.Abstractions" />
45+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.FileProviders.Composite" />
46+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.FileProviders.Physical" />
47+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.FileSystemGlobbing" />
48+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Hosting" />
49+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Hosting.Abstractions" />
50+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Http" />
51+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging" />
52+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging.Abstractions" />
53+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging.Configuration" />
54+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging.Console" />
55+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging.Debug" />
56+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging.EventLog" />
57+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging.EventSource" />
58+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Options" />
59+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
60+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Primitives" />
61+
</ItemGroup>
62+
2563
</Project>

src/Package/build/ReferenceTrimmer.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
RuntimeIdentifier="$(RuntimeIdentifier)"
4242
NuGetRestoreTargets="$(NuGetRestoreTargets)"
4343
TargetFrameworkDirectories="$(TargetFrameworkDirectory)"
44+
IgnorePackageBuildFiles="@(ReferenceTrimmerIgnorePackageBuildFiles)"
4445
NuGetPackageRoot="$(NuGetPackageRoot)" />
4546

4647
<ItemGroup>

src/Tasks/CollectDeclaredReferencesTask.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public sealed class CollectDeclaredReferencesTask : MSBuildTask
4040

4141
public ITaskItem[]? PackageReferences { get; set; }
4242

43+
public ITaskItem[]? IgnorePackageBuildFiles { get; set; }
44+
4345
public string? ProjectAssetsFile { get; set; }
4446

4547
public string? TargetFrameworkMoniker { get; set; }
@@ -170,7 +172,6 @@ public override bool Execute()
170172
continue;
171173
}
172174

173-
// Ignore packages with build logic as we cannot easily evaluate whether the build logic is necessary or not.
174175
if (packageInfo.BuildFiles.Count > 0)
175176
{
176177
continue;
@@ -245,6 +246,12 @@ private Dictionary<string, PackageInfo> GetPackageInfos()
245246
}
246247
}
247248

249+
HashSet<string> packageToIgnoreBuildFiles = new(StringComparer.OrdinalIgnoreCase);
250+
foreach (ITaskItem item in IgnorePackageBuildFiles ?? [])
251+
{
252+
packageToIgnoreBuildFiles.Add(item.ItemSpec);
253+
}
254+
248255
// Get the transitive closure of assemblies included by each package
249256
foreach (LockFileTargetLibrary nugetLibrary in nugetLibraries)
250257
{
@@ -274,11 +281,13 @@ private Dictionary<string, PackageInfo> GetPackageInfos()
274281
})
275282
.ToList();
276283

277-
List<string> buildFiles = nugetLibrary.Build
278-
.Select(item => item.Path)
279-
.Where(IsValidFile)
280-
.Select(path => Path.Combine(nugetLibraryAbsolutePath, path))
281-
.ToList();
284+
List<string> buildFiles = packageToIgnoreBuildFiles.Contains(nugetLibrary.Name)
285+
? []
286+
: nugetLibrary.Build
287+
.Select(item => item.Path)
288+
.Where(IsValidFile)
289+
.Select(path => Path.Combine(nugetLibraryAbsolutePath, path))
290+
.ToList();
282291

283292
// Add this package's assets, if there are any
284293
if (nugetLibraryAssemblies.Count > 0 || buildFiles.Count > 0)

src/Tests/E2ETests.cs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,29 @@ public Task PackageReferenceWithFakeBuildFile()
491491
]);
492492
}
493493

494+
[TestMethod]
495+
public async Task IgnorePackageBuildFiles()
496+
{
497+
await RunMSBuildAsync(
498+
projectFile: "Library/Library.csproj",
499+
expectedWarnings: [],
500+
globalProperties: new Dictionary<string, string>
501+
{
502+
{ "IgnorePackageBuildFiles", "false" },
503+
});
504+
505+
await RunMSBuildAsync(
506+
projectFile: "Library/Library.csproj",
507+
expectedWarnings:
508+
[
509+
new Warning("RT0003: PackageReference Microsoft.Extensions.Logging can be removed", "Library/Library.csproj"),
510+
],
511+
globalProperties: new Dictionary<string, string>
512+
{
513+
{ "IgnorePackageBuildFiles", "true" },
514+
});
515+
}
516+
494517
private static (string ExePath, string Verb, string? VsInstallDir) GetMsBuildExeAndVerb()
495518
{
496519
// On Windows, try to find Visual Studio using vswhere
@@ -614,7 +637,13 @@ private static (string ExePath, string Verb, string? VsInstallDir) GetMsBuildExe
614637
return env;
615638
}
616639

617-
private async Task RunMSBuildAsync(string projectFile, Warning[] expectedWarnings, string[]? expectedConsoleOutputs = null, bool expectUnusedMsvcLibrariesLog = false, bool enableReferenceTrimmerDiagnostics = false)
640+
private async Task RunMSBuildAsync(
641+
string projectFile,
642+
Warning[] expectedWarnings,
643+
string[]? expectedConsoleOutputs = null,
644+
bool expectUnusedMsvcLibrariesLog = false,
645+
bool enableReferenceTrimmerDiagnostics = false,
646+
IReadOnlyDictionary<string, string>? globalProperties = null)
618647
{
619648
var testDataSourcePath = Path.GetFullPath(Path.Combine("TestData", TestContext?.TestName ?? string.Empty));
620649

@@ -641,6 +670,14 @@ private async Task RunMSBuildAsync(string projectFile, Warning[] expectedWarning
641670
$"-distributedlogger:CentralLogger,\"{loggersAssemblyPath}\"*ForwardingLogger,\"{loggersAssemblyPath}\" " +
642671
(enableReferenceTrimmerDiagnostics ? "-p:EnableReferenceTrimmerDiagnostics=true" : string.Empty);
643672

673+
if (globalProperties is not null)
674+
{
675+
foreach ((string key, string value) in globalProperties)
676+
{
677+
msbuildArgs += $" -p:{key}={value}";
678+
}
679+
}
680+
644681
Process? process = Process.Start(
645682
new ProcessStartInfo
646683
{
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Library
2+
{
3+
public static class Foo
4+
{
5+
public static string Bar() => "Baz";
6+
}
7+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Library</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
10+
</ItemGroup>
11+
12+
<!-- Clear out the defaults so we can test -->
13+
<ItemGroup>
14+
<ReferenceTrimmerIgnorePackageBuildFiles Remove="@(ReferenceTrimmerIgnorePackageBuildFiles)" />
15+
</ItemGroup>
16+
17+
<ItemGroup Condition="'$(IgnorePackageBuildFiles)' == 'true'">
18+
<!-- Microsoft.Extensions.Logging is the reference, but its dependencies are the ones with the build files. -->
19+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Logging.Abstractions" />
20+
<ReferenceTrimmerIgnorePackageBuildFiles Include="Microsoft.Extensions.Options" />
21+
</ItemGroup>
22+
23+
</Project>

version.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
3-
"version": "3.3",
4-
"assemblyVersion": "3.3",
3+
"version": "3.4",
4+
"assemblyVersion": "3.4",
55
"buildNumberOffset": -1,
66
"publicReleaseRefSpec": [
77
"^refs/tags/v\\d+\\.\\d+\\.\\d+"

0 commit comments

Comments
 (0)