提交 34b7e140 编写于 作者: J Joao Moreno

make git service debuggable

上级 d216493e
......@@ -7,6 +7,7 @@
import {IDisposable} from 'vs/base/common/lifecycle';
import CallbackList from 'vs/base/common/callbackList';
import {EventEmitter} from 'vs/base/common/eventEmitter';
import {TPromise} from 'vs/base/common/winjs.base';
/**
* To an event a function with one or zero parameters
......@@ -151,6 +152,33 @@ export function fromEventEmitter<T>(emitter: EventEmitter, eventType: string): E
};
}
export function fromPromise<T>(promise: TPromise<Event<T>>): Event<T> {
let toCancel: TPromise<any> = null;
let listener: IDisposable = null;
const emitter = new Emitter<T>({
onFirstListenerAdd() {
toCancel = promise.then(
event => listener = event(e => emitter.fire(e)),
() => null
);
},
onLastListenerRemove() {
if (toCancel) {
toCancel.cancel();
toCancel = null;
}
if (listener) {
listener.dispose();
listener = null;
}
}
});
return emitter.event;
}
export function mapEvent<I,O>(event: Event<I>, map: (i:I)=>O): Event<O> {
return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables);
}
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { TPromise } from 'vs/base/common/winjs.base';
import { IRawGitService, RawServiceState } from 'vs/workbench/parts/git/common/git';
import { IRawGitService, RawServiceState, IGitConfiguration } from 'vs/workbench/parts/git/common/git';
import { NoOpGitService } from 'vs/workbench/parts/git/common/noopGitService';
import { GitService } from 'vs/workbench/parts/git/browser/gitServices';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
......@@ -18,7 +18,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
import { getDelayedChannel, getNextTickChannel } from 'vs/base/parts/ipc/common/ipc';
import { Client } from 'vs/base/parts/ipc/node/ipc.cp';
import { GitChannelClient, UnavailableGitChannel } from 'vs/workbench/parts/git/common/gitIpc';
import { RawGitService } from 'vs/workbench/parts/git/node/rawGitService';
import { RawGitService, DelayedRawGitService } from 'vs/workbench/parts/git/node/rawGitService';
import URI from 'vs/base/common/uri';
import { spawn, exec } from 'child_process';
import { join } from 'path';
......@@ -146,7 +146,53 @@ class DisabledRawGitService extends RawGitService {
}
}
function createRemoteRawGitService(gitPath: string, workspaceRoot: string, encoding: string, verbose: boolean): IRawGitService {
const promise = TPromise.timeout(0) // free event loop cos finding git costs
.then(() => findGit(gitPath))
.then(({ path, version }) => {
const client = new Client(
URI.parse(require.toUrl('bootstrap')).fsPath,
{
serverName: 'Git',
timeout: 1000 * 60,
args: [path, workspaceRoot, encoding, remote.process.execPath, version],
env: {
ELECTRON_RUN_AS_NODE: 1,
PIPE_LOGGING: 'true',
AMD_ENTRYPOINT: 'vs/workbench/parts/git/node/gitApp',
VERBOSE_LOGGING: String(verbose)
}
}
);
return client.getChannel('git');
})
.then(null, () => new UnavailableGitChannel());
const channel = getNextTickChannel(getDelayedChannel(promise));
return new GitChannelClient(channel);
}
interface IRawGitServiceBootstrap {
createRawGitService(gitPath: string, workspaceRoot: string, defaultEncoding: string, exePath: string, version: string): TPromise<IRawGitService>;
}
function createRawGitService(gitPath: string, workspaceRoot: string, encoding: string, verbose: boolean): IRawGitService {
const promise = new TPromise<IRawGitService>((c, e) => {
require(['vs/workbench/parts/git/node/rawGitServiceBootstrap'], ({ createRawGitService }: IRawGitServiceBootstrap) => {
findGit(gitPath)
.then(({ path, version }) => createRawGitService(path, workspaceRoot, encoding, remote.process.execPath, version))
.done(c, e);
}, e);
});
return new DelayedRawGitService(promise);
}
export class ElectronGitService extends GitService {
private static USE_REMOTE_PROCESS_SERVICE = true;
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@IEventService eventService: IEventService,
......@@ -158,45 +204,27 @@ export class ElectronGitService extends GitService {
@IStorageService storageService: IStorageService,
@IConfigurationService configurationService: IConfigurationService
) {
const conf = configurationService.getConfiguration<any>();
const enabled = conf.git ? conf.git.enabled : true;
const conf = configurationService.getConfiguration<IGitConfiguration>('git');
const filesConf = configurationService.getConfiguration<any>('files');
const workspace = contextService.getWorkspace();
let raw: IRawGitService;
if (!enabled) {
if (!conf.enabled) {
raw = new DisabledRawGitService();
} else if (!workspace) {
raw = new NoOpGitService();
} else {
const gitPath = (conf.git && conf.git.path) || null;
const encoding = (conf.files && conf.files.encoding) || 'utf8';
const gitPath = conf.path || null;
const encoding = filesConf.encoding || 'utf8';
const workspaceRoot = workspace.resource.fsPath;
const verbose = !contextService.getConfiguration().env.isBuilt || contextService.getConfiguration().env.verboseLogging;
const promise = TPromise.timeout(0) // free event loop cos finding git costs
.then(() => findGit(gitPath))
.then(({ path, version }) => {
const client = new Client(
URI.parse(require.toUrl('bootstrap')).fsPath,
{
serverName: 'Git',
timeout: 1000 * 60,
args: [path, workspaceRoot, encoding, remote.process.execPath, version],
env: {
ELECTRON_RUN_AS_NODE: 1,
PIPE_LOGGING: 'true',
AMD_ENTRYPOINT: 'vs/workbench/parts/git/node/gitApp',
VERBOSE_LOGGING: String(!contextService.getConfiguration().env.isBuilt || contextService.getConfiguration().env.verboseLogging)
}
}
);
return client.getChannel('git');
})
.then(null, () => new UnavailableGitChannel());
const channel = getNextTickChannel(getDelayedChannel(promise));
raw = new GitChannelClient(channel);
if (ElectronGitService.USE_REMOTE_PROCESS_SERVICE) {
raw = createRemoteRawGitService(gitPath, workspaceRoot, encoding, verbose);
} else {
raw = createRawGitService(gitPath, workspaceRoot, encoding, verbose);
}
}
super(raw, instantiationService, eventService, messageService, editorService, outputService, contextService, lifecycleService, storageService, configurationService);
......
......@@ -2,58 +2,13 @@
* 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 { TPromise } from 'vs/base/common/winjs.base';
import { Server } from 'vs/base/parts/ipc/node/ipc.cp';
import objects = require('vs/base/common/objects');
import uri from 'vs/base/common/uri';
import { GitErrorCodes, IRawGitService } from 'vs/workbench/parts/git/common/git';
import gitlib = require('vs/workbench/parts/git/node/git.lib');
import { RawGitService } from 'vs/workbench/parts/git/node/rawGitService';
import { join, normalize } from 'path';
import { tmpdir } from 'os';
import { realpath } from 'vs/base/node/pfs';
import { createRawGitService } from './rawGitServiceBootstrap';
import { GitChannel } from 'vs/workbench/parts/git/common/gitIpc';
function createRawGitService(gitPath: string, workspaceRoot: string, defaultEncoding: string, exePath: string, version: string): TPromise<IRawGitService> {
if (!gitPath) {
return TPromise.as(new RawGitService(null));
}
const gitRootPath = uri.parse(require.toUrl('vs/workbench/parts/git/node')).fsPath;
const bootstrapPath = `${ uri.parse(require.toUrl('bootstrap')).fsPath }.js`;
workspaceRoot = normalize(workspaceRoot);
const env = objects.assign({}, process.env, {
GIT_ASKPASS: join(gitRootPath, 'askpass.sh'),
VSCODE_GIT_ASKPASS_BOOTSTRAP: bootstrapPath,
VSCODE_GIT_ASKPASS_NODE: exePath,
VSCODE_GIT_ASKPASS_MODULE_ID: 'vs/workbench/parts/git/node/askpass'
});
const git = new gitlib.Git({
gitPath, version,
tmpPath: tmpdir(),
defaultEncoding: defaultEncoding,
env: env
});
const repo = git.open(workspaceRoot);
return repo.getRoot()
.then<string>(null, (err: gitlib.GitError) => {
if (err instanceof gitlib.GitError && err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
return workspaceRoot;
}
return TPromise.wrapError(err);
})
.then(root => realpath(root))
.then(root => git.open(root))
.then(repo => new RawGitService(repo));
}
const server = new Server();
const service = createRawGitService(process.argv[2], process.argv[3], process.argv[4], process.argv[5], process.argv[6]);
const channel = new GitChannel(service);
......
......@@ -10,7 +10,7 @@ import { detectMimesFromFile, detectMimesFromStream } from 'vs/base/node/mime';
import { realpath, exists} from 'vs/base/node/pfs';
import { Repository, GitError } from 'vs/workbench/parts/git/node/git.lib';
import { IRawGitService, RawServiceState, IRawStatus, IRef, GitErrorCodes, IPushOptions } from 'vs/workbench/parts/git/common/git';
import Event, { Emitter } from 'vs/base/common/event';
import Event, { Emitter, fromPromise } from 'vs/base/common/event';
export class RawGitService implements IRawGitService {
......@@ -192,3 +192,28 @@ export class RawGitService implements IRawGitService {
});
}
}
export class DelayedRawGitService implements IRawGitService {
constructor(private raw: TPromise<IRawGitService>){}
onOutput: Event<string> = fromPromise(this.raw.then(r => r.onOutput));
getVersion(): TPromise<string> { return this.raw.then(r => r.getVersion()); }
serviceState(): TPromise<RawServiceState> { return this.raw.then(r => r.serviceState()); }
statusCount(): TPromise<number> { return this.raw.then(r => r.statusCount()); }
status(): TPromise<IRawStatus> { return this.raw.then(r => r.status()); }
init(): TPromise<IRawStatus> { return this.raw.then(r => r.init()); }
add(filesPaths?: string[]): TPromise<IRawStatus> { return this.raw.then(r => r.add(filesPaths)); }
stage(filePath: string, content: string): TPromise<IRawStatus> { return this.raw.then(r => r.stage(filePath, content)); }
branch(name: string, checkout?: boolean): TPromise<IRawStatus> { return this.raw.then(r => r.branch(name, checkout)); }
checkout(treeish?: string, filePaths?: string[]): TPromise<IRawStatus> { return this.raw.then(r => r.checkout(treeish, filePaths)); }
clean(filePaths: string[]): TPromise<IRawStatus> { return this.raw.then(r => r.clean(filePaths)); }
undo(): TPromise<IRawStatus> { return this.raw.then(r => r.undo()); }
reset(treeish:string, hard?: boolean): TPromise<IRawStatus> { return this.raw.then(r => r.reset(treeish, hard)); }
revertFiles(treeish:string, filePaths?: string[]): TPromise<IRawStatus> { return this.raw.then(r => r.revertFiles(treeish, filePaths)); }
fetch(): TPromise<IRawStatus> { return this.raw.then(r => r.fetch()); }
pull(rebase?: boolean): TPromise<IRawStatus> { return this.raw.then(r => r.pull(rebase)); }
push(remote?: string, name?: string, options?:IPushOptions): TPromise<IRawStatus> { return this.raw.then(r => r.push(remote, name, options)); }
sync(): TPromise<IRawStatus> { return this.raw.then(r => r.sync()); }
commit(message:string, amend?: boolean, stage?: boolean): TPromise<IRawStatus> { return this.raw.then(r => r.commit(message, amend, stage)); }
detectMimetypes(path: string, treeish?: string): TPromise<string[]> { return this.raw.then(r => r.detectMimetypes(path, treeish)); }
show(path: string, treeish?: string): TPromise<string> { return this.raw.then(r => r.show(path, treeish)); }
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* 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 { TPromise } from 'vs/base/common/winjs.base';
import objects = require('vs/base/common/objects');
import uri from 'vs/base/common/uri';
import { GitErrorCodes, IRawGitService } from 'vs/workbench/parts/git/common/git';
import gitlib = require('vs/workbench/parts/git/node/git.lib');
import { RawGitService } from 'vs/workbench/parts/git/node/rawGitService';
import { join, normalize } from 'path';
import { tmpdir } from 'os';
import { realpath } from 'vs/base/node/pfs';
export function createRawGitService(gitPath: string, workspaceRoot: string, defaultEncoding: string, exePath: string, version: string): TPromise<IRawGitService> {
if (!gitPath) {
return TPromise.as(new RawGitService(null));
}
const gitRootPath = uri.parse(require.toUrl('vs/workbench/parts/git/node')).fsPath;
const bootstrapPath = `${ uri.parse(require.toUrl('bootstrap')).fsPath }.js`;
workspaceRoot = normalize(workspaceRoot);
const env = objects.assign({}, process.env, {
GIT_ASKPASS: join(gitRootPath, 'askpass.sh'),
VSCODE_GIT_ASKPASS_BOOTSTRAP: bootstrapPath,
VSCODE_GIT_ASKPASS_NODE: exePath,
VSCODE_GIT_ASKPASS_MODULE_ID: 'vs/workbench/parts/git/node/askpass'
});
const git = new gitlib.Git({
gitPath, version,
tmpPath: tmpdir(),
defaultEncoding: defaultEncoding,
env: env
});
const repo = git.open(workspaceRoot);
return repo.getRoot()
.then<string>(null, (err: gitlib.GitError) => {
if (err instanceof gitlib.GitError && err.gitErrorCode === GitErrorCodes.NotAGitRepository) {
return workspaceRoot;
}
return TPromise.wrapError(err);
})
.then(root => realpath(root))
.then(root => git.open(root))
.then(repo => new RawGitService(repo));
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册