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
1 change: 1 addition & 0 deletions news/3 Code Health/2180.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Change the download links of the language server files.
24 changes: 18 additions & 6 deletions src/client/activation/downloader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

'use strict';

import * as fileSystem from 'fs';
import * as path from 'path';
import * as request from 'request';
Expand All @@ -11,7 +13,7 @@ import { createDeferred } from '../common/helpers';
import { IFileSystem, IPlatformService } from '../common/platform/types';
import { IExtensionContext, IOutputChannel } from '../common/types';
import { IServiceContainer } from '../ioc/types';
import { PlatformData } from './platformData';
import { PlatformData, PlatformName } from './platformData';

// tslint:disable-next-line:no-require-imports no-var-requires
const StreamZip = require('node-stream-zip');
Expand All @@ -21,6 +23,13 @@ const downloadBaseFileName = 'Python-Language-Server';
const downloadVersion = '0.1.0';
const downloadFileExtension = '.nupkg';

const DownloadLinks = {
[PlatformName.Windows32Bit]: `${downloadUriPrefix}/${downloadBaseFileName}-${PlatformName.Windows32Bit}.${downloadVersion}${downloadFileExtension}`,
[PlatformName.Windows64Bit]: `${downloadUriPrefix}/${downloadBaseFileName}-${PlatformName.Windows64Bit}.${downloadVersion}${downloadFileExtension}`,
[PlatformName.Linux64Bit]: `${downloadUriPrefix}/${downloadBaseFileName}-${PlatformName.Linux64Bit}.${downloadVersion}${downloadFileExtension}`,
[PlatformName.Mac64Bit]: `${downloadUriPrefix}/${downloadBaseFileName}-${PlatformName.Mac64Bit}.${downloadVersion}${downloadFileExtension}`
};

