Skip to content

Commit 66f8a27

Browse files
authored
Updated logic used to determine whether the Language Server is supported (microsoft#3565)
For microsoft#2729
1 parent 874b116 commit 66f8a27

69 files changed

Lines changed: 967 additions & 1053 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

news/2 Fixes/2729.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Updated logic used to determine whether the Language Server is supported.

news/2 Fixes/3514.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/client/activation/activationService.ts

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,22 @@ import {
1414
} from '../common/application/types';
1515
import { STANDARD_OUTPUT_CHANNEL } from '../common/constants';
1616
import '../common/extensions';
17-
import { IPlatformService } from '../common/platform/types';
1817
import {
1918
IConfigurationService, IDisposableRegistry,
2019
IOutputChannel, IPythonSettings
2120
} from '../common/types';
2221
import { displayProgress } from '../common/utils/decorators';
2322
import { LanguageService } from '../common/utils/localize';
24-
import { OSDistro, OSType } from '../common/utils/platform';
2523
import { IServiceContainer } from '../ioc/types';
2624
import { sendTelemetryEvent } from '../telemetry';
2725
import { PYTHON_LANGUAGE_SERVER_PLATFORM_NOT_SUPPORTED } from '../telemetry/constants';
2826
import {
2927
ExtensionActivators, IExtensionActivationService,
30-
IExtensionActivator
28+
IExtensionActivator,
29+
ILanguageServerCompatibilityService
3130
} from './types';
3231

3332
const jediEnabledSetting: keyof IPythonSettings = 'jediEnabled';
34-
const LS_MIN_OS_VERSIONS: [OSType, OSDistro, string][] = [
35-
// See: https://code.visualstudio.com/docs/supporting/requirements
36-
[OSType.OSX, OSDistro.Unknown, '10.12'], // Sierra or higher
37-
[OSType.Windows, OSDistro.Unknown, '6.1'], // Win 7 or higher
38-
// tslint:disable-next-line: no-suspicious-comment
39-
// TODO: Are these right?
40-
[OSType.Linux, OSDistro.Ubuntu, '14.04'], // "precise"
41-
[OSType.Linux, OSDistro.Debian, '7'],
42-
[OSType.Linux, OSDistro.RHEL, '7'],
43-
[OSType.Linux, OSDistro.CentOS, '7'],
44-
[OSType.Linux, OSDistro.Fedora, '23']
45-
];
46-
4733
type ActivatorInfo = { jedi: boolean; activator: IExtensionActivator };
4834

4935
@injectable()
@@ -53,7 +39,8 @@ export class ExtensionActivationService implements IExtensionActivationService,
5339
private readonly output: OutputChannel;
5440
private readonly appShell: IApplicationShell;
5541

56-
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {
42+
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer,
43+
@inject(ILanguageServerCompatibilityService) private readonly lsCompatibility: ILanguageServerCompatibilityService) {
5744
this.workspaceService = this.serviceContainer.get<IWorkspaceService>(IWorkspaceService);
5845
this.output = this.serviceContainer.get<OutputChannel>(IOutputChannel, STANDARD_OUTPUT_CHANNEL);
5946
this.appShell = this.serviceContainer.get<IApplicationShell>(IApplicationShell);
@@ -70,10 +57,8 @@ export class ExtensionActivationService implements IExtensionActivationService,
7057
}
7158

7259
let jedi = this.useJedi();
73-
if (!jedi && !isLSSupported(this.serviceContainer)) {
60+
if (!jedi && !await this.lsCompatibility.isSupported()) {
7461
this.appShell.showWarningMessage('The Python Language Server is not supported on your platform.');
75-
// tslint:disable-next-line:no-suspicious-comment
76-
// TODO: Only send once (ever)?
7762
sendTelemetryEvent(PYTHON_LANGUAGE_SERVER_PLATFORM_NOT_SUPPORTED);
7863
jedi = true;
7964
}
@@ -119,30 +104,3 @@ export class ExtensionActivationService implements IExtensionActivationService,
119104
return workspacesUris.filter(uri => configuraionService.getSettings(uri).jediEnabled).length > 0;
120105
}
121106
}
122-
123-
function isLSSupported(services: IServiceContainer): boolean {
124-
const platform = services.get<IPlatformService>(IPlatformService);
125-
let minVer = '';
126-
for (const [osType, distro, ver] of LS_MIN_OS_VERSIONS) {
127-
if (platform.info.type === osType && platform.info.distro === distro) {
128-
minVer = ver;
129-
break;
130-
}
131-
}
132-
if (minVer === '') {
133-
return true;
134-
}
135-
minVer = normalizeVersion(minVer);
136-
return platform.info.version.compare(minVer) >= 0;
137-
}
138-
139-
function normalizeVersion(ver: string): string {
140-
ver = ver.replace(/\.00*/, '.');
141-
if (/^\d\d*$/.test(ver)) {
142-
return `${ver}.0.0`;
143-
} else if (/^\d\d*\.\d\d*$/.test(ver)) {
144-
return `${ver}.0`;
145-
} else {
146-
return ver;
147-
}
148-
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
import { inject, injectable } from 'inversify';
7+
import { IDotNetCompatibilityService } from '../../common/dotnet/types';
8+
import { sendTelemetryEvent } from '../../telemetry';
9+
import { PYTHON_LANGUAGE_SERVER_PLATFORM_SUPPORTED } from '../../telemetry/constants';
10+
import { ILanguageServerCompatibilityService } from '../types';
11+
12+
@injectable()
13+
export class LanguageServerCompatibilityService implements ILanguageServerCompatibilityService {
14+
constructor(@inject(IDotNetCompatibilityService) private readonly dotnetCompatibility: IDotNetCompatibilityService) { }
15+
public async isSupported(): Promise<boolean> {
16+
const supported = await this.dotnetCompatibility.isSupported();
17+
sendTelemetryEvent(PYTHON_LANGUAGE_SERVER_PLATFORM_SUPPORTED, undefined, { supported });
18+
return supported;
19+
}
20+
}

src/client/activation/languageServer/languageServerFolderService.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { inject, injectable } from 'inversify';
77
import * as path from 'path';
88
import * as semver from 'semver';
99
import { EXTENSION_ROOT_DIR } from '../../common/constants';
10-
import { traceVerbose } from '../../common/logger';
10+
import { traceDecorators } from '../../common/logger';
1111
import { NugetPackage } from '../../common/nuget/types';
1212
import { IFileSystem } from '../../common/platform/types';
1313
import { IConfigurationService } from '../../common/types';
@@ -20,7 +20,7 @@ const languageServerFolder = 'languageServer';
2020
export class LanguageServerFolderService implements ILanguageServerFolderService {
2121
constructor(@inject(IServiceContainer) private readonly serviceContainer: IServiceContainer) { }
2222

23-
@traceVerbose('Get language server folder name')
23+
@traceDecorators.verbose('Get language server folder name')
2424
public async getLanguageServerFolderName(): Promise<string> {
2525
const currentFolder = await this.getCurrentLanguageServerDirectory();
2626
let serverVersion: NugetPackage | undefined;
@@ -40,7 +40,7 @@ export class LanguageServerFolderService implements ILanguageServerFolderService
4040
return `${languageServerFolder}.${serverVersion!.version.raw}`;
4141
}
4242

43-
@traceVerbose('Get latest version of Language Server')
43+
@traceDecorators.verbose('Get latest version of Language Server')
4444
public getLatestLanguageServerVersion(): Promise<NugetPackage | undefined> {
4545
const lsPackageService = this.serviceContainer.get<ILanguageServerPackageService>(ILanguageServerPackageService);
4646
return lsPackageService.getLatestNugetPackageVersion();

src/client/activation/languageServer/languageServerPackageService.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import { inject, injectable } from 'inversify';
77
import { parse, SemVer } from 'semver';
88
import { IApplicationEnvironment } from '../../common/application/types';
99
import { PVSC_EXTENSION_ID } from '../../common/constants';
10-
import { traceVerbose } from '../../common/logger';
10+
import { traceDecorators, traceVerbose } from '../../common/logger';
1111
import { INugetRepository, INugetService, NugetPackage } from '../../common/nuget/types';
1212
import { IPlatformService } from '../../common/platform/types';
1313
import { IConfigurationService, IExtensions, LanguageServerDownloadChannels } from '../../common/types';
14-
import { Architecture, OSType } from '../../common/utils/platform';
14+
import { OSType } from '../../common/utils/platform';
1515
import { IServiceContainer } from '../../ioc/types';
1616
import { PlatformName } from '../platformData';
1717
import { ILanguageServerPackageService } from '../types';
@@ -30,13 +30,12 @@ export const PackageNames = {
3030
export class LanguageServerPackageService implements ILanguageServerPackageService {
3131
public maxMajorVersion: number = maxMajorVersion;
3232
constructor(@inject(IServiceContainer) protected readonly serviceContainer: IServiceContainer,
33-
@inject(IApplicationEnvironment) private readonly appEnv: IApplicationEnvironment) { }
33+
@inject(IApplicationEnvironment) private readonly appEnv: IApplicationEnvironment,
34+
@inject(IPlatformService) private readonly platform: IPlatformService) { }
3435
public getNugetPackageName(): string {
35-
const plaform = this.serviceContainer.get<IPlatformService>(IPlatformService);
36-
switch (plaform.info.type) {
36+
switch (this.platform.osType) {
3737
case OSType.Windows: {
38-
const is64Bit = plaform.info.architecture === Architecture.x64;
39-
return PackageNames[is64Bit ? PlatformName.Windows64Bit : PlatformName.Windows32Bit];
38+
return PackageNames[this.platform.is64bit ? PlatformName.Windows64Bit : PlatformName.Windows32Bit];
4039
}
4140
case OSType.OSX: {
4241
return PackageNames[PlatformName.Mac64Bit];
@@ -47,7 +46,7 @@ export class LanguageServerPackageService implements ILanguageServerPackageServi
4746
}
4847
}
4948

50-
@traceVerbose('Get latest language server nuget package version')
49+
@traceDecorators.verbose('Get latest language server nuget package version')
5150
public async getLatestNugetPackageVersion(): Promise<NugetPackage> {
5251
const downloadChannel = this.getLanguageServerDownloadChannel();
5352
const nugetRepo = this.serviceContainer.get<INugetRepository>(INugetRepository, downloadChannel);

src/client/activation/serviceRegistry.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import { ExtensionActivationService } from './activationService';
1313
import { DownloadBetaChannelRule, DownloadDailyChannelRule, DownloadStableChannelRule } from './downloadChannelRules';
1414
import { JediExtensionActivator } from './jedi';
1515
import { LanguageServerExtensionActivator } from './languageServer/languageServer';
16+
import { LanguageServerCompatibilityService } from './languageServer/languageServerCompatibilityService';
1617
import { LanguageServerFolderService } from './languageServer/languageServerFolderService';
1718
import { BetaLanguageServerPackageRepository, DailyLanguageServerPackageRepository, LanguageServerDownloadChannel, StableLanguageServerPackageRepository } from './languageServer/languageServerPackageRepository';
1819
import { LanguageServerPackageService } from './languageServer/languageServerPackageService';
19-
import { ExtensionActivators, IDownloadChannelRule, IExtensionActivationService, IExtensionActivator, ILanguageServerFolderService, ILanguageServerPackageService } from './types';
20+
import { ExtensionActivators, IDownloadChannelRule, IExtensionActivationService, IExtensionActivator, ILanguageServerCompatibilityService as ILanagueServerCompatibilityService, ILanguageServerFolderService, ILanguageServerPackageService } from './types';
2021

2122
export function registerTypes(serviceManager: IServiceManager) {
2223
serviceManager.addSingleton<IExtensionActivationService>(IExtensionActivationService, ExtensionActivationService);
@@ -33,4 +34,5 @@ export function registerTypes(serviceManager: IServiceManager) {
3334
serviceManager.addSingleton<IDownloadChannelRule>(IDownloadChannelRule, DownloadDailyChannelRule, LanguageServerDownloadChannel.daily);
3435
serviceManager.addSingleton<IDownloadChannelRule>(IDownloadChannelRule, DownloadBetaChannelRule, LanguageServerDownloadChannel.beta);
3536
serviceManager.addSingleton<IDownloadChannelRule>(IDownloadChannelRule, DownloadStableChannelRule, LanguageServerDownloadChannel.stable);
37+
serviceManager.addSingleton<ILanagueServerCompatibilityService>(ILanagueServerCompatibilityService, LanguageServerCompatibilityService);
3638
}

src/client/activation/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,7 @@ export const IDownloadChannelRule = Symbol('IDownloadChannelRule');
5858
export interface IDownloadChannelRule {
5959
shouldLookForNewLanguageServer(currentFolder?: FolderVersionPair): Promise<boolean>;
6060
}
61+
export const ILanguageServerCompatibilityService = Symbol('ILanguageServerCompatibilityService');
62+
export interface ILanguageServerCompatibilityService {
63+
isSupported(): Promise<boolean>;
64+
}

src/client/common/configSettings.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import { sendTelemetryEvent } from '../telemetry';
1111
import { COMPLETION_ADD_BRACKETS, FORMAT_ON_TYPE } from '../telemetry/constants';
1212
import { isTestExecution } from './constants';
13+
import { IS_WINDOWS } from './platform/constants';
1314
import {
1415
IAnalysisSettings,
1516
IAutoCompleteSettings,
@@ -27,8 +28,6 @@ import { SystemVariables } from './variables/systemVariables';
2728
// tslint:disable-next-line:no-require-imports no-var-requires
2829
const untildify = require('untildify');
2930

30-
export const IS_WINDOWS = /^win/.test(process.platform);
31-
3231
// tslint:disable-next-line:completed-docs
3332
export class PythonSettings extends EventEmitter implements IPythonSettings {
3433
private static pythonSettings: Map<string, PythonSettings> = new Map<string, PythonSettings>();
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
import { inject, injectable, named } from 'inversify';
7+
import { IPlatformService } from '../platform/types';
8+
import { OSType } from '../utils/platform';
9+
import { IDotNetCompatibilityService, IOSDotNetCompatibilityService } from './types';
10+
11+
/**
12+
* .NET Core 2.1 OS Requirements
13+
* https://github.com/dotnet/core/blob/master/release-notes/2.1/2.1-supported-os.md
14+
* We are using the versions provided in the above .NET 2.1 Core requirements page as minimum required versions.
15+
* Why, cuz getting distros, mapping them to the ones listd on .NET 2.1 Core requirements are entirely accurate.
16+
* Due to the inaccuracy, its easier and safer to just assume futur versions of an OS are also supported.
17+
* We will need to regularly update the requirements over time, when using .NET Core 2.2 or 3, etc.
18+
*/
19+
@injectable()
20+
export class DotNetCompatibilityService implements IDotNetCompatibilityService {
21+
private readonly mappedServices = new Map<OSType, IDotNetCompatibilityService>();
22+
constructor(@inject(IOSDotNetCompatibilityService) @named(OSType.Unknown) unknownOsService: IOSDotNetCompatibilityService,
23+
@inject(IOSDotNetCompatibilityService) @named(OSType.OSX) macService: IOSDotNetCompatibilityService,
24+
@inject(IOSDotNetCompatibilityService) @named(OSType.Windows) winService: IOSDotNetCompatibilityService,
25+
@inject(IOSDotNetCompatibilityService) @named(OSType.Linux) linuxService: IOSDotNetCompatibilityService,
26+
@inject(IPlatformService) private readonly platformService: IPlatformService) {
27+
this.mappedServices.set(OSType.Unknown, unknownOsService);
28+
this.mappedServices.set(OSType.OSX, macService);
29+
this.mappedServices.set(OSType.Windows, winService);
30+
this.mappedServices.set(OSType.Linux, linuxService);
31+
}
32+
public isSupported() {
33+
return this.mappedServices.get(this.platformService.osType)!.isSupported();
34+
}
35+
}

0 commit comments

Comments
 (0)