Skip to content

Commit 2529cf7

Browse files
committed
Ensure correct runner is chosen
1 parent ee24868 commit 2529cf7

File tree

3 files changed

+108
-36
lines changed

3 files changed

+108
-36
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ NOTE: This file is imported from the following contexts, so be aware when writin
189189
</PropertyGroup>
190190

191191
<PropertyGroup Condition="'$(ToolCommandRunner)' == ''">
192-
<ToolCommandRunner>dotnet</ToolCommandRunner>
193-
<ToolCommandRunner Condition="'$(SelfContained)' == 'true'">executable</ToolCommandRunner>
192+
<ToolCommandRunner Condition="!$(UseAppHost)">dotnet</ToolCommandRunner>
193+
<ToolCommandRunner Condition="$(UseAppHost)">executable</ToolCommandRunner>
194194
</PropertyGroup>
195195

196196
<Target Name="_GenerateToolsSettingsFileInputCache">

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

Lines changed: 89 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public void InstallAndRunNativeAotGlobalTool()
4949
{
5050
NativeAOT = true
5151
};
52-
string toolPackagesPath = ToolBuilder.CreateTestTool(Log, toolSettings);
52+
string toolPackagesPath = ToolBuilder.CreateTestTool(Log, toolSettings, collectBinlogs: true);
5353

5454
var testDirectory = _testAssetsManager.CreateTestDirectory();
5555

@@ -138,10 +138,9 @@ public void InstallAndRunNativeAotLocalTool()
138138
[Fact]
139139
public void PackagesMultipleToolsWithASingleInvocation()
140140
{
141-
142141
var toolSettings = new TestToolBuilder.TestToolSettings()
143142
{
144-
SelfContained = true
143+
RidSpecific = true
145144
};
146145
string toolPackagesPath = ToolBuilder.CreateTestTool(Log, toolSettings);
147146

@@ -154,21 +153,15 @@ public void PackagesMultipleToolsWithASingleInvocation()
154153
{
155154
var packageName = $"{toolSettings.ToolPackageId}.{rid}.{toolSettings.ToolPackageVersion}";
156155
var package = packages.FirstOrDefault(p => p.EndsWith(packageName + ".nupkg"));
157-
package.Should().NotBeNull($"Package {packageName} should be present in the tool packages directory");
156+
package.Should()
157+
.NotBeNull($"Package {packageName} should be present in the tool packages directory")
158+
.And.Satisfy<string>(EnsurePackageIsAnExecutable);
158159
}
159160

160161
// top-level package should declare all of the rids
161162
var topLevelPackage = packages.First(p => p.EndsWith($"{packageIdentifier}.{toolSettings.ToolPackageVersion}.nupkg"));
162-
using var zipArchive = ZipFile.OpenRead(topLevelPackage);
163-
var nuspecEntry = zipArchive.GetEntry($"tools/{ToolsetInfo.CurrentTargetFramework}/any/DotnetToolSettings.xml")!;
164-
var stream = nuspecEntry.Open();
165-
var xml = XDocument.Load(stream, LoadOptions.None);
166-
var packageNodes =
167-
(xml.Root!.Nodes()
168-
.First(n => n is XElement e && e.Name == "RuntimeIdentifierPackages") as XElement)!.Nodes()
169-
.Where(n => (n as XElement)!.Name == "RuntimeIdentifierPackage")
170-
.Select(e => (e as XElement)!.Attributes().First(a => a.Name == "RuntimeIdentifier").Value);
171-
packageNodes.Should().BeEquivalentTo(expectedRids, "The top-level package should declare all of the RIDs for the tools it contains");
163+
var foundRids = GetRidsInSettingsFile(topLevelPackage);
164+
foundRids.Should().BeEquivalentTo(expectedRids, "The top-level package should declare all of the RIDs for the tools it contains");
172165
}
173166

174167
[Fact]
@@ -189,22 +182,94 @@ public void PackagesMultipleTrimmedToolsWithASingleInvocation()
189182
{
190183
var packageName = $"{toolSettings.ToolPackageId}.{rid}.{toolSettings.ToolPackageVersion}";
191184
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");
185+
package.Should()
186+
.NotBeNull($"Package {packageName} should be present in the tool packages directory")
187+
.And.Satisfy<string>(EnsurePackageIsAnExecutable)
188+
.And.Satisfy((string package) => EnsurePackageLacksTrimmedDependency(package, "System.Xml.dll"));
194189
}
195190

