Parcourir la source

Closes #225 - reduces startup time & package size

Replaces spawn-rx with homegrown (stolen) implementation
Removes telemetry for now (until I get an azure account again)
Removes unused lodash modules
Removes unused testing dependencies
main
Eric Amodio il y a 7 ans
Parent
révision
060e992a92
11 fichiers modifiés avec 358 ajouts et 297 suppressions
  1. +45
    -104
      package-lock.json
  2. +1
    -7
      package.json
  3. +3
    -3
      src/commands/common.ts
  4. +7
    -9
      src/extension.ts
  5. +33
    -44
      src/git/git.ts
  6. +6
    -5
      src/git/gitLocator.ts
  7. +148
    -0
      src/git/shell.ts
  8. +2
    -2
      src/logger.ts
  9. +0
    -5
      src/system/object.ts
  10. +0
    -5
      src/system/string.ts
  11. +113
    -113
      src/telemetry.ts

+ 45
- 104
package-lock.json Voir le fichier

@ -16,19 +16,13 @@
"integrity": "sha1-qjuL2ivlErGuCgV7lC6GnDcKVWk=",
"dev": true,
"requires": {
"@types/node": "8.5.1"
"@types/node": "8.5.2"
}
},
"@types/mocha": {
"version": "2.2.44",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.44.tgz",
"integrity": "sha512-k2tWTQU8G4+iSMvqKi0Q9IIsWAp/n8xzdZS4Q4YVIltApoMA00wFBFdlJnmoaK1/z7B0Cy0yPe6GgXteSmdUNw==",
"dev": true
},
"@types/node": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.1.tgz",
"integrity": "sha512-SrmAO+NhnsuG/6TychSl2VdxBZiw/d6V+8j+DFo8O3PwFi+QeYXWHhAw+b170aSc6zYab6/PjEWRZHIDN9mNUw==",
"version": "8.5.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.2.tgz",
"integrity": "sha512-KA4GKOpgXnrqEH2eCVhiv2CsxgXGQJgV1X0vsGlh+WCnxbeAE1GT44ZsTU1IN5dEeV/gDupKa7gWo08V5IxWVQ==",
"dev": true
},
"@types/tmp": {
@ -140,16 +134,6 @@
}
}
},
"applicationinsights": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-0.21.0.tgz",
"integrity": "sha1-Ng9JIrg7wHhMb3TfBjZ+QlOJGWM=",
"requires": {
"diagnostic-channel": "0.1.0",
"diagnostic-channel-publishers": "0.1.3",
"zone.js": "0.7.6"
}
},
"aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@ -566,7 +550,7 @@
"requires": {
"ansi-styles": "3.2.0",
"escape-string-regexp": "1.0.5",
"supports-color": "4.4.0"
"supports-color": "4.5.0"
}
},
"chokidar": {
@ -717,9 +701,9 @@
}
},
"commander": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==",
"dev": true
},
"commondir": {
@ -920,9 +904,10 @@
"dev": true
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
@ -958,23 +943,10 @@
"minimalistic-assert": "1.0.0"
}
},
"diagnostic-channel": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-0.1.0.tgz",
"integrity": "sha1-emrYrVBmusVE2go3m6F0ujYqV88=",
"requires": {
"semver": "5.4.1"
}
},
"diagnostic-channel-publishers": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.1.3.tgz",
"integrity": "sha1-y9bdEK8e7M1JWsDtZ69fi2hvAKM="
},
"diff": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
"integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz",
"integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==",
"dev": true
},
"diffie-hellman": {
@ -2948,7 +2920,7 @@
"dev": true,
"requires": {
"chalk": "1.1.3",
"commander": "2.11.0",
"commander": "2.12.2",
"is-my-json-valid": "2.17.1",
"pinkie-promise": "2.0.1"
},
@ -3565,11 +3537,6 @@
"integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=",
"dev": true
},
"lodash.assign": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc="
},
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@ -3584,11 +3551,6 @@
"lodash._root": "3.0.1"
}
},
"lodash.escaperegexp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
"integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c="
},
"lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
@ -3604,7 +3566,8 @@
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
"dev": true
},
"lodash.keys": {
"version": "3.1.2",
@ -3886,13 +3849,25 @@
"supports-color": "4.4.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"commander": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
"dev": true
},
"diff": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
"integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
"dev": true
},
"supports-color": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
"dev": true,
"requires": {
"ms": "2.0.0"
"has-flag": "2.0.0"
}
}
}
@ -3914,7 +3889,8 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
"multimatch": {
"version": "2.1.0",
@ -4753,14 +4729,6 @@
"aproba": "1.2.0"
}
},
"rxjs": {
"version": "5.5.5",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.5.tgz",
"integrity": "sha512-D/MfQnPMBk8P8gfwGxvCkuaWBcG58W7dUMT//URPoYzIbDEKT0GezdirkK5whMgKFBATfCoTpxO8bJQGJ04W5A==",
"requires": {
"symbol-observable": "1.0.1"
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
@ -4779,7 +4747,8 @@
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"dev": true
},
"serialize-javascript": {
"version": "1.4.0",
@ -4872,16 +4841,6 @@
"integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=",
"dev": true
},
"spawn-rx": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/spawn-rx/-/spawn-rx-2.0.12.tgz",
"integrity": "sha512-gOPXiQQFQ9lTOLuys0iMn3jfxxv9c7zzwhbYLOEbQGvEShHVJ5sSR1oD3Daj88os7jKArDYT7rbOKdvNhe7iEg==",
"requires": {
"debug": "2.6.9",
"lodash.assign": "4.2.0",
"rxjs": "5.5.5"
}
},
"spdx-correct": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
@ -5103,19 +5062,14 @@
"dev": true
},
"supports-color": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
"dev": true,
"requires": {
"has-flag": "2.0.0"
}
},
"symbol-observable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz",
"integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ="
},
"sync-exec": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz",
@ -5238,8 +5192,8 @@
"babel-code-frame": "6.26.0",
"builtin-modules": "1.1.1",
"chalk": "2.3.0",
"commander": "2.11.0",
"diff": "3.3.1",
"commander": "2.12.2",
"diff": "3.4.0",
"glob": "7.1.2",
"minimatch": "3.0.4",
"resolve": "1.5.0",
@ -5296,14 +5250,6 @@
"requires": {
"commander": "2.12.2",
"source-map": "0.6.1"
},
"dependencies": {
"commander": {
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==",
"dev": true
}
}
},
"uglify-to-browserify": {
@ -5624,7 +5570,7 @@
"mkdirp": "0.5.1",
"node-libs-browser": "2.1.0",
"source-map": "0.5.7",
"supports-color": "4.4.0",
"supports-color": "4.5.0",
"tapable": "0.2.8",
"uglifyjs-webpack-plugin": "0.4.6",
"watchpack": "1.4.0",
@ -5864,11 +5810,6 @@
"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="
}
}
}

