From 9bc4d2f8871853f04f8190aa5951f524541dd9d1 Mon Sep 17 00:00:00 2001 From: Rajkumar Janakiraman Date: Thu, 9 Jun 2016 17:57:39 -0700 Subject: [PATCH 1/5] Adding pipeCwd to schema. (#415) * Adding pipeCwd to schema. * Adding pipeEnv. * Updating MIEngine and OpenDebugAD7 dependencies. --- package.json | 50 ++++++++++++++++++++++++++++++++++++++- src/coreclr-debug/main.ts | 4 ++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 1ab61fe6c4..7899f04b41 100644 --- a/package.json +++ b/package.json @@ -298,10 +298,16 @@ "type": "object", "description": "When present, this tells the debugger to connect to a remote computer using another executable as a pipe that will relay standard input/output between VS Code and the .NET Core debugger backend executable (clrdbg).", "default": { + "pipeCwd": "${workspaceRoot}", "pipeProgram": "enter the fully qualified path for the pipe program name, for example 'c:\\tools\\plink.exe'", "pipeArgs": [] }, "properties" : { + "pipeCwd": { + "type": "string", + "description": "The fully qualified path to the working directory for the pipe program.", + "default": "${workspaceRoot}" + }, "pipeProgram": { "type": "string", "description": "The fully qualified pipe command to execute.", @@ -315,14 +321,26 @@ }, "default": [] }, + "pipeEnv": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Environment variables passed to the pipe program.", + "default": { } + }, "windows": { "type": "object", "description": "Windows-specific pipe launch configuration options", "default": { + "pipeCwd": "${workspaceRoot}", "pipeProgram": "enter the fully qualified path for the pipe program name, for example 'c:\\tools\\plink.exe'", "pipeArgs": [] }, "properties": { + "pipeCwd": { + "type": "string", + "description": "The fully qualified path to the working directory for the pipe program.", + "default": "${workspaceRoot}" + }, "pipeProgram": { "type": "string", "description": "The fully qualified pipe command to execute.", @@ -335,6 +353,12 @@ "type": "string" }, "default": [] + }, + "pipeEnv": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Environment variables passed to the pipe program.", + "default": { } } } }, @@ -342,10 +366,16 @@ "type": "object", "description": "OSX-specific pipe launch configuration options", "default": { + "pipeCwd": "${workspaceRoot}", "pipeProgram": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'", "pipeArgs": [] }, "properties": { + "pipeCwd": { + "type": "string", + "description": "The fully qualified path to the working directory for the pipe program.", + "default": "${workspaceRoot}" + }, "pipeProgram": { "type": "string", "description": "The fully qualified pipe command to execute.", @@ -358,17 +388,29 @@ "type": "string" }, "default": [] - } + }, + "pipeEnv": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Environment variables passed to the pipe program.", + "default": { } + } } }, "linux": { "type": "object", "description": "Linux-specific pipe launch configuration options", "default": { + "pipeCwd": "${workspaceRoot}", "pipeProgram": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'", "pipeArgs": [] }, "properties": { + "pipeCwd": { + "type": "string", + "description": "The fully qualified path to the working directory for the pipe program.", + "default": "${workspaceRoot}" + }, "pipeProgram": { "type": "string", "description": "The fully qualified pipe command to execute.", @@ -381,6 +423,12 @@ "type": "string" }, "default": [] + }, + "pipeEnv": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Environment variables passed to the pipe program.", + "default": { } } } } diff --git a/src/coreclr-debug/main.ts b/src/coreclr-debug/main.ts index f8c77524c0..4fcc27c0d3 100644 --- a/src/coreclr-debug/main.ts +++ b/src/coreclr-debug/main.ts @@ -337,8 +337,8 @@ function createProjectJson(targetRuntime: string): any }, dependencies: { "Microsoft.VisualStudio.clrdbg": "14.0.25406-preview-3044032", - "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30606-preview-1", - "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20527-preview-1", + "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30610-preview-1", + "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20610-preview-3", "NETStandard.Library": "1.5.0-rc2-24027", "Newtonsoft.Json": "7.0.1", "Microsoft.VisualStudio.Debugger.Interop.Portable": "1.0.1", From 339348aca288545ca973119725a8ba9fd29a568c Mon Sep 17 00:00:00 2001 From: Chuck Ries Date: Fri, 3 Jun 2016 11:44:56 -0700 Subject: [PATCH 2/5] Add requireExactSource to launch.json schema --- package.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/package.json b/package.json index 7899f04b41..9bbd8e7389 100644 --- a/package.json +++ b/package.json @@ -294,6 +294,11 @@ }, "default": [] }, + "requireExactSource": { + "type": "boolean", + "description": "Optional flag to require current source code to match the pdb.", + "default": true + }, "pipeTransport": { "type": "object", "description": "When present, this tells the debugger to connect to a remote computer using another executable as a pipe that will relay standard input/output between VS Code and the .NET Core debugger backend executable (clrdbg).", @@ -467,6 +472,11 @@ "items": { "type": "string" }, + "requireExactSource": { + "type": "boolean", + "description": "Optional flag to require current source code to match the pdb.", + "default": true + }, "default": [] } } From dda3815218b769246a92a75b621fae66823a9d4f Mon Sep 17 00:00:00 2001 From: Gregg Miskelly Date: Tue, 14 Jun 2016 12:19:24 -0700 Subject: [PATCH 3/5] Update version to v1.1.6 (#437) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9bbd8e7389..ca834ebe98 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "csharp", "publisher": "ms-vscode", - "version": "1.1.5", + "version": "1.1.6", "description": "C# for Visual Studio Code (powered by OmniSharp).", "displayName": "C#", "author": "Microsoft Corporation", From 98fa4b91904d868417769f72f008c63608f8ce71 Mon Sep 17 00:00:00 2001 From: Gregg Miskelly Date: Tue, 14 Jun 2016 12:35:29 -0700 Subject: [PATCH 4/5] Merge offline VSIX work to master (#435) This checkin cherry-pick's commit 8b2cda1ba22c25f465889dff34ac73f34da88965 into master. As part of this, I changed the versions for debugger components in install.ts to match what the master branch was installing already. Original description: commit 8b2cda1ba22c25f465889dff34ac73f34da88965 Author: Chuck Ries Date: Mon Jun 6 14:41:53 2016 -0700 Implement task to create offline VSIX's This implements a gulp task that creates platform specific vsix's that do not require the secondary download/installation steps. 1. Refactor coreclr-debug/main.ts into activation.ts and install.ts 2. Remove VS Code specific modules from install.ts so that it can be called from gulp 3. Refactor omnisharpDownload.ts so that it has no VS Code dependencies and can be called from gulp task. 4. Create packaging gulp task that will perform the download of the debugger and omnisharp in place, package the extension, and clean it up. This repeats for as many platforms as we need to ship. --- .vscodeignore | 7 +- gulpfile.js | 141 ++++++++++-- src/coreclr-debug/activate.ts | 194 ++++++++++++++++ src/coreclr-debug/install.ts | 231 +++++++++++++++++++ src/coreclr-debug/main.ts | 400 --------------------------------- src/coreclr-debug/proxy.ts | 22 +- src/coreclr-debug/util.ts | 88 +++++--- src/omnisharpDownload.ts | 35 ++- src/omnisharpMain.ts | 4 +- src/omnisharpPath.ts | 2 +- src/omnisharpServer.ts | 4 +- src/omnisharpServerLauncher.ts | 13 +- src/proxy.ts | 9 +- src/utils.ts | 2 +- 14 files changed, 660 insertions(+), 492 deletions(-) create mode 100644 src/coreclr-debug/activate.ts create mode 100644 src/coreclr-debug/install.ts delete mode 100644 src/coreclr-debug/main.ts diff --git a/.vscodeignore b/.vscodeignore index 32376201b6..14673ecc76 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -5,14 +5,9 @@ src/** **/*.map .vscode/** -.omnisharp/** **/.nyc_output/** **/coverage/** -coreclr-debug/debugAdapters/** -coreclr-debug/bin/** -coreclr-debug/obj/** -coreclr-debug/project.lock.json -coreclr-debug/install.log +RuntimeLicenses/dependencies/* +coreclr-debug/install.log \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 9522da46b9..ade7982408 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -5,21 +5,142 @@ 'use strict'; +const fs = require('fs'); +const path = require('path'); const del = require('del'); const gulp = require('gulp'); +const gulpUtil = require('gulp-util'); const tslint = require('gulp-tslint'); const vsce = require('vsce'); -//const omnisharpDownload = require('./out/omnisharpDownload'); +const debugUtil = require('./out/coreclr-debug/util.js'); +const debugInstall = require('./out/coreclr-debug/install.js'); +const fs_extra = require('fs-extra-promise'); +const omnisharpDownload = require('./out/omnisharpDownload'); +const child_process = require('child_process'); + +const OmniSharpVersion = omnisharpDownload.OmniSharpVersion; + +/// used in offline packaging run so does not clean .vsix +function clean() { + cleanDebugger(); + return cleanOmnisharp(); +} + +gulp.task('clean', ['omnisharp:clean', 'debugger:clean', 'package:clean'], () => { + +}); + +/// Omnisharp Tasks +function installOmnisharp(omnisharpAssetName) { + const logFunction = (message) => { console.log(message); }; + return omnisharpDownload.downloadOmnisharp(logFunction, omnisharpAssetName); +} + +function cleanOmnisharp() { + return del('.omnisharp'); +} gulp.task('omnisharp:clean', () => { - return del('.omnisharp'); + return cleanOmnisharp(); +}); + +gulp.task('omnisharp:install', ['omnisharp:clean'], () => { + var asset = gulpUtil.env.asset || omnisharpDownload.getOmnisharpAssetName(); + return installOmnisharp(asset); +}); + +/// Debugger Tasks +function getDebugInstaller() { + return new debugInstall.DebugInstaller(new debugUtil.CoreClrDebugUtil(path.resolve('.')), true); +} + +function installDebugger(runtimeId) { + return getDebugInstaller().install(runtimeId); +} + +function cleanDebugger() { + try { + getDebugInstaller().clean(); + console.log('Cleaned Succesfully'); + } catch (error) { + console.error(error); + } +} + +gulp.task('debugger:install', ['debugger:clean'], () => { + installDebugger(gulp.env.runtimeId).then(() => { + console.log('Installed Succesfully'); + }).catch((error) => { + console.error(error); + }); +}); + +gulp.task('debugger:clean', () => { + cleanDebugger(); +}); + +/// Packaging Tasks +function doPackageSync(packageName) { + + var vsceArgs = []; + vsceArgs.push(path.join(__dirname, 'node_modules', 'vsce', 'out', 'vsce')) + vsceArgs.push('package'); // package command + + if (packageName !== undefined) { + vsceArgs.push('-o'); + vsceArgs.push(packageName); + } + + var proc = child_process.spawnSync('node', vsceArgs); + if (proc.error) { + console.error(proc.error.toString()); + } +} + +function doOfflinePackage(runtimeId, omnisharpAsset, packageName) { + return clean().then(() => { + return installDebugger(runtimeId); + }).then(() => { + return installOmnisharp(omnisharpAsset); + }).then(() => { + doPackageSync(packageName + '-' + runtimeId + '.vsix'); + }); +} + +gulp.task('package:clean', () => { + return del('*.vsix'); +}); + +gulp.task('package:online', ['clean'], () => { + doPackageSync(); }); -//TODO: decouple omnisharpDownload (specifically proxy.ts) from vscode -// gulp.task('omnisharp:fetch', ['omnisharp:clean'], () => { -// return omnisharpDownload.downloadOmnisharp(); -// }); +gulp.task('package:offline', ['clean'], () => { + var json = JSON.parse(fs.readFileSync('package.json')); + var name = json.name; + var version = json.version; + var packageName = name + '.' + version; + var packages = []; + packages.push({rid: 'win7-x64', omni: `omnisharp-${OmniSharpVersion}-win-x64-net451.zip`}); + packages.push({rid: 'osx.10.11-x64', omni: `omnisharp-${OmniSharpVersion}-osx-x64-netcoreapp1.0.tar.gz`}); + packages.push({rid: 'centos.7-x64', omni: `omnisharp-${OmniSharpVersion}-centos-x64-netcoreapp1.0.tar.gz`}); + packages.push({rid: 'debian.8-x64', omni: `omnisharp-${OmniSharpVersion}-debian-x64-netcoreapp1.0.tar.gz`}); + packages.push({rid: 'rhel.7.2-x64', omni: `omnisharp-${OmniSharpVersion}-rhel-x64-netcoreapp1.0.tar.gz`}); + packages.push({rid: 'ubuntu.14.04-x64', omni: `omnisharp-${OmniSharpVersion}-ubuntu-x64-netcoreapp1.0.tar.gz`}); + + var promise = Promise.resolve(); + + packages.forEach(pair => { + promise = promise.then(() => { + return doOfflinePackage(pair.rid, pair.omni, packageName); + }) + }); + + return promise; +}); + +/// Misc Tasks const allTypeScript = [ 'src/**/*.ts', '!**/*.d.ts', @@ -29,7 +150,7 @@ const allTypeScript = [ const lintReporter = (output, file, options) => { //emits: src/helloWorld.c:5:3: warning: implicit declaration of function ‘prinft’ var relativeBase = file.base.substring(file.cwd.length + 1).replace('\\', '/'); - output.forEach(function(e) { + output.forEach(e => { var message = relativeBase + e.name + ':' + (e.startPosition.line + 1) + ':' + (e.startPosition.character + 1) + ': ' + e.failure; console.log('[tslint] ' + message); }); @@ -44,10 +165,4 @@ gulp.task('tslint', () => { summarizeFailureOutput: false, emitError: false })) -}); - -// gulp.task('omnisharp', ['omnisharp:fetch']); - -gulp.task('package', () => { - vsce(['', '', 'package']); }); \ No newline at end of file diff --git a/src/coreclr-debug/activate.ts b/src/coreclr-debug/activate.ts new file mode 100644 index 0000000000..3445d14509 --- /dev/null +++ b/src/coreclr-debug/activate.ts @@ -0,0 +1,194 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as vscode from 'vscode'; +import * as child_process from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; +import TelemetryReporter from 'vscode-extension-telemetry'; +import { CoreClrDebugUtil } from './util'; +import * as debugInstall from './install'; + +let _reporter: TelemetryReporter = null; +let _channel: vscode.OutputChannel = null; +let _util: CoreClrDebugUtil = null; + +export function activate(context: vscode.ExtensionContext, reporter: TelemetryReporter) { + _reporter = reporter; + _channel = vscode.window.createOutputChannel('coreclr-debug'); + _util = new CoreClrDebugUtil(context.extensionPath, _channel); + + if (CoreClrDebugUtil.existsSync(_util.installCompleteFilePath())) { + console.log('.NET Core Debugger tools already installed'); + return; + } + + if (!isOnPath('dotnet')) { + const getDotNetMessage = "Get .NET CLI tools"; + vscode.window.showErrorMessage("The .NET CLI tools cannot be located. .NET Core debugging will not be enabled. Make sure .NET CLI tools are installed and are on the path.", + getDotNetMessage).then(value => { + if (value === getDotNetMessage) { + let open = require('open'); + open("http://dotnet.github.io/getting-started/"); + } + }); + + return; + } + + let installer = new debugInstall.DebugInstaller(_util); + _util.createInstallLog(); + + let runtimeId = getPlatformRuntimeId(); + + let statusBarMessage = vscode.window.setStatusBarMessage("Downloading and configuring the .NET Core Debugger..."); + + let installStage = "installBegin"; + let installError = ""; + + writeInstallBeginFile().then(() => { + return installer.install(runtimeId); + }).then(() => { + installStage = "completeSuccess"; + statusBarMessage.dispose(); + vscode.window.setStatusBarMessage('Successfully installed .NET Core Debugger.'); + }) + .catch((error: debugInstall.InstallError) => { + const viewLogMessage = "View Log"; + vscode.window.showErrorMessage('Error while installing .NET Core Debugger.', viewLogMessage).then(value => { + if (value === viewLogMessage) { + _channel.show(vscode.ViewColumn.Three); + } + }); + statusBarMessage.dispose(); + + installStage = error.installStage; + installError = error.installError; + }).then(() => { + // log telemetry and delete install begin file + logTelemetry('Acquisition', {installStage: installStage, installError: installError}); + try { + deleteInstallBeginFile(); + } catch (err) { + // if this throws there's really nothing we can do + } + _util.closeInstallLog(); + }); +} + +function logTelemetry(eventName: string, properties?: {[prop: string]: string}): void { + if (_reporter !== null) { + _reporter.sendTelemetryEvent('coreclr-debug/' + eventName, properties); + } +} + +function writeInstallBeginFile() : Promise { + return CoreClrDebugUtil.writeEmptyFile(_util.installBeginFilePath()); +} + +function deleteInstallBeginFile() { + if (CoreClrDebugUtil.existsSync(_util.installBeginFilePath())) { + fs.unlinkSync(_util.installBeginFilePath()); + } +} + +// Determines if the specified command is in one of the directories in the PATH environment variable. +function isOnPath(command : string) : boolean { + let pathValue = process.env['PATH']; + if (!pathValue) { + return false; + } + let fileName = command; + if (process.platform == 'win32') { + // on Windows, add a '.exe', and the path is semi-colon seperatode + fileName = fileName + ".exe"; + } + + let pathSegments: string[] = pathValue.split(path.delimiter); + for (let segment of pathSegments) { + if (segment.length === 0 || !path.isAbsolute(segment)) { + continue; + } + + const segmentPath = path.join(segment, fileName); + + try { + if (CoreClrDebugUtil.existsSync(segmentPath)) { + return true; + } + } catch (err) { + // any error from existsSync can be treated as the command not being on the path + continue; + } + } + + return false; +} + +function getPlatformRuntimeId() : string { + switch (process.platform) { + case 'win32': + return 'win7-x64'; + case 'darwin': + return getDotnetRuntimeId(); + case 'linux': + return getDotnetRuntimeId(); + default: + _util.log('Error: Unsupported platform ' + process.platform); + throw Error('Unsupported platform ' + process.platform); + } +} + +function getDotnetRuntimeId(): string { + _util.log("Starting 'dotnet --info'"); + + const cliVersionErrorMessage = "Ensure that .NET Core CLI Tools version >= 1.0.0-beta-002173 is installed. Run 'dotnet --version' to see what version is installed."; + + let child = child_process.spawnSync('dotnet', ['--info'], { cwd: _util.coreClrDebugDir() }); + + if (child.stderr.length > 0) { + _util.log('Error: ' + child.stderr.toString()); + } + const out = child.stdout.toString(); + if (out.length > 0) { + _util.log(out); + } + + if (child.status !== 0) { + const message = `Error: 'dotnet --info' failed with error ${child.status}`; + _util.log(message); + _util.log(cliVersionErrorMessage); + throw new Error(message); + } + + if (out.length === 0) { + const message = "Error: 'dotnet --info' provided no output"; + _util.log(message); + _util.log(cliVersionErrorMessage); + throw new Error(message); + } + + let lines = out.split('\n'); + let ridLine = lines.filter(value => { + return value.trim().startsWith('RID:'); + }); + + if (ridLine.length < 1) { + _util.log("Error: Cannot find 'RID' property"); + _util.log(cliVersionErrorMessage); + throw new Error('Cannot obtain Runtime ID from dotnet cli'); + } + + let rid = ridLine[0].split(':')[1].trim(); + + if (!rid) { + _util.log("Error: Unable to parse 'RID' property."); + _util.log(cliVersionErrorMessage); + throw new Error('Unable to determine Runtime ID'); + } + + return rid; +} diff --git a/src/coreclr-debug/install.ts b/src/coreclr-debug/install.ts new file mode 100644 index 0000000000..892e565e10 --- /dev/null +++ b/src/coreclr-debug/install.ts @@ -0,0 +1,231 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { CoreClrDebugUtil } from './util'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as child_process from 'child_process'; +import * as fs_extra from 'fs-extra-promise'; + +export class InstallError extends Error { + public installStage: string; + public installError: string; + + constructor(stage: string, error: string) { + super("Error during installation."); + this.installStage = stage; + this.installError = error; + } +} + +export class DebugInstaller +{ + private _util: CoreClrDebugUtil = null; + private _isOffline; + + constructor(util: CoreClrDebugUtil, isOffline?: boolean) { + this._util = util; + this._isOffline = isOffline || false; + } + + public install(runtimeId: string): Promise { + let installStage = 'writeProjectJson'; + return this.writeProjectJson(runtimeId).then(() => { + installStage = 'dotnetRestore'; + return this.spawnChildProcess('dotnet', ['--verbose', 'restore', '--configfile', 'NuGet.config'], this._util.coreClrDebugDir()); + }).then(() => { + installStage = "dotnetPublish"; + return this.spawnChildProcess('dotnet', ['--verbose', 'publish', '-r', runtimeId, '-o', this._util.debugAdapterDir()], this._util.coreClrDebugDir()); + }).then(() => { + installStage = "ensureAd7"; + return this.ensureAd7EngineExists(this._util.debugAdapterDir()); + }).then(() => { + installStage = "renameDummyEntrypoint"; + return this.renameDummyEntrypoint(); + }).then(() => { + installStage = "rewriteManifest"; + this.rewriteManifest(); + installStage = "writeCompletionFile"; + return this.writeCompletionFile(); + }).catch((error) => { + throw new InstallError(installStage, error.toString()); + }); + } + + public clean(): void { + let cleanItems: string[] = []; + + cleanItems.push(this._util.debugAdapterDir()); + cleanItems.push(this._util.installLogPath()); + cleanItems.push(path.join(this._util.coreClrDebugDir(), "bin")); + cleanItems.push(path.join(this._util.coreClrDebugDir(), "obj")); + cleanItems.push(path.join(this._util.coreClrDebugDir(), 'project.json')); + cleanItems.push(path.join(this._util.coreClrDebugDir(), 'project.lock.json')); + + cleanItems.forEach((item) => { + if (CoreClrDebugUtil.existsSync(item)) { + this._util.log(`Cleaning ${item}`); + fs_extra.removeSync(item); + } + }); + } + + private rewriteManifest() : void { + const manifestPath = path.join(this._util.extensionDir(), 'package.json'); + let manifestString = fs.readFileSync(manifestPath, 'utf8'); + let manifestObject = JSON.parse(manifestString); + delete manifestObject.contributes.debuggers[0].runtime; + delete manifestObject.contributes.debuggers[0].program; + + let programString = './coreclr-debug/debugAdapters/OpenDebugAD7'; + manifestObject.contributes.debuggers[0].windows = { program: programString + '.exe' }; + manifestObject.contributes.debuggers[0].osx = { program: programString }; + manifestObject.contributes.debuggers[0].linux = { program: programString }; + + manifestString = JSON.stringify(manifestObject, null, 2); + fs.writeFileSync(manifestPath, manifestString); + } + + private writeCompletionFile() : Promise { + return CoreClrDebugUtil.writeEmptyFile(this._util.installCompleteFilePath()); + } + + private renameDummyEntrypoint() : Promise { + let src = path.join(this._util.debugAdapterDir(), 'dummy'); + let dest = path.join(this._util.debugAdapterDir(), 'OpenDebugAD7'); + + if (!CoreClrDebugUtil.existsSync(src)) { + if (CoreClrDebugUtil.existsSync(src + '.exe')) { + src += '.exe'; + dest += '.exe'; + } + } + + const promise = new Promise((resolve, reject) => { + fs.rename(src, dest, (err) => { + if (err) { + reject(err.code); + } else { + resolve(); + } + }); + }); + + return promise; + } + + private ensureAd7EngineExists(outputDirectory: string) : Promise { + let filePath = path.join(outputDirectory, "coreclr.ad7Engine.json"); + return new Promise((resolve, reject) => { + fs.exists(filePath, (exists) => { + if (exists) { + return resolve(); + } else { + this._util.log(`${filePath} does not exist.`); + this._util.log(''); + // NOTE: The minimum build number is actually less than 1584, but this is the minimum + // build that I have tested. + this._util.log("Error: The .NET CLI did not correctly restore debugger files. Ensure that you have .NET CLI version 1.0.0 build #001584 or newer. You can check your .NET CLI version using 'dotnet --version'."); + return reject("The .NET CLI did not correctly restore debugger files."); + } + }); + }); + } + + private writeProjectJson(runtimeId: string): Promise { + return new Promise((resolve, reject) => { + const projectJsonPath = path.join(this._util.coreClrDebugDir(), 'project.json'); + this._util.log('Creating ' + projectJsonPath); + + const projectJson = this.createProjectJson(runtimeId); + + fs.writeFile(projectJsonPath, JSON.stringify(projectJson, null, 2), {encoding: 'utf8'}, (err) => { + if (err) { + this._util.log('Error: Unable to write to project.json: ' + err.message); + reject(err.code); + } + else { + resolve(); + } + }); + }); + } + + private createProjectJson(targetRuntime: string): any + { + let projectJson = { + name: "dummy", + buildOptions: { + emitEntryPoint: true + }, + dependencies: { + "Microsoft.VisualStudio.clrdbg": "14.0.25406-preview-3044032", + "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30610-preview-1", + "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20610-preview-3", + "NETStandard.Library": "1.5.0-rc2-24027", + "Newtonsoft.Json": "7.0.1", + "Microsoft.VisualStudio.Debugger.Interop.Portable": "1.0.1", + "System.Collections.Specialized": "4.0.1-rc2-24027", + "System.Collections.Immutable": "1.2.0-rc2-24027", + "System.Diagnostics.Process" : "4.1.0-rc2-24027", + "System.Diagnostics.StackTrace": "4.0.1-rc2-24027", + "System.Dynamic.Runtime": "4.0.11-rc2-24027", + "Microsoft.CSharp": "4.0.1-rc2-24027", + "System.Threading.Tasks.Dataflow": "4.6.0-rc2-24027", + "System.Threading.Thread": "4.0.0-rc2-24027", + "System.Xml.XDocument": "4.0.11-rc2-24027", + "System.Xml.XmlDocument": "4.0.1-rc2-24027", + "System.Xml.XmlSerializer": "4.0.11-rc2-24027", + "System.ComponentModel": "4.0.1-rc2-24027", + "System.ComponentModel.Annotations": "4.1.0-rc2-24027", + "System.ComponentModel.EventBasedAsync": "4.0.11-rc2-24027", + "System.Runtime.Serialization.Primitives": "4.1.1-rc2-24027", + "System.Net.Http": "4.0.1-rc2-24027" + }, + frameworks: { + "netcoreapp1.0": { + imports: [ "dnxcore50", "portable-net45+win8" ] + } + }, + runtimes: { + } + }; + + projectJson.runtimes[targetRuntime] = {}; + + if (this._isOffline) { + projectJson.dependencies["Microsoft.NetCore.DotNetHostPolicy"] = "1.0.1-rc-002702"; + } + + return projectJson; + } + + private spawnChildProcess(process: string, args: string[], workingDirectory: string) : Promise { + const promise = new Promise((resolve, reject) => { + const child = child_process.spawn(process, args, {cwd: workingDirectory}); + + child.stdout.on('data', (data) => { + this._util.log(`${data}`); + }); + + child.stderr.on('data', (data) => { + this._util.log(`Error: ${data}`); + }); + + child.on('close', (code: number) => { + if (code != 0) { + this._util.log(`${process} exited with error code ${code}`); + reject(new Error(code.toString())); + } + else { + resolve(); + } + }); + }); + + return promise; + } +} \ No newline at end of file diff --git a/src/coreclr-debug/main.ts b/src/coreclr-debug/main.ts deleted file mode 100644 index 4fcc27c0d3..0000000000 --- a/src/coreclr-debug/main.ts +++ /dev/null @@ -1,400 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import * as vscode from 'vscode'; -import * as child_process from 'child_process'; -import * as fs from 'fs'; -import * as path from 'path'; -import TelemetryReporter from 'vscode-extension-telemetry'; -import CoreClrDebugUtil from './util' - -let _channel: vscode.OutputChannel; -let _installLog: NodeJS.WritableStream; -let _reporter: TelemetryReporter; // Telemetry reporter -let _util: CoreClrDebugUtil; - -export function activate(context: vscode.ExtensionContext, reporter: TelemetryReporter) { - _util = new CoreClrDebugUtil(context.extensionPath); - - if (CoreClrDebugUtil.existsSync(_util.installCompleteFilePath())) { - console.log('.NET Core Debugger tools already installed'); - return; - } - - if (!isOnPath('dotnet')) { - const getDotNetMessage = "Get .NET CLI tools"; - vscode.window.showErrorMessage("The .NET CLI tools cannot be located. .NET Core debugging will not be enabled. Make sure .NET CLI tools are installed and are on the path.", - getDotNetMessage).then(function (value) { - if (value === getDotNetMessage) { - let open = require('open'); - open("http://dotnet.github.io/getting-started/"); - } - }); - - return; - } - - _reporter = reporter; - _channel = vscode.window.createOutputChannel('coreclr-debug'); - - // Create our log file and override _channel.append to also output to the log - _installLog = fs.createWriteStream(_util.installLogPath()); - (function() { - let proxied = _channel.append; - _channel.append = function(val: string) { - _installLog.write(val); - proxied.apply(this, arguments); - }; - })(); - - let statusBarMessage = vscode.window.setStatusBarMessage("Downloading and configuring the .NET Core Debugger..."); - - let installStage = 'installBegin'; - let installError = ''; - - writeInstallBeginFile().then(function() { - installStage = 'writeProjectJson'; - return writeProjectJson(_channel); - }).then(function() { - installStage = 'dotnetRestore' - return spawnChildProcess('dotnet', ['--verbose', 'restore', '--configfile', 'NuGet.config'], _channel, _util.coreClrDebugDir()) - }).then(function() { - installStage = "dotnetPublish"; - return spawnChildProcess('dotnet', ['--verbose', 'publish', '-o', _util.debugAdapterDir()], _channel, _util.coreClrDebugDir()); - }).then(function() { - installStage = "ensureAd7"; - return ensureAd7EngineExists(_channel, _util.debugAdapterDir()); - }).then(function() { - installStage = "additionalTasks"; - let promises: Promise[] = []; - - promises.push(renameDummyEntrypoint()); - promises.push(removeLibCoreClrTraceProvider()); - - return Promise.all(promises); - }).then(function() { - installStage = "rewriteManifest"; - rewriteManifest(); - installStage = "writeCompletionFile"; - return writeCompletionFile(); - }).then(function() { - installStage = "completeSuccess"; - statusBarMessage.dispose(); - vscode.window.setStatusBarMessage('Successfully installed .NET Core Debugger.'); - }) - .catch(function(error) { - const viewLogMessage = "View Log"; - vscode.window.showErrorMessage('Error while installing .NET Core Debugger.', viewLogMessage).then(function (value) { - if (value === viewLogMessage) { - _channel.show(vscode.ViewColumn.Three); - } - }); - statusBarMessage.dispose(); - - installError = error.toString(); - console.log(error); - - - }).then(function() { - // log telemetry and delete install begin file - logTelemetry('Acquisition', {installStage: installStage, installError: installError}); - - try { - deleteInstallBeginFile(); - } catch (err) { - // if this throws there's really nothing we can do - } - }); -} - -function logTelemetry(eventName: string, properties?: {[prop: string]: string}) { - if (_reporter) - { - _reporter.sendTelemetryEvent('coreclr-debug/' + eventName, properties); - } -} - -function rewriteManifest() : void { - const manifestPath = path.join(_util.extensionDir(), 'package.json'); - let manifestString = fs.readFileSync(manifestPath, 'utf8'); - let manifestObject = JSON.parse(manifestString); - manifestObject.contributes.debuggers[0].runtime = ''; - manifestObject.contributes.debuggers[0].program = './coreclr-debug/debugAdapters/OpenDebugAD7' + CoreClrDebugUtil.getPlatformExeExtension(); - manifestString = JSON.stringify(manifestObject, null, 2); - fs.writeFileSync(manifestPath, manifestString); -} - -function writeInstallBeginFile() : Promise { - return writeEmptyFile(_util.installBeginFilePath()); -} - -function deleteInstallBeginFile() { - if (CoreClrDebugUtil.existsSync(_util.installBeginFilePath())) { - fs.unlinkSync(_util.installBeginFilePath()); - } -} - -function writeCompletionFile() : Promise { - return writeEmptyFile(_util.installCompleteFilePath()); -} - -function writeEmptyFile(path: string) : Promise { - return new Promise(function(resolve, reject) { - fs.writeFile(path, '', function(err) { - if (err) { - reject(err.code); - } else { - resolve(); - } - }); - }); -} - -function renameDummyEntrypoint() : Promise { - let src = path.join(_util.debugAdapterDir(), 'dummy'); - let dest = path.join(_util.debugAdapterDir(), 'OpenDebugAD7'); - - src += CoreClrDebugUtil.getPlatformExeExtension(); - dest += CoreClrDebugUtil.getPlatformExeExtension(); - - const promise = new Promise(function(resolve, reject) { - fs.rename(src, dest, function(err) { - if (err) { - reject(err.code); - } else { - resolve(); - } - }); - }); - - return promise; -} - -function removeLibCoreClrTraceProvider() : Promise -{ - const filePath = path.join(_util.debugAdapterDir(), 'libcoreclrtraceptprovider' + CoreClrDebugUtil.getPlatformLibExtension()); - - if (!CoreClrDebugUtil.existsSync(filePath)) { - return Promise.resolve(); - } else { - return new Promise(function(resolve, reject) { - fs.unlink(filePath, function(err) { - if (err) { - reject(err.code); - } else { - _channel.appendLine('Successfully deleted ' + filePath); - resolve(); - } - }); - }); - } -} - -// Determines if the specified command is in one of the directories in the PATH environment variable. -function isOnPath(command : string) : boolean { - let pathValue = process.env['PATH']; - if (!pathValue) { - return false; - } - let fileName = command; - if (process.platform == 'win32') { - // on Windows, add a '.exe', and the path is semi-colon seperatode - fileName = fileName + ".exe"; - } - - let pathSegments: string[] = pathValue.split(path.delimiter); - for (let segment of pathSegments) { - if (segment.length === 0 || !path.isAbsolute(segment)) { - continue; - } - - const segmentPath = path.join(segment, fileName); - - try { - if (CoreClrDebugUtil.existsSync(segmentPath)) { - return true; - } - } catch (err) { - // any error from existsSync can be treated as the command not being on the path - continue; - } - } - - return false; -} - -function ensureAd7EngineExists(channel: vscode.OutputChannel, outputDirectory: string) : Promise { - let filePath = path.join(outputDirectory, "coreclr.ad7Engine.json"); - return new Promise((resolve, reject) => { - fs.exists(filePath, (exists) => { - if (exists) { - return resolve(); - } else { - channel.appendLine(`${filePath} does not exist.`); - channel.appendLine(''); - // NOTE: The minimum build number is actually less than 1584, but this is the minimum - // build that I have tested. - channel.appendLine("Error: The .NET CLI did not correctly restore debugger files. Ensure that you have .NET CLI version 1.0.0 build #001584 or newer. You can check your .NET CLI version using 'dotnet --version'."); - return reject("The .NET CLI did not correctly restore debugger files."); - } - }); - }); -} - -function writeProjectJson(channel: vscode.OutputChannel): Promise { - return new Promise(function (resolve, reject) { - const projectJsonPath = path.join(_util.coreClrDebugDir(), 'project.json'); - _channel.appendLine('Creating ' + projectJsonPath); - - const projectJson = createProjectJson(getPlatformRuntimeId(channel)); - - fs.writeFile(projectJsonPath, JSON.stringify(projectJson, null, 2), {encoding: 'utf8'}, function(err) { - if (err) { - channel.appendLine('Error: Unable to write to project.json: ' + err.message); - reject(err.code); - } - else { - resolve(); - } - }); - }); -} - -function getPlatformRuntimeId(channel: vscode.OutputChannel) : string { - switch (process.platform) { - case 'win32': - return 'win7-x64'; - case 'darwin': - return getDotnetRuntimeId(channel); - case 'linux': - return getDotnetRuntimeId(channel); - default: - channel.appendLine('Error: Unsupported platform ' + process.platform); - throw Error('Unsupported platform ' + process.platform); - } -} - -function getDotnetRuntimeId(channel: vscode.OutputChannel): string { - channel.appendLine("Starting 'dotnet --info'"); - - const cliVersionErrorMessage = "Ensure that .NET Core CLI Tools version >= 1.0.0-beta-002173 is installed. Run 'dotnet --version' to see what version is installed."; - - let child = child_process.spawnSync('dotnet', ['--info'], { cwd: _util.coreClrDebugDir() }); - - if (child.stderr.length > 0) { - channel.append('Error: ' + child.stderr.toString()); - } - const out = child.stdout.toString(); - if (out.length > 0) { - channel.append(out); - } - - if (child.status !== 0) { - const message = `Error: 'dotnet --info' failed with error ${child.status}`; - channel.appendLine(message); - channel.appendLine(cliVersionErrorMessage); - throw new Error(message); - } - - if (out.length === 0) { - const message = "Error: 'dotnet --info' provided no output"; - channel.appendLine(message); - channel.appendLine(cliVersionErrorMessage); - throw new Error(message); - } - - let lines = out.split('\n'); - let ridLine = lines.filter(function (value) { - return value.trim().startsWith('RID:'); - }); - - if (ridLine.length < 1) { - channel.appendLine("Error: Cannot find 'RID' property"); - channel.appendLine(cliVersionErrorMessage); - throw new Error('Cannot obtain Runtime ID from dotnet cli'); - } - - let rid = ridLine[0].split(':')[1].trim(); - - if (!rid) { - channel.appendLine("Error: Unable to parse 'RID' property."); - channel.appendLine(cliVersionErrorMessage); - throw new Error('Unable to determine Runtime ID'); - } - - return rid; -} - -function createProjectJson(targetRuntime: string): any -{ - let projectJson = { - name: "dummy", - buildOptions: { - emitEntryPoint: true - }, - dependencies: { - "Microsoft.VisualStudio.clrdbg": "14.0.25406-preview-3044032", - "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30610-preview-1", - "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20610-preview-3", - "NETStandard.Library": "1.5.0-rc2-24027", - "Newtonsoft.Json": "7.0.1", - "Microsoft.VisualStudio.Debugger.Interop.Portable": "1.0.1", - "System.Collections.Specialized": "4.0.1-rc2-24027", - "System.Collections.Immutable": "1.2.0-rc2-24027", - "System.Diagnostics.Process" : "4.1.0-rc2-24027", - "System.Diagnostics.StackTrace": "4.0.1-rc2-24027", - "System.Dynamic.Runtime": "4.0.11-rc2-24027", - "Microsoft.CSharp": "4.0.1-rc2-24027", - "System.Threading.Tasks.Dataflow": "4.6.0-rc2-24027", - "System.Threading.Thread": "4.0.0-rc2-24027", - "System.Xml.XDocument": "4.0.11-rc2-24027", - "System.Xml.XmlDocument": "4.0.1-rc2-24027", - "System.Xml.XmlSerializer": "4.0.11-rc2-24027", - "System.ComponentModel": "4.0.1-rc2-24027", - "System.ComponentModel.Annotations": "4.1.0-rc2-24027", - "System.ComponentModel.EventBasedAsync": "4.0.11-rc2-24027", - "System.Runtime.Serialization.Primitives": "4.1.1-rc2-24027", - "System.Net.Http": "4.0.1-rc2-24027" - }, - frameworks: { - "netstandardapp1.5": { - imports: [ "dnxcore50", "portable-net45+win8" ] - } - }, - runtimes: { - } - } - - projectJson.runtimes[targetRuntime] = {}; - - return projectJson; -} - -function spawnChildProcess(process: string, args: string[], channel: vscode.OutputChannel, workingDirectory: string) : Promise { - const promise = new Promise(function(resolve, reject) { - const child = child_process.spawn(process, args, {cwd: workingDirectory}); - - child.stdout.on('data', (data) => { - channel.append(`${data}`); - }); - - child.stderr.on('data', (data) => { - channel.appendLine(`Error: ${data}`); - }); - - child.on('close', (code: number) => { - if (code != 0) { - channel.appendLine(`${process} exited with error code ${code}`); - reject(new Error(code.toString())); - } - else { - resolve(); - } - }); - }); - - return promise; -} diff --git a/src/coreclr-debug/proxy.ts b/src/coreclr-debug/proxy.ts index d6a9c3bfd4..8e98895635 100644 --- a/src/coreclr-debug/proxy.ts +++ b/src/coreclr-debug/proxy.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import { DebugProtocol } from 'vscode-debugprotocol'; import * as child_process from 'child_process'; -import CoreClrDebugUtil from './util'; +import { CoreClrDebugUtil } from './util'; class ProxyErrorResponse implements DebugProtocol.ErrorResponse { public body: { error?: DebugProtocol.Message }; @@ -50,7 +50,7 @@ function proxy() { } else { - new Promise(function(resolve, reject) { + new Promise((resolve, reject) => { let processPath = path.join(util.debugAdapterDir(), "OpenDebugAD7" + CoreClrDebugUtil.getPlatformExeExtension()); let args = process.argv.slice(2); @@ -59,7 +59,7 @@ function proxy() { const child = child_process.spawn(processPath, args); // If we don't exit cleanly from the child process, log the error. - child.on('close', function(code: number) { + child.on('close', code => { if (code !== 0) { reject(new Error(code.toString())); } else { @@ -69,38 +69,38 @@ function proxy() { process.stdin.setEncoding('utf8'); - child.on('error', function(data) { + child.on('error', data => { util.logToFile(`Child error: ${data}`); }); - process.on('SIGTERM', function() { + process.on('SIGTERM', () => { child.kill(); process.exit(0); }); - process.on('SIGHUP', function() { + process.on('SIGHUP', () => { child.kill(); process.exit(0); }); - process.stdin.on('error', function(error) { + process.stdin.on('error', error => { util.logToFile(`process.stdin error: ${error}`); }); - process.stdout.on('error', function(error) { + process.stdout.on('error', error => { util.logToFile(`process.stdout error: ${error}`); }); - child.stdout.on('data', function(data) { + child.stdout.on('data', data => { process.stdout.write(data); }); - process.stdin.on('data', function(data) { + process.stdin.on('data', data => { child.stdin.write(data); }); process.stdin.resume(); - }).catch(function(err) { + }).catch(err => { util.logToFile(`Promise failed: ${err}`); }); } diff --git a/src/coreclr-debug/util.ts b/src/coreclr-debug/util.ts index e17f35af98..b29575f7dc 100644 --- a/src/coreclr-debug/util.ts +++ b/src/coreclr-debug/util.ts @@ -7,16 +7,9 @@ import * as path from 'path'; import * as fs from 'fs'; import * as os from 'os'; -import * as child_process from 'child_process' +import * as vscode from 'vscode'; -let _extensionDir: string = ''; -let _coreClrDebugDir: string = ''; -let _debugAdapterDir: string = ''; -let _installLogPath: string = ''; -let _installBeginFilePath: string = ''; -let _installCompleteFilePath: string = ''; - -export default class CoreClrDebugUtil +export class CoreClrDebugUtil { private _extensionDir: string = ''; private _coreClrDebugDir: string = ''; @@ -24,58 +17,97 @@ export default class CoreClrDebugUtil private _installLogPath: string = ''; private _installBeginFilePath: string = ''; private _installCompleteFilePath: string = ''; + + private _installLog: fs.WriteStream = null; + private _channel: vscode.OutputChannel = null; - constructor(extensionDir) { - _extensionDir = extensionDir; - _coreClrDebugDir = path.join(_extensionDir, 'coreclr-debug'); - _debugAdapterDir = path.join(_coreClrDebugDir, 'debugAdapters'); - _installLogPath = path.join(_coreClrDebugDir, 'install.log'); - _installBeginFilePath = path.join(_coreClrDebugDir, 'install.begin'); - _installCompleteFilePath = path.join(_debugAdapterDir, 'install.complete'); + constructor(extensionDir: string, channel?: vscode.OutputChannel) { + this._extensionDir = extensionDir; + this._coreClrDebugDir = path.join(this._extensionDir, 'coreclr-debug'); + this._debugAdapterDir = path.join(this._coreClrDebugDir, 'debugAdapters'); + this._installLogPath = path.join(this._coreClrDebugDir, 'install.log'); + this._installBeginFilePath = path.join(this._coreClrDebugDir, 'install.begin'); + this._installCompleteFilePath = path.join(this._debugAdapterDir, 'install.complete'); + + this._channel = channel; } extensionDir(): string { - if (_extensionDir === '') + if (this._extensionDir === '') { throw new Error('Failed to set extension directory'); } - return _extensionDir; + return this._extensionDir; } coreClrDebugDir(): string { - if (_coreClrDebugDir === '') { + if (this._coreClrDebugDir === '') { throw new Error('Failed to set coreclrdebug directory'); } - return _coreClrDebugDir; + return this._coreClrDebugDir; } debugAdapterDir(): string { - if (_debugAdapterDir === '') { + if (this._debugAdapterDir === '') { throw new Error('Failed to set debugadpter directory'); } - return _debugAdapterDir; + return this._debugAdapterDir; } installLogPath(): string { - if (_installLogPath === '') { + if (this._installLogPath === '') { throw new Error('Failed to set install log path'); } - return _installLogPath; + return this._installLogPath; } installBeginFilePath(): string { - if (_installBeginFilePath === '') { + if (this._installBeginFilePath === '') { throw new Error('Failed to set install begin file path'); } - return _installBeginFilePath; + return this._installBeginFilePath; } installCompleteFilePath(): string { - if (_installCompleteFilePath === '') + if (this._installCompleteFilePath === '') { throw new Error('Failed to set install complete file path'); } - return _installCompleteFilePath; + return this._installCompleteFilePath; + } + + createInstallLog(): void { + this._installLog = fs.createWriteStream(this.installLogPath()); + } + + closeInstallLog(): void { + if (this._installLog !== null) { + this._installLog.close(); + } + } + + log(message: string): void { + console.log(message); + + if (this._installLog != null) { + this._installLog.write(message); + } + + if (this._channel != null) { + this._channel.appendLine(message); + } + } + + static writeEmptyFile(path: string) : Promise { + return new Promise((resolve, reject) => { + fs.writeFile(path, '', (err) => { + if (err) { + reject(err.code); + } else { + resolve(); + } + }); + }); } static existsSync(path: string) : boolean { diff --git a/src/omnisharpDownload.ts b/src/omnisharpDownload.ts index 5fcae44310..f64ab72b01 100644 --- a/src/omnisharpDownload.ts +++ b/src/omnisharpDownload.ts @@ -13,17 +13,16 @@ import * as tmp from 'tmp'; import {parse} from 'url'; import {SupportedPlatform, getSupportedPlatform} from './utils'; import {getProxyAgent} from './proxy'; -import {OutputChannel} from 'vscode'; const decompress = require('decompress'); const BaseDownloadUrl = 'https://vscodeoscon.blob.core.windows.net/ext'; const DefaultInstallLocation = path.join(__dirname, '../.omnisharp'); -const OmniSharpVersion = '1.9-beta5'; +export const OmniSharpVersion = '1.9-beta5'; tmp.setGracefulCleanup(); -function getOmnisharpAssetName(): string { +export function getOmnisharpAssetName(): string { switch (getSupportedPlatform()) { case SupportedPlatform.Windows: return `omnisharp-${OmniSharpVersion}-win-x64-net451.zip`; @@ -48,10 +47,10 @@ function getOmnisharpAssetName(): string { } } -function download(urlString: string): Promise { +function download(urlString: string, proxy?: string, strictSSL?: boolean): Promise { let url = parse(urlString); - const agent = getProxyAgent(url); + const agent = getProxyAgent(url, proxy, strictSSL); let options: https.RequestOptions = { host: url.host, @@ -74,23 +73,23 @@ function download(urlString: string): Promise { }); } -export function downloadOmnisharp(output: OutputChannel): Promise { +export function downloadOmnisharp(log: (message: string) => void, omnisharpAssetName?: string, proxy?: string, strictSSL?: boolean) { return new Promise((resolve, reject) => { - output.appendLine(`[INFO] Installing to ${DefaultInstallLocation}`); - - const assetName = getOmnisharpAssetName(); + log(`[INFO] Installing to ${DefaultInstallLocation}`); + + const assetName = omnisharpAssetName || getOmnisharpAssetName(); const urlString = `${BaseDownloadUrl}/${assetName}`; - - output.appendLine(`[INFO] Attempting to download ${assetName}...`); - return download(urlString) + log(`[INFO] Attempting to download ${assetName}...`); + + return download(urlString, proxy, strictSSL) .then(inStream => { tmp.file((err, tmpPath, fd, cleanupCallback) => { if (err) { return reject(err); } - output.appendLine(`[INFO] Downloading to ${tmpPath}...`); + log(`[INFO] Downloading to ${tmpPath}...`); const outStream = fs.createWriteStream(null, { fd: fd }); @@ -100,16 +99,16 @@ export function downloadOmnisharp(output: OutputChannel): Promise { outStream.once('finish', () => { // At this point, the asset has finished downloading. - output.appendLine(`[INFO] Download complete!`); - output.appendLine(`[INFO] Decompressing...`); + log(`[INFO] Download complete!`); + log(`[INFO] Decompressing...`); return decompress(tmpPath, DefaultInstallLocation) .then(files => { - output.appendLine(`[INFO] Done! ${files.length} files unpacked.`) + log(`[INFO] Done! ${files.length} files unpacked.`); return resolve(true); }) .catch(err => { - output.appendLine(`[ERROR] ${err}`); + log(`[ERROR] ${err}`); return reject(err); }); }); @@ -119,7 +118,7 @@ export function downloadOmnisharp(output: OutputChannel): Promise { }) .catch(err => { - output.appendLine(`[ERROR] ${err}`); + log(`[ERROR] ${err}`); }); }); } \ No newline at end of file diff --git a/src/omnisharpMain.ts b/src/omnisharpMain.ts index ec5e51e04b..ddedf93e88 100644 --- a/src/omnisharpMain.ts +++ b/src/omnisharpMain.ts @@ -22,7 +22,7 @@ import registerCommands from './features/commands'; import {StdioOmnisharpServer} from './omnisharpServer'; import forwardChanges from './features/changeForwarding'; import reportStatus from './features/omnisharpStatus'; -import * as coreclrdebug from './coreclr-debug/main'; +import * as coreclrdebug from './coreclr-debug/activate'; import {addAssetsIfNecessary} from './assets'; import * as vscode from 'vscode'; import TelemetryReporter from 'vscode-extension-telemetry'; @@ -91,7 +91,7 @@ export function activate(context: vscode.ExtensionContext): any { server.stop(); })); - // install coreclr-debug + // activate coreclr-debug coreclrdebug.activate(context, reporter); context.subscriptions.push(...disposables); diff --git a/src/omnisharpPath.ts b/src/omnisharpPath.ts index a1f4392779..f1554edf5f 100644 --- a/src/omnisharpPath.ts +++ b/src/omnisharpPath.ts @@ -50,7 +50,7 @@ function getLaunchPathFromSettings(): Promise { .catch(err => { vscode.window.showWarningMessage(`Invalid "csharp.omnisharp" use setting specified ('${setting}).`); throw err; - }) + }); } return Promise.reject(new Error('OmniSharp use setting does not exists.')); diff --git a/src/omnisharpServer.ts b/src/omnisharpServer.ts index 33bf072240..582cffac6c 100644 --- a/src/omnisharpServer.ts +++ b/src/omnisharpServer.ts @@ -14,7 +14,7 @@ import {Disposable, CancellationToken, OutputChannel, workspace, window} from 'v import {ErrorMessage, UnresolvedDependenciesMessage, MSBuildProjectDiagnostics, ProjectInformationResponse} from './protocol'; import getLaunchTargets, {LaunchTarget} from './launchTargetFinder'; import TelemetryReporter from 'vscode-extension-telemetry'; -import * as vscode from 'vscode' +import * as vscode from 'vscode'; enum ServerState { Starting, @@ -153,7 +153,7 @@ export abstract class OmnisharpServer { } public reportAndClearTelemetry() { - for (var path in this._requestDelays) { + for (const path in this._requestDelays) { const eventName = 'omnisharp' + path; const measures = this._requestDelays[path].toMeasures(); diff --git a/src/omnisharpServerLauncher.ts b/src/omnisharpServerLauncher.ts index b4d0bb87d2..63a0d8e3a4 100644 --- a/src/omnisharpServerLauncher.ts +++ b/src/omnisharpServerLauncher.ts @@ -5,13 +5,11 @@ 'use strict'; -import {exists as fileExists} from 'fs'; import {spawn, ChildProcess} from 'child_process'; import {workspace, OutputChannel} from 'vscode'; import {satisfies} from 'semver'; -import {join} from 'path'; import {getOmnisharpLaunchFilePath} from './omnisharpPath'; -import {downloadOmnisharp} from './omnisharpDownload'; +import {downloadOmnisharp, getOmnisharpAssetName} from './omnisharpDownload'; import {SupportedPlatform, getSupportedPlatform} from './utils'; const isWindows = process.platform === 'win32'; @@ -37,9 +35,14 @@ export function installOmnisharpIfNeeded(output: OutputChannel): Promise throw err; } - return downloadOmnisharp(output).then(_ => { + const logFunction = (message: string) => { output.appendLine(message); }; + const omnisharpAssetName = getOmnisharpAssetName(); + const proxy = workspace.getConfiguration().get('http.proxy'); + const strictSSL = workspace.getConfiguration().get('http.proxyStrictSSL', true); + + return downloadOmnisharp(logFunction, omnisharpAssetName, proxy, strictSSL).then(_ => { return getOmnisharpLaunchFilePath(); - }) + }); }); } diff --git a/src/proxy.ts b/src/proxy.ts index 1eaa96197a..250554fd3b 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -8,7 +8,6 @@ import { Url, parse as parseUrl } from 'url'; import HttpProxyAgent = require('http-proxy-agent'); import HttpsProxyAgent = require('https-proxy-agent'); -import {workspace} from 'vscode'; function getSystemProxyURL(requestURL: Url): string { if (requestURL.protocol === 'http:') { @@ -20,9 +19,8 @@ function getSystemProxyURL(requestURL: Url): string { return null; } -export function getProxyAgent(requestURL: Url): any { - const vsConfigProxyUrl = workspace.getConfiguration().get('http.proxy'); - const proxyURL = vsConfigProxyUrl || getSystemProxyURL(requestURL); +export function getProxyAgent(requestURL: Url, proxy?: string, strictSSL?: boolean): any { + const proxyURL = proxy || getSystemProxyURL(requestURL); if (!proxyURL) { return null; @@ -34,7 +32,8 @@ export function getProxyAgent(requestURL: Url): any { return null; } - const strictSSL = workspace.getConfiguration().get('http.proxyStrictSSL', true); + strictSSL = strictSSL || true; + const opts = { host: proxyEndpoint.hostname, port: Number(proxyEndpoint.port), diff --git a/src/utils.ts b/src/utils.ts index 551c0c1979..c9a5958e88 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,7 +5,7 @@ 'use strict'; -import * as child_process from 'child_process' +import * as child_process from 'child_process'; export enum SupportedPlatform { None, From 8de8228637f79292be8d82568e5be47526a265e7 Mon Sep 17 00:00:00 2001 From: Chuck Ries Date: Tue, 14 Jun 2016 12:40:17 -0700 Subject: [PATCH 5/5] Update OpenDebugAD7 reference. --- src/coreclr-debug/install.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr-debug/install.ts b/src/coreclr-debug/install.ts index 892e565e10..58a9fa2718 100644 --- a/src/coreclr-debug/install.ts +++ b/src/coreclr-debug/install.ts @@ -164,7 +164,7 @@ export class DebugInstaller dependencies: { "Microsoft.VisualStudio.clrdbg": "14.0.25406-preview-3044032", "Microsoft.VisualStudio.clrdbg.MIEngine": "14.0.30610-preview-1", - "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20610-preview-3", + "Microsoft.VisualStudio.OpenDebugAD7": "1.0.20614-preview-2", "NETStandard.Library": "1.5.0-rc2-24027", "Newtonsoft.Json": "7.0.1", "Microsoft.VisualStudio.Debugger.Interop.Portable": "1.0.1",