Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable multiple download of omnisharp #2065

Merged
merged 16 commits into from
Feb 27, 2018
Merged
Show file tree
Hide file tree
Changes from 8 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
62 changes: 44 additions & 18 deletions package-lock.json

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

20 changes: 13 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"postinstall": "node ./node_modules/vscode/bin/install"
},
"dependencies": {
"chai-as-promised": "^7.1.1",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a dev dependency only?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is automatically added when I npm install the package. What do you think should be changed here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just move this dependency in the devdependecies list and fix it to 7.1.1 instead of compatible versions

"fs-extra": "^5.0.0",
"http-proxy-agent": "^2.0.0",
"https-proxy-agent": "^2.1.1",
Expand Down Expand Up @@ -93,7 +94,8 @@
"architectures": [
"x86"
],
"installTestPath": "./.omnisharp/OmniSharp.exe"
"installTestPath": "./.omnisharp/OmniSharp.exe",
"platformId": "win-x86"
},
{
"description": "OmniSharp for Windows (.NET 4.6 / x64)",
Expand All @@ -106,7 +108,8 @@
"architectures": [
"x86_64"
],
"installTestPath": "./.omnisharp/OmniSharp.exe"
"installTestPath": "./.omnisharp/OmniSharp.exe",
"platformId": "win-x64"
},
{
"description": "OmniSharp for OSX",
Expand All @@ -120,7 +123,8 @@
"./mono.osx",
"./run"
],
"installTestPath": "./.omnisharp/mono.osx"
"installTestPath": "./.omnisharp/mono.osx",
"platformId": "osx"
},
{
"description": "OmniSharp for Linux (x86)",
Expand All @@ -138,7 +142,8 @@
"./mono.linux-x86",
"./run"
],
"installTestPath": "./.omnisharp/mono.linux-x86"
"installTestPath": "./.omnisharp/mono.linux-x86",
"platformId": "linux-x86"
},
{
"description": "OmniSharp for Linux (x64)",
Expand All @@ -155,7 +160,8 @@
"./mono.linux-x86_64",
"./run"
],
"installTestPath": "./.omnisharp/mono.linux-x86_64"
"installTestPath": "./.omnisharp/mono.linux-x86_64",
"platformId": "linux-x64"
},
{
"description": ".NET Core Debugger (Windows / x64)",
Expand Down Expand Up @@ -361,7 +367,7 @@
"null"
],
"default": null,
"description": "Specifies the full path to the OmniSharp server."
"description": "Specifies the path to OmniSharp. This can be the absolute path to an OmniSharp executable, a specific version number, or \"latest\". If a version number or \"latest\" is specified, the appropriate version of OmniSharp will be downloaded on your behalf."
},
"omnisharp.useMono": {
"type": "boolean",
Expand Down Expand Up @@ -2125,4 +2131,4 @@
}
]
}
}
}
79 changes: 79 additions & 0 deletions src/OmnisharpDownload.Helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { Status, PackageError } from './packages';
import { PlatformInformation } from './platform';
import { Logger } from './logger';
import TelemetryReporter from 'vscode-extension-telemetry';

export function GetNetworkDependencies() {
const config = vscode.workspace.getConfiguration();
const proxy = config.get<string>('http.proxy');
const strictSSL = config.get('http.proxyStrictSSL', true);
return { Proxy: proxy, StrictSSL: strictSSL };
}

export function SetStatus() {
let statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
let status: Status = {
setMessage: text => {
statusItem.text = text;
statusItem.show();
},
setDetail: text => {
statusItem.tooltip = text;
statusItem.show();
}
};

return { StatusItem: statusItem, Status: status };
}

export function LogPlatformInformation(logger: Logger, platformInfo: PlatformInformation) {
logger.appendLine(`Platform: ${platformInfo.toString()}`);
logger.appendLine();
}

export function ReportInstallationError(logger: Logger, error, telemetryProps: any, installationStage: string) {
let errorMessage: string;
if (error instanceof PackageError) {
// we can log the message in a PackageError to telemetry as we do not put PII in PackageError messages
telemetryProps['error.message'] = error.message;
if (error.innerError) {
errorMessage = error.innerError.toString();
}
else {
errorMessage = error.message;
}
if (error.pkg) {
telemetryProps['error.packageUrl'] = error.pkg.url;
}
}
else {
// do not log raw errorMessage in telemetry as it is likely to contain PII.
errorMessage = error.toString();
}

logger.appendLine();
logger.appendLine(`Failed at stage: ${installationStage}`);
logger.appendLine(errorMessage);
}

