Skip to content

Commit 0b61630

Browse files
Merge pull request #106 from DustinCampbell/download-omnisharp
Download and install OmniSharp during extension activation if necessary
2 parents 83ea676 + 88dfe82 commit 0b61630

File tree

9 files changed

+243
-474
lines changed

9 files changed

+243
-474
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
bin
22
node_modules
33
out
4+
.omnisharp
45

56
*.vsix

gulpfile.js

Lines changed: 11 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,17 @@
55

66
'use strict';
77

8-
const decompress = require('gulp-decompress');
98
const del = require('del');
10-
const fs = require('fs-extra-promise');
119
const gulp = require('gulp');
12-
const path = require('path');
1310
const tslint = require('gulp-tslint');
14-
const omnisharpInstall = require('./out/omnisharpInstall');
11+
const omnisharpDownload = require('./out/omnisharpDownload');
1512

1613
gulp.task('omnisharp:clean', () => {
17-
return del('bin');
14+
return del('.omnisharp');
1815
});
1916

2017
gulp.task('omnisharp:fetch', ['omnisharp:clean'], () => {
21-
return omnisharpInstall.downloadOmnisharp('v1.6.7.9')
22-
.pipe(decompress({strip: 1}))
23-
.pipe(gulp.dest('bin'));
18+
return omnisharpDownload.downloadOmnisharp();
2419
});
2520

2621
const allTypeScript = [
@@ -40,46 +35,13 @@ const lintReporter = (output, file, options) => {
4035

4136
gulp.task('tslint', () => {
4237
gulp.src(allTypeScript)
43-
.pipe(tslint({
44-
rulesDirectory: "node_modules/tslint-microsoft-contrib"
45-
}))
46-
.pipe(tslint.report(lintReporter, {
47-
summarizeFailureOutput: false,
48-
emitError: false
49-
}))
38+
.pipe(tslint({
39+
rulesDirectory: "node_modules/tslint-microsoft-contrib"
40+
}))
41+
.pipe(tslint.report(lintReporter, {
42+
summarizeFailureOutput: false,
43+
emitError: false
44+
}))
5045
});
5146

52-
gulp.task('omnisharp:fixscripts', ['omnisharp:fetch'], () => {
53-
54-
var _fixes = Object.create(null);
55-
_fixes['./bin/omnisharp.cmd'] = '@"%~dp0packages\\dnx-clr-win-x86.1.0.0-beta4\\bin\\dnx.exe" "%~dp0packages\\OmniSharp\\1.0.0\\root" run %*';
56-
_fixes['./bin/omnisharp'] = '#!/bin/bash\n'
57-
+ 'SOURCE="${BASH_SOURCE[0]}"\n'
58-
+ 'while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink\n'
59-
+ 'DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"\n'
60-
+ 'SOURCE="$(readlink "$SOURCE")"\n'
61-
+ '[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located\n'
62-
+ 'done\n'
63-
+ 'DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"\n'
64-
+ 'export SET DNX_APPBASE="$DIR/packages/OmniSharp/1.0.0/root"\n'
65-
+ 'export PATH=/usr/local/bin:/Library/Frameworks/Mono.framework/Commands:$PATH # this is required for the users of the Homebrew Mono package\n'
66-
+ 'exec "$DIR/packages/dnx-mono.1.0.0-beta4/bin/dnx" "$DNX_APPBASE" run "$@"\n'
67-
+ '\n';
68-
69-
const promises = Object.keys(_fixes).map(key => {
70-
return new Promise((resolve, reject) => {
71-
fs.writeFile(path.join(__dirname, key), _fixes[key], err => {
72-
if (err) {
73-
reject(err);
74-
}
75-
else {
76-
resolve();
77-
}
78-
});
79-
});
80-
});
81-
82-
return Promise.all(promises)
83-
});
84-
85-
gulp.task('omnisharp', ['omnisharp:fixscripts']);
47+
gulp.task('omnisharp', ['omnisharp:fetch']);

package.json

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,20 @@
1515
],
1616
"main": "./out/omnisharpMain",
1717
"scripts": {
18-
"postinstall": "tsc && gulp omnisharp"
18+
"postinstall": "tsc"
1919
},
2020
"dependencies": {
21+
"decompress": "^3.0.0",
2122
"del": "^2.0.2",
22-
"event-stream": "^3.3.2",
2323
"fs-extra-promise": "^0.3.1",
2424
"github-releases": "^0.3.0",
2525
"run-in-terminal": "*",
2626
"semver": "*",
2727
"vscode-extension-telemetry": "0.0.4",
28-
"tmp": "0.0.28",
29-
"vinyl-fs": "^2.2.1"
28+
"tmp": "0.0.28"
3029
},
3130
"devDependencies": {
32-
"gulp": "^3.8.9",
33-
"gulp-decompress": "^1.2.0",
31+
"gulp": "^3.9.1",
3432
"gulp-tslint": "^4.3.0",
3533
"tslint": "^3.3.0",
3634
"tslint-microsoft-contrib": "^2.0.0",

src/omnisharpDownload.ts

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
'use strict';
7+
8+
import * as fs from 'fs-extra-promise';
9+
import * as path from 'path';
10+
import * as tmp from 'tmp';
11+
12+
const Decompress = require('decompress');
13+
const Github = require('github-releases');
14+
15+
const OmnisharpRepo = 'OmniSharp/omnisharp-roslyn';
16+
const OmnisharpVersion = 'v1.9-alpha3';
17+
const DefaultInstallLocation = path.join(__dirname, '../.omnisharp');
18+
19+
tmp.setGracefulCleanup();
20+
21+
function getOmnisharpAssetName(): string {
22+
switch (process.platform) {
23+
case 'win32':
24+
return 'omnisharp-win-x64-dnx451.zip';
25+
case 'darwin':
26+
return 'omnisharp-osx-x64-dnxcore50.tar.gz';
27+
case 'linux':
28+
return 'omnisharp-linux-x64-dnxcore50.tar.gz';
29+
default:
30+
throw new Error(`Unsupported platform: ${process.platform}`);
31+
}
32+
}
33+
34+
export function downloadOmnisharp(): Promise<boolean> {
35+
return new Promise<boolean>((resolve, reject) => {
36+
console.log(`[OmniSharp]: Installing to ${DefaultInstallLocation}`);
37+
38+
const repo = new Github({ repo: OmnisharpRepo, token: null });
39+
const assetName = getOmnisharpAssetName();
40+
41+
console.log(`[OmniSharp] Looking for ${OmnisharpVersion}, ${assetName}...`);
42+
43+
repo.getReleases({ tag_name: OmnisharpVersion }, (err, releases) => {
44+
if (err) {
45+
return reject(err);
46+
}
47+
48+
if (!releases.length) {
49+
return reject(new Error(`OmniSharp release ${OmnisharpVersion} not found.`));
50+
}
51+
52+
// Note: there should only be a single release, but use the first one
53+
// if there are ever multiple results. Same thing for assets.
54+
let foundAsset = null;
55+
56+
for (var asset of releases[0].assets) {
57+
if (asset.name === assetName) {
58+
foundAsset = asset;
59+
break;
60+
}
61+
}
62+
63+
if (!foundAsset) {
64+
return reject(new Error(`OmniSharp release ${OmnisharpVersion} asset, ${assetName} not found.`));
65+
}
66+
67+
console.log(`[OmniSharp] Found it!`);
68+
69+
repo.downloadAsset(foundAsset, (err, inStream) => {
70+
if (err) {
71+
return reject(err);
72+
}
73+
74+
tmp.file((err, tmpPath, fd, cleanupCallback) => {
75+
if (err) {
76+
return reject(err);
77+
}
78+
79+
console.log(`[OmniSharp] Downloading to ${tmpPath}...`);
80+
81+
const outStream = fs.createWriteStream(null, { fd: fd });
82+
83+
outStream.once('error', err => reject(err));
84+
inStream.once('error', err => reject(err));
85+
86+
outStream.once('finish', () => {
87+
// At this point, the asset has finished downloading.
88+
89+
console.log(`[OmniSharp] Download complete!`);
90+
91+
let decompress = new Decompress()
92+
.src(tmpPath)
93+
.dest(DefaultInstallLocation);
94+
95+
if (path.extname(foundAsset.name).toLowerCase() === '.zip') {
96+
decompress = decompress.use(Decompress.zip());
97+
console.log(`[OmniSharp] Unzipping...`);
98+
}
99+
else {
100+
decompress = decompress.use(Decompress.targz());
101+
console.log(`[OmniSharp] Untaring...`);
102+
}
103+
104+
decompress.run((err, files) => {
105+
if (err) {
106+
return reject(err);
107+
}
108+
109+
console.log(`[OmniSharp] Done! ${files.length} files unpacked.`)
110+
111+
return resolve(true);
112+
});
113+
});
114+
115+
inStream.pipe(outStream);
116+
});
117+
});
118+
});
119+
});
120+
}

src/omnisharpInstall.ts

Lines changed: 0 additions & 65 deletions
This file was deleted.

src/omnisharpPath.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
'use strict';
7+
8+
import * as fs from 'fs-extra-promise';
9+
import * as path from 'path';
10+
import * as vscode from 'vscode';
11+
12+
const runFileName = process.platform === 'win32' ? 'run.cmd' : 'run';
13+
const omnisharpFileName = process.platform === 'win32' ? 'omnisharp.cmd' : 'omnisharp';
14+
const omnisharpExeFileName = process.platform === 'win32' ? 'omnisharp.exe' : 'omnisharp';
15+
16+
function getLaunchFilePath(filePathOrFolder: string): Promise<string> {
17+
return fs.lstatAsync(filePathOrFolder).then(stats => {
18+
// If a file path was passed, assume its the launch file.
19+
if (stats.isFile()) {
20+
return filePathOrFolder;
21+
}
22+
23+
// Otherwise, search the specified folder.
24+
let candidate: string;
25+
26+
candidate = path.join(filePathOrFolder, runFileName);
27+
if (fs.existsSync(candidate)) {
28+
return candidate;
29+
}
30+
31+
candidate = path.join(filePathOrFolder, omnisharpFileName);
32+
if (fs.existsSync(candidate)) {
33+
return candidate;
34+
}
35+
36+
candidate = path.join(filePathOrFolder, omnisharpExeFileName);
37+
if (fs.existsSync(candidate)) {
38+
return candidate;
39+
}
40+
41+
throw new Error(`Could not fnd launch file in ${filePathOrFolder}. Expected '${runFileName}', '${omnisharpFileName}', '${omnisharpExeFileName}'`);
42+
});
43+
}
44+
45+
function getLaunchPathFromSettings(): Promise<string> {
46+
const setting = vscode.workspace.getConfiguration('csharp').get<string>('omnisharp');
47+
48+
if (setting) {
49+
return getLaunchFilePath(setting)
50+
.catch(err => {
51+
vscode.window.showWarningMessage(`Invalid "csharp.omnisharp" use setting specified ('${setting}).`);
52+
throw err;
53+
})
54+
}
55+
56+
return Promise.reject<string>(new Error('OmniSharp use setting does not exists.'));
57+
}
58+
59+
function getLaunchPathFromDefaultInstallFolder(): Promise<string> {
60+
const installLocation = path.join(__dirname, '../.omnisharp');
61+
return getLaunchFilePath(installLocation);
62+
}
63+
64+
export function getOmnisharpLaunchFilePath(): Promise<string> {
65+
// Attempt to find launch file path first from settings, and then from the default install location.
66+
67+
return getLaunchPathFromSettings()
68+
.catch(getLaunchPathFromDefaultInstallFolder);
69+
}

0 commit comments

Comments
 (0)