Skip to content

Teach client to find Homebrew installations on Apple Silicon #5164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const SnapPreviewExePath = "/snap/bin/pwsh-preview";
const MacOSExePath = "/usr/local/bin/pwsh";
const MacOSPreviewExePath = "/usr/local/bin/pwsh-preview";

const MacOSHomebrewExePath = "/opt/homebrew/bin/pwsh";
const MacOSHomebrewLTSExePath = "/opt/homebrew/bin/pwsh-lts";
const MacOSHomebrewPreviewExePath = "/opt/homebrew/bin/pwsh-preview";

export enum OperatingSystem {
Unknown,
Windows,
Expand Down Expand Up @@ -169,6 +173,7 @@ export class PowerShellExeFinder {
* Iterates through all the possible well-known PowerShell installations on a machine.
* Returned values may not exist, but come with an .exists property
* which will check whether the executable exists.
* TODO: We really need to define the order in which we search for stable/LTS/preview/daily
*/
private async *enumerateDefaultPowerShellInstallations(): AsyncIterable<IPossiblePowerShellExe | undefined> {
// Find PSCore stable first
Expand All @@ -183,10 +188,14 @@ export class PowerShellExeFinder {
case OperatingSystem.Windows:
// Windows may have a 32-bit pwsh.exe
yield this.findPSCoreWindowsInstallation({ useAlternateBitness: true });

// Also look for the MSIX/UWP installation
yield await this.findPSCoreMsix();
break;

case OperatingSystem.MacOS:
// On MacOS, find the Homebrew installations
yield this.findPSCoreHomebrewStable();
yield this.findPSCoreHomebrewLTS();
break;
}

Expand Down Expand Up @@ -220,6 +229,11 @@ export class PowerShellExeFinder {
yield this.findWinPS({ useAlternateBitness: true });

break;

case OperatingSystem.MacOS:
// On MacOS, find the Homebrew preview
yield this.findPSCoreHomebrewPreview();
break;
}

// Look for PSCore daily
Expand Down Expand Up @@ -336,6 +350,8 @@ export class PowerShellExeFinder {
* if ($Daily) {
* $Destination = "${Destination}-daily"
* }
*
* TODO: Remove this after the daily is officially no longer supported.
*/
private findPSCoreDaily(): IPossiblePowerShellExe | undefined {
switch (this.platformDetails.operatingSystem) {
Expand All @@ -359,6 +375,19 @@ export class PowerShellExeFinder {
}
}

// The Homebrew installations of PowerShell on Apple Silicon are no longer in the default PATH.
private findPSCoreHomebrewStable(): IPossiblePowerShellExe {
return new PossiblePowerShellExe(MacOSHomebrewExePath, "PowerShell (Homebrew)");
}

private findPSCoreHomebrewLTS(): IPossiblePowerShellExe {
return new PossiblePowerShellExe(MacOSHomebrewLTSExePath, "PowerShell LTS (Homebrew)");
}

private findPSCoreHomebrewPreview(): IPossiblePowerShellExe {
return new PossiblePowerShellExe(MacOSHomebrewPreviewExePath, "PowerShell Preview (Homebrew)");
}

private findPSCoreDotnetGlobalTool(): IPossiblePowerShellExe {
const exeName: string = this.platformDetails.operatingSystem === OperatingSystem.Windows
? "pwsh.exe"
Expand Down Expand Up @@ -398,6 +427,7 @@ export class PowerShellExeFinder {
return undefined;
}

// TODO: Are snaps still a thing?
private findPSCoreStableSnap(): IPossiblePowerShellExe {
return new PossiblePowerShellExe(SnapExePath, "PowerShell Snap");
}
Expand Down
20 changes: 20 additions & 0 deletions test/core/platform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,11 +595,26 @@ if (process.platform === "win32") {
displayName: "PowerShell",
supportsProperArguments: true
},
{
exePath: "/opt/homebrew/bin/pwsh",
displayName: "PowerShell (Homebrew)",
supportsProperArguments: true
},
{
exePath: "/opt/homebrew/bin/pwsh-lts",
displayName: "PowerShell LTS (Homebrew)",
supportsProperArguments: true
},
{
exePath: "/usr/local/bin/pwsh-preview",
displayName: "PowerShell Preview",
supportsProperArguments: true
},
{
exePath: "/opt/homebrew/bin/pwsh-preview",
displayName: "PowerShell Preview (Homebrew)",
supportsProperArguments: true
},
{
exePath: path.join(pwshDailyDir, "pwsh"),
displayName: "PowerShell Daily",
Expand All @@ -611,6 +626,11 @@ if (process.platform === "win32") {
"pwsh": "",
"pwsh-preview": "",
},
"/opt/homebrew/bin/": {
"pwsh": "",
"pwsh-lts": "",
"pwsh-preview": "",
},
[pwshDailyDir]: {
"pwsh": ""
}
Expand Down