Skip to content

Commit 6a93987

Browse files
authored
Merge pull request #715 from chuckries/versioncheck
Versioncheck
2 parents 77f753a + cc293bf commit 6a93987

File tree

4 files changed

+117
-81
lines changed

4 files changed

+117
-81
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "csharp",
33
"publisher": "ms-vscode",
4-
"version": "1.4.0-beta7",
4+
"version": "1.4.0-beta8",
55
"description": "C# for Visual Studio Code (powered by OmniSharp).",
66
"displayName": "C#",
77
"author": "Microsoft Corporation",

src/coreclr-debug/activate.ts

Lines changed: 97 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,26 @@
55
'use strict';
66

77
import * as vscode from 'vscode';
8-
import * as child_process from 'child_process';
98
import * as fs from 'fs';
10-
import * as path from 'path';
119
import TelemetryReporter from 'vscode-extension-telemetry';
1210
import { CoreClrDebugUtil } from './util';
1311
import * as debugInstall from './install';
1412
import { Platform, getCurrentPlatform } from './../platform';
13+
import * as semver from 'semver';
14+
15+
const MINIMUM_SUPPORTED_DOTNET_CLI: string = '1.0.0-preview2-003121';
1516

1617
let _reporter: TelemetryReporter = null;
1718
let _channel: vscode.OutputChannel = null;
1819
let _util: CoreClrDebugUtil = null;
1920

21+
class DotnetInfo
22+
{
23+
public Version: string;
24+
public OsVersion: string;
25+
public RuntimeId: string;
26+
}
27+
2028
export function activate(context: vscode.ExtensionContext, reporter: TelemetryReporter) {
2129
_reporter = reporter;
2230
_channel = vscode.window.createOutputChannel('coreclr-debug');
@@ -27,22 +35,7 @@ export function activate(context: vscode.ExtensionContext, reporter: TelemetryRe
2735
return;
2836
}
2937

30-
let dotnetVersion: string = '';
31-
let osVersion: string = '';
32-
let osRID: string = '';
33-
_util.spawnChildProcess('dotnet', ['--info'], _util.coreClrDebugDir(), (data: Buffer) => {
34-
var lines: string[] = data.toString().replace(/\r/mg, '').split('\n');
35-
lines.forEach(line => {
36-
let match: RegExpMatchArray;
37-
if (match = /^\ Version:\s*([^\s].*)$/.exec(line)) {
38-
dotnetVersion = match[1];
39-
} else if (match = /^\ OS Version:\s*([^\s].*)$/.exec(line)) {
40-
osVersion = match[1];
41-
} else if (match = /^\ RID:\s*([\w\-\.]+)$/.exec(line)) {
42-
osRID = match[1];
43-
}
44-
});
45-
}).then(() => {
38+
checkForDotnetTools().then((dotnetInfo: DotnetInfo) => {
4639
let installer = new debugInstall.DebugInstaller(_util);
4740
_util.createInstallLog();
4841

@@ -61,54 +54,98 @@ export function activate(context: vscode.ExtensionContext, reporter: TelemetryRe
6154
statusBarMessage.dispose();
6255
vscode.window.setStatusBarMessage('Successfully installed .NET Core Debugger.');
6356
}).catch((error: debugInstall.InstallError) => {
64-
const viewLogMessage = "View Log";
65-
vscode.window.showErrorMessage('Error while installing .NET Core Debugger.', viewLogMessage).then(value => {
66-
if (value === viewLogMessage) {
67-
_channel.show(vscode.ViewColumn.Three);
68-
}
69-
});
70-
statusBarMessage.dispose();
71-
72-
installStage = error.installStage;
73-
installError = error.errorMessage;
74-
moreErrors = error.hasMoreErrors ? 'true' : 'false';
75-
}).then(() => {
76-
// log telemetry and delete install begin file
77-
logTelemetry('Acquisition', {
78-
installStage: installStage,
79-
installError: installError,
80-
moreErrors: moreErrors,
81-
dotnetVersion: dotnetVersion,
82-
osVersion: osVersion,
83-
osRID: osRID
84-
});
85-
try {
86-
deleteInstallBeginFile();
87-
} catch (err) {
88-
// if this throws there's really nothing we can do
57+
const viewLogMessage = "View Log";
58+
vscode.window.showErrorMessage('Error while installing .NET Core Debugger.', viewLogMessage).then(value => {
59+
if (value === viewLogMessage) {
60+
_channel.show(vscode.ViewColumn.Three);
8961
}
90-
_util.closeInstallLog();
9162
});
92-
}).catch(() => {
93-
const config = vscode.workspace.getConfiguration('csharp');
94-
if (!config.get('suppressDotnetInstallWarning', false)) {
95-
const getDotNetMessage = 'Get .NET CLI tools';
96-
const goToSettingsMessage = 'Disable this message in user settings';
97-
// Buttons are shown in right-to-left order, with a close button to the right of everything;
98-
// getDotNetMessage will be the first button, then goToSettingsMessage, then the close button.
99-
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.',
100-
goToSettingsMessage, getDotNetMessage).then(value => {
101-
if (value === getDotNetMessage) {
102-
let open = require('open');
103-
open('https://www.microsoft.com/net/core');
104-
} else if (value === goToSettingsMessage) {
105-
vscode.commands.executeCommand('workbench.action.openGlobalSettings');
106-
}
107-
});
63+
statusBarMessage.dispose();
64+
65+
installStage = error.installStage;
66+
installError = error.errorMessage;
67+
moreErrors = error.hasMoreErrors ? 'true' : 'false';
68+
}).then(() => {
69+
// log telemetry and delete install begin file
70+
logTelemetry('Acquisition', {
71+
installStage: installStage,
72+
installError: installError,
73+
moreErrors: moreErrors,
74+
dotnetVersion: dotnetInfo.Version,
75+
osVersion: dotnetInfo.OsVersion,
76+
osRID: dotnetInfo.RuntimeId
77+
});
78+
try {
79+
deleteInstallBeginFile();
80+
} catch (err) {
81+
// if this throws there's really nothing we can do
82+
}
83+
_util.closeInstallLog();
84+
});
85+
}).catch((error) => {
86+
// log errors from checkForDotnetTools
87+
_util.log(error.message);
88+
});
89+
}
90+
91+
// This function checks for the presence of dotnet on the path and ensures the Version
92+
// is new enough for us. Any error UI that needs to be displayed is handled by this function.
93+
// Returns: a promise that returns a DotnetInfo class
94+
// Throws: An Error() from the return promise if either dotnet does not exist or is too old.
95+
function checkForDotnetTools() : Promise<DotnetInfo>
96+
{
97+
let dotnetInfo = new DotnetInfo();
98+
99+
return _util.spawnChildProcess('dotnet', ['--info'], _util.coreClrDebugDir(), (data: Buffer) => {
100+
let lines: string[] = data.toString().replace(/\r/mg, '').split('\n');
101+
lines.forEach(line => {
102+
let match: RegExpMatchArray;
103+
if (match = /^\ Version:\s*([^\s].*)$/.exec(line)) {
104+
dotnetInfo.Version = match[1];
105+
} else if (match = /^\ OS Version:\s*([^\s].*)$/.exec(line)) {
106+
dotnetInfo.OsVersion = match[1];
107+
} else if (match = /^\ RID:\s*([\w\-\.]+)$/.exec(line)) {
108+
dotnetInfo.RuntimeId = match[1];
109+
}
110+
});
111+
}).catch((error) => {
112+
// something went wrong with spawning 'dotnet --info'
113+
let message = '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.';
114+
showDotnetToolsWarning(message);
115+
throw new Error("Failed to spawn 'dotnet --info'");
116+
}).then(() => {
117+
// succesfully spawned 'dotnet --info', check the Version
118+
if (semver.lt(dotnetInfo.Version, MINIMUM_SUPPORTED_DOTNET_CLI))
119+
{
120+
let message = 'The .NET CLI tools on the path are too old. .NET Core debugging will not be enabled. The minimum supported version is ' + MINIMUM_SUPPORTED_DOTNET_CLI + '.';
121+
showDotnetToolsWarning(message);
122+
throw new Error("dotnet cli is too old");
108123
}
124+
125+
return dotnetInfo;
109126
});
110127
}
111128

129+
function showDotnetToolsWarning(message: string) : void
130+
{
131+
const config = vscode.workspace.getConfiguration('csharp');
132+
if (!config.get('suppressDotnetInstallWarning', false)) {
133+
const getDotNetMessage = 'Get .NET CLI tools';
134+
const goToSettingsMessage = 'Disable this message in user settings';
135+
// Buttons are shown in right-to-left order, with a close button to the right of everything;
136+
// getDotNetMessage will be the first button, then goToSettingsMessage, then the close button.
137+
vscode.window.showErrorMessage(message,
138+
goToSettingsMessage, getDotNetMessage).then(value => {
139+
if (value === getDotNetMessage) {
140+
let open = require('open');
141+
open('https://www.microsoft.com/net/core');
142+
} else if (value === goToSettingsMessage) {
143+
vscode.commands.executeCommand('workbench.action.openGlobalSettings');
144+
}
145+
});
146+
}
147+
}
148+
112149
function logTelemetry(eventName: string, properties?: {[prop: string]: string}): void {
113150
if (_reporter !== null) {
114151
_reporter.sendTelemetryEvent('coreclr-debug/' + eventName, properties);

src/coreclr-debug/install.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import { CoreClrDebugUtil } from './util';
88
import * as fs from 'fs';
99
import * as path from 'path';
10-
import * as child_process from 'child_process';
1110
import * as fs_extra from 'fs-extra-promise';
1211

1312
export class InstallError extends Error {
@@ -53,22 +52,22 @@ export class DebugInstaller {
5352
}
5453

5554
public install(runtimeId: string): Promise<void> {
56-
var errorBuilder: InstallError = new InstallError();
55+
let errorBuilder: InstallError = new InstallError();
5756
errorBuilder.installStage = 'writeProjectJson';
5857

5958
return this.writeProjectJson(runtimeId).then(() => {
6059
errorBuilder.installStage = 'dotnetRestore';
6160
return this._util.spawnChildProcess('dotnet', ['--verbose', 'restore', '--configfile', 'NuGet.config'], this._util.coreClrDebugDir(),
6261
(data: Buffer) => {
63-
var text: string = data.toString();
62+
let text: string = data.toString();
6463
this._util.logRaw(text);
6564

6665
// Certain errors are only logged to stdout.
6766
// Detect these and make a note of the kind of error.
6867
DebugInstaller.parseRestoreErrors(text, errorBuilder);
6968
},
7069
(data: Buffer) => {
71-
var text: string = data.toString();
70+
let text: string = data.toString();
7271
this._util.logRaw(text);
7372

7473
// Reference errors are sent to stderr at the end of restore.
@@ -78,7 +77,7 @@ export class DebugInstaller {
7877
errorBuilder.installStage = 'dotnetPublish';
7978
return this._util.spawnChildProcess('dotnet', ['--verbose', 'publish', '-r', runtimeId, '-o', this._util.debugAdapterDir()], this._util.coreClrDebugDir(),
8079
(data: Buffer) => {
81-
var text: string = data.toString();
80+
let text: string = data.toString();
8281
this._util.logRaw(text);
8382

8483
DebugInstaller.parsePublishErrors(text, errorBuilder);
@@ -253,7 +252,7 @@ export class DebugInstaller {
253252
}
254253

255254
private static parseRestoreErrors(output: string, errorBuilder: InstallError): void {
256-
var lines: string[] = output.replace(/\r/mg, '').split('\n');
255+
let lines: string[] = output.replace(/\r/mg, '').split('\n');
257256
lines.forEach(line => {
258257
if (line.startsWith('error')) {
259258
const connectionError: string = 'The server name or address could not be resolved';
@@ -271,16 +270,16 @@ export class DebugInstaller {
271270

272271
private static parseReferenceErrors(output: string, errorBuilder: InstallError): void {
273272
// Reference errors are restated at the end of the output. Find this section first.
274-
var errorRegionRegExp: RegExp = /^Errors in .*project\.json$/gm
275-
var beginIndex: number = output.search(errorRegionRegExp);
276-
var errorBlock: string = output.slice(beginIndex);
273+
let errorRegionRegExp: RegExp = /^Errors in .*project\.json$/gm;
274+
let beginIndex: number = output.search(errorRegionRegExp);
275+
let errorBlock: string = output.slice(beginIndex);
277276

278-
var lines: string[] = errorBlock.replace(/\r/mg, '').split('\n');
277+
let lines: string[] = errorBlock.replace(/\r/mg, '').split('\n');
279278
lines.forEach(line => {
280-
var referenceRegExp: RegExp = /^(?:\t|\ \ \ \ )Unable to resolve '([^']+)'/g
281-
var match: RegExpMatchArray;
279+
let referenceRegExp: RegExp = /^(?:\t|\ \ \ \ )Unable to resolve '([^']+)'/g;
280+
let match: RegExpMatchArray;
282281
while (match = referenceRegExp.exec(line)) {
283-
var reference: string = match[1];
282+
let reference: string = match[1];
284283
if (reference.startsWith('Microsoft') ||
285284
reference.startsWith('System') ||
286285
reference.startsWith('NETStandard') ||
@@ -294,15 +293,15 @@ export class DebugInstaller {
294293
}
295294

296295
private static parsePublishErrors(output: string, errorBuilder: InstallError): void {
297-
var lines: string[] = output.replace(/\r/mg, '').split('\n');
296+
let lines: string[] = output.replace(/\r/mg, '').split('\n');
298297
lines.forEach(line => {
299-
var errorTypeRegExp: RegExp = /^([\w\.]+Exception)/g
300-
var typeMatch: RegExpMatchArray;
298+
const errorTypeRegExp: RegExp = /^([\w\.]+Exception)/g;
299+
let typeMatch: RegExpMatchArray;
301300
while (typeMatch = errorTypeRegExp.exec(line)) {
302-
var type: string = typeMatch[1];
301+
let type: string = typeMatch[1];
303302
if (type === 'System.IO.IOException') {
304-
var ioExceptionRegExp: RegExp = /System\.IO\.IOException: The process cannot access the file '(.*)' because it is being used by another process./g
305-
var ioMatch: RegExpMatchArray;
303+
const ioExceptionRegExp: RegExp = /System\.IO\.IOException: The process cannot access the file '(.*)' because it is being used by another process./g;
304+
let ioMatch: RegExpMatchArray;
306305
if (ioMatch = ioExceptionRegExp.exec(line)) {
307306
// Remove path as it may contain user information.
308307
errorBuilder.errorMessage = `System.IO.IOException: unable to access '${path.basename(ioMatch[1])}'`;

src/coreclr-debug/util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export class CoreClrDebugUtil
149149

150150
child.on('error', (error: Error) => {
151151
reject(error);
152-
})
152+
});
153153
});
154154

155155
return promise;

0 commit comments

Comments
 (0)