Skip to content

Commit

Permalink
Linux version check
Browse files Browse the repository at this point in the history
  • Loading branch information
MikhailArkhipov committed Aug 8, 2018
1 parent 4e12b3c commit 0d3c066
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 22 deletions.
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,12 @@
"description": "Path to directory containing the Jedi library (this path will contain the 'Jedi' sub directory).",
"scope": "resource"
},
"python.analysis.checkOSVersion": {
"type": "boolean",
"default": true,
"description": "Enables checking of the OS version to determine if the Language Server will run.",
"scope": "resource"
},
"python.analysis.openFilesOnly": {
"type": "boolean",
"default": true,
Expand Down
11 changes: 5 additions & 6 deletions src/client/activation/languageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,14 @@ export class LanguageServerExtensionActivator implements IExtensionActivator {
(this.configuration.getSettings() as PythonSettings).removeListener('change', this.onSettingsChanged.bind(this));
}

private checkSupportedPlatform(): boolean {
private async checkSupportedPlatform(): Promise<boolean> {
const platform = this.services.get<IPlatformService>(IPlatformService);
if (!platform.isNetCoreCompatibleOS) {
const message = await platform.isNetCoreCompatibleOS();
if (message && message.length > 0) {
if (platform.isMac) {
this.services.get<ILogger>(ILogger).logError('Unsupported MacOS');
this.appShell.showErrorMessage('Microsoft Python Language Server does not support MacOS older than 10.12.');
this.services.get<ILogger>(ILogger).logError(message);
this.appShell.showErrorMessage(message);
}
// tslint:disable-next-line:no-suspicious-comment
// TODO: Linux messages
return false;
}
return true;
Expand Down
112 changes: 97 additions & 15 deletions src/client/common/platform/platformService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// Licensed under the MIT License.
'use strict';

import { injectable } from 'inversify';
import { inject, injectable } from 'inversify';
import { arch, release } from 'os';
import { IServiceContainer } from '../../ioc/types';
import { IProcessService, IProcessServiceFactory } from '../process/types';
import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants';
import { IPlatformService, IVersion } from './types';

Expand All @@ -21,20 +23,105 @@ class OSVersion implements IVersion {
}
}

enum OSCheckResult {
Compatible,
Incompatible,
Unknown
}

class MacOSVersion {
public get isCompatibleOS(): boolean {
public isCompatibleOS(): Promise<string> {
// https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history
// 10.12 == Darwin 16.0
return new OSVersion().versionMajor >= 16;
return Promise.resolve(new OSVersion().versionMajor >= 16 ? '' : 'Microsoft Python Language Server does not support MacOS older than 10.12.');
}
}

class LinuxVersion {
constructor(private serviceContainer: IServiceContainer) { }
public async isCompatibleOS(): Promise<string> {
const factory = this.serviceContainer.get<IProcessServiceFactory>(IProcessServiceFactory);
const process = await factory.create();

// https://github.com/dotnet/core/blob/master/release-notes/2.1/2.1-supported-os.md
// OS version run 'lsb_release -a' on Ubuntu
let result = await this.checkLinux(process, 'lsb_release', ['-a'], 'Ubuntu', 'Release:', ['18', '16', '14']);
if (result === OSCheckResult.Compatible) {
return Promise.resolve('');
} else if (result === OSCheckResult.Incompatible) {
return Promise.resolve('Microsoft Python Language Server only supports Ubuntu 18, 16 or 14.');
}

// 'cat /etc/centos-release' on CentOS
result = await this.checkLinux(process, 'cat', ['/etc/centos-release'], 'CentOS', 'release', ['7']);
if (result === OSCheckResult.Compatible) {
return Promise.resolve('');
} else if (result === OSCheckResult.Incompatible) {
return Promise.resolve('Microsoft Python Language Server only support CentOS 7.');
}

// 'cat /etc/fedora-release' on Fedora
result = await this.checkLinux(process, 'cat', ['/etc/fedora-release'], 'Fedora', 'release', ['28', '27']);
if (result === OSCheckResult.Compatible) {
return Promise.resolve('');
} else if (result === OSCheckResult.Incompatible) {
return Promise.resolve('Microsoft Python Language Server only support Fedora 28 and 27.');
}

// 'cat /etc/redhat-release' on RedHat
result = await this.checkLinux(process, 'cat', ['/etc/redhat-release'], 'Red Hat', 'release', ['7', '6']);
if (result === OSCheckResult.Compatible) {
return Promise.resolve('');
} else if (result === OSCheckResult.Incompatible) {
return Promise.resolve('Microsoft Python Language Server only support RedHat 6 or 7.');
}

// 'cat /etc/suse-release' on SUSE
result = await this.checkLinux(process, 'cat', ['/etc/suse-release'], 'SUSE', 'release', ['12']);
if (result === OSCheckResult.Compatible) {
return Promise.resolve('');
} else if (result === OSCheckResult.Incompatible) {
return Promise.resolve('Microsoft Python Language Server only support SUSE 12.');
}

// 'cat /etc/suse-release' on Debian
result = await this.checkLinux(process, 'lsb_release', ['-a'], 'Debian', 'Release:', ['9', '8.7']);
if (result === OSCheckResult.Compatible) {
return Promise.resolve('');
} else if (result === OSCheckResult.Incompatible) {
return Promise.resolve('Microsoft Python Language Server only support SUSE 12.');
}

return Promise.resolve(''); // Optimistic for other Linuxes
}

private async checkLinux(process: IProcessService, command: string, args: string[], osName: string, key: string, values: string[]): Promise<OSCheckResult> {
const result = await process.exec(command, args);
const words = result.stdout.split(' \t\n');
if (words.indexOf(osName) > 0) {
const index = words.indexOf(key);
if (index >= 0 && index < words.length - 1) {
const version = words[index + 1];
const major = version.split('.')[0];
for (const v of values) {
if (major === v) {
return Promise.resolve(OSCheckResult.Compatible);
}
}
}
return Promise.resolve(OSCheckResult.Incompatible);
}
return Promise.resolve(OSCheckResult.Unknown);
}
}

// tslint:disable-next-line:max-classes-per-file
@injectable()
export class PlatformService implements IPlatformService {
private _isWindows: boolean;
private _isMac: boolean;

constructor() {
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {
this._isWindows = /^win/.test(process.platform);
this._isMac = /^darwin/.test(process.platform);
}
Expand All @@ -56,18 +143,13 @@ export class PlatformService implements IPlatformService {
public get virtualEnvBinName() {
return this.isWindows ? 'scripts' : 'bin';
}
public get isNetCoreCompatibleOS(): boolean {
public isNetCoreCompatibleOS(): Promise<string> {
if (this.isMac) {
return new MacOSVersion().isCompatibleOS;
return new MacOSVersion().isCompatibleOS();
}
// tslint:disable-next-line:no-suspicious-comment
// TODO: implement Linux checks. They are all over.
// release() reports kernel version. For the actual
// OS version run 'lsb_release -a' on Ubuntu,
// 'cat /etc/centos-release' on CentOS
// 'cat /etc/fedora-release' on Fedora
// 'cat /etc/lsb-release' on Mint
// 'cat /etc/redhat-release' on Red Hat
return true; // Windows matches between .NET Core and VS Code.
if (this.isLinux) {
return new LinuxVersion(this.serviceContainer).isCompatibleOS();
}
return Promise.resolve(''); // Windows matches between .NET Core and VS Code.
}
}
2 changes: 1 addition & 1 deletion src/client/common/platform/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface IPlatformService {
is64bit: boolean;
pathVariableName: 'Path' | 'PATH';
virtualEnvBinName: 'bin' | 'scripts';
isNetCoreCompatibleOS: boolean;
isNetCoreCompatibleOS(): Promise<string>;
}

export type TemporaryFile = { filePath: string } & Disposable;
Expand Down

0 comments on commit 0d3c066

Please sign in to comment.