From 997635ac0d79a9f6e0cc45458c77a1e5ff0c7b07 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Fri, 8 Jun 2018 14:07:24 -0700 Subject: [PATCH 01/65] LS symbol providers --- src/client/activation/classic.ts | 6 +++++- src/client/extension.ts | 2 -- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/client/activation/classic.ts b/src/client/activation/classic.ts index 17ca5c929047..72745cab86be 100644 --- a/src/client/activation/classic.ts +++ b/src/client/activation/classic.ts @@ -17,6 +17,7 @@ import { PythonRenameProvider } from '../providers/renameProvider'; import { PythonSignatureProvider } from '../providers/signatureProvider'; import { PythonSymbolProvider } from '../providers/symbolProvider'; import { IUnitTestManagementService } from '../unittests/types'; +import { WorkspaceSymbols } from '../workspaceSymbols/main'; import { IExtensionActivator } from './types'; @injectable() @@ -46,7 +47,10 @@ export class ClassicExtensionActivator implements IExtensionActivator { context.subscriptions.push(languages.registerCompletionItemProvider(this.documentSelector, new PythonCompletionItemProvider(jediFactory, this.serviceManager), '.')); context.subscriptions.push(languages.registerCodeLensProvider(this.documentSelector, this.serviceManager.get(IShebangCodeLensProvider))); - const symbolProvider = new PythonSymbolProvider(this.serviceManager.get(IServiceContainer), jediFactory); + const serviceContainer = this.serviceManager.get(IServiceContainer); + context.subscriptions.push(new WorkspaceSymbols(serviceContainer)); + + const symbolProvider = new PythonSymbolProvider(serviceContainer, jediFactory); context.subscriptions.push(languages.registerDocumentSymbolProvider(this.documentSelector, symbolProvider)); const pythonSettings = this.serviceManager.get(IConfigurationService).getSettings(); diff --git a/src/client/extension.ts b/src/client/extension.ts index 2228cca81495..43d42ac389a6 100644 --- a/src/client/extension.ts +++ b/src/client/extension.ts @@ -56,7 +56,6 @@ import { BlockFormatProviders } from './typeFormatters/blockFormatProvider'; import { OnEnterFormatter } from './typeFormatters/onEnterFormatter'; import { TEST_OUTPUT_CHANNEL } from './unittests/common/constants'; import { registerTypes as unitTestsRegisterTypes } from './unittests/serviceRegistry'; -import { WorkspaceSymbols } from './workspaceSymbols/main'; const activationDeferred = createDeferred(); export const activated = activationDeferred.promise; @@ -143,7 +142,6 @@ export async function activate(context: ExtensionContext) { context.subscriptions.push(new ReplProvider(serviceContainer)); context.subscriptions.push(new TerminalProvider(serviceContainer)); - context.subscriptions.push(new WorkspaceSymbols(serviceContainer)); type ConfigurationProvider = BaseConfigurationProvider; serviceContainer.getAll(IDebugConfigurationProvider).forEach(debugConfig => { From d4fd3ab791703afa4638daee9307a4805617d902 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Tue, 3 Jul 2018 22:41:53 -0700 Subject: [PATCH 02/65] Different ready wait --- src/client/activation/analysis.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/client/activation/analysis.ts b/src/client/activation/analysis.ts index 3c50866ae56c..bc3ed7170abf 100644 --- a/src/client/activation/analysis.ts +++ b/src/client/activation/analysis.ts @@ -134,22 +134,23 @@ export class AnalysisExtensionActivator implements IExtensionActivator { } private async startLanguageClient(): Promise { - this.languageClient!.onReady() - .then(() => { - this.startupCompleted.resolve(); - if (this.loadExtensionArgs) { - this.languageClient!.sendRequest('python/loadExtension', this.loadExtensionArgs); - this.loadExtensionArgs = undefined; - } - }) - .catch(error => this.startupCompleted.reject(error)); - this.context.subscriptions.push(this.languageClient!.start()); - if (isTestExecution()) { + this.serverReady().ignoreErrors(); + if (isTestExecution()) { await this.startupCompleted.promise; } } + private async serverReady(): Promise { + while (!this.languageClient!.initializeResult) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + if (this.loadExtensionArgs) { + this.languageClient!.sendRequest('python/loadExtension', this.loadExtensionArgs); + } + this.startupCompleted.resolve(); + } + private createSimpleLanguageClient(clientOptions: LanguageClientOptions): LanguageClient { const commandOptions = { stdio: 'pipe' }; const serverModule = path.join(this.context.extensionPath, analysisEngineFolder, this.platformData.getEngineDllName()); From 56bf6885bfd4f49267cc1e8191dc5308bddbd0f0 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 12 Jul 2018 13:49:49 -0700 Subject: [PATCH 03/65] Upgrade dependencies to latest LS --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 4bc0621b780b..ac473d17af12 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "theme": "dark" }, "engines": { - "vscode": "^1.23.0" + "vscode": "^1.25.0" }, "recommendations": [ "donjayamanne.jupyter" @@ -1990,8 +1990,8 @@ "vscode-debugadapter": "1.28.0", "vscode-debugprotocol": "1.28.0", "vscode-extension-telemetry": "0.0.15", - "vscode-languageclient": "3.5.1", - "vscode-languageserver": "3.5.1", + "vscode-languageclient": "^4.3.0", + "vscode-languageserver": "^4.3.0", "winreg": "1.2.4", "xml2js": "0.4.19" }, From 37f1154c728d64e3f4bebe6d4d3346ef6220ba70 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 12 Jul 2018 14:08:53 -0700 Subject: [PATCH 04/65] Make open files only default --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ac473d17af12..0821db29cbcd 100644 --- a/package.json +++ b/package.json @@ -1277,7 +1277,7 @@ }, "python.analysis.openFilesOnly": { "type": "boolean", - "default": false, + "default": true, "description": "Only show errors and warnings for open files rather than for the entire workspace.", "scope": "resource" }, From 4092bcc6e858a78710dfd828363f5db9d70009e4 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 12 Jul 2018 15:52:31 -0700 Subject: [PATCH 05/65] Turn off hash checks --- package.json | 1 + src/client/activation/downloader.ts | 2 +- src/client/activation/languageServer.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0821db29cbcd..72d0637d45a6 100644 --- a/package.json +++ b/package.json @@ -1992,6 +1992,7 @@ "vscode-extension-telemetry": "0.0.15", "vscode-languageclient": "^4.3.0", "vscode-languageserver": "^4.3.0", + "vscode-languageserver-protocol": "^3.9.0", "winreg": "1.2.4", "xml2js": "0.4.19" }, diff --git a/src/client/activation/downloader.ts b/src/client/activation/downloader.ts index 59f9fd91a8db..aaf48c7923fa 100644 --- a/src/client/activation/downloader.ts +++ b/src/client/activation/downloader.ts @@ -42,7 +42,7 @@ export class LanguageServerDownloader { let localTempFilePath = ''; try { localTempFilePath = await this.downloadFile(downloadUriPrefix, enginePackageFileName, 'Downloading Microsoft Python Language Server... '); - await this.verifyDownload(localTempFilePath, platformString); + // await this.verifyDownload(localTempFilePath, platformString); await this.unpackArchive(context.extensionPath, localTempFilePath); } catch (err) { this.output.appendLine('failed.'); diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index 0d4a6f20871b..5154b92a41af 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -232,7 +232,7 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { properties }, displayOptions: { - preferredFormat: 1, // Markdown + preferredFormat: 'markdown', trimDocumentationLines: false, maxDocumentationLineLength: 0, trimDocumentationText: false, From 49ec38a59eedf55ba1ac28225cce2562d001dfa2 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 12 Jul 2018 15:56:59 -0700 Subject: [PATCH 06/65] Fix double progress display --- src/client/activation/downloader.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/activation/downloader.ts b/src/client/activation/downloader.ts index aaf48c7923fa..b8d5a37a4e12 100644 --- a/src/client/activation/downloader.ts +++ b/src/client/activation/downloader.ts @@ -70,8 +70,7 @@ export class LanguageServerDownloader { }); await window.withProgress({ - location: ProgressLocation.Window, - title + location: ProgressLocation.Window }, (progress) => { requestProgress(request(uri)) From f7e245b44dce6f2518c517bac6aab5f0f44c52a8 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Fri, 13 Jul 2018 12:20:31 -0700 Subject: [PATCH 07/65] Update packages --- package-lock.json | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index e42cc4b1a58e..ee9849eb35e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9652,40 +9652,47 @@ } }, "vscode-jsonrpc": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz", - "integrity": "sha1-hyOdnhZrLXNSJFuKgTWXgEwdY6o=" + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.6.2.tgz", + "integrity": "sha512-T24Jb5V48e4VgYliUXMnZ379ItbrXgOimweKaJshD84z+8q7ZOZjJan0MeDe+Ugb+uqERDVV8SBmemaGMSMugA==" }, "vscode-languageclient": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.1.tgz", - "integrity": "sha512-GTQ+hSq/o4c/y6GYmyP9XNrVoIu0NFZ67KltSkqN+tO0eUNDIlrVNX+3DJzzyLhSsrctuGzuYWm3t87mNAcBmQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-4.3.0.tgz", + "integrity": "sha512-vDpsmYfYpfuyDKZ46pCJEFBOCNHepRBSmlBGA0fczEbYghYm059BiFo3SmT4MK1r8NvYrFEem4k5TYNW3wommg==", "requires": { - "vscode-languageserver-protocol": "3.5.1" + "vscode-languageserver-protocol": "^3.9.0" } }, "vscode-languageserver": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.1.tgz", - "integrity": "sha512-RYUKn0DgHTFcS8kS4VaNCjNMaQXYqiXdN9bKrFjXzu5RPKfjIYcoh47oVWwZj4L3R/DPB0Se7HPaDatvYY2XgQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-4.3.0.tgz", + "integrity": "sha512-4dTpnyTB6Q0HmMhxaG60rrpQthbTBlMtFX5cwJpPxcPzLZIFDWB3msR6TxGCzWpdYF11REIJihWByobpGkljdQ==", "requires": { - "vscode-languageserver-protocol": "3.5.1", - "vscode-uri": "^1.0.1" + "vscode-languageserver-protocol": "^3.9.0", + "vscode-uri": "^1.0.3" + }, + "dependencies": { + "vscode-uri": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.5.tgz", + "integrity": "sha1-O4majvccN/MFTXm9vdoxx7828g0=" + } } }, "vscode-languageserver-protocol": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.1.tgz", - "integrity": "sha512-1fPDIwsAv1difCV+8daOrJEGunClNJWqnUHq/ncWrjhitKWXgGmRCjlwZ3gDUTt54yRcvXz1PXJDaRNvNH6pYA==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.9.0.tgz", + "integrity": "sha512-i1sG5iU88Mocc7egTeh6dAow/yRWpPK5PLJaxsWsKiA+dspq1Yzr/R1bNLPc+6P/ab010lXhzdUHQY0CuIUyDw==", "requires": { - "vscode-jsonrpc": "3.5.0", - "vscode-languageserver-types": "3.5.0" + "vscode-jsonrpc": "^3.6.2", + "vscode-languageserver-types": "^3.9.0" } }, "vscode-languageserver-types": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz", - "integrity": "sha1-5I15li8LjgLelV4/UkkI4rGcA3Q=" + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.9.0.tgz", + "integrity": "sha512-Qzh3VsU3t0zhKtYl1revyax+4gGHl2ejNzYXeiZYQMF3i0vX4dtPohxGDFoZYfGFQI738aXYbSUQmhLeBckDlQ==" }, "vscode-uri": { "version": "1.0.1", From bdce0ff1fd20d82aad4d11feacf0e4d9d7440568 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 13 Jul 2018 14:53:03 -0700 Subject: [PATCH 08/65] Anchor dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 72d0637d45a6..2795d022a5c4 100644 --- a/package.json +++ b/package.json @@ -1964,7 +1964,7 @@ "fs-extra": "4.0.3", "fuzzy": "0.1.3", "get-port": "3.2.0", - "glob": "^7.1.2", + "glob": "7.1.2", "iconv-lite": "0.4.21", "inversify": "4.11.1", "line-by-line": "0.1.6", @@ -1990,9 +1990,9 @@ "vscode-debugadapter": "1.28.0", "vscode-debugprotocol": "1.28.0", "vscode-extension-telemetry": "0.0.15", - "vscode-languageclient": "^4.3.0", - "vscode-languageserver": "^4.3.0", - "vscode-languageserver-protocol": "^3.9.0", + "vscode-languageclient": "4.3.0", + "vscode-languageserver": "4.3.0", + "vscode-languageserver-protocol": "3.9.0", "winreg": "1.2.4", "xml2js": "0.4.19" }, From 5d455586265b550a7168e203bfd9cf2d7e61cfee Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 6 Aug 2018 15:47:01 -0700 Subject: [PATCH 09/65] Add setting for diag throttling --- package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package.json b/package.json index b49bced7af3c..3f1cff09dd1d 100644 --- a/package.json +++ b/package.json @@ -823,6 +823,12 @@ "description": "Only show errors and warnings for open files rather than for the entire workspace.", "scope": "resource" }, + "python.analysis.diagnosticPublishDelay": { + "type": "integer", + "default": 1000, + "description": "Delay before diagnostic messages are transferred to the problems list.", + "scope": "resource" + }, "python.analysis.typeshedPaths": { "type": "array", "default": [], From 70b13f75b01c5eb72bd35611f411b801994f5e63 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Tue, 7 Aug 2018 12:49:03 -0700 Subject: [PATCH 10/65] Add MacOS version check --- src/client/activation/languageServer.ts | 31 +++++++++++++++---- src/client/common/platform/platformService.ts | 13 +++++++- src/client/common/platform/types.ts | 3 ++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index 0842d07e0ec0..1ba4711112cc 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -3,18 +3,24 @@ import { inject, injectable } from 'inversify'; import * as path from 'path'; -import { CancellationToken, CompletionContext, OutputChannel, Position, - TextDocument, Uri } from 'vscode'; -import { Disposable, LanguageClient, LanguageClientOptions, - ProvideCompletionItemsSignature, ServerOptions } from 'vscode-languageclient'; +import { + CancellationToken, CompletionContext, OutputChannel, Position, + TextDocument, Uri +} from 'vscode'; +import { + Disposable, LanguageClient, LanguageClientOptions, + ProvideCompletionItemsSignature, ServerOptions +} from 'vscode-languageclient'; import { IApplicationShell, ICommandManager, IWorkspaceService } from '../common/application/types'; import { PythonSettings } from '../common/configSettings'; import { isTestExecution, STANDARD_OUTPUT_CHANNEL } from '../common/constants'; import { createDeferred, Deferred } from '../common/helpers'; import { IFileSystem, IPlatformService } from '../common/platform/types'; import { StopWatch } from '../common/stopWatch'; -import { BANNER_NAME_LS_SURVEY, IConfigurationService, IExtensionContext, ILogger, - IOutputChannel, IPythonExtensionBanner, IPythonSettings } from '../common/types'; +import { + BANNER_NAME_LS_SURVEY, IConfigurationService, IExtensionContext, ILogger, + IOutputChannel, IPythonExtensionBanner, IPythonSettings +} from '../common/types'; import { IServiceContainer } from '../ioc/types'; import { PYTHON_LANGUAGE_SERVER_DOWNLOADED, @@ -91,6 +97,10 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { } public async activate(): Promise { + if (!this.checkSupportedPlatform()) { + return false; + } + this.sw.reset(); const clientOptions = await this.getAnalysisOptions(); if (!clientOptions) { @@ -115,6 +125,15 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { (this.configuration.getSettings() as PythonSettings).removeListener('change', this.onSettingsChanged.bind(this)); } + private checkSupportedPlatform(): boolean { + const platform = this.services.get(IPlatformService); + if (platform.isMac && platform.versionMajor === 10 && platform.versionMinor < 12) { + this.services.get(ILogger).logError('Unsupported MacOS'); + this.appShell.showErrorMessage('Microsoft Python Language Server does not support MacOS older than 10.12.'); + return false; + } + return true; + } private async startLanguageServer(clientOptions: LanguageClientOptions): Promise { // Determine if we are running MSIL/Universal via dotnet or self-contained app. diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index f60f9eaf3ba5..df6b6142f5b5 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -3,7 +3,7 @@ 'use strict'; import { injectable } from 'inversify'; -import { arch } from 'os'; +import { arch, release } from 'os'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; import { IPlatformService } from './types'; @@ -34,4 +34,15 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } + public get version(): string { + return release(); + } + public get versionMajor(): number { + const parts = this.version.split('.'); + return parts.length > 0 ? parseInt(parts[0], 10) : 0; + } + public get versionMinor(): number { + const parts = this.version.split('.'); + return parts.length > 1 ? parseInt(parts[1], 10) : 0; + } } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index ec08fd7d284c..48b0058558f1 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -27,6 +27,9 @@ export interface IPlatformService { is64bit: boolean; pathVariableName: 'Path' | 'PATH'; virtualEnvBinName: 'bin' | 'scripts'; + version: string; + versionMajor: number; + versionMinor: number; } export type TemporaryFile = { filePath: string } & Disposable; From 462ff7c4b1f05e1abe180b27104b8a3f0bfd2e67 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Tue, 7 Aug 2018 12:56:06 -0700 Subject: [PATCH 11/65] News --- news/1 Enhancements/2245.md | 1 + news/1 Enhancements/2270.md | 1 + 2 files changed, 2 insertions(+) create mode 100644 news/1 Enhancements/2245.md create mode 100644 news/1 Enhancements/2270.md diff --git a/news/1 Enhancements/2245.md b/news/1 Enhancements/2245.md new file mode 100644 index 000000000000..f4e948db7211 --- /dev/null +++ b/news/1 Enhancements/2245.md @@ -0,0 +1 @@ +Python extension detects MacOS older than 10.12 and prevents language server from starting since .NET Core 2.x is not supported on older Mac platforms. \ No newline at end of file diff --git a/news/1 Enhancements/2270.md b/news/1 Enhancements/2270.md new file mode 100644 index 000000000000..0d3cca04bee0 --- /dev/null +++ b/news/1 Enhancements/2270.md @@ -0,0 +1 @@ +python.analysis.diagnosticPublishDelay allows you to control when language server publishes diagnostics. Default is 1 second after the user activity, such a typing, ceases. If diagnostic is clear (i.e. errors got fixed), the publishing is immediate. \ No newline at end of file From 4e12b3c0f540e988f708928fef9f499c8562dd39 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 11:13:33 -0700 Subject: [PATCH 12/65] Correct MacOS check and lay infra for Linux checks --- src/client/activation/languageServer.ts | 10 ++-- src/client/common/platform/platformService.ts | 47 ++++++++++++++----- src/client/common/platform/types.ts | 10 ++-- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index 1ba4711112cc..a540584880bd 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -127,9 +127,13 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { private checkSupportedPlatform(): boolean { const platform = this.services.get(IPlatformService); - if (platform.isMac && platform.versionMajor === 10 && platform.versionMinor < 12) { - this.services.get(ILogger).logError('Unsupported MacOS'); - this.appShell.showErrorMessage('Microsoft Python Language Server does not support MacOS older than 10.12.'); + if (!platform.isNetCoreCompatibleOS) { + if (platform.isMac) { + this.services.get(ILogger).logError('Unsupported MacOS'); + this.appShell.showErrorMessage('Microsoft Python Language Server does not support MacOS older than 10.12.'); + } + // tslint:disable-next-line:no-suspicious-comment + // TODO: Linux messages return false; } return true; diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index df6b6142f5b5..17e31ed63fba 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -5,7 +5,29 @@ import { injectable } from 'inversify'; import { arch, release } from 'os'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; -import { IPlatformService } from './types'; +import { IPlatformService, IVersion } from './types'; + +class OSVersion implements IVersion { + public get versionString(): string { + return release(); + } + public get versionMajor(): number { + const parts = this.versionString.split('.'); + return parts.length > 0 ? parseInt(parts[0], 10) : 0; + } + public get versionMinor(): number { + const parts = this.versionString.split('.'); + return parts.length > 1 ? parseInt(parts[1], 10) : 0; + } +} + +class MacOSVersion { + public get isCompatibleOS(): boolean { + // https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history + // 10.12 == Darwin 16.0 + return new OSVersion().versionMajor >= 16; + } +} @injectable() export class PlatformService implements IPlatformService { @@ -34,15 +56,18 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } - public get version(): string { - return release(); - } - public get versionMajor(): number { - const parts = this.version.split('.'); - return parts.length > 0 ? parseInt(parts[0], 10) : 0; - } - public get versionMinor(): number { - const parts = this.version.split('.'); - return parts.length > 1 ? parseInt(parts[1], 10) : 0; + public get isNetCoreCompatibleOS(): boolean { + if (this.isMac) { + 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. } } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 48b0058558f1..4fd22b4d6b72 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -27,9 +27,7 @@ export interface IPlatformService { is64bit: boolean; pathVariableName: 'Path' | 'PATH'; virtualEnvBinName: 'bin' | 'scripts'; - version: string; - versionMajor: number; - versionMinor: number; + isNetCoreCompatibleOS: boolean; } export type TemporaryFile = { filePath: string } & Disposable; @@ -56,3 +54,9 @@ export interface IFileSystem { search(globPattern: string): Promise; createTemporaryFile(extension: string): Promise; } + +export interface IVersion { + readonly versionString: string; + readonly versionMajor: number; + readonly versionMinor: number; +} From 0d3c0669191e65b09d0d3ec06a5bf9d42f220874 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 14:08:55 -0700 Subject: [PATCH 13/65] Linux version check --- package.json | 6 + src/client/activation/languageServer.ts | 11 +- src/client/common/platform/platformService.ts | 112 +++++++++++++++--- src/client/common/platform/types.ts | 2 +- 4 files changed, 109 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 3f1cff09dd1d..2118556f9dab 100644 --- a/package.json +++ b/package.json @@ -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, diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index a540584880bd..e9802bcc072c 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -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 { const platform = this.services.get(IPlatformService); - if (!platform.isNetCoreCompatibleOS) { + const message = await platform.isNetCoreCompatibleOS(); + if (message && message.length > 0) { if (platform.isMac) { - this.services.get(ILogger).logError('Unsupported MacOS'); - this.appShell.showErrorMessage('Microsoft Python Language Server does not support MacOS older than 10.12.'); + this.services.get(ILogger).logError(message); + this.appShell.showErrorMessage(message); } - // tslint:disable-next-line:no-suspicious-comment - // TODO: Linux messages return false; } return true; diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index 17e31ed63fba..73e50eb599c1 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -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'; @@ -21,20 +23,105 @@ class OSVersion implements IVersion { } } +enum OSCheckResult { + Compatible, + Incompatible, + Unknown +} + class MacOSVersion { - public get isCompatibleOS(): boolean { + public isCompatibleOS(): Promise { // 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 { + const factory = this.serviceContainer.get(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 { + 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); } @@ -56,18 +143,13 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } - public get isNetCoreCompatibleOS(): boolean { + public isNetCoreCompatibleOS(): Promise { 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. } } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 4fd22b4d6b72..2d5812c99920 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -27,7 +27,7 @@ export interface IPlatformService { is64bit: boolean; pathVariableName: 'Path' | 'PATH'; virtualEnvBinName: 'bin' | 'scripts'; - isNetCoreCompatibleOS: boolean; + isNetCoreCompatibleOS(): Promise; } export type TemporaryFile = { filePath: string } & Disposable; From 925f6635adf79cf4ec41fba6a0700f93d97668a3 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 14:25:44 -0700 Subject: [PATCH 14/65] Linux check --- src/client/common/platform/platformService.ts | 36 +++++++++++++------ src/client/common/types.ts | 2 ++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index 73e50eb599c1..9f6e802404a9 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -4,8 +4,10 @@ import { inject, injectable } from 'inversify'; import { arch, release } from 'os'; +import { Uri } from 'vscode'; import { IServiceContainer } from '../../ioc/types'; import { IProcessService, IProcessServiceFactory } from '../process/types'; +import { IConfigurationService } from '../types'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; import { IPlatformService, IVersion } from './types'; @@ -98,20 +100,29 @@ class LinuxVersion { private async checkLinux(process: IProcessService, command: string, args: string[], osName: string, key: string, values: string[]): Promise { 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) { + if (words.indexOf(osName) <= 0) { + return Promise.resolve(OSCheckResult.Unknown); + } + + const index = words.indexOf(key); // looking for 'release' variety + if (index >= 0 && index < words.length - 1) { + const version = words[index + 1]; + const parts = version.split('.'); + const major = parts[0]; + const minor = parts.length > 1 ? parts[1] : undefined; + for (const v of values) { + if (v.indexOf('.') > 0 && minor) { + // We need to check both major and minor + const p = v.split('.'); + if (major === p[0] && minor && parseInt(minor, 10) >= parseInt(p[1], 10)) { return Promise.resolve(OSCheckResult.Compatible); } + } else if (major === v) { + return Promise.resolve(OSCheckResult.Compatible); } } - return Promise.resolve(OSCheckResult.Incompatible); } - return Promise.resolve(OSCheckResult.Unknown); + return Promise.resolve(OSCheckResult.Incompatible); } } @@ -143,7 +154,12 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } - public isNetCoreCompatibleOS(): Promise { + public isNetCoreCompatibleOS(resource?: Uri): Promise { + const config = this.serviceContainer.get(IConfigurationService); + const settings = config.getSettings(resource); + if (settings && settings.analysis && !settings.analysis.checkOSVersion) { + return Promise.resolve(''); + } if (this.isMac) { return new MacOSVersion().isCompatibleOS(); } diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 400e21f466b6..15e729490823 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -244,6 +244,8 @@ export interface IAnalysisSettings { readonly information: string[]; readonly disabled: string[]; readonly traceLogging: boolean; + readonly diagnosticPublishDelay: number; + readonly checkOSVersion: boolean; } export const IConfigurationService = Symbol('IConfigurationService'); From fef0e9263035f57acf5212cf2799ff6d4579cb04 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 14:29:04 -0700 Subject: [PATCH 15/65] Simplify --- src/client/common/platform/platformService.ts | 20 ++++--------------- src/client/common/platform/types.ts | 6 ------ 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index 9f6e802404a9..42b089294e1b 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -9,21 +9,7 @@ import { IServiceContainer } from '../../ioc/types'; import { IProcessService, IProcessServiceFactory } from '../process/types'; import { IConfigurationService } from '../types'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; -import { IPlatformService, IVersion } from './types'; - -class OSVersion implements IVersion { - public get versionString(): string { - return release(); - } - public get versionMajor(): number { - const parts = this.versionString.split('.'); - return parts.length > 0 ? parseInt(parts[0], 10) : 0; - } - public get versionMinor(): number { - const parts = this.versionString.split('.'); - return parts.length > 1 ? parseInt(parts[1], 10) : 0; - } -} +import { IPlatformService } from './types'; enum OSCheckResult { Compatible, @@ -35,7 +21,9 @@ class MacOSVersion { public isCompatibleOS(): Promise { // https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history // 10.12 == Darwin 16.0 - return Promise.resolve(new OSVersion().versionMajor >= 16 ? '' : 'Microsoft Python Language Server does not support MacOS older than 10.12.'); + const parts = release().split('.'); + const versionMajor = parts.length > 0 ? parseInt(parts[0], 10) : 0; + return Promise.resolve(versionMajor >= 16 ? '' : 'Microsoft Python Language Server does not support MacOS older than 10.12.'); } } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 2d5812c99920..5c8d5cbab396 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -54,9 +54,3 @@ export interface IFileSystem { search(globPattern: string): Promise; createTemporaryFile(extension: string): Promise; } - -export interface IVersion { - readonly versionString: string; - readonly versionMajor: number; - readonly versionMinor: number; -} From 2c7243c310c2d460e77e816c3c193f10197e7a70 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 16:12:37 -0700 Subject: [PATCH 16/65] Test prep --- src/client/activation/languageServer.ts | 2 +- src/client/common/platform/operatingSystem.ts | 15 ++++ src/client/common/platform/platformService.ts | 44 ++++++------ src/client/common/platform/serviceRegistry.ts | 6 +- src/client/common/platform/types.ts | 13 +++- src/client/common/process/currentProcess.ts | 3 + src/client/common/types.ts | 1 + .../common/platform/platform.unit.test.ts | 71 +++++++++++++++++++ .../envVarsProvider.multiroot.test.ts | 3 +- .../common/variables/envVarsService.test.ts | 12 +++- src/test/mocks/process.ts | 3 + 11 files changed, 147 insertions(+), 26 deletions(-) create mode 100644 src/client/common/platform/operatingSystem.ts create mode 100644 src/test/common/platform/platform.unit.test.ts diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index e9802bcc072c..b3265c9aafb7 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -127,7 +127,7 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { private async checkSupportedPlatform(): Promise { const platform = this.services.get(IPlatformService); - const message = await platform.isNetCoreCompatibleOS(); + const message = await platform.isNetCoreCompatible(); if (message && message.length > 0) { if (platform.isMac) { this.services.get(ILogger).logError(message); diff --git a/src/client/common/platform/operatingSystem.ts b/src/client/common/platform/operatingSystem.ts new file mode 100644 index 000000000000..bf63182761bb --- /dev/null +++ b/src/client/common/platform/operatingSystem.ts @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +'use strict'; + +import { arch, release } from 'os'; +import { IOperatingSystem } from './types'; + +export class OperatingSystem implements IOperatingSystem { + public release(): string { + return release(); + } + public arch(): string { + return arch(); + } +} diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index 42b089294e1b..ca7ea85188e2 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -3,13 +3,12 @@ 'use strict'; import { inject, injectable } from 'inversify'; -import { arch, release } from 'os'; import { Uri } from 'vscode'; import { IServiceContainer } from '../../ioc/types'; import { IProcessService, IProcessServiceFactory } from '../process/types'; -import { IConfigurationService } from '../types'; +import { IConfigurationService, ICurrentProcess } from '../types'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; -import { IPlatformService } from './types'; +import { IOperatingSystem, IPlatformService } from './types'; enum OSCheckResult { Compatible, @@ -18,10 +17,10 @@ enum OSCheckResult { } class MacOSVersion { - public isCompatibleOS(): Promise { + public isCompatibleOS(os: IOperatingSystem): Promise { // https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history // 10.12 == Darwin 16.0 - const parts = release().split('.'); + const parts = os.release().split('.'); const versionMajor = parts.length > 0 ? parseInt(parts[0], 10) : 0; return Promise.resolve(versionMajor >= 16 ? '' : 'Microsoft Python Language Server does not support MacOS older than 10.12.'); } @@ -87,7 +86,7 @@ class LinuxVersion { private async checkLinux(process: IProcessService, command: string, args: string[], osName: string, key: string, values: string[]): Promise { const result = await process.exec(command, args); - const words = result.stdout.split(' \t\n'); + const words = result.stdout.split(/\s/); if (words.indexOf(osName) <= 0) { return Promise.resolve(OSCheckResult.Unknown); } @@ -117,12 +116,15 @@ class LinuxVersion { // tslint:disable-next-line:max-classes-per-file @injectable() export class PlatformService implements IPlatformService { - private _isWindows: boolean; - private _isMac: boolean; + private readonly _isWindows: boolean; + private readonly _isMac: boolean; + private readonly os: IOperatingSystem; constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { + const process = serviceContainer.get(ICurrentProcess); this._isWindows = /^win/.test(process.platform); this._isMac = /^darwin/.test(process.platform); + this.os = this.serviceContainer.get(IOperatingSystem); } public get isWindows(): boolean { return this._isWindows; @@ -134,7 +136,7 @@ export class PlatformService implements IPlatformService { return !(this.isWindows || this.isMac); } public get is64bit(): boolean { - return arch() === 'x64'; + return this.os.arch() === 'x64'; } public get pathVariableName() { return this.isWindows ? WINDOWS_PATH_VARIABLE_NAME : NON_WINDOWS_PATH_VARIABLE_NAME; @@ -142,17 +144,19 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } - public isNetCoreCompatibleOS(resource?: Uri): Promise { - const config = this.serviceContainer.get(IConfigurationService); - const settings = config.getSettings(resource); - if (settings && settings.analysis && !settings.analysis.checkOSVersion) { - return Promise.resolve(''); - } - if (this.isMac) { - return new MacOSVersion().isCompatibleOS(); - } - if (this.isLinux) { - return new LinuxVersion(this.serviceContainer).isCompatibleOS(); + public isNetCoreCompatible(resource?: Uri): Promise { + if (this.serviceContainer) { + const config = this.serviceContainer.get(IConfigurationService); + const settings = config.getSettings(resource); + if (settings && settings.analysis && !settings.analysis.checkOSVersion) { + return Promise.resolve(''); + } + if (this.isMac) { + return new MacOSVersion().isCompatibleOS(this.os); + } + if (this.isLinux) { + return new LinuxVersion(this.serviceContainer).isCompatibleOS(); + } } return Promise.resolve(''); // Windows matches between .NET Core and VS Code. } diff --git a/src/client/common/platform/serviceRegistry.ts b/src/client/common/platform/serviceRegistry.ts index dce3511f9f37..6ab3116a2de5 100644 --- a/src/client/common/platform/serviceRegistry.ts +++ b/src/client/common/platform/serviceRegistry.ts @@ -3,14 +3,18 @@ 'use strict'; import { IServiceManager } from '../../ioc/types'; +import { CurrentProcess } from '../process/currentProcess'; +import { ICurrentProcess } from '../types'; import { FileSystem } from './fileSystem'; +import { OperatingSystem } from './operatingSystem'; import { PlatformService } from './platformService'; import { RegistryImplementation } from './registry'; -import { IFileSystem, IPlatformService, IRegistry } from './types'; +import { IFileSystem, IOperatingSystem, IPlatformService, IRegistry } from './types'; export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(IPlatformService, PlatformService); serviceManager.addSingleton(IFileSystem, FileSystem); + serviceManager.addSingleton(IOperatingSystem, OperatingSystem); if (serviceManager.get(IPlatformService).isWindows) { serviceManager.addSingleton(IRegistry, RegistryImplementation); } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 5c8d5cbab396..395bc3e5f5a2 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -27,7 +27,7 @@ export interface IPlatformService { is64bit: boolean; pathVariableName: 'Path' | 'PATH'; virtualEnvBinName: 'bin' | 'scripts'; - isNetCoreCompatibleOS(): Promise; + isNetCoreCompatible(): Promise; } export type TemporaryFile = { filePath: string } & Disposable; @@ -54,3 +54,14 @@ export interface IFileSystem { search(globPattern: string): Promise; createTemporaryFile(extension: string): Promise; } + +export const IOperatingSystem = Symbol('IOperatingSystem'); +export interface IOperatingSystem { + release(): string; + arch(): string; +} + +export const ICurrentProcess = Symbol('ICurrentProcess'); +export interface ICurrentProcess { + readonly platform: string; +} diff --git a/src/client/common/process/currentProcess.ts b/src/client/common/process/currentProcess.ts index fc2bb97bb01d..f9b30aed5ad3 100644 --- a/src/client/common/process/currentProcess.ts +++ b/src/client/common/process/currentProcess.ts @@ -22,4 +22,7 @@ export class CurrentProcess implements ICurrentProcess { public get stdin(): NodeJS.ReadStream { return process.stdin; } + public get platform(): string { + return process.platform; + } } diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 15e729490823..8ffbd8ae2ff5 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -111,6 +111,7 @@ export interface ICurrentProcess { readonly argv: string[]; readonly stdout: NodeJS.WriteStream; readonly stdin: NodeJS.ReadStream; + readonly platform: string; on(event: string | symbol, listener: Function): this; } diff --git a/src/test/common/platform/platform.unit.test.ts b/src/test/common/platform/platform.unit.test.ts new file mode 100644 index 000000000000..1be4b01756ca --- /dev/null +++ b/src/test/common/platform/platform.unit.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { expect, use } from 'chai'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +import * as TypeMoq from 'typemoq'; +import { Container } from '../../../../node_modules/inversify'; +import { FileSystem } from '../../../client/common/platform/fileSystem'; +import { PlatformService } from '../../../client/common/platform/platformService'; +import { ICurrentProcess, IFileSystem, IOperatingSystem, IPlatformService } from '../../../client/common/platform/types'; +import { IPythonExecutionFactory, IPythonExecutionService } from '../../../client/common/process/types'; +import { IAnalysisSettings, IConfigurationService, IPythonSettings } from '../../../client/common/types'; +import { ServiceContainer } from '../../../client/ioc/container'; +import { ServiceManager } from '../../../client/ioc/serviceManager'; +// tslint:disable-next-line:no-require-imports no-var-requires +const assertArrays = require('chai-arrays'); +use(assertArrays); + +// tslint:disable-next-line:max-func-body-length +suite('Platform', () => { + let process: TypeMoq.IMock; + let os: TypeMoq.IMock; + let config: TypeMoq.IMock; + let pythonSettings: TypeMoq.IMock; + let analysisSettings: TypeMoq.IMock; + let execFactory: TypeMoq.IMock; + let exec: TypeMoq.IMock; + let serviceContainer: ServiceContainer; + + setup(() => { + const cont = new Container(); + const serviceManager = new ServiceManager(cont); + serviceContainer = new ServiceContainer(cont); + + process = TypeMoq.Mock.ofType(); + os = TypeMoq.Mock.ofType(); + config = TypeMoq.Mock.ofType(); + pythonSettings = TypeMoq.Mock.ofType(); + analysisSettings = TypeMoq.Mock.ofType(); + execFactory = TypeMoq.Mock.ofType(); + exec = TypeMoq.Mock.ofType(); + + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + + pythonSettings.setup(x => x.analysis).returns(() => analysisSettings.object); + config.setup(x => x.getSettings(TypeMoq.It.isAny())).returns(() => pythonSettings.object); + serviceManager.addSingletonInstance(IConfigurationService, config.object); + + execFactory.setup(x => x.create(TypeMoq.It.isAny())).returns(() => Promise.resolve(exec.object)); + serviceManager.addSingletonInstance(IPythonExecutionFactory, execFactory.object); + }); + test('Windows platform check', async () => { + const platform = new PlatformService(serviceContainer); + process.setup(x => x.platform).returns(() => 'win'); + expect(platform.isWindows).to.be.equal(true, 'Platform must be Windows'); + expect(platform.isMac).to.be.equal(true, 'Platform must not be Mac'); + expect(platform.isLinux).to.be.equal(true, 'Platform must not be Linux'); + }); + test('32-bit platform check', async () => { + const platform = new PlatformService(serviceContainer); + os.setup(x => x.arch()).returns(() => ''); + expect(platform.is64bit).to.be.equal(false, 'Platform must not be x64'); + }); + test('64-bit platform check', async () => { + const platform = new PlatformService(serviceContainer); + os.setup(x => x.arch()).returns(() => 'x64'); + expect(platform.is64bit).to.be.equal(true, 'Platform must be x64'); + }); +}); diff --git a/src/test/common/variables/envVarsProvider.multiroot.test.ts b/src/test/common/variables/envVarsProvider.multiroot.test.ts index da27c8c99cb7..2114f1d66295 100644 --- a/src/test/common/variables/envVarsProvider.multiroot.test.ts +++ b/src/test/common/variables/envVarsProvider.multiroot.test.ts @@ -9,8 +9,7 @@ import * as path from 'path'; import { ConfigurationTarget, Disposable, Uri, workspace } from 'vscode'; import { createDeferred } from '../../../client/common/helpers'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from '../../../client/common/platform/constants'; -import { IDisposableRegistry, IPathUtils } from '../../../client/common/types'; -import { IsWindows } from '../../../client/common/types'; +import { IDisposableRegistry, IPathUtils, IsWindows } from '../../../client/common/types'; import { IS_WINDOWS } from '../../../client/common/utils'; import { EnvironmentVariablesService } from '../../../client/common/variables/environment'; import { EnvironmentVariablesProvider } from '../../../client/common/variables/environmentVariablesProvider'; diff --git a/src/test/common/variables/envVarsService.test.ts b/src/test/common/variables/envVarsService.test.ts index 9f77ab7ebcd2..c6c832a6fe61 100644 --- a/src/test/common/variables/envVarsService.test.ts +++ b/src/test/common/variables/envVarsService.test.ts @@ -4,11 +4,16 @@ import { expect, use } from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; import * as path from 'path'; +import { Container } from '../../../../node_modules/inversify'; +import { OperatingSystem } from '../../../client/common/platform/operatingSystem'; import { PathUtils } from '../../../client/common/platform/pathUtils'; import { PlatformService } from '../../../client/common/platform/platformService'; +import { IOperatingSystem } from '../../../client/common/platform/types'; import { IPathUtils } from '../../../client/common/types'; import { EnvironmentVariablesService } from '../../../client/common/variables/environment'; import { IEnvironmentVariablesService } from '../../../client/common/variables/types'; +import { ServiceContainer } from '../../../client/ioc/container'; +import { ServiceManager } from '../../../client/ioc/serviceManager'; use(chaiAsPromised); @@ -19,7 +24,12 @@ suite('Environment Variables Service', () => { let pathUtils: IPathUtils; let variablesService: IEnvironmentVariablesService; setup(() => { - pathUtils = new PathUtils(new PlatformService().isWindows); + const cont = new Container(); + const serviceManager = new ServiceManager(cont); + const serviceContainer = new ServiceContainer(cont); + serviceManager.addSingleton(IOperatingSystem, OperatingSystem); + + pathUtils = new PathUtils(new PlatformService(serviceContainer).isWindows); variablesService = new EnvironmentVariablesService(pathUtils); }); diff --git a/src/test/mocks/process.ts b/src/test/mocks/process.ts index f3bb89449e7d..9dc24c1ae0b2 100644 --- a/src/test/mocks/process.ts +++ b/src/test/mocks/process.ts @@ -21,4 +21,7 @@ export class MockProcess implements ICurrentProcess { public get stdin(): NodeJS.ReadStream { return TypeMoq.Mock.ofType().object; } + public get platform(): string { + return 'win'; + } } From 07dc2fae054415b5877d6f7289df68b5fbef5846 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 16:34:26 -0700 Subject: [PATCH 17/65] Platform tests --- src/client/common/platform/types.ts | 5 -- .../common/platform/platform.unit.test.ts | 63 +++++++++++++------ src/test/index.ts | 2 +- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 395bc3e5f5a2..11fd3927c55a 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -60,8 +60,3 @@ export interface IOperatingSystem { release(): string; arch(): string; } - -export const ICurrentProcess = Symbol('ICurrentProcess'); -export interface ICurrentProcess { - readonly platform: string; -} diff --git a/src/test/common/platform/platform.unit.test.ts b/src/test/common/platform/platform.unit.test.ts index 1be4b01756ca..2b7a2bd3f95a 100644 --- a/src/test/common/platform/platform.unit.test.ts +++ b/src/test/common/platform/platform.unit.test.ts @@ -1,21 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { expect, use } from 'chai'; -import * as fs from 'fs-extra'; -import * as path from 'path'; +import { expect } from 'chai'; import * as TypeMoq from 'typemoq'; import { Container } from '../../../../node_modules/inversify'; -import { FileSystem } from '../../../client/common/platform/fileSystem'; import { PlatformService } from '../../../client/common/platform/platformService'; -import { ICurrentProcess, IFileSystem, IOperatingSystem, IPlatformService } from '../../../client/common/platform/types'; +import { IOperatingSystem } from '../../../client/common/platform/types'; import { IPythonExecutionFactory, IPythonExecutionService } from '../../../client/common/process/types'; -import { IAnalysisSettings, IConfigurationService, IPythonSettings } from '../../../client/common/types'; +import { IAnalysisSettings, IConfigurationService, ICurrentProcess, IPythonSettings } from '../../../client/common/types'; import { ServiceContainer } from '../../../client/ioc/container'; import { ServiceManager } from '../../../client/ioc/serviceManager'; -// tslint:disable-next-line:no-require-imports no-var-requires -const assertArrays = require('chai-arrays'); -use(assertArrays); // tslint:disable-next-line:max-func-body-length suite('Platform', () => { @@ -26,11 +20,12 @@ suite('Platform', () => { let analysisSettings: TypeMoq.IMock; let execFactory: TypeMoq.IMock; let exec: TypeMoq.IMock; + let serviceManager: ServiceManager; let serviceContainer: ServiceContainer; setup(() => { const cont = new Container(); - const serviceManager = new ServiceManager(cont); + serviceManager = new ServiceManager(cont); serviceContainer = new ServiceContainer(cont); process = TypeMoq.Mock.ofType(); @@ -41,9 +36,6 @@ suite('Platform', () => { execFactory = TypeMoq.Mock.ofType(); exec = TypeMoq.Mock.ofType(); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - pythonSettings.setup(x => x.analysis).returns(() => analysisSettings.object); config.setup(x => x.getSettings(TypeMoq.It.isAny())).returns(() => pythonSettings.object); serviceManager.addSingletonInstance(IConfigurationService, config.object); @@ -52,20 +44,55 @@ suite('Platform', () => { serviceManager.addSingletonInstance(IPythonExecutionFactory, execFactory.object); }); test('Windows platform check', async () => { + process.setup(x => x.platform).returns(() => 'win32'); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); const platform = new PlatformService(serviceContainer); - process.setup(x => x.platform).returns(() => 'win'); + expect(platform.isWindows).to.be.equal(true, 'Platform must be Windows'); - expect(platform.isMac).to.be.equal(true, 'Platform must not be Mac'); - expect(platform.isLinux).to.be.equal(true, 'Platform must not be Linux'); + expect(platform.isMac).to.be.equal(false, 'Platform must not be Mac'); + expect(platform.isLinux).to.be.equal(false, 'Platform must not be Linux'); }); - test('32-bit platform check', async () => { + test('Mac platform check', async () => { + process.setup(x => x.platform).returns(() => 'darwin'); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); const platform = new PlatformService(serviceContainer); + + expect(platform.isMac).to.be.equal(true, 'Platform must be Mac'); + expect(platform.isWindows).to.be.equal(false, 'Platform must not be Windows'); + expect(platform.isLinux).to.be.equal(false, 'Platform must not be Linux'); + }); + test('32-bit platform check', async () => { os.setup(x => x.arch()).returns(() => ''); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + const platform = new PlatformService(serviceContainer); + expect(platform.is64bit).to.be.equal(false, 'Platform must not be x64'); }); test('64-bit platform check', async () => { - const platform = new PlatformService(serviceContainer); os.setup(x => x.arch()).returns(() => 'x64'); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + const platform = new PlatformService(serviceContainer); + expect(platform.is64bit).to.be.equal(true, 'Platform must be x64'); }); + test('bin/scripts check (Windows)', async () => { + process.setup(x => x.platform).returns(() => 'win32'); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + const platform = new PlatformService(serviceContainer); + + expect(platform.virtualEnvBinName).to.be.equal('scripts', 'Venv bin must be scripts on Windows'); + }); + test('bin/scripts check (Mac/Linux)', async () => { + process.setup(x => x.platform).returns(() => 'darwin'); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + const platform = new PlatformService(serviceContainer); + + expect(platform.virtualEnvBinName).to.be.equal('bin', 'Venv bin must be scripts on Mac'); + }); }); diff --git a/src/test/index.ts b/src/test/index.ts index b63fe1ba47b4..eefb622b7c5d 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -18,7 +18,7 @@ process.env.IS_MULTI_ROOT_TEST = IS_MULTI_ROOT_TEST.toString(); // If running on CI server and we're running the debugger tests, then ensure we only run debug tests. // We do this to ensure we only run debugger test, as debugger tests are very flaky on CI. // So the solution is to run them separately and first on CI. -const grep = IS_CI_SERVER && IS_CI_SERVER_TEST_DEBUGGER ? 'Debug' : undefined; +const grep = IS_CI_SERVER && IS_CI_SERVER_TEST_DEBUGGER ? 'Debug' : 'Platform'; const testFilesSuffix = process.env.TEST_FILES_SUFFIX; // You can directly control Mocha options by uncommenting the following lines. From cd970bea17f2b141bb49cf3c63aa2406a1d23449 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 16:52:00 -0700 Subject: [PATCH 18/65] Mac compat tests --- .../common/platform/platform.unit.test.ts | 65 +++++++++++++------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/src/test/common/platform/platform.unit.test.ts b/src/test/common/platform/platform.unit.test.ts index 2b7a2bd3f95a..76beea820ed3 100644 --- a/src/test/common/platform/platform.unit.test.ts +++ b/src/test/common/platform/platform.unit.test.ts @@ -4,8 +4,9 @@ import { expect } from 'chai'; import * as TypeMoq from 'typemoq'; import { Container } from '../../../../node_modules/inversify'; +import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from '../../../client/common/platform/constants'; import { PlatformService } from '../../../client/common/platform/platformService'; -import { IOperatingSystem } from '../../../client/common/platform/types'; +import { IOperatingSystem, IPlatformService } from '../../../client/common/platform/types'; import { IPythonExecutionFactory, IPythonExecutionService } from '../../../client/common/process/types'; import { IAnalysisSettings, IConfigurationService, ICurrentProcess, IPythonSettings } from '../../../client/common/types'; import { ServiceContainer } from '../../../client/ioc/container'; @@ -44,21 +45,13 @@ suite('Platform', () => { serviceManager.addSingletonInstance(IPythonExecutionFactory, execFactory.object); }); test('Windows platform check', async () => { - process.setup(x => x.platform).returns(() => 'win32'); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - const platform = new PlatformService(serviceContainer); - + const platform = setupWindows(); expect(platform.isWindows).to.be.equal(true, 'Platform must be Windows'); expect(platform.isMac).to.be.equal(false, 'Platform must not be Mac'); expect(platform.isLinux).to.be.equal(false, 'Platform must not be Linux'); }); test('Mac platform check', async () => { - process.setup(x => x.platform).returns(() => 'darwin'); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - const platform = new PlatformService(serviceContainer); - + const platform = setupMac(); expect(platform.isMac).to.be.equal(true, 'Platform must be Mac'); expect(platform.isWindows).to.be.equal(false, 'Platform must not be Windows'); expect(platform.isLinux).to.be.equal(false, 'Platform must not be Linux'); @@ -80,19 +73,51 @@ suite('Platform', () => { expect(platform.is64bit).to.be.equal(true, 'Platform must be x64'); }); test('bin/scripts check (Windows)', async () => { - process.setup(x => x.platform).returns(() => 'win32'); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - const platform = new PlatformService(serviceContainer); - + const platform = setupWindows(); expect(platform.virtualEnvBinName).to.be.equal('scripts', 'Venv bin must be scripts on Windows'); }); test('bin/scripts check (Mac/Linux)', async () => { + const platform = setupMac(); + expect(platform.virtualEnvBinName).to.be.equal('bin', 'Venv bin must be scripts on Mac'); + }); + test('Path variable check (Windows)', async () => { + const platform = setupWindows(); + expect(platform.pathVariableName).to.be.equal(WINDOWS_PATH_VARIABLE_NAME, 'Wrong path variable name on Windows'); + }); + test('Path variable check (Mac/Linux)', async () => { + const platform = setupMac(); + expect(platform.pathVariableName).to.be.equal(NON_WINDOWS_PATH_VARIABLE_NAME, 'Wrong path variable name on Mac'); + }); + test('.NET Core compat (Windows)', async () => { + const platform = setupWindows(); + expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Windows must be .NET Core compatible'); + }); + test('.NET Core compat (Mac 16)', async () => { + const platform = setupMac('16.1'); + expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Darwin 16.1 must be .NET Core compatible'); + }); + test('.NET Core compat (Mac 17)', async () => { + const platform = setupMac('17.0'); + expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Darwin 17.0 must be .NET Core compatible'); + }); + test('.NET Core compat (Mac 15)', async () => { + const platform = setupMac('15.1'); + expect(platform.isNetCoreCompatible()).to.eventually.be.equal('Microsoft Python Language Server does not support MacOS older than 10.12.', 'Darwin 15.1 must not be .NET Core compatible'); + }); + + function setupWindows(): IPlatformService { + process.setup(x => x.platform).returns(() => 'win32'); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + return new PlatformService(serviceContainer); + } + function setupMac(release?: string): IPlatformService { process.setup(x => x.platform).returns(() => 'darwin'); serviceManager.addSingletonInstance(ICurrentProcess, process.object); + if (release) { + os.setup(x => x.release()).returns(() => release); + } serviceManager.addSingletonInstance(IOperatingSystem, os.object); - const platform = new PlatformService(serviceContainer); - - expect(platform.virtualEnvBinName).to.be.equal('bin', 'Venv bin must be scripts on Mac'); - }); + return new PlatformService(serviceContainer); + } }); From c63c90464291352d817f1e41ac3c12775ae5ecd7 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:11:25 -0700 Subject: [PATCH 19/65] Ubuntu tests --- .../common/platform/platform.unit.test.ts | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/test/common/platform/platform.unit.test.ts b/src/test/common/platform/platform.unit.test.ts index 76beea820ed3..3b58c426ecce 100644 --- a/src/test/common/platform/platform.unit.test.ts +++ b/src/test/common/platform/platform.unit.test.ts @@ -7,7 +7,7 @@ import { Container } from '../../../../node_modules/inversify'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from '../../../client/common/platform/constants'; import { PlatformService } from '../../../client/common/platform/platformService'; import { IOperatingSystem, IPlatformService } from '../../../client/common/platform/types'; -import { IPythonExecutionFactory, IPythonExecutionService } from '../../../client/common/process/types'; +import { ExecutionResult, IProcessService, IProcessServiceFactory } from '../../../client/common/process/types'; import { IAnalysisSettings, IConfigurationService, ICurrentProcess, IPythonSettings } from '../../../client/common/types'; import { ServiceContainer } from '../../../client/ioc/container'; import { ServiceManager } from '../../../client/ioc/serviceManager'; @@ -19,8 +19,8 @@ suite('Platform', () => { let config: TypeMoq.IMock; let pythonSettings: TypeMoq.IMock; let analysisSettings: TypeMoq.IMock; - let execFactory: TypeMoq.IMock; - let exec: TypeMoq.IMock; + let execFactory: TypeMoq.IMock; + let exec: TypeMoq.IMock; let serviceManager: ServiceManager; let serviceContainer: ServiceContainer; @@ -34,15 +34,15 @@ suite('Platform', () => { config = TypeMoq.Mock.ofType(); pythonSettings = TypeMoq.Mock.ofType(); analysisSettings = TypeMoq.Mock.ofType(); - execFactory = TypeMoq.Mock.ofType(); - exec = TypeMoq.Mock.ofType(); + execFactory = TypeMoq.Mock.ofType(); + exec = TypeMoq.Mock.ofType(); pythonSettings.setup(x => x.analysis).returns(() => analysisSettings.object); config.setup(x => x.getSettings(TypeMoq.It.isAny())).returns(() => pythonSettings.object); serviceManager.addSingletonInstance(IConfigurationService, config.object); execFactory.setup(x => x.create(TypeMoq.It.isAny())).returns(() => Promise.resolve(exec.object)); - serviceManager.addSingletonInstance(IPythonExecutionFactory, execFactory.object); + serviceManager.addSingletonInstance(IProcessServiceFactory, execFactory.object); }); test('Windows platform check', async () => { const platform = setupWindows(); @@ -92,18 +92,34 @@ suite('Platform', () => { const platform = setupWindows(); expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Windows must be .NET Core compatible'); }); - test('.NET Core compat (Mac 16)', async () => { + test('.NET Core compat (MacOS 10.12)', async () => { const platform = setupMac('16.1'); expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Darwin 16.1 must be .NET Core compatible'); }); - test('.NET Core compat (Mac 17)', async () => { + test('.NET Core compat (MacOS 10.13)', async () => { const platform = setupMac('17.0'); expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Darwin 17.0 must be .NET Core compatible'); }); - test('.NET Core compat (Mac 15)', async () => { + test('.NET Core compat (MacOS 10.11)', async () => { const platform = setupMac('15.1'); expect(platform.isNetCoreCompatible()).to.eventually.be.equal('Microsoft Python Language Server does not support MacOS older than 10.12.', 'Darwin 15.1 must not be .NET Core compatible'); }); + test('.NET Core compat (Ubuntu 18)', async () => { + const platform = setupLinux('Description:\t\tUbuntu 18\nRelease:\t18.04'); + expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Ubuntu 18 must be .NET Core compatible'); + }); + test('.NET Core compat (Ubuntu 16)', async () => { + const platform = setupLinux('Description:\t\tUbuntu 16\nRelease:\t16.04'); + expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Ubuntu 16 must be .NET Core compatible'); + }); + test('.NET Core compat (Ubuntu 14)', async () => { + const platform = setupLinux('Description:\t\tUbuntu 14\nRelease:\t14.04'); + expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Ubuntu 14 must be .NET Core compatible'); + }); + test('.NET Core compat (Ubuntu 17)', async () => { + const platform = setupLinux('Description:\t\tUbuntu 17\nRelease:\t17.04'); + expect(platform.isNetCoreCompatible()).to.eventually.be.equal('Microsoft Python Language Server only supports Ubuntu 18, 16 or 14.', 'Ubuntu 17 must be not .NET Core compatible'); + }); function setupWindows(): IPlatformService { process.setup(x => x.platform).returns(() => 'win32'); @@ -120,4 +136,14 @@ suite('Platform', () => { serviceManager.addSingletonInstance(IOperatingSystem, os.object); return new PlatformService(serviceContainer); } + function setupLinux(version: string): IPlatformService { + const output: ExecutionResult = { + stdout: version + }; + exec.setup(x => x.exec(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(() => Promise.resolve(output)); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + return new PlatformService(serviceContainer); + } }); From 42ebdd13d821cde89c0d625b0616009798c83f2b Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:21:28 -0700 Subject: [PATCH 20/65] Revert "Ubuntu tests" This reverts commit c63c90464291352d817f1e41ac3c12775ae5ecd7. --- .../common/platform/platform.unit.test.ts | 44 ++++--------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/src/test/common/platform/platform.unit.test.ts b/src/test/common/platform/platform.unit.test.ts index 3b58c426ecce..76beea820ed3 100644 --- a/src/test/common/platform/platform.unit.test.ts +++ b/src/test/common/platform/platform.unit.test.ts @@ -7,7 +7,7 @@ import { Container } from '../../../../node_modules/inversify'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from '../../../client/common/platform/constants'; import { PlatformService } from '../../../client/common/platform/platformService'; import { IOperatingSystem, IPlatformService } from '../../../client/common/platform/types'; -import { ExecutionResult, IProcessService, IProcessServiceFactory } from '../../../client/common/process/types'; +import { IPythonExecutionFactory, IPythonExecutionService } from '../../../client/common/process/types'; import { IAnalysisSettings, IConfigurationService, ICurrentProcess, IPythonSettings } from '../../../client/common/types'; import { ServiceContainer } from '../../../client/ioc/container'; import { ServiceManager } from '../../../client/ioc/serviceManager'; @@ -19,8 +19,8 @@ suite('Platform', () => { let config: TypeMoq.IMock; let pythonSettings: TypeMoq.IMock; let analysisSettings: TypeMoq.IMock; - let execFactory: TypeMoq.IMock; - let exec: TypeMoq.IMock; + let execFactory: TypeMoq.IMock; + let exec: TypeMoq.IMock; let serviceManager: ServiceManager; let serviceContainer: ServiceContainer; @@ -34,15 +34,15 @@ suite('Platform', () => { config = TypeMoq.Mock.ofType(); pythonSettings = TypeMoq.Mock.ofType(); analysisSettings = TypeMoq.Mock.ofType(); - execFactory = TypeMoq.Mock.ofType(); - exec = TypeMoq.Mock.ofType(); + execFactory = TypeMoq.Mock.ofType(); + exec = TypeMoq.Mock.ofType(); pythonSettings.setup(x => x.analysis).returns(() => analysisSettings.object); config.setup(x => x.getSettings(TypeMoq.It.isAny())).returns(() => pythonSettings.object); serviceManager.addSingletonInstance(IConfigurationService, config.object); execFactory.setup(x => x.create(TypeMoq.It.isAny())).returns(() => Promise.resolve(exec.object)); - serviceManager.addSingletonInstance(IProcessServiceFactory, execFactory.object); + serviceManager.addSingletonInstance(IPythonExecutionFactory, execFactory.object); }); test('Windows platform check', async () => { const platform = setupWindows(); @@ -92,34 +92,18 @@ suite('Platform', () => { const platform = setupWindows(); expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Windows must be .NET Core compatible'); }); - test('.NET Core compat (MacOS 10.12)', async () => { + test('.NET Core compat (Mac 16)', async () => { const platform = setupMac('16.1'); expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Darwin 16.1 must be .NET Core compatible'); }); - test('.NET Core compat (MacOS 10.13)', async () => { + test('.NET Core compat (Mac 17)', async () => { const platform = setupMac('17.0'); expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Darwin 17.0 must be .NET Core compatible'); }); - test('.NET Core compat (MacOS 10.11)', async () => { + test('.NET Core compat (Mac 15)', async () => { const platform = setupMac('15.1'); expect(platform.isNetCoreCompatible()).to.eventually.be.equal('Microsoft Python Language Server does not support MacOS older than 10.12.', 'Darwin 15.1 must not be .NET Core compatible'); }); - test('.NET Core compat (Ubuntu 18)', async () => { - const platform = setupLinux('Description:\t\tUbuntu 18\nRelease:\t18.04'); - expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Ubuntu 18 must be .NET Core compatible'); - }); - test('.NET Core compat (Ubuntu 16)', async () => { - const platform = setupLinux('Description:\t\tUbuntu 16\nRelease:\t16.04'); - expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Ubuntu 16 must be .NET Core compatible'); - }); - test('.NET Core compat (Ubuntu 14)', async () => { - const platform = setupLinux('Description:\t\tUbuntu 14\nRelease:\t14.04'); - expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Ubuntu 14 must be .NET Core compatible'); - }); - test('.NET Core compat (Ubuntu 17)', async () => { - const platform = setupLinux('Description:\t\tUbuntu 17\nRelease:\t17.04'); - expect(platform.isNetCoreCompatible()).to.eventually.be.equal('Microsoft Python Language Server only supports Ubuntu 18, 16 or 14.', 'Ubuntu 17 must be not .NET Core compatible'); - }); function setupWindows(): IPlatformService { process.setup(x => x.platform).returns(() => 'win32'); @@ -136,14 +120,4 @@ suite('Platform', () => { serviceManager.addSingletonInstance(IOperatingSystem, os.object); return new PlatformService(serviceContainer); } - function setupLinux(version: string): IPlatformService { - const output: ExecutionResult = { - stdout: version - }; - exec.setup(x => x.exec(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(() => Promise.resolve(output)); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - return new PlatformService(serviceContainer); - } }); From d3c7acba05c9d4deda19208b1382dee4b8ce2c08 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:21:53 -0700 Subject: [PATCH 21/65] Revert "Mac compat tests" This reverts commit cd970bea17f2b141bb49cf3c63aa2406a1d23449. --- .../common/platform/platform.unit.test.ts | 65 ++++++------------- 1 file changed, 20 insertions(+), 45 deletions(-) diff --git a/src/test/common/platform/platform.unit.test.ts b/src/test/common/platform/platform.unit.test.ts index 76beea820ed3..2b7a2bd3f95a 100644 --- a/src/test/common/platform/platform.unit.test.ts +++ b/src/test/common/platform/platform.unit.test.ts @@ -4,9 +4,8 @@ import { expect } from 'chai'; import * as TypeMoq from 'typemoq'; import { Container } from '../../../../node_modules/inversify'; -import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from '../../../client/common/platform/constants'; import { PlatformService } from '../../../client/common/platform/platformService'; -import { IOperatingSystem, IPlatformService } from '../../../client/common/platform/types'; +import { IOperatingSystem } from '../../../client/common/platform/types'; import { IPythonExecutionFactory, IPythonExecutionService } from '../../../client/common/process/types'; import { IAnalysisSettings, IConfigurationService, ICurrentProcess, IPythonSettings } from '../../../client/common/types'; import { ServiceContainer } from '../../../client/ioc/container'; @@ -45,13 +44,21 @@ suite('Platform', () => { serviceManager.addSingletonInstance(IPythonExecutionFactory, execFactory.object); }); test('Windows platform check', async () => { - const platform = setupWindows(); + process.setup(x => x.platform).returns(() => 'win32'); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + const platform = new PlatformService(serviceContainer); + expect(platform.isWindows).to.be.equal(true, 'Platform must be Windows'); expect(platform.isMac).to.be.equal(false, 'Platform must not be Mac'); expect(platform.isLinux).to.be.equal(false, 'Platform must not be Linux'); }); test('Mac platform check', async () => { - const platform = setupMac(); + process.setup(x => x.platform).returns(() => 'darwin'); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + const platform = new PlatformService(serviceContainer); + expect(platform.isMac).to.be.equal(true, 'Platform must be Mac'); expect(platform.isWindows).to.be.equal(false, 'Platform must not be Windows'); expect(platform.isLinux).to.be.equal(false, 'Platform must not be Linux'); @@ -73,51 +80,19 @@ suite('Platform', () => { expect(platform.is64bit).to.be.equal(true, 'Platform must be x64'); }); test('bin/scripts check (Windows)', async () => { - const platform = setupWindows(); - expect(platform.virtualEnvBinName).to.be.equal('scripts', 'Venv bin must be scripts on Windows'); - }); - test('bin/scripts check (Mac/Linux)', async () => { - const platform = setupMac(); - expect(platform.virtualEnvBinName).to.be.equal('bin', 'Venv bin must be scripts on Mac'); - }); - test('Path variable check (Windows)', async () => { - const platform = setupWindows(); - expect(platform.pathVariableName).to.be.equal(WINDOWS_PATH_VARIABLE_NAME, 'Wrong path variable name on Windows'); - }); - test('Path variable check (Mac/Linux)', async () => { - const platform = setupMac(); - expect(platform.pathVariableName).to.be.equal(NON_WINDOWS_PATH_VARIABLE_NAME, 'Wrong path variable name on Mac'); - }); - test('.NET Core compat (Windows)', async () => { - const platform = setupWindows(); - expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Windows must be .NET Core compatible'); - }); - test('.NET Core compat (Mac 16)', async () => { - const platform = setupMac('16.1'); - expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Darwin 16.1 must be .NET Core compatible'); - }); - test('.NET Core compat (Mac 17)', async () => { - const platform = setupMac('17.0'); - expect(platform.isNetCoreCompatible()).to.eventually.be.equal('', 'Darwin 17.0 must be .NET Core compatible'); - }); - test('.NET Core compat (Mac 15)', async () => { - const platform = setupMac('15.1'); - expect(platform.isNetCoreCompatible()).to.eventually.be.equal('Microsoft Python Language Server does not support MacOS older than 10.12.', 'Darwin 15.1 must not be .NET Core compatible'); - }); - - function setupWindows(): IPlatformService { process.setup(x => x.platform).returns(() => 'win32'); serviceManager.addSingletonInstance(ICurrentProcess, process.object); serviceManager.addSingletonInstance(IOperatingSystem, os.object); - return new PlatformService(serviceContainer); - } - function setupMac(release?: string): IPlatformService { + const platform = new PlatformService(serviceContainer); + + expect(platform.virtualEnvBinName).to.be.equal('scripts', 'Venv bin must be scripts on Windows'); + }); + test('bin/scripts check (Mac/Linux)', async () => { process.setup(x => x.platform).returns(() => 'darwin'); serviceManager.addSingletonInstance(ICurrentProcess, process.object); - if (release) { - os.setup(x => x.release()).returns(() => release); - } serviceManager.addSingletonInstance(IOperatingSystem, os.object); - return new PlatformService(serviceContainer); - } + const platform = new PlatformService(serviceContainer); + + expect(platform.virtualEnvBinName).to.be.equal('bin', 'Venv bin must be scripts on Mac'); + }); }); From d86997b3f94b0ed153e1089aaa4c4c709fd1ae27 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:22:04 -0700 Subject: [PATCH 22/65] Revert "Platform tests" This reverts commit 07dc2fae054415b5877d6f7289df68b5fbef5846. --- src/client/common/platform/types.ts | 5 ++ .../common/platform/platform.unit.test.ts | 63 ++++++------------- src/test/index.ts | 2 +- 3 files changed, 24 insertions(+), 46 deletions(-) diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 11fd3927c55a..395bc3e5f5a2 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -60,3 +60,8 @@ export interface IOperatingSystem { release(): string; arch(): string; } + +export const ICurrentProcess = Symbol('ICurrentProcess'); +export interface ICurrentProcess { + readonly platform: string; +} diff --git a/src/test/common/platform/platform.unit.test.ts b/src/test/common/platform/platform.unit.test.ts index 2b7a2bd3f95a..1be4b01756ca 100644 --- a/src/test/common/platform/platform.unit.test.ts +++ b/src/test/common/platform/platform.unit.test.ts @@ -1,15 +1,21 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { expect } from 'chai'; +import { expect, use } from 'chai'; +import * as fs from 'fs-extra'; +import * as path from 'path'; import * as TypeMoq from 'typemoq'; import { Container } from '../../../../node_modules/inversify'; +import { FileSystem } from '../../../client/common/platform/fileSystem'; import { PlatformService } from '../../../client/common/platform/platformService'; -import { IOperatingSystem } from '../../../client/common/platform/types'; +import { ICurrentProcess, IFileSystem, IOperatingSystem, IPlatformService } from '../../../client/common/platform/types'; import { IPythonExecutionFactory, IPythonExecutionService } from '../../../client/common/process/types'; -import { IAnalysisSettings, IConfigurationService, ICurrentProcess, IPythonSettings } from '../../../client/common/types'; +import { IAnalysisSettings, IConfigurationService, IPythonSettings } from '../../../client/common/types'; import { ServiceContainer } from '../../../client/ioc/container'; import { ServiceManager } from '../../../client/ioc/serviceManager'; +// tslint:disable-next-line:no-require-imports no-var-requires +const assertArrays = require('chai-arrays'); +use(assertArrays); // tslint:disable-next-line:max-func-body-length suite('Platform', () => { @@ -20,12 +26,11 @@ suite('Platform', () => { let analysisSettings: TypeMoq.IMock; let execFactory: TypeMoq.IMock; let exec: TypeMoq.IMock; - let serviceManager: ServiceManager; let serviceContainer: ServiceContainer; setup(() => { const cont = new Container(); - serviceManager = new ServiceManager(cont); + const serviceManager = new ServiceManager(cont); serviceContainer = new ServiceContainer(cont); process = TypeMoq.Mock.ofType(); @@ -36,6 +41,9 @@ suite('Platform', () => { execFactory = TypeMoq.Mock.ofType(); exec = TypeMoq.Mock.ofType(); + serviceManager.addSingletonInstance(ICurrentProcess, process.object); + serviceManager.addSingletonInstance(IOperatingSystem, os.object); + pythonSettings.setup(x => x.analysis).returns(() => analysisSettings.object); config.setup(x => x.getSettings(TypeMoq.It.isAny())).returns(() => pythonSettings.object); serviceManager.addSingletonInstance(IConfigurationService, config.object); @@ -44,55 +52,20 @@ suite('Platform', () => { serviceManager.addSingletonInstance(IPythonExecutionFactory, execFactory.object); }); test('Windows platform check', async () => { - process.setup(x => x.platform).returns(() => 'win32'); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); const platform = new PlatformService(serviceContainer); - + process.setup(x => x.platform).returns(() => 'win'); expect(platform.isWindows).to.be.equal(true, 'Platform must be Windows'); - expect(platform.isMac).to.be.equal(false, 'Platform must not be Mac'); - expect(platform.isLinux).to.be.equal(false, 'Platform must not be Linux'); - }); - test('Mac platform check', async () => { - process.setup(x => x.platform).returns(() => 'darwin'); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - const platform = new PlatformService(serviceContainer); - - expect(platform.isMac).to.be.equal(true, 'Platform must be Mac'); - expect(platform.isWindows).to.be.equal(false, 'Platform must not be Windows'); - expect(platform.isLinux).to.be.equal(false, 'Platform must not be Linux'); + expect(platform.isMac).to.be.equal(true, 'Platform must not be Mac'); + expect(platform.isLinux).to.be.equal(true, 'Platform must not be Linux'); }); test('32-bit platform check', async () => { - os.setup(x => x.arch()).returns(() => ''); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); const platform = new PlatformService(serviceContainer); - + os.setup(x => x.arch()).returns(() => ''); expect(platform.is64bit).to.be.equal(false, 'Platform must not be x64'); }); test('64-bit platform check', async () => { - os.setup(x => x.arch()).returns(() => 'x64'); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); const platform = new PlatformService(serviceContainer); - + os.setup(x => x.arch()).returns(() => 'x64'); expect(platform.is64bit).to.be.equal(true, 'Platform must be x64'); }); - test('bin/scripts check (Windows)', async () => { - process.setup(x => x.platform).returns(() => 'win32'); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - const platform = new PlatformService(serviceContainer); - - expect(platform.virtualEnvBinName).to.be.equal('scripts', 'Venv bin must be scripts on Windows'); - }); - test('bin/scripts check (Mac/Linux)', async () => { - process.setup(x => x.platform).returns(() => 'darwin'); - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - const platform = new PlatformService(serviceContainer); - - expect(platform.virtualEnvBinName).to.be.equal('bin', 'Venv bin must be scripts on Mac'); - }); }); diff --git a/src/test/index.ts b/src/test/index.ts index eefb622b7c5d..b63fe1ba47b4 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -18,7 +18,7 @@ process.env.IS_MULTI_ROOT_TEST = IS_MULTI_ROOT_TEST.toString(); // If running on CI server and we're running the debugger tests, then ensure we only run debug tests. // We do this to ensure we only run debugger test, as debugger tests are very flaky on CI. // So the solution is to run them separately and first on CI. -const grep = IS_CI_SERVER && IS_CI_SERVER_TEST_DEBUGGER ? 'Debug' : 'Platform'; +const grep = IS_CI_SERVER && IS_CI_SERVER_TEST_DEBUGGER ? 'Debug' : undefined; const testFilesSuffix = process.env.TEST_FILES_SUFFIX; // You can directly control Mocha options by uncommenting the following lines. From 5caca65dcf27cb1c588d9db407aaffee166852ef Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:22:11 -0700 Subject: [PATCH 23/65] Revert "Test prep" This reverts commit 2c7243c310c2d460e77e816c3c193f10197e7a70. --- src/client/activation/languageServer.ts | 2 +- src/client/common/platform/operatingSystem.ts | 15 ---- src/client/common/platform/platformService.ts | 44 ++++++------ src/client/common/platform/serviceRegistry.ts | 6 +- src/client/common/platform/types.ts | 13 +--- src/client/common/process/currentProcess.ts | 3 - src/client/common/types.ts | 1 - .../common/platform/platform.unit.test.ts | 71 ------------------- .../envVarsProvider.multiroot.test.ts | 3 +- .../common/variables/envVarsService.test.ts | 12 +--- src/test/mocks/process.ts | 3 - 11 files changed, 26 insertions(+), 147 deletions(-) delete mode 100644 src/client/common/platform/operatingSystem.ts delete mode 100644 src/test/common/platform/platform.unit.test.ts diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index b3265c9aafb7..e9802bcc072c 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -127,7 +127,7 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { private async checkSupportedPlatform(): Promise { const platform = this.services.get(IPlatformService); - const message = await platform.isNetCoreCompatible(); + const message = await platform.isNetCoreCompatibleOS(); if (message && message.length > 0) { if (platform.isMac) { this.services.get(ILogger).logError(message); diff --git a/src/client/common/platform/operatingSystem.ts b/src/client/common/platform/operatingSystem.ts deleted file mode 100644 index bf63182761bb..000000000000 --- a/src/client/common/platform/operatingSystem.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -'use strict'; - -import { arch, release } from 'os'; -import { IOperatingSystem } from './types'; - -export class OperatingSystem implements IOperatingSystem { - public release(): string { - return release(); - } - public arch(): string { - return arch(); - } -} diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index ca7ea85188e2..42b089294e1b 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -3,12 +3,13 @@ 'use strict'; import { inject, injectable } from 'inversify'; +import { arch, release } from 'os'; import { Uri } from 'vscode'; import { IServiceContainer } from '../../ioc/types'; import { IProcessService, IProcessServiceFactory } from '../process/types'; -import { IConfigurationService, ICurrentProcess } from '../types'; +import { IConfigurationService } from '../types'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; -import { IOperatingSystem, IPlatformService } from './types'; +import { IPlatformService } from './types'; enum OSCheckResult { Compatible, @@ -17,10 +18,10 @@ enum OSCheckResult { } class MacOSVersion { - public isCompatibleOS(os: IOperatingSystem): Promise { + public isCompatibleOS(): Promise { // https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history // 10.12 == Darwin 16.0 - const parts = os.release().split('.'); + const parts = release().split('.'); const versionMajor = parts.length > 0 ? parseInt(parts[0], 10) : 0; return Promise.resolve(versionMajor >= 16 ? '' : 'Microsoft Python Language Server does not support MacOS older than 10.12.'); } @@ -86,7 +87,7 @@ class LinuxVersion { private async checkLinux(process: IProcessService, command: string, args: string[], osName: string, key: string, values: string[]): Promise { const result = await process.exec(command, args); - const words = result.stdout.split(/\s/); + const words = result.stdout.split(' \t\n'); if (words.indexOf(osName) <= 0) { return Promise.resolve(OSCheckResult.Unknown); } @@ -116,15 +117,12 @@ class LinuxVersion { // tslint:disable-next-line:max-classes-per-file @injectable() export class PlatformService implements IPlatformService { - private readonly _isWindows: boolean; - private readonly _isMac: boolean; - private readonly os: IOperatingSystem; + private _isWindows: boolean; + private _isMac: boolean; constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { - const process = serviceContainer.get(ICurrentProcess); this._isWindows = /^win/.test(process.platform); this._isMac = /^darwin/.test(process.platform); - this.os = this.serviceContainer.get(IOperatingSystem); } public get isWindows(): boolean { return this._isWindows; @@ -136,7 +134,7 @@ export class PlatformService implements IPlatformService { return !(this.isWindows || this.isMac); } public get is64bit(): boolean { - return this.os.arch() === 'x64'; + return arch() === 'x64'; } public get pathVariableName() { return this.isWindows ? WINDOWS_PATH_VARIABLE_NAME : NON_WINDOWS_PATH_VARIABLE_NAME; @@ -144,19 +142,17 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } - public isNetCoreCompatible(resource?: Uri): Promise { - if (this.serviceContainer) { - const config = this.serviceContainer.get(IConfigurationService); - const settings = config.getSettings(resource); - if (settings && settings.analysis && !settings.analysis.checkOSVersion) { - return Promise.resolve(''); - } - if (this.isMac) { - return new MacOSVersion().isCompatibleOS(this.os); - } - if (this.isLinux) { - return new LinuxVersion(this.serviceContainer).isCompatibleOS(); - } + public isNetCoreCompatibleOS(resource?: Uri): Promise { + const config = this.serviceContainer.get(IConfigurationService); + const settings = config.getSettings(resource); + if (settings && settings.analysis && !settings.analysis.checkOSVersion) { + return Promise.resolve(''); + } + if (this.isMac) { + return new MacOSVersion().isCompatibleOS(); + } + if (this.isLinux) { + return new LinuxVersion(this.serviceContainer).isCompatibleOS(); } return Promise.resolve(''); // Windows matches between .NET Core and VS Code. } diff --git a/src/client/common/platform/serviceRegistry.ts b/src/client/common/platform/serviceRegistry.ts index 6ab3116a2de5..dce3511f9f37 100644 --- a/src/client/common/platform/serviceRegistry.ts +++ b/src/client/common/platform/serviceRegistry.ts @@ -3,18 +3,14 @@ 'use strict'; import { IServiceManager } from '../../ioc/types'; -import { CurrentProcess } from '../process/currentProcess'; -import { ICurrentProcess } from '../types'; import { FileSystem } from './fileSystem'; -import { OperatingSystem } from './operatingSystem'; import { PlatformService } from './platformService'; import { RegistryImplementation } from './registry'; -import { IFileSystem, IOperatingSystem, IPlatformService, IRegistry } from './types'; +import { IFileSystem, IPlatformService, IRegistry } from './types'; export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(IPlatformService, PlatformService); serviceManager.addSingleton(IFileSystem, FileSystem); - serviceManager.addSingleton(IOperatingSystem, OperatingSystem); if (serviceManager.get(IPlatformService).isWindows) { serviceManager.addSingleton(IRegistry, RegistryImplementation); } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 395bc3e5f5a2..5c8d5cbab396 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -27,7 +27,7 @@ export interface IPlatformService { is64bit: boolean; pathVariableName: 'Path' | 'PATH'; virtualEnvBinName: 'bin' | 'scripts'; - isNetCoreCompatible(): Promise; + isNetCoreCompatibleOS(): Promise; } export type TemporaryFile = { filePath: string } & Disposable; @@ -54,14 +54,3 @@ export interface IFileSystem { search(globPattern: string): Promise; createTemporaryFile(extension: string): Promise; } - -export const IOperatingSystem = Symbol('IOperatingSystem'); -export interface IOperatingSystem { - release(): string; - arch(): string; -} - -export const ICurrentProcess = Symbol('ICurrentProcess'); -export interface ICurrentProcess { - readonly platform: string; -} diff --git a/src/client/common/process/currentProcess.ts b/src/client/common/process/currentProcess.ts index f9b30aed5ad3..fc2bb97bb01d 100644 --- a/src/client/common/process/currentProcess.ts +++ b/src/client/common/process/currentProcess.ts @@ -22,7 +22,4 @@ export class CurrentProcess implements ICurrentProcess { public get stdin(): NodeJS.ReadStream { return process.stdin; } - public get platform(): string { - return process.platform; - } } diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 8ffbd8ae2ff5..15e729490823 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -111,7 +111,6 @@ export interface ICurrentProcess { readonly argv: string[]; readonly stdout: NodeJS.WriteStream; readonly stdin: NodeJS.ReadStream; - readonly platform: string; on(event: string | symbol, listener: Function): this; } diff --git a/src/test/common/platform/platform.unit.test.ts b/src/test/common/platform/platform.unit.test.ts deleted file mode 100644 index 1be4b01756ca..000000000000 --- a/src/test/common/platform/platform.unit.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { expect, use } from 'chai'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as TypeMoq from 'typemoq'; -import { Container } from '../../../../node_modules/inversify'; -import { FileSystem } from '../../../client/common/platform/fileSystem'; -import { PlatformService } from '../../../client/common/platform/platformService'; -import { ICurrentProcess, IFileSystem, IOperatingSystem, IPlatformService } from '../../../client/common/platform/types'; -import { IPythonExecutionFactory, IPythonExecutionService } from '../../../client/common/process/types'; -import { IAnalysisSettings, IConfigurationService, IPythonSettings } from '../../../client/common/types'; -import { ServiceContainer } from '../../../client/ioc/container'; -import { ServiceManager } from '../../../client/ioc/serviceManager'; -// tslint:disable-next-line:no-require-imports no-var-requires -const assertArrays = require('chai-arrays'); -use(assertArrays); - -// tslint:disable-next-line:max-func-body-length -suite('Platform', () => { - let process: TypeMoq.IMock; - let os: TypeMoq.IMock; - let config: TypeMoq.IMock; - let pythonSettings: TypeMoq.IMock; - let analysisSettings: TypeMoq.IMock; - let execFactory: TypeMoq.IMock; - let exec: TypeMoq.IMock; - let serviceContainer: ServiceContainer; - - setup(() => { - const cont = new Container(); - const serviceManager = new ServiceManager(cont); - serviceContainer = new ServiceContainer(cont); - - process = TypeMoq.Mock.ofType(); - os = TypeMoq.Mock.ofType(); - config = TypeMoq.Mock.ofType(); - pythonSettings = TypeMoq.Mock.ofType(); - analysisSettings = TypeMoq.Mock.ofType(); - execFactory = TypeMoq.Mock.ofType(); - exec = TypeMoq.Mock.ofType(); - - serviceManager.addSingletonInstance(ICurrentProcess, process.object); - serviceManager.addSingletonInstance(IOperatingSystem, os.object); - - pythonSettings.setup(x => x.analysis).returns(() => analysisSettings.object); - config.setup(x => x.getSettings(TypeMoq.It.isAny())).returns(() => pythonSettings.object); - serviceManager.addSingletonInstance(IConfigurationService, config.object); - - execFactory.setup(x => x.create(TypeMoq.It.isAny())).returns(() => Promise.resolve(exec.object)); - serviceManager.addSingletonInstance(IPythonExecutionFactory, execFactory.object); - }); - test('Windows platform check', async () => { - const platform = new PlatformService(serviceContainer); - process.setup(x => x.platform).returns(() => 'win'); - expect(platform.isWindows).to.be.equal(true, 'Platform must be Windows'); - expect(platform.isMac).to.be.equal(true, 'Platform must not be Mac'); - expect(platform.isLinux).to.be.equal(true, 'Platform must not be Linux'); - }); - test('32-bit platform check', async () => { - const platform = new PlatformService(serviceContainer); - os.setup(x => x.arch()).returns(() => ''); - expect(platform.is64bit).to.be.equal(false, 'Platform must not be x64'); - }); - test('64-bit platform check', async () => { - const platform = new PlatformService(serviceContainer); - os.setup(x => x.arch()).returns(() => 'x64'); - expect(platform.is64bit).to.be.equal(true, 'Platform must be x64'); - }); -}); diff --git a/src/test/common/variables/envVarsProvider.multiroot.test.ts b/src/test/common/variables/envVarsProvider.multiroot.test.ts index 2114f1d66295..da27c8c99cb7 100644 --- a/src/test/common/variables/envVarsProvider.multiroot.test.ts +++ b/src/test/common/variables/envVarsProvider.multiroot.test.ts @@ -9,7 +9,8 @@ import * as path from 'path'; import { ConfigurationTarget, Disposable, Uri, workspace } from 'vscode'; import { createDeferred } from '../../../client/common/helpers'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from '../../../client/common/platform/constants'; -import { IDisposableRegistry, IPathUtils, IsWindows } from '../../../client/common/types'; +import { IDisposableRegistry, IPathUtils } from '../../../client/common/types'; +import { IsWindows } from '../../../client/common/types'; import { IS_WINDOWS } from '../../../client/common/utils'; import { EnvironmentVariablesService } from '../../../client/common/variables/environment'; import { EnvironmentVariablesProvider } from '../../../client/common/variables/environmentVariablesProvider'; diff --git a/src/test/common/variables/envVarsService.test.ts b/src/test/common/variables/envVarsService.test.ts index c6c832a6fe61..9f77ab7ebcd2 100644 --- a/src/test/common/variables/envVarsService.test.ts +++ b/src/test/common/variables/envVarsService.test.ts @@ -4,16 +4,11 @@ import { expect, use } from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; import * as path from 'path'; -import { Container } from '../../../../node_modules/inversify'; -import { OperatingSystem } from '../../../client/common/platform/operatingSystem'; import { PathUtils } from '../../../client/common/platform/pathUtils'; import { PlatformService } from '../../../client/common/platform/platformService'; -import { IOperatingSystem } from '../../../client/common/platform/types'; import { IPathUtils } from '../../../client/common/types'; import { EnvironmentVariablesService } from '../../../client/common/variables/environment'; import { IEnvironmentVariablesService } from '../../../client/common/variables/types'; -import { ServiceContainer } from '../../../client/ioc/container'; -import { ServiceManager } from '../../../client/ioc/serviceManager'; use(chaiAsPromised); @@ -24,12 +19,7 @@ suite('Environment Variables Service', () => { let pathUtils: IPathUtils; let variablesService: IEnvironmentVariablesService; setup(() => { - const cont = new Container(); - const serviceManager = new ServiceManager(cont); - const serviceContainer = new ServiceContainer(cont); - serviceManager.addSingleton(IOperatingSystem, OperatingSystem); - - pathUtils = new PathUtils(new PlatformService(serviceContainer).isWindows); + pathUtils = new PathUtils(new PlatformService().isWindows); variablesService = new EnvironmentVariablesService(pathUtils); }); diff --git a/src/test/mocks/process.ts b/src/test/mocks/process.ts index 9dc24c1ae0b2..f3bb89449e7d 100644 --- a/src/test/mocks/process.ts +++ b/src/test/mocks/process.ts @@ -21,7 +21,4 @@ export class MockProcess implements ICurrentProcess { public get stdin(): NodeJS.ReadStream { return TypeMoq.Mock.ofType().object; } - public get platform(): string { - return 'win'; - } } From 983cbebeacf058b4cb2204c6cc64d3792f5ecb9a Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:22:17 -0700 Subject: [PATCH 24/65] Revert "Simplify" This reverts commit fef0e9263035f57acf5212cf2799ff6d4579cb04. --- src/client/common/platform/platformService.ts | 20 +++++++++++++++---- src/client/common/platform/types.ts | 6 ++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index 42b089294e1b..9f6e802404a9 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -9,7 +9,21 @@ import { IServiceContainer } from '../../ioc/types'; import { IProcessService, IProcessServiceFactory } from '../process/types'; import { IConfigurationService } from '../types'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; -import { IPlatformService } from './types'; +import { IPlatformService, IVersion } from './types'; + +class OSVersion implements IVersion { + public get versionString(): string { + return release(); + } + public get versionMajor(): number { + const parts = this.versionString.split('.'); + return parts.length > 0 ? parseInt(parts[0], 10) : 0; + } + public get versionMinor(): number { + const parts = this.versionString.split('.'); + return parts.length > 1 ? parseInt(parts[1], 10) : 0; + } +} enum OSCheckResult { Compatible, @@ -21,9 +35,7 @@ class MacOSVersion { public isCompatibleOS(): Promise { // https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history // 10.12 == Darwin 16.0 - const parts = release().split('.'); - const versionMajor = parts.length > 0 ? parseInt(parts[0], 10) : 0; - return Promise.resolve(versionMajor >= 16 ? '' : 'Microsoft Python Language Server does not support MacOS older than 10.12.'); + return Promise.resolve(new OSVersion().versionMajor >= 16 ? '' : 'Microsoft Python Language Server does not support MacOS older than 10.12.'); } } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 5c8d5cbab396..2d5812c99920 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -54,3 +54,9 @@ export interface IFileSystem { search(globPattern: string): Promise; createTemporaryFile(extension: string): Promise; } + +export interface IVersion { + readonly versionString: string; + readonly versionMajor: number; + readonly versionMinor: number; +} From 0f116cccc50511205aec130cd35874269f66b1c4 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:22:23 -0700 Subject: [PATCH 25/65] Revert "Linux check" This reverts commit 925f6635adf79cf4ec41fba6a0700f93d97668a3. --- src/client/common/platform/platformService.ts | 36 ++++++------------- src/client/common/types.ts | 2 -- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index 9f6e802404a9..73e50eb599c1 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -4,10 +4,8 @@ import { inject, injectable } from 'inversify'; import { arch, release } from 'os'; -import { Uri } from 'vscode'; import { IServiceContainer } from '../../ioc/types'; import { IProcessService, IProcessServiceFactory } from '../process/types'; -import { IConfigurationService } from '../types'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; import { IPlatformService, IVersion } from './types'; @@ -100,29 +98,20 @@ class LinuxVersion { private async checkLinux(process: IProcessService, command: string, args: string[], osName: string, key: string, values: string[]): Promise { const result = await process.exec(command, args); const words = result.stdout.split(' \t\n'); - if (words.indexOf(osName) <= 0) { - return Promise.resolve(OSCheckResult.Unknown); - } - - const index = words.indexOf(key); // looking for 'release' variety - if (index >= 0 && index < words.length - 1) { - const version = words[index + 1]; - const parts = version.split('.'); - const major = parts[0]; - const minor = parts.length > 1 ? parts[1] : undefined; - for (const v of values) { - if (v.indexOf('.') > 0 && minor) { - // We need to check both major and minor - const p = v.split('.'); - if (major === p[0] && minor && parseInt(minor, 10) >= parseInt(p[1], 10)) { + 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); } - } else if (major === v) { - return Promise.resolve(OSCheckResult.Compatible); } } + return Promise.resolve(OSCheckResult.Incompatible); } - return Promise.resolve(OSCheckResult.Incompatible); + return Promise.resolve(OSCheckResult.Unknown); } } @@ -154,12 +143,7 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } - public isNetCoreCompatibleOS(resource?: Uri): Promise { - const config = this.serviceContainer.get(IConfigurationService); - const settings = config.getSettings(resource); - if (settings && settings.analysis && !settings.analysis.checkOSVersion) { - return Promise.resolve(''); - } + public isNetCoreCompatibleOS(): Promise { if (this.isMac) { return new MacOSVersion().isCompatibleOS(); } diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 15e729490823..400e21f466b6 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -244,8 +244,6 @@ export interface IAnalysisSettings { readonly information: string[]; readonly disabled: string[]; readonly traceLogging: boolean; - readonly diagnosticPublishDelay: number; - readonly checkOSVersion: boolean; } export const IConfigurationService = Symbol('IConfigurationService'); From cfc9b2d13eff1ddba9e9746837dd2f79b7399a30 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:22:32 -0700 Subject: [PATCH 26/65] Revert "Linux version check" This reverts commit 0d3c0669191e65b09d0d3ec06a5bf9d42f220874. --- package.json | 6 - src/client/activation/languageServer.ts | 11 +- src/client/common/platform/platformService.ts | 112 +++--------------- src/client/common/platform/types.ts | 2 +- 4 files changed, 22 insertions(+), 109 deletions(-) diff --git a/package.json b/package.json index 2118556f9dab..3f1cff09dd1d 100644 --- a/package.json +++ b/package.json @@ -817,12 +817,6 @@ "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, diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index e9802bcc072c..a540584880bd 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -125,14 +125,15 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { (this.configuration.getSettings() as PythonSettings).removeListener('change', this.onSettingsChanged.bind(this)); } - private async checkSupportedPlatform(): Promise { + private checkSupportedPlatform(): boolean { const platform = this.services.get(IPlatformService); - const message = await platform.isNetCoreCompatibleOS(); - if (message && message.length > 0) { + if (!platform.isNetCoreCompatibleOS) { if (platform.isMac) { - this.services.get(ILogger).logError(message); - this.appShell.showErrorMessage(message); + this.services.get(ILogger).logError('Unsupported MacOS'); + this.appShell.showErrorMessage('Microsoft Python Language Server does not support MacOS older than 10.12.'); } + // tslint:disable-next-line:no-suspicious-comment + // TODO: Linux messages return false; } return true; diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index 73e50eb599c1..17e31ed63fba 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -2,10 +2,8 @@ // Licensed under the MIT License. 'use strict'; -import { inject, injectable } from 'inversify'; +import { 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'; @@ -23,105 +21,20 @@ class OSVersion implements IVersion { } } -enum OSCheckResult { - Compatible, - Incompatible, - Unknown -} - class MacOSVersion { - public isCompatibleOS(): Promise { + public get isCompatibleOS(): boolean { // https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history // 10.12 == Darwin 16.0 - 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 { - const factory = this.serviceContainer.get(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 { - 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); + return new OSVersion().versionMajor >= 16; } } -// tslint:disable-next-line:max-classes-per-file @injectable() export class PlatformService implements IPlatformService { private _isWindows: boolean; private _isMac: boolean; - constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { + constructor() { this._isWindows = /^win/.test(process.platform); this._isMac = /^darwin/.test(process.platform); } @@ -143,13 +56,18 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } - public isNetCoreCompatibleOS(): Promise { + public get isNetCoreCompatibleOS(): boolean { if (this.isMac) { - return new MacOSVersion().isCompatibleOS(); + return new MacOSVersion().isCompatibleOS; } - if (this.isLinux) { - return new LinuxVersion(this.serviceContainer).isCompatibleOS(); - } - return Promise.resolve(''); // Windows matches between .NET Core and VS Code. + // 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. } } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 2d5812c99920..4fd22b4d6b72 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -27,7 +27,7 @@ export interface IPlatformService { is64bit: boolean; pathVariableName: 'Path' | 'PATH'; virtualEnvBinName: 'bin' | 'scripts'; - isNetCoreCompatibleOS(): Promise; + isNetCoreCompatibleOS: boolean; } export type TemporaryFile = { filePath: string } & Disposable; From 4fe10527812db60729bdca722c4601b397f8a019 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:22:40 -0700 Subject: [PATCH 27/65] Revert "Correct MacOS check and lay infra for Linux checks" This reverts commit 4e12b3c0f540e988f708928fef9f499c8562dd39. --- src/client/activation/languageServer.ts | 10 ++-- src/client/common/platform/platformService.ts | 47 +++++-------------- src/client/common/platform/types.ts | 10 ++-- 3 files changed, 17 insertions(+), 50 deletions(-) diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index a540584880bd..1ba4711112cc 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -127,13 +127,9 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { private checkSupportedPlatform(): boolean { const platform = this.services.get(IPlatformService); - if (!platform.isNetCoreCompatibleOS) { - if (platform.isMac) { - this.services.get(ILogger).logError('Unsupported MacOS'); - this.appShell.showErrorMessage('Microsoft Python Language Server does not support MacOS older than 10.12.'); - } - // tslint:disable-next-line:no-suspicious-comment - // TODO: Linux messages + if (platform.isMac && platform.versionMajor === 10 && platform.versionMinor < 12) { + this.services.get(ILogger).logError('Unsupported MacOS'); + this.appShell.showErrorMessage('Microsoft Python Language Server does not support MacOS older than 10.12.'); return false; } return true; diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index 17e31ed63fba..df6b6142f5b5 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -5,29 +5,7 @@ import { injectable } from 'inversify'; import { arch, release } from 'os'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; -import { IPlatformService, IVersion } from './types'; - -class OSVersion implements IVersion { - public get versionString(): string { - return release(); - } - public get versionMajor(): number { - const parts = this.versionString.split('.'); - return parts.length > 0 ? parseInt(parts[0], 10) : 0; - } - public get versionMinor(): number { - const parts = this.versionString.split('.'); - return parts.length > 1 ? parseInt(parts[1], 10) : 0; - } -} - -class MacOSVersion { - public get isCompatibleOS(): boolean { - // https://en.wikipedia.org/wiki/Darwin_%28operating_system%29#Release_history - // 10.12 == Darwin 16.0 - return new OSVersion().versionMajor >= 16; - } -} +import { IPlatformService } from './types'; @injectable() export class PlatformService implements IPlatformService { @@ -56,18 +34,15 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } - public get isNetCoreCompatibleOS(): boolean { - if (this.isMac) { - 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. + public get version(): string { + return release(); + } + public get versionMajor(): number { + const parts = this.version.split('.'); + return parts.length > 0 ? parseInt(parts[0], 10) : 0; + } + public get versionMinor(): number { + const parts = this.version.split('.'); + return parts.length > 1 ? parseInt(parts[1], 10) : 0; } } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 4fd22b4d6b72..48b0058558f1 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -27,7 +27,9 @@ export interface IPlatformService { is64bit: boolean; pathVariableName: 'Path' | 'PATH'; virtualEnvBinName: 'bin' | 'scripts'; - isNetCoreCompatibleOS: boolean; + version: string; + versionMajor: number; + versionMinor: number; } export type TemporaryFile = { filePath: string } & Disposable; @@ -54,9 +56,3 @@ export interface IFileSystem { search(globPattern: string): Promise; createTemporaryFile(extension: string): Promise; } - -export interface IVersion { - readonly versionString: string; - readonly versionMajor: number; - readonly versionMinor: number; -} From c8dedc3207ada29706478211464cf5b685b9dfe5 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:23:18 -0700 Subject: [PATCH 28/65] Revert "News" This reverts commit 462ff7c4b1f05e1abe180b27104b8a3f0bfd2e67. --- news/1 Enhancements/2245.md | 1 - news/1 Enhancements/2270.md | 1 - 2 files changed, 2 deletions(-) delete mode 100644 news/1 Enhancements/2245.md delete mode 100644 news/1 Enhancements/2270.md diff --git a/news/1 Enhancements/2245.md b/news/1 Enhancements/2245.md deleted file mode 100644 index f4e948db7211..000000000000 --- a/news/1 Enhancements/2245.md +++ /dev/null @@ -1 +0,0 @@ -Python extension detects MacOS older than 10.12 and prevents language server from starting since .NET Core 2.x is not supported on older Mac platforms. \ No newline at end of file diff --git a/news/1 Enhancements/2270.md b/news/1 Enhancements/2270.md deleted file mode 100644 index 0d3cca04bee0..000000000000 --- a/news/1 Enhancements/2270.md +++ /dev/null @@ -1 +0,0 @@ -python.analysis.diagnosticPublishDelay allows you to control when language server publishes diagnostics. Default is 1 second after the user activity, such a typing, ceases. If diagnostic is clear (i.e. errors got fixed), the publishing is immediate. \ No newline at end of file From 5e407752b4b6afe2d0b718f29fe6feae12510933 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:23:24 -0700 Subject: [PATCH 29/65] Revert "Add MacOS version check" This reverts commit 70b13f75b01c5eb72bd35611f411b801994f5e63. --- src/client/activation/languageServer.ts | 31 ++++--------------- src/client/common/platform/platformService.ts | 13 +------- src/client/common/platform/types.ts | 3 -- 3 files changed, 7 insertions(+), 40 deletions(-) diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index 1ba4711112cc..0842d07e0ec0 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -3,24 +3,18 @@ import { inject, injectable } from 'inversify'; import * as path from 'path'; -import { - CancellationToken, CompletionContext, OutputChannel, Position, - TextDocument, Uri -} from 'vscode'; -import { - Disposable, LanguageClient, LanguageClientOptions, - ProvideCompletionItemsSignature, ServerOptions -} from 'vscode-languageclient'; +import { CancellationToken, CompletionContext, OutputChannel, Position, + TextDocument, Uri } from 'vscode'; +import { Disposable, LanguageClient, LanguageClientOptions, + ProvideCompletionItemsSignature, ServerOptions } from 'vscode-languageclient'; import { IApplicationShell, ICommandManager, IWorkspaceService } from '../common/application/types'; import { PythonSettings } from '../common/configSettings'; import { isTestExecution, STANDARD_OUTPUT_CHANNEL } from '../common/constants'; import { createDeferred, Deferred } from '../common/helpers'; import { IFileSystem, IPlatformService } from '../common/platform/types'; import { StopWatch } from '../common/stopWatch'; -import { - BANNER_NAME_LS_SURVEY, IConfigurationService, IExtensionContext, ILogger, - IOutputChannel, IPythonExtensionBanner, IPythonSettings -} from '../common/types'; +import { BANNER_NAME_LS_SURVEY, IConfigurationService, IExtensionContext, ILogger, + IOutputChannel, IPythonExtensionBanner, IPythonSettings } from '../common/types'; import { IServiceContainer } from '../ioc/types'; import { PYTHON_LANGUAGE_SERVER_DOWNLOADED, @@ -97,10 +91,6 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { } public async activate(): Promise { - if (!this.checkSupportedPlatform()) { - return false; - } - this.sw.reset(); const clientOptions = await this.getAnalysisOptions(); if (!clientOptions) { @@ -125,15 +115,6 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { (this.configuration.getSettings() as PythonSettings).removeListener('change', this.onSettingsChanged.bind(this)); } - private checkSupportedPlatform(): boolean { - const platform = this.services.get(IPlatformService); - if (platform.isMac && platform.versionMajor === 10 && platform.versionMinor < 12) { - this.services.get(ILogger).logError('Unsupported MacOS'); - this.appShell.showErrorMessage('Microsoft Python Language Server does not support MacOS older than 10.12.'); - return false; - } - return true; - } private async startLanguageServer(clientOptions: LanguageClientOptions): Promise { // Determine if we are running MSIL/Universal via dotnet or self-contained app. diff --git a/src/client/common/platform/platformService.ts b/src/client/common/platform/platformService.ts index df6b6142f5b5..f60f9eaf3ba5 100644 --- a/src/client/common/platform/platformService.ts +++ b/src/client/common/platform/platformService.ts @@ -3,7 +3,7 @@ 'use strict'; import { injectable } from 'inversify'; -import { arch, release } from 'os'; +import { arch } from 'os'; import { NON_WINDOWS_PATH_VARIABLE_NAME, WINDOWS_PATH_VARIABLE_NAME } from './constants'; import { IPlatformService } from './types'; @@ -34,15 +34,4 @@ export class PlatformService implements IPlatformService { public get virtualEnvBinName() { return this.isWindows ? 'scripts' : 'bin'; } - public get version(): string { - return release(); - } - public get versionMajor(): number { - const parts = this.version.split('.'); - return parts.length > 0 ? parseInt(parts[0], 10) : 0; - } - public get versionMinor(): number { - const parts = this.version.split('.'); - return parts.length > 1 ? parseInt(parts[1], 10) : 0; - } } diff --git a/src/client/common/platform/types.ts b/src/client/common/platform/types.ts index 48b0058558f1..ec08fd7d284c 100644 --- a/src/client/common/platform/types.ts +++ b/src/client/common/platform/types.ts @@ -27,9 +27,6 @@ export interface IPlatformService { is64bit: boolean; pathVariableName: 'Path' | 'PATH'; virtualEnvBinName: 'bin' | 'scripts'; - version: string; - versionMajor: number; - versionMinor: number; } export type TemporaryFile = { filePath: string } & Disposable; From e63479b39a96f6fd9bb84e8e125ac2329b772515 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:26:06 -0700 Subject: [PATCH 30/65] News --- news/1 Enhancements/2270.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/1 Enhancements/2270.md diff --git a/news/1 Enhancements/2270.md b/news/1 Enhancements/2270.md new file mode 100644 index 000000000000..0d3cca04bee0 --- /dev/null +++ b/news/1 Enhancements/2270.md @@ -0,0 +1 @@ +python.analysis.diagnosticPublishDelay allows you to control when language server publishes diagnostics. Default is 1 second after the user activity, such a typing, ceases. If diagnostic is clear (i.e. errors got fixed), the publishing is immediate. \ No newline at end of file From e44afad233b9b0f64b3defd5cc88dcc8d79ff648 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:27:17 -0700 Subject: [PATCH 31/65] Format --- src/client/activation/languageServer.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index 0842d07e0ec0..0122e3ceecf9 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -3,18 +3,24 @@ import { inject, injectable } from 'inversify'; import * as path from 'path'; -import { CancellationToken, CompletionContext, OutputChannel, Position, - TextDocument, Uri } from 'vscode'; -import { Disposable, LanguageClient, LanguageClientOptions, - ProvideCompletionItemsSignature, ServerOptions } from 'vscode-languageclient'; +import { + CancellationToken, CompletionContext, OutputChannel, Position, + TextDocument, Uri +} from 'vscode'; +import { + Disposable, LanguageClient, LanguageClientOptions, + ProvideCompletionItemsSignature, ServerOptions +} from 'vscode-languageclient'; import { IApplicationShell, ICommandManager, IWorkspaceService } from '../common/application/types'; import { PythonSettings } from '../common/configSettings'; import { isTestExecution, STANDARD_OUTPUT_CHANNEL } from '../common/constants'; import { createDeferred, Deferred } from '../common/helpers'; import { IFileSystem, IPlatformService } from '../common/platform/types'; import { StopWatch } from '../common/stopWatch'; -import { BANNER_NAME_LS_SURVEY, IConfigurationService, IExtensionContext, ILogger, - IOutputChannel, IPythonExtensionBanner, IPythonSettings } from '../common/types'; +import { + BANNER_NAME_LS_SURVEY, IConfigurationService, IExtensionContext, ILogger, + IOutputChannel, IPythonExtensionBanner, IPythonSettings +} from '../common/types'; import { IServiceContainer } from '../ioc/types'; import { PYTHON_LANGUAGE_SERVER_DOWNLOADED, From d7cd632515468e7243e978188529c1fc80b58471 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Wed, 8 Aug 2018 17:28:40 -0700 Subject: [PATCH 32/65] Undo --- src/client/activation/downloader.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/client/activation/downloader.ts b/src/client/activation/downloader.ts index af300b4c7e07..0bb6b9dbcf20 100644 --- a/src/client/activation/downloader.ts +++ b/src/client/activation/downloader.ts @@ -54,7 +54,6 @@ export class LanguageServerDownloader { let localTempFilePath = ''; try { localTempFilePath = await this.downloadFile(downloadUri, 'Downloading Microsoft Python Language Server... '); - // await this.verifyDownload(localTempFilePath, platformString); await this.unpackArchive(context.extensionPath, localTempFilePath); } catch (err) { this.output.appendLine('failed.'); From d70322c0a45684d7b81bbd237f14bfcc31f8cceb Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 9 Aug 2018 17:10:45 -0700 Subject: [PATCH 33/65] Pass async startup option to LS --- src/client/activation/languageServer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index 0122e3ceecf9..ea16f3e1481c 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -262,7 +262,8 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { excludeFiles: this.excludedFiles, testEnvironment: isTestExecution(), analysisUpdates: true, - traceLogging + traceLogging, + asyncStartup: true }, middleware: { provideCompletionItem: (document: TextDocument, position: Position, context: CompletionContext, token: CancellationToken, next: ProvideCompletionItemsSignature) => { From ed8ac1b8982111433510618159bebdcc42253220 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Fri, 10 Aug 2018 09:34:03 -0700 Subject: [PATCH 34/65] News for LS fixes --- news/2 Fixes/2179.md | 1 + news/2 Fixes/2262.md | 1 + 2 files changed, 2 insertions(+) create mode 100644 news/2 Fixes/2179.md create mode 100644 news/2 Fixes/2262.md diff --git a/news/2 Fixes/2179.md b/news/2 Fixes/2179.md new file mode 100644 index 000000000000..bc845e8eaa2c --- /dev/null +++ b/news/2 Fixes/2179.md @@ -0,0 +1 @@ +Fixed issue in the language server when documentation for a function always produced "Documentation is still being calculated, please try again soon". \ No newline at end of file diff --git a/news/2 Fixes/2262.md b/news/2 Fixes/2262.md new file mode 100644 index 000000000000..44d41a398f43 --- /dev/null +++ b/news/2 Fixes/2262.md @@ -0,0 +1 @@ +Fixed issue in the language server when typing dot under certain conditions produced null reference exception. \ No newline at end of file From c000856ed6a2bd068432a74a08e6eac404044cf6 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Fri, 10 Aug 2018 09:43:36 -0700 Subject: [PATCH 35/65] News for LS fixes --- news/2 Fixes/2050.md | 1 + news/2 Fixes/2334.md | 1 + 2 files changed, 2 insertions(+) create mode 100644 news/2 Fixes/2050.md create mode 100644 news/2 Fixes/2334.md diff --git a/news/2 Fixes/2050.md b/news/2 Fixes/2050.md new file mode 100644 index 000000000000..7fee4a23ef1b --- /dev/null +++ b/news/2 Fixes/2050.md @@ -0,0 +1 @@ +Language server now populates document outline with all symbols instead of just top-level ones. \ No newline at end of file diff --git a/news/2 Fixes/2334.md b/news/2 Fixes/2334.md new file mode 100644 index 000000000000..1d511260ba1c --- /dev/null +++ b/news/2 Fixes/2334.md @@ -0,0 +1 @@ +Fixed issue in the language server when document outline was not populated with symbols. \ No newline at end of file From 3bd21b1b7ee92918ae151d0e057cc0729bca89a6 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Fri, 10 Aug 2018 12:35:54 -0700 Subject: [PATCH 36/65] Remove issue that is not fixed --- news/2 Fixes/2334.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 news/2 Fixes/2334.md diff --git a/news/2 Fixes/2334.md b/news/2 Fixes/2334.md deleted file mode 100644 index 1d511260ba1c..000000000000 --- a/news/2 Fixes/2334.md +++ /dev/null @@ -1 +0,0 @@ -Fixed issue in the language server when document outline was not populated with symbols. \ No newline at end of file From a399fc40d37931856748a4e3d2304d13c139c74d Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Fri, 10 Aug 2018 12:38:54 -0700 Subject: [PATCH 37/65] Add news --- news/2 Fixes/2017.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/2 Fixes/2017.md diff --git a/news/2 Fixes/2017.md b/news/2 Fixes/2017.md new file mode 100644 index 000000000000..a0e859a9b920 --- /dev/null +++ b/news/2 Fixes/2017.md @@ -0,0 +1 @@ +Fix null reference exception in the language server causing server initialization to fail. The exception happened when search paths contained a folder that did not exist. \ No newline at end of file From 6870109e40e2aed3b2c2ea216e1cb113c8bda53b Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Fri, 10 Aug 2018 15:10:16 -0700 Subject: [PATCH 38/65] News --- news/2 Fixes/2207.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/2 Fixes/2207.md diff --git a/news/2 Fixes/2207.md b/news/2 Fixes/2207.md new file mode 100644 index 000000000000..55ef7b0b43b9 --- /dev/null +++ b/news/2 Fixes/2207.md @@ -0,0 +1 @@ +Fixed language server issue when it could enter infinite loop reloading modules. \ No newline at end of file From adcd0ab7f5a021d6d339a72b68295978ccd6ecca Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Fri, 10 Aug 2018 15:12:32 -0700 Subject: [PATCH 39/65] News --- news/1 Enhancements/1865.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/1 Enhancements/1865.md diff --git a/news/1 Enhancements/1865.md b/news/1 Enhancements/1865.md new file mode 100644 index 000000000000..f4b440f199f3 --- /dev/null +++ b/news/1 Enhancements/1865.md @@ -0,0 +1 @@ +Improved language server startup time by 40%. \ No newline at end of file From 0756aefc93bea0663ce1e56b3db0b766b429ced9 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 13 Aug 2018 14:01:17 -0700 Subject: [PATCH 40/65] News --- news/2 Fixes/2240.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/2 Fixes/2240.md diff --git a/news/2 Fixes/2240.md b/news/2 Fixes/2240.md new file mode 100644 index 000000000000..54b32b81f831 --- /dev/null +++ b/news/2 Fixes/2240.md @@ -0,0 +1 @@ +Language server now correctly handles 'with' statement when '_enter_' is declared in a base class. \ No newline at end of file From 9e4024849ed7108d59dd970041554b1964587322 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 13 Aug 2018 17:18:44 -0700 Subject: [PATCH 41/65] News --- news/2 Fixes/2345.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/2 Fixes/2345.md diff --git a/news/2 Fixes/2345.md b/news/2 Fixes/2345.md new file mode 100644 index 000000000000..ff879023f530 --- /dev/null +++ b/news/2 Fixes/2345.md @@ -0,0 +1 @@ +Language server now correctly merges data from typeshed and the Python library. \ No newline at end of file From 40bac62eb8e5866451e4bfcaf3c2bd3ccf5a8317 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 16 Aug 2018 09:38:44 -0700 Subject: [PATCH 42/65] Drop typeshed submodule --- .gitmodules | 4 ---- news/2 Fixes/2224.md | 1 + src/client/activation/languageServer.ts | 2 +- typeshed | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 .gitmodules create mode 100644 news/2 Fixes/2224.md delete mode 160000 typeshed diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index a57bae098756..000000000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "typeshed"] - path = typeshed - url = https://github.com/python/typeshed.git - branch = master \ No newline at end of file diff --git a/news/2 Fixes/2224.md b/news/2 Fixes/2224.md new file mode 100644 index 000000000000..74d47870369b --- /dev/null +++ b/news/2 Fixes/2224.md @@ -0,0 +1 @@ +Improve reliability of document outline population with language server. \ No newline at end of file diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index ea16f3e1481c..f32e1cf0d3cf 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -308,7 +308,7 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { private getTypeshedPaths(settings: IPythonSettings): string[] { return settings.analysis.typeshedPaths && settings.analysis.typeshedPaths.length > 0 ? settings.analysis.typeshedPaths - : [path.join(this.context.extensionPath, 'typeshed')]; + : [path.join(this.context.extensionPath, 'languageServer', 'Typeshed')]; } private async onSettingsChanged(): Promise { diff --git a/typeshed b/typeshed deleted file mode 160000 index 95eff73ab209..000000000000 --- a/typeshed +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 95eff73ab2092f2c3158198d404a921447172418 From e0c4b8751a02847a2dc61cb1e5f2abc118a3837a Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 16 Aug 2018 12:00:30 -0700 Subject: [PATCH 43/65] Add settings to control LS output --- package.json | 17 +++++++++++++++++ src/client/common/types.ts | 2 ++ 2 files changed, 19 insertions(+) diff --git a/package.json b/package.json index 376df3f3ab72..07c00865ad37 100644 --- a/package.json +++ b/package.json @@ -874,6 +874,23 @@ "description": "List of suppressed diagnostic messages.", "scope": "resource" }, + "python.analysis.logLevel": { + "type": "string", + "enum": [ + "Error", + "Warning", + "Information" + ], + "default": "error", + "description": "Defines type of log messages language server writes into the output window.", + "scope": "resource" + }, + "python.analysis.traceLogging": { + "type": "boolean", + "default": false, + "description": "Enables full diagnostic logging in the language server.", + "scope": "resource" + }, "python.linting.enabled": { "type": "boolean", "default": true, diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 400e21f466b6..66b6aa927834 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -236,6 +236,7 @@ export interface ITerminalSettings { readonly launchArgs: string[]; readonly activateEnvironment: boolean; } + export interface IAnalysisSettings { readonly openFilesOnly: boolean; readonly typeshedPaths: string[]; @@ -244,6 +245,7 @@ export interface IAnalysisSettings { readonly information: string[]; readonly disabled: string[]; readonly traceLogging: boolean; + readonly logLevel: LogLevel; } export const IConfigurationService = Symbol('IConfigurationService'); From 1d1d7bfaef0cf03abee54ae1aea8fccae80f8443 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 16 Aug 2018 12:04:00 -0700 Subject: [PATCH 44/65] News --- news/2 Fixes/2405.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/2 Fixes/2405.md diff --git a/news/2 Fixes/2405.md b/news/2 Fixes/2405.md new file mode 100644 index 000000000000..e796a51dabe7 --- /dev/null +++ b/news/2 Fixes/2405.md @@ -0,0 +1 @@ +Added setting to control language server log output. Default is now 'error' so there should be much less noise in the output. \ No newline at end of file From 8e11bea53f3fa9771ab2c4e56ff5c0bc5e859fb3 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Fri, 17 Aug 2018 10:25:12 -0700 Subject: [PATCH 45/65] Fix case --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 07c00865ad37..18675960f6ee 100644 --- a/package.json +++ b/package.json @@ -881,7 +881,7 @@ "Warning", "Information" ], - "default": "error", + "default": "Error", "description": "Defines type of log messages language server writes into the output window.", "scope": "resource" }, From 652ab22680d850bf97919630b057a42337aa9a7a Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 20 Aug 2018 10:28:51 -0700 Subject: [PATCH 46/65] Switch to 1.26 and LSP 4.4 for outline --- package.json | 21 +++++++++++---------- src/client/activation/languageServer.ts | 4 +--- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 07c00865ad37..7b2355ac495c 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "theme": "dark" }, "engines": { - "vscode": "^1.25.0" + "vscode": "^1.26.0" }, "recommendations": [ "donjayamanne.jupyter" @@ -879,16 +879,17 @@ "enum": [ "Error", "Warning", - "Information" + "Information", + "Trace" ], "default": "error", "description": "Defines type of log messages language server writes into the output window.", "scope": "resource" }, - "python.analysis.traceLogging": { - "type": "boolean", - "default": false, - "description": "Enables full diagnostic logging in the language server.", + "python.analysis.symbolsHierarchyDepthLimit": { + "type": "integer", + "default": 10, + "description": "Limits depth of the symbol tree in the document outline.", "scope": "resource" }, "python.linting.enabled": { @@ -1549,9 +1550,9 @@ "vscode-debugadapter": "1.28.0", "vscode-debugprotocol": "1.28.0", "vscode-extension-telemetry": "0.0.15", - "vscode-languageclient": "4.3.0", - "vscode-languageserver": "4.3.0", - "vscode-languageserver-protocol": "3.9.0", + "vscode-languageclient": "4.4.0", + "vscode-languageserver": "4.4.0", + "vscode-languageserver-protocol": "3.10.3", "winreg": "1.2.4", "xml2js": "0.4.19" }, @@ -1622,7 +1623,7 @@ "typescript": "^2.9.1", "typescript-formatter": "^7.1.0", "uuid": "^3.2.1", - "vscode": "^1.1.5", + "vscode": "^1.1.21", "vscode-debugadapter-testsupport": "^1.27.0" }, "__metadata": { diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index f32e1cf0d3cf..6dc512b0dcbe 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -236,8 +236,6 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { this.excludedFiles = this.getExcludedFiles(); this.typeshedPaths = this.getTypeshedPaths(settings); - const traceLogging = (settings.analysis && settings.analysis.traceLogging) ? settings.analysis.traceLogging : false; - // Options to control the language client return { // Register the server for Python documents @@ -262,7 +260,7 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { excludeFiles: this.excludedFiles, testEnvironment: isTestExecution(), analysisUpdates: true, - traceLogging, + traceLogging: true, // Max level, let LS decide through settings actual level of logging. asyncStartup: true }, middleware: { From 83c356d76d932f978cd9ee57784abe7c3633076e Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 20 Aug 2018 10:32:25 -0700 Subject: [PATCH 47/65] News --- news/1 Enhancements/2384.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 news/1 Enhancements/2384.md diff --git a/news/1 Enhancements/2384.md b/news/1 Enhancements/2384.md new file mode 100644 index 000000000000..e69de29bb2d1 From 8c63050a6249813b414d4cd8431d225a202a16e3 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 20 Aug 2018 11:20:05 -0700 Subject: [PATCH 48/65] News --- news/1 Enhancements/2384.md | 1 + 1 file changed, 1 insertion(+) diff --git a/news/1 Enhancements/2384.md b/news/1 Enhancements/2384.md index e69de29bb2d1..6894b3219315 100644 --- a/news/1 Enhancements/2384.md +++ b/news/1 Enhancements/2384.md @@ -0,0 +1 @@ +Language server now supports hierarchical document outline per language server protocol 4.4+ and VS Code 1.26+. \ No newline at end of file From 797941b9804db1d644003d92d3726987ea7ab4b1 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 20 Aug 2018 14:00:51 -0700 Subject: [PATCH 49/65] Add package lock --- package-lock.json | 108 ++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 61 deletions(-) diff --git a/package-lock.json b/package-lock.json index 277d79370c4a..fbe87dc78ed3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1026,9 +1026,9 @@ "dev": true }, "buffer-from": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, "builtin-modules": { @@ -2796,14 +2796,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2818,20 +2816,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -2948,8 +2943,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -2961,7 +2955,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2976,7 +2969,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2984,14 +2976,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -3010,7 +3000,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -3091,8 +3080,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -3104,7 +3092,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3226,7 +3213,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4141,9 +4127,9 @@ }, "dependencies": { "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", "dev": true }, "clone-stats": { @@ -4159,9 +4145,9 @@ "dev": true }, "vinyl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", - "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { "clone": "^2.1.1", @@ -4723,9 +4709,9 @@ } }, "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", "dev": true }, "clone-stats": { @@ -4979,9 +4965,9 @@ } }, "vinyl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz", - "integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { "clone": "^2.1.1", @@ -8290,9 +8276,9 @@ } }, "source-map-support": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz", - "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.8.tgz", + "integrity": "sha512-WqAEWPdb78u25RfKzOF0swBpY0dKrNdjc4GvLwm7ScX/o9bj8Eh/YL8mcMhBHYDGl87UkkSXDOFnW4G7GhWhGg==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -9537,9 +9523,9 @@ } }, "vscode": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.18.tgz", - "integrity": "sha512-SyDw4qFwZ+WthZX7RWp71PNiWLF7VhpM65j2oryY/6jtSORd8qH6J8vclwWZJ6Jvu0EH7JamO2RWNfBfsMR9Zw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.21.tgz", + "integrity": "sha512-tJl9eL15ZMm6vzCYYeQ26sSYRuXGMGPsaeIAmG2rOOYRn01jdaDg6I4b9G5Ed6FISdmn6egpKThk4o4om8Ax/A==", "dev": true, "requires": { "glob": "^7.1.2", @@ -9554,7 +9540,7 @@ "request": "^2.83.0", "semver": "^5.4.1", "source-map-support": "^0.5.0", - "url-parse": "^1.1.9", + "url-parse": "^1.4.3", "vinyl-source-stream": "^1.1.0" }, "dependencies": { @@ -9671,42 +9657,42 @@ "integrity": "sha512-T24Jb5V48e4VgYliUXMnZ379ItbrXgOimweKaJshD84z+8q7ZOZjJan0MeDe+Ugb+uqERDVV8SBmemaGMSMugA==" }, "vscode-languageclient": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-4.3.0.tgz", - "integrity": "sha512-vDpsmYfYpfuyDKZ46pCJEFBOCNHepRBSmlBGA0fczEbYghYm059BiFo3SmT4MK1r8NvYrFEem4k5TYNW3wommg==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-4.4.0.tgz", + "integrity": "sha512-sXBwIcwG4W5MjnDAfXf0hM5ErOcXxEBlix6QJb5ijf0gtecYygrMAqv8hag7sEg/jCCOKQdXJ4K1iZL3GZcJZg==", "requires": { - "vscode-languageserver-protocol": "^3.9.0" + "vscode-languageserver-protocol": "^3.10.0" } }, "vscode-languageserver": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-4.3.0.tgz", - "integrity": "sha512-4dTpnyTB6Q0HmMhxaG60rrpQthbTBlMtFX5cwJpPxcPzLZIFDWB3msR6TxGCzWpdYF11REIJihWByobpGkljdQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-4.4.0.tgz", + "integrity": "sha512-NO4JQg286YLSdU11Fko6cke19kwSob3O0bhf6xDxIJuDhUbFy0VEPRB5ITc3riVmp13+Ki344xtqJYmqfcmCrg==", "requires": { - "vscode-languageserver-protocol": "^3.9.0", + "vscode-languageserver-protocol": "^3.10.0", "vscode-uri": "^1.0.3" }, "dependencies": { "vscode-uri": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.5.tgz", - "integrity": "sha1-O4majvccN/MFTXm9vdoxx7828g0=" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.6.tgz", + "integrity": "sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==" } } }, "vscode-languageserver-protocol": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.9.0.tgz", - "integrity": "sha512-i1sG5iU88Mocc7egTeh6dAow/yRWpPK5PLJaxsWsKiA+dspq1Yzr/R1bNLPc+6P/ab010lXhzdUHQY0CuIUyDw==", + "version": "3.10.3", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.10.3.tgz", + "integrity": "sha512-R9hKsmXmpIXBLpy6I0eztfAcWU0KHr1lADJiJq+VCmdiHGVUJugMIvU6qVCzLP9wRtZ02AF98j09NAKq10hWeQ==", "requires": { "vscode-jsonrpc": "^3.6.2", - "vscode-languageserver-types": "^3.9.0" + "vscode-languageserver-types": "^3.10.1" } }, "vscode-languageserver-types": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.9.0.tgz", - "integrity": "sha512-Qzh3VsU3t0zhKtYl1revyax+4gGHl2ejNzYXeiZYQMF3i0vX4dtPohxGDFoZYfGFQI738aXYbSUQmhLeBckDlQ==" + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.10.1.tgz", + "integrity": "sha512-HeQ1BPYJDly4HfKs0h2TUAZyHfzTAhgQsCwsa1tW9PhuvGGsd2r3Q53FFVugwP7/2bUv3GWPoTgAuIAkIdBc4w==" }, "vscode-uri": { "version": "1.0.1", From e24c7e5559341483a47e2bb1018bcfc4ca20c1b5 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 20 Aug 2018 14:20:27 -0700 Subject: [PATCH 50/65] Update mock to 1.26 --- src/test/mocks/vsc/extHostedTypes.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/mocks/vsc/extHostedTypes.ts b/src/test/mocks/vsc/extHostedTypes.ts index 0d5f6bc2f2ae..3748b4c6e11d 100644 --- a/src/test/mocks/vsc/extHostedTypes.ts +++ b/src/test/mocks/vsc/extHostedTypes.ts @@ -526,6 +526,16 @@ export namespace vscMockExtHostedTypes { // return this._resourceEdits.map(({ from, to }) => (<[vscode.Uri, vscode.Uri]>[from, to])); // } + createFile(uri: vscode.Uri, options?: { overwrite?: boolean; ignoreIfExists?: boolean; }): void { + throw new Error("Method not implemented."); + } + deleteFile(uri: vscode.Uri, options?: { recursive?: boolean; ignoreIfNotExists?: boolean; }): void { + throw new Error("Method not implemented."); + } + renameFile(oldUri: vscode.Uri, newUri: vscode.Uri, options?: { overwrite?: boolean; ignoreIfExists?: boolean; }): void { + throw new Error("Method not implemented."); + } + replace(uri: vscUri.URI, range: Range, newText: string): void { let edit = new TextEdit(range, newText); let array = this.get(uri); From c3334c82311506f490f608b067e68986515d72ff Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 21 Aug 2018 10:39:54 -0700 Subject: [PATCH 51/65] Tweak news entry wording --- news/2 Fixes/2405.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/news/2 Fixes/2405.md b/news/2 Fixes/2405.md index e796a51dabe7..9e091a14b24c 100644 --- a/news/2 Fixes/2405.md +++ b/news/2 Fixes/2405.md @@ -1 +1 @@ -Added setting to control language server log output. Default is now 'error' so there should be much less noise in the output. \ No newline at end of file +Added setting to control language server log output through the `python.analysis.logLevel` setting (the default is now 'Error'). From f3a08aa99e696dfe2775dec091d5532f562c3dc7 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 27 Aug 2018 11:59:54 -0700 Subject: [PATCH 52/65] Move rope rename off common to Jedi --- src/client/activation/jedi.ts | 13 +++++++++---- src/client/extension.ts | 7 +------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/client/activation/jedi.ts b/src/client/activation/jedi.ts index 86629009162a..e1a1d3b32c68 100644 --- a/src/client/activation/jedi.ts +++ b/src/client/activation/jedi.ts @@ -2,9 +2,9 @@ // Licensed under the MIT License. import { inject, injectable } from 'inversify'; -import { DocumentFilter, languages } from 'vscode'; -import { PYTHON } from '../common/constants'; -import { IConfigurationService, IExtensionContext, ILogger } from '../common/types'; +import { DocumentFilter, languages, OutputChannel } from 'vscode'; +import { PYTHON, STANDARD_OUTPUT_CHANNEL } from '../common/constants'; +import { IConfigurationService, IExtensionContext, ILogger, IOutputChannel } from '../common/types'; import { IShebangCodeLensProvider } from '../interpreter/contracts'; import { IServiceContainer, IServiceManager } from '../ioc/types'; import { JediFactory } from '../languageServices/jediProxyFactory'; @@ -15,6 +15,7 @@ import { activateGoToObjectDefinitionProvider } from '../providers/objectDefinit import { PythonReferenceProvider } from '../providers/referenceProvider'; import { PythonRenameProvider } from '../providers/renameProvider'; import { PythonSignatureProvider } from '../providers/signatureProvider'; +import { activateSimplePythonRefactorProvider } from '../providers/simpleRefactorProvider'; import { PythonSymbolProvider } from '../providers/symbolProvider'; import { IUnitTestManagementService } from '../unittests/types'; import { WorkspaceSymbols } from '../workspaceSymbols/main'; @@ -58,7 +59,11 @@ export class JediExtensionActivator implements IExtensionActivator { context.subscriptions.push(languages.registerSignatureHelpProvider(this.documentSelector, new PythonSignatureProvider(jediFactory), '(', ',')); } - const testManagementService = this.serviceManager.get(IUnitTestManagementService); + const standardOutputChannel = serviceContainer.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); + context.subscriptions.push(languages.registerRenameProvider(PYTHON, new PythonRenameProvider(serviceContainer))); + activateSimplePythonRefactorProvider(context, standardOutputChannel, serviceContainer); + + const testManagementService = this.serviceManager.get(IUnitTestManagementService); testManagementService.activate() .then(() => testManagementService.activateCodeLenses(symbolProvider)) .catch(ex => this.serviceManager.get(ILogger).logError('Failed to activate Unit Tests', ex)); diff --git a/src/client/extension.ts b/src/client/extension.ts index d57df8a2ea06..826018ba7074 100644 --- a/src/client/extension.ts +++ b/src/client/extension.ts @@ -48,9 +48,7 @@ import { ILintingEngine } from './linters/types'; import { PythonCodeActionProvider } from './providers/codeActionsProvider'; import { PythonFormattingEditProvider } from './providers/formatProvider'; import { LinterProvider } from './providers/linterProvider'; -import { PythonRenameProvider } from './providers/renameProvider'; import { ReplProvider } from './providers/replProvider'; -import { activateSimplePythonRefactorProvider } from './providers/simpleRefactorProvider'; import { TerminalProvider } from './providers/terminalProvider'; import { activateUpdateSparkLibraryProvider } from './providers/updateSparkLibraryProvider'; import * as sortImports from './sortImports'; @@ -84,13 +82,10 @@ export async function activate(context: ExtensionContext) { const configuration = serviceManager.get(IConfigurationService); const pythonSettings = configuration.getSettings(); - const standardOutputChannel = serviceManager.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); - context.subscriptions.push(languages.registerRenameProvider(PYTHON, new PythonRenameProvider(serviceManager))); - activateSimplePythonRefactorProvider(context, standardOutputChannel, serviceManager); - const activationService = serviceContainer.get(IExtensionActivationService); await activationService.activate(); + const standardOutputChannel = serviceManager.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); sortImports.activate(context, standardOutputChannel, serviceManager); serviceManager.get(ICodeExecutionManager).registerCommands(); From c51936c86fbcbe1b5bb89590b4006efb6a8c8c1b Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 30 Aug 2018 13:01:00 -0700 Subject: [PATCH 53/65] Move Rename to LS --- src/client/activation/jedi.ts | 11 ++++------- src/client/extension.ts | 4 +++- src/client/providers/renameProvider.ts | 23 +++++++++++++---------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/client/activation/jedi.ts b/src/client/activation/jedi.ts index e1a1d3b32c68..f1c0e48f9117 100644 --- a/src/client/activation/jedi.ts +++ b/src/client/activation/jedi.ts @@ -2,9 +2,9 @@ // Licensed under the MIT License. import { inject, injectable } from 'inversify'; -import { DocumentFilter, languages, OutputChannel } from 'vscode'; -import { PYTHON, STANDARD_OUTPUT_CHANNEL } from '../common/constants'; -import { IConfigurationService, IExtensionContext, ILogger, IOutputChannel } from '../common/types'; +import { DocumentFilter, languages } from 'vscode'; +import { PYTHON } from '../common/constants'; +import { IConfigurationService, IExtensionContext, ILogger } from '../common/types'; import { IShebangCodeLensProvider } from '../interpreter/contracts'; import { IServiceContainer, IServiceManager } from '../ioc/types'; import { JediFactory } from '../languageServices/jediProxyFactory'; @@ -15,7 +15,6 @@ import { activateGoToObjectDefinitionProvider } from '../providers/objectDefinit import { PythonReferenceProvider } from '../providers/referenceProvider'; import { PythonRenameProvider } from '../providers/renameProvider'; import { PythonSignatureProvider } from '../providers/signatureProvider'; -import { activateSimplePythonRefactorProvider } from '../providers/simpleRefactorProvider'; import { PythonSymbolProvider } from '../providers/symbolProvider'; import { IUnitTestManagementService } from '../unittests/types'; import { WorkspaceSymbols } from '../workspaceSymbols/main'; @@ -59,11 +58,9 @@ export class JediExtensionActivator implements IExtensionActivator { context.subscriptions.push(languages.registerSignatureHelpProvider(this.documentSelector, new PythonSignatureProvider(jediFactory), '(', ',')); } - const standardOutputChannel = serviceContainer.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); context.subscriptions.push(languages.registerRenameProvider(PYTHON, new PythonRenameProvider(serviceContainer))); - activateSimplePythonRefactorProvider(context, standardOutputChannel, serviceContainer); - const testManagementService = this.serviceManager.get(IUnitTestManagementService); + const testManagementService = this.serviceManager.get(IUnitTestManagementService); testManagementService.activate() .then(() => testManagementService.activateCodeLenses(symbolProvider)) .catch(ex => this.serviceManager.get(ILogger).logError('Failed to activate Unit Tests', ex)); diff --git a/src/client/extension.ts b/src/client/extension.ts index 826018ba7074..d83ca7ba19fa 100644 --- a/src/client/extension.ts +++ b/src/client/extension.ts @@ -82,10 +82,12 @@ export async function activate(context: ExtensionContext) { const configuration = serviceManager.get(IConfigurationService); const pythonSettings = configuration.getSettings(); + const standardOutputChannel = serviceContainer.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); + activateSimplePythonRefactorProvider(context, standardOutputChannel, serviceContainer); + const activationService = serviceContainer.get(IExtensionActivationService); await activationService.activate(); - const standardOutputChannel = serviceManager.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); sortImports.activate(context, standardOutputChannel, serviceManager); serviceManager.get(ICodeExecutionManager).registerCommands(); diff --git a/src/client/providers/renameProvider.ts b/src/client/providers/renameProvider.ts index 827a4b213a3e..c440b2e8b777 100644 --- a/src/client/providers/renameProvider.ts +++ b/src/client/providers/renameProvider.ts @@ -1,6 +1,9 @@ import * as path from 'path'; -import * as vscode from 'vscode'; -import { OutputChannel, ProviderResult } from 'vscode'; +import { + CancellationToken, OutputChannel, + Position, ProviderResult, RenameProvider, + TextDocument, window, workspace, WorkspaceEdit +} from 'vscode'; import { PythonSettings } from '../common/configSettings'; import { STANDARD_OUTPUT_CHANNEL } from '../common/constants'; import { getWorkspaceEditsFromPatch } from '../common/editor'; @@ -15,19 +18,19 @@ type RenameResponse = { results: [{ diff: string }]; }; -export class PythonRenameProvider implements vscode.RenameProvider { +export class PythonRenameProvider implements RenameProvider { private readonly outputChannel: OutputChannel; constructor(private serviceContainer: IServiceContainer) { this.outputChannel = serviceContainer.get(IOutputChannel, STANDARD_OUTPUT_CHANNEL); } @captureTelemetry(REFACTOR_RENAME) - public provideRenameEdits(document: vscode.TextDocument, position: vscode.Position, newName: string, token: vscode.CancellationToken): ProviderResult { - return vscode.workspace.saveAll(false).then(() => { + public provideRenameEdits(document: TextDocument, position: Position, newName: string, token: CancellationToken): ProviderResult { + return workspace.saveAll(false).then(() => { return this.doRename(document, position, newName, token); }); } - private doRename(document: vscode.TextDocument, position: vscode.Position, newName: string, token: vscode.CancellationToken): ProviderResult { + private doRename(document: TextDocument, position: Position, newName: string, token: CancellationToken): ProviderResult { if (document.lineAt(position.line).text.match(/^\s*\/\//)) { return; } @@ -44,9 +47,9 @@ export class PythonRenameProvider implements vscode.RenameProvider { return; } - let workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri); - if (!workspaceFolder && Array.isArray(vscode.workspace.workspaceFolders) && vscode.workspace.workspaceFolders.length > 0) { - workspaceFolder = vscode.workspace.workspaceFolders[0]; + let workspaceFolder = workspace.getWorkspaceFolder(document.uri); + if (!workspaceFolder && Array.isArray(workspace.workspaceFolders) && workspace.workspaceFolders.length > 0) { + workspaceFolder = workspace.workspaceFolders[0]; } const workspaceRoot = workspaceFolder ? workspaceFolder.uri.fsPath : __dirname; const pythonSettings = PythonSettings.getInstance(workspaceFolder ? workspaceFolder.uri : undefined); @@ -62,7 +65,7 @@ export class PythonRenameProvider implements vscode.RenameProvider { .catch(ex => console.error('Python Extension: promptToInstall', ex)); return Promise.reject(''); } else { - vscode.window.showErrorMessage(reason); + window.showErrorMessage(reason); this.outputChannel.appendLine(reason); } return Promise.reject(reason); From f67cbfad00e8a77f31764094a6f9cc667eb88d2b Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 30 Aug 2018 13:01:35 -0700 Subject: [PATCH 54/65] Ref fix --- src/client/extension.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client/extension.ts b/src/client/extension.ts index d83ca7ba19fa..8d3f14f2bb86 100644 --- a/src/client/extension.ts +++ b/src/client/extension.ts @@ -49,6 +49,7 @@ import { PythonCodeActionProvider } from './providers/codeActionsProvider'; import { PythonFormattingEditProvider } from './providers/formatProvider'; import { LinterProvider } from './providers/linterProvider'; import { ReplProvider } from './providers/replProvider'; +import { activateSimplePythonRefactorProvider } from './providers/simpleRefactorProvider'; import { TerminalProvider } from './providers/terminalProvider'; import { activateUpdateSparkLibraryProvider } from './providers/updateSparkLibraryProvider'; import * as sortImports from './sortImports'; From f4353dd15b3c1bf111b9f911afcc48bba0cdcba7 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 6 Sep 2018 12:40:05 -0700 Subject: [PATCH 55/65] Update LS contrib --- CONTRIBUTING - LANGUAGE SERVER.md | 63 ------------------------------- CONTRIBUTING.md | 3 +- 2 files changed, 2 insertions(+), 64 deletions(-) delete mode 100644 CONTRIBUTING - LANGUAGE SERVER.md diff --git a/CONTRIBUTING - LANGUAGE SERVER.md b/CONTRIBUTING - LANGUAGE SERVER.md deleted file mode 100644 index 7c363ce23b81..000000000000 --- a/CONTRIBUTING - LANGUAGE SERVER.md +++ /dev/null @@ -1,63 +0,0 @@ -# Contributing to Microsoft Python Language Server -[![Contributing to Python Tools for Visual Studio](https://github.com/Microsoft/PTVS/blob/master/CONTRIBUTING.md)] - -[![Build Status (Travis)](https://travis-ci.org/Microsoft/vscode-python.svg?branch=master)](https://travis-ci.org/Microsoft/vscode-python) [![Build status (AppVeyor)](https://ci.appveyor.com/api/projects/status/s0pt8d79gqw222j7?svg=true)](https://ci.appveyor.com/project/DonJayamanne/vscode-python-v3vd6) [![codecov](https://codecov.io/gh/Microsoft/vscode-python/branch/master/graph/badge.svg)](https://codecov.io/gh/Microsoft/vscode-python) - - -## Contributing a pull request - -### Prerequisites - -1. .NET Core 2.1 SDK - - [Windows](https://www.microsoft.com/net/learn/get-started/windows) - - [Mac OS](https://www.microsoft.com/net/learn/get-started/macos) - - [Linux](https://www.microsoft.com/net/learn/get-started/linux/rhel) -2. C# Extension to VS Code (all platforms) -3. Python 2.7 -4. Python 3.6 - -*Alternative:* [Visual Studio 2017](https://www.visualstudio.com/downloads/) (Windows only) with .NET Core and C# Workloads. Community Edition is free and is fully functional. - -### Setup - -```shell -git clone https://github.com/microsoft/ptvs -cd ptvs/Python/Product/VSCode/AnalysisVsc -dotnet build -``` - -Visual Studio 2017: -1. Open solution in Python/Product/VsCode -2. Build AnalysisVsc project -3. Binaries arrive in *Python/BuildOutput/VsCode/raw* -4. Delete contents of the *languageServer* folder in the Python Extension folder -5. Copy *.dll, *.pdb, *.json fron *Python/BuildOutput/VsCode/raw* to *languageServer* -6. In VS Code set setting *python.downloadLanguageServer* to *false* -7. In VS Code set setting *python.jediEnabled* to *false* - -### Debugging code in Python Extension to VS Code -Folow regular TypeScript debugging steps - -### Debugging C# code in Python Analysis Engine -1. Launch another instance of VS Code -2. Open Python/Product/VsCode/AnalysisVsc folder -3. Python Analysis Engine code is in *Python/Product/VsCode/Analysis* -4. Run extension from VS Code -5. In the instance with C# code select Dotnet Attach launch task. -6. Attach to *dotnet* process running *Microsoft.Python.languageServer.dll* - -On Windows you can also attach from Visual Studio 2017. - -### Validate your changes - -1. Build C# code -2. Copy binaries to *analysis* folder -3. Use the `Launch Extension` launch option. - -### Unit Tests -1. Run the Unit Tests via the `Launch Analysis Engine Tests`. -2. On Windows you can also open complete PTVS solution in Visual Studio and run its tests (or at least the Analysis section). - - -### Coding Standards -See [![Contributing to Python Tools for Visual Studio](https://github.com/Microsoft/PTVS/blob/master/CONTRIBUTING.md)] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 966591a200da..f5330f4228a1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,8 @@ --- -[[Contributing to Python Analysis Engine](https://github.com/Microsoft/vscode-python/blob/master/CONTRIBUTING%20-%20PYTHON_ANALYSIS.md) is covered in a separate document.] +[Microsoft Python Language Server](https://github.com/Microsoft/python-language-server) is located in its own repo +[Contributing to Microsoft Python Language Server](https://github.com/Microsoft/python-language-server/blob/master/CONTRIBUTING.md) ## Contributing a pull request From 1b33dde6fe275d3ea8e4abb2eb32d8c2e4377d14 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 6 Sep 2018 12:41:43 -0700 Subject: [PATCH 56/65] Merge issue --- news/2 Fixes/2405.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 news/2 Fixes/2405.md diff --git a/news/2 Fixes/2405.md b/news/2 Fixes/2405.md deleted file mode 100644 index 9a5e6967909e..000000000000 --- a/news/2 Fixes/2405.md +++ /dev/null @@ -1 +0,0 @@ -Added setting to control language server log output. Default is now 'error' so there should be much less noise in the output. From 1187d7e93cc04b7084b4469b945065bcb5076f5a Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 13 Sep 2018 12:19:27 -0700 Subject: [PATCH 57/65] Make sure progress is cleared --- src/client/activation/languageServer.ts | 3 +++ src/client/activation/progress.ts | 21 ++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index d655b95d6c7d..2dfd79bb6a7c 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -179,6 +179,9 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { } private async startLanguageClient(): Promise { + if (this.progressReporting) { + this.progressReporting.dispose(); + } this.context.subscriptions.push(this.languageClient!.start()); await this.serverReady(); this.progressReporting = new ProgressReporting(this.languageClient!); diff --git a/src/client/activation/progress.ts b/src/client/activation/progress.ts index a955cda92644..930ad1c0c0a6 100644 --- a/src/client/activation/progress.ts +++ b/src/client/activation/progress.ts @@ -5,7 +5,7 @@ import { Progress, ProgressLocation, window } from 'vscode'; import { Disposable, LanguageClient } from 'vscode-languageclient'; import { createDeferred, Deferred } from '../../utils/async'; -export class ProgressReporting { +export class ProgressReporting implements Disposable { private statusBarMessage: Disposable | undefined; private progress: Progress<{ message?: string; increment?: number }> | undefined; private progressDeferred: Deferred | undefined; @@ -19,6 +19,7 @@ export class ProgressReporting { }); this.languageClient.onNotification('python/beginProgress', async _ => { + this.clearProgress(); this.progressDeferred = createDeferred(); window.withProgress({ location: ProgressLocation.Window, @@ -36,11 +37,17 @@ export class ProgressReporting { this.progress.report({ message: m }); }); - this.languageClient.onNotification('python/endProgress', _ => { - if (this.progressDeferred) { - this.progressDeferred.resolve(); - this.progressDeferred = undefined; - } - }); + this.languageClient.onNotification('python/endProgress', _ => this.clearProgress()); + } + + public dispose(): void { + this.clearProgress(); + } + + private clearProgress(): void { + if (this.progressDeferred) { + this.progressDeferred.resolve(); + this.progressDeferred = undefined; + } } } From 1d19d2fe840cca2c79367ba9cefd2d55cb8d5a50 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Tue, 18 Sep 2018 10:09:22 -0700 Subject: [PATCH 58/65] Revert "Make sure progress is cleared" This reverts commit 1187d7e93cc04b7084b4469b945065bcb5076f5a. --- src/client/activation/languageServer.ts | 3 --- src/client/activation/progress.ts | 21 +++++++-------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/client/activation/languageServer.ts b/src/client/activation/languageServer.ts index 2dfd79bb6a7c..d655b95d6c7d 100644 --- a/src/client/activation/languageServer.ts +++ b/src/client/activation/languageServer.ts @@ -179,9 +179,6 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { } private async startLanguageClient(): Promise { - if (this.progressReporting) { - this.progressReporting.dispose(); - } this.context.subscriptions.push(this.languageClient!.start()); await this.serverReady(); this.progressReporting = new ProgressReporting(this.languageClient!); diff --git a/src/client/activation/progress.ts b/src/client/activation/progress.ts index 930ad1c0c0a6..a955cda92644 100644 --- a/src/client/activation/progress.ts +++ b/src/client/activation/progress.ts @@ -5,7 +5,7 @@ import { Progress, ProgressLocation, window } from 'vscode'; import { Disposable, LanguageClient } from 'vscode-languageclient'; import { createDeferred, Deferred } from '../../utils/async'; -export class ProgressReporting implements Disposable { +export class ProgressReporting { private statusBarMessage: Disposable | undefined; private progress: Progress<{ message?: string; increment?: number }> | undefined; private progressDeferred: Deferred | undefined; @@ -19,7 +19,6 @@ export class ProgressReporting implements Disposable { }); this.languageClient.onNotification('python/beginProgress', async _ => { - this.clearProgress(); this.progressDeferred = createDeferred(); window.withProgress({ location: ProgressLocation.Window, @@ -37,17 +36,11 @@ export class ProgressReporting implements Disposable { this.progress.report({ message: m }); }); - this.languageClient.onNotification('python/endProgress', _ => this.clearProgress()); - } - - public dispose(): void { - this.clearProgress(); - } - - private clearProgress(): void { - if (this.progressDeferred) { - this.progressDeferred.resolve(); - this.progressDeferred = undefined; - } + this.languageClient.onNotification('python/endProgress', _ => { + if (this.progressDeferred) { + this.progressDeferred.resolve(); + this.progressDeferred = undefined; + } + }); } } From 1471e90dd4eb0ba0f63595adf862965c3eb3a451 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Tue, 18 Sep 2018 16:48:09 -0700 Subject: [PATCH 59/65] Line breaks and remove duplication --- src/client/activation/downloader.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/client/activation/downloader.ts b/src/client/activation/downloader.ts index 4443814175ee..a82bc42d1460 100644 --- a/src/client/activation/downloader.ts +++ b/src/client/activation/downloader.ts @@ -119,7 +119,7 @@ export class LanguageServerDownloader { deferred.reject(err); }) .on('end', () => { - this.output.append('complete.'); + this.output.appendLine('complete.'); deferred.resolve(); }) .pipe(fileStream); @@ -137,8 +137,7 @@ export class LanguageServerDownloader { const title = 'Extracting files... '; await window.withProgress({ - location: ProgressLocation.Window, - title + location: ProgressLocation.Window }, (progress) => { const zip = new StreamZip({ file: tempFilePath, From 0b532c01628ed511e0207b84d192f13a06d76074 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 20 Sep 2018 16:56:04 -0700 Subject: [PATCH 60/65] Add news --- news/1 Enhancements/2650.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/1 Enhancements/2650.md diff --git a/news/1 Enhancements/2650.md b/news/1 Enhancements/2650.md new file mode 100644 index 000000000000..e4df2bd4ea44 --- /dev/null +++ b/news/1 Enhancements/2650.md @@ -0,0 +1 @@ +Language server now provides rename functionality. \ No newline at end of file From 589ea3333ee40d109d012e5326ce58b89e4803aa Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Wed, 17 Oct 2018 16:39:44 -0700 Subject: [PATCH 61/65] Listen to LS telemetry event --- src/client/activation/languageServer/languageServer.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/client/activation/languageServer/languageServer.ts b/src/client/activation/languageServer/languageServer.ts index 1c04c177fec2..7c107726bafe 100644 --- a/src/client/activation/languageServer/languageServer.ts +++ b/src/client/activation/languageServer/languageServer.ts @@ -165,6 +165,9 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { this.languageClient = this.createSelfContainedLanguageClient(serverModule, clientOptions); try { await this.startLanguageClient(); + this.languageClient.onTelemetry(data => { + reporter.sendTelemetryEvent('Microsoft Python Language Server', { data }); + }); return true; } catch (ex) { this.appShell.showErrorMessage(`Language server failed to start. Error ${ex}`); From cc09f953455cd41c92ce0554d7f2aa521c2d0504 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 18 Oct 2018 11:45:06 -0700 Subject: [PATCH 62/65] Remove prefixPath as :S does not need it --- src/client/activation/interpreterDataService.ts | 12 ++++-------- .../activation/languageServer/languageServer.ts | 2 -- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/client/activation/interpreterDataService.ts b/src/client/activation/interpreterDataService.ts index 897863053369..daa595ebf383 100644 --- a/src/client/activation/interpreterDataService.ts +++ b/src/client/activation/interpreterDataService.ts @@ -20,7 +20,6 @@ export class InterpreterData { // tslint:disable-next-line:no-shadowed-variable public readonly path: string, public readonly version: string, - public readonly prefix: string, public readonly searchPaths: string, public readonly hash: string ) { } @@ -81,15 +80,13 @@ export class InterpreterDataService { } private async getInterpreterDataFromPython(execService: IPythonExecutionService, interpreterPath: string): Promise { - const result = await execService.exec(['-c', 'import sys; print(sys.version_info); print(sys.prefix)'], {}); - // 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) <> - // [MSC v.1500 32 bit (Intel)] - // C:\Python27 + const result = await execService.exec(['-c', 'import sys; print(sys.version_info)'], {}); + // sys.version_info(major=3, minor=6, micro=6, releaselevel='final', serial=0) if (!result.stdout) { throw Error('Unable to determine Python interpreter version and system prefix.'); } const output = result.stdout.splitLines({ removeEmptyEntries: true, trim: true }); - if (!output || output.length < 2) { + if (!output || output.length < 1) { throw Error('Unable to parse version and and system prefix from the Python interpreter output.'); } const majorMatches = output[0].match(/major=(\d*?),/); @@ -97,10 +94,9 @@ export class InterpreterDataService { if (!majorMatches || majorMatches.length < 2 || !minorMatches || minorMatches.length < 2) { throw Error('Unable to parse interpreter version.'); } - const prefix = output[output.length - 1]; const hash = await this.getInterpreterHash(interpreterPath); const searchPaths = await this.getSearchPaths(execService); - return new InterpreterData(DataVersion, interpreterPath, `${majorMatches[1]}.${minorMatches[1]}`, prefix, searchPaths, hash); + return new InterpreterData(DataVersion, interpreterPath, `${majorMatches[1]}.${minorMatches[1]}`, searchPaths, hash); } private async getSearchPaths(execService: IPythonExecutionService): Promise { diff --git a/src/client/activation/languageServer/languageServer.ts b/src/client/activation/languageServer/languageServer.ts index 1c04c177fec2..dba4b62eeb91 100644 --- a/src/client/activation/languageServer/languageServer.ts +++ b/src/client/activation/languageServer/languageServer.ts @@ -232,8 +232,6 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { properties['InterpreterPath'] = interpreterData.path; // tslint:disable-next-line:no-string-literal properties['Version'] = interpreterData.version; - // tslint:disable-next-line:no-string-literal - properties['PrefixPath'] = interpreterData.prefix; } // tslint:disable-next-line:no-string-literal From c40d39f223edb4db6f27d6930bc2a6d24ab3cd23 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 22 Oct 2018 12:12:10 -0700 Subject: [PATCH 63/65] LS temetry support --- src/client/activation/languageServer/languageServer.ts | 8 +++++--- src/client/telemetry/constants.ts | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/client/activation/languageServer/languageServer.ts b/src/client/activation/languageServer/languageServer.ts index 614f44a61884..dc4f0f0d2161 100644 --- a/src/client/activation/languageServer/languageServer.ts +++ b/src/client/activation/languageServer/languageServer.ts @@ -32,7 +32,8 @@ import { IServiceContainer } from '../../ioc/types'; import { LanguageServerSymbolProvider } from '../../providers/symbolProvider'; import { PYTHON_LANGUAGE_SERVER_ENABLED, - PYTHON_LANGUAGE_SERVER_ERROR + PYTHON_LANGUAGE_SERVER_ERROR, + PYTHON_LANGUAGE_SERVER_TELEMETRY } from '../../telemetry/constants'; import { getTelemetryReporter } from '../../telemetry/telemetry'; import { IUnitTestManagementService } from '../../unittests/types'; @@ -165,8 +166,9 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { this.languageClient = this.createSelfContainedLanguageClient(serverModule, clientOptions); try { await this.startLanguageClient(); - this.languageClient.onTelemetry(data => { - reporter.sendTelemetryEvent('Microsoft Python Language Server', { data }); + this.languageClient.onTelemetry(telemetryEvent => { + const eventName = telemetryEvent.Name ? telemetryEvent.Name : PYTHON_LANGUAGE_SERVER_TELEMETRY; + reporter.sendTelemetryEvent(eventName, telemetryEvent.Properties, telemetryEvent.Measurements); }); return true; } catch (ex) { diff --git a/src/client/telemetry/constants.ts b/src/client/telemetry/constants.ts index 7eb0589779f6..a38fe6747e7a 100644 --- a/src/client/telemetry/constants.ts +++ b/src/client/telemetry/constants.ts @@ -39,6 +39,7 @@ export const PYTHON_LANGUAGE_SERVER_DOWNLOADED = 'PYTHON_LANGUAGE_SERVER.DOWNLOA export const PYTHON_LANGUAGE_SERVER_ERROR = 'PYTHON_LANGUAGE_SERVER.ERROR'; export const PYTHON_LANGUAGE_SERVER_STARTUP = 'PYTHON_LANGUAGE_SERVER.STARTUP'; export const PYTHON_LANGUAGE_SERVER_PLATFORM_NOT_SUPPORTED = 'PYTHON_LANGUAGE_SERVER.PLATFORM_NOT_SUPPORTED'; +export const PYTHON_LANGUAGE_SERVER_TELEMETRY = 'PYTHON_LANGUAGE_SERVER.EVENT'; export const TERMINAL_CREATE = 'TERMINAL.CREATE'; export const PYTHON_LANGUAGE_SERVER_LIST_BLOB_STORE_PACKAGES = 'PYTHON_LANGUAGE_SERVER.LIST_BLOB_PACKAGES'; From f9881cdb0674b1f4513a437b6f3c837a15520cc9 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 22 Oct 2018 12:20:15 -0700 Subject: [PATCH 64/65] Merge master --- src/client/activation/languageServer/languageServer.ts | 5 ++--- src/client/telemetry/types.ts | 7 ++++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/client/activation/languageServer/languageServer.ts b/src/client/activation/languageServer/languageServer.ts index e023ef94b34e..d22d8e80cfd8 100644 --- a/src/client/activation/languageServer/languageServer.ts +++ b/src/client/activation/languageServer/languageServer.ts @@ -167,7 +167,7 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { await this.startLanguageClient(); this.languageClient.onTelemetry(telemetryEvent => { const eventName = telemetryEvent.Name ? telemetryEvent.Name : PYTHON_LANGUAGE_SERVER_TELEMETRY; - reporter.sendTelemetryEvent(eventName, telemetryEvent.Properties, telemetryEvent.Measurements); + sendTelemetryEvent(eventName, telemetryEvent.Measurements, telemetryEvent.Properties); }); return true; } catch (ex) { @@ -217,8 +217,7 @@ export class LanguageServerExtensionActivator implements IExtensionActivator { // tslint:disable-next-line:member-ordering public async getAnalysisOptions(): Promise { - // tslint:disable-next-line:no-any - const properties = new Map(); + const properties = new Map(); let interpreterData: InterpreterData | undefined; let pythonPath = ''; diff --git a/src/client/telemetry/types.ts b/src/client/telemetry/types.ts index 94680da80220..0efcecaf05b1 100644 --- a/src/client/telemetry/types.ts +++ b/src/client/telemetry/types.ts @@ -15,7 +15,7 @@ export type FormatTelemetry = { formatSelection: boolean; }; -export type LanguageServerTelemetry = { +export type LanguageServerVersionTelemetry = { success: boolean; lsVersion?: string; }; @@ -24,6 +24,10 @@ export type LanguageServerErrorTelemetry = { error: string; }; +export type LanguageServerTelemetry = { + [key: string]: string; +}; + export type LinterTrigger = 'auto' | 'save'; export type LintingTelemetry = { @@ -93,6 +97,7 @@ export type TerminalTelemetry = { }; export type TelemetryProperties = FormatTelemetry | LanguageServerTelemetry + | LanguageServerVersionTelemetry | LanguageServerErrorTelemetry | LintingTelemetry | EditorLoadTelemetry From e202b61e5b6347ea828707ce729d1f5fac00c1b2 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 22 Oct 2018 12:23:15 -0700 Subject: [PATCH 65/65] Package --- package-lock.json | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1679820b4df1..3741f60c5eb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2130,7 +2130,7 @@ }, "dotenv": { "version": "5.0.1", - "resolved": "http://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==" }, "download": { @@ -2919,12 +2919,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2939,17 +2941,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3066,7 +3071,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3078,6 +3084,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3092,6 +3099,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3105,6 +3113,7 @@ "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -3203,7 +3212,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3215,6 +3225,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3337,6 +3348,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6761,7 +6773,7 @@ }, "md5.js": { "version": "1.3.4", - "resolved": "http://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", "requires": { "hash-base": "^3.0.0", @@ -7741,7 +7753,7 @@ }, "pretty-hrtime": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, @@ -9590,7 +9602,7 @@ }, "validator": { "version": "9.4.1", - "resolved": "http://registry.npmjs.org/validator/-/validator-9.4.1.tgz", + "resolved": "https://registry.npmjs.org/validator/-/validator-9.4.1.tgz", "integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA==" }, "value-or-function": { @@ -10085,7 +10097,7 @@ }, "xmlbuilder": { "version": "9.0.7", - "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" }, "xtend": {