Skip to content

Commit 301ca1d

Browse files
authored
Merge branch 'master' into users/winstonliu/feature-nullability
2 parents 5d02faf + ef7d6cc commit 301ca1d

File tree

5 files changed

+178
-12
lines changed

5 files changed

+178
-12
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: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export async function getDotnetInfo(dotNetCliPaths: string[]): Promise<DotnetInf
2020
return _dotnetInfo;
2121
}
2222

23-
let dotnetExeName = CoreClrDebugUtil.getPlatformExeExtension();
24-
let dotnetExecutablePath = undefined;
23+
let dotnetExeName = join('dotnet', CoreClrDebugUtil.getPlatformExeExtension());
24+
let dotnetExecutablePath: string | undefined = undefined;
2525

2626
for (const dotnetPath of dotNetCliPaths) {
2727
let dotnetFullPath = join(dotnetPath, dotnetExeName);
@@ -31,13 +31,12 @@ export async function getDotnetInfo(dotNetCliPaths: string[]): Promise<DotnetInf
3131
}
3232
}
3333

34-
let dotnetInfo = new DotnetInfo();
34+
const dotnetInfo = new DotnetInfo();
3535

3636
try {
37-
let data = await execChildProcess(`${dotnetExecutablePath || 'dotnet'} --info`, process.cwd());
38-
39-
dotnetInfo.CliPath = dotnetExecutablePath;
37+
let data = await execChildProcess(`${dotnetExecutablePath || 'dotnet'} --info`, process.cwd(), process.env);
4038

39+
dotnetInfo.CliPath = dotnetExecutablePath;
4140
dotnetInfo.FullInfo = data;
4241

4342
let lines: string[] = data.replace(/\r/mg, '').split('\n');

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)