22// Licensed under the MIT License.
33'use strict' ;
44
5- import { injectable } from 'inversify' ;
5+ import { inject , injectable } from 'inversify' ;
66import { arch , release } from 'os' ;
7+ import { IServiceContainer } from '../../ioc/types' ;
8+ import { IProcessService , IProcessServiceFactory } from '../process/types' ;
79import { NON_WINDOWS_PATH_VARIABLE_NAME , WINDOWS_PATH_VARIABLE_NAME } from './constants' ;
810import { IPlatformService , IVersion } from './types' ;
911
@@ -21,20 +23,105 @@ class OSVersion implements IVersion {
2123 }
2224}
2325
26+ enum OSCheckResult {
27+ Compatible ,
28+ Incompatible ,
29+ Unknown
30+ }
31+
2432class MacOSVersion {
25- public get isCompatibleOS ( ) : boolean {
33+ public isCompatibleOS ( ) : Promise < string > {
2634 // https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history
2735 // 10.12 == Darwin 16.0
28- return new OSVersion ( ) . versionMajor >= 16 ;
36+ return Promise . resolve ( new OSVersion ( ) . versionMajor >= 16 ? '' : 'Microsoft Python Language Server does not support MacOS older than 10.12.' ) ;
37+ }
38+ }
39+
40+ class LinuxVersion {
41+ constructor ( private serviceContainer : IServiceContainer ) { }
42+ public async isCompatibleOS ( ) : Promise < string > {
43+ const factory = this . serviceContainer . get < IProcessServiceFactory > ( IProcessServiceFactory ) ;
44+ const process = await factory . create ( ) ;
45+
46+ // https://github.com/dotnet/core/blob/master/release-notes/2.1/2.1-supported-os.md
47+ // OS version run 'lsb_release -a' on Ubuntu
48+ let result = await this . checkLinux ( process , 'lsb_release' , [ '-a' ] , 'Ubuntu' , 'Release:' , [ '18' , '16' , '14' ] ) ;
49+ if ( result === OSCheckResult . Compatible ) {
50+ return Promise . resolve ( '' ) ;
51+ } else if ( result === OSCheckResult . Incompatible ) {
52+ return Promise . resolve ( 'Microsoft Python Language Server only supports Ubuntu 18, 16 or 14.' ) ;
53+ }
54+
55+ // 'cat /etc/centos-release' on CentOS
56+ result = await this . checkLinux ( process , 'cat' , [ '/etc/centos-release' ] , 'CentOS' , 'release' , [ '7' ] ) ;
57+ if ( result === OSCheckResult . Compatible ) {
58+ return Promise . resolve ( '' ) ;
59+ } else if ( result === OSCheckResult . Incompatible ) {
60+ return Promise . resolve ( 'Microsoft Python Language Server only support CentOS 7.' ) ;
61+ }
62+
63+ // 'cat /etc/fedora-release' on Fedora
64+ result = await this . checkLinux ( process , 'cat' , [ '/etc/fedora-release' ] , 'Fedora' , 'release' , [ '28' , '27' ] ) ;
65+ if ( result === OSCheckResult . Compatible ) {
66+ return Promise . resolve ( '' ) ;
67+ } else if ( result === OSCheckResult . Incompatible ) {
68+ return Promise . resolve ( 'Microsoft Python Language Server only support Fedora 28 and 27.' ) ;
69+ }
70+
71+ // 'cat /etc/redhat-release' on RedHat
72+ result = await this . checkLinux ( process , 'cat' , [ '/etc/redhat-release' ] , 'Red Hat' , 'release' , [ '7' , '6' ] ) ;
73+ if ( result === OSCheckResult . Compatible ) {
74+ return Promise . resolve ( '' ) ;
75+ } else if ( result === OSCheckResult . Incompatible ) {
76+ return Promise . resolve ( 'Microsoft Python Language Server only support RedHat 6 or 7.' ) ;
77+ }
78+
79+ // 'cat /etc/suse-release' on SUSE
80+ result = await this . checkLinux ( process , 'cat' , [ '/etc/suse-release' ] , 'SUSE' , 'release' , [ '12' ] ) ;
81+ if ( result === OSCheckResult . Compatible ) {
82+ return Promise . resolve ( '' ) ;
83+ } else if ( result === OSCheckResult . Incompatible ) {
84+ return Promise . resolve ( 'Microsoft Python Language Server only support SUSE 12.' ) ;
85+ }
86+
87+ // 'cat /etc/suse-release' on Debian
88+ result = await this . checkLinux ( process , 'lsb_release' , [ '-a' ] , 'Debian' , 'Release:' , [ '9' , '8.7' ] ) ;
89+ if ( result === OSCheckResult . Compatible ) {
90+ return Promise . resolve ( '' ) ;
91+ } else if ( result === OSCheckResult . Incompatible ) {
92+ return Promise . resolve ( 'Microsoft Python Language Server only support SUSE 12.' ) ;
93+ }
94+
95+ return Promise . resolve ( '' ) ; // Optimistic for other Linuxes
96+ }
97+
98+ private async checkLinux ( process : IProcessService , command : string , args : string [ ] , osName : string , key : string , values : string [ ] ) : Promise < OSCheckResult > {
99+ const result = await process . exec ( command , args ) ;
100+ const words = result . stdout . split ( ' \t\n' ) ;
101+ if ( words . indexOf ( osName ) > 0 ) {
102+ const index = words . indexOf ( key ) ;
103+ if ( index >= 0 && index < words . length - 1 ) {
104+ const version = words [ index + 1 ] ;
105+ const major = version . split ( '.' ) [ 0 ] ;
106+ for ( const v of values ) {
107+ if ( major === v ) {
108+ return Promise . resolve ( OSCheckResult . Compatible ) ;
109+ }
110+ }
111+ }
112+ return Promise . resolve ( OSCheckResult . Incompatible ) ;
113+ }
114+ return Promise . resolve ( OSCheckResult . Unknown ) ;
29115 }
30116}
31117
118+ // tslint:disable-next-line:max-classes-per-file
32119@injectable ( )
33120export class PlatformService implements IPlatformService {
34121 private _isWindows : boolean ;
35122 private _isMac : boolean ;
36123
37- constructor ( ) {
124+ constructor ( @ inject ( IServiceContainer ) private serviceContainer : IServiceContainer ) {
38125 this . _isWindows = / ^ w i n / . test ( process . platform ) ;
39126 this . _isMac = / ^ d a r w i n / . test ( process . platform ) ;
40127 }
@@ -56,18 +143,13 @@ export class PlatformService implements IPlatformService {
56143 public get virtualEnvBinName ( ) {
57144 return this . isWindows ? 'scripts' : 'bin' ;
58145 }
59- public get isNetCoreCompatibleOS ( ) : boolean {
146+ public isNetCoreCompatibleOS ( ) : Promise < string > {
60147 if ( this . isMac ) {
61- return new MacOSVersion ( ) . isCompatibleOS ;
148+ return new MacOSVersion ( ) . isCompatibleOS ( ) ;
62149 }
63- // tslint:disable-next-line:no-suspicious-comment
64- // TODO: implement Linux checks. They are all over.
65- // release() reports kernel version. For the actual
66- // OS version run 'lsb_release -a' on Ubuntu,
67- // 'cat /etc/centos-release' on CentOS
68- // 'cat /etc/fedora-release' on Fedora
69- // 'cat /etc/lsb-release' on Mint
70- // 'cat /etc/redhat-release' on Red Hat
71- return true ; // Windows matches between .NET Core and VS Code.
150+ if ( this . isLinux ) {
151+ return new LinuxVersion ( this . serviceContainer ) . isCompatibleOS ( ) ;
152+ }
153+ return Promise . resolve ( '' ) ; // Windows matches between .NET Core and VS Code.
72154 }
73155}
0 commit comments