Skip to content

Commit ee24868

Browse files
authored
Keep Publish* properties across Restore so that we can gather all required implicit packages (#49501)
2 parents 8f97224 + 3bf1a2b commit ee24868

File tree

3 files changed

+63
-7
lines changed

3 files changed

+63
-7
lines changed

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.PackTool.targets

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ NOTE: This file is imported from the following contexts, so be aware when writin
4242
<IncludeBuildOutput>false</IncludeBuildOutput>
4343

4444
<!-- the publish* properties _can_ be set, but only for the 'inner' RID-specific builds. We need to make sure that for the outer, agnostic build they are unset -->
45-
<PublishSelfContained Condition="'$(RuntimeIdentifier)' == ''">false</PublishSelfContained>
45+
<!-- RID information is also stripped during Restore, so we need to make sure user
46+
decisions are preserved when Restoring, so that publishing-related packages are implicitly included. -->
47+
<PublishSelfContained Condition="'$(RuntimeIdentifier)' == '' and '$(MSBuildIsRestoring)' != 'true'">false</PublishSelfContained>
4648
<!-- Have to set SelfContained similarly because PackTool targets are imported _after_ RuntimeIdentifierInference targets, where the Publish* properties are
4749
forwarded to the 'base' properties. -->
48-
<SelfContained Condition="'$(RuntimeIdentifier)' == ''">false</SelfContained>
49-
<PublishTrimmed Condition="'$(RuntimeIdentifier)' == ''">false</PublishTrimmed>
50-
<PublishReadyToRun Condition="'$(RuntimeIdentifier)' == ''">false</PublishReadyToRun>
51-
<PublishSingleFile Condition="'$(RuntimeIdentifier)' == ''">false</PublishSingleFile>
50+
<SelfContained Condition="'$(RuntimeIdentifier)' == '' and '$(MSBuildIsRestoring)' != 'true'">false</SelfContained>
51+
<PublishTrimmed Condition="'$(RuntimeIdentifier)' == '' and '$(MSBuildIsRestoring)' != 'true'">false</PublishTrimmed>
52+
<PublishReadyToRun Condition="'$(RuntimeIdentifier)' == '' and '$(MSBuildIsRestoring)' != 'true'">false</PublishReadyToRun>
53+
<PublishSingleFile Condition="'$(RuntimeIdentifier)' == '' and '$(MSBuildIsRestoring)' != 'true'">false</PublishSingleFile>
5254

5355
<!-- We need to know if the inner builds are _intended_ to be AOT even if we then explicitly disable AOT for the outer builds.
5456
Knowing this lets us correctly decide to create the RID-specific inner tools or not when packaging the outer tool. -->

test/Microsoft.DotNet.PackageInstall.Tests/EndToEndToolTests.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ public void PackagesMultipleToolsWithASingleInvocation()
154154
{
155155
var packageName = $"{toolSettings.ToolPackageId}.{rid}.{toolSettings.ToolPackageVersion}";
156156
var package = packages.FirstOrDefault(p => p.EndsWith(packageName + ".nupkg"));
157-
packages.Should().NotBeNull($"Package {packageName} should be present in the tool packages directory");
157+
package.Should().NotBeNull($"Package {packageName} should be present in the tool packages directory");
158158
}
159159

160160
// top-level package should declare all of the rids
@@ -170,6 +170,53 @@ public void PackagesMultipleToolsWithASingleInvocation()
170170
.Select(e => (e as XElement)!.Attributes().First(a => a.Name == "RuntimeIdentifier").Value);
171171
packageNodes.Should().BeEquivalentTo(expectedRids, "The top-level package should declare all of the RIDs for the tools it contains");
172172
}
173+
174+
[Fact]
175+
public void PackagesMultipleTrimmedToolsWithASingleInvocation()
176+
{
177+
var toolSettings = new TestToolBuilder.TestToolSettings()
178+
{
179+
Trimmed = true
180+
};
181+
string toolPackagesPath = ToolBuilder.CreateTestTool(Log, toolSettings);
182+
183+
var packages = Directory.GetFiles(toolPackagesPath, "*.nupkg");
184+
var packageIdentifier = toolSettings.ToolPackageId;
185+
var expectedRids = ToolsetInfo.LatestRuntimeIdentifiers.Split(';');
186+
187+
packages.Length.Should().Be(expectedRids.Length + 1, "There should be one package for the tool-wrapper and one for each RID");
188+
foreach (string rid in expectedRids)
189+
{
190+
var packageName = $"{toolSettings.ToolPackageId}.{rid}.{toolSettings.ToolPackageVersion}";
191+
var package = packages.FirstOrDefault(p => p.EndsWith(packageName + ".nupkg"));
192+
package.Should().NotBeNull($"Package {packageName} should be present in the tool packages directory");
193+
EnsurePackageLacksTrimmedDependency(package!, "System.Xml.dll");
194+
}
195+
196+
// top-level package should declare all of the rids
197+
var topLevelPackage = packages.First(p => p.EndsWith($"{packageIdentifier}.{toolSettings.ToolPackageVersion}.nupkg"));
198+
using var zipArchive = ZipFile.OpenRead(topLevelPackage);
199+
var nuspecEntry = zipArchive.GetEntry($"tools/{ToolsetInfo.CurrentTargetFramework}/any/DotnetToolSettings.xml")!;
200+
var stream = nuspecEntry.Open();
201+
var xml = XDocument.Load(stream, LoadOptions.None);
202+
var packageNodes =
203+
(xml.Root!.Nodes()
204+
.First(n => n is XElement e && e.Name == "RuntimeIdentifierPackages") as XElement)!.Nodes()
205+
.Where(n => (n as XElement)!.Name == "RuntimeIdentifierPackage")
206+
.Select(e => (e as XElement)!.Attributes().First(a => a.Name == "RuntimeIdentifier").Value);
207+
packageNodes.Should().BeEquivalentTo(expectedRids, "The top-level package should declare all of the RIDs for the tools it contains");
208+
}
209+
210+
/// <summary>
211+
/// Opens the nupkg and verifies that it does not contain a dependency on the given dll.
212+
/// </summary>
213+
private void EnsurePackageLacksTrimmedDependency(string packagePath, string dll)
214+
{
215+
using var zipArchive = ZipFile.OpenRead(packagePath);
216+
zipArchive.Entries.Should().NotContain(
217+
e => e.FullName.EndsWith(dll, StringComparison.OrdinalIgnoreCase),
218+
$"The package {Path.GetFileName(packagePath)} should not contain a dependency on {dll}.");
219+
}
173220
}
174221