export function SendInstallationTelemetry(logger: Logger, reporter: TelemetryReporter, telemetryProps: any, installationStage: string, platformInfo: PlatformInformation) {
telemetryProps['installStage'] = installationStage;
telemetryProps['platform.architecture'] = platformInfo.architecture;
telemetryProps['platform.platform'] = platformInfo.platform;
if (platformInfo.distribution) {
telemetryProps['platform.distribution'] = platformInfo.distribution.toTelemetryString();
}
if (reporter) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is reporter ever null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think so. But I just followed by the pattern followed by CSharpExtDownloader.

Currently this pattern helps because in testing I am conveniently passing this field as null, but in future we might want to test the Telemetry as well.

For the current PR, I think we can retain this pattern. What do you think ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we can refactor later.

reporter.sendTelemetryEvent('Acquisition', telemetryProps);
}

logger.appendLine();
installationStage = '';
logger.appendLine('Finished');
logger.appendLine();
}
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<{ init
let runtimeDependenciesExist = await ensureRuntimeDependencies(extension, logger, reporter);

// activate language services
let omniSharpPromise = OmniSharp.activate(context, reporter, _channel);
let omniSharpPromise = OmniSharp.activate(context, reporter, _channel, logger, extension.packageJSON);

// register JSON completion & hover providers for project.json
context.subscriptions.push(addJSONProviders());
Expand Down
96 changes: 96 additions & 0 deletions src/omnisharp/OmnisharpDownloader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { PackageManager, Package, Status } from '../packages';
import { PlatformInformation } from '../platform';
import { Logger } from '../logger';
import TelemetryReporter from 'vscode-extension-telemetry';
import { GetPackagesFromVersion, GetVersionFilePackage } from './OmnisharpPackageCreator';
import { SetStatus, LogPlatformInformation, ReportInstallationError, SendInstallationTelemetry, GetNetworkDependencies } from '../OmnisharpDownload.Helper';

export class OmnisharpDownloader {
private status: Status;
private statusItem: vscode.StatusBarItem;
private proxy: string;
private strictSSL: boolean;
private packageManager: PackageManager;
private telemetryProps: any;

public constructor(
private channel: vscode.OutputChannel,
private logger: Logger,
private packageJSON: any,
private platformInfo: PlatformInformation,
private reporter?: TelemetryReporter) {

let statusObject = SetStatus();
this.status = statusObject.Status;
this.statusItem = statusObject.StatusItem;

let networkObject = GetNetworkDependencies();
this.proxy = networkObject.Proxy;
this.strictSSL = networkObject.StrictSSL;

this.telemetryProps = {};
this.packageManager = new PackageManager(this.platformInfo, this.packageJSON);
}

public async DownloadAndInstallOmnisharp(version: string, serverUrl: string, installPath: string) {
this.logger.append('Installing Omnisharp Packages...');
this.logger.appendLine();
this.channel.show();

let installationStage = '';

if (this.reporter) {
this.reporter.sendTelemetryEvent("AcquisitionStart");
}

try {
LogPlatformInformation(this.logger, this.platformInfo);

installationStage = 'getPackageInfo';
let packages: Package[] = GetPackagesFromVersion(version, this.packageJSON.runtimeDependencies, serverUrl, installPath);

installationStage = 'downloadPackages';

// Specify the packages that the package manager needs to download
this.packageManager.SetVersionPackagesForDownload(packages);
await this.packageManager.DownloadPackages(this.logger, this.status, this.proxy, this.strictSSL);

this.logger.appendLine();

installationStage = 'installPackages';
await this.packageManager.InstallPackages(this.logger, this.status);

installationStage = 'completeSuccess';
}
catch (error) {
ReportInstallationError(this.logger, error, this.telemetryProps, installationStage);
throw error;// throw the error up to the server
}
finally {
SendInstallationTelemetry(this.logger, this.reporter, this.telemetryProps, installationStage, this.platformInfo);
this.statusItem.dispose();
}
}

public async GetLatestVersion(serverUrl: string, versionFilePathInServer): Promise<string> {
let installationStage = 'getLatestVersionInfoFile';
try {
this.logger.appendLine('Getting latest build information...');
this.logger.appendLine();
//The package manager needs a package format to download, hence we form a package for the latest version file
let filePackage = GetVersionFilePackage(serverUrl, versionFilePathInServer);
//Fetch the latest version information from the file
return await this.packageManager.GetLatestVersionFromFile(this.logger, this.status, this.proxy, this.strictSSL, filePackage);
}
catch (error) {
ReportInstallationError(this.logger, error, this.telemetryProps, installationStage);
throw error;
}
}
}
Loading