Skip to content

aspire ls dedupes settings vs walk using case-sensitive comparison on macOS #17635

@adamint

Description

@adamint

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions