Skip to content

Commit fd414e9

Browse files
committed
Merge branch 'master' into users/winstonliu/coreclr-debug-nullability
2 parents 2896b4f + f807baf commit fd414e9

File tree

5 files changed

+175
-8
lines changed

5 files changed

+175
-8
lines changed

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@
231231
"darwin"
232232
],
233233
"architectures": [
234-
"x86_64"
234+
"x86_64",
235+
"arm64"
235236
],
236237
"binaries": [
237238
"./mono.osx",
@@ -333,7 +334,7 @@
333334
},
334335
{
335336
"id": "OmniSharp",
336-
"description": "OmniSharp for Linux (Framework / arm64)",
337+
"description": "OmniSharp for Linux (Mono / arm64)",
337338
"url": "https://roslynomnisharp.blob.core.windows.net/releases/1.39.1/omnisharp-linux-arm64-1.39.1.zip",
338339
"installPath": ".omnisharp/1.39.1",
339340
"platforms": [
@@ -1013,7 +1014,7 @@
10131014
"default": true,
10141015
"description": "Specifies whether the OmniSharp server will be automatically started or not. If false, OmniSharp can be started with the 'Restart OmniSharp' command"
10151016
},
1016-
"omnisharp.projectFilesExcludePattern" :{
1017+
"omnisharp.projectFilesExcludePattern": {
10171018
"type": "string",
10181019
"default": "**/node_modules/**,**/.git/**,**/bower_components/**",
10191020
"description": "The exclude pattern used by OmniSharp to find all project files."
@@ -4104,4 +4105,4 @@
41044105
}
41054106
]
41064107
}
4107-
}
4108+
}

src/omnisharp/requirementCheck.ts

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from "vscode";
7+
import * as semver from "semver";
8+
import { getDotnetInfo } from "../utils/getDotnetInfo";
9+
import { Options } from "./options";
10+
import { getMonoVersion } from "../utils/getMonoVersion";
11+
import { OmniSharpMonoResolver } from "./OmniSharpMonoResolver";
12+
import { getMSBuildVersion } from "../utils/getMSBuildInfo";
13+
14+
export interface RequirementResult {
15+
needsDotNetSdk: boolean;
16+
needsMono: boolean;
17+
needsMSBuildTools: boolean;
18+
}
19+
20+
export async function validateRequirements(options: Options): Promise<boolean> {
21+
const result = await checkRequirements(options);
22+
23+
if (result.needsDotNetSdk) {
24+
const downloadSdk = await promptToDownloadDotNetSDK();
25+
26+
if (downloadSdk === PromptResult.Yes) {
27+
let dotnetcoreURL = 'https://dot.net/core-sdk-vscode';
28+
vscode.env.openExternal(vscode.Uri.parse(dotnetcoreURL));
29+
} else if (downloadSdk === PromptResult.No) {
30+
vscode.commands.executeCommand('workbench.action.openGlobalSettings');
31+
}
32+
33+
return false;
34+
}
35+
36+
if (result.needsMono
37+
|| result.needsMSBuildTools) { // Since we are currently not checking for MSBuild Tools on Windows this indicates a partial install of Mono.
38+
39+
const downloadMono = await promptToDownloadMono();
40+
41+
if (downloadMono === PromptResult.Yes) {
42+
let monoURL = 'https://www.mono-project.com/download/stable/';
43+
vscode.env.openExternal(vscode.Uri.parse(monoURL));
44+
} else if (downloadMono === PromptResult.No) {
45+
vscode.commands.executeCommand('workbench.action.openGlobalSettings');
46+
}
47+
48+
return false;
49+
}
50+
51+
return true;
52+
}
53+
54+
async function checkRequirements(options: Options): Promise<RequirementResult> {
55+
if (options.useModernNet) {
56+
const dotnetInfo = await getDotnetInfo(options.dotNetCliPaths);
57+
const needsDotNetSdk = dotnetInfo.Version === undefined || semver.lt(dotnetInfo.Version, '6.0.0');
58+
return {
59+
needsDotNetSdk,
60+
needsMono: false,
61+
needsMSBuildTools: false,
62+
};
63+
}
64+
65+
if (process.platform === 'win32') {
66+
// Need to determine way to surface missing MSBuild Tools for windows.
67+
return {
68+
needsMSBuildTools: false,
69+
needsDotNetSdk: false,
70+
needsMono: false,
71+
};
72+
}
73+
else {
74+
const monoResolver = new OmniSharpMonoResolver(getMonoVersion);
75+
let monoError: Error | undefined;
76+
try {
77+
await monoResolver.getHostExecutableInfo(options);
78+
} catch (e) {
79+
monoError = e;
80+
}
81+
82+
const msbuildVersion = await getMSBuildVersion();
83+
84+
return {
85+
needsMono: monoError !== undefined,
86+
needsDotNetSdk: false,
87+
needsMSBuildTools: msbuildVersion !== undefined,
88+
};
89+
}
90+
}
91+
92+
enum PromptResult {
93+
Dismissed,
94+
Yes,
95+
No
96+
}
97+
98+
interface PromptItem extends vscode.MessageItem {
99+
result: PromptResult;
100+
}
101+
102+
async function promptToDownloadDotNetSDK() {
103+
return new Promise<PromptResult>((resolve, reject) => {
104+
const message = 'OmniSharp requires an install of the .NET SDK to provide language services when `omnisharp.useModernNet` is enabled in Settings. Please install the latest .NET SDK and restart vscode. If you continue see this error after installing .NET and restarting vscode, you may need to log out and log back in or restart your system for changes to the PATH to take effect.';
105+
106+
const messageOptions: vscode.MessageOptions = { modal: true };
107+
108+
const yesItem: PromptItem = { title: 'Get the SDK', result: PromptResult.Yes };
109+
const noItem: PromptItem = { title: 'Open settings', result: PromptResult.No, isCloseAffordance: true };
110+
111+
vscode.window.showErrorMessage(message, messageOptions, noItem, yesItem)
112+
.then(selection => resolve(selection?.result ?? PromptResult.Dismissed));
113+
});
114+
}
115+
116+
async function promptToDownloadMono() {
117+
return new Promise<PromptResult>((resolve, reject) => {
118+
const message = 'OmniSharp requires a complete install of Mono (including MSBuild) to provide language services when `omnisharp.useModernNet` is disabled in Settings. Please install the latest Mono and restart.';
119+
120+
const messageOptions: vscode.MessageOptions = { modal: true };
121+
122+
const yesItem: PromptItem = { title: 'Download Mono', result: PromptResult.Yes };
123+
const noItem: PromptItem = { title: 'Open settings', result: PromptResult.No, isCloseAffordance: true };
124+
125+
vscode.window.showErrorMessage(message, messageOptions, noItem, yesItem)
126+
.then(selection => resolve(selection?.result ?? PromptResult.Dismissed));
127+
});
128+
}

src/omnisharp/server.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import OptionProvider from '../observers/OptionProvider';
3333
import { IHostExecutableResolver } from '../constants/IHostExecutableResolver';
3434
import { showProjectSelector } from '../features/commands';
3535
import { removeBOMFromBuffer, removeBOMFromString } from '../utils/removeBOM';
36+
import { validateRequirements } from './requirementCheck';
3637

3738
enum ServerState {
3839
Starting,
@@ -277,6 +278,13 @@ export class OmniSharpServer {
277278
return;
278279
}
279280

281+
const options = this.optionProvider.GetLatestOptions();
282+
283+
if (!await validateRequirements(options)) {
284+
this.eventStream.post(new ObservableEvents.OmnisharpServerMessage("OmniSharp failed to start because of missing requirements."));
285+
return;
286+
}
287+
280288
const disposables = new CompositeDisposable();
281289

282290
disposables.add(this.onServerError(err =>
@@ -340,8 +348,6 @@ export class OmniSharpServer {
340348
const solutionPath = launchTarget.target;
341349
const cwd = path.dirname(solutionPath);
342350

343-
const options = this.optionProvider.GetLatestOptions();
344-
345351
const args = [
346352
'-z',
347353
'-s', solutionPath,

src/utils/getDotnetInfo.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export async function getDotnetInfo(dotNetCliPaths: string[]): Promise<DotnetInf
1515
return _dotnetInfo;
1616
}
1717

18-
let dotnetExeName = CoreClrDebugUtil.getPlatformExeExtension();
18+
let dotnetExeName = join('dotnet', CoreClrDebugUtil.getPlatformExeExtension());
1919
let dotnetExecutablePath: string | undefined;
2020

2121
for (const dotnetPath of dotNetCliPaths) {
@@ -27,7 +27,7 @@ export async function getDotnetInfo(dotNetCliPaths: string[]): Promise<DotnetInf
2727
}
2828

2929
try {
30-
const data = await execChildProcess(`${dotnetExecutablePath ?? 'dotnet'} --info`, process.cwd());
30+
const data = await execChildProcess(`${dotnetExecutablePath ?? 'dotnet'} --info`, process.cwd(), process.env);
3131

3232
const cliPath = dotnetExecutablePath;
3333
const fullInfo = data;

src/utils/getMSBuildInfo.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { join } from "path";
7+
import { execChildProcess } from "../common";
8+
import { CoreClrDebugUtil } from "../coreclr-debug/util";
9+
10+
export const MSBUILD_MISSING_MESSAGE = "A valid msbuild installation could not be found.";
11+
12+
let _msbuildVersion: string | undefined;
13+
14+
export async function getMSBuildVersion(): Promise<string | undefined> {
15+
if (_msbuildVersion !== undefined) {
16+
return _msbuildVersion;
17+
}
18+
19+
const msbuildExeName = join('msbuild', CoreClrDebugUtil.getPlatformExeExtension());
20+
21+
try {
22+
let data = await execChildProcess(`${msbuildExeName} --version --nologo`, process.cwd(), process.env);
23+
const match = /^(\d+\.\d+\.\d+\.\d+)$/.exec(data);
24+
if (match.length > 0) {
25+
_msbuildVersion = match[1];
26+
}
27+
}
28+
catch {
29+
}
30+
31+
return _msbuildVersion;
32+
}

0 commit comments

Comments
 (0)