export class LanguageServerDownloader {
private readonly output: OutputChannel;
private readonly platform: IPlatformService;
Expand All @@ -34,13 +43,17 @@ export class LanguageServerDownloader {
this.platformData = new PlatformData(this.platform, this.fs);
}

public async downloadLanguageServer(context: IExtensionContext): Promise<void> {
public async getDownloadUri() {
const platformString = await this.platformData.getPlatformName();
const enginePackageFileName = `${downloadBaseFileName}-${platformString}.${downloadVersion}${downloadFileExtension}`;
return DownloadLinks[platformString];
}

public async downloadLanguageServer(context: IExtensionContext): Promise<void> {
const downloadUri = await this.getDownloadUri();

let localTempFilePath = '';
try {
localTempFilePath = await this.downloadFile(downloadUriPrefix, enginePackageFileName, 'Downloading Microsoft Python Language Server... ');
localTempFilePath = await this.downloadFile(downloadUri, 'Downloading Microsoft Python Language Server... ');
await this.unpackArchive(context.extensionPath, localTempFilePath);
} catch (err) {
this.output.appendLine('failed.');
Expand All @@ -53,8 +66,7 @@ export class LanguageServerDownloader {
}
}

private async downloadFile(location: string, fileName: string, title: string): Promise<string> {
const uri = `${location}/${fileName}`;
private async downloadFile(uri: string, title: string): Promise<string> {
this.output.append(`Downloading ${uri}... `);
const tempFile = await this.fs.createTemporaryFile(downloadFileExtension);

Expand Down
15 changes: 11 additions & 4 deletions src/client/activation/platformData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,27 @@ import {
language_server_win_x86_sha512
} from './languageServerHashes';

export enum PlatformName {
Windows32Bit = 'win-x86',
Windows64Bit = 'win-x64',
Mac64Bit = 'osx-x64',
Linux64Bit = 'linux-x64'
}

export class PlatformData {
constructor(private platform: IPlatformService, fs: IFileSystem) { }
public async getPlatformName(): Promise<string> {
public async getPlatformName(): Promise<PlatformName> {
if (this.platform.isWindows) {
return this.platform.is64bit ? 'win-x64' : 'win-x86';
return this.platform.is64bit ? PlatformName.Windows64Bit : PlatformName.Windows32Bit;
}
if (this.platform.isMac) {
return 'osx-x64';
return PlatformName.Mac64Bit;
}
if (this.platform.isLinux) {
if (!this.platform.is64bit) {
throw new Error('Microsoft Python Language Server does not support 32-bit Linux.');
}
return 'linux-x64';
return PlatformName.Linux64Bit;
}
throw new Error('Unknown OS platform.');
}
Expand Down
68 changes: 68 additions & 0 deletions src/test/activation/downloader.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

'use strict';

// tslint:disable:no-unused-variable

import * as assert from 'assert';
import * as TypeMoq from 'typemoq';
import { LanguageServerDownloader } from '../../client/activation/downloader';
import { IFileSystem, IPlatformService } from '../../client/common/platform/types';
import { IOutputChannel } from '../../client/common/types';
import { IServiceContainer } from '../../client/ioc/types';

const downloadUriPrefix = 'https://pvsc.blob.core.windows.net/python-language-server';
const downloadBaseFileName = 'Python-Language-Server';
const downloadVersion = '0.1.0';
const downloadFileExtension = '.nupkg';

suite('Activation - Downloader', () => {
let languageServerDownloader: LanguageServerDownloader;
let serviceContainer: TypeMoq.IMock<IServiceContainer>;
let platformService: TypeMoq.IMock<IPlatformService>;
setup(() => {
serviceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
platformService = TypeMoq.Mock.ofType<IPlatformService>();
const fs = TypeMoq.Mock.ofType<IFileSystem>();
const output = TypeMoq.Mock.ofType<IOutputChannel>();

serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IOutputChannel), TypeMoq.It.isAny())).returns(() => output.object);
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IPlatformService))).returns(() => platformService.object);
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IFileSystem))).returns(() => fs.object);

languageServerDownloader = new LanguageServerDownloader(serviceContainer.object, '');
});
type PlatformIdentifier = {
windows?: boolean;
mac?: boolean;
linux?: boolean;
is64Bit?: boolean;
};
function setupPlatform(platform: PlatformIdentifier) {
platformService.setup(x => x.isWindows).returns(() => platform.windows === true);
platformService.setup(x => x.isMac).returns(() => platform.mac === true);
platformService.setup(x => x.isLinux).returns(() => platform.linux === true);
platformService.setup(x => x.is64bit).returns(() => platform.is64Bit === true);
}
test('Windows 32Bit', async () => {
setupPlatform({ windows: true });
const link = await languageServerDownloader.getDownloadUri();
assert.equal(link, `${downloadUriPrefix}/${downloadBaseFileName}-win-x86.${downloadVersion}${downloadFileExtension}`);
});
test('Windows 64Bit', async () => {
setupPlatform({ windows: true, is64Bit: true });
const link = await languageServerDownloader.getDownloadUri();
assert.equal(link, `${downloadUriPrefix}/${downloadBaseFileName}-win-x64.${downloadVersion}${downloadFileExtension}`);
});
test('Mac 64Bit', async () => {
setupPlatform({ mac: true, is64Bit: true });
const link = await languageServerDownloader.getDownloadUri();
assert.equal(link, `${downloadUriPrefix}/${downloadBaseFileName}-osx-x64.${downloadVersion}${downloadFileExtension}`);
});
test('Linux 64Bit', async () => {
setupPlatform({ linux: true, is64Bit: true });
const link = await languageServerDownloader.getDownloadUri();
assert.equal(link, `${downloadUriPrefix}/${downloadBaseFileName}-linux-x64.${downloadVersion}${downloadFileExtension}`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as assert from 'assert';
import * as TypeMoq from 'typemoq';
import { PlatformData } from '../../client/activation/platformData';
import { IFileSystem, IPlatformService } from '../../client/common/platform/types';
import { initialize } from '../initialize';

const testDataWinMac = [
{ isWindows: true, is64Bit: true, expectedName: 'win-x64' },
Expand All @@ -31,8 +30,6 @@ const testDataModuleName = [

// tslint:disable-next-line:max-func-body-length
suite('Activation - platform data', () => {
suiteSetup(initialize);

test('Name and hash (Windows/Mac)', async () => {
for (const t of testDataWinMac) {
const platformService = TypeMoq.Mock.ofType<IPlatformService>();
Expand All @@ -43,11 +40,11 @@ suite('Activation - platform data', () => {
const fs = TypeMoq.Mock.ofType<IFileSystem>();
const pd = new PlatformData(platformService.object, fs.object);

let actual = await pd.getPlatformName();
const actual = await pd.getPlatformName();
assert.equal(actual, t.expectedName, `${actual} does not match ${t.expectedName}`);

actual = await pd.getExpectedHash();
assert.equal(actual, t.expectedName, `${actual} hash not match ${t.expectedName}`);
const actualHash = await pd.getExpectedHash();
assert.equal(actualHash, t.expectedName, `${actual} hash not match ${t.expectedName}`);
}
});
test('Name and hash (Linux)', async () => {
Expand All @@ -62,10 +59,10 @@ suite('Activation - platform data', () => {
fs.setup(x => x.readFile(TypeMoq.It.isAnyString())).returns(() => Promise.resolve(`NAME="name"\nID=${t.name}\nID_LIKE=debian`));
const pd = new PlatformData(platformService.object, fs.object);

let actual = await pd.getPlatformName();
const actual = await pd.getPlatformName();
assert.equal(actual, t.expectedName, `${actual} does not match ${t.expectedName}`);

actual = await pd.getExpectedHash();
const actualHash = await pd.getExpectedHash();
assert.equal(actual, t.expectedName, `${actual} hash not match ${t.expectedName}`);
}
});
Expand Down