diff --git a/gulpfile.js b/gulpfile.js index 5f7e30266b..a114bb2f40 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,70 +1,35 @@ -var gulp = require('gulp'); -var decompress = require('gulp-decompress'); -var tslint = require("gulp-tslint"); -var es = require('event-stream'); -var GitHub = require('github-releases'); -var tmp = require('tmp'); -var vfs = require('vinyl-fs'); -var del = require('del'); -var fs = require('fs'); -var path = require('path'); - -tmp.setGracefulCleanup(); - -function downloadOmnisharp(version) { - var result = es.through(); - - function onError(err) { - result.emit('error', err); - } - - var repo = new GitHub({ - repo: 'OmniSharp/omnisharp-roslyn', - token: process.env['GITHUB_TOKEN'] - }); - - repo.getReleases({ tag_name: version }, function (err, releases) { - if (err) { return onError(err); } - if (!releases.length) { return onError(new Error('Release not found')); } - if (!releases[0].assets.length) { return onError(new Error('Assets not found')); } - - repo.downloadAsset(releases[0].assets[0], function (err, istream) { - if (err) { return onError(err); } - - tmp.file(function (err, tmpPath, fd, cleanupCallback) { - if (err) { return onError(err); } - - var ostream = fs.createWriteStream(null, { fd: fd }); - ostream.once('error', onError); - istream.once('error', onError); - ostream.once('finish', function () { - vfs.src(tmpPath).pipe(result); - }); - istream.pipe(ostream); - }); - }); - }); - - return result; -} - -gulp.task('omnisharp:clean', function () { +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +const decompress = require('gulp-decompress'); +const del = require('del'); +const fs = require('fs-extra-promise'); +const gulp = require('gulp'); +const path = require('path'); +const tslint = require('gulp-tslint'); +const omnisharpInstall = require('./out/omnisharpInstall'); + +gulp.task('omnisharp:clean', () => { return del('bin'); }); -gulp.task('omnisharp:fetch', ['omnisharp:clean'], function () { - return downloadOmnisharp('v1.6.7.9') +gulp.task('omnisharp:fetch', ['omnisharp:clean'], () => { + return omnisharpInstall.downloadOmnisharp('v1.6.7.9') .pipe(decompress({strip: 1})) .pipe(gulp.dest('bin')); }); -var allTypeScript = [ +const allTypeScript = [ 'src/**/*.ts', '!**/*.d.ts', '!**/typings**' ]; -var lintReporter = function (output, file, options) { +const lintReporter = (output, file, options) => { //emits: src/helloWorld.c:5:3: warning: implicit declaration of function ‘prinft’ var relativeBase = file.base.substring(file.cwd.length + 1).replace('\\', '/'); output.forEach(function(e) { @@ -73,7 +38,7 @@ var lintReporter = function (output, file, options) { }); }; -gulp.task('tslint', function () { +gulp.task('tslint', () => { gulp.src(allTypeScript) .pipe(tslint({ rulesDirectory: "node_modules/tslint-microsoft-contrib" @@ -84,37 +49,37 @@ gulp.task('tslint', function () { })) }); -gulp.task('omnisharp:fixscripts', ['omnisharp:fetch'], function () { +gulp.task('omnisharp:fixscripts', ['omnisharp:fetch'], () => { var _fixes = Object.create(null); _fixes['./bin/omnisharp.cmd'] = '@"%~dp0packages\\dnx-clr-win-x86.1.0.0-beta4\\bin\\dnx.exe" "%~dp0packages\\OmniSharp\\1.0.0\\root" run %*'; - _fixes['./bin/omnisharp'] = '#!/bin/bash\n\ -SOURCE="${BASH_SOURCE[0]}"\n\ -while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink\n\ - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"\n\ - SOURCE="$(readlink "$SOURCE")"\n\ - [[ $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\ -done\n\ -DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"\n\ -export SET DNX_APPBASE="$DIR/packages/OmniSharp/1.0.0/root"\n\ -export PATH=/usr/local/bin:/Library/Frameworks/Mono.framework/Commands:$PATH # this is required for the users of the Homebrew Mono package\n\ -exec "$DIR/packages/dnx-mono.1.0.0-beta4/bin/dnx" "$DNX_APPBASE" run "$@"\n\ -\n'; - - var promises = Object.keys(_fixes).map(function (key) { - return new Promise(function(resolve, reject) { - fs.writeFile(path.join(__dirname, key), _fixes[key], function (err) { + _fixes['./bin/omnisharp'] = '#!/bin/bash\n' ++ 'SOURCE="${BASH_SOURCE[0]}"\n' ++ 'while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink\n' ++ 'DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"\n' ++ 'SOURCE="$(readlink "$SOURCE")"\n' ++ '[[ $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' ++ 'done\n' ++ 'DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"\n' ++ 'export SET DNX_APPBASE="$DIR/packages/OmniSharp/1.0.0/root"\n' ++ 'export PATH=/usr/local/bin:/Library/Frameworks/Mono.framework/Commands:$PATH # this is required for the users of the Homebrew Mono package\n' ++ 'exec "$DIR/packages/dnx-mono.1.0.0-beta4/bin/dnx" "$DNX_APPBASE" run "$@"\n' ++ '\n'; + + const promises = Object.keys(_fixes).map(key => { + return new Promise((resolve, reject) => { + fs.writeFile(path.join(__dirname, key), _fixes[key], err => { if (err) { reject(err); - } else { + } + else { resolve(); } - }) + }); }); }); return Promise.all(promises) }); - gulp.task('omnisharp', ['omnisharp:fixscripts']); \ No newline at end of file diff --git a/package.json b/package.json index 10c5a627a3..dc8d7c26e3 100644 --- a/package.json +++ b/package.json @@ -15,26 +15,26 @@ ], "main": "./out/omnisharpMain", "scripts": { - "postinstall": "gulp omnisharp && tsc" + "postinstall": "tsc && gulp omnisharp" }, "dependencies": { + "del": "^2.0.2", + "event-stream": "^3.3.2", "fs-extra-promise": "^0.3.1", + "github-releases": "^0.3.0", "run-in-terminal": "*", "semver": "*", - "vscode-extension-telemetry": "0.0.4" + "vscode-extension-telemetry": "0.0.4", + "tmp": "0.0.28", + "vinyl-fs": "^2.2.1" }, "devDependencies": { - "del": "^2.0.2", - "event-stream": "^3.3.2", - "github-releases": "^0.3.0", "gulp": "^3.8.9", "gulp-decompress": "^1.2.0", "gulp-tslint": "^4.3.0", - "tmp": "0.0.28", "tslint": "^3.3.0", "tslint-microsoft-contrib": "^2.0.0", "typescript": "^1.7.3", - "vinyl-fs": "^2.2.1", "vscode": "^0.10.1" }, "engines": { diff --git a/src/omnisharpInstall.ts b/src/omnisharpInstall.ts new file mode 100644 index 0000000000..b861efca63 --- /dev/null +++ b/src/omnisharpInstall.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as fs from 'fs-extra-promise'; +import * as tmp from 'tmp'; +import * as vfs from 'vinyl-fs'; + +const es = require('event-stream'); +const github = require('github-releases'); + +tmp.setGracefulCleanup(); + +export function downloadOmnisharp(version: string) { + var result = es.through(); + + function onError(err) { + result.emit('error', err); + } + + var repo = new github({ + repo: 'OmniSharp/omnisharp-roslyn', + token: process.env['GITHUB_TOKEN'] + }); + + repo.getReleases({ tag_name: version }, function (err, releases) { + if (err) { + return onError(err); + } + + if (!releases.length) { + return onError(new Error('Release not found')); + } + + if (!releases[0].assets.length) { + return onError(new Error('Assets not found')); + } + + repo.downloadAsset(releases[0].assets[0], function (err, istream) { + if (err) { + return onError(err); + } + + tmp.file(function (err, tmpPath, fd, cleanupCallback) { + if (err) { + return onError(err); + } + + var ostream = fs.createWriteStream(null, { fd: fd }); + ostream.once('error', onError); + istream.once('error', onError); + ostream.once('finish', function () { + vfs.src(tmpPath).pipe(result); + }); + + istream.pipe(ostream); + }); + }); + }); + + return result; +} diff --git a/src/typings/del/del.d.ts b/src/typings/del/del.d.ts new file mode 100644 index 0000000000..372bf07a30 --- /dev/null +++ b/src/typings/del/del.d.ts @@ -0,0 +1,28 @@ +// Type definitions for del v2.2.0 +// Project: https://github.com/sindresorhus/del +// Definitions by: Asana , Aya Morisawa + +// /// +// /// + +declare module "del" { + import glob = require("glob"); + + function Del(pattern: string): Promise; + function Del(pattern: string, options: Del.Options): Promise; + + function Del(patterns: string[]): Promise; + function Del(patterns: string[], options: Del.Options): Promise; + + module Del { + function sync(pattern: string, options?: Options): string[]; + function sync(patterns: string[], options?: Options): string[]; + + interface Options extends glob.IOptions { + force?: boolean; + dryRun?: boolean; + } + } + + export = Del; +} diff --git a/src/typings/fs-extra-promise/fs-extra-promise.d.ts b/src/typings/fs-extra-promise/fs-extra-promise.d.ts index 1c669e35cf..c57403c79f 100644 --- a/src/typings/fs-extra-promise/fs-extra-promise.d.ts +++ b/src/typings/fs-extra-promise/fs-extra-promise.d.ts @@ -4,8 +4,8 @@ // Imported from: https://github.com/soywiz/typescript-node-definitions/fs-extra.d.ts via TSD fs-extra definition -// /// -// /// +/// +/// declare module "fs-extra-promise" { import stream = require("stream"); @@ -177,13 +177,16 @@ declare module "fs-extra-promise" { encoding?: string; fd?: number; mode?: number; - bufferSize?: number; + autoClose?: boolean; } + export interface WriteStreamOptions { flags?: string; - encoding?: string; - string?: string; + defaultEncounding?: string; + fd?: number; + mode?: number; } + export function createReadStream(path: string, options?: ReadStreamOptions): ReadStream; export function createWriteStream(path: string, options?: WriteStreamOptions): WriteStream; diff --git a/src/typings/ref.d.ts b/src/typings/ref.d.ts index 07bc4a016a..32edf923c7 100644 --- a/src/typings/ref.d.ts +++ b/src/typings/ref.d.ts @@ -3,4 +3,5 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -/// \ No newline at end of file +/// +/// \ No newline at end of file diff --git a/src/typings/tmp/tmp.d.ts b/src/typings/tmp/tmp.d.ts new file mode 100644 index 0000000000..b626734426 --- /dev/null +++ b/src/typings/tmp/tmp.d.ts @@ -0,0 +1,47 @@ +// Type definitions for tmp v0.0.28 +// Project: https://www.npmjs.com/package/tmp +// Definitions by: Jared Klopper + +declare module "tmp" { + + module tmp { + interface Options extends SimpleOptions { + mode?: number; + } + + interface SimpleOptions { + prefix?: string; + postfix?: string; + template?: string; + dir?: string; + tries?: number; + keep?: boolean; + unsafeCleanup?: boolean; + } + + interface SynchrounousResult { + name: string; + fd: number; + removeCallback: () => void; + } + + function file(callback: (err: any, path: string, fd: number, cleanupCallback: () => void) => void): void; + function file(config: Options, callback?: (err: any, path: string, fd: number, cleanupCallback: () => void) => void): void; + + function fileSync(config?: Options): SynchrounousResult; + + function dir(callback: (err: any, path: string, cleanupCallback: () => void) => void): void; + function dir(config: Options, callback?: (err: any, path: string, cleanupCallback: () => void) => void): void; + + function dirSync(config?: Options): SynchrounousResult; + + function tmpName(callback: (err: any, path: string) => void): void; + function tmpName(config: SimpleOptions, callback?: (err: any, path: string) => void): void; + + function tmpNameSync(config?: SimpleOptions): string; + + function setGracefulCleanup(): void; + } + + export = tmp; +} diff --git a/src/typings/vinyl-fs/vinyl-fs.d.ts b/src/typings/vinyl-fs/vinyl-fs.d.ts new file mode 100644 index 0000000000..9356db7cbc --- /dev/null +++ b/src/typings/vinyl-fs/vinyl-fs.d.ts @@ -0,0 +1,164 @@ +// Type definitions for vinyl-fs +// Project: https://github.com/wearefractal/vinyl-fs +// Definitions by: vvakame + +// /// +// /// + +declare module NodeJS { + interface WritableStream { + write(buffer: any/* Vinyl.File */, cb?: Function): boolean; + } +} + +declare module "vinyl-fs" { + import _events = require("events"); + import File = require("vinyl"); + + interface ISrcOptions { + /** Specifies the working directory the folder is relative to */ + cwd?: string; + + /** + * Specifies the folder relative to the cwd + * This is used to determine the file names when saving in .dest() + * Default is where the glob begins + */ + base?: string; + + /** + * Setting this to false will make file.contents a paused stream + * If true it will buffer the file contents + * Defaults to true + */ + buffer?: boolean; + + /** + * Setting this to false will ignore the contents of the file and disable writing to disk to speed up operations + * Defaults to true + */ + read?: boolean; + + /** Only find files that have been modified since the time specified */ + since?: Date|number; + + /** Setting this to true will create a duplex stream, one that passes through items and emits globbed files. + * Defaults to false */ + passthrough?: boolean; + + /** Setting this to true will enable sourcemaps. + * Defaults to false */ + sourcemaps?: boolean; + } + + /** + * Gets files that match the glob and converts them into the vinyl format + * @param globs Takes a glob string or an array of glob strings as the first argument + * Globs are executed in order, so negations should follow positive globs + * fs.src(['!b*.js', '*.js']) would not exclude any files, but this would: fs.src(['*.js', '!b*.js']) + * @param opt Options Vinyl source options, changes the way the files are read, found, or stored in the vinyl stream + */ + function src(globs: string|string[], opt?: ISrcOptions): NodeJS.ReadWriteStream; + + /** + * This is just a glob-watcher + * + * @param globs Takes a glob string or an array of glob strings as the first argument + * Globs are executed in order, so negations should follow positive globs + * fs.src(['!b*.js', '*.js']) would not exclude any files, but this would: fs.src(['*.js', '!b*.js']) + */ + function watch(globs: string|string[], cb?: (outEvt: { type: any; path: any; old: any; }) => void): _events.EventEmitter; + + /** + * This is just a glob-watcher + * + * @param globs Takes a glob string or an array of glob strings as the first argument + * Globs are executed in order, so negations should follow positive globs + * fs.src(['!b*.js', '*.js']) would not exclude any files, but this would: fs.src(['*.js', '!b*.js']) + */ + function watch(globs: string|string[], opt?: { interval?: number; debounceDelay?: number; cwd?: string; maxListeners?: Function; }, cb?: (outEvt: { type: any; path: any; old: any; }) => void): _events.EventEmitter; + + /** + * On write the stream will save the vinyl File to disk at the folder/cwd specified. + * After writing the file to disk, it will be emitted from the stream so you can keep piping these around. + * The file will be modified after being written to this stream: + * cwd, base, and path will be overwritten to match the folder + * stat.mode will be overwritten if you used a mode parameter + * contents will have it's position reset to the beginning if it is a stream + * @param folder destination folder + */ + function dest(folder: string, opt?: { + /** Specify the working directory the folder is relative to + * Default is process.cwd() + */ + cwd?: string; + + /** Specify the mode the files should be created with + * Default is the mode of the input file (file.stat.mode) + * or the process mode if the input file has no mode property + */ + mode?: number|string; + + /** Specify the mode the directory should be created with. Default is the process mode */ + dirMode?: number|string; + + /** Specify if existing files with the same path should be overwritten or not. Default is true, to always overwrite existing files */ + overwrite?: boolean; + }): NodeJS.ReadWriteStream; + + /** + * On write the stream will save the vinyl File to disk at the folder/cwd specified. + * After writing the file to disk, it will be emitted from the stream so you can keep piping these around. + * The file will be modified after being written to this stream: + * cwd, base, and path will be overwritten to match the folder + * stat.mode will be overwritten if you used a mode parameter + * contents will have it's position reset to the beginning if it is a stream + * @param getFolderPath function that takes in a file and returns a folder path + */ + function dest(getFolderPath: (file: File) => string): NodeJS.ReadWriteStream; + + /** + * On write the stream will create a symbolic link (i.e. symlink) on disk at the folder/cwd specified. + * After creating the symbolic link, it will be emitted from the stream so you can keep piping these around. + * The file will be modified after being written to this stream: + * cwd, base, and path will be overwritten to match the folder + */ + function symlink(folder: string, opts?: { + /** + * Specify the working directory the folder is relative to + * Default is process.cwd() + */ + cwd?: string; + + /** Specify the mode the directory should be created with. Default is the process mode */ + mode?: number|string; + + /** + * Specify the mode the directory should be created with + * Default is the process mode + */ + dirMode?: number + }): NodeJS.ReadWriteStream; + + /** + * On write the stream will create a symbolic link (i.e. symlink) on disk at the folder/cwd generated from getFolderPath. + * After creating the symbolic link, it will be emitted from the stream so you can keep piping these around. + * The file will be modified after being written to this stream: + * cwd, base, and path will be overwritten to match the folder + */ + function symlink(getFolderPath: (File: File) => string, opts?: + { + /** + * Specify the working directory the folder is relative to + * Default is process.cwd() + */ + cwd?: string; + + /** + * Specify the mode the directory should be created with + * Default is the process mode + */ + dirMode?: number + + }): NodeJS.ReadWriteStream; +} diff --git a/src/typings/vinyl/vinyl.d.ts b/src/typings/vinyl/vinyl.d.ts new file mode 100644 index 0000000000..d716dc9117 --- /dev/null +++ b/src/typings/vinyl/vinyl.d.ts @@ -0,0 +1,141 @@ +// Type definitions for vinyl 1.1.0 +// Project: https://github.com/wearefractal/vinyl +// Definitions by: vvakame , jedmao + +// /// + +declare module "vinyl" { + + import fs = require("fs"); + + /** + * A virtual file format. + */ + class File { + constructor(options?: { + + /** + * Default: process.cwd() + */ + cwd?: string; + + /** + * Used for relative pathing. Typically where a glob starts. + */ + base?: string; + + /** + * Full path to the file. + */ + path?: string; + + /** + * Path history. Has no effect if options.path is passed. + */ + history?: string[]; + + /** + * The result of an fs.stat call. See fs.Stats for more information. + */ + stat?: fs.Stats; + + /** + * File contents. + * Type: Buffer, Stream, or null + */ + contents?: Buffer | NodeJS.ReadWriteStream; + }); + + /** + * Default: process.cwd() + */ + public cwd: string; + + /** + * Used for relative pathing. Typically where a glob starts. + */ + public dirname: string; + public basename: string; + public base: string; + + /** + * Full path to the file. + */ + public path: string; + public stat: fs.Stats; + + /** + * Gets and sets stem (filename without suffix) for the file path. + */ + public stem: string; + + /** + * Gets and sets path.extname for the file path + */ + public extname: string; + + /** + * Array of path values the file object has had + */ + public history: string[]; + + /** + * Type: Buffer|Stream|null (Default: null) + */ + public contents: Buffer | NodeJS.ReadableStream; + + /** + * Returns path.relative for the file base and file path. + * Example: + * var file = new File({ + * cwd: "/", + * base: "/test/", + * path: "/test/file.js" + * }); + * console.log(file.relative); // file.js + */ + public relative: string; + + /** + * Returns true if file.contents is a Buffer. + */ + public isBuffer(): boolean; + + /** + * Returns true if file.contents is a Stream. + */ + public isStream(): boolean; + + /** + * Returns true if file.contents is null. + */ + public isNull(): boolean; + + /** + * Returns a new File object with all attributes cloned. Custom attributes are deep-cloned. + */ + public clone(opts?: { contents?: boolean, deep?:boolean }): File; + + /** + * If file.contents is a Buffer, it will write it to the stream. + * If file.contents is a Stream, it will pipe it to the stream. + * If file.contents is null, it will do nothing. + */ + public pipe( + stream: T, + opts?: { + /** + * If false, the destination stream will not be ended (same as node core). + */ + end?: boolean; + }): T; + + /** + * Returns a pretty String interpretation of the File. Useful for console.log. + */ + public inspect(): string; + } + + export = File; + +}