Skip to content

Commit 320d55c

Browse files
committed
Delete dotnet.dotnetPath option and migrate to replacements
1 parent 603bd60 commit 320d55c

13 files changed

+377
-80
lines changed

.devcontainer/devcontainer.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
// Set the context to the workspace folder to allow us to copy files from it.
88
"context": ".."
99
},
10+
"mounts": [
11+
"type=volume,target=${containerWorkspaceFolder}/node_modules"
12+
],
1013
"customizations": {
1114
"vscode": {
1215
"settings": {
@@ -37,7 +40,8 @@
3740
"powershell.integratedConsole.showOnStartup": false,
3841
"powershell.startAutomatically": false,
3942
// ms-azure-devops.azure-pipelines settings
40-
"azure-pipelines.customSchemaFile": ".vscode/dnceng-schema.json"
43+
"azure-pipelines.customSchemaFile": ".vscode/dnceng-schema.json",
44+
"jest.jestCommandLine": "./node_modules/.bin/jest"
4145
},
4246
"extensions": [
4347
"ms-dotnettools.csharp",
@@ -52,5 +56,5 @@
5256
]
5357
}
5458
},
55-
"postCreateCommand": "npm ci && npx gulp installDependencies"
59+
"postCreateCommand": "npm i && npx gulp installDependencies && npm i -g gulp"
5660
}

.vscode/settings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@
2020
"editor.formatOnSave": false,
2121
"eslint.lintTask.enable": true,
2222
"dotnet.defaultSolution": "disable",
23-
"jest.autoRun": "off"
23+
"jest.autoRun": "off",
2424
}

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -1405,11 +1405,6 @@
14051405
"default": false,
14061406
"description": "%configuration.dotnet.preferCSharpExtension%"
14071407
},
1408-
"dotnet.dotnetPath": {
1409-
"type": "string",
1410-
"scope": "machine-overridable",
1411-
"description": "%configuration.dotnet.dotnetPath%"
1412-
},
14131408
"dotnet.server.path": {
14141409
"type": "string",
14151410
"scope": "machine-overridable",
@@ -1536,6 +1531,11 @@
15361531
"description": "%configuration.omnisharp.dotnet.server.useOmnisharp%",
15371532
"order": 0
15381533
},
1534+
"omnisharp.dotnetPath": {
1535+
"type": "string",
1536+
"scope": "machine-overridable",
1537+
"description": "%configuration.omnisharp.dotnetPath%"
1538+
},
15391539
"csharp.format.enable": {
15401540
"type": "boolean",
15411541
"default": true,

package.nls.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
"command.dotnet.test.debugTestsInContext": "Debug Tests in Context",
2525
"command.dotnet.restartServer": "Restart Language Server",
2626
"configuration.dotnet.defaultSolution.description": "The path of the default solution to be opened in the workspace, or set to 'disable' to skip it. (Previously `omnisharp.defaultLaunchSolution`)",
27-
"configuration.dotnet.dotnetPath": "Specifies the path to a dotnet installation directory to use instead of the default system one. This only influences the dotnet installation to use for hosting the language server itself. Example: \"/home/username/mycustomdotnetdirectory\".",
2827
"configuration.dotnet.server.path": "Specifies the absolute path to the server (LSP or O#) executable. When left empty the version pinned to the C# Extension is used. (Previously `omnisharp.path`)",
2928
"configuration.dotnet.server.componentPaths": "Allows overriding the folder path for built in components of the language server (for example, override the .roslynDevKit path in the extension directory to use locally built components)",
3029
"configuration.dotnet.server.componentPaths.roslynDevKit": "Overrides the folder path for the .roslynDevKit component of the language server",
@@ -86,6 +85,7 @@
8685
]
8786
},
8887
"configuration.omnisharp.dotnet.server.useOmnisharp": "Switches to use the Omnisharp server for language features when enabled (requires restart). This option will not be honored with C# Dev Kit installed.",
88+
"configuration.omnisharp.dotnetPath": "Specifies the path to a dotnet installation directory to use instead of the default system one. This only influences the dotnet installation to use for hosting the OmniSharp server itself. Example: \"/home/username/mycustomdotnetdirectory\".",
8989
"configuration.omnisharp.csharp.format.enable": "Enable/disable default C# formatter (requires restart).",
9090
"configuration.omnisharp.csharp.suppressDotnetInstallWarning": "Suppress the warning that the .NET Core SDK is not on the path.",
9191
"configuration.omnisharp.csharp.suppressDotnetRestoreNotification": "Suppress the notification window to perform a 'dotnet restore' when dependencies can't be resolved.",

