Skip to content

Commit 7d95f55

Browse files
authored
Update ProcessFrameworkReferences and ResolveAppHosts to not look for runtime-specific assets for the any RID (#50421)
1 parent aaa06cc commit 7d95f55

File tree

7 files changed

+94
-14
lines changed

7 files changed

+94
-14
lines changed

src/Tasks/Microsoft.NET.Build.Tasks/DependencyContextBuilder.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public DependencyContextBuilder(
112112
runtimeIdentifier,
113113
string.IsNullOrWhiteSpace(platformLibraryName));
114114

115-
_isPortable = _isFrameworkDependent && string.IsNullOrEmpty(_runtimeIdentifier);
115+
_isPortable = _isFrameworkDependent && (string.IsNullOrEmpty(_runtimeIdentifier) || _runtimeIdentifier == "any");
116116

117117
if (_isFrameworkDependent != true || _isPortable != true)
118118
{
@@ -317,7 +317,7 @@ public DependencyContext Build(string[] userRuntimeAssemblies = null)
317317
* 1. If runtimeAssemblyGroups, nativeLibraryGroups, dependencies, and resourceAssemblies are all empty, remove this runtimeLibrary as well as any dependencies on it.
318318
* 2. Add all runtimeLibraries to a list of to-be-processed libraries called libraryCandidatesForRemoval
319319
* 3. libraryCandidatesForRemoval.Pop() --> if there are no runtimeAssemblyGroups, nativeLibraryGroups, or resourceAssemblies, and either dependencies is empty or all
320-
* dependencies have something else that depends on them, remove it (and from libraryCandidatesForRemoval), adding everything that depends on this to
320+
* dependencies have something else that depends on them, remove it (and from libraryCandidatesForRemoval), adding everything that depends on this to
321321
* libraryCandidatesForRemoval if it isn't already there
322322
* Repeat 3 until libraryCandidatesForRemoval is empty
323323
*/
@@ -483,8 +483,8 @@ public DependencyContext Build(string[] userRuntimeAssemblies = null)
483483
runtimeSignature: string.Empty,
484484
_isPortable);
485485

486-
// Compute the runtime fallback graph
487-
//
486+
// Compute the runtime fallback graph
487+
//
488488
// If the input RuntimeGraph is empty, or we're not compiling
489489
// for a specific RID, then an runtime fallback graph is empty
490490
//

src/Tasks/Microsoft.NET.Build.Tasks/GenerateDepsFile.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ public class GenerateDepsFile : TaskBase
3131

3232
public string RuntimeIdentifier { get; set; }
3333

34+
/// <summary>
35+
/// Strips the RID if it's any, because that's not reasonable
36+
/// </summary>
37+
private string EffectiveRuntimeIdentifier => string.IsNullOrEmpty(RuntimeIdentifier) ? null : RuntimeIdentifier == "any" ? null : RuntimeIdentifier;
38+
3439
public string PlatformLibraryName { get; set; }
3540

3641
public ITaskItem[] RuntimeFrameworks { get; set; }
@@ -95,7 +100,7 @@ public class GenerateDepsFile : TaskBase
95100

96101
public bool IncludeProjectsNotInAssetsFile { get; set; }
97102

98-
// List of runtime identifer (platform part only) to validate for runtime assets
103+
// List of runtime identifier (platform part only) to validate for runtime assets
99104
// If set, the task will warn on any RIDs that aren't in the list
100105
public string[] ValidRuntimeIdentifierPlatformsForAssets { get; set; }
101106

@@ -137,7 +142,7 @@ private void WriteDepsFile(string depsFilePath)
137142
LockFile lockFile = new LockFileCache(this).GetLockFile(AssetsFilePath);
138143
projectContext = lockFile.CreateProjectContext(
139144
TargetFramework,
140-
RuntimeIdentifier,
145+
EffectiveRuntimeIdentifier,
141146
PlatformLibraryName,
142147
RuntimeFrameworks,
143148
IsSelfContained);
@@ -226,7 +231,7 @@ bool ShouldIncludeRuntimeAsset(ITaskItem item)
226231
RuntimeFrameworks,
227232
isSelfContained: IsSelfContained,
228233
platformLibraryName: PlatformLibraryName,
229-
runtimeIdentifier: RuntimeIdentifier,
234+
runtimeIdentifier: EffectiveRuntimeIdentifier,
230235
targetFramework: TargetFramework);
231236
}
232237

src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public static ProjectContext CreateProjectContext(
9494
public static bool IsFrameworkDependent(ITaskItem[] runtimeFrameworks, bool isSelfContained, string runtimeIdentifier, bool hasPlatformLibrary)
9595
{
9696
return (hasPlatformLibrary || runtimeFrameworks?.Any() == true) &&
97-
(!isSelfContained || string.IsNullOrEmpty(runtimeIdentifier));
97+
(!isSelfContained || (string.IsNullOrEmpty(runtimeIdentifier) || runtimeIdentifier == "any"));
9898
}
9999

100100
public static LockFileTargetLibrary GetLibrary(this LockFileTarget lockFileTarget, string libraryName)

src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ out List<KnownRuntimePack> knownRuntimePacksForTargetFramework
335335
var runtimeRequiredByDeployment
336336
= (SelfContained || ReadyToRunEnabled) &&
337337
!string.IsNullOrEmpty(RuntimeIdentifier) &&
338+
RuntimeIdentifier != "any" &&
338339
selectedRuntimePack != null &&
339340
!string.IsNullOrEmpty(selectedRuntimePack.Value.RuntimePackNamePatterns);
340341

@@ -372,6 +373,13 @@ var runtimeRequiredByDeployment
372373
continue;
373374
}
374375

376+
if (runtimeIdentifier == "any")
377+
{
378+
// The `any` RID represents a platform-agnostic target. As such, it has no
379+
// platform-specific runtime pack associated with it.
380+
continue;
381+
}
382+
375383
// Pass in null for the runtimePacks list, as for these runtime identifiers we only want to
376384
// download the runtime packs, but not use the assets from them
377385
ProcessRuntimeIdentifier(runtimeIdentifier, runtimePackForRuntimeIDProcessing, runtimePackVersion, additionalFrameworkReferencesForRuntimePack: null,

src/Tasks/Microsoft.NET.Build.Tasks/ResolveAppHosts.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@ protected override void ExecuteCore()
188188
{
189189
foreach (var otherRuntimeIdentifier in OtherRuntimeIdentifiers)
190190
{
191+
// The 'any' RID represents a platform-agnostic platform. As such, it has no
192+
// apphost pack associated with it.
193+
if (otherRuntimeIdentifier == "any")
194+
{
195+
continue;
196+
}
197+
191198
// Download any apphost packages for other runtime identifiers.
192199
// This allows you to specify the list of RIDs in RuntimeIdentifiers and only restore once,
193200
// and then build for each RuntimeIdentifier without restoring separately.

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

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,9 @@ public void PackageToolWithAnyRid()
261261
.And.Satisfy<string>(EnsureFddPackageHasAllRuntimeAssets);
262262

263263
// top-level package should declare all of the rids
264-
var topLevelPackage = packages.First(p => p.EndsWith($"{packageIdentifier}.{toolSettings.ToolPackageVersion}.nupkg"));
265-
var settingsXml = GetToolSettingsFile(topLevelPackage);
266-
var packageNodes = GetRidsInSettingsFile(settingsXml);
267-
268-
packageNodes.Should().BeEquivalentTo([.. expectedRids, "any"], "The top-level package should declare all of the RIDs for the tools it contains");
264+
var topLevelPackage = packages.FirstOrDefault(p => p.EndsWith($"{packageIdentifier}.{toolSettings.ToolPackageVersion}.nupkg"));
265+
topLevelPackage.Should().NotBeNull($"Package {packageIdentifier}.{toolSettings.ToolPackageVersion}.nupkg should be present in the tool packages directory")
266+
.And.Satisfy<string>(SupportAllOfTheseRuntimes([.. expectedRids, "any"]));
269267
}
270268

271269
[Fact]
@@ -354,6 +352,45 @@ public void StripsPackageTypesFromInnerToolPackages()
354352
foundRids.Should().BeEquivalentTo(expectedRids, "The top-level package should declare all of the RIDs for the tools it contains");
355353
}
356354

355+
[Fact]
356+
public void MixedPackageTypesBuildInASingleBatchSuccessfully()
357+
{
358+
var toolSettings = new TestToolBuilder.TestToolSettings()
359+
{
360+
RidSpecific = true,
361+
IncludeAnyRid = true,
362+
SelfContained = true // ensure that the RID-specific packages get runtime packs/assets - but the any RID package does not!
363+
};
364+
string toolPackagesPath = ToolBuilder.CreateTestTool(Log, toolSettings, collectBinlogs: true);
365+
366+
var packages = Directory.GetFiles(toolPackagesPath, "*.nupkg");
367+
var packageIdentifier = toolSettings.ToolPackageId;
368+
var ridSpecificPackages = ToolsetInfo.LatestRuntimeIdentifiers.Split(';');
369+
packages.Length.Should().Be(ridSpecificPackages.Length + 1 + 1, "There should be one package for the tool-wrapper and one for each RID, and one for the any rid");
370+
foreach (string rid in ridSpecificPackages)
371+
{
372+
var packageName = $"{toolSettings.ToolPackageId}.{rid}.{toolSettings.ToolPackageVersion}";
373+
var package = packages.FirstOrDefault(p => p.EndsWith(packageName + ".nupkg"));
374+
package.Should()
375+
.NotBeNull($"Package {packageName} should be present in the tool packages directory")
376+
.And.Satisfy<string>(EnsurePackageIsAnExecutable)
377+
.And.Satisfy<string>(EnsurePackageOnlyHasToolRidPackageType);
378+
}
379+
380+
var agnosticFallbackPackageId = $"{toolSettings.ToolPackageId}.any.{toolSettings.ToolPackageVersion}";
381+
var agnosticFallbackPackage = packages.FirstOrDefault(p => p.EndsWith(agnosticFallbackPackageId + ".nupkg"));
382+
agnosticFallbackPackage.Should()
383+
.NotBeNull($"Package {agnosticFallbackPackageId} should be present in the tool packages directory")
384+
.And.Satisfy<string>(EnsurePackageIsFdd)
385+
.And.Satisfy<string>(EnsurePackageOnlyHasToolRidPackageType);
386+
387+
// top-level package should declare all of the rids
388+
var topLevelPackage = packages.First(p => p.EndsWith($"{packageIdentifier}.{toolSettings.ToolPackageVersion}.nupkg"));
389+
topLevelPackage.Should().NotBeNull($"Package {packageIdentifier}.{toolSettings.ToolPackageVersion}.nupkg should be present in the tool packages directory")
390+
.And.Satisfy<string>(EnsurePackageHasNoRunner)
391+
.And.Satisfy(SupportAllOfTheseRuntimes([..ridSpecificPackages, "any"]));
392+
}
393+
357394
private Action<string> EnsurePackageHasToolPackageTypeAnd(string[] additionalPackageTypes) => (string packagePath) =>
358395
{
359396
var nuspec = GetPackageNuspec(packagePath);
@@ -364,6 +401,13 @@ private Action<string> EnsurePackageHasToolPackageTypeAnd(string[] additionalPac
364401
.And.BeEquivalentTo(expectedPackageTypes, "The PackageType should be 'DotnetTool'.");
365402
};
366403

404+
private Action<string> SupportAllOfTheseRuntimes(string[] runtimes) => (string packagePath) =>
405+
{
406+
var settingsXml = GetToolSettingsFile(packagePath);
407+
var rids = GetRidsInSettingsFile(settingsXml);
408+
rids.Should().BeEquivalentTo(runtimes, "The tool settings file should contain all of the specified RuntimeIdentifierPackage elements.");
409+
};
410+
367411
static void EnsurePackageOnlyHasToolRidPackageType(string packagePath)
368412
{
369413
var nuspec = GetPackageNuspec(packagePath);

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,28 @@ public class TestToolSettings
2828
public string ToolPackageVersion { get; set; } = "1.0.0";
2929
public string ToolCommandName { get; set; } = "TestTool";
3030
public string[]? AdditionalPackageTypes { get; set; } = null;
31-
3231
public bool NativeAOT { get; set { field = value; this.RidSpecific = value; } } = false;
3332
public bool SelfContained { get; set { field = value; this.RidSpecific = value; } } = false;
3433
public bool Trimmed { get; set { field = value; this.RidSpecific = value; } } = false;
34+
35+
/// <summary>
36+
/// If set, the generated tool will include the <c>any</c> RID in the list of RIDs to target.
37+
/// This will cause a framework-dependent, platform-agnostic package to be created.
38+
/// </summary>
3539
public bool IncludeAnyRid { get; set { field = value; } } = false;
40+
41+
/// <summary>
42+
/// If set, the generated tool will target all of the RIDs specified in <see cref="ToolsetInfo.LatestRuntimeIdentifiers"/>.
43+
/// Defaults to <see langword="false"/>.
44+
/// </summary>
3645
public bool RidSpecific { get; set; } = false;
46+
47+
/// <summary>
48+
/// If set, the generated tool will include the current executing platform's RID in the list of RIDs to target
49+
/// (which is otherwise made of <see cref="ToolsetInfo.LatestRuntimeIdentifiers"/>.) If set to <see langword="false"/>,
50+
/// the current RID will be stripped from that set.
51+
/// Defaults to <see langword="true"/>.
52+
/// </summary>
3753
public bool IncludeCurrentRid { get; set; } = true;
3854

3955
public string GetIdentifier() {

0 commit comments

Comments
 (0)