196191
// top-level package should declare all of the rids
197192
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()
193+
var foundRids = GetRidsInSettingsFile(topLevelPackage);
194+
foundRids.Should().BeEquivalentTo(expectedRids, "The top-level package should declare all of the RIDs for the tools it contains");
195+
}
196+
197+
[Fact]
198+
public void PackagesFrameworkDependentRidSpecificPackagesCorrectly()
199+
{
200+
var toolSettings = new TestToolBuilder.TestToolSettings()
201+
{
202+
RidSpecific = true,
203+
};
204+
string toolPackagesPath = ToolBuilder.CreateTestTool(Log, toolSettings, collectBinlogs: true);
205+
206+
var packages = Directory.GetFiles(toolPackagesPath, "*.nupkg");
207+
var packageIdentifier = toolSettings.ToolPackageId;
208+
var expectedRids = ToolsetInfo.LatestRuntimeIdentifiers.Split(';');
209+
210+
packages.Length.Should().Be(expectedRids.Length + 1, "There should be one package for the tool-wrapper and one for each RID");
211+
foreach (string rid in expectedRids)
212+
{
213+
var packageName = $"{toolSettings.ToolPackageId}.{rid}.{toolSettings.ToolPackageVersion}";
214+
var package = packages.FirstOrDefault(p => p.EndsWith(packageName + ".nupkg"));
215+
package.Should()
216+
.NotBeNull($"Package {packageName} should be present in the tool packages directory")
217+
.And.Satisfy<string>(EnsurePackageIsAnExecutable);
218+
}
219+
220+
// top-level package should declare all of the rids
221+
var topLevelPackage = packages.First(p => p.EndsWith($"{packageIdentifier}.{toolSettings.ToolPackageVersion}.nupkg"));
222+
var foundRids = GetRidsInSettingsFile(topLevelPackage);
223+
foundRids.Should().BeEquivalentTo(expectedRids, "The top-level package should declare all of the RIDs for the tools it contains");
224+
}
225+
226+
227+
private void EnsurePackageIsFdd(string packagePath)
228+
{
229+
var settingsXml = GetToolSettingsFile(packagePath);
230+
var runner = GetRunnerFromSettingsFile(settingsXml);
231+
runner.Should().Be("dotnet", "The tool should be packaged as a framework-dependent executable (FDD) with a 'dotnet' runner.");
232+
}
233+
234+
private void EnsurePackageIsAnExecutable(string packagePath)
235+
{
236+
var settingsXml = GetToolSettingsFile(packagePath);
237+
var runner = GetRunnerFromSettingsFile(settingsXml);
238+
runner.Should().Be("executable", "The tool should be packaged as a executable with an 'executable' runner.");
239+
}
240+
241+
private object GetRunnerFromSettingsFile(XElement settingsXml)
242+
{
243+
return settingsXml.Elements("Commands").First().Elements("Command").First().Attribute("Runner")?.Value
244+
?? throw new InvalidOperationException("The tool settings file does not contain a 'Runner' attribute.");
245+
}
246+
247+
private string[] GetRidsInSettingsFile(string packagePath)
248+
{
249+
var settingsXml = GetToolSettingsFile(packagePath);
250+
var rids = GetRidsInSettingsFile(settingsXml);
251+
rids.Should().NotBeEmpty("The tool settings file should contain at least one RuntimeIdentifierPackage element.");
252+
return rids;
253+
}
254+
255+
private string[] GetRidsInSettingsFile(XElement settingsXml)
256+
{
257+
var nodes = (settingsXml.Nodes()
204258
.First(n => n is XElement e && e.Name == "RuntimeIdentifierPackages") as XElement)!.Nodes()
205259
.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");
260+
.Select(e => (e as XElement)!.Attributes().First(a => a.Name == "RuntimeIdentifier").Value)
261+
.ToArray();
262+
return nodes;
263+
}
264+
265+
private XElement GetToolSettingsFile(string packagePath)
266+
{
267+
using var zipArchive = ZipFile.OpenRead(packagePath);
268+
var nuspecEntry = zipArchive.Entries.First(e => e.Name == "DotnetToolSettings.xml")!;
269+
var stream = nuspecEntry.Open();
270+
var xml = XDocument.Load(stream, LoadOptions.None);
271+
return xml.Root!;
272+
208273
}
209274

210275
/// <summary>

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,17 @@ public class TestToolSettings
3232
public string ToolPackageVersion { get; set; } = "1.0.0";
3333
public string ToolCommandName { get; set; } = "TestTool";
3434