src/lsptoolshost/dotnetRuntimeExtensionResolver.ts

+25-35
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as vscode from 'vscode';
88
import { HostExecutableInformation } from '../shared/constants/hostExecutableInformation';
99
import { IHostExecutableResolver } from '../shared/constants/IHostExecutableResolver';
1010
import { PlatformInformation } from '../shared/platform';
11-
import { commonOptions, languageServerOptions } from '../shared/options';
11+
import { languageServerOptions } from '../shared/options';
1212
import { existsSync } from 'fs';
1313
import { CSharpExtensionId } from '../constants/csharpExtensionId';
1414
import { readFile } from 'fs/promises';
@@ -36,40 +36,34 @@ export class DotnetRuntimeExtensionResolver implements IHostExecutableResolver {
3636
private hostInfo: HostExecutableInformation | undefined;
3737

3838
async getHostExecutableInfo(): Promise<HostExecutableInformation> {
39-
let dotnetExecutablePath: string;
40-
if (commonOptions.dotnetPath) {
41-
const dotnetExecutableName = this.getDotnetExecutableName();
42-
dotnetExecutablePath = path.join(commonOptions.dotnetPath, dotnetExecutableName);
43-
} else {
44-
if (this.hostInfo) {
45-
return this.hostInfo;
46-
}
39+
if (this.hostInfo) {
40+
return this.hostInfo;
41+
}
4742

48-
this.channel.appendLine(`Locating .NET runtime version ${DotNetRuntimeVersion}`);
49-
const extensionArchitecture = (await this.getArchitectureFromTargetPlatform()) ?? process.arch;
50-
const findPathRequest: IDotnetFindPathContext = {
51-
acquireContext: {
52-
version: DotNetRuntimeVersion,
53-
requestingExtensionId: CSharpExtensionId,
54-
architecture: extensionArchitecture,
55-
mode: 'runtime',
56-
},
57-
versionSpecRequirement: 'greater_than_or_equal',
58-
};
59-
let acquireResult = await vscode.commands.executeCommand<IDotnetAcquireResult | undefined>(
60-
'dotnet.findPath',
61-
findPathRequest
43+
this.channel.appendLine(`Locating .NET runtime version ${DotNetRuntimeVersion}`);
44+
const extensionArchitecture = (await this.getArchitectureFromTargetPlatform()) ?? process.arch;
45+
const findPathRequest: IDotnetFindPathContext = {
46+
acquireContext: {
47+
version: DotNetRuntimeVersion,
48+
requestingExtensionId: CSharpExtensionId,
49+
architecture: extensionArchitecture,
50+
mode: 'runtime',
51+
},
52+
versionSpecRequirement: 'greater_than_or_equal',
53+
};
54+
let acquireResult = await vscode.commands.executeCommand<IDotnetAcquireResult | undefined>(
55+
'dotnet.findPath',
56+
findPathRequest
57+
);
58+
if (acquireResult === undefined) {
59+
this.channel.appendLine(
60+
`Did not find .NET ${DotNetRuntimeVersion} on path, falling back to acquire runtime via ms-dotnettools.vscode-dotnet-runtime`
6261
);
63-
if (acquireResult === undefined) {
64-
this.channel.appendLine(
65-
`Did not find .NET ${DotNetRuntimeVersion} on path, falling back to acquire runtime via ms-dotnettools.vscode-dotnet-runtime`
66-
);
67-
acquireResult = await this.acquireDotNetProcessDependencies();
68-
}
69-
70-
dotnetExecutablePath = acquireResult.dotnetPath;
62+
acquireResult = await this.acquireDotNetProcessDependencies();
7163
}
7264

65+
const dotnetExecutablePath = acquireResult.dotnetPath;
66+
7367
const hostInfo = {
7468
version: '' /* We don't need to know the version - we've already downloaded the correct one */,
7569
path: dotnetExecutablePath,
@@ -186,8 +180,4 @@ export class DotnetRuntimeExtensionResolver implements IHostExecutableResolver {
186180
throw new Error(`Unknown extension target platform: ${targetPlatform}`);
187181
}
188182
}
189-
190-
private getDotnetExecutableName(): string {
191-
return this.platformInfo.isWindows() ? 'dotnet.exe' : 'dotnet';
192-
}
193183
}

src/main.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ import { TelemetryEventNames } from './shared/telemetryEventNames';
4747
export async function activate(
4848
context: vscode.ExtensionContext
4949
): Promise<CSharpExtensionExports | OmnisharpExtensionExports | null> {
50+
const csharpChannel = vscode.window.createOutputChannel('C#', { log: true });
51+
5052
await MigrateOptions(vscode);
5153
const optionStream = createOptionStream(vscode);
5254

@@ -67,7 +69,6 @@ export async function activate(
6769
// ensure it gets properly disposed. Upon disposal the events will be flushed.
6870
context.subscriptions.push(reporter);
6971

70-
const csharpChannel = vscode.window.createOutputChannel('C#', { log: true });
7172
const csharpchannelObserver = new CsharpChannelObserver(csharpChannel);
7273
const csharpLogObserver = new CsharpLoggerObserver(csharpChannel);
7374
eventStream.subscribe(csharpchannelObserver.post);

src/omnisharp/dotnetResolver.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { promisify } from 'util';
1010
import { HostExecutableInformation } from '../shared/constants/hostExecutableInformation';
1111
import { IHostExecutableResolver } from '../shared/constants/IHostExecutableResolver';
1212
import { PlatformInformation } from '../shared/platform';
13-
import { commonOptions } from '../shared/options';
13+
import { omnisharpOptions } from '../shared/options';
1414

1515
export class DotnetResolver implements IHostExecutableResolver {
1616
private readonly minimumDotnetVersion = '6.0.100';
@@ -21,7 +21,7 @@ export class DotnetResolver implements IHostExecutableResolver {
2121
const dotnet = this.platformInfo.isWindows() ? 'dotnet.exe' : 'dotnet';
2222
const env = { ...process.env };
2323

24-
const dotnetPathOption = commonOptions.dotnetPath;
24+
const dotnetPathOption = omnisharpOptions.dotnetPath;
2525
if (dotnetPathOption.length > 0) {
2626
env['PATH'] = dotnetPathOption + path.delimiter + env['PATH'];
2727
}

src/shared/configurationProvider.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {
1616
} from '../shared/processPicker';
1717
import { PlatformInformation } from './platform';
1818
import { getCSharpDevKit } from '../utils/getCSharpDevKit';
19-
import { commonOptions } from './options';
2019
import {
2120
ActionOption,
2221
showErrorMessageWithOptions,
@@ -150,7 +149,7 @@ export class BaseVsDbgConfigurationProvider implements vscode.DebugConfiguration
150149
}
151150

152151
if (debugConfiguration.checkForDevCert) {
153-
if (!(await this.checkForDevCerts(commonOptions.dotnetPath))) {
152+
if (!(await this.checkForDevCerts())) {
154153
return undefined;
155154
}
156155
}
@@ -235,11 +234,11 @@ export class BaseVsDbgConfigurationProvider implements vscode.DebugConfiguration
235234
}
236235
}
237236

238-
private async checkForDevCerts(dotnetPath: string): Promise<boolean> {
237+
private async checkForDevCerts(): Promise<boolean> {
239238
let result: boolean | undefined = undefined;
240239

241240
while (result === undefined) {
242-
const returnData = await hasDotnetDevCertsHttps(dotnetPath);
241+
const returnData = await hasDotnetDevCertsHttps();
243242
const errorCode = returnData.error?.code;
244243
if (
245244
errorCode === CertToolStatusCodes.CertificateNotTrusted ||
@@ -261,7 +260,7 @@ export class BaseVsDbgConfigurationProvider implements vscode.DebugConfiguration
261260
);
262261

263262
if (dialogResult === labelYes) {
264-
const returnData = await createSelfSignedCert(dotnetPath);
263+
const returnData = await createSelfSignedCert();
265264
if (returnData.error === null) {
266265
// if the process returns 0, returnData.error is null, otherwise the return code can be accessed in returnData.error.code
267266
const message = errorCode === CertToolStatusCodes.CertificateNotTrusted ? 'trusted' : 'created';

src/shared/migrateOptions.ts

+102
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,20 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import * as fs from 'fs';
7+
import * as path from 'path';
68
import { types } from 'util';
79
import { ConfigurationTarget, vscode, WorkspaceConfiguration } from '../vscodeAdapter';
10+
import { CSharpExtensionId } from '../constants/csharpExtensionId';
11+
import { commonOptions } from './options';
12+
13+
export interface IDotnetAcquisitionExistingPaths {
14+
extensionId: string;
15+
path: string;
16+
}
17+
18+
export const dotnetPathOption = 'dotnet.dotnetPath';
19+
export const dotnetAcquisitionExtensionOption = 'dotnetAcquisitionExtension.existingDotnetPath';
820

921
// Option in the array should be identical to each other, except the name.
1022
export const migrateOptions = [
@@ -111,6 +123,96 @@ export async function MigrateOptions(vscode: vscode): Promise<void> {
111123
await MoveOptionsValue(oldName, newName, configuration);
112124
}
113125
}
126+
127+
await migrateDotnetPathOption(vscode);
128+
}
129+
130+
async function migrateDotnetPathOption(vscode: vscode): Promise<void> {
131+
const configuration = vscode.workspace.getConfiguration();
132+
133+
if (commonOptions.useOmnisharpServer) {
134+
// Migrate to O# specific option.
135+
await MoveOptionsValue(dotnetPathOption, 'omnisharp.dotnetPath', configuration);
136+
} else {
137+
const oldOptionInspect = configuration.inspect<string>(dotnetPathOption);
138+
if (
139+
!oldOptionInspect ||
140+
(!oldOptionInspect.globalValue &&
141+
!oldOptionInspect.workspaceValue &&
142+
!oldOptionInspect.workspaceFolderValue)
143+
) {
144+
// No value is set, nothing to migrate.
145+
return;
146+
}
147+
148+
const newOptionInspect = configuration.inspect<IDotnetAcquisitionExistingPaths[]>(
149+
dotnetAcquisitionExtensionOption
150+
);
151+
152+
if (oldOptionInspect.globalValue) {
153+
await migrateSingleDotnetPathValue(
154+
dotnetPathOption,
155+
oldOptionInspect.globalValue,
156+
dotnetAcquisitionExtensionOption,
157+
newOptionInspect?.globalValue,
158+
configuration,
159+
ConfigurationTarget.Global
160+
);
161+
}
162+
163+
if (oldOptionInspect.workspaceValue) {
164+
await migrateSingleDotnetPathValue(
165+
dotnetPathOption,
166+
oldOptionInspect.workspaceValue,
167+
dotnetAcquisitionExtensionOption,
168+
newOptionInspect?.workspaceValue,
169+
configuration,
170+
ConfigurationTarget.Workspace
171+
);
172+
}
173+
174+
if (oldOptionInspect.workspaceFolderValue) {
175+
await migrateSingleDotnetPathValue(
176+
dotnetPathOption,
177+
oldOptionInspect.workspaceFolderValue,
178+
dotnetAcquisitionExtensionOption,
179+
newOptionInspect?.workspaceFolderValue,
180+
configuration,
181+
ConfigurationTarget.WorkspaceFolder
182+
);
183+
}
184+
}
185+
}
186+
187+
async function migrateSingleDotnetPathValue(
188+
oldOptionName: string,
189+
oldValue: string,
190+
newOptionName: string,
191+
currentNewValue: IDotnetAcquisitionExistingPaths[] | undefined,
192+
configuration: WorkspaceConfiguration,
193+
configurationTarget: ConfigurationTarget
194+
): Promise<void> {
195+
// Migrate to .NET install tool specific option.
196+
// This requires some adjustments as the .NET install tool expects the full path to the exe and can already have a value set (e.g. a diff extension).
197+
const extension = process.platform === 'win32' ? '.exe' : '';
198+
const newValue = path.join(oldValue, `dotnet${extension}`);
199+
200+
if (!fs.existsSync(newValue)) {
201+
// If the existing option points to a location that doesn't exist, we'll just remove the old value.
202+
configuration.update(oldOptionName, undefined, configurationTarget);
203+
return;
204+
}
205+
206+
currentNewValue = currentNewValue ?? [];
207+
if (currentNewValue && currentNewValue.filter((p) => p.extensionId === CSharpExtensionId).length !== 0) {
208+
// There's already a dotnet path set for this extension, we don't want to overwrite it. Just delete the old one.
209+
await configuration.update(oldOptionName, undefined, configurationTarget);
210+
return;
211+
}
212+
213+
currentNewValue.push({ extensionId: CSharpExtensionId, path: newValue });
214+
await configuration.update(newOptionName, currentNewValue, configurationTarget);
215+
await configuration.update(oldOptionName, undefined, configurationTarget);
114216
}
115217

116218
function shouldMove(newOptionValue: unknown, defaultInspectValueOfNewOption: unknown): boolean {

0 commit comments

Comments
 (0)