+ 1
- 7
package.json Voir le fichier

@ -2935,26 +2935,20 @@
"prepush": "npm run compile"
},
"dependencies": {
"applicationinsights": "0.21.0",
"copy-paste": "1.3.0",
"date-fns": "1.29.0",
"iconv-lite": "0.4.19",
"lodash.debounce": "4.0.8",
"lodash.escaperegexp": "4.1.2",
"lodash.isequal": "4.5.0",
"lodash.once": "4.1.1",
"spawn-rx": "2.0.12",
"tmp": "0.0.33",
"tslib": "^1.8.1"
},
"devDependencies": {
"@types/copy-paste": "1.1.30",
"@types/iconv-lite": "0.0.1",
"@types/mocha": "2.2.44",
"@types/node": "8.5.1",
"@types/node": "8.5.2",
"@types/tmp": "0.0.33",
"husky": "^0.14.3",
"mocha": "4.0.1",
"ts-loader": "^3.2.0",
"tslint": "5.8.0",
"typescript": "2.6.2",

+ 3
- 3
src/commands/common.ts Voir le fichier

@ -3,7 +3,7 @@ import { commands, Disposable, SourceControlResourceGroup, SourceControlResource
import { ExplorerNode, ExplorerRefNode } from '../views/explorerNodes';
import { GitBranch, GitCommit, GitRemote, GitUri } from '../gitService';
import { Logger } from '../logger';
import { Telemetry } from '../telemetry';
// import { Telemetry } from '../telemetry';
export enum Commands {
ClearFileAnnotations = 'gitlens.clearFileAnnotations',
@ -162,7 +162,7 @@ export abstract class Command extends Disposable {
abstract execute(...args: any[]): any;
protected _execute(command: string, ...args: any[]): any {
Telemetry.trackEvent(command);
// Telemetry.trackEvent(command);
const [context, rest] = Command.parseContext(command, this.contextParsingOptions, ...args);
return this.preExecute(context, ...rest);
@ -282,7 +282,7 @@ export abstract class EditorCommand extends Disposable {
}
private executeCore(command: string, editor: TextEditor, edit: TextEditorEdit, ...args: any[]): any {
Telemetry.trackEvent(command);
// Telemetry.trackEvent(command);
return this.execute(editor, edit, ...args);
}

+ 7
- 9
src/extension.ts Voir le fichier

@ -3,7 +3,7 @@ import { Objects } from './system';
import { ConfigurationTarget, ExtensionContext, extensions, languages, window, workspace } from 'vscode';
import { AnnotationController } from './annotations/annotationController';
import { configuration, Configuration, IConfig } from './configuration';
import { ApplicationInsightsKey, CommandContext, ExtensionKey, GlobalState, QualifiedExtensionId, setCommandContext } from './constants';
import { CommandContext, ExtensionKey, GlobalState, QualifiedExtensionId, setCommandContext } from './constants';
import { CodeLensController } from './codeLensController';
import { configureCommands } from './commands';
import { CurrentLineController } from './currentLineController';
@ -16,7 +16,7 @@ import { Keyboard } from './keyboard';
import { Logger } from './logger';
import { Messages, SuppressedMessages } from './messages';
import { ResultsExplorer } from './views/resultsExplorer';
import { Telemetry } from './telemetry';
// import { Telemetry } from './telemetry';
// this method is called when your extension is activated
export async function activate(context: ExtensionContext) {
@ -44,12 +44,12 @@ export async function activate(context: ExtensionContext) {
const gitVersion = GitService.getGitVersion();
Telemetry.configure(ApplicationInsightsKey);
// Telemetry.configure(ApplicationInsightsKey);
const telemetryContext: { [id: string]: any } = Object.create(null);
telemetryContext.version = gitlensVersion;
telemetryContext['git.version'] = gitVersion;
Telemetry.setContext(telemetryContext);
// const telemetryContext: { [id: string]: any } = Object.create(null);
// telemetryContext.version = gitlensVersion;
// telemetryContext['git.version'] = gitVersion;
// Telemetry.setContext(telemetryContext);
const previousVersion = context.globalState.get<string>(GlobalState.GitLensVersion);
@ -90,8 +90,6 @@ export async function activate(context: ExtensionContext) {
// Constantly over my data cap so stop collecting initialized event
// Telemetry.trackEvent('initialized', Objects.flatten(cfg, 'config', true));
// setCommandContext(CommandContext.ResultsExplorer, false);
// Slightly delay enabling the explorer to not stop the rest of GitLens from being usable
setTimeout(() => setCommandContext(CommandContext.GitExplorer, true), 1000);

+ 33
- 44
src/git/git.ts Voir le fichier

@ -1,10 +1,8 @@
'use strict';
import { Strings } from '../system';
import { SpawnOptions } from 'child_process';
import { findGitPath, IGit } from './gitLocator';
import { Logger } from '../logger';
import { Observable } from 'rxjs';
import { spawnPromise } from 'spawn-rx';
import { CommandOptions, runCommand } from './shell';
import * as fs from 'fs';
import * as iconv from 'iconv-lite';
import * as path from 'path';
@ -39,17 +37,7 @@ const GitWarnings = [
/ambiguous argument '.*?': unknown revision or path not in the working tree/
];
interface GitCommandOptions {
cwd: string;
env?: any;
encoding?: string;
stdin?: Observable<string> | undefined;
willHandleErrors?: boolean;
}
async function gitCommand(options: GitCommandOptions, ...args: any[]): Promise<string> {
if (options.willHandleErrors) return gitCommandCore(options, ...args);
async function gitCommand(options: CommandOptions, ...args: any[]): Promise<string> {
try {
return await gitCommandCore(options, ...args);
}
@ -61,27 +49,26 @@ async function gitCommand(options: GitCommandOptions, ...args: any[]): Promise
// A map of running git commands -- avoids running duplicate overlaping commands
const pendingCommands: Map<string, Promise<string>> = new Map();
async function gitCommandCore(options: GitCommandOptions, ...args: any[]): Promise<string> {
async function gitCommandCore(options: CommandOptions, ...args: any[]): Promise<string> {
// Fixes https://github.com/eamodio/vscode-gitlens/issues/73 & https://github.com/eamodio/vscode-gitlens/issues/161
// See https://stackoverflow.com/questions/4144417/how-to-handle-asian-characters-in-file-names-in-git-on-os-x
args.splice(0, 0, '-c', 'core.quotepath=false', '-c', 'color.ui=false');
const opts = { encoding: 'utf8', ...options };
const encoding = options.encoding || 'utf8';
const opts = {
...options,
encoding: encoding === 'utf8' ? 'utf8' : 'binary',
// Adds GCM environment variables to avoid any possible credential issues -- from https://github.com/Microsoft/vscode/issues/26573#issuecomment-338686581
// Shouldn't *really* be needed but better safe than sorry
env: { ...(options.env || process.env), GCM_INTERACTIVE: 'NEVER', GCM_PRESERVE_CREDS: 'TRUE' }
} as CommandOptions;
const command = `(${options.cwd}): git ` + args.join(' ');
const command = `(${opts.cwd}): git ${args.join(' ')}`;
let promise = pendingCommands.get(command);
if (promise === undefined) {
Logger.log(`Spawning${command}`);
promise = spawnPromise(git.path, args, {
cwd: options.cwd,
// Adds GCM environment variables to avoid any possible credential issues -- from https://github.com/Microsoft/vscode/issues/26573#issuecomment-338686581
// Shouldn't *really* be needed but better safe than sorry
env: { ...(options.env || process.env), GCM_INTERACTIVE: 'NEVER', GCM_PRESERVE_CREDS: 'TRUE' },
encoding: (opts.encoding === 'utf8') ? 'utf8' : 'binary',
stdin: opts.stdin
} as SpawnOptions);
Logger.log(`Running${command}`);
promise = runCommand(git.path, args, opts);
pendingCommands.set(command, promise);
}
@ -98,12 +85,12 @@ async function gitCommandCore(options: GitCommandOptions, ...args: any[]): Promi
Logger.log(`Completed${command}`);
}
if (opts.encoding === 'utf8' || opts.encoding === 'binary') return data;
if (encoding === 'utf8' || encoding === 'binary') return data;
return iconv.decode(Buffer.from(data, 'binary'), opts.encoding);
return iconv.decode(Buffer.from(data, 'binary'), encoding);
}
function gitCommandDefaultErrorHandler(ex: Error, options: GitCommandOptions, ...args: any[]): string {
function gitCommandDefaultErrorHandler(ex: Error, options: CommandOptions, ...args: any[]): string {
const msg = ex && ex.toString();
if (msg) {
for (const warning of GitWarnings) {
@ -253,7 +240,8 @@ export class Git {
params.push(`-L ${options.startLine},${options.endLine}`);
}
let stdin: Observable<string> | undefined;
// let stdin: Observable<string> | undefined;
let stdin: string | undefined;
if (sha) {
if (Git.isStagedUncommitted(sha)) {
// Pipe the blame contents to stdin
@ -261,7 +249,7 @@ export class Git {
params.push('-');
// Get the file contents for the staged version using `:`
stdin = Observable.from<string>(Git.show(repoPath, fileName, ':') as any);
stdin = await Git.show(repoPath, fileName, ':');
}
else {
params.push(sha);
@ -288,7 +276,7 @@ export class Git {
static async config_get(key: string, repoPath?: string) {
try {
const data = await gitCommand({ cwd: repoPath || '', willHandleErrors: true }, `config`, `--get`, key);
const data = await gitCommandCore({ cwd: repoPath || '' }, `config`, `--get`, key);
return data.trim();
}
catch {
@ -305,7 +293,8 @@ export class Git {
params.push(Git.isStagedUncommitted(sha2) ? '--staged' : sha2);
}
return gitCommand({ cwd: repoPath, encoding: options.encoding || 'utf8' }, ...params, '--', fileName);
const encoding: BufferEncoding = options.encoding === 'utf8' ? 'utf8' : 'binary';
return gitCommand({ cwd: repoPath, encoding: encoding }, ...params, '--', fileName);
}
static diff_nameStatus(repoPath: string, sha1?: string, sha2?: string, options: { filter?: string } = {}) {
@ -408,7 +397,7 @@ export class Git {
static async log_resolve(repoPath: string, fileName: string, ref: string) {
try {
const data = await gitCommand({ cwd: repoPath, willHandleErrors: true }, `log`, `--full-history`, `-M`, `-n1`, `--no-merges`, `--format=%H`, ref, `--`, fileName);
const data = await gitCommandCore({ cwd: repoPath }, `log`, `--full-history`, `-M`, `-n1`, `--no-merges`, `--format=%H`, ref, `--`, fileName);
return data.trim();
}
catch {
@ -440,7 +429,7 @@ export class Git {
}
try {
const data = await gitCommand({ cwd: repoPath, willHandleErrors: true }, ...params, fileName);
const data = await gitCommandCore({ cwd: repoPath }, ...params, fileName);
return data.trim();
}
catch {
@ -458,10 +447,10 @@ export class Git {
static async revparse(repoPath: string, ref: string): Promise<string | undefined> {
try {
const data = await gitCommand({ cwd: repoPath, willHandleErrors: true }, `rev-parse`, ref);
const data = await gitCommandCore({ cwd: repoPath }, `rev-parse`, ref);
return data.trim();
}
catch (ex) {
catch {
return undefined;
}
}
@ -469,9 +458,9 @@ export class Git {
static async revparse_currentBranch(repoPath: string): Promise<string | undefined> {
const params = [`rev-parse`, `--abbrev-ref`, `--symbolic-full-name`, `@`, `@{u}`];
const opts = { cwd: repoPath, willHandleErrors: true } as GitCommandOptions;
const opts = { cwd: repoPath } as CommandOptions;
try {
const data = await gitCommand(opts, ...params);
const data = await gitCommandCore(opts, ...params);
return data;
}
catch (ex) {
@ -482,7 +471,7 @@ export class Git {
if (/ambiguous argument '.*?': unknown revision or path not in the working tree/.test(msg)) {
try {
const params = [`symbolic-ref`, `-q`, `--short`, `HEAD`];
const data = await gitCommand(opts, ...params);
const data = await gitCommandCore(opts, ...params);
return data;
}
catch {
@ -496,7 +485,7 @@ export class Git {
static async revparse_toplevel(cwd: string): Promise<string | undefined> {
try {
const data = await gitCommand({ cwd: cwd, willHandleErrors: true }, 'rev-parse', '--show-toplevel');
const data = await gitCommandCore({ cwd: cwd }, 'rev-parse', '--show-toplevel');
return data.trim();
}
catch {
@ -512,13 +501,13 @@ export class Git {
}
if (Git.isUncommitted(ref)) throw new Error(`sha=${ref} is uncommitted`);
const opts = { cwd: root, encoding: options.encoding || 'utf8', willHandleErrors: true } as GitCommandOptions;
const opts = { cwd: root, encoding: options.encoding || 'utf8' } as CommandOptions;
const args = ref.endsWith(':')
? `${ref}./${file}`
: `${ref}:./${file}`;
try {
const data = await gitCommand(opts, 'show', args);
const data = await gitCommandCore(opts, 'show', args);
return data;
}
catch (ex) {

+ 6
- 5
src/git/gitLocator.ts Voir le fichier

@ -1,5 +1,6 @@
'use strict';
import { findActualExecutable, spawnPromise } from 'spawn-rx';
// import { findActualExecutable, spawnPromise } from 'spawn-rx';
import { findExecutable, runCommand } from './shell';
import * as path from 'path';
export interface IGit {
@ -12,10 +13,10 @@ function parseVersion(raw: string): string {
}
async function findSpecificGit(path: string): Promise<IGit> {
const version = await spawnPromise(path, ['--version']);
const version = await runCommand(path, ['--version']);
// If needed, let's update our path to avoid the search on every command
if (!path || path === 'git') {
path = findActualExecutable(path, ['--version']).cmd;
path = findExecutable(path, ['--version']).cmd;
}
return {
@ -26,7 +27,7 @@ async function findSpecificGit(path: string): Promise {
async function findGitDarwin(): Promise<IGit> {
try {
let path = await spawnPromise('which', ['git']);
let path = await runCommand('which', ['git']);
path = path.replace(/^\s+|\s+$/g, '');
if (path !== '/usr/bin/git') {
@ -34,7 +35,7 @@ async function findGitDarwin(): Promise {
}
try {
await spawnPromise('xcode-select', ['-p']);
await runCommand('xcode-select', ['-p']);
return findSpecificGit(path);
}
catch (ex) {

+ 148
- 0
src/git/shell.ts Voir le fichier

@ -0,0 +1,148 @@
'use strict';
import { execFile } from 'child_process';
import { Logger } from '../logger';
import * as fs from 'fs';
import * as path from 'path';
const isWindows = process.platform === 'win32';
/**
* Search PATH to see if a file exists in any of the path folders.
*
* @param {string} exe The file to search for
* @return {string} A fully qualified path, or the original path if nothing
* is found
*
* @private
*/
function runDownPath(exe: string): string {
// NB: Windows won't search PATH looking for executables in spawn like
// Posix does
// Files with any directory path don't get this applied
if (exe.match(/[\\\/]/)) return exe;
const target = path.join('.', exe);
try {
if (fs.statSync(target) ) return target;
}
catch { }
const haystack = process.env.PATH!.split(isWindows ? ';' : ':');
for (const p of haystack) {
const needle = path.join(p, exe);
try {
if (fs.statSync(needle)) return needle;
}
catch { }
}
return exe;
}
/**
* Finds the executable and parameters to run on Windows. This method
* mimics the POSIX behavior of being able to run scripts as executables by
* replacing the passed-in executable with the script runner, for PowerShell,
* CMD, and node scripts.
*
* This method also does the work of running down PATH, which spawn on Windows
* also doesn't do, unlike on POSIX.
*/
export function findExecutable(exe: string, args: string[]): { cmd: string; args: string[] } {
// POSIX can just execute scripts directly, no need for silly goosery
if (!isWindows) return { cmd: runDownPath(exe), args: args };
if (!fs.existsSync(exe)) {
// NB: When you write something like `surf-client ... -- surf-build` on Windows,
// a shell would normally convert that to surf-build.cmd, but since it's passed
// in as an argument, it doesn't happen
const possibleExts = ['.exe', '.bat', '.cmd', '.ps1'];
for (const ext of possibleExts) {
const possibleFullPath = runDownPath(`${exe}${ext}`);
if (fs.existsSync(possibleFullPath)) return findExecutable(possibleFullPath, args);
}
}
if (exe.match(/\.ps1$/i)) {
const cmd = path.join(process.env.SYSTEMROOT!, 'System32', 'WindowsPowerShell', 'v1.0', 'PowerShell.exe');
const psargs = ['-ExecutionPolicy', 'Unrestricted', '-NoLogo', '-NonInteractive', '-File', exe];
return { cmd: cmd, args: psargs.concat(args) };
}
if (exe.match(/\.(bat|cmd)$/i)) {
const cmd = path.join(process.env.SYSTEMROOT!, 'System32', 'cmd.exe');
const cmdArgs = ['/C', exe, ...args];
return { cmd: cmd, args: cmdArgs };
}
if (exe.match(/\.(js)$/i)) {
const cmd = process.execPath;
const nodeArgs = [exe];
return { cmd: cmd, args: nodeArgs.concat(args) };
}
return { cmd: exe, args: args };
}
export interface CommandOptions {
readonly cwd?: string;
readonly env?: Object;
readonly encoding?: BufferEncoding;
/**
* The size the output buffer to allocate to the spawned process. Set this
* if you are anticipating a large amount of output.
*
* If not specified, this will be 10MB (10485760 bytes) which should be
* enough for most Git operations.
*/
readonly maxBuffer?: number;
/**
* An optional string or buffer which will be written to
* the child process stdin stream immediately immediately
* after spawning the process.
*/
readonly stdin?: string | Buffer;
/**
* The encoding to use when writing to stdin, if the stdin
* parameter is a string.
*/
readonly stdinEncoding?: string;
}
export function runCommand(command: string, args: any[], options: CommandOptions = {}) {
const { stdin, stdinEncoding, ...opts } = { maxBuffer: 10 * 1024 * 1024, ...options } as CommandOptions;
return new Promise<string>((resolve, reject) => {
const proc = execFile(
command,
args,
opts,
(err: Error & { code?: string | number } | null, stdout, stderr) => {
if (!err) {
if (stderr) {
Logger.warn(`Warning(${command} ${args.join(' ')}): ${stderr}`);
}
resolve(stdout);
return;
}
if (err.message === 'stdout maxBuffer exceeded') {
reject(new Error(`Command output exceeded the allocated stdout buffer. Set 'options.maxBuffer' to a larger value than ${opts.maxBuffer} bytes`));
}
Logger.warn(`Error(${command} ${args.join(' ')}): (${err.code}) ${stderr}`);
reject(err);
}
);
if (stdin) {
proc.stdin.end(stdin, stdinEncoding || 'utf8');
}
});
}

+ 2
- 2
src/logger.ts Voir le fichier

@ -2,7 +2,7 @@
import { ConfigurationChangeEvent, ExtensionContext, OutputChannel, window } from 'vscode';
import { configuration } from './configuration';
import { ExtensionOutputChannelName } from './constants';
import { Telemetry } from './telemetry';
// import { Telemetry } from './telemetry';
const ConsolePrefix = `[${ExtensionOutputChannelName}]`;
@ -66,7 +66,7 @@ export class Logger {
this.output.appendLine((this.debug ? [this.timestamp, classOrMethod, ex, ...params] : [classOrMethod, ex, ...params]).join(' '));
}
Telemetry.trackException(ex);
// Telemetry.trackException(ex);
}
static warn(message?: any, ...params: any[]): void {

+ 0
- 5
src/system/object.ts Voir le fichier

@ -1,11 +1,6 @@
'use strict';
const _isEqual = require('lodash.isequal');
export namespace Objects {
export function areEquivalent(first: any, second: any): boolean {
return _isEqual(first, second);
}
export function entries<T>(o: { [key: string]: T }): IterableIterator<[string, T]>;
export function entries<T>(o: { [key: number]: T }): IterableIterator<[string, T]>;
export function* entries<T>(o: any): IterableIterator<[string, T]> {

+ 0
- 5
src/system/string.ts Voir le fichier

@ -1,12 +1,7 @@
'use strict';
const _escapeRegExp = require('lodash.escaperegexp');
import * as crypto from 'crypto';
export namespace Strings {
export function escapeRegExp(s: string): string {
return _escapeRegExp(s);
}
const TokenRegex = /\$\{([^|]*?)(?:\|(\d+)(\-|\?)?)?\}/g;
const TokenSanitizeRegex = /\$\{(\w*?)(?:\W|\d)*?\}/g;

+ 113
- 113
src/telemetry.ts Voir le fichier

@ -1,113 +1,113 @@
'use strict';
import { Disposable, env, version, workspace } from 'vscode';
import { configuration } from './configuration';
import { Logger } from './logger';
import * as os from 'os';
let _reporter: TelemetryReporter;
export class Telemetry extends Disposable {
static configure(key: string) {
if (!configuration.get<boolean>(configuration.name('advanced')('telemetry')('enabled').value) ||
!workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
return;
}
const start = process.hrtime();
_reporter = new TelemetryReporter(key);
const duration = process.hrtime(start);
Logger.log(`Telemetry.configure took ${(duration[0] * 1000) + Math.floor(duration[1] / 1000000)} ms`);
}
static setContext(context?: { [key: string]: string }) {
if (_reporter === undefined) return;
_reporter.setContext(context);
}
static trackEvent(name: string, properties?: { [key: string]: string }, measurements?: { [key: string]: number; }) {
if (_reporter === undefined) return;
_reporter.trackEvent(name, properties, measurements);
}
static trackException(ex: Error) {
if (_reporter === undefined) return;
_reporter.trackException(ex);
}
}
export class TelemetryReporter {
private appInsights: ApplicationInsights;
private _client: Client;
private _context: { [key: string]: string };
constructor(key: string) {
const diagChannelState = process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'];
(process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'] ass="kr">as any) ="o">= true;
this.appInsights = require('applicationinsights') as ApplicationInsights;
process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'] class="o">= diagChannelState;
if (this.appInsights.client) {
this._client = this.appInsights.getClient(key);
// no other way to enable offline mode
this._client.channel.setOfflineMode(true);
}
else {
this._client = this.appInsights.setup(key)
.setAutoCollectRequests(false)
.setAutoCollectPerformance(false)
.setAutoCollectExceptions(false)
.setAutoCollectDependencies(false)
.setAutoCollectConsole(false)
.setAutoDependencyCorrelation(false)
.setOfflineMode(true)
.start()
.client;
}
this.setContext();
this.stripPII(this._client);
}
setContext(context?: { [key: string]: string }) {
if (!this._context) {
this._context = Object.create(null);
// Add vscode properties
this._context['code.language'] = env.language;
this._context['code.version'] = version;
this._context[this._client.context.keys.sessionId] = env.sessionId;
// Add os properties
this._context['os.platform'] = os.platform();
this._context['os.version'] = os.release();
}
if (context) {
Object.assign(this._context, context);
}
Object.assign(this._client.commonProperties, this._context);
}
trackEvent(name: string, properties?: { [key: string]: string }, measurements?: { [key: string]: number; }) {
this._client.trackEvent(name, properties, measurements);
}
trackException(ex: Error) {
this._client.trackException(ex);
}
private stripPII(client: Client) {
if (client && client.context && client.context.keys && client.context.tags) {
const machineNameKey = client.context.keys.deviceMachineName;
client.context.tags[machineNameKey] = '';
}
}
}
// 'use strict';
// import { env, version, workspace } from 'vscode';
// import { configuration } from './configuration';
// import { Logger } from './logger';
// import * as os from 'os';
// let _reporter: TelemetryReporter | undefined;
// export class Telemetry {
// static configure(key: string) {
// if (!configuration.get<boolean>(configuration.name('advanced')('telemetry')('enabled').value) ||
// !workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
// return;
// }
// const start = process.hrtime();
// _reporter = new TelemetryReporter(key);
// const duration = process.hrtime(start);
// Logger.log(`Telemetry.configure took ${(duration[0] * 1000) + Math.floor(duration[1] / 1000000)} ms`);
// }
// static setContext(context?: { [key: string]: string }) {
// if (_reporter === undefined) return;
// _reporter.setContext(context);
// }
// static trackEvent(name: string, properties?: { [key: string]: string }, measurements?: { [key: string]: number; }) {
// if (_reporter === undefined) return;
// _reporter.trackEvent(name, properties, measurements);
// }
// static trackException(ex: Error) {
// if (_reporter === undefined) return;
// _reporter.trackException(ex);
// }
// }
// export class TelemetryReporter {
// private appInsights: ApplicationInsights;
// private _client: Client;
// private _context: { [key: string]: string };
// constructor(key: string) {
// const diagChannelState = process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'];
// (process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'] as any) = true;
// this.appInsights = require('applicationinsights') as ApplicationInsights;
// process.env['APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL'] = diagChannelState;
// if (this.appInsights.client) {
// this._client = this.appInsights.getClient(key);
// // no other way to enable offline mode
// this._client.channel.setOfflineMode(true);
// }
// else {
// this._client = this.appInsights.setup(key)
// .setAutoCollectRequests(false)
// .setAutoCollectPerformance(false)
// .setAutoCollectExceptions(false)
// .setAutoCollectDependencies(false)
// .setAutoCollectConsole(false)
// .setAutoDependencyCorrelation(false)
// .setOfflineMode(true)
// .start()
// .client;
// }
// this.setContext();
// this.stripPII(this._client);
// }
// setContext(context?: { [key: string]: string }) {
// if (!this._context) {
// this._context = Object.create(null);
// // Add vscode properties
// this._context['code.language'] = env.language;
// this._context['code.version'] = version;
// this._context[this._client.context.keys.sessionId] = env.sessionId;
// // Add os properties
// this._context['os.platform'] = os.platform();
// this._context['os.version'] = os.release();
// }
// if (context) {
// Object.assign(this._context, context);
// }
// Object.assign(this._client.commonProperties, this._context);
// }
// trackEvent(name: string, properties?: { [key: string]: string }, measurements?: { [key: string]: number; }) {
// this._client.trackEvent(name, properties, measurements);
// }
// trackException(ex: Error) {
// this._client.trackException(ex);
// }
// private stripPII(client: Client) {
// if (client && client.context && client.context.keys && client.context.tags) {
// const machineNameKey = client.context.keys.deviceMachineName;
// client.context.tags[machineNameKey] = '';
// }
// }
// }

Chargement…
Annuler
Enregistrer