35-
public bool NativeAOT { get; set; } = false;
36-
public bool SelfContained { get; set; } = false;
37-
public bool Trimmed { get; set; } = false;
35+
public bool NativeAOT { get; set { field = value; this.RidSpecific = value; } } = false;
36+
public bool SelfContained { get; set { field = value; this.RidSpecific = value; } } = false;
37+
public bool Trimmed { get; set { field = value; this.RidSpecific = value; } } = false;
38+
public bool IncludeAnyRid { get; set { field = value; this.RidSpecific = value; } } = false;
39+
public bool RidSpecific { get; set; } = false;
3840

39-
public string GetIdentifier() => $"{ToolPackageId}-{ToolPackageVersion}-{ToolCommandName}-{(NativeAOT ? "nativeaot" : SelfContained ? "selfcontained" : Trimmed ? "trimmed" : "managed")}";
41+
public string GetIdentifier() => $"{ToolPackageId}-{ToolPackageVersion}-{ToolCommandName}-{(NativeAOT ? "nativeaot" : SelfContained ? "selfcontained" : Trimmed ? "trimmed" : "managed")}{(RidSpecific ? "-specific" : "")}{(IncludeAnyRid ? "-anyrid" : "")}";
4042
}
4143

4244

43-
public string CreateTestTool(ITestOutputHelper log, TestToolSettings toolSettings)
45+
public string CreateTestTool(ITestOutputHelper log, TestToolSettings toolSettings, bool collectBinlogs = false)
4446
{
4547
var targetDirectory = Path.Combine(TestContext.Current.TestExecutionDirectory, "TestTools", toolSettings.GetIdentifier());
4648

@@ -55,22 +57,27 @@ public string CreateTestTool(ITestOutputHelper log, TestToolSettings toolSetting
5557
testProject.AdditionalProperties["ImplicitUsings"] = "enable";
5658
testProject.AdditionalProperties["Version"] = toolSettings.ToolPackageVersion;
5759

60+
var singleRid = RuntimeInformation.RuntimeIdentifier;
61+
var multiRid = toolSettings.IncludeAnyRid ? $"{ToolsetInfo.LatestRuntimeIdentifiers};any" : ToolsetInfo.LatestRuntimeIdentifiers;
62+
63+
if (toolSettings.RidSpecific)
64+
{
65+
testProject.AdditionalProperties["RuntimeIdentifiers"] = multiRid;
66+
}
67+
5868
if (toolSettings.NativeAOT)
5969
{
6070
testProject.AdditionalProperties["PublishAot"] = "true";
61-
testProject.AdditionalProperties["RuntimeIdentifiers"] = RuntimeInformation.RuntimeIdentifier;
6271
}
6372

6473
if (toolSettings.SelfContained)
6574
{
6675
testProject.AdditionalProperties["SelfContained"] = "true";
67-
testProject.AdditionalProperties["RuntimeIdentifiers"] = ToolsetInfo.LatestRuntimeIdentifiers;
6876
}
6977

7078
if (toolSettings.Trimmed)
7179
{
7280
testProject.AdditionalProperties["PublishTrimmed"] = "true";
73-
testProject.AdditionalProperties["RuntimeIdentifiers"] = ToolsetInfo.LatestRuntimeIdentifiers;
7481
}
7582

7683
testProject.SourceFiles.Add("Program.cs", "Console.WriteLine(\"Hello Tool!\");");
@@ -101,15 +108,15 @@ public string CreateTestTool(ITestOutputHelper log, TestToolSettings toolSetting
101108
{
102109
new DotnetPackCommand(log)
103110
.WithWorkingDirectory(targetDirectory)
104-
.Execute()
111+
.Execute(collectBinlogs ? $"--bl:{toolSettings.GetIdentifier()}-{{}}" : "")
105112
.Should().Pass();
106113

107114
if (toolSettings.NativeAOT)
108115
{
109116
// For Native AOT tools, we need to repack the tool to include the runtime-specific files that were generated during publish
110117
new DotnetPackCommand(log, "-r", RuntimeInformation.RuntimeIdentifier)
111118
.WithWorkingDirectory(targetDirectory)
112-
.Execute()
119+
.Execute(collectBinlogs ? $"--bl:{toolSettings.GetIdentifier()}-{RuntimeInformation.RuntimeIdentifier}-{{}}" : "")
113120
.Should().Pass();
114121
}
115122

0 commit comments

Comments
 (0)