From 3b271570f75971a094461fba2cbe62d737df696e Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Sat, 23 Nov 2019 09:54:18 -0800 Subject: [PATCH 1/2] fix update powershell feature on windows --- src/features/UpdatePowerShell.ts | 76 +++++++++++++++++++++----------- src/process.ts | 4 +- src/session.ts | 1 + src/utils.ts | 8 ++-- 4 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/features/UpdatePowerShell.ts b/src/features/UpdatePowerShell.ts index 5252e11f65..9f3d468221 100644 --- a/src/features/UpdatePowerShell.ts +++ b/src/features/UpdatePowerShell.ts @@ -2,13 +2,23 @@ * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ +import { spawn } from "child_process"; +import * as fs from "fs"; import fetch, { RequestInit } from "node-fetch"; +import * as os from "os"; +import * as path from "path"; import * as semver from "semver"; -import { MessageItem, window } from "vscode"; +import * as stream from "stream"; +import * as util from "util"; +import { MessageItem, ProgressLocation, window } from "vscode"; import { LanguageClient } from "vscode-languageclient"; +import { SessionManager } from "../session"; import * as Settings from "../settings"; +import { isMacOS, isWindows } from "../utils"; import { EvaluateRequestType } from "./Console"; +const streamPipeline = util.promisify(stream.pipeline); + const PowerShellGitHubReleasesUrl = "https://api.github.com/repos/PowerShell/PowerShell/releases/latest"; const PowerShellGitHubPrereleasesUrl = @@ -67,6 +77,7 @@ interface IUpdateMessageItem extends MessageItem { } export async function InvokePowerShellUpdateCheck( + sessionManager: SessionManager, languageServerClient: LanguageClient, localVersion: semver.SemVer, arch: string, @@ -103,7 +114,6 @@ export async function InvokePowerShellUpdateCheck( return; } - const isMacOS: boolean = process.platform === "darwin"; const result = await window.showInformationMessage( `${commonText} Would you like to update the version? ${ isMacOS ? "(Homebrew is required on macOS)" : "" @@ -116,39 +126,55 @@ export async function InvokePowerShellUpdateCheck( switch (result.id) { // Yes choice. case 0: - let script: string; - if (process.platform === "win32") { + if (isWindows) { const msiMatcher = arch === "x86" ? "win-x86.msi" : "win-x64.msi"; - const assetUrl = release.assets.filter((asset: any) => - asset.name.indexOf(msiMatcher) >= 0)[0].browser_download_url; - - // Grab MSI and run it. - // tslint:disable-next-line: max-line-length - script = ` -$randomFileName = [System.IO.Path]::GetRandomFileName() -$tmpMsiPath = Microsoft.PowerShell.Management\\Join-Path ([System.IO.Path]::GetTempPath()) "$randomFileName.msi" -Microsoft.PowerShell.Utility\\Invoke-RestMethod -Uri ${assetUrl} -OutFile $tmpMsiPath -try -{ - Microsoft.PowerShell.Management\\Start-Process -Wait -Path $tmpMsiPath -} -finally -{ - Microsoft.PowerShell.Management\\Remove-Item $tmpMsiPath -}`; + const asset = release.assets.filter((a: any) => a.name.indexOf(msiMatcher) >= 0)[0]; + const msiDownloadPath = path.join(os.tmpdir(), asset.name); + + const res = await fetch(asset.browser_download_url); + if (!res.ok) { + throw new Error("unable to fetch MSI"); + } + + await window.withProgress({ + title: "Downloading PowerShell Installer...", + location: ProgressLocation.Notification, + cancellable: false, + }, + async () => { + // Streams the body of the request to a file. + await streamPipeline(res.body, fs.createWriteStream(msiDownloadPath)); + }); + + // Stop the Integrated Console session because Windows likes to hold on to files. + sessionManager.stop(); + + // Invoke the MSI via cmd. + const msi = spawn("cmd", [`/S /C ${msiDownloadPath}`], { + detached: true, + cwd: os.homedir(), + env: process.env, + }); + + msi.on("close", (code) => { + // Now that the MSI is finished, start the Integrated Console session. + sessionManager.start(); + fs.unlinkSync(msiDownloadPath); + }); } else if (isMacOS) { - script = "brew cask upgrade powershell"; + let script = "brew cask upgrade powershell"; if (release.isPreview) { script = "brew cask upgrade powershell-preview"; } + + await languageServerClient.sendRequest(EvaluateRequestType, { + expression: script, + }); } - await languageServerClient.sendRequest(EvaluateRequestType, { - expression: script, - }); break; // Never choice. diff --git a/src/process.ts b/src/process.ts index 051da88488..d3d9a660ca 100644 --- a/src/process.ts +++ b/src/process.ts @@ -69,7 +69,7 @@ export class PowerShellProcess { ]; // Only add ExecutionPolicy param on Windows - if (utils.isWindowsOS()) { + if (utils.isWindows) { powerShellArgs.push("-ExecutionPolicy", "Bypass"); } @@ -77,7 +77,7 @@ export class PowerShellProcess { PowerShellProcess.escapeSingleQuotes(startScriptPath) + "' " + this.startArgs; - if (utils.isWindowsOS()) { + if (utils.isWindows) { powerShellArgs.push( "-Command", startEditorServices); diff --git a/src/session.ts b/src/session.ts index 7b4e5cb6b8..5a2cd3a6ac 100644 --- a/src/session.ts +++ b/src/session.ts @@ -546,6 +546,7 @@ export class SessionManager implements Middleware { await GitHubReleaseInformation.FetchLatestRelease(isPreRelease); await InvokePowerShellUpdateCheck( + this, this.languageServerClient, localVersion, this.versionDetails.architecture, diff --git a/src/utils.ts b/src/utils.ts index 8604c26deb..57527cf529 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -8,7 +8,7 @@ import fs = require("fs"); import os = require("os"); import path = require("path"); -export let PowerShellLanguageId = "powershell"; +export const PowerShellLanguageId = "powershell"; export function ensurePathExists(targetPath: string) { // Ensure that the path exists @@ -116,6 +116,6 @@ export function getTimestampString() { return `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}]`; } -export function isWindowsOS(): boolean { - return os.platform() === "win32"; -} +export const isMacOS: boolean = process.platform === "darwin"; +export const isWindows: boolean = process.platform === "win32"; +export const isLinux: boolean = !isMacOS && !isWindows; From e3bff17fd51a67efb725348997647ff27bb02bb4 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Mon, 25 Nov 2019 22:15:17 -0800 Subject: [PATCH 2/2] PR feedback --- src/features/UpdatePowerShell.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/features/UpdatePowerShell.ts b/src/features/UpdatePowerShell.ts index 9f3d468221..ba33673063 100644 --- a/src/features/UpdatePowerShell.ts +++ b/src/features/UpdatePowerShell.ts @@ -152,11 +152,7 @@ export async function InvokePowerShellUpdateCheck( sessionManager.stop(); // Invoke the MSI via cmd. - const msi = spawn("cmd", [`/S /C ${msiDownloadPath}`], { - detached: true, - cwd: os.homedir(), - env: process.env, - }); + const msi = spawn("msiexec", ["/i", msiDownloadPath]); msi.on("close", (code) => { // Now that the MSI is finished, start the Integrated Console session. @@ -165,10 +161,9 @@ export async function InvokePowerShellUpdateCheck( }); } else if (isMacOS) { - let script = "brew cask upgrade powershell"; - if (release.isPreview) { - script = "brew cask upgrade powershell-preview"; - } + const script = release.isPreview + ? "brew cask upgrade powershell-preview" + : "brew cask upgrade powershell"; await languageServerClient.sendRequest(EvaluateRequestType, { expression: script,