Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ coverage:
precision: 0
round: up
range: "70...90"
status:
project: off
comment:
layout: "diff, flags"
behavior: default
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@
"python.linting.enabled": false,
"python.unitTest.promptToConfigure": false,
"python.workspaceSymbols.enabled": false,
"python.formatting.provider": "none"
"python.formatting.provider": "none",
"typescript.preferences.quoteStyle": "single",
"javascript.preferences.quoteStyle": "single",
"typescriptHero.imports.stringQuoteStyle": "'"
}
1 change: 0 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,6 @@ function getFilesToProcess(fileList) {
* @param {hygieneOptions} options
*/
function getFileListToProcess(options) {
return [];
const mode = options ? options.mode : 'all';
const gulpSrcOptions = { base: '.' };

Expand Down
1 change: 1 addition & 0 deletions news/2 Fixes/3346.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Ensure extension does not start multiple language servers.
70 changes: 70 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1542,7 +1542,7 @@
"type": "string",
"default": "pipenv",
"description": "Path to the pipenv executable to use for activation.",
"scope": "window"
"scope": "resource"
},
"python.sortImports.args": {
"type": "array",
Expand Down Expand Up @@ -1929,6 +1929,7 @@
"@types/semver": "^5.5.0",
"@types/shortid": "^0.0.29",
"@types/sinon": "^4.3.0",
"@types/stack-trace": "0.0.29",
"@types/temp": "^0.8.32",
"@types/tmp": "0.0.33",
"@types/untildify": "^3.0.0",
Expand Down Expand Up @@ -1987,6 +1988,7 @@
"relative": "^3.0.2",
"remap-istanbul": "^0.10.1",
"retyped-diff-match-patch-tsd-ambient": "^1.0.0-0",
"rewiremock": "^3.13.0",
"shortid": "^2.2.8",
"source-map-support": "^0.5.9",
"style-loader": "^0.23.1",
Expand Down
13 changes: 9 additions & 4 deletions src/client/activation/activationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class ExtensionActivationService implements IExtensionActivationService,
if (!jedi) {
const diagnostic = await this.lsNotSupportedDiagnosticService.diagnose();
this.lsNotSupportedDiagnosticService.handle(diagnostic).ignoreErrors();
if (diagnostic.length){
if (diagnostic.length) {
sendTelemetryEvent(PYTHON_LANGUAGE_SERVER_PLATFORM_NOT_SUPPORTED);
jedi = true;
}
Expand All @@ -70,8 +70,13 @@ export class ExtensionActivationService implements IExtensionActivationService,
let activator = this.serviceContainer.get<IExtensionActivator>(IExtensionActivator, activatorName);
this.currentActivator = { jedi, activator };

const success = await activator.activate();
if (!success && !jedi) {
try {
await activator.activate();
return;
} catch (ex) {
if (jedi) {
return;
}
//Language server fails, reverting to jedi
jedi = true;
await this.logStartup(jedi);
Expand All @@ -84,7 +89,7 @@ export class ExtensionActivationService implements IExtensionActivationService,

public dispose() {
if (this.currentActivator) {
this.currentActivator.activator.deactivate().ignoreErrors();
this.currentActivator.activator.dispose();
}
}

Expand Down
56 changes: 24 additions & 32 deletions src/client/activation/downloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,42 @@

'use strict';

import { inject, injectable, named } from 'inversify';
import * as path from 'path';
import { ProgressLocation, window } from 'vscode';
import { IApplicationShell } from '../common/application/types';
import { STANDARD_OUTPUT_CHANNEL } from '../common/constants';
import { IFileSystem } from '../common/platform/types';
import { IExtensionContext, IOutputChannel } from '../common/types';
import { IOutputChannel } from '../common/types';
import { createDeferred } from '../common/utils/async';
import { LanguageService } from '../common/utils/localize';
import { StopWatch } from '../common/utils/stopWatch';
import { IServiceContainer } from '../ioc/types';
import { sendTelemetryEvent } from '../telemetry';
import {
PYTHON_LANGUAGE_SERVER_DOWNLOADED,
PYTHON_LANGUAGE_SERVER_ERROR,
PYTHON_LANGUAGE_SERVER_EXTRACTED
} from '../telemetry/constants';
import {
IHttpClient, ILanguageServerDownloader, ILanguageServerFolderService,
ILanguageServerPlatformData
} from './types';
import { IHttpClient, ILanguageServerDownloader, ILanguageServerFolderService, IPlatformData } from './types';

const downloadFileExtension = '.nupkg';

@injectable()
export class LanguageServerDownloader implements ILanguageServerDownloader {
private readonly output: IOutputChannel;
private readonly fs: IFileSystem;
private readonly appShell: IApplicationShell;
constructor(
private readonly platformData: ILanguageServerPlatformData,
private readonly engineFolder: string,
private readonly serviceContainer: IServiceContainer
@inject(IPlatformData) private readonly platformData: IPlatformData,
@inject(IOutputChannel) @named(STANDARD_OUTPUT_CHANNEL) private readonly output: IOutputChannel,
@inject(IHttpClient) private readonly httpClient: IHttpClient,
@inject(ILanguageServerFolderService) private readonly lsFolderService: ILanguageServerFolderService,
@inject(IApplicationShell) private readonly appShell: IApplicationShell,
@inject(IFileSystem) private readonly fs: IFileSystem
) {
this.output = this.serviceContainer.get<IOutputChannel>(IOutputChannel, STANDARD_OUTPUT_CHANNEL);
this.fs = this.serviceContainer.get<IFileSystem>(IFileSystem);
this.appShell = this.serviceContainer.get<IApplicationShell>(IApplicationShell);

}

public async getDownloadInfo() {
const lsFolderService = this.serviceContainer.get<ILanguageServerFolderService>(ILanguageServerFolderService);
return lsFolderService.getLatestLanguageServerVersion().then(item => item!);
return this.lsFolderService.getLatestLanguageServerVersion().then(item => item!);
}

public async downloadLanguageServer(context: IExtensionContext): Promise<void> {
public async downloadLanguageServer(destinationFolder: string): Promise<void> {
const downloadInfo = await this.getDownloadInfo();
const downloadUri = downloadInfo.uri;
const lsVersion = downloadInfo.version.raw;
Expand All @@ -61,7 +53,7 @@ export class LanguageServerDownloader implements ILanguageServerDownloader {
this.output.appendLine(err);
success = false;
this.appShell.showErrorMessage(LanguageService.lsFailedToDownload());
sendTelemetryEvent(PYTHON_LANGUAGE_SERVER_ERROR, undefined, { error: 'Failed to download (platform)' });
sendTelemetryEvent(PYTHON_LANGUAGE_SERVER_ERROR, undefined, { error: 'Failed to download (platform)' }, err);
throw new Error(err);
} finally {
sendTelemetryEvent(
Expand All @@ -73,13 +65,13 @@ export class LanguageServerDownloader implements ILanguageServerDownloader {

timer.reset();
try {
await this.unpackArchive(context.extensionPath, localTempFilePath);
await this.unpackArchive(destinationFolder, localTempFilePath);
} catch (err) {
this.output.appendLine('extraction failed.');
this.output.appendLine(err);
success = false;
this.appShell.showErrorMessage(LanguageService.lsFailedToExtract());
sendTelemetryEvent(PYTHON_LANGUAGE_SERVER_ERROR, undefined, { error: 'Failed to extract (platform)' });
sendTelemetryEvent(PYTHON_LANGUAGE_SERVER_ERROR, undefined, { error: 'Failed to extract (platform)' }, err);
throw new Error(err);
} finally {
sendTelemetryEvent(
Expand Down Expand Up @@ -107,11 +99,12 @@ export class LanguageServerDownloader implements ILanguageServerDownloader {
await window.withProgress({
location: ProgressLocation.Window
}, async (progress) => {
const httpClient = this.serviceContainer.get<IHttpClient>(IHttpClient);
const req = await httpClient.downloadFile(uri);
const req = await this.httpClient.downloadFile(uri);
req.on('response', (response) => {
if (response.statusCode !== 200) {
throw new Error(`Failed with status ${response.statusCode}, ${response.statusMessage}, Uri ${uri}`);
const error = new Error(`Failed with status ${response.statusCode}, ${response.statusMessage}, Uri ${uri}`);
deferred.reject(error);
throw error;
}
});
const requestProgress = await import('request-progress');
Expand Down Expand Up @@ -139,10 +132,9 @@ export class LanguageServerDownloader implements ILanguageServerDownloader {
return tempFile.filePath;
}

protected async unpackArchive(extensionPath: string, tempFilePath: string): Promise<void> {
protected async unpackArchive(destinationFolder: string, tempFilePath: string): Promise<void> {
this.output.append('Unpacking archive... ');

const installFolder = path.join(extensionPath, this.engineFolder);
const deferred = createDeferred();

const title = 'Extracting files... ';
Expand All @@ -160,10 +152,10 @@ export class LanguageServerDownloader implements ILanguageServerDownloader {
let extractedFiles = 0;
zip.on('ready', async () => {
totalFiles = zip.entriesCount;
if (!await this.fs.directoryExists(installFolder)) {
await this.fs.createDirectory(installFolder);
if (!await this.fs.directoryExists(destinationFolder)) {
await this.fs.createDirectory(destinationFolder);
}
zip.extract(null, installFolder, (err) => {
zip.extract(null, destinationFolder, (err) => {
if (err) {
deferred.reject(err);
} else {
Expand All @@ -181,7 +173,7 @@ export class LanguageServerDownloader implements ILanguageServerDownloader {
});

// Set file to executable (nothing happens in Windows, as chmod has no definition there)
const executablePath = path.join(installFolder, this.platformData.getEngineExecutableName());
const executablePath = path.join(destinationFolder, this.platformData.engineExecutableName);
await this.fs.chmod(executablePath, '0764'); // -rwxrw-r--

this.output.appendLine('done.');
Expand Down
28 changes: 0 additions & 28 deletions src/client/activation/hashVerifier.ts

This file was deleted.

Loading