175222
static class EndToEndToolTestExtensions

test/Microsoft.DotNet.PackageInstall.Tests/TestToolBuilder.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ public class TestToolSettings
3434

3535
public bool NativeAOT { get; set; } = false;
3636
public bool SelfContained { get; set; } = false;
37+
public bool Trimmed { get; set; } = false;
3738

38-
public string GetIdentifier() => $"{ToolPackageId}-{ToolPackageVersion}-{ToolCommandName}-{(NativeAOT ? "nativeaot" : SelfContained ? "selfcontained" : "managed")}";
39+
public string GetIdentifier() => $"{ToolPackageId}-{ToolPackageVersion}-{ToolCommandName}-{(NativeAOT ? "nativeaot" : SelfContained ? "selfcontained" : Trimmed ? "trimmed" : "managed")}";
3940
}
4041

4142

@@ -66,6 +67,12 @@ public string CreateTestTool(ITestOutputHelper log, TestToolSettings toolSetting
6667
testProject.AdditionalProperties["RuntimeIdentifiers"] = ToolsetInfo.LatestRuntimeIdentifiers;
6768
}
6869

70+
if (toolSettings.Trimmed)
71+
{
72+
testProject.AdditionalProperties["PublishTrimmed"] = "true";
73+
testProject.AdditionalProperties["RuntimeIdentifiers"] = ToolsetInfo.LatestRuntimeIdentifiers;
74+
}
75+
6976
testProject.SourceFiles.Add("Program.cs", "Console.WriteLine(\"Hello Tool!\");");
7077

7178
var testAssetManager = new TestAssetsManager(log);

0 commit comments

Comments
 (0)