From 01bc4aeb42278a36d15aaaac243ff90ebef9cea2 Mon Sep 17 00:00:00 2001 From: akshita31 Date: Wed, 14 Feb 2018 15:40:07 -0800 Subject: [PATCH 01/12] Enable usage of omnisharp.path option for downloading multiple versions of omnisharp (#2028) * Enable usage of multiple versions * Either load the server from a path or download the version packages * Tests for the package creator * Added null check and removed semver check in package creator * Test for the experiment omnisharp downloader * Added test for package manager * Code clean up * Added null or empty check for version * Changes * Modified the description Put the clean up logic in the teardown function * Remove comment * Remove unnecessary usage * CR comments * Removed experimental * Modified launcher * Removed experimental * Modified tests * Modified package description to include version information * Renamed launch path * Add more tests * Changed the description in package.json --- package-lock.json | 62 ++++-- package.json | 20 +- src/OmnisharpDownload.Helper.ts | 83 ++++++++ src/main.ts | 2 +- src/omnisharp/OmnisharpDownloader.ts | 72 +++++++ src/omnisharp/OmnisharpManager.ts | 68 ++++++ src/omnisharp/OmnisharpPackageCreator.ts | 58 ++++++ src/omnisharp/extension.ts | 5 +- src/omnisharp/launcher.ts | 50 +++-- src/omnisharp/server.ts | 39 +++- src/packages.ts | 19 +- test/unitTests/OmnisharpDownloader.test.ts | 186 +++++++++++++++++ test/unitTests/OmnisharpManager.test.ts | 106 ++++++++++ .../unitTests/OmnisharpPackageCreator.test.ts | 197 ++++++++++++++++++ 14 files changed, 900 insertions(+), 67 deletions(-) create mode 100644 src/OmnisharpDownload.Helper.ts create mode 100644 src/omnisharp/OmnisharpDownloader.ts create mode 100644 src/omnisharp/OmnisharpManager.ts create mode 100644 src/omnisharp/OmnisharpPackageCreator.ts create mode 100644 test/unitTests/OmnisharpDownloader.test.ts create mode 100644 test/unitTests/OmnisharpManager.test.ts create mode 100644 test/unitTests/OmnisharpPackageCreator.test.ts diff --git a/package-lock.json b/package-lock.json index 878983cb6..b8ee77a4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "csharp", - "version": "1.14.0-beta2", + "version": "1.14.0-beta3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -93,11 +93,6 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, - "applicationinsights": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-0.18.0.tgz", - "integrity": "sha1-Fi67SKODQIvE3kTbMrQXMH9Fu8E=" - }, "archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", @@ -397,6 +392,14 @@ "integrity": "sha512-jWAvZu1BV8tL3pj0iosBECzzHEg+XB1zSnMjJGX83bGi/1GlGdDO7J/A0sbBBS6KJT0FVqZIzZW9C6WLiMkHpQ==", "dev": true }, + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "requires": { + "check-error": "1.0.2" + } + }, "chai-fs": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chai-fs/-/chai-fs-2.0.0.tgz", @@ -423,8 +426,7 @@ "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" }, "cheerio": { "version": "1.0.0-rc.2", @@ -697,6 +699,19 @@ "fs-exists-sync": "0.1.0" } }, + "diagnostic-channel": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz", + "integrity": "sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc=", + "requires": { + "semver": "5.4.1" + } + }, + "diagnostic-channel-publishers": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz", + "integrity": "sha1-ji1geottef6IC1SLxYzGvrKIxPM=" + }, "diff": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", @@ -5127,12 +5142,23 @@ "integrity": "sha512-e1EUy/5npqa0NlAwRCUu8A9LnVRf6tkwiPQcCLyUFCC9o2GxcAqH5Va4mqXDoxQ58ar3zODivKQeRb3z1KH7WA==" }, "vscode-extension-telemetry": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.8.tgz", - "integrity": "sha1-ImG/+Ya2aQpvH3RqRaxb0fhdKeA=", + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.11.tgz", + "integrity": "sha512-P1ALLofywtfpQy9TB5Sx2edp80fHXby+CGG5pq8P1vPL2zKIUjYy3eK8mFHCOGeljTf2PTTmXJ98DeBV0kCafQ==", "requires": { - "applicationinsights": "0.18.0", - "winreg": "1.2.3" + "applicationinsights": "1.0.1" + }, + "dependencies": { + "applicationinsights": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-1.0.1.tgz", + "integrity": "sha1-U0Rrgw/o1dYZ7uKieLMdPSUDCSc=", + "requires": { + "diagnostic-channel": "0.2.0", + "diagnostic-channel-publishers": "0.2.1", + "zone.js": "0.7.6" + } + } } }, "vscode-nls": { @@ -5161,11 +5187,6 @@ "isexe": "2.0.0" } }, - "winreg": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.3.tgz", - "integrity": "sha1-k60RayaW2ofVj3JlqPzqUlSpZdU=" - }, "wolfy87-eventemitter": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.4.tgz", @@ -5219,6 +5240,11 @@ "requires": { "buffer-crc32": "0.2.13" } + }, + "zone.js": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.7.6.tgz", + "integrity": "sha1-+7w50+AmHQmG8boGMG6zrrDSIAk=" } } } diff --git a/package.json b/package.json index 74d13546f..a1e69404f 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "postinstall": "node ./node_modules/vscode/bin/install" }, "dependencies": { + "chai-as-promised": "^7.1.1", "fs-extra": "^5.0.0", "http-proxy-agent": "^2.0.0", "https-proxy-agent": "^2.1.1", @@ -93,7 +94,8 @@ "architectures": [ "x86" ], - "installTestPath": "./.omnisharp/OmniSharp.exe" + "installTestPath": "./.omnisharp/OmniSharp.exe", + "experimentalPackageId": "win-x86" }, { "description": "OmniSharp for Windows (.NET 4.6 / x64)", @@ -106,7 +108,8 @@ "architectures": [ "x86_64" ], - "installTestPath": "./.omnisharp/OmniSharp.exe" + "installTestPath": "./.omnisharp/OmniSharp.exe", + "experimentalPackageId": "win-x64" }, { "description": "OmniSharp for OSX", @@ -120,7 +123,8 @@ "./mono.osx", "./run" ], - "installTestPath": "./.omnisharp/mono.osx" + "installTestPath": "./.omnisharp/mono.osx", + "experimentalPackageId": "osx" }, { "description": "OmniSharp for Linux (x86)", @@ -138,7 +142,8 @@ "./mono.linux-x86", "./run" ], - "installTestPath": "./.omnisharp/mono.linux-x86" + "installTestPath": "./.omnisharp/mono.linux-x86", + "experimentalPackageId": "linux-x86" }, { "description": "OmniSharp for Linux (x64)", @@ -155,7 +160,8 @@ "./mono.linux-x86_64", "./run" ], - "installTestPath": "./.omnisharp/mono.linux-x86_64" + "installTestPath": "./.omnisharp/mono.linux-x86_64", + "experimentalPackageId": "linux-x64" }, { "description": ".NET Core Debugger (Windows / x64)", @@ -361,7 +367,7 @@ "null" ], "default": null, - "description": "Specifies the full path to the OmniSharp server." + "description": "Specifies how to acquire the OmniSharp to use. Can be one of \"latest\", a specific version number, or the absolute path to a local OmniSharp folder." }, "omnisharp.useMono": { "type": "boolean", @@ -2125,4 +2131,4 @@ } ] } -} \ No newline at end of file +} diff --git a/src/OmnisharpDownload.Helper.ts b/src/OmnisharpDownload.Helper.ts new file mode 100644 index 000000000..1fcb7326e --- /dev/null +++ b/src/OmnisharpDownload.Helper.ts @@ -0,0 +1,83 @@ +/*--------------------------------------------------------------------------------------------- +* 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, Status, PackageError, Package } from './packages'; +import { PlatformInformation } from './platform'; +import { Logger } from './logger'; +import TelemetryReporter from 'vscode-extension-telemetry'; + +export async function GetDependenciesAndDownloadPackages(packages: Package[], status: Status, platformInfo: PlatformInformation, packageManager: PackageManager, logger: Logger) { + const config = vscode.workspace.getConfiguration(); + const proxy = config.get('http.proxy'); + const strictSSL = config.get('http.proxyStrictSSL', true); + await packageManager.DownloadPackages(logger, status, proxy, 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 async function GetAndLogPlatformInformation(logger: Logger): Promise { + let platformInfo = await PlatformInformation.GetCurrent(); + + logger.appendLine(`Platform: ${platformInfo.toString()}`); + logger.appendLine(); + + return platformInfo; +} + +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(`Failed at stage: ${installationStage}`); + logger.appendLine(errorMessage); +} + +export function SendInstallationTelemetry(logger: Logger, reporter: TelemetryReporter, telemetryProps: any, installationStage: string, platformInfo: PlatformInformation, statusItem: vscode.StatusBarItem) { + telemetryProps['installStage'] = installationStage; + telemetryProps['platform.architecture'] = platformInfo.architecture; + telemetryProps['platform.platform'] = platformInfo.platform; + if (platformInfo.distribution) { + telemetryProps['platform.distribution'] = platformInfo.distribution.toTelemetryString(); + } + if (reporter) { + reporter.sendTelemetryEvent('Acquisition', telemetryProps); + } + + logger.appendLine(); + installationStage = ''; + logger.appendLine('Finished'); + + statusItem.dispose(); +} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 7301d7904..ac6ffe997 100644 --- a/src/main.ts +++ b/src/main.ts @@ -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()); diff --git a/src/omnisharp/OmnisharpDownloader.ts b/src/omnisharp/OmnisharpDownloader.ts new file mode 100644 index 000000000..356aeb617 --- /dev/null +++ b/src/omnisharp/OmnisharpDownloader.ts @@ -0,0 +1,72 @@ +/*--------------------------------------------------------------------------------------------- + * 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 } from '../packages'; +import { PlatformInformation } from '../platform'; +import { Logger } from '../logger'; +import TelemetryReporter from 'vscode-extension-telemetry'; +import { GetPackagesFromVersion } from './OmnisharpPackageCreator'; +import { GetDependenciesAndDownloadPackages, SetStatus, GetAndLogPlatformInformation, ReportInstallationError, SendInstallationTelemetry } from '../OmnisharpDownload.Helper'; + +export class OmnisharpDownloader { + public constructor( + private channel: vscode.OutputChannel, + private logger: Logger, + private packageJSON: any, + private reporter?: TelemetryReporter) { + } + + public async DownloadAndInstallOmnisharp(version: string, serverUrl: string, installPath: string) { + if (!version) { + throw new Error('Invalid version'); + } + + this.logger.append('Installing Omnisharp Packages...'); + this.logger.appendLine(); + this.channel.show(); + + let statusObject = SetStatus(); + let status = statusObject.Status; + let statusItem = statusObject.StatusItem; + + let telemetryProps: any = {}; + let installationStage = ''; + let platformInfo: PlatformInformation; + + if (this.reporter) { + this.reporter.sendTelemetryEvent("AcquisitionStart"); + } + + try { + installationStage = 'getPlatformInfo'; + platformInfo = await GetAndLogPlatformInformation(this.logger); + + installationStage = 'getPackageInfo'; + let packages: Package[] = GetPackagesFromVersion(version, this.packageJSON.runtimeDependencies, serverUrl, installPath); + + installationStage = 'downloadPackages'; + let packageManager = new PackageManager(platformInfo, this.packageJSON); + // Specify the packages that the package manager needs to download + packageManager.SetVersionPackagesForDownload(packages); + await GetDependenciesAndDownloadPackages(packages,status, platformInfo, packageManager, this.logger); + + this.logger.appendLine(); + + installationStage = 'installPackages'; + await packageManager.InstallPackages(this.logger, status); + + installationStage = 'completeSuccess'; + } + + catch (error) { + ReportInstallationError(this.logger, error, telemetryProps, installationStage); + throw error;// throw the error up to the server + } + finally { + SendInstallationTelemetry(this.logger, this.reporter, telemetryProps, installationStage, platformInfo, statusItem); + } + } +} diff --git a/src/omnisharp/OmnisharpManager.ts b/src/omnisharp/OmnisharpManager.ts new file mode 100644 index 000000000..61dff1ec0 --- /dev/null +++ b/src/omnisharp/OmnisharpManager.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as util from '../common'; +import * as path from 'path'; +import * as semver from 'semver'; +import * as vscode from 'vscode'; +import { Logger } from '../logger'; +import { OmnisharpDownloader } from './OmnisharpDownloader'; +import TelemetryReporter from 'vscode-extension-telemetry'; +import { PlatformInformation } from '../platform'; + +export class OmnisharpManager { + public constructor( + private channel: vscode.OutputChannel, + private logger: Logger, + private packageJSON: any, + private reporter?: TelemetryReporter) { + } + + public async GetOmnisharpPath(omnisharpPath: string, useMono: boolean, serverUrl: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation): Promise { + // Looks at the options path, installs the dependencies and returns the path to be loaded by the omnisharp server + // To Do : Add the functionality for the latest option + + if (path.isAbsolute(omnisharpPath)) { + if (await util.fileExists(omnisharpPath)) { + return omnisharpPath; + } + else { + throw new Error('Invalid path specified'); + } + } + //If the path is not a valid path on disk, treat it as a version + return await this.InstallVersionAndReturnLaunchPath(omnisharpPath, useMono, serverUrl, installPath, extensionPath, platformInfo); + } + + public async InstallVersionAndReturnLaunchPath(version: string, useMono: boolean, serverUrl: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { + if (semver.valid(version)) { + let downloader = new OmnisharpDownloader(this.channel, this.logger, this.packageJSON, this.reporter); + await downloader.DownloadAndInstallOmnisharp(version, serverUrl, installPath); + + return await GetLaunchPathForVersion(platformInfo, version, installPath, extensionPath, useMono); + } + else { + throw new Error('Invalid omnisharp version specified'); + } + } +} + +export async function GetLaunchPathForVersion(platformInfo: PlatformInformation, version: string, installPath: string, extensionPath: string, useMono: boolean) { + if (!version) { + throw new Error('Invalid Version'); + } + + let basePath = path.resolve(extensionPath, installPath, version); + + if (platformInfo.isWindows()) { + return path.join(basePath, 'OmniSharp.exe'); + } + if (useMono) { + return path.join(basePath, 'omnisharp', 'OmniSharp.exe'); + } + + return path.join(basePath, 'run'); +} + diff --git a/src/omnisharp/OmnisharpPackageCreator.ts b/src/omnisharp/OmnisharpPackageCreator.ts new file mode 100644 index 000000000..66fe6abeb --- /dev/null +++ b/src/omnisharp/OmnisharpPackageCreator.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Package } from "../packages"; + +export function GetPackagesFromVersion(version: string, runTimeDependencies: Package[], serverUrl: string, installPath: string): Package[] { + if (!version) { + throw new Error('Invalid version'); + } + + let versionPackages = new Array(); + for (let inputPackage of runTimeDependencies) { + if (inputPackage.experimentalPackageId) { + versionPackages.push(GetOmnisharpPackage(inputPackage, serverUrl, version, installPath)); + } + } + + return versionPackages; +} + +export function GetOmnisharpPackage(inputPackage: Package, serverUrl: string, version: string, installPath: string): Package { + let installBinary: string; + if (inputPackage.experimentalPackageId == "win-x86" || inputPackage.experimentalPackageId == "win-x64") { + installBinary = "OmniSharp.exe"; + } + else if (inputPackage.experimentalPackageId == "osx") { + installBinary = "mono.osx"; + } + else if (inputPackage.experimentalPackageId == "linux-x86") { + installBinary = "mono.linux-x86"; + } + else if (inputPackage.experimentalPackageId == "linux-x64") { + installBinary = "mono.linux-x86_64"; + } + + return GetPackageFromArchitecture(inputPackage, serverUrl, version, inputPackage.experimentalPackageId, installPath, installBinary); +} + +function GetPackageFromArchitecture(inputPackage: Package, serverUrl: string, version: string, architectureInfo: string, installPath: string, installBinary: string): Package { + if (!version) { + throw new Error('Invalid version'); + } + + let versionPackage = { + "description": `${inputPackage.description}, Version = ${version}`, + "url": `${serverUrl}/releases/${version}/omnisharp-${architectureInfo}.zip`, + "installPath": `${installPath}/${version}`, + "platforms": inputPackage.platforms, + "architectures": inputPackage.architectures, + "binaries": inputPackage.binaries, + "installTestPath": `./${installPath}/${version}/${installBinary}`, + "experimentalPackageId": architectureInfo + }; + + return versionPackage; +} \ No newline at end of file diff --git a/src/omnisharp/extension.ts b/src/omnisharp/extension.ts index 968b836b4..9c0301f73 100644 --- a/src/omnisharp/extension.ts +++ b/src/omnisharp/extension.ts @@ -32,10 +32,11 @@ import WorkspaceSymbolProvider from '../features/workspaceSymbolProvider'; import forwardChanges from '../features/changeForwarding'; import registerCommands from '../features/commands'; import reportStatus from '../features/status'; +import { Logger } from '../logger'; export let omnisharp: OmniSharpServer; -export function activate(context: vscode.ExtensionContext, reporter: TelemetryReporter, channel: vscode.OutputChannel) { +export function activate(context: vscode.ExtensionContext, reporter: TelemetryReporter, channel: vscode.OutputChannel, logger: Logger, packageJSON: any) { const documentSelector: vscode.DocumentSelector = { language: 'csharp', scheme: 'file' // only files from disk @@ -43,7 +44,7 @@ export function activate(context: vscode.ExtensionContext, reporter: TelemetryRe const options = Options.Read(); - const server = new OmniSharpServer(reporter); + const server = new OmniSharpServer(reporter, logger, channel, packageJSON); omnisharp = server; const advisor = new Advisor(server); // create before server is started const disposables: vscode.Disposable[] = []; diff --git a/src/omnisharp/launcher.ts b/src/omnisharp/launcher.ts index 2a70ac273..3c00a6bdb 100644 --- a/src/omnisharp/launcher.ts +++ b/src/omnisharp/launcher.ts @@ -46,7 +46,7 @@ export function findLaunchTargets(): Thenable { const options = Options.Read(); return vscode.workspace.findFiles( - /*include*/ '{**/*.sln,**/*.csproj,**/project.json,**/*.csx,**/*.cake}', + /*include*/ '{**/*.sln,**/*.csproj,**/project.json,**/*.csx,**/*.cake}', /*exclude*/ '{**/node_modules/**,**/.git/**,**/bower_components/**}', /*maxResults*/ options.maxProjectResults) .then(resourcesToLaunchTargets); @@ -88,8 +88,7 @@ function resourcesToLaunchTargets(resources: vscode.Uri[]): LaunchTarget[] { let targets: LaunchTarget[] = []; - workspaceFolderToUriMap.forEach((resources, folderIndex) => - { + workspaceFolderToUriMap.forEach((resources, folderIndex) => { let hasCsProjFiles = false, hasSlnFile = false, hasProjectJson = false, @@ -98,15 +97,15 @@ function resourcesToLaunchTargets(resources: vscode.Uri[]): LaunchTarget[] { hasCake = false; hasCsProjFiles = resources.some(isCSharpProject); - + let folder = vscode.workspace.workspaceFolders[folderIndex]; let folderPath = folder.uri.fsPath; - + resources.forEach(resource => { // Add .sln files if there are .csproj files if (hasCsProjFiles && isSolution(resource)) { hasSlnFile = true; - + targets.push({ label: path.basename(resource.fsPath), description: vscode.workspace.asRelativePath(path.dirname(resource.fsPath)), @@ -115,13 +114,13 @@ function resourcesToLaunchTargets(resources: vscode.Uri[]): LaunchTarget[] { kind: LaunchTargetKind.Solution }); } - + // Add project.json files if (isProjectJson(resource)) { const dirname = path.dirname(resource.fsPath); hasProjectJson = true; hasProjectJsonAtRoot = hasProjectJsonAtRoot || dirname === folderPath; - + targets.push({ label: path.basename(resource.fsPath), description: vscode.workspace.asRelativePath(path.dirname(resource.fsPath)), @@ -130,18 +129,18 @@ function resourcesToLaunchTargets(resources: vscode.Uri[]): LaunchTarget[] { kind: LaunchTargetKind.ProjectJson }); } - + // Discover if there is any CSX file if (!hasCSX && isCsx(resource)) { hasCSX = true; } - + // Discover if there is any Cake file if (!hasCake && isCake(resource)) { hasCake = true; } }); - + // Add the root folder under the following circumstances: // * If there are .csproj files, but no .sln file, and none in the root. // * If there are project.json files, but none in the root. @@ -154,7 +153,7 @@ function resourcesToLaunchTargets(resources: vscode.Uri[]): LaunchTarget[] { kind: LaunchTargetKind.Folder }); } - + // if we noticed any CSX file(s), add a single CSX-specific target pointing at the root folder if (hasCSX) { targets.push({ @@ -165,7 +164,7 @@ function resourcesToLaunchTargets(resources: vscode.Uri[]): LaunchTarget[] { kind: LaunchTargetKind.Csx }); } - + // if we noticed any Cake file(s), add a single Cake-specific target pointing at the root folder if (hasCake) { targets.push({ @@ -207,9 +206,9 @@ export interface LaunchResult { usingMono: boolean; } -export function launchOmniSharp(cwd: string, args: string[]): Promise { +export function launchOmniSharp(cwd: string, args: string[], launchPath: string): Promise { return new Promise((resolve, reject) => { - launch(cwd, args) + launch(cwd, args, launchPath) .then(result => { // async error - when target not not ENEOT result.process.on('error', err => { @@ -225,12 +224,11 @@ export function launchOmniSharp(cwd: string, args: string[]): Promise { +function launch(cwd: string, args: string[], launchPath: string): Promise { return PlatformInformation.GetCurrent().then(platformInfo => { const options = Options.Read(); - if (options.useEditorFormattingSettings) - { + if (options.useEditorFormattingSettings) { let globalConfig = vscode.workspace.getConfiguration(); let csharpConfig = vscode.workspace.getConfiguration('[csharp]'); @@ -239,18 +237,18 @@ function launch(cwd: string, args: string[]): Promise { args.push(`formattingOptions:indentationSize=${getConfigurationValue(globalConfig, csharpConfig, 'editor.tabSize', 4)}`); } - // If the user has provide a path to OmniSharp, we'll use that. - if (options.path) { + // If the user has provided an absolute path or the specified version has been installed successfully, we'll use the path. + if (launchPath) { if (platformInfo.isWindows()) { - return launchWindows(options.path, cwd, args); + return launchWindows(launchPath, cwd, args); } // If we're launching on macOS/Linux, we have two possibilities: // 1. Launch using Mono // 2. Launch process directly (e.g. a 'run' script) return options.useMono - ? launchNixMono(options.path, cwd, args) - : launchNix(options.path, cwd, args); + ? launchNixMono(launchPath, cwd, args) + : launchNix(launchPath, cwd, args); } // If the user has not provided a path, we'll use the locally-installed OmniSharp @@ -274,11 +272,11 @@ function launch(cwd: string, args: string[]): Promise { function getConfigurationValue(globalConfig: vscode.WorkspaceConfiguration, csharpConfig: vscode.WorkspaceConfiguration, configurationPath: string, defaultValue: any): any { - + if (csharpConfig[configurationPath] != undefined) { return csharpConfig[configurationPath]; } - + return globalConfig.get(configurationPath, defaultValue); } @@ -287,7 +285,7 @@ function launchWindows(launchPath: string, cwd: string, args: string[]): LaunchR const hasSpaceWithoutQuotes = /^[^"].* .*[^"]/; return hasSpaceWithoutQuotes.test(arg) ? `"${arg}"` - : arg.replace("&","^&"); + : arg.replace("&", "^&"); } let argsCopy = args.slice(0); // create copy of args diff --git a/src/omnisharp/server.ts b/src/omnisharp/server.ts index bd3b9c8a9..5c62d14e7 100644 --- a/src/omnisharp/server.ts +++ b/src/omnisharp/server.ts @@ -19,6 +19,8 @@ import * as protocol from './protocol'; import * as utils from '../common'; import * as vscode from 'vscode'; import { setTimeout } from 'timers'; +import { OmnisharpManager } from './OmnisharpManager'; +import { PlatformInformation } from '../platform'; enum ServerState { Starting, @@ -82,7 +84,11 @@ export class OmniSharpServer { private _serverProcess: ChildProcess; private _options: Options; - constructor(reporter: TelemetryReporter) { + private _csharpLogger: Logger; + private _csharpChannel: vscode.OutputChannel; + private _packageJSON: any; + + constructor(reporter: TelemetryReporter, csharpLogger?: Logger, csharpChannel?: vscode.OutputChannel, packageJSON?: any) { this._reporter = reporter; this._channel = vscode.window.createOutputChannel('OmniSharp Log'); @@ -93,17 +99,20 @@ export class OmniSharpServer { : new Logger(message => { }); this._requestQueue = new RequestQueueCollection(logger, 8, request => this._makeRequest(request)); + this._csharpLogger = csharpLogger; + this._csharpChannel = csharpChannel; + this._packageJSON = packageJSON; } public isRunning(): boolean { return this._state === ServerState.Started; } - public async waitForEmptyEventQueue() : Promise { + public async waitForEmptyEventQueue(): Promise { while (!this._requestQueue.isEmpty()) { let p = new Promise((resolve) => setTimeout(resolve, 100)); await p; - } + } } private _getState(): ServerState { @@ -238,14 +247,14 @@ export class OmniSharpServer { // --- start, stop, and connect - private _start(launchTarget: LaunchTarget): Promise { + private async _start(launchTarget: LaunchTarget): Promise { this._setState(ServerState.Starting); this._launchTarget = launchTarget; const solutionPath = launchTarget.target; const cwd = path.dirname(solutionPath); this._options = Options.Read(); - + let args = [ '-s', solutionPath, '--hostPID', process.pid.toString(), @@ -259,6 +268,24 @@ export class OmniSharpServer { args.push('--debug'); } + let launchPath: string; + if (this._options.path) { + try { + let serverUrl = "https://roslynomnisharp.blob.core.windows.net"; + let installPath = ".omnisharp/experimental"; + let extensionPath = utils.getExtensionPath(); + let manager = new OmnisharpManager(this._csharpChannel, this._csharpLogger, this._packageJSON, this._reporter); + let platformInfo = await PlatformInformation.GetCurrent(); + launchPath = await manager.GetOmnisharpPath(this._options.path, this._options.useMono, serverUrl, installPath, extensionPath, platformInfo); + } + catch (error) { + this._logger.appendLine('Error occured in loading omnisharp from omnisharp.path'); + this._logger.appendLine(`Could not start the server due to ${error.toString()}`); + this._logger.appendLine(); + return; + } + } + this._logger.appendLine(`Starting OmniSharp server at ${new Date().toLocaleString()}`); this._logger.increaseIndent(); this._logger.appendLine(`Target: ${solutionPath}`); @@ -267,7 +294,7 @@ export class OmniSharpServer { this._fireEvent(Events.BeforeServerStart, solutionPath); - return launchOmniSharp(cwd, args).then(value => { + return launchOmniSharp(cwd, args, launchPath).then(value => { if (value.usingMono) { this._logger.appendLine(`OmniSharp server started wth Mono`); } diff --git a/src/packages.ts b/src/packages.ts index 2e3592d35..a5e15d197 100644 --- a/src/packages.ts +++ b/src/packages.ts @@ -24,6 +24,7 @@ export interface Package { architectures: string[]; binaries: string[]; tmpFile: tmp.SynchrounousResult; + experimentalPackageId?: string; // Path to use to test if the package has already been installed installTestPath?: string; @@ -36,9 +37,9 @@ export interface Status { export class PackageError extends Error { // Do not put PII (personally identifiable information) in the 'message' field as it will be logged to telemetry - constructor(public message: string, - public pkg: Package = null, - public innerError: any = null) { + constructor(public message: string, + public pkg: Package = null, + public innerError: any = null) { super(message); } } @@ -107,6 +108,10 @@ export class PackageManager { }); }); } + + public SetVersionPackagesForDownload(packages: Package[]) { + this.allPackages = packages; + } } function getBaseInstallPath(pkg: Package): string { @@ -139,7 +144,7 @@ function downloadPackage(pkg: Package, logger: Logger, status: Status, proxy: st status = status || getNoopStatus(); logger.append(`Downloading package '${pkg.description}' `); - + status.setMessage("$(cloud-download) Downloading packages"); status.setDetail(`Downloading package '${pkg.description}'...`); @@ -199,7 +204,7 @@ function downloadFile(urlString: string, pkg: Package, logger: Logger, status: S logger.appendLine(`failed (error code '${response.statusCode}')`); return reject(new PackageError(response.statusCode.toString(), pkg)); } - + // Downloading - hook up events let packageSize = parseInt(response.headers['content-length'], 10); let downloadedBytes = 0; @@ -338,7 +343,7 @@ function installPackage(pkg: Package, logger: Logger, status?: Status): Promise< }); } -function doesPackageTestPathExist(pkg: Package) : Promise { +function doesPackageTestPathExist(pkg: Package): Promise { const testPath = getPackageTestPath(pkg); if (testPath) { return util.fileExists(testPath); @@ -347,7 +352,7 @@ function doesPackageTestPathExist(pkg: Package) : Promise { } } -function getPackageTestPath(pkg: Package) : string { +function getPackageTestPath(pkg: Package): string { if (pkg.installTestPath) { return path.join(util.getExtensionPath(), pkg.installTestPath); } else { diff --git a/test/unitTests/OmnisharpDownloader.test.ts b/test/unitTests/OmnisharpDownloader.test.ts new file mode 100644 index 000000000..84678cd49 --- /dev/null +++ b/test/unitTests/OmnisharpDownloader.test.ts @@ -0,0 +1,186 @@ +/*--------------------------------------------------------------------------------------------- + * 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 * as path from 'path'; +import * as util from '../../src/common'; +import { should } from 'chai'; +import { Logger } from '../../src/logger'; +import { OmnisharpDownloader } from '../../src/omnisharp/OmnisharpDownloader'; +import { rimraf } from 'async-file'; + +const tmp = require('tmp'); +const chai = require("chai"); +chai.use(require("chai-as-promised")); +let expect = chai.expect; + +suite("DownloadAndInstallExperimentalVersion : Gets the version packages, downloads and installs them", () => { + let tmpDir = null; + const version = "1.2.3"; + const downloader = GetOmnisharpDownloader(); + const serverUrl = "https://roslynomnisharp.blob.core.windows.net"; + const installPath = ".omnisharp/experimental/"; + + setup(() => { + tmpDir = tmp.dirSync(); + util.setExtensionPath(tmpDir.name); + }); + + test('Throws error if version is null', () => { + expect(downloader.DownloadAndInstallOmnisharp(null, serverUrl, installPath)).to.be.rejectedWith(Error); + }); + + test('Throws error if version is empty string', () => { + expect(downloader.DownloadAndInstallOmnisharp("", serverUrl, installPath)).to.be.rejectedWith(Error); + }); + + test('Throws error if request is made for a version that doesnot exist on the server', () => { + expect(downloader.DownloadAndInstallOmnisharp("1.00000001.0000", serverUrl, installPath)).to.be.rejectedWith(Error); + }); + + test('Packages are downloaded from the specified server url and installed at the specified path', async () => { + /* Download a test package that conatins a install_check_1.2.3.txt file and check whether the + file appears at the expected path */ + await downloader.DownloadAndInstallOmnisharp(version, serverUrl, installPath); + let exists = await util.fileExists(path.resolve(tmpDir.name, installPath, version, `install_check_1.2.3.txt`)); + exists.should.equal(true); + }); + + teardown(async () => { + if (tmpDir) { + await rimraf(tmpDir.name); + } + + tmpDir = null; + }); +}); + +function GetOmnisharpDownloader() { + let channel = vscode.window.createOutputChannel('Experiment Channel'); + let logger = new Logger(text => channel.append(text)); + return new OmnisharpDownloader(channel, logger, GetTestPackageJSON(), null); +} + +//Since we need only the runtime dependencies of packageJSON for the downloader create a testPackageJSON +//with just that +export function GetTestPackageJSON() { + let testpackageJSON = { + "runtimeDependencies": [ + { + "description": "OmniSharp for Windows (.NET 4.6 / x86)", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505823/5804b7d3b5eeb7e4ae812a7cff03bd52/omnisharp-win-x86-1.28.0.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-win-x86-1.28.0.zip", + "installPath": ".omnisharp", + "platforms": [ + "win32" + ], + "architectures": [ + "x86" + ], + "installTestPath": "./.omnisharp/OmniSharp.exe", + "experimentalPackageId": "win-x86" + }, + { + "description": "OmniSharp for Windows (.NET 4.6 / x64)", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505821/c570a9e20dbf7172f79850babd058872/omnisharp-win-x64-1.28.0.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-win-x64-1.28.0.zip", + "installPath": ".omnisharp", + "platforms": [ + "win32" + ], + "architectures": [ + "x86_64" + ], + "installTestPath": "./.omnisharp/OmniSharp.exe", + "experimentalPackageId": "win-x64" + }, + { + "description": "OmniSharp for OSX", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505818/6b99c6a86da3221919158ca0f36a3e45/omnisharp-osx-1.28.0.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-osx-1.28.0.zip", + "installPath": ".omnisharp", + "platforms": [ + "darwin" + ], + "binaries": [ + "./mono.osx", + "./run" + ], + "installTestPath": "./.omnisharp/mono.osx", + "experimentalPackageId": "osx" + }, + { + "description": "OmniSharp for Linux (x86)", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505817/b710ec9c2bedc0cfdb57da82da166c47/omnisharp-linux-x86-1.28.0.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-linux-x86-1.28.0.zip", + "installPath": ".omnisharp", + "platforms": [ + "linux" + ], + "architectures": [ + "x86", + "i686" + ], + "binaries": [ + "./mono.linux-x86", + "./run" + ], + "installTestPath": "./.omnisharp/mono.linux-x86", + "experimentalPackageId": "linux-x86" + }, + { + "description": "OmniSharp for Linux (x64)", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505485/3f8a10409240decebb8a3189429f3fdf/omnisharp-linux-x64-1.28.0.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-linux-x64-1.28.0.zip", + "installPath": ".omnisharp", + "platforms": [ + "linux" + ], + "architectures": [ + "x86_64" + ], + "binaries": [ + "./mono.linux-x86_64", + "./run" + ], + "installTestPath": "./.omnisharp/mono.linux-x86_64", + "experimentalPackageId": "linux-x64" + }, + { + "description": "OmniSharp for Test OS(architecture)", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505485/3f8a10409240decebb8a3189429f3fdf/omnisharp-os-architecture-version.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-os-architecture-version.zip", + "installPath": ".omnisharp", + "platforms": [ + "platform1" + ], + "architectures": [ + "architecture" + ], + "binaries": [ + "./binary1", + "./binary2" + ], + "installTestPath": "./.omnisharp/binary", + "experimentalPackageId": "os-architecture" + }, + { + "description": "Non omnisharp package without experimentalPackageID", + "url": "https://download.visualstudio.microsoft.com/download/pr/100317420/a30d7e11bc435433d297adc824ee837f/coreclr-debug-win7-x64.zip", + "fallbackUrl": "https://vsdebugger.blob.core.windows.net/coreclr-debug-1-14-4/coreclr-debug-win7-x64.zip", + "installPath": ".debugger", + "platforms": [ + "win32" + ], + "architectures": [ + "x86_64" + ], + "installTestPath": "./.debugger/vsdbg-ui.exe" + } + ] + }; + + return testpackageJSON; +} diff --git a/test/unitTests/OmnisharpManager.test.ts b/test/unitTests/OmnisharpManager.test.ts new file mode 100644 index 000000000..1593baec7 --- /dev/null +++ b/test/unitTests/OmnisharpManager.test.ts @@ -0,0 +1,106 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'path'; +import * as vscode from 'vscode'; +import * as util from '../../src/common'; +import { should } from "chai"; +import { PlatformInformation } from "../../src/platform"; +import { Logger } from '../../src/logger'; +import { rimraf } from 'async-file'; +import { GetTestPackageJSON } from './OmnisharpDownloader.test'; +import { GetLaunchPathForVersion, OmnisharpManager } from '../../src/omnisharp/OmnisharpManager'; + +const chai = require("chai"); +chai.use(require("chai-as-promised")); +let expect = chai.expect; + +const tmp = require('tmp'); + +suite('GetExperimentalOmnisharpPath : Returns Omnisharp experiment path depending on the path and useMono option', () => { + const platformInfo = new PlatformInformation("win32", "x86"); + const serverUrl = "https://roslynomnisharp.blob.core.windows.net"; + const installPath = ".omnisharp/experimental"; + const useMono = false; + const manager = GetTestOmnisharpManager(); + let extensionPath: string; + let tmpDir: any; + let tmpFile: any; + + suiteSetup(() => should()); + + setup(() => { + tmpDir = tmp.dirSync(); + extensionPath = tmpDir.name; + util.setExtensionPath(tmpDir.name); + }); + + test('Throws error if the path is neither an absolute path nor a valid semver', async () => { + expect(manager.GetOmnisharpPath("Some incorrect path", useMono, serverUrl, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); + }); + + test('Throws error when the specified path is null', async () => { + expect(manager.GetOmnisharpPath(null, useMono, serverUrl, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); + }); + + test('Throws error when the specified path is empty', async () => { + expect(manager.GetOmnisharpPath("", useMono, serverUrl, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); + }); + + test('Throws error when the specified path is an invalid semver', async () => { + expect(manager.GetOmnisharpPath("a.b.c", useMono, serverUrl, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); + }); + + test('Returns the same path if absolute path to an existing file is passed', async () => { + tmpFile = tmp.fileSync(); + let omnisharpPath = await manager.GetOmnisharpPath(tmpFile.name, useMono, serverUrl, installPath, extensionPath, platformInfo); + omnisharpPath.should.equal(tmpFile.name); + }); + + test('Installs the test version and returns the launch path based on the version and platform', async () => { + let omnisharpPath = await manager.GetOmnisharpPath("1.2.3", useMono, serverUrl, installPath, extensionPath, platformInfo); + omnisharpPath.should.equal(path.resolve(extensionPath, `.omnisharp/experimental/1.2.3/OmniSharp.exe`)); + }); + + test('Downloads package from given url and installs them at the specified path', async () => { + let launchPath = await manager.GetOmnisharpPath("1.2.3", useMono, serverUrl, installPath, extensionPath, platformInfo); + let exists = await util.fileExists(path.resolve(extensionPath, `.omnisharp/experimental/1.2.3/install_check_1.2.3.txt`)); + exists.should.equal(true); + }); + + test('Downloads package and returns launch path based on platform - Not using mono on Linux ', async () => { + let launchPath = await manager.GetOmnisharpPath("1.2.3", useMono, serverUrl, installPath, extensionPath, new PlatformInformation("linux", "x64")); + launchPath.should.equal(path.resolve(extensionPath, '.omnisharp/experimental/1.2.3/run')); + }); + + test('Downloads package and returns launch path based on platform - Using mono on Linux ', async () => { + let launchPath = await manager.InstallVersionAndReturnLaunchPath("1.2.3", true, serverUrl, installPath, extensionPath, new PlatformInformation("linux", "x64")); + launchPath.should.equal(path.resolve(extensionPath, '.omnisharp/experimental/1.2.3/omnisharp/OmniSharp.exe')); + }); + + test('Downloads package and returns launch path based on install path ', async () => { + let launchPath = await manager.InstallVersionAndReturnLaunchPath("1.2.3", true, serverUrl, "installHere", extensionPath, platformInfo); + launchPath.should.equal(path.resolve(extensionPath, 'installHere/1.2.3/OmniSharp.exe')); + }); + + teardown(async () => { + if (tmpDir) { + await rimraf(tmpDir.name); + } + + if (tmpFile) { + tmpFile.removeCallback(); + } + + tmpFile = null; + tmpDir = null; + }); +}); + +function GetTestOmnisharpManager() { + let channel = vscode.window.createOutputChannel('Experiment Channel'); + let logger = new Logger(text => channel.append(text)); + return new OmnisharpManager(channel, logger, GetTestPackageJSON(), null); +} \ No newline at end of file diff --git a/test/unitTests/OmnisharpPackageCreator.test.ts b/test/unitTests/OmnisharpPackageCreator.test.ts new file mode 100644 index 000000000..34c97403d --- /dev/null +++ b/test/unitTests/OmnisharpPackageCreator.test.ts @@ -0,0 +1,197 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { assert, should, expect } from "chai"; +import { Package } from "../../src/packages"; +import { GetTestPackageJSON } from "./OmnisharpDownloader.test"; +import { GetOmnisharpPackage, GetPackagesFromVersion } from "../../src/omnisharp/OmnisharpPackageCreator"; + +suite("GetOmnisharpPackage : Output package depends on the input package and other input parameters like serverUrl", () => { + + let serverUrl: string; + let version: string; + let installPath: string; + let inputPackages: any; + + suiteSetup(() => { + serverUrl = "http://serverUrl"; + version = "0.0.0"; + installPath = "testPath"; + let packageJSON = GetTestPackageJSON(); + inputPackages = (packageJSON.runtimeDependencies); + should(); + }); + + test('Throws exception if version is empty', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); + let fn = function () { GetOmnisharpPackage(testPackage, serverUrl, "", installPath); }; + expect(fn).to.throw('Invalid version'); + }); + + test('Throws exception if version is null', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); + let fn = function () { GetOmnisharpPackage(testPackage, serverUrl, null, installPath);}; + expect(fn).to.throw('Invalid version'); + }); + + test('Architectures, binaries and platforms do not change', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); + let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, version, installPath); + + resultPackage.architectures.should.equal(testPackage.architectures); + assert.equal(resultPackage.binaries, testPackage.binaries); + resultPackage.platforms.should.equal(testPackage.platforms); + }); + + test('Version information is appended to the description', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); + let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", installPath); + + resultPackage.description.should.equal(`${testPackage.description}, Version = 1.2.3`); + }); + + test('Download url is calculated using server url and version', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); + let resultPackage = GetOmnisharpPackage(testPackage, "http://someurl", "1.1.1", installPath); + resultPackage.url.should.equal("http://someurl/releases/1.1.1/omnisharp-os-architecture.zip"); + }); + + test('Install path is calculated using the specified path and version', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); + let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + resultPackage.installPath.should.equal("experimentPath/1.2.3"); + }); + + test('Install test path is calculated using specified path, version and ends with Omnisharp.exe - Windows(x86)', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "win-x86")); + let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/OmniSharp.exe"); + }); + + test('Install test path is calculated using specified path, version and ends with Omnisharp.exe - Windows(x64)', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "win-x64")); + let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/OmniSharp.exe"); + }); + + test('Install test path is calculated using specified path, version and ends with mono.osx - OSX', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "osx")); + let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/mono.osx"); + }); + + test('Install test path is calculated using specified path, version and ends with mono.linux-x86 - Linux(x86)', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "linux-x86")); + let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/mono.linux-x86"); + }); + + test('Install test path is calculated using specified path, version and ends with mono.linux-x86_64 - Linux(x64)', () => { + let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "linux-x64")); + let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/mono.linux-x86_64"); + }); +}); + +suite('GetPackagesFromVersion : Gets the experimental omnisharp packages from a set of input packages', () => { + + const serverUrl = "http://serverUrl"; + const installPath = "testPath"; + let inputPackages : any; + + suiteSetup(() => { + inputPackages = (GetTestPackageJSON().runtimeDependencies); + should(); + }); + + test('Throws exception if the version is null', () => { + let version: string = null; + let fn = function () { GetPackagesFromVersion(version, inputPackages, serverUrl, installPath); }; + expect(fn).to.throw('Invalid version'); + }); + + test('Throws exception if the version is empty', () => { + let version = ""; + let fn = function () { GetPackagesFromVersion(version, inputPackages, serverUrl, installPath); }; + expect(fn).to.throw('Invalid version'); + }); + + test('Returns experiment packages with install test path depending on install path and version', () => { + let inputPackages = [ + { + "description": "OmniSharp for Windows (.NET 4.6 / x64)", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505821/c570a9e20dbf7172f79850babd058872/omnisharp-win-x64-1.28.0.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-win-x64-1.28.0.zip", + "installPath": ".omnisharp", + "platforms": [ + "win32" + ], + "architectures": [ + "x86_64" + ], + "installTestPath": "./.omnisharp/OmniSharp.exe", + "experimentalPackageId": "win-x64" + }, + { + "description": "OmniSharp for OSX", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505818/6b99c6a86da3221919158ca0f36a3e45/omnisharp-osx-1.28.0.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-osx-1.28.0.zip", + "installPath": ".omnisharp", + "platforms": [ + "darwin" + ], + "binaries": [ + "./mono.osx", + "./run" + ], + "installTestPath": "./.omnisharp/mono.osx", + "experimentalPackageId": "osx" + }, + ]; + + let outPackages = GetPackagesFromVersion("1.1.1", inputPackages, serverUrl, "experimentPath"); + outPackages.length.should.equal(2); + outPackages[0].installTestPath.should.equal("./experimentPath/1.1.1/OmniSharp.exe"); + outPackages[1].installTestPath.should.equal("./experimentPath/1.1.1/mono.osx"); + }); + + test('Returns only omnisharp packages with experimentalIds', () => { + let version = "0.0.0"; + let inputPackages = [ + { + "description": "OmniSharp for Windows (.NET 4.6 / x64)", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505821/c570a9e20dbf7172f79850babd058872/omnisharp-win-x64-1.28.0.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-win-x64-1.28.0.zip", + "installPath": ".omnisharp", + "platforms": [ + "win32" + ], + "architectures": [ + "x86_64" + ], + "installTestPath": "./.omnisharp/OmniSharp.exe", + "experimentalPackageId": "win-x64" + }, + { + "description": "Some other package - no experimental id", + "url": "https://download.visualstudio.microsoft.com/download/pr/100505818/6b99c6a86da3221919158ca0f36a3e45/omnisharp-osx-1.28.0.zip", + "fallbackUrl": "https://omnisharpdownload.blob.core.windows.net/ext/omnisharp-osx-1.28.0.zip", + "installPath": ".omnisharp", + "platforms": [ + "darwin" + ], + "binaries": [ + "./mono.osx", + "./run" + ], + "installTestPath": "./.omnisharp/mono.osx", + }, + ]; + + let outPackages = GetPackagesFromVersion(version, inputPackages, serverUrl, installPath); + outPackages.length.should.equal(1); + outPackages[0].experimentalPackageId.should.equal("win-x64"); + }); +}); \ No newline at end of file From d3fc133cc89f1224e2a521196f027f479978096c Mon Sep 17 00:00:00 2001 From: akshita31 Date: Fri, 23 Feb 2018 14:53:56 -0800 Subject: [PATCH 02/12] Enable download and usage of latest version of omnisharp (#2039) * Enable usage of multiple versions * Either load the server from a path or download the version packages * Tests for the package creator * Added null check and removed semver check in package creator * Test for the experiment omnisharp downloader * Added test for package manager * Code clean up * Added null or empty check for version * Changes * Modified the description * Put the clean up logic in the teardown function * Remove comment * Remove unnecessary usage * CR comments * Removed experimental * Modified launcher * Removed experimental * Modified tests * Modified package description to include version information * Renamed launch path * Add more tests * Changed the description in package.json * Getting latest version info * Refactored code and added tests * Remove unnecessary using * CR comments * Use common function for latest download * Add new line * Resolve binaries on linux --- package.json | 2 +- src/OmnisharpDownload.Helper.ts | 13 ++-- src/omnisharp/OmnisharpDownloader.ts | 65 +++++++++++++------ src/omnisharp/OmnisharpManager.ts | 28 ++++---- src/omnisharp/OmnisharpPackageCreator.ts | 9 ++- src/omnisharp/server.ts | 3 +- src/packages.ts | 33 ++++++++-- test/unitTests/OmnisharpDownloader.test.ts | 7 +- test/unitTests/OmnisharpManager.test.ts | 26 +++++--- .../unitTests/OmnisharpPackageCreator.test.ts | 14 +++- 10 files changed, 140 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 706b7924d..21ddbd8cd 100644 --- a/package.json +++ b/package.json @@ -367,7 +367,7 @@ "null" ], "default": null, - "description": "Specifies how to acquire the OmniSharp to use. Can be one of \"latest\", a specific version number, or the absolute path to a local OmniSharp folder." + "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", diff --git a/src/OmnisharpDownload.Helper.ts b/src/OmnisharpDownload.Helper.ts index 1fcb7326e..3281d38d5 100644 --- a/src/OmnisharpDownload.Helper.ts +++ b/src/OmnisharpDownload.Helper.ts @@ -3,16 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { PackageManager, Status, PackageError, Package } from './packages'; +import { Status, PackageError } from './packages'; import { PlatformInformation } from './platform'; import { Logger } from './logger'; import TelemetryReporter from 'vscode-extension-telemetry'; -export async function GetDependenciesAndDownloadPackages(packages: Package[], status: Status, platformInfo: PlatformInformation, packageManager: PackageManager, logger: Logger) { +export function GetNetworkDependencies() { const config = vscode.workspace.getConfiguration(); const proxy = config.get('http.proxy'); const strictSSL = config.get('http.proxyStrictSSL', true); - await packageManager.DownloadPackages(logger, status, proxy, strictSSL); + return { Proxy: proxy, StrictSSL: strictSSL }; } export function SetStatus() { @@ -31,13 +31,9 @@ export function SetStatus() { return { StatusItem: statusItem, Status: status }; } -export async function GetAndLogPlatformInformation(logger: Logger): Promise { - let platformInfo = await PlatformInformation.GetCurrent(); - +export function LogPlatformInformation(logger: Logger, platformInfo: PlatformInformation) { logger.appendLine(`Platform: ${platformInfo.toString()}`); logger.appendLine(); - - return platformInfo; } export function ReportInstallationError(logger: Logger, error, telemetryProps: any, installationStage: string) { @@ -60,6 +56,7 @@ export function ReportInstallationError(logger: Logger, error, telemetryProps: a errorMessage = error.toString(); } + logger.appendLine(); logger.appendLine(`Failed at stage: ${installationStage}`); logger.appendLine(errorMessage); } diff --git a/src/omnisharp/OmnisharpDownloader.ts b/src/omnisharp/OmnisharpDownloader.ts index 356aeb617..abb223833 100644 --- a/src/omnisharp/OmnisharpDownloader.ts +++ b/src/omnisharp/OmnisharpDownloader.ts @@ -4,19 +4,38 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { PackageManager, Package } from '../packages'; +import { PackageManager, Package, Status } from '../packages'; import { PlatformInformation } from '../platform'; import { Logger } from '../logger'; import TelemetryReporter from 'vscode-extension-telemetry'; -import { GetPackagesFromVersion } from './OmnisharpPackageCreator'; -import { GetDependenciesAndDownloadPackages, SetStatus, GetAndLogPlatformInformation, ReportInstallationError, SendInstallationTelemetry } from '../OmnisharpDownload.Helper'; +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) { @@ -24,49 +43,57 @@ export class OmnisharpDownloader { throw new Error('Invalid version'); } - this.logger.append('Installing Omnisharp Packages...'); + this.logger.appendLine('Installing Omnisharp Packages...'); this.logger.appendLine(); this.channel.show(); - let statusObject = SetStatus(); - let status = statusObject.Status; - let statusItem = statusObject.StatusItem; - - let telemetryProps: any = {}; let installationStage = ''; - let platformInfo: PlatformInformation; if (this.reporter) { this.reporter.sendTelemetryEvent("AcquisitionStart"); } try { - installationStage = 'getPlatformInfo'; - platformInfo = await GetAndLogPlatformInformation(this.logger); + LogPlatformInformation(this.logger, this.platformInfo); installationStage = 'getPackageInfo'; let packages: Package[] = GetPackagesFromVersion(version, this.packageJSON.runtimeDependencies, serverUrl, installPath); installationStage = 'downloadPackages'; - let packageManager = new PackageManager(platformInfo, this.packageJSON); + // Specify the packages that the package manager needs to download - packageManager.SetVersionPackagesForDownload(packages); - await GetDependenciesAndDownloadPackages(packages,status, platformInfo, packageManager, this.logger); + this.packageManager.SetVersionPackagesForDownload(packages); + await this.packageManager.DownloadPackages(this.logger, this.status, this.proxy, this.strictSSL); this.logger.appendLine(); installationStage = 'installPackages'; - await packageManager.InstallPackages(this.logger, status); + await this.packageManager.InstallPackages(this.logger, this.status); installationStage = 'completeSuccess'; } - catch (error) { - ReportInstallationError(this.logger, error, telemetryProps, installationStage); + ReportInstallationError(this.logger, error, this.telemetryProps, installationStage); throw error;// throw the error up to the server } finally { - SendInstallationTelemetry(this.logger, this.reporter, telemetryProps, installationStage, platformInfo, statusItem); + SendInstallationTelemetry(this.logger, this.reporter, this.telemetryProps, installationStage, this.platformInfo, this.statusItem); + } + } + + public async GetLatestVersion(serverUrl: string, versionFilePathInServer): Promise { + 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; } } } diff --git a/src/omnisharp/OmnisharpManager.ts b/src/omnisharp/OmnisharpManager.ts index 61dff1ec0..3ef632564 100644 --- a/src/omnisharp/OmnisharpManager.ts +++ b/src/omnisharp/OmnisharpManager.ts @@ -20,28 +20,34 @@ export class OmnisharpManager { private reporter?: TelemetryReporter) { } - public async GetOmnisharpPath(omnisharpPath: string, useMono: boolean, serverUrl: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation): Promise { + public async GetOmnisharpPath(omnisharpPath: string, useMono: boolean, serverUrl: string, versionFilePathInServer: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation): Promise { // Looks at the options path, installs the dependencies and returns the path to be loaded by the omnisharp server - // To Do : Add the functionality for the latest option - + let downloader = new OmnisharpDownloader(this.channel, this.logger, this.packageJSON, platformInfo, this.reporter); if (path.isAbsolute(omnisharpPath)) { if (await util.fileExists(omnisharpPath)) { return omnisharpPath; } else { - throw new Error('Invalid path specified'); + throw new Error('The system could not find the specified path'); } } - //If the path is not a valid path on disk, treat it as a version - return await this.InstallVersionAndReturnLaunchPath(omnisharpPath, useMono, serverUrl, installPath, extensionPath, platformInfo); + else if (omnisharpPath == "latest") { + return await this.LatestInstallAndReturnLaunchPath(downloader, useMono, serverUrl, versionFilePathInServer, installPath, extensionPath, platformInfo); + } + + //If the path is neither a valid path on disk not the string "latest", treat it as a version + return await this.InstallVersionAndReturnLaunchPath(downloader, omnisharpPath, useMono, serverUrl, installPath, extensionPath, platformInfo); } - public async InstallVersionAndReturnLaunchPath(version: string, useMono: boolean, serverUrl: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { + public async LatestInstallAndReturnLaunchPath(downloader: OmnisharpDownloader, useMono: boolean, serverUrl: string, versionFilePathInServer: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { + let version = await downloader.GetLatestVersion(serverUrl, versionFilePathInServer); + return await this.InstallVersionAndReturnLaunchPath(downloader, version, useMono, serverUrl, installPath, extensionPath, platformInfo); + } + + public async InstallVersionAndReturnLaunchPath(downloader: OmnisharpDownloader, version: string, useMono: boolean, serverUrl: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { if (semver.valid(version)) { - let downloader = new OmnisharpDownloader(this.channel, this.logger, this.packageJSON, this.reporter); await downloader.DownloadAndInstallOmnisharp(version, serverUrl, installPath); - - return await GetLaunchPathForVersion(platformInfo, version, installPath, extensionPath, useMono); + return GetLaunchPathForVersion(platformInfo, version, installPath, extensionPath, useMono); } else { throw new Error('Invalid omnisharp version specified'); @@ -49,7 +55,7 @@ export class OmnisharpManager { } } -export async function GetLaunchPathForVersion(platformInfo: PlatformInformation, version: string, installPath: string, extensionPath: string, useMono: boolean) { +export function GetLaunchPathForVersion(platformInfo: PlatformInformation, version: string, installPath: string, extensionPath: string, useMono: boolean) { if (!version) { throw new Error('Invalid Version'); } diff --git a/src/omnisharp/OmnisharpPackageCreator.ts b/src/omnisharp/OmnisharpPackageCreator.ts index 66fe6abeb..a645311da 100644 --- a/src/omnisharp/OmnisharpPackageCreator.ts +++ b/src/omnisharp/OmnisharpPackageCreator.ts @@ -55,4 +55,11 @@ function GetPackageFromArchitecture(inputPackage: Package, serverUrl: string, ve }; return versionPackage; -} \ No newline at end of file +} + +export function GetVersionFilePackage(serverUrl: string, pathInServer: string): Package { + return { + "description": "Latest version information file", + "url": `${serverUrl}/${pathInServer}` + }; +} diff --git a/src/omnisharp/server.ts b/src/omnisharp/server.ts index 5c62d14e7..bd1a269e6 100644 --- a/src/omnisharp/server.ts +++ b/src/omnisharp/server.ts @@ -274,9 +274,10 @@ export class OmniSharpServer { let serverUrl = "https://roslynomnisharp.blob.core.windows.net"; let installPath = ".omnisharp/experimental"; let extensionPath = utils.getExtensionPath(); + let versionFilePathInServer = 'releases/versioninfo.txt'; let manager = new OmnisharpManager(this._csharpChannel, this._csharpLogger, this._packageJSON, this._reporter); let platformInfo = await PlatformInformation.GetCurrent(); - launchPath = await manager.GetOmnisharpPath(this._options.path, this._options.useMono, serverUrl, installPath, extensionPath, platformInfo); + launchPath = await manager.GetOmnisharpPath(this._options.path, this._options.useMono, serverUrl, versionFilePathInServer,installPath, extensionPath, platformInfo); } catch (error) { this._logger.appendLine('Error occured in loading omnisharp from omnisharp.path'); diff --git a/src/packages.ts b/src/packages.ts index a5e15d197..64a2ebbd2 100644 --- a/src/packages.ts +++ b/src/packages.ts @@ -78,11 +78,7 @@ export class PackageManager { this.allPackages = this.packageJSON.runtimeDependencies; // Convert relative binary paths to absolute - for (let pkg of this.allPackages) { - if (pkg.binaries) { - pkg.binaries = pkg.binaries.map(value => path.resolve(getBaseInstallPath(pkg), value)); - } - } + resolvePackageBinaries(this.allPackages); resolve(this.allPackages); } @@ -111,6 +107,33 @@ export class PackageManager { public SetVersionPackagesForDownload(packages: Package[]) { this.allPackages = packages; + resolvePackageBinaries(this.allPackages); + } + + public async GetLatestVersionFromFile(logger: Logger, status: Status, proxy: string, strictSSL: boolean, filePackage: Package): Promise { + try { + let latestVersion: string; + await maybeDownloadPackage(filePackage, logger, status, proxy, strictSSL); + if (filePackage.tmpFile) { + latestVersion = fs.readFileSync(filePackage.tmpFile.name, 'utf8'); + //Delete the temporary file created + filePackage.tmpFile.removeCallback(); + } + + return latestVersion; + } + catch (error) { + throw new Error(`Could not download the latest version file due to ${error.toString()}`); + } + } +} + +function resolvePackageBinaries(packages: Package[]) { + // Convert relative binary paths to absolute + for (let pkg of packages) { + if (pkg.binaries) { + pkg.binaries = pkg.binaries.map(value => path.resolve(getBaseInstallPath(pkg), value)); + } } } diff --git a/test/unitTests/OmnisharpDownloader.test.ts b/test/unitTests/OmnisharpDownloader.test.ts index 84678cd49..1709be753 100644 --- a/test/unitTests/OmnisharpDownloader.test.ts +++ b/test/unitTests/OmnisharpDownloader.test.ts @@ -10,6 +10,7 @@ import { should } from 'chai'; import { Logger } from '../../src/logger'; import { OmnisharpDownloader } from '../../src/omnisharp/OmnisharpDownloader'; import { rimraf } from 'async-file'; +import { PlatformInformation } from '../../src/platform'; const tmp = require('tmp'); const chai = require("chai"); @@ -19,7 +20,7 @@ let expect = chai.expect; suite("DownloadAndInstallExperimentalVersion : Gets the version packages, downloads and installs them", () => { let tmpDir = null; const version = "1.2.3"; - const downloader = GetOmnisharpDownloader(); + const downloader = GetTestOmnisharpDownloader(); const serverUrl = "https://roslynomnisharp.blob.core.windows.net"; const installPath = ".omnisharp/experimental/"; @@ -57,10 +58,10 @@ suite("DownloadAndInstallExperimentalVersion : Gets the version packages, downlo }); }); -function GetOmnisharpDownloader() { +function GetTestOmnisharpDownloader() { let channel = vscode.window.createOutputChannel('Experiment Channel'); let logger = new Logger(text => channel.append(text)); - return new OmnisharpDownloader(channel, logger, GetTestPackageJSON(), null); + return new OmnisharpDownloader(channel, logger, GetTestPackageJSON(), new PlatformInformation("win32", "x86"), null); } //Since we need only the runtime dependencies of packageJSON for the downloader create a testPackageJSON diff --git a/test/unitTests/OmnisharpManager.test.ts b/test/unitTests/OmnisharpManager.test.ts index 1593baec7..e9338311e 100644 --- a/test/unitTests/OmnisharpManager.test.ts +++ b/test/unitTests/OmnisharpManager.test.ts @@ -23,6 +23,7 @@ suite('GetExperimentalOmnisharpPath : Returns Omnisharp experiment path dependin const platformInfo = new PlatformInformation("win32", "x86"); const serverUrl = "https://roslynomnisharp.blob.core.windows.net"; const installPath = ".omnisharp/experimental"; + const versionFilepathInServer = "releases/testVersionInfo.txt"; const useMono = false; const manager = GetTestOmnisharpManager(); let extensionPath: string; @@ -38,50 +39,55 @@ suite('GetExperimentalOmnisharpPath : Returns Omnisharp experiment path dependin }); test('Throws error if the path is neither an absolute path nor a valid semver', async () => { - expect(manager.GetOmnisharpPath("Some incorrect path", useMono, serverUrl, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); + expect(manager.GetOmnisharpPath("Some incorrect path", useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); }); test('Throws error when the specified path is null', async () => { - expect(manager.GetOmnisharpPath(null, useMono, serverUrl, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); + expect(manager.GetOmnisharpPath(null, useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); }); test('Throws error when the specified path is empty', async () => { - expect(manager.GetOmnisharpPath("", useMono, serverUrl, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); + expect(manager.GetOmnisharpPath("", useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); }); test('Throws error when the specified path is an invalid semver', async () => { - expect(manager.GetOmnisharpPath("a.b.c", useMono, serverUrl, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); + expect(manager.GetOmnisharpPath("a.b.c", useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); }); test('Returns the same path if absolute path to an existing file is passed', async () => { tmpFile = tmp.fileSync(); - let omnisharpPath = await manager.GetOmnisharpPath(tmpFile.name, useMono, serverUrl, installPath, extensionPath, platformInfo); + let omnisharpPath = await manager.GetOmnisharpPath(tmpFile.name, useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, platformInfo); omnisharpPath.should.equal(tmpFile.name); }); + test('Installs the latest version and returns the launch path based on the version and platform', async () => { + let omnisharpPath = await manager.GetOmnisharpPath("latest", useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, platformInfo); + omnisharpPath.should.equal(path.resolve(extensionPath, `.omnisharp/experimental/1.2.3/OmniSharp.exe`)); + }); + test('Installs the test version and returns the launch path based on the version and platform', async () => { - let omnisharpPath = await manager.GetOmnisharpPath("1.2.3", useMono, serverUrl, installPath, extensionPath, platformInfo); + let omnisharpPath = await manager.GetOmnisharpPath("1.2.3", useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, platformInfo); omnisharpPath.should.equal(path.resolve(extensionPath, `.omnisharp/experimental/1.2.3/OmniSharp.exe`)); }); test('Downloads package from given url and installs them at the specified path', async () => { - let launchPath = await manager.GetOmnisharpPath("1.2.3", useMono, serverUrl, installPath, extensionPath, platformInfo); + let launchPath = await manager.GetOmnisharpPath("1.2.3", useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, platformInfo); let exists = await util.fileExists(path.resolve(extensionPath, `.omnisharp/experimental/1.2.3/install_check_1.2.3.txt`)); exists.should.equal(true); }); test('Downloads package and returns launch path based on platform - Not using mono on Linux ', async () => { - let launchPath = await manager.GetOmnisharpPath("1.2.3", useMono, serverUrl, installPath, extensionPath, new PlatformInformation("linux", "x64")); + let launchPath = await manager.GetOmnisharpPath("1.2.3", useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, new PlatformInformation("linux", "x64")); launchPath.should.equal(path.resolve(extensionPath, '.omnisharp/experimental/1.2.3/run')); }); test('Downloads package and returns launch path based on platform - Using mono on Linux ', async () => { - let launchPath = await manager.InstallVersionAndReturnLaunchPath("1.2.3", true, serverUrl, installPath, extensionPath, new PlatformInformation("linux", "x64")); + let launchPath = await manager.GetOmnisharpPath("1.2.3", true, serverUrl, versionFilepathInServer, installPath, extensionPath, new PlatformInformation("linux", "x64")); launchPath.should.equal(path.resolve(extensionPath, '.omnisharp/experimental/1.2.3/omnisharp/OmniSharp.exe')); }); test('Downloads package and returns launch path based on install path ', async () => { - let launchPath = await manager.InstallVersionAndReturnLaunchPath("1.2.3", true, serverUrl, "installHere", extensionPath, platformInfo); + let launchPath = await manager.GetOmnisharpPath("1.2.3", true, serverUrl, versionFilepathInServer, "installHere", extensionPath, platformInfo); launchPath.should.equal(path.resolve(extensionPath, 'installHere/1.2.3/OmniSharp.exe')); }); diff --git a/test/unitTests/OmnisharpPackageCreator.test.ts b/test/unitTests/OmnisharpPackageCreator.test.ts index 34c97403d..b06f56990 100644 --- a/test/unitTests/OmnisharpPackageCreator.test.ts +++ b/test/unitTests/OmnisharpPackageCreator.test.ts @@ -6,7 +6,7 @@ import { assert, should, expect } from "chai"; import { Package } from "../../src/packages"; import { GetTestPackageJSON } from "./OmnisharpDownloader.test"; -import { GetOmnisharpPackage, GetPackagesFromVersion } from "../../src/omnisharp/OmnisharpPackageCreator"; +import { GetOmnisharpPackage, GetPackagesFromVersion, GetVersionFilePackage } from "../../src/omnisharp/OmnisharpPackageCreator"; suite("GetOmnisharpPackage : Output package depends on the input package and other input parameters like serverUrl", () => { @@ -194,4 +194,16 @@ suite('GetPackagesFromVersion : Gets the experimental omnisharp packages from a outPackages.length.should.equal(1); outPackages[0].experimentalPackageId.should.equal("win-x64"); }); +}); + +suite('GetVersionFilePackage : Gives the package for the latest file download', () => { + test('Contains the expected description', () => { + let testPackage = GetVersionFilePackage("someUrl", "somePath"); + expect(testPackage.description).to.equal('Latest version information file'); + }); + + test('Contains the url based on serverUrl and the pathInServer', () => { + let testPackage = GetVersionFilePackage("someUrl", "somePath"); + expect(testPackage.url).to.equal('someUrl/somePath'); + }); }); \ No newline at end of file From 7e11418ca194170fddba70d1716d5ca97942f6da Mon Sep 17 00:00:00 2001 From: Akshita Agarwal Date: Fri, 23 Feb 2018 16:40:41 -0800 Subject: [PATCH 03/12] Copy pacakges by value --- src/packages.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/packages.ts b/src/packages.ts index 64a2ebbd2..97b558a74 100644 --- a/src/packages.ts +++ b/src/packages.ts @@ -75,7 +75,8 @@ export class PackageManager { resolve(this.allPackages); } else if (this.packageJSON.runtimeDependencies) { - this.allPackages = this.packageJSON.runtimeDependencies; + this.allPackages = JSON.parse(JSON.stringify(this.packageJSON.runtimeDependencies)); + //Copying the packages by value and not by reference so that there are no side effects // Convert relative binary paths to absolute resolvePackageBinaries(this.allPackages); From 180f4385d3a995b84d8971891e226b7414cfd1d7 Mon Sep 17 00:00:00 2001 From: Akshita Agarwal Date: Fri, 23 Feb 2018 17:12:42 -0800 Subject: [PATCH 04/12] Renamed experimentalId and some methods --- package.json | 10 ++-- src/omnisharp/OmnisharpDownloader.ts | 4 -- src/omnisharp/OmnisharpManager.ts | 4 +- src/omnisharp/OmnisharpPackageCreator.ts | 28 +++++----- src/packages.ts | 2 +- ...ingleCsproj.csproj.CoreCompileInputs.cache | 2 +- test/unitTests/OmnisharpDownloader.test.ts | 22 +++----- .../unitTests/OmnisharpPackageCreator.test.ts | 54 +++++++++---------- 8 files changed, 55 insertions(+), 71 deletions(-) diff --git a/package.json b/package.json index 21ddbd8cd..b80ae5b22 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "x86" ], "installTestPath": "./.omnisharp/OmniSharp.exe", - "experimentalPackageId": "win-x86" + "platformId": "win-x86" }, { "description": "OmniSharp for Windows (.NET 4.6 / x64)", @@ -109,7 +109,7 @@ "x86_64" ], "installTestPath": "./.omnisharp/OmniSharp.exe", - "experimentalPackageId": "win-x64" + "platformId": "win-x64" }, { "description": "OmniSharp for OSX", @@ -124,7 +124,7 @@ "./run" ], "installTestPath": "./.omnisharp/mono.osx", - "experimentalPackageId": "osx" + "platformId": "osx" }, { "description": "OmniSharp for Linux (x86)", @@ -143,7 +143,7 @@ "./run" ], "installTestPath": "./.omnisharp/mono.linux-x86", - "experimentalPackageId": "linux-x86" + "platformId": "linux-x86" }, { "description": "OmniSharp for Linux (x64)", @@ -161,7 +161,7 @@ "./run" ], "installTestPath": "./.omnisharp/mono.linux-x86_64", - "experimentalPackageId": "linux-x64" + "platformId": "linux-x64" }, { "description": ".NET Core Debugger (Windows / x64)", diff --git a/src/omnisharp/OmnisharpDownloader.ts b/src/omnisharp/OmnisharpDownloader.ts index abb223833..1af4d0838 100644 --- a/src/omnisharp/OmnisharpDownloader.ts +++ b/src/omnisharp/OmnisharpDownloader.ts @@ -39,10 +39,6 @@ export class OmnisharpDownloader { } public async DownloadAndInstallOmnisharp(version: string, serverUrl: string, installPath: string) { - if (!version) { - throw new Error('Invalid version'); - } - this.logger.appendLine('Installing Omnisharp Packages...'); this.logger.appendLine(); this.channel.show(); diff --git a/src/omnisharp/OmnisharpManager.ts b/src/omnisharp/OmnisharpManager.ts index 3ef632564..6a12e1d68 100644 --- a/src/omnisharp/OmnisharpManager.ts +++ b/src/omnisharp/OmnisharpManager.ts @@ -32,14 +32,14 @@ export class OmnisharpManager { } } else if (omnisharpPath == "latest") { - return await this.LatestInstallAndReturnLaunchPath(downloader, useMono, serverUrl, versionFilePathInServer, installPath, extensionPath, platformInfo); + return await this.InstallLatestAndReturnLaunchPath(downloader, useMono, serverUrl, versionFilePathInServer, installPath, extensionPath, platformInfo); } //If the path is neither a valid path on disk not the string "latest", treat it as a version return await this.InstallVersionAndReturnLaunchPath(downloader, omnisharpPath, useMono, serverUrl, installPath, extensionPath, platformInfo); } - public async LatestInstallAndReturnLaunchPath(downloader: OmnisharpDownloader, useMono: boolean, serverUrl: string, versionFilePathInServer: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { + public async InstallLatestAndReturnLaunchPath(downloader: OmnisharpDownloader, useMono: boolean, serverUrl: string, versionFilePathInServer: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { let version = await downloader.GetLatestVersion(serverUrl, versionFilePathInServer); return await this.InstallVersionAndReturnLaunchPath(downloader, version, useMono, serverUrl, installPath, extensionPath, platformInfo); } diff --git a/src/omnisharp/OmnisharpPackageCreator.ts b/src/omnisharp/OmnisharpPackageCreator.ts index a645311da..fb0d6bb2d 100644 --- a/src/omnisharp/OmnisharpPackageCreator.ts +++ b/src/omnisharp/OmnisharpPackageCreator.ts @@ -12,46 +12,42 @@ export function GetPackagesFromVersion(version: string, runTimeDependencies: Pac let versionPackages = new Array(); for (let inputPackage of runTimeDependencies) { - if (inputPackage.experimentalPackageId) { - versionPackages.push(GetOmnisharpPackage(inputPackage, serverUrl, version, installPath)); + if (inputPackage.platformId) { + versionPackages.push(SetBinaryAndGetPackage(inputPackage, serverUrl, version, installPath)); } } return versionPackages; } -export function GetOmnisharpPackage(inputPackage: Package, serverUrl: string, version: string, installPath: string): Package { +export function SetBinaryAndGetPackage(inputPackage: Package, serverUrl: string, version: string, installPath: string): Package { let installBinary: string; - if (inputPackage.experimentalPackageId == "win-x86" || inputPackage.experimentalPackageId == "win-x64") { + if (inputPackage.platformId == "win-x86" || inputPackage.platformId == "win-x64") { installBinary = "OmniSharp.exe"; } - else if (inputPackage.experimentalPackageId == "osx") { + else if (inputPackage.platformId == "osx") { installBinary = "mono.osx"; } - else if (inputPackage.experimentalPackageId == "linux-x86") { + else if (inputPackage.platformId == "linux-x86") { installBinary = "mono.linux-x86"; } - else if (inputPackage.experimentalPackageId == "linux-x64") { + else if (inputPackage.platformId == "linux-x64") { installBinary = "mono.linux-x86_64"; } - return GetPackageFromArchitecture(inputPackage, serverUrl, version, inputPackage.experimentalPackageId, installPath, installBinary); + return GetPackage(inputPackage, serverUrl, version, installPath, installBinary); } -function GetPackageFromArchitecture(inputPackage: Package, serverUrl: string, version: string, architectureInfo: string, installPath: string, installBinary: string): Package { +function GetPackage(inputPackage: Package, serverUrl: string, version: string, installPath: string, installBinary: string): Package { if (!version) { throw new Error('Invalid version'); } - let versionPackage = { + let versionPackage = {...inputPackage, "description": `${inputPackage.description}, Version = ${version}`, - "url": `${serverUrl}/releases/${version}/omnisharp-${architectureInfo}.zip`, + "url": `${serverUrl}/releases/${version}/omnisharp-${inputPackage.platformId}.zip`, "installPath": `${installPath}/${version}`, - "platforms": inputPackage.platforms, - "architectures": inputPackage.architectures, - "binaries": inputPackage.binaries, - "installTestPath": `./${installPath}/${version}/${installBinary}`, - "experimentalPackageId": architectureInfo + "installTestPath": `./${installPath}/${version}/${installBinary}` }; return versionPackage; diff --git a/src/packages.ts b/src/packages.ts index 97b558a74..a16a9b38d 100644 --- a/src/packages.ts +++ b/src/packages.ts @@ -24,7 +24,7 @@ export interface Package { architectures: string[]; binaries: string[]; tmpFile: tmp.SynchrounousResult; - experimentalPackageId?: string; + platformId?: string; // Path to use to test if the package has already been installed installTestPath?: string; diff --git a/test/integrationTests/testAssets/singleCsproj/obj/Debug/netcoreapp2.0/singleCsproj.csproj.CoreCompileInputs.cache b/test/integrationTests/testAssets/singleCsproj/obj/Debug/netcoreapp2.0/singleCsproj.csproj.CoreCompileInputs.cache index 2c37f2978..0cb96c1c5 100644 --- a/test/integrationTests/testAssets/singleCsproj/obj/Debug/netcoreapp2.0/singleCsproj.csproj.CoreCompileInputs.cache +++ b/test/integrationTests/testAssets/singleCsproj/obj/Debug/netcoreapp2.0/singleCsproj.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -a42255fc669f86623d73c2e9ad48ccb8310c65c0 +ffcdec535c6ed9f5449ad17c7f1a870da5e60671 diff --git a/test/unitTests/OmnisharpDownloader.test.ts b/test/unitTests/OmnisharpDownloader.test.ts index 1709be753..af276f096 100644 --- a/test/unitTests/OmnisharpDownloader.test.ts +++ b/test/unitTests/OmnisharpDownloader.test.ts @@ -29,14 +29,6 @@ suite("DownloadAndInstallExperimentalVersion : Gets the version packages, downlo util.setExtensionPath(tmpDir.name); }); - test('Throws error if version is null', () => { - expect(downloader.DownloadAndInstallOmnisharp(null, serverUrl, installPath)).to.be.rejectedWith(Error); - }); - - test('Throws error if version is empty string', () => { - expect(downloader.DownloadAndInstallOmnisharp("", serverUrl, installPath)).to.be.rejectedWith(Error); - }); - test('Throws error if request is made for a version that doesnot exist on the server', () => { expect(downloader.DownloadAndInstallOmnisharp("1.00000001.0000", serverUrl, installPath)).to.be.rejectedWith(Error); }); @@ -81,7 +73,7 @@ export function GetTestPackageJSON() { "x86" ], "installTestPath": "./.omnisharp/OmniSharp.exe", - "experimentalPackageId": "win-x86" + "platformId": "win-x86" }, { "description": "OmniSharp for Windows (.NET 4.6 / x64)", @@ -95,7 +87,7 @@ export function GetTestPackageJSON() { "x86_64" ], "installTestPath": "./.omnisharp/OmniSharp.exe", - "experimentalPackageId": "win-x64" + "platformId": "win-x64" }, { "description": "OmniSharp for OSX", @@ -110,7 +102,7 @@ export function GetTestPackageJSON() { "./run" ], "installTestPath": "./.omnisharp/mono.osx", - "experimentalPackageId": "osx" + "platformId": "osx" }, { "description": "OmniSharp for Linux (x86)", @@ -129,7 +121,7 @@ export function GetTestPackageJSON() { "./run" ], "installTestPath": "./.omnisharp/mono.linux-x86", - "experimentalPackageId": "linux-x86" + "platformId": "linux-x86" }, { "description": "OmniSharp for Linux (x64)", @@ -147,7 +139,7 @@ export function GetTestPackageJSON() { "./run" ], "installTestPath": "./.omnisharp/mono.linux-x86_64", - "experimentalPackageId": "linux-x64" + "platformId": "linux-x64" }, { "description": "OmniSharp for Test OS(architecture)", @@ -165,10 +157,10 @@ export function GetTestPackageJSON() { "./binary2" ], "installTestPath": "./.omnisharp/binary", - "experimentalPackageId": "os-architecture" + "platformId": "os-architecture" }, { - "description": "Non omnisharp package without experimentalPackageID", + "description": "Non omnisharp package without platformId", "url": "https://download.visualstudio.microsoft.com/download/pr/100317420/a30d7e11bc435433d297adc824ee837f/coreclr-debug-win7-x64.zip", "fallbackUrl": "https://vsdebugger.blob.core.windows.net/coreclr-debug-1-14-4/coreclr-debug-win7-x64.zip", "installPath": ".debugger", diff --git a/test/unitTests/OmnisharpPackageCreator.test.ts b/test/unitTests/OmnisharpPackageCreator.test.ts index b06f56990..02cbdaee0 100644 --- a/test/unitTests/OmnisharpPackageCreator.test.ts +++ b/test/unitTests/OmnisharpPackageCreator.test.ts @@ -6,7 +6,7 @@ import { assert, should, expect } from "chai"; import { Package } from "../../src/packages"; import { GetTestPackageJSON } from "./OmnisharpDownloader.test"; -import { GetOmnisharpPackage, GetPackagesFromVersion, GetVersionFilePackage } from "../../src/omnisharp/OmnisharpPackageCreator"; +import { SetBinaryAndGetPackage, GetPackagesFromVersion, GetVersionFilePackage } from "../../src/omnisharp/OmnisharpPackageCreator"; suite("GetOmnisharpPackage : Output package depends on the input package and other input parameters like serverUrl", () => { @@ -25,20 +25,20 @@ suite("GetOmnisharpPackage : Output package depends on the input package and oth }); test('Throws exception if version is empty', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); - let fn = function () { GetOmnisharpPackage(testPackage, serverUrl, "", installPath); }; + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "os-architecture")); + let fn = function () { SetBinaryAndGetPackage(testPackage, serverUrl, "", installPath); }; expect(fn).to.throw('Invalid version'); }); test('Throws exception if version is null', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); - let fn = function () { GetOmnisharpPackage(testPackage, serverUrl, null, installPath);}; + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "os-architecture")); + let fn = function () { SetBinaryAndGetPackage(testPackage, serverUrl, null, installPath);}; expect(fn).to.throw('Invalid version'); }); test('Architectures, binaries and platforms do not change', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); - let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, version, installPath); + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "os-architecture")); + let resultPackage = SetBinaryAndGetPackage(testPackage, serverUrl, version, installPath); resultPackage.architectures.should.equal(testPackage.architectures); assert.equal(resultPackage.binaries, testPackage.binaries); @@ -46,51 +46,51 @@ suite("GetOmnisharpPackage : Output package depends on the input package and oth }); test('Version information is appended to the description', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); - let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", installPath); + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "os-architecture")); + let resultPackage = SetBinaryAndGetPackage(testPackage, serverUrl, "1.2.3", installPath); resultPackage.description.should.equal(`${testPackage.description}, Version = 1.2.3`); }); test('Download url is calculated using server url and version', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); - let resultPackage = GetOmnisharpPackage(testPackage, "http://someurl", "1.1.1", installPath); + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "os-architecture")); + let resultPackage = SetBinaryAndGetPackage(testPackage, "http://someurl", "1.1.1", installPath); resultPackage.url.should.equal("http://someurl/releases/1.1.1/omnisharp-os-architecture.zip"); }); test('Install path is calculated using the specified path and version', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "os-architecture")); - let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "os-architecture")); + let resultPackage = SetBinaryAndGetPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); resultPackage.installPath.should.equal("experimentPath/1.2.3"); }); test('Install test path is calculated using specified path, version and ends with Omnisharp.exe - Windows(x86)', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "win-x86")); - let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "win-x86")); + let resultPackage = SetBinaryAndGetPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/OmniSharp.exe"); }); test('Install test path is calculated using specified path, version and ends with Omnisharp.exe - Windows(x64)', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "win-x64")); - let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "win-x64")); + let resultPackage = SetBinaryAndGetPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/OmniSharp.exe"); }); test('Install test path is calculated using specified path, version and ends with mono.osx - OSX', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "osx")); - let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "osx")); + let resultPackage = SetBinaryAndGetPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/mono.osx"); }); test('Install test path is calculated using specified path, version and ends with mono.linux-x86 - Linux(x86)', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "linux-x86")); - let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "linux-x86")); + let resultPackage = SetBinaryAndGetPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/mono.linux-x86"); }); test('Install test path is calculated using specified path, version and ends with mono.linux-x86_64 - Linux(x64)', () => { - let testPackage = inputPackages.find(element => (element.experimentalPackageId && element.experimentalPackageId == "linux-x64")); - let resultPackage = GetOmnisharpPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); + let testPackage = inputPackages.find(element => (element.platformId && element.platformId == "linux-x64")); + let resultPackage = SetBinaryAndGetPackage(testPackage, serverUrl, "1.2.3", "experimentPath"); resultPackage.installTestPath.should.equal("./experimentPath/1.2.3/mono.linux-x86_64"); }); }); @@ -132,7 +132,7 @@ suite('GetPackagesFromVersion : Gets the experimental omnisharp packages from a "x86_64" ], "installTestPath": "./.omnisharp/OmniSharp.exe", - "experimentalPackageId": "win-x64" + "platformId": "win-x64" }, { "description": "OmniSharp for OSX", @@ -147,7 +147,7 @@ suite('GetPackagesFromVersion : Gets the experimental omnisharp packages from a "./run" ], "installTestPath": "./.omnisharp/mono.osx", - "experimentalPackageId": "osx" + "platformId": "osx" }, ]; @@ -172,7 +172,7 @@ suite('GetPackagesFromVersion : Gets the experimental omnisharp packages from a "x86_64" ], "installTestPath": "./.omnisharp/OmniSharp.exe", - "experimentalPackageId": "win-x64" + "platformId": "win-x64" }, { "description": "Some other package - no experimental id", @@ -192,7 +192,7 @@ suite('GetPackagesFromVersion : Gets the experimental omnisharp packages from a let outPackages = GetPackagesFromVersion(version, inputPackages, serverUrl, installPath); outPackages.length.should.equal(1); - outPackages[0].experimentalPackageId.should.equal("win-x64"); + outPackages[0].platformId.should.equal("win-x64"); }); }); From 88221c34b3c4ff4c4aad29d0abec00b3f491e826 Mon Sep 17 00:00:00 2001 From: Akshita Agarwal Date: Fri, 23 Feb 2018 17:40:19 -0800 Subject: [PATCH 05/12] Moved status item out of method and added version to message --- src/OmnisharpDownload.Helper.ts | 4 +--- src/omnisharp/OmnisharpDownloader.ts | 3 ++- src/omnisharp/OmnisharpManager.ts | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/OmnisharpDownload.Helper.ts b/src/OmnisharpDownload.Helper.ts index 3281d38d5..290bfc07a 100644 --- a/src/OmnisharpDownload.Helper.ts +++ b/src/OmnisharpDownload.Helper.ts @@ -61,7 +61,7 @@ export function ReportInstallationError(logger: Logger, error, telemetryProps: a logger.appendLine(errorMessage); } -export function SendInstallationTelemetry(logger: Logger, reporter: TelemetryReporter, telemetryProps: any, installationStage: string, platformInfo: PlatformInformation, statusItem: vscode.StatusBarItem) { +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; @@ -75,6 +75,4 @@ export function SendInstallationTelemetry(logger: Logger, reporter: TelemetryRep logger.appendLine(); installationStage = ''; logger.appendLine('Finished'); - - statusItem.dispose(); } \ No newline at end of file diff --git a/src/omnisharp/OmnisharpDownloader.ts b/src/omnisharp/OmnisharpDownloader.ts index 1af4d0838..0d46c4c30 100644 --- a/src/omnisharp/OmnisharpDownloader.ts +++ b/src/omnisharp/OmnisharpDownloader.ts @@ -73,7 +73,8 @@ export class OmnisharpDownloader { throw error;// throw the error up to the server } finally { - SendInstallationTelemetry(this.logger, this.reporter, this.telemetryProps, installationStage, this.platformInfo, this.statusItem); + SendInstallationTelemetry(this.logger, this.reporter, this.telemetryProps, installationStage, this.platformInfo); + this.statusItem.dispose(); } } diff --git a/src/omnisharp/OmnisharpManager.ts b/src/omnisharp/OmnisharpManager.ts index 6a12e1d68..f72959885 100644 --- a/src/omnisharp/OmnisharpManager.ts +++ b/src/omnisharp/OmnisharpManager.ts @@ -50,7 +50,7 @@ export class OmnisharpManager { return GetLaunchPathForVersion(platformInfo, version, installPath, extensionPath, useMono); } else { - throw new Error('Invalid omnisharp version specified'); + throw new Error(`Invalid omnisharp version - ${version}`); } } } From 9d6b82cd8e8dcdcb4d657f89b346b30388e970ba Mon Sep 17 00:00:00 2001 From: VperuS Date: Sat, 24 Feb 2018 03:45:00 +0200 Subject: [PATCH 06/12] Fix typo (#2066) --- src/omnisharp/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/omnisharp/server.ts b/src/omnisharp/server.ts index bd1a269e6..4a800df69 100644 --- a/src/omnisharp/server.ts +++ b/src/omnisharp/server.ts @@ -297,7 +297,7 @@ export class OmniSharpServer { return launchOmniSharp(cwd, args, launchPath).then(value => { if (value.usingMono) { - this._logger.appendLine(`OmniSharp server started wth Mono`); + this._logger.appendLine(`OmniSharp server started with Mono`); } else { this._logger.appendLine(`OmniSharp server started`); From a917cd6b3d393974d2af1ff4cc1088ddffc96b58 Mon Sep 17 00:00:00 2001 From: Akshita Agarwal Date: Sun, 25 Feb 2018 22:31:34 -0800 Subject: [PATCH 07/12] Formatting for better display structure --- src/OmnisharpDownload.Helper.ts | 1 + src/omnisharp/OmnisharpDownloader.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/OmnisharpDownload.Helper.ts b/src/OmnisharpDownload.Helper.ts index 290bfc07a..2e9c57643 100644 --- a/src/OmnisharpDownload.Helper.ts +++ b/src/OmnisharpDownload.Helper.ts @@ -75,4 +75,5 @@ export function SendInstallationTelemetry(logger: Logger, reporter: TelemetryRep logger.appendLine(); installationStage = ''; logger.appendLine('Finished'); + logger.appendLine(); } \ No newline at end of file diff --git a/src/omnisharp/OmnisharpDownloader.ts b/src/omnisharp/OmnisharpDownloader.ts index 0d46c4c30..20bb25ebd 100644 --- a/src/omnisharp/OmnisharpDownloader.ts +++ b/src/omnisharp/OmnisharpDownloader.ts @@ -39,7 +39,7 @@ export class OmnisharpDownloader { } public async DownloadAndInstallOmnisharp(version: string, serverUrl: string, installPath: string) { - this.logger.appendLine('Installing Omnisharp Packages...'); + this.logger.append('Installing Omnisharp Packages...'); this.logger.appendLine(); this.channel.show(); From 29deec5560937618f92f6bd2958c9321a09c739f Mon Sep 17 00:00:00 2001 From: Akshita Agarwal Date: Mon, 26 Feb 2018 10:36:46 -0800 Subject: [PATCH 08/12] Move to const fields in server --- src/omnisharp/OmnisharpDownloader.ts | 4 ++-- src/omnisharp/OmnisharpManager.ts | 8 ++++---- src/omnisharp/server.ts | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/omnisharp/OmnisharpDownloader.ts b/src/omnisharp/OmnisharpDownloader.ts index 20bb25ebd..3e334710d 100644 --- a/src/omnisharp/OmnisharpDownloader.ts +++ b/src/omnisharp/OmnisharpDownloader.ts @@ -78,13 +78,13 @@ export class OmnisharpDownloader { } } - public async GetLatestVersion(serverUrl: string, versionFilePathInServer): Promise { + public async GetLatestVersion(serverUrl: string, latestVersionFileServerPath: string): Promise { 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); + let filePackage = GetVersionFilePackage(serverUrl, latestVersionFileServerPath); //Fetch the latest version information from the file return await this.packageManager.GetLatestVersionFromFile(this.logger, this.status, this.proxy, this.strictSSL, filePackage); } diff --git a/src/omnisharp/OmnisharpManager.ts b/src/omnisharp/OmnisharpManager.ts index f72959885..7a2d77a8f 100644 --- a/src/omnisharp/OmnisharpManager.ts +++ b/src/omnisharp/OmnisharpManager.ts @@ -20,7 +20,7 @@ export class OmnisharpManager { private reporter?: TelemetryReporter) { } - public async GetOmnisharpPath(omnisharpPath: string, useMono: boolean, serverUrl: string, versionFilePathInServer: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation): Promise { + public async GetOmnisharpPath(omnisharpPath: string, useMono: boolean, serverUrl: string, latestVersionFileServerPath: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation): Promise { // Looks at the options path, installs the dependencies and returns the path to be loaded by the omnisharp server let downloader = new OmnisharpDownloader(this.channel, this.logger, this.packageJSON, platformInfo, this.reporter); if (path.isAbsolute(omnisharpPath)) { @@ -32,15 +32,15 @@ export class OmnisharpManager { } } else if (omnisharpPath == "latest") { - return await this.InstallLatestAndReturnLaunchPath(downloader, useMono, serverUrl, versionFilePathInServer, installPath, extensionPath, platformInfo); + return await this.InstallLatestAndReturnLaunchPath(downloader, useMono, serverUrl, latestVersionFileServerPath, installPath, extensionPath, platformInfo); } //If the path is neither a valid path on disk not the string "latest", treat it as a version return await this.InstallVersionAndReturnLaunchPath(downloader, omnisharpPath, useMono, serverUrl, installPath, extensionPath, platformInfo); } - public async InstallLatestAndReturnLaunchPath(downloader: OmnisharpDownloader, useMono: boolean, serverUrl: string, versionFilePathInServer: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { - let version = await downloader.GetLatestVersion(serverUrl, versionFilePathInServer); + public async InstallLatestAndReturnLaunchPath(downloader: OmnisharpDownloader, useMono: boolean, serverUrl: string, latestVersionFileServerPath: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { + let version = await downloader.GetLatestVersion(serverUrl, latestVersionFileServerPath); return await this.InstallVersionAndReturnLaunchPath(downloader, version, useMono, serverUrl, installPath, extensionPath, platformInfo); } diff --git a/src/omnisharp/server.ts b/src/omnisharp/server.ts index 4a800df69..6de6e4c38 100644 --- a/src/omnisharp/server.ts +++ b/src/omnisharp/server.ts @@ -60,6 +60,9 @@ module Events { } const TelemetryReportingDelay = 2 * 60 * 1000; // two minutes +const serverUrl = "https://roslynomnisharp.blob.core.windows.net"; +const installPath = ".omnisharp/experimental"; +const latestVersionFileServerPath = 'releases/versioninfo.txt'; export class OmniSharpServer { @@ -271,13 +274,10 @@ export class OmniSharpServer { let launchPath: string; if (this._options.path) { try { - let serverUrl = "https://roslynomnisharp.blob.core.windows.net"; - let installPath = ".omnisharp/experimental"; let extensionPath = utils.getExtensionPath(); - let versionFilePathInServer = 'releases/versioninfo.txt'; let manager = new OmnisharpManager(this._csharpChannel, this._csharpLogger, this._packageJSON, this._reporter); let platformInfo = await PlatformInformation.GetCurrent(); - launchPath = await manager.GetOmnisharpPath(this._options.path, this._options.useMono, serverUrl, versionFilePathInServer,installPath, extensionPath, platformInfo); + launchPath = await manager.GetOmnisharpPath(this._options.path, this._options.useMono, serverUrl, latestVersionFileServerPath, installPath, extensionPath, platformInfo); } catch (error) { this._logger.appendLine('Error occured in loading omnisharp from omnisharp.path'); From ea4c35121fff858fbad54b828e474a279e4d9753 Mon Sep 17 00:00:00 2001 From: Akshita Agarwal Date: Mon, 26 Feb 2018 10:45:47 -0800 Subject: [PATCH 09/12] Make methods private --- src/omnisharp/OmnisharpManager.ts | 6 +++--- test/unitTests/OmnisharpManager.test.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/omnisharp/OmnisharpManager.ts b/src/omnisharp/OmnisharpManager.ts index 7a2d77a8f..e60b1f6b1 100644 --- a/src/omnisharp/OmnisharpManager.ts +++ b/src/omnisharp/OmnisharpManager.ts @@ -39,12 +39,12 @@ export class OmnisharpManager { return await this.InstallVersionAndReturnLaunchPath(downloader, omnisharpPath, useMono, serverUrl, installPath, extensionPath, platformInfo); } - public async InstallLatestAndReturnLaunchPath(downloader: OmnisharpDownloader, useMono: boolean, serverUrl: string, latestVersionFileServerPath: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { + private async InstallLatestAndReturnLaunchPath(downloader: OmnisharpDownloader, useMono: boolean, serverUrl: string, latestVersionFileServerPath: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { let version = await downloader.GetLatestVersion(serverUrl, latestVersionFileServerPath); return await this.InstallVersionAndReturnLaunchPath(downloader, version, useMono, serverUrl, installPath, extensionPath, platformInfo); } - public async InstallVersionAndReturnLaunchPath(downloader: OmnisharpDownloader, version: string, useMono: boolean, serverUrl: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { + private async InstallVersionAndReturnLaunchPath(downloader: OmnisharpDownloader, version: string, useMono: boolean, serverUrl: string, installPath: string, extensionPath: string, platformInfo: PlatformInformation) { if (semver.valid(version)) { await downloader.DownloadAndInstallOmnisharp(version, serverUrl, installPath); return GetLaunchPathForVersion(platformInfo, version, installPath, extensionPath, useMono); @@ -55,7 +55,7 @@ export class OmnisharpManager { } } -export function GetLaunchPathForVersion(platformInfo: PlatformInformation, version: string, installPath: string, extensionPath: string, useMono: boolean) { +function GetLaunchPathForVersion(platformInfo: PlatformInformation, version: string, installPath: string, extensionPath: string, useMono: boolean) { if (!version) { throw new Error('Invalid Version'); } diff --git a/test/unitTests/OmnisharpManager.test.ts b/test/unitTests/OmnisharpManager.test.ts index e9338311e..e0ba1dff3 100644 --- a/test/unitTests/OmnisharpManager.test.ts +++ b/test/unitTests/OmnisharpManager.test.ts @@ -11,7 +11,7 @@ import { PlatformInformation } from "../../src/platform"; import { Logger } from '../../src/logger'; import { rimraf } from 'async-file'; import { GetTestPackageJSON } from './OmnisharpDownloader.test'; -import { GetLaunchPathForVersion, OmnisharpManager } from '../../src/omnisharp/OmnisharpManager'; +import { OmnisharpManager } from '../../src/omnisharp/OmnisharpManager'; const chai = require("chai"); chai.use(require("chai-as-promised")); From 4dde51c3ff2233227ed3a693e1c289997cbb53ae Mon Sep 17 00:00:00 2001 From: Akshita Agarwal Date: Mon, 26 Feb 2018 10:49:02 -0800 Subject: [PATCH 10/12] Move chai-as-promised to devDependencies --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b80ae5b22..fff9b856b 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ "postinstall": "node ./node_modules/vscode/bin/install" }, "dependencies": { - "chai-as-promised": "^7.1.1", "fs-extra": "^5.0.0", "http-proxy-agent": "^2.0.0", "https-proxy-agent": "^2.1.1", @@ -67,6 +66,7 @@ "chai": "4.1.2", "chai-arrays": "2.0.0", "chai-fs": "2.0.0", + "chai-as-promised": "7.1.1", "cross-env": "5.1.1", "del": "3.0.0", "gulp": "3.9.1", From 1ce54c165812d2bec21fc16bdf9abee0ea989643 Mon Sep 17 00:00:00 2001 From: Akshita Agarwal Date: Mon, 26 Feb 2018 11:17:39 -0800 Subject: [PATCH 11/12] Removed unnecessary function --- src/OmnisharpDownload.Helper.ts | 5 ----- src/omnisharp/OmnisharpDownloader.ts | 5 +++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/OmnisharpDownload.Helper.ts b/src/OmnisharpDownload.Helper.ts index 2e9c57643..997ade140 100644 --- a/src/OmnisharpDownload.Helper.ts +++ b/src/OmnisharpDownload.Helper.ts @@ -31,11 +31,6 @@ export function SetStatus() { 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) { diff --git a/src/omnisharp/OmnisharpDownloader.ts b/src/omnisharp/OmnisharpDownloader.ts index 3e334710d..50af5323e 100644 --- a/src/omnisharp/OmnisharpDownloader.ts +++ b/src/omnisharp/OmnisharpDownloader.ts @@ -9,7 +9,7 @@ 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'; +import { SetStatus, ReportInstallationError, SendInstallationTelemetry, GetNetworkDependencies } from '../OmnisharpDownload.Helper'; export class OmnisharpDownloader { private status: Status; @@ -50,7 +50,8 @@ export class OmnisharpDownloader { } try { - LogPlatformInformation(this.logger, this.platformInfo); + this.logger.appendLine(`Platform: ${this.platformInfo.toString()}`); + this.logger.appendLine(); installationStage = 'getPackageInfo'; let packages: Package[] = GetPackagesFromVersion(version, this.packageJSON.runtimeDependencies, serverUrl, installPath); From 7cf98862193070ce7782edd423a764ced4eb844a Mon Sep 17 00:00:00 2001 From: Akshita Agarwal Date: Mon, 26 Feb 2018 13:01:44 -0800 Subject: [PATCH 12/12] Modified test description --- test/unitTests/OmnisharpManager.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unitTests/OmnisharpManager.test.ts b/test/unitTests/OmnisharpManager.test.ts index e0ba1dff3..494bb0878 100644 --- a/test/unitTests/OmnisharpManager.test.ts +++ b/test/unitTests/OmnisharpManager.test.ts @@ -38,7 +38,7 @@ suite('GetExperimentalOmnisharpPath : Returns Omnisharp experiment path dependin util.setExtensionPath(tmpDir.name); }); - test('Throws error if the path is neither an absolute path nor a valid semver', async () => { + test('Throws error if the path is neither an absolute path nor a valid semver, nor the string "latest"', async () => { expect(manager.GetOmnisharpPath("Some incorrect path", useMono, serverUrl, versionFilepathInServer, installPath, extensionPath, platformInfo)).to.be.rejectedWith(Error); }); @@ -109,4 +109,4 @@ function GetTestOmnisharpManager() { let channel = vscode.window.createOutputChannel('Experiment Channel'); let logger = new Logger(text => channel.append(text)); return new OmnisharpManager(channel, logger, GetTestPackageJSON(), null); -} \ No newline at end of file +}