Skip to content

Commit 30681bb

Browse files
authored
Merge pull request #12649 from karthiknadig/release-pick
Cherry picks for point release
2 parents bd0b9d0 + ed449dc commit 30681bb

13 files changed

+208
-102
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,3 @@ ptvsd*.log
4242
pydevd*.log
4343
nodeLanguageServer/**
4444
nodeLanguageServer.*/**
45-
bundledLanguageServer/**

news/2 Fixes/12614.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Stop looking for mspythonconfig.json file in subfolders.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
"onCommand:python.datascience.selectjupytercommandline",
9393
"onCommand:python.enableSourceMapSupport",
9494
"onNotebookEditor:jupyter-notebook",
95-
"workspaceContains:**/mspythonconfig.json"
95+
"workspaceContains:mspythonconfig.json"
9696
],
9797
"main": "./out/client/extension",
9898
"contributes": {

src/client/activation/activationService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ export class LanguageServerExtensionActivationService
287287
outputLine = 'Starting Microsoft Python language server.';
288288
break;
289289
case LanguageServerType.Node:
290-
outputLine = 'Starting Node.js language server.';
290+
outputLine = 'Starting Pylance language server.';
291291
break;
292292
case LanguageServerType.None:
293293
outputLine = 'Editor support is inactive since language server is set to None.';

src/client/activation/common/downloader.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ export class LanguageServerDownloader implements ILanguageServerDownloader {
5959
}
6060

6161
public async downloadLanguageServer(destinationFolder: string, resource: Resource): Promise<void> {
62-
if (this.lsFolderService.isBundled()) {
63-
// Sanity check; a bundled LS should never be downloaded.
64-
traceError('Attempted to download bundled language server');
62+
if (await this.lsFolderService.skipDownload()) {
63+
// Sanity check; this case should not be hit if skipDownload is true elsewhere.
64+
traceError('Attempted to download with skipDownload true.');
6565
return;
6666
}
6767

src/client/activation/common/languageServerFolderService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export abstract class LanguageServerFolderService implements ILanguageServerFold
2626
@unmanaged() protected readonly languageServerFolder: string
2727
) {}
2828

29-
public isBundled(): boolean {
29+
public async skipDownload(): Promise<boolean> {
3030
return false;
3131
}
3232

src/client/activation/node/languageClientFactory.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ export class NodeLanguageClientFactory implements ILanguageClientFactory {
3131
const commandArgs = (clientOptions.connectionOptions
3232
?.cancellationStrategy as FileBasedCancellationStrategy).getCommandLineArguments();
3333

34-
const languageServerFolder = await this.languageServerFolderService.getLanguageServerFolderName(resource);
35-
const bundlePath = path.join(EXTENSION_ROOT_DIR, languageServerFolder, 'server.bundle.js');
36-
const nonBundlePath = path.join(EXTENSION_ROOT_DIR, languageServerFolder, 'server.js');
34+
const folderName = await this.languageServerFolderService.getLanguageServerFolderName(resource);
35+
const languageServerFolder = path.isAbsolute(folderName)
36+
? folderName
37+
: path.join(EXTENSION_ROOT_DIR, folderName);
38+
39+
const bundlePath = path.join(languageServerFolder, 'server.bundle.js');
40+
const nonBundlePath = path.join(languageServerFolder, 'server.js');
3741
const modulePath = (await this.fs.fileExists(nonBundlePath)) ? nonBundlePath : bundlePath;
3842
const debugOptions = { execArgv: ['--nolazy', '--inspect=6600'] };
3943

src/client/activation/node/languageServerFolderService.ts

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,18 @@
33

44
'use strict';
55

6+
import * as assert from 'assert';
67
import { inject, injectable } from 'inversify';
7-
import * as semver from 'semver';
8-
import { IApplicationEnvironment, IWorkspaceService } from '../../common/application/types';
8+
import * as path from 'path';
9+
import { SemVer } from 'semver';
10+
import { IWorkspaceService } from '../../common/application/types';
911
import { NugetPackage } from '../../common/nuget/types';
10-
import { IConfigurationService, Resource } from '../../common/types';
12+
import { IConfigurationService, IExtensions, Resource } from '../../common/types';
1113
import { IServiceContainer } from '../../ioc/types';
12-
import { traceWarning } from '../../logging';
1314
import { LanguageServerFolderService } from '../common/languageServerFolderService';
14-
import {
15-
BundledLanguageServerFolder,
16-
FolderVersionPair,
17-
ILanguageServerFolderService,
18-
NodeLanguageServerFolder
19-
} from '../types';
15+
import { FolderVersionPair, ILanguageServerFolderService, NodeLanguageServerFolder } from '../types';
2016

21-
// Must match languageServerVersion* keys in package.json
22-
export const NodeLanguageServerVersionKey = 'languageServerVersionV2';
17+
export const PylanceExtensionName = 'ms-python.vscode-pylance';
2318

2419
class FallbackNodeLanguageServerFolderService extends LanguageServerFolderService {
2520
constructor(serviceContainer: IServiceContainer) {
@@ -31,62 +26,90 @@ class FallbackNodeLanguageServerFolderService extends LanguageServerFolderServic
3126
}
3227
}
3328

29+
// Exported for testing.
30+
export interface ILanguageServerFolder {
31+
path: string;
32+
version: string; // SemVer, in string form to avoid cross-extension type issues.
33+
}
34+
35+
// Exported for testing.
36+
export interface ILSExtensionApi {
37+
languageServerFolder?(): Promise<ILanguageServerFolder>;
38+
}
39+
3440
@injectable()
3541
export class NodeLanguageServerFolderService implements ILanguageServerFolderService {
36-
private readonly _bundledVersion: semver.SemVer | undefined;
3742
private readonly fallback: FallbackNodeLanguageServerFolderService;
3843

3944
constructor(
4045
@inject(IServiceContainer) serviceContainer: IServiceContainer,
41-
@inject(IConfigurationService) configService: IConfigurationService,
42-
@inject(IWorkspaceService) workspaceService: IWorkspaceService,
43-
@inject(IApplicationEnvironment) appEnv: IApplicationEnvironment
46+
@inject(IConfigurationService) private configService: IConfigurationService,
47+
@inject(IWorkspaceService) private workspaceService: IWorkspaceService,
48+
@inject(IExtensions) readonly extensions: IExtensions
4449
) {
4550
this.fallback = new FallbackNodeLanguageServerFolderService(serviceContainer);
46-
47-
// downloadLanguageServer is a bit of a misnomer; if false then this indicates that a local
48-
// development copy should be run instead of a "real" build, telemetry discarded, etc.
49-
// So, we require it to be true, even though in the bundled case no real download happens.
50-
if (
51-
configService.getSettings().downloadLanguageServer &&
52-
!workspaceService.getConfiguration('python').get<string>('packageName')
53-
) {
54-
const ver = appEnv.packageJson[NodeLanguageServerVersionKey] as string;
55-
this._bundledVersion = semver.parse(ver) || undefined;
56-
if (this._bundledVersion === undefined) {
57-
traceWarning(
58-
`invalid language server version ${ver} in package.json (${NodeLanguageServerVersionKey})`
59-
);
60-
}
61-
}
62-
}
63-
64-
public get bundledVersion(): semver.SemVer | undefined {
65-
return this._bundledVersion;
6651
}
6752

68-
public isBundled(): boolean {
69-
return this._bundledVersion !== undefined;
53+
public async skipDownload(): Promise<boolean> {
54+
return (await this.lsExtensionApi()) !== undefined;
7055
}
7156

7257
public async getLanguageServerFolderName(resource: Resource): Promise<string> {
73-
if (this._bundledVersion) {
74-
return BundledLanguageServerFolder;
58+
const lsf = await this.languageServerFolder();
59+
if (lsf) {
60+
assert.ok(path.isAbsolute(lsf.path));
61+
return lsf.path;
7562
}
7663
return this.fallback.getLanguageServerFolderName(resource);
7764
}
7865

7966
public async getLatestLanguageServerVersion(resource: Resource): Promise<NugetPackage | undefined> {
80-
if (this._bundledVersion) {
67+
if (await this.lsExtensionApi()) {
8168
return undefined;
8269
}
8370
return this.fallback.getLatestLanguageServerVersion(resource);
8471
}
8572

8673
public async getCurrentLanguageServerDirectory(): Promise<FolderVersionPair | undefined> {
87-
if (this._bundledVersion) {
88-
return { path: BundledLanguageServerFolder, version: this._bundledVersion };
74+
const lsf = await this.languageServerFolder();
75+
if (lsf) {
76+
assert.ok(path.isAbsolute(lsf.path));
77+
return {
78+
path: lsf.path,
79+
version: new SemVer(lsf.version)
80+
};
8981
}
9082
return this.fallback.getCurrentLanguageServerDirectory();
9183
}
84+
85+
protected async languageServerFolder(): Promise<ILanguageServerFolder | undefined> {
86+
const extension = await this.lsExtensionApi();
87+
if (!extension?.languageServerFolder) {
88+
return undefined;
89+
}
90+
return extension.languageServerFolder();
91+
}
92+
93+
private async lsExtensionApi(): Promise<ILSExtensionApi | undefined> {
94+
// downloadLanguageServer is a bit of a misnomer; if false then this indicates that a local
95+
// development copy should be run instead of a "real" build, telemetry discarded, etc.
96+
// So, we require it to be true, even though in the pinned case no real download happens.
97+
if (
98+
!this.configService.getSettings().downloadLanguageServer ||
99+
this.workspaceService.getConfiguration('python').get<string>('packageName')
100+
) {
101+
return undefined;
102+
}
103+
104+
const extension = this.extensions.getExtension<ILSExtensionApi>(PylanceExtensionName);
105+
if (!extension) {
106+
return undefined;
107+
}
108+
109+
if (!extension.isActive) {
110+
return extension.activate();
111+
}
112+
113+
return extension.exports;
114+
}
92115
}

src/client/activation/node/languageServerProxy.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33
import '../../common/extensions';
44

55
import { inject, injectable } from 'inversify';
6-
import { Disposable, LanguageClient, LanguageClientOptions } from 'vscode-languageclient';
6+
import {
7+
DidChangeConfigurationNotification,
8+
Disposable,
9+
LanguageClient,
10+
LanguageClientOptions
11+
} from 'vscode-languageclient';
712

13+
import { DeprecatePythonPath } from '../../common/experiments/groups';
814
import { traceDecorators, traceError } from '../../common/logger';
9-
import { IConfigurationService, Resource } from '../../common/types';
15+
import { IConfigurationService, IExperimentsManager, IInterpreterPathService, Resource } from '../../common/types';
1016
import { createDeferred, Deferred, sleep } from '../../common/utils/async';
1117
import { swallowExceptions } from '../../common/utils/decorators';
1218
import { noop } from '../../common/utils/misc';
@@ -32,7 +38,9 @@ export class NodeLanguageServerProxy implements ILanguageServerProxy {
3238
@inject(ILanguageClientFactory) private readonly factory: ILanguageClientFactory,
3339
@inject(ITestManagementService) private readonly testManager: ITestManagementService,
3440
@inject(IConfigurationService) private readonly configurationService: IConfigurationService,
35-
@inject(ILanguageServerFolderService) private readonly folderService: ILanguageServerFolderService
41+
@inject(ILanguageServerFolderService) private readonly folderService: ILanguageServerFolderService,
42+
@inject(IExperimentsManager) private readonly experiments: IExperimentsManager,
43+
@inject(IInterpreterPathService) private readonly interpreterPathService: IInterpreterPathService
3644
) {
3745
this.startupCompleted = createDeferred<void>();
3846
}
@@ -95,6 +103,20 @@ export class NodeLanguageServerProxy implements ILanguageServerProxy {
95103
const progressReporting = new ProgressReporting(this.languageClient!);
96104
this.disposables.push(progressReporting);
97105

106+
if (this.experiments.inExperiment(DeprecatePythonPath.experiment)) {
107+
this.disposables.push(
108+
this.interpreterPathService.onDidChange(() => {
109+
// Manually send didChangeConfiguration in order to get the server to requery
110+
// the workspace configurations (to then pick up pythonPath set in the middleware).
111+
// This is needed as interpreter changes via the interpreter path service happen
112+
// outside of VS Code's settings (which would mean VS Code sends the config updates itself).
113+
this.languageClient!.sendNotification(DidChangeConfigurationNotification.type, {
114+
settings: null
115+
});
116+
})
117+
);
118+
}
119+
98120
const settings = this.configurationService.getSettings(resource);
99121
if (settings.downloadLanguageServer) {
100122
this.languageClient.onTelemetry((telemetryEvent) => {

src/client/activation/types.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,12 @@ export interface IExtensionActivationService {
6666
export enum LanguageServerType {
6767
Jedi = 'Jedi',
6868
Microsoft = 'Microsoft',
69-
Node = 'Node',
69+
Node = 'Pylance',
7070
None = 'None'
7171
}
7272

7373
export const DotNetLanguageServerFolder = 'languageServer';
7474
export const NodeLanguageServerFolder = 'nodeLanguageServer';
75-
export const BundledLanguageServerFolder = 'bundledLanguageServer';
7675

7776
// tslint:disable-next-line: interface-name
7877
export interface DocumentHandler {
@@ -117,7 +116,7 @@ export interface ILanguageServerFolderService {
117116
getLanguageServerFolderName(resource: Resource): Promise<string>;
118117
getLatestLanguageServerVersion(resource: Resource): Promise<NugetPackage | undefined>;
119118
getCurrentLanguageServerDirectory(): Promise<FolderVersionPair | undefined>;
120-
isBundled(): boolean;
119+
skipDownload(): Promise<boolean>;
121120
}
122121

123122
export const ILanguageServerDownloader = Symbol('ILanguageServerDownloader');

0 commit comments

Comments
 (0)