Background
PR #17631 (L5 from #17626) added symlink-aware dedupe between the apphost path declared in aspire.config.json / .aspire/settings.json and the path produced by the recursive workspace walk in aspire ls. The dedupe currently uses OperatingSystem.IsWindows() ? OrdinalIgnoreCase : Ordinal (same comparison code as before the PR; #17626 only added symlink canonicalization on top).
Bug
macOS APFS is case-insensitive by default. If the user authored the settings path with different casing than the actual on-disk filename, e.g.
{ "appHost": { "path": "$WS/APPHOST.csproj" } }
…while the discovery walk surfaces $WS/AppHost.csproj, aspire ls shows two rows for the same file:
│ /private/var/.../AppHost.csproj │ csharp │ possibly-unbuildable │
│ /var/.../APPHOST.csproj │ csharp │ possibly-unbuildable │
Both paths refer to the same inode on the file system, so they should dedupe.
Repro
WS=$(mktemp -d)
echo '<Project/>' > "$WS/AppHost.csproj"
cat > "$WS/aspire.config.json" <<EOF
{ "appHost": { "path": "$WS/APPHOST.csproj" } }
EOF
cd "$WS"
aspire ls
Proposed fix
Extend the case-insensitive comparison to macOS as well — APFS is case-insensitive by default and case-sensitive APFS volumes are rare. PathNormalizer.ResolveSymlinks could also be extended to normalize on-disk casing via DirectoryInfo.EnumerateFileSystemInfos lookup if a more precise per-volume check is needed.
var pathComparison = OperatingSystem.IsWindows() || OperatingSystem.IsMacOS()
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
Notes
Background
PR #17631 (L5 from #17626) added symlink-aware dedupe between the apphost path declared in
aspire.config.json/.aspire/settings.jsonand the path produced by the recursive workspace walk inaspire ls. The dedupe currently usesOperatingSystem.IsWindows() ? OrdinalIgnoreCase : Ordinal(same comparison code as before the PR; #17626 only added symlink canonicalization on top).Bug
macOS APFS is case-insensitive by default. If the user authored the settings path with different casing than the actual on-disk filename, e.g.
{ "appHost": { "path": "$WS/APPHOST.csproj" } }…while the discovery walk surfaces
$WS/AppHost.csproj,aspire lsshows two rows for the same file:Both paths refer to the same inode on the file system, so they should dedupe.
Repro
Proposed fix
Extend the case-insensitive comparison to macOS as well — APFS is case-insensitive by default and case-sensitive APFS volumes are rare.
PathNormalizer.ResolveSymlinkscould also be extended to normalize on-disk casing viaDirectoryInfo.EnumerateFileSystemInfoslookup if a more precise per-volume check is needed.Notes
aspire lsbugs from #17620 (L1–L5) #17631) — the same comparison code lived inAddSettingsAppHostCandidateAsyncbefore the L5 fix.aspire lsbugs from #17620 (L1–L5) #17631 for edge cases. Filing as low-priority follow-up rather than expanding Fix fiveaspire lsbugs from #17620 (L1–L5) #17631 scope.aspire lsbugs from #17620 (L1–L5) #17631).