Skip to content

Commit

Permalink
Implementation of additional exe paths
Browse files Browse the repository at this point in the history
Fix #1243
  • Loading branch information
rkeithhill committed Apr 16, 2018
1 parent 9a363c7 commit 783752e
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 22 deletions.
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
36 changes: 25 additions & 11 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,19 +139,22 @@ 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())
.filter((item) => {
const exePath = path.join(item, "pwsh.exe");
return fs.lstatSync(item).isDirectory() && fs.existsSync(exePath);
})
.map((item) => {
let exePath = path.join(item, "pwsh.exe");
if (!fs.existsSync(exePath)) {
exePath = path.join(item, "powershell.exe");
}

const exePath = path.join(item, "pwsh.exe");
return {
versionName: `PowerShell Core ${path.parse(item).base}`,
versionName: `PowerShell Core ${path.parse(item).base} ${arch}`,
exePath,
};
});
Expand All @@ -162,11 +164,23 @@ export function getAvailablePowerShellExes(platformDetails: IPlatformDetails): I
}
}
} 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);
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 ||
"").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();
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
3 changes: 2 additions & 1 deletion test/platform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import * as assert from "assert";
import * as vscode from "vscode";
import * as platform from "../src/platform";
import { SessionManager } from "../src/session";

function checkDefaultPowerShellPath(platformDetails, expectedPath) {
test("returns correct default path", () => {
Expand All @@ -21,7 +22,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

0 comments on commit 783752e

Please sign in to comment.