diff --git a/src/DiffEngine.Tests/BundledViewerRidTests.cs b/src/DiffEngine.Tests/BundledViewerRidTests.cs new file mode 100644 index 00000000..6b6efd8b --- /dev/null +++ b/src/DiffEngine.Tests/BundledViewerRidTests.cs @@ -0,0 +1,36 @@ +#if NET10_0 +/// +/// Which RIDs the bundled viewer is probed for. +/// +/// The framework's own RID comes first, and on Alpine that is linux-musl-x64, which the package +/// does not ship - so the probe is supposed to miss and the caller falls through to the dotnet +/// tool. The synthesised linux-{arch} that followed it undid that, because it names the glibc +/// build, and resolving one against musl hands back an apphost that cannot start. +/// +/// +public class BundledViewerRidTests +{ + [Test] + [Arguments("linux-musl-x64")] + [Arguments("linux-musl-arm64")] + public async Task MuslProbesItsOwnRidAndNothingElse(string runtimeIdentifier) + { + var rids = BundledViewerDirectory.Rids(runtimeIdentifier).ToList(); + + await Assert.That(rids).IsEquivalentTo([runtimeIdentifier]); + } + + /// + /// Everywhere else the synthesised RID still follows, which is what makes the probe work when + /// the framework reports something the package does not ship under that exact name. + /// + [Test] + public async Task GlibcStillFallsBackToTheSynthesisedRid() + { + var rids = BundledViewerDirectory.Rids("linux-x64").ToList(); + + await Assert.That(rids.Count).IsGreaterThan(1); + await Assert.That(rids[0]).IsEqualTo("linux-x64"); + } +} +#endif diff --git a/src/DiffEngine/Viewer/BundledViewerDirectory.cs b/src/DiffEngine/Viewer/BundledViewerDirectory.cs index 8f108f3e..abda2325 100644 --- a/src/DiffEngine/Viewer/BundledViewerDirectory.cs +++ b/src/DiffEngine/Viewer/BundledViewerDirectory.cs @@ -80,13 +80,30 @@ static class BundledViewerDirectory } #endif - static IEnumerable Rids() - { + static IEnumerable Rids() => #if NET6_0_OR_GREATER + Rids(RuntimeInformation.RuntimeIdentifier); + + internal static IEnumerable Rids(string runtimeIdentifier) + { // The framework's own value first. On Alpine that is linux-musl-x64, a RID we do not // ship, so the probe misses and the caller falls through to the dotnet tool rather than // resolving a glibc build against musl. - yield return RuntimeInformation.RuntimeIdentifier; + yield return runtimeIdentifier; + + // And nothing else, or the synthesised RID below undoes that: linux-{arch} is the glibc + // build, so on musl the probe would hit after all and hand back an apphost that cannot + // start. Falling through to the dotnet tool is the outcome the comment above describes and + // was not what happened + if (runtimeIdentifier.Contains("-musl-", StringComparison.Ordinal)) + { + yield break; + } +#else + InnerRids(); + + static IEnumerable InnerRids() + { #endif var architecture = RuntimeInformation.OSArchitecture switch