From 0af30e350c5f69508ff2448708a4a1a794ef0304 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Tue, 23 Apr 2019 18:27:23 -0700 Subject: [PATCH 1/9] Switch to using the installExtension command for offline/insider vsix installing --- Extension/src/LanguageServer/extension.ts | 107 +--------------------- Extension/src/githubAPI.ts | 14 ++- 2 files changed, 12 insertions(+), 109 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 8d1f63207..ce88ef28c 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -417,111 +417,6 @@ function onInterval(): void { clients.ActiveClient.onInterval(); } -/** - * Install a VSIX package. This helper function will exist until VSCode offers a command to do so. - * @param updateChannel The user's updateChannel setting. - */ -function installVsix(vsixLocation: string, updateChannel: string): Promise { - // Get the path to the VSCode command -- replace logic later when VSCode allows calling of - // workbench.extensions.action.installVSIX from TypeScript w/o instead popping up a file dialog - return PlatformInformation.GetPlatformInformation().then((platformInfo) => { - const vsCodeScriptPath: string = function(platformInfo): string { - if (platformInfo.platform === 'win32') { - const vsCodeBinName: string = path.basename(process.execPath); - let cmdFile: string; // Windows VS Code Insiders/Exploration breaks VS Code naming conventions - if (vsCodeBinName === 'Code - Insiders.exe') { - cmdFile = 'code-insiders.cmd'; - } else if (vsCodeBinName === 'Code - Exploration.exe') { - cmdFile = 'code-exploration.cmd'; - } else { - cmdFile = 'code.cmd'; - } - const vsCodeExeDir: string = path.dirname(process.execPath); - return path.join(vsCodeExeDir, 'bin', cmdFile); - } else if (platformInfo.platform === 'darwin') { - return path.join(process.execPath, '..', '..', '..', '..', '..', - 'Resources', 'app', 'bin', 'code'); - } else { - const vsCodeBinName: string = path.basename(process.execPath); - try { - const stdout: Buffer = execSync('which ' + vsCodeBinName); - return stdout.toString().trim(); - } catch (error) { - return undefined; - } - } - }(platformInfo); - if (!vsCodeScriptPath) { - return Promise.reject(new Error('Failed to find VS Code script')); - } - - // 1.28.0 changes the CLI for making installations - let userVersion: PackageVersion = new PackageVersion(vscode.version); - let breakingVersion: PackageVersion = new PackageVersion('1.28.0'); - if (userVersion.isGreaterThan(breakingVersion, 'insider')) { - return new Promise((resolve, reject) => { - let process: ChildProcess; - try { - process = spawn(vsCodeScriptPath, ['--install-extension', vsixLocation, '--force']); - - // Timeout the process if no response is sent back. Ensures this Promise resolves/rejects - const timer: NodeJS.Timer = setTimeout(() => { - process.kill(); - reject(new Error('Failed to receive response from VS Code script process for installation within 30s.')); - }, 30000); - - process.on('exit', (code: number) => { - clearInterval(timer); - if (code !== 0) { - reject(new Error(`VS Code script exited with error code ${code}`)); - } else { - resolve(); - } - }); - if (process.pid === undefined) { - throw new Error(); - } - } catch (error) { - reject(new Error('Failed to launch VS Code script process for installation')); - return; - } - }); - } - - return new Promise((resolve, reject) => { - let process: ChildProcess; - try { - process = spawn(vsCodeScriptPath, ['--install-extension', vsixLocation]); - if (process.pid === undefined) { - throw new Error(); - } - } catch (error) { - reject(new Error('Failed to launch VS Code script process for installation')); - return; - } - - // Timeout the process if no response is sent back. Ensures this Promise resolves/rejects - const timer: NodeJS.Timer = setTimeout(() => { - process.kill(); - reject(new Error('Failed to receive response from VS Code script process for installation within 30s.')); - }, 30000); - - // If downgrading, the VS Code CLI will prompt whether the user is sure they would like to downgrade. - // Respond to this by writing 0 to stdin (the option to override and install the VSIX package) - let sentOverride: boolean = false; - process.stdout.on('data', () => { - if (sentOverride) { - return; - } - process.stdin.write('0\n'); - sentOverride = true; - clearInterval(timer); - resolve(); - }); - }); - }); -} - async function suggestInsidersChannel(): Promise { let suggestInsiders: PersistentState = new PersistentState("CPP.suggestInsiders", true); @@ -601,7 +496,7 @@ function applyUpdate(buildInfo: BuildInfo, updateChannel: string): Promise break; } try { - await installVsix(vsixPath, updateChannel); + await vscode.commands.executeCommand('workbench.extensions.installExtension', vscode.Uri.file(vsixPath)); } catch (error) { reject(error); return; diff --git a/Extension/src/githubAPI.ts b/Extension/src/githubAPI.ts index 646d7ea9f..c9173b7eb 100644 --- a/Extension/src/githubAPI.ts +++ b/Extension/src/githubAPI.ts @@ -124,6 +124,11 @@ export interface BuildInfo { name: string; } +/** + * Set this hook to true to force an update, to test the update flow. + */ +let testUpdateFlow: boolean = false; + /** * Use the GitHub API to retrieve the download URL of the extension version the user should update to, if any. * @param updateChannel The user's updateChannel setting. @@ -141,8 +146,11 @@ export async function getTargetBuildInfo(updateChannel: string): Promise Date: Wed, 24 Apr 2019 10:16:31 -0700 Subject: [PATCH 2/9] Remove superfluous test hook --- Extension/src/githubAPI.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Extension/src/githubAPI.ts b/Extension/src/githubAPI.ts index c9173b7eb..646d7ea9f 100644 --- a/Extension/src/githubAPI.ts +++ b/Extension/src/githubAPI.ts @@ -124,11 +124,6 @@ export interface BuildInfo { name: string; } -/** - * Set this hook to true to force an update, to test the update flow. - */ -let testUpdateFlow: boolean = false; - /** * Use the GitHub API to retrieve the download URL of the extension version the user should update to, if any. * @param updateChannel The user's updateChannel setting. @@ -146,11 +141,8 @@ export async function getTargetBuildInfo(updateChannel: string): Promise Date: Wed, 24 Apr 2019 10:18:54 -0700 Subject: [PATCH 3/9] Upgrade vscode dependency to 1.33.0 --- Extension/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/package.json b/Extension/package.json index 0348d9f4a..87ff30a8d 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -12,7 +12,7 @@ }, "license": "SEE LICENSE IN LICENSE.txt", "engines": { - "vscode": "^1.30.0" + "vscode": "^1.33.0" }, "bugs": { "url": "https://github.com/Microsoft/vscode-cpptools/issues", From aefc35fcb63cd5f528826d3e53cdea85a3225bb4 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Wed, 24 Apr 2019 12:45:57 -0700 Subject: [PATCH 4/9] Remove unused imports --- Extension/src/LanguageServer/extension.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index ce88ef28c..f3d2f78fb 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -17,13 +17,11 @@ import { CppSettings } from './settings'; import { PersistentWorkspaceState, PersistentState } from './persistentState'; import { getLanguageConfig } from './languageConfig'; import { getCustomConfigProviders } from './customProviders'; -import { PlatformInformation } from '../platform'; import { Range } from 'vscode-languageclient'; import { ChildProcess, spawn, execSync } from 'child_process'; import * as tmp from 'tmp'; import { getTargetBuildInfo, BuildInfo } from '../githubAPI'; import * as configs from './configurations'; -import { PackageVersion } from '../packageVersion'; import { getTemporaryCommandRegistrarInstance } from '../commands'; let prevCrashFile: string; From a94b41984ab1ee90b57af4dd2e2be9ead32a5bbf Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Thu, 25 Apr 2019 17:06:13 -0700 Subject: [PATCH 5/9] Work in progress --- Extension/src/LanguageServer/extension.ts | 114 +++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index f3d2f78fb..c6758b2ad 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -415,6 +415,118 @@ function onInterval(): void { clients.ActiveClient.onInterval(); } +/** + * Install a VSIX package. This helper function will exist until VSCode offers a command to do so. + * @param updateChannel The user's updateChannel setting. + */ +function installVsix(vsixLocation: string, updateChannel: string): Promise { + let userVersion: PackageVersion = new PackageVersion(vscode.version); + + // 1.33.0 introduces workbench.extensions.installExtension + let versionWithInstallVsixCommand: PackageVersion = new PackageVersion('1.33.0'); + if (userVersion.isGreaterThan(versionWithInstallVsixCommand, 'insider')) { + return vscode.commands.executeCommand('workbench.extensions.installExtension', vscode.Uri.file(vsixLocation)); + } + + // Get the path to the VSCode command -- replace logic later when VSCode allows calling of + // workbench.extensions.action.installVSIX from TypeScript w/o instead popping up a file dialog + return PlatformInformation.GetPlatformInformation().then((platformInfo) => { + const vsCodeScriptPath: string = function(platformInfo): string { + if (platformInfo.platform === 'win32') { + const vsCodeBinName: string = path.basename(process.execPath); + let cmdFile: string; // Windows VS Code Insiders/Exploration breaks VS Code naming conventions + if (vsCodeBinName === 'Code - Insiders.exe') { + cmdFile = 'code-insiders.cmd'; + } else if (vsCodeBinName === 'Code - Exploration.exe') { + cmdFile = 'code-exploration.cmd'; + } else { + cmdFile = 'code.cmd'; + } + const vsCodeExeDir: string = path.dirname(process.execPath); + return path.join(vsCodeExeDir, 'bin', cmdFile); + } else if (platformInfo.platform === 'darwin') { + return path.join(process.execPath, '..', '..', '..', '..', '..', + 'Resources', 'app', 'bin', 'code'); + } else { + const vsCodeBinName: string = path.basename(process.execPath); + try { + const stdout: Buffer = execSync('which ' + vsCodeBinName); + return stdout.toString().trim(); + } catch (error) { + return undefined; + } + } + }(platformInfo); + if (!vsCodeScriptPath) { + return Promise.reject(new Error('Failed to find VS Code script')); + } + + // 1.28.0 changes the CLI for making installations + let breakingVersion: PackageVersion = new PackageVersion('1.28.0'); + if (userVersion.isGreaterThan(breakingVersion, 'insider')) { + return new Promise((resolve, reject) => { + let process: ChildProcess; + try { + process = spawn(vsCodeScriptPath, ['--install-extension', vsixLocation, '--force']); + + // Timeout the process if no response is sent back. Ensures this Promise resolves/rejects + const timer: NodeJS.Timer = setTimeout(() => { + process.kill(); + reject(new Error('Failed to receive response from VS Code script process for installation within 30s.')); + }, 30000); + + process.on('exit', (code: number) => { + clearInterval(timer); + if (code !== 0) { + reject(new Error(`VS Code script exited with error code ${code}`)); + } else { + resolve(); + } + }); + if (process.pid === undefined) { + throw new Error(); + } + } catch (error) { + reject(new Error('Failed to launch VS Code script process for installation')); + return; + } + }); + } + + return new Promise((resolve, reject) => { + let process: ChildProcess; + try { + process = spawn(vsCodeScriptPath, ['--install-extension', vsixLocation]); + if (process.pid === undefined) { + throw new Error(); + } + } catch (error) { + reject(new Error('Failed to launch VS Code script process for installation')); + return; + } + + // Timeout the process if no response is sent back. Ensures this Promise resolves/rejects + const timer: NodeJS.Timer = setTimeout(() => { + process.kill(); + reject(new Error('Failed to receive response from VS Code script process for installation within 30s.')); + }, 30000); + + // If downgrading, the VS Code CLI will prompt whether the user is sure they would like to downgrade. + // Respond to this by writing 0 to stdin (the option to override and install the VSIX package) + let sentOverride: boolean = false; + process.stdout.on('data', () => { + if (sentOverride) { + return; + } + process.stdin.write('0\n'); + sentOverride = true; + clearInterval(timer); + resolve(); + }); + }); + }); +} + async function suggestInsidersChannel(): Promise { let suggestInsiders: PersistentState = new PersistentState("CPP.suggestInsiders", true); @@ -494,7 +606,7 @@ function applyUpdate(buildInfo: BuildInfo, updateChannel: string): Promise break; } try { - await vscode.commands.executeCommand('workbench.extensions.installExtension', vscode.Uri.file(vsixPath)); + await installVsix(vsixPath, updateChannel); } catch (error) { reject(error); return; From e54e6ec47a1a88737f64a4f1f5a0bcbcc9f18692 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Thu, 25 Apr 2019 17:33:42 -0700 Subject: [PATCH 6/9] Use version check at runtime --- Extension/src/LanguageServer/extension.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index c6758b2ad..b56d73287 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -17,11 +17,13 @@ import { CppSettings } from './settings'; import { PersistentWorkspaceState, PersistentState } from './persistentState'; import { getLanguageConfig } from './languageConfig'; import { getCustomConfigProviders } from './customProviders'; +import { PlatformInformation } from '../platform'; import { Range } from 'vscode-languageclient'; import { ChildProcess, spawn, execSync } from 'child_process'; import * as tmp from 'tmp'; import { getTargetBuildInfo, BuildInfo } from '../githubAPI'; import * as configs from './configurations'; +import { PackageVersion } from '../packageVersion'; import { getTemporaryCommandRegistrarInstance } from '../commands'; let prevCrashFile: string; @@ -419,12 +421,12 @@ function onInterval(): void { * Install a VSIX package. This helper function will exist until VSCode offers a command to do so. * @param updateChannel The user's updateChannel setting. */ -function installVsix(vsixLocation: string, updateChannel: string): Promise { +function installVsix(vsixLocation: string): Thenable { let userVersion: PackageVersion = new PackageVersion(vscode.version); // 1.33.0 introduces workbench.extensions.installExtension let versionWithInstallVsixCommand: PackageVersion = new PackageVersion('1.33.0'); - if (userVersion.isGreaterThan(versionWithInstallVsixCommand, 'insider')) { + if (userVersion.isGreaterThan(versionWithInstallVsixCommand)) { return vscode.commands.executeCommand('workbench.extensions.installExtension', vscode.Uri.file(vsixLocation)); } @@ -463,7 +465,7 @@ function installVsix(vsixLocation: string, updateChannel: string): Promise // 1.28.0 changes the CLI for making installations let breakingVersion: PackageVersion = new PackageVersion('1.28.0'); - if (userVersion.isGreaterThan(breakingVersion, 'insider')) { + if (userVersion.isGreaterThan(breakingVersion)) { return new Promise((resolve, reject) => { let process: ChildProcess; try { @@ -568,7 +570,7 @@ async function suggestInsidersChannel(): Promise { } } -function applyUpdate(buildInfo: BuildInfo, updateChannel: string): Promise { +function applyUpdate(buildInfo: BuildInfo): Promise { return new Promise((resolve, reject) => { tmp.file({postfix: '.vsix'}, async (err, vsixPath, fd, cleanupCallback) => { if (err) { @@ -606,7 +608,7 @@ function applyUpdate(buildInfo: BuildInfo, updateChannel: string): Promise break; } try { - await installVsix(vsixPath, updateChannel); + await installVsix(vsixPath); } catch (error) { reject(error); return; @@ -648,7 +650,7 @@ async function checkAndApplyUpdate(updateChannel: string): Promise { if (!buildInfo) { return; // No need to update. } - await applyUpdate(buildInfo, updateChannel); + await applyUpdate(buildInfo); } /********************************************* From a28207baad4449e710517a93f5fce37b6ac931aa Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Thu, 25 Apr 2019 17:35:04 -0700 Subject: [PATCH 7/9] Revert version dependency --- Extension/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/package.json b/Extension/package.json index 87ff30a8d..0348d9f4a 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -12,7 +12,7 @@ }, "license": "SEE LICENSE IN LICENSE.txt", "engines": { - "vscode": "^1.33.0" + "vscode": "^1.30.0" }, "bugs": { "url": "https://github.com/Microsoft/vscode-cpptools/issues", From 946620b9f610d8b31ef1d13a2146af692f5b76a4 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Thu, 25 Apr 2019 17:52:32 -0700 Subject: [PATCH 8/9] Fix use of PackageVersion.isGreaterThan --- Extension/src/LanguageServer/extension.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index b56d73287..f5c50453e 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -424,9 +424,9 @@ function onInterval(): void { function installVsix(vsixLocation: string): Thenable { let userVersion: PackageVersion = new PackageVersion(vscode.version); - // 1.33.0 introduces workbench.extensions.installExtension - let versionWithInstallVsixCommand: PackageVersion = new PackageVersion('1.33.0'); - if (userVersion.isGreaterThan(versionWithInstallVsixCommand)) { + // 1.33.0 introduces workbench.extensions.installExtension. 1.32.3 was immediately prior. + let lastVersionWithoutInstallExtensionCommand: PackageVersion = new PackageVersion('1.32.3'); + if (userVersion.isGreaterThan(lastVersionWithoutInstallExtensionCommand)) { return vscode.commands.executeCommand('workbench.extensions.installExtension', vscode.Uri.file(vsixLocation)); } @@ -463,8 +463,8 @@ function installVsix(vsixLocation: string): Thenable { return Promise.reject(new Error('Failed to find VS Code script')); } - // 1.28.0 changes the CLI for making installations - let breakingVersion: PackageVersion = new PackageVersion('1.28.0'); + // 1.28.0 changes the CLI for making installations. 1.27.2 was immediately prior. + let breakingVersion: PackageVersion = new PackageVersion('1.27.2'); if (userVersion.isGreaterThan(breakingVersion)) { return new Promise((resolve, reject) => { let process: ChildProcess; From fa13353b9a62ec9c6e0614a3eb31c1eaa6d9cd61 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson Date: Thu, 25 Apr 2019 17:56:02 -0700 Subject: [PATCH 9/9] Rename a variable --- Extension/src/LanguageServer/extension.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index f5c50453e..f24309ad2 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -464,8 +464,8 @@ function installVsix(vsixLocation: string): Thenable { } // 1.28.0 changes the CLI for making installations. 1.27.2 was immediately prior. - let breakingVersion: PackageVersion = new PackageVersion('1.27.2'); - if (userVersion.isGreaterThan(breakingVersion)) { + let oldVersion: PackageVersion = new PackageVersion('1.27.2'); + if (userVersion.isGreaterThan(oldVersion)) { return new Promise((resolve, reject) => { let process: ChildProcess; try {