Skip to content

Implementation of additional exe paths #1270

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 2 commits into from
Apr 18, 2018
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
27 changes: 27 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,33 @@
"isExecutable": true,
"description": "Specifies the full path to a PowerShell executable. Changes the installation of PowerShell used for language and debugging services."
},
"powershell.powerShellAdditionalExePaths": {
"type":"array",
"description": "Specifies an array of versionName / exePath pairs where exePath points to a non-standard install location for PowerShell and versionName can be used to reference this path with the powershell.powerShellDefaultVersion setting.",
"isExecutable": true,
"uniqueItems": true,
"items": {
"type": "object",
"required":[
"versionName",
"exePath"
],
"properties": {
"versionName": {
"type":"string",
"description": "Specifies the version name of this PowerShell executable. The version name can be referenced via the powershell.powerShellDefaultVersion setting."
},
"exePath": {
"type":"string",
"description": "Specifies the path to the PowerShell executable. Typically this is a path to a non-standard install location."
}
}
}
},
"powershell.powerShellDefaultVersion": {
"type":"string",
"description": "Specifies the name of the PowerShell version used in the startup session when the extension loads e.g \"Windows PowerShell (x86)\" or \"PowerShell Core 6.0.2 (x64)\"."
},
"powershell.startAutomatically": {
"type": "boolean",
"default": true,
Expand Down
43 changes: 27 additions & 16 deletions src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,13 @@ export function fixWindowsPowerShellPath(powerShellExePath: string, platformDeta
return powerShellExePath;
}

export function getAvailablePowerShellExes(platformDetails: IPlatformDetails): IPowerShellExeDetails[] {
export function getAvailablePowerShellExes(
platformDetails: IPlatformDetails,
sessionSettings: Settings.ISettings | undefined): IPowerShellExeDetails[] {

let paths: IPowerShellExeDetails[] = [];

if (platformDetails.operatingSystem === OperatingSystem.Windows) {
const psCoreInstallPath =
(!platformDetails.isProcess64Bit ? process.env.ProgramW6432 : process.env.ProgramFiles) + "\\PowerShell";

if (platformDetails.isProcess64Bit) {
paths.push({
versionName: WindowsPowerShell64BitLabel,
Expand All @@ -140,33 +139,45 @@ export function getAvailablePowerShellExes(platformDetails: IPlatformDetails): I
});
}

const psCoreInstallPath =
(!platformDetails.isProcess64Bit ? process.env.ProgramW6432 : process.env.ProgramFiles) + "\\PowerShell";

if (fs.existsSync(psCoreInstallPath)) {
const arch = platformDetails.isProcess64Bit ? "(x64)" : "(x86)";
const psCorePaths =
fs.readdirSync(psCoreInstallPath)
.map((item) => path.join(psCoreInstallPath, item))
.filter((item) => fs.lstatSync(item).isDirectory())
.map((item) => {
let exePath = path.join(item, "pwsh.exe");
if (!fs.existsSync(exePath)) {
exePath = path.join(item, "powershell.exe");
}

return {
versionName: `PowerShell Core ${path.parse(item).base}`,
exePath,
};
});
.filter((item) => {
const exePath = path.join(item, "pwsh.exe");
return fs.lstatSync(item).isDirectory() && fs.existsSync(exePath);
})
.map((item) => ({
versionName: `PowerShell Core ${path.parse(item).base} ${arch}`,
exePath: path.join(item, "pwsh.exe"),
}));

if (psCorePaths) {
paths = paths.concat(psCorePaths);
}
}
} else {
// Handle Linux and macOS case
paths.push({
versionName: "PowerShell Core",
exePath: this.getDefaultPowerShellPath(platformDetails),
});
}

// When unit testing, we don't have session settings to test so skip reading this setting
if (sessionSettings) {
// Add additional PowerShell paths as configured in settings
for (const additionalPowerShellExePath of sessionSettings.powerShellAdditionalExePaths) {
paths.push({
versionName: additionalPowerShellExePath.versionName,
exePath: additionalPowerShellExePath.exePath,
});
}
}

return paths;
}
50 changes: 40 additions & 10 deletions src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
getPlatformDetails, IPlatformDetails, OperatingSystem } from "./platform";

export enum SessionStatus {
NeverStarted,
NotStarted,
Initializing,
Running,
Expand All @@ -40,7 +41,7 @@ export class SessionManager implements Middleware {
private hostVersion: string;
private editorServicesArgs: string;
private powerShellExePath: string = "";
private sessionStatus: SessionStatus;
private sessionStatus: SessionStatus = SessionStatus.NeverStarted;
private suppressRestartPrompt: boolean;
private focusConsoleOnExecute: boolean;
private platformDetails: IPlatformDetails;
Expand Down Expand Up @@ -246,6 +247,7 @@ export class SessionManager implements Middleware {
}

public getPowerShellExePath(): string {
let powerShellExePath: string;

if (!this.sessionSettings.powerShellExePath &&
this.sessionSettings.developer.powerShellExePath) {
Expand Down Expand Up @@ -280,11 +282,27 @@ export class SessionManager implements Middleware {
});
}

// If powershell.powerShellDefaultVersion specified, attempt to find the PowerShell exe path
// of the version specified by the setting.
if ((this.sessionStatus === SessionStatus.NeverStarted) && this.sessionSettings.powerShellDefaultVersion) {
const powerShellExePaths = getAvailablePowerShellExes(this.platformDetails, this.sessionSettings);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm going crazy but where is getAvailablePowerShellExes defined? I see it's in platform.ts but not it session.ts. How is being called here?

I trust it works, but I'm just curious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's imported from platform.ts on line 25.

const powerShellDefaultVersion =
powerShellExePaths.find((item) => item.versionName === this.sessionSettings.powerShellDefaultVersion);

if (powerShellDefaultVersion) {
powerShellExePath = powerShellDefaultVersion.exePath;
} else {
this.log.writeWarning(
`Could not find powerShellDefaultVersion: '${this.sessionSettings.powerShellDefaultVersion}'`);
}
}

// Is there a setting override for the PowerShell path?
let powerShellExePath =
(this.sessionSettings.powerShellExePath ||
this.sessionSettings.developer.powerShellExePath ||
"").trim();
powerShellExePath =
(powerShellExePath ||
this.sessionSettings.powerShellExePath ||
this.sessionSettings.developer.powerShellExePath ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is for backcompat?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check for this.sessionSettings.developer.powerShellExePath is for back compat. For 2.0, I say we remove the setting and this fallback.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming it's a fallback? Should the developer path come before the other one, or is the intent to need to blank out the normal path to get the dev one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah back in the day it was called this.sessionSettings.developer.powerShellExePath that was changed to this.sessionSettings.powerShellExePath. Now Keith is changing that. Since VSCode doesn't notify when a setting has become deprecated (AFAIK) we support them as fallback until we want to remove support.

Keith, I totally agree v2 should remove this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I "think" the only change I made was to use the value of powerShellExePath if and only if it has already been set by the code above. If not, then we look in the same settings with the same fallback order as before. And the code above this will only ever set powerShellExePath on the initial startup of the extension and only if the setting powerShellDefaultVersion has been set.

"").trim();

// New versions of PS Core uninstall the previous version
// so make sure the path stored in the settings exists.
Expand Down Expand Up @@ -718,12 +736,25 @@ export class SessionManager implements Middleware {
private showSessionMenu() {
let menuItems: SessionMenuItem[] = [];

const currentExePath = (this.powerShellExePath || "").toLowerCase();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is SUPER nitpicky (I'm sorry) but is there a reason this line comes before the getAvailablePowerShellExes call instead of closer to where it's first used in this function (aka between 743-744 after the if vs where it is now)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries. I could move it below availablePowerShellExes but availablePowerShellExes is referenced before currentExePath. And both are used outside the if/else if statement

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahhh I see it below now. No need to change it.

const availablePowerShellExes =
getAvailablePowerShellExes(this.platformDetails, this.sessionSettings);

if (this.sessionStatus === SessionStatus.Running) {
const currentPowerShellExe =
availablePowerShellExes
.find((item) => item.exePath.toLowerCase() === currentExePath);

const powerShellSessionName =
currentPowerShellExe ?
currentPowerShellExe.versionName :
`PowerShell ${this.versionDetails.displayVersion} ` +
`(${this.versionDetails.architecture}) ${this.versionDetails.edition} Edition ` +
`[${this.versionDetails.version}]`;

menuItems = [
new SessionMenuItem(
`Current session: PowerShell ${this.versionDetails.displayVersion} ` +
`(${this.versionDetails.architecture}) ${this.versionDetails.edition} Edition ` +
`[${this.versionDetails.version}]`,
`Current session: ${powerShellSessionName}`,
() => { vscode.commands.executeCommand("PowerShell.ShowLogs"); }),

new SessionMenuItem(
Expand All @@ -738,9 +769,8 @@ export class SessionManager implements Middleware {
];
}

const currentExePath = (this.powerShellExePath || "").toLowerCase();
const powerShellItems =
getAvailablePowerShellExes(this.platformDetails)
availablePowerShellExes
.filter((item) => item.exePath.toLowerCase() !== currentExePath)
.map((item) => {
return new SessionMenuItem(
Expand Down
11 changes: 11 additions & 0 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ enum CodeFormattingPreset {
Stroustrup,
}

export interface IPowerShellAdditionalExePathSettings {
versionName: string;
exePath: string;
}

export interface IBugReportingSettings {
project: string;
}
Expand Down Expand Up @@ -50,6 +55,8 @@ export interface IDeveloperSettings {
}

export interface ISettings {
powerShellAdditionalExePaths?: IPowerShellAdditionalExePathSettings[];
powerShellDefaultVersion?: string;
powerShellExePath?: string;
startAutomatically?: boolean;
useX86Host?: boolean;
Expand Down Expand Up @@ -115,6 +122,10 @@ export function load(): ISettings {
return {
startAutomatically:
configuration.get<boolean>("startAutomatically", true),
powerShellAdditionalExePaths:
configuration.get<IPowerShellAdditionalExePathSettings[]>("powerShellAdditionalExePaths", undefined),
powerShellDefaultVersion:
configuration.get<string>("powerShellDefaultVersion", undefined),
powerShellExePath:
configuration.get<string>("powerShellExePath", undefined),
useX86Host:
Expand Down
2 changes: 1 addition & 1 deletion test/platform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function checkAvailableWindowsPowerShellPaths(

// The system may return PowerShell Core paths so only
// enumerate the first list items.
const enumeratedPaths = platform.getAvailablePowerShellExes(platformDetails);
const enumeratedPaths = platform.getAvailablePowerShellExes(platformDetails, undefined);
for (let i; i < expectedPaths.length; i++) {
assert.equal(enumeratedPaths[i], expectedPaths[i]);
}
Expand Down