From b72180fdcd22c824da3c1d869b0f869dea2df61d Mon Sep 17 00:00:00 2001 From: ole1986 Date: Tue, 26 Nov 2019 15:34:24 +0100 Subject: [PATCH] Replaced several git commands with git extension API --- src/adapter/parsers/refs/parser.ts | 2 - src/adapter/repository/factory.ts | 34 +++- src/adapter/repository/git.ts | 166 +++++------------- src/adapter/repository/gitArgsService.ts | 6 - src/adapter/repository/types.ts | 2 - src/application/types/workspace.ts | 10 -- src/application/workspace.ts | 3 - src/commandHandlers/commit/compare.ts | 2 +- .../commit/gitBranchFromCommit.ts | 2 +- src/commandHandlers/commit/gitCheckout.ts | 2 +- src/commandHandlers/commit/gitCherryPick.ts | 2 +- src/commandHandlers/commit/gitMerge.ts | 2 +- src/commandHandlers/commit/gitRebase.ts | 2 +- src/commandHandlers/commit/revert.ts | 2 +- src/commandHandlers/fileCommit/fileCompare.ts | 2 +- src/commandHandlers/fileCommit/fileHistory.ts | 10 +- src/commandHandlers/gitHistory.ts | 26 +-- src/common/types.ts | 3 +- src/common/uiService.ts | 76 +------- src/server/apiController.ts | 4 +- src/server/serverHost.ts | 2 +- src/server/types.ts | 2 +- src/types.ts | 16 +- src/viewers/file/commitFileViewer.ts | 2 +- 24 files changed, 106 insertions(+), 274 deletions(-) diff --git a/src/adapter/parsers/refs/parser.ts b/src/adapter/parsers/refs/parser.ts index bb4f8f75..b1dc0191 100644 --- a/src/adapter/parsers/refs/parser.ts +++ b/src/adapter/parsers/refs/parser.ts @@ -2,8 +2,6 @@ export * from './types'; import { injectable, multiInject } from 'inversify'; import { ILogService } from '../../../common/types'; import { Ref } from '../../../types'; -// import { TYPES } from '../constants'; -// import * as TYPES from '../types'; import { IRefsParser } from '../types'; import { IRefParser } from './types'; diff --git a/src/adapter/repository/factory.ts b/src/adapter/repository/factory.ts index 36f7de98..095f9db4 100644 --- a/src/adapter/repository/factory.ts +++ b/src/adapter/repository/factory.ts @@ -1,29 +1,49 @@ import { inject, injectable } from 'inversify'; -import * as md5 from 'md5'; import { Uri } from 'vscode'; import { IServiceContainer } from '../../ioc/types'; import { IGitService, IGitServiceFactory } from '../../types'; import { IGitCommandExecutor } from '../exec'; import { ILogParser } from '../parsers/types'; import { Git } from './git'; +import { API } from './git.d'; import { IGitArgsService } from './types'; @injectable() export class GitServiceFactory implements IGitServiceFactory { - private readonly gitServices = new Map(); + private readonly gitServices = new Map(); + private gitApi: API; constructor(@inject(IGitCommandExecutor) private gitCmdExecutor: IGitCommandExecutor, @inject(ILogParser) private logParser: ILogParser, @inject(IGitArgsService) private gitArgsService: IGitArgsService, @inject(IServiceContainer) private serviceContainer: IServiceContainer) { + this.gitApi = this.gitCmdExecutor.gitExtension.getAPI(1); } - public async createGitService(workspaceRoot: string, resource: Uri | string): Promise { + + public async createGitService(resource?: Uri | string): Promise { const resourceUri = typeof resource === 'string' ? Uri.file(resource) : resource; + let repoIndex: number = -1; + + if (!resourceUri) { + // no git service initialized, so take the selected as primary + repoIndex = this.gitApi.repositories.findIndex(x => x.ui.selected); + } - const id = md5(workspaceRoot + resourceUri.fsPath); - if (!this.gitServices.has(id)) { - this.gitServices.set(id, new Git(this.serviceContainer, workspaceRoot, resourceUri, this.gitCmdExecutor, this.logParser, this.gitArgsService)); + if (repoIndex === -1) { + // find the correct repository from the given resource uri + this.gitApi.repositories.forEach((x, i) => { + if (resourceUri!.fsPath.startsWith(x.rootUri.fsPath)) { + if (repoIndex === -1 || x.rootUri.fsPath.length > this.gitApi.repositories[repoIndex].rootUri.fsPath.length) { + repoIndex = i; + } + } + }); } - return this.gitServices.get(id)!; + + if (!this.gitServices.has(repoIndex)) { + this.gitServices.set(repoIndex, new Git(this.gitApi.repositories[repoIndex], this.serviceContainer, this.gitCmdExecutor, this.logParser, this.gitArgsService)); + } + + return this.gitServices.get(repoIndex)!; } } diff --git a/src/adapter/repository/git.ts b/src/adapter/repository/git.ts index bc7c6fbe..36bad926 100644 --- a/src/adapter/repository/git.ts +++ b/src/adapter/repository/git.ts @@ -11,66 +11,28 @@ import { ActionedUser, Branch, CommittedFile, FsUri, Hash, IGitService, LogEntri import { IGitCommandExecutor } from '../exec'; import { IFileStatParser, ILogParser } from '../parsers/types'; import { ITEM_ENTRY_SEPARATOR, LOG_ENTRY_SEPARATOR, LOG_FORMAT_ARGS } from './constants'; +import { API, Repository } from './git.d'; import { GitOriginType } from './index'; import { IGitArgsService } from './types'; @injectable() export class Git implements IGitService { - private gitRootPath: string | undefined; - private knownGitRoots: Set; - constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer, - private workspaceRoot: string, - private resource: Uri, + private gitApi: API; + constructor(private repo: Repository, @inject(IServiceContainer) private serviceContainer: IServiceContainer, @inject(IGitCommandExecutor) private gitCmdExecutor: IGitCommandExecutor, @inject(ILogParser) private logParser: ILogParser, @inject(IGitArgsService) private gitArgsService: IGitArgsService) { - this.knownGitRoots = new Set(); - } - public getHashCode() { - return this.workspaceRoot; + + this.gitApi = this.gitCmdExecutor.gitExtension.getAPI(1); } - @cache('IGitService') public async getGitRoot(): Promise { - if (this.gitRootPath) { - return this.gitRootPath; - } - const gitRootPath = await this.gitCmdExecutor.exec(this.resource.fsPath, ...this.gitArgsService.getGitRootArgs()); - return this.gitRootPath = gitRootPath.split(/\r?\n/g)[0].trim(); + return this.repo.rootUri.fsPath; } - @cache('IGitService', 5 * 60 * 1000) - public async getGitRoots(rootDirectory?: string): Promise { - // Lets not enable support for sub modules for now. - if (rootDirectory && (this.knownGitRoots.has(rootDirectory) || this.knownGitRoots.has(Uri.file(rootDirectory).fsPath))) { - return [rootDirectory]; - } - const rootDirectories: string[] = []; - if (rootDirectory) { - rootDirectories.push(rootDirectory); - } else { - const workspace = this.serviceContainer.get(IWorkspaceService); - const workspaceFolders = Array.isArray(workspace.workspaceFolders) ? workspace.workspaceFolders.map(item => item.uri.fsPath) : []; - rootDirectories.push(...workspaceFolders); - } - if (rootDirectories.length === 0) { - return []; - } + public async getGitRoots(): Promise { // Instead of traversing the directory structure for the entire workspace, use the Git extension API to get all repo paths - const git = this.gitCmdExecutor.gitExtension.getAPI(1); - - const sourceControlFolders: string[] = git.repositories.map(repo => repo.rootUri.path); - sourceControlFolders.sort(); - // gitFoldersList should be an Array of Arrays - const gitFoldersList = [sourceControlFolders]; - const gitRoots = new Set(); - gitFoldersList - .reduce((aggregate, items) => { aggregate.push(...items); return aggregate; }, []) - .forEach(item => { - gitRoots.add(item); - this.knownGitRoots.add(item); - }); - return Array.from(gitRoots.values()); + return this.gitApi.repositories.map(x => path.basename(x.rootUri.path)); } public async getGitRelativePath(file: Uri | FsUri) { if (!path.isAbsolute(file.fsPath)) { @@ -79,16 +41,25 @@ export class Git implements IGitService { const gitRoot: string = await this.getGitRoot(); return path.relative(gitRoot, file.fsPath).replace(/\\/g, '/'); } - @cache('IGitService', 10 * 1000) - public async getHeadHashes(): Promise<{ ref: string; hash: string }[]> { - const fullHashArgs = ['show-ref']; - const fullHashRefsOutput = await this.exec(...fullHashArgs); - return fullHashRefsOutput.split(/\r?\n/g) - .filter(line => line.length > 0) - .filter(line => line.indexOf('refs/heads/') > 0 || line.indexOf('refs/remotes/') > 0) - .map(line => line.trim().split(' ')) - .filter(lineParts => lineParts.length > 1) - .map(hashAndRef => { return { ref: hashAndRef[1], hash: hashAndRef[0] }; }); + public async getHeadHashes(): Promise<{ ref?: string; hash?: string }[]> { + return this.repo.state.refs.filter(x => x.type <= 1).map(x => { return { ref: x.name, hash: x.commit }; }); + } + public async getBranches(): Promise { + const currentBranchName = await this.getCurrentBranch(); + const gitRootPath = this.repo.rootUri.fsPath; + const localBranches = this.repo.state.refs.filter(x => x.type === 0); + + return localBranches.map(x => { + // tslint:disable-next-line:no-object-literal-type-assertion + return { + gitRoot: gitRootPath, + name: x.name, + current: currentBranchName === x.name + } as Branch; + }); + } + public async getCurrentBranch(): Promise { + return this.repo.state.HEAD!.name || ''; } @cache('IGitService', 60 * 1000) @@ -126,42 +97,6 @@ export class Git implements IGitService { }) .sort((a, b) => a.name > b.name ? 1 : -1); } - - // tslint:disable-next-line:no-suspicious-comment - // TODO: We need a way of clearing this cache, if a new branch is created. - @cache('IGitService', 30 * 1000) - public async getBranches(): Promise { - const output = await this.exec('branch'); - const gitRootPath = await this.getGitRoot(); - return output.split(/\r?\n/g) - .filter(line => line.trim()) - .filter(line => line.length > 0) - .map(line => { - const isCurrent = line.startsWith('*'); - const name = isCurrent ? line.substring(1).trim() : line.trim(); - return { - gitRoot: gitRootPath, - name, - current: isCurrent - }; - }); - } - // tslint:disable-next-line:no-suspicious-comment - // TODO: We need a way of clearing this cache, if a new branch is created. - @cache('IGitService', 30 * 1000) - public async getCurrentBranch(): Promise { - const args = this.gitArgsService.getCurrentBranchArgs(); - const branch = await this.exec(...args); - return branch.split(/\r?\n/g)[0].trim(); - } - @cache('IGitService') - public async getObjectHash(object: string): Promise { - // Get the hash of the given ref - // E.g. git show --format=%H --shortstat remotes/origin/tyriar/xterm-v3 - const args = this.gitArgsService.getObjectHashArgs(object); - const output = await this.exec(...args); - return output.split(/\r?\n/g)[0].trim(); - } @cache('IGitService') public async getOriginType(): Promise { const url = await this.getOriginUrl(); @@ -173,33 +108,23 @@ export class Git implements IGitService { } else if (url.indexOf('visualstudio') > 0) { return GitOriginType.vsts; } - return undefined; } @cache('IGitService') public async getOriginUrl(): Promise { - try { - const remoteName = await this.exec('status', '--porcelain=v1', '-b', '--untracked-files=no').then((branchDetails) => { - const matchResult = branchDetails.match(/.*\.\.\.(.*?)\//); - return matchResult && matchResult[1] ? matchResult[1] : 'origin'; - }); + const currentBranchName = await this.getCurrentBranch(); + const branch = await this.repo.getBranch(currentBranchName); - const url = await this.exec('remote', 'get-url', remoteName); - return url.substring(0, url.length - 1); - } catch { - return ""; + if (branch.upstream) { + const remoteIndex = this.repo.state.remotes.findIndex(x => x.name === branch.upstream!.remote); + return this.repo.state.remotes[remoteIndex].fetchUrl || ''; } + + return ''; } public async getRefsContainingCommit(hash: string): Promise { - const args = this.gitArgsService.getRefsContainingCommitArgs(hash); - const entries = await this.exec(...args); - return entries.split(/\r?\n/g) - .map(line => line.trim()) - .filter(line => line.length > 0) - // Remove the '*' prefix from current branch - .map(line => line.startsWith('*') ? line.substring(1) : line) - // Remove the '->' from ref pointers (take first portion) - .map(ref => ref.indexOf(' ') ? ref.split(' ')[0].trim() : ref); + // tslint:disable-next-line:possible-timing-attack + return this.repo.state.refs.filter(x => x.commit === hash).map(x => x.name || ''); } public async getLogEntries(pageIndex: number = 0, pageSize: number = 0, branch: string = '', searchText: string = '', file?: Uri, lineNumber?: number, author?: string): Promise { if (pageSize <= 0) { @@ -208,7 +133,7 @@ export class Git implements IGitService { pageSize = workspace.getConfiguration('gitHistory').get('pageSize', 100); } const relativePath = file ? await this.getGitRelativePath(file) : undefined; - const args = await this.gitArgsService.getLogArgs(pageIndex, pageSize, branch, searchText, relativePath, lineNumber, author); + const args = this.gitArgsService.getLogArgs(pageIndex, pageSize, branch, searchText, relativePath, lineNumber, author); const gitRootPathPromise = this.getGitRoot(); const outputPromise = this.exec(...args.logArgs); @@ -243,7 +168,7 @@ export class Git implements IGitService { const headHashes = await this.getHeadHashes(); const headHashesOnly = headHashes.map(item => item.hash); // tslint:disable-next-line:prefer-type-cast - const headHashMap = new Map(headHashes.map(item => [item.ref, item.hash] as [string, string])); + //const headHashMap = new Map(headHashes.map(item => [item.ref, item.hash] as [string, string])); items.forEach(async item => { item.gitRoot = gitRepoPath; @@ -256,14 +181,14 @@ export class Git implements IGitService { if (!item.isLastCommit) { return; } - const refsContainingThisCommit = await this.getRefsContainingCommit(item.hash.full); + /*const refsContainingThisCommit = await this.getRefsContainingCommit(item.hash.full); const hashesOfRefs = refsContainingThisCommit .filter(ref => headHashMap.has(ref)) .map(ref => headHashMap.get(ref)!) // tslint:disable-next-line:possible-timing-attack .filter(hash => hash !== item.hash.full); // If we have hashes other than current, then yes it has been merged - item.isThisLastCommitMerged = hashesOfRefs.length > 0; + item.isThisLastCommitMerged = hashesOfRefs.length > 0;*/ }); // tslint:disable-next-line:no-suspicious-comment @@ -280,15 +205,6 @@ export class Git implements IGitService { } as LogEntries; } @cache('IGitService') - public async getHash(hash: string): Promise { - const hashes = await this.exec('show', '--format=%H-%h', '--no-patch', hash); - const parts = hashes.split(/\r?\n/g).filter(item => item.length > 0)[0].split('-'); - return { - full: parts[0], - short: parts[1] - }; - } - @cache('IGitService') public async getCommitDate(hash: string): Promise { const args = this.gitArgsService.getCommitDateArgs(hash); const output = await this.exec(...args); @@ -359,7 +275,9 @@ export class Git implements IGitService { fsStream.end(); resolve(Uri.file(tmpFile)); } catch (ex) { + // tslint:disable-next-line:no-console console.error('Git History: failed to get file contents (again)'); + // tslint:disable-next-line:no-console console.error(ex); reject(ex); } diff --git a/src/adapter/repository/gitArgsService.ts b/src/adapter/repository/gitArgsService.ts index e8f7145d..4666cad3 100644 --- a/src/adapter/repository/gitArgsService.ts +++ b/src/adapter/repository/gitArgsService.ts @@ -8,12 +8,6 @@ import { GitLogArgs, IGitArgsService } from './types'; export class GitArgsService implements IGitArgsService { constructor(private isWindows: boolean = /^win/.test(process.platform)) {} - public getGitRootArgs(): string[] { - return ['rev-parse', '--show-toplevel']; - } - public getCurrentBranchArgs(): string[] { - return ['rev-parse', '--abbrev-ref', 'HEAD']; - } public getCommitDateArgs(hash: string) { return ['show', `--format=${Helpers.GetCommitInfoFormatCode(CommitInfo.CommitterDateUnixTime)}`, hash]; } diff --git a/src/adapter/repository/types.ts b/src/adapter/repository/types.ts index 78ca078c..1a6bd2af 100644 --- a/src/adapter/repository/types.ts +++ b/src/adapter/repository/types.ts @@ -8,9 +8,7 @@ export type GitLogArgs = { export const IGitArgsService = Symbol('IGitArgsService'); export interface IGitArgsService { - getGitRootArgs(): string[]; getAuthorsArgs(): string[]; - getCurrentBranchArgs(): string[]; getCommitDateArgs(hash: string): string[]; getCommitArgs(hash: string): string[]; getCommitParentHashesArgs(hash: string): string[]; diff --git a/src/application/types/workspace.ts b/src/application/types/workspace.ts index 2b5cd1f8..0fa2f589 100644 --- a/src/application/types/workspace.ts +++ b/src/application/types/workspace.ts @@ -23,16 +23,6 @@ export interface IWorkspaceService { */ readonly onDidChangeConfiguration: Event; - /** - * Returns the [workspace folder](#WorkspaceFolder) that contains a given uri. - * * returns `undefined` when the given uri doesn't match any workspace folder - * * returns the *input* when the given uri is a workspace folder itself - * - * @param uri An uri. - * @return A workspace folder or `undefined` - */ - getWorkspaceFolder(uri: Uri): WorkspaceFolder | undefined; - /** * Returns a path that is relative to the workspace folder or folders. * diff --git a/src/application/workspace.ts b/src/application/workspace.ts index a078b69a..4c53dd47 100644 --- a/src/application/workspace.ts +++ b/src/application/workspace.ts @@ -19,9 +19,6 @@ export class WorkspaceService implements IWorkspaceService { public getConfiguration(section?: string, resource?: Uri): WorkspaceConfiguration { return workspace.getConfiguration(section, resource); } - public getWorkspaceFolder(uri: Uri): WorkspaceFolder | undefined { - return workspace.getWorkspaceFolder(uri); - } public asRelativePath(pathOrUri: string | Uri, includeWorkspaceFolder?: boolean): string { return workspace.asRelativePath(pathOrUri, includeWorkspaceFolder); } diff --git a/src/commandHandlers/commit/compare.ts b/src/commandHandlers/commit/compare.ts index 787a8cd7..fd6729b2 100644 --- a/src/commandHandlers/commit/compare.ts +++ b/src/commandHandlers/commit/compare.ts @@ -36,7 +36,7 @@ export class GitCompareCommitCommandHandler implements IGitCompareCommandHandler await this.commandManager.executeCommand('setContext', 'git.commit.compare.view.show', true); // display explorer view when running compare await this.commandManager.executeCommand('workbench.view.explorer'); - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.workspaceFolder, commit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.logEntry.gitRoot); const fileDiffs = await gitService.getDifferences(this.selectedCommit!.logEntry.hash.full, commit.logEntry.hash.full); const compareCommit = new CompareCommitDetails(this.selectedCommit, commit, fileDiffs); this.commitViewerFactory.getCompareCommitViewer().showCommitTree(compareCommit); diff --git a/src/commandHandlers/commit/gitBranchFromCommit.ts b/src/commandHandlers/commit/gitBranchFromCommit.ts index e7fa2b46..caabcd62 100644 --- a/src/commandHandlers/commit/gitBranchFromCommit.ts +++ b/src/commandHandlers/commit/gitBranchFromCommit.ts @@ -24,7 +24,7 @@ export class GitBranchFromCommitCommandHandler implements IGitBranchFromCommitCo return; } - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.workspaceFolder, commit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.logEntry.gitRoot); gitService.createBranch(newBranchName, commit.logEntry.hash.full) .catch(async err => { const currentBranchName = await gitService.getCurrentBranch(); diff --git a/src/commandHandlers/commit/gitCheckout.ts b/src/commandHandlers/commit/gitCheckout.ts index 46c711f5..ad7c4841 100644 --- a/src/commandHandlers/commit/gitCheckout.ts +++ b/src/commandHandlers/commit/gitCheckout.ts @@ -16,7 +16,7 @@ export class GitCheckoutCommandHandler implements IGitCheckoutCommandHandler { @command('git.commit.checkout', IGitCheckoutCommandHandler) public async checkoutCommit(commit: CommitDetails) { commit = commit ? commit : this.commitViewerFactory.getCommitViewer().selectedCommit; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.workspaceFolder, commit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.logEntry.gitRoot); gitService.checkout(commit.logEntry.hash.full) .catch(err => { diff --git a/src/commandHandlers/commit/gitCherryPick.ts b/src/commandHandlers/commit/gitCherryPick.ts index f6126f77..2b0e235c 100644 --- a/src/commandHandlers/commit/gitCherryPick.ts +++ b/src/commandHandlers/commit/gitCherryPick.ts @@ -16,7 +16,7 @@ export class GitCherryPickCommandHandler implements IGitCherryPickCommandHandler @command('git.commit.cherryPick', IGitCherryPickCommandHandler) public async cherryPickCommit(commit: CommitDetails, showPrompt: boolean = true) { commit = commit ? commit : this.commitViewerFactory.getCommitViewer().selectedCommit; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.workspaceFolder, commit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.logEntry.gitRoot); const currentBranch = await gitService.getCurrentBranch(); const msg = `Cherry pick ${commit.logEntry.hash.short} into ${currentBranch}?`; diff --git a/src/commandHandlers/commit/gitMerge.ts b/src/commandHandlers/commit/gitMerge.ts index cc9a9b6a..80b64a08 100644 --- a/src/commandHandlers/commit/gitMerge.ts +++ b/src/commandHandlers/commit/gitMerge.ts @@ -16,7 +16,7 @@ export class GitMergeCommandHandler implements IGitMergeCommandHandler { @command('git.commit.merge', IGitMergeCommandHandler) public async merge(commit: CommitDetails, showPrompt: boolean = true) { commit = commit ? commit : this.commitViewerFactory.getCommitViewer().selectedCommit; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.workspaceFolder, commit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.logEntry.gitRoot); const currentBranch = await gitService.getCurrentBranch(); const commitBranches = (await gitService.getRefsContainingCommit(commit.logEntry.hash.full)) diff --git a/src/commandHandlers/commit/gitRebase.ts b/src/commandHandlers/commit/gitRebase.ts index 920ae424..a242f7c4 100644 --- a/src/commandHandlers/commit/gitRebase.ts +++ b/src/commandHandlers/commit/gitRebase.ts @@ -16,7 +16,7 @@ export class GitRebaseCommandHandler implements IGitRebaseCommandHandler { @command('git.commit.rebase', IGitRebaseCommandHandler) public async rebase(commit: CommitDetails, showPrompt: boolean = true) { commit = commit ? commit : this.commitViewerFactory.getCommitViewer().selectedCommit; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.workspaceFolder, commit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.logEntry.gitRoot); const currentBranch = await gitService.getCurrentBranch(); const msg = `Rebase ${currentBranch} onto '${commit.logEntry.hash.short}'?`; diff --git a/src/commandHandlers/commit/revert.ts b/src/commandHandlers/commit/revert.ts index 280393e8..5aa9a58c 100644 --- a/src/commandHandlers/commit/revert.ts +++ b/src/commandHandlers/commit/revert.ts @@ -16,7 +16,7 @@ export class GitRevertCommandHandler implements IGitRevertCommandHandler { @command('git.commit.revert', IGitRevertCommandHandler) public async revertCommit(commit: CommitDetails, showPrompt: boolean = true) { commit = commit ? commit : this.commitViewerFactory.getCommitViewer().selectedCommit; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.workspaceFolder, commit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(commit.logEntry.gitRoot); const msg = `Are you sure you want to revert this '${commit.logEntry.hash.short}' commit?`; const yesNo = showPrompt ? await this.applicationShell.showQuickPick(['Yes', 'No'], { placeHolder: msg }) : 'Yes'; diff --git a/src/commandHandlers/fileCommit/fileCompare.ts b/src/commandHandlers/fileCommit/fileCompare.ts index 1cc3d387..34589e74 100644 --- a/src/commandHandlers/fileCommit/fileCompare.ts +++ b/src/commandHandlers/fileCommit/fileCompare.ts @@ -33,7 +33,7 @@ export class GitCompareFileCommitCommandHandler implements IGitCompareFileComman return; } const fileCommit = nodeOrFileCommit instanceof FileCommitDetails ? nodeOrFileCommit : nodeOrFileCommit.data!; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.workspaceFolder, fileCommit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.logEntry.gitRoot); const fileDiffs = await gitService.getDifferences(this.selectedCommit!.logEntry.hash.full, fileCommit.logEntry.hash.full); await this.commandManager.executeCommand('git.commit.diff.view', this.selectedCommit!, fileCommit, fileDiffs); } diff --git a/src/commandHandlers/fileCommit/fileHistory.ts b/src/commandHandlers/fileCommit/fileHistory.ts index 750e6b58..aaf14525 100644 --- a/src/commandHandlers/fileCommit/fileHistory.ts +++ b/src/commandHandlers/fileCommit/fileHistory.ts @@ -30,7 +30,7 @@ export class GitFileHistoryCommandHandler implements IGitFileHistoryCommandHandl @command('git.commit.FileEntry.ViewFileContents', IGitFileHistoryCommandHandler) public async viewFile(nodeOrFileCommit: FileNode | FileCommitDetails): Promise { const fileCommit = nodeOrFileCommit instanceof FileCommitDetails ? nodeOrFileCommit : nodeOrFileCommit.data!; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.workspaceFolder, fileCommit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.logEntry.gitRoot); if (fileCommit.committedFile.status === Status.Deleted) { return this.applicationShell.showErrorMessage('File cannot be viewed as it was deleted').then(() => void 0); } @@ -42,7 +42,7 @@ export class GitFileHistoryCommandHandler implements IGitFileHistoryCommandHandl @command('git.commit.FileEntry.CompareAgainstWorkspace', IGitFileHistoryCommandHandler) public async compareFileWithWorkspace(nodeOrFileCommit: FileNode | FileCommitDetails): Promise { const fileCommit = nodeOrFileCommit instanceof FileCommitDetails ? nodeOrFileCommit : nodeOrFileCommit.data!; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.workspaceFolder, fileCommit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.logEntry.gitRoot); if (fileCommit.committedFile.status === Status.Deleted) { return this.applicationShell.showErrorMessage('File cannot be compared with, as it was deleted').then(() => void 0); } @@ -59,7 +59,7 @@ export class GitFileHistoryCommandHandler implements IGitFileHistoryCommandHandl @command('git.commit.FileEntry.CompareAgainstPrevious', IGitFileHistoryCommandHandler) public async compareFileWithPrevious(nodeOrFileCommit: FileNode | FileCommitDetails): Promise { const fileCommit = nodeOrFileCommit instanceof FileCommitDetails ? nodeOrFileCommit : nodeOrFileCommit.data!; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.workspaceFolder, fileCommit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.logEntry.gitRoot); if (fileCommit.committedFile.status === Status.Deleted) { return this.applicationShell.showErrorMessage('File cannot be compared with, as it was deleted').then(() => void 0); @@ -84,7 +84,7 @@ export class GitFileHistoryCommandHandler implements IGitFileHistoryCommandHandl @command('git.commit.FileEntry.ViewPreviousFileContents', IGitFileHistoryCommandHandler) public async viewPreviousFile(nodeOrFileCommit: FileNode | FileCommitDetails): Promise { const fileCommit = nodeOrFileCommit instanceof FileCommitDetails ? nodeOrFileCommit : nodeOrFileCommit.data!; - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.workspaceFolder, fileCommit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.logEntry.gitRoot); if (fileCommit.committedFile.status === Status.Added) { return this.applicationShell.showErrorMessage('Previous version of the file cannot be opened, as this is a new file').then(() => void 0); @@ -99,7 +99,7 @@ export class GitFileHistoryCommandHandler implements IGitFileHistoryCommandHandl } @command('git.commit.compare.file.compare', IGitFileHistoryCommandHandler) public async compareFileAcrossCommits(fileCommit: CompareFileCommitDetails): Promise { - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.workspaceFolder, fileCommit.logEntry.gitRoot); + const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(fileCommit.logEntry.gitRoot); if (fileCommit.committedFile.status === Status.Deleted) { return this.applicationShell.showErrorMessage('File cannot be compared with, as it was deleted').then(() => void 0); diff --git a/src/commandHandlers/gitHistory.ts b/src/commandHandlers/gitHistory.ts index e4d91bb2..175c1c3e 100644 --- a/src/commandHandlers/gitHistory.ts +++ b/src/commandHandlers/gitHistory.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import { Uri, ViewColumn, window } from 'vscode'; import { ICommandManager } from '../application/types'; import { IDisposableRegistry } from '../application/types/disposableRegistry'; -import { FileCommitDetails, IUiService } from '../common/types'; +import { FileCommitDetails } from '../common/types'; import { previewUri } from '../constants'; import { IServiceContainer } from '../ioc/types'; import { FileNode } from '../nodes/types'; @@ -71,28 +71,18 @@ export class GitHistoryCommandHandler implements IGitHistoryCommandHandler { } public async viewHistory(fileUri?: Uri, lineNumber?: number): Promise { - const uiService = this.serviceContainer.get(IUiService); - const selection = await uiService.getWorkspaceFolder(fileUri); - if (!selection) { - return undefined; - } - const workspaceFolder = selection.workspaceFolder; - const gitRoot = selection.gitRoot; const gitService = await this.serviceContainer.get(IGitServiceFactory) - .createGitService(workspaceFolder, gitRoot); - const branchNamePromise = gitService.getCurrentBranch(); - const startupInfoPromise = this.server!.start(workspaceFolder); - const localePromise = osLocale(); - const gitRootsUnderWorkspacePromise = gitService.getGitRoots(workspaceFolder); - - const [branchName, startupInfo, locale, gitRootsUnderWorkspace] = await Promise.all([branchNamePromise, startupInfoPromise, localePromise, gitRootsUnderWorkspacePromise]); - + .createGitService(fileUri); + const branchName = await gitService.getCurrentBranch(); + const gitRoot = await gitService.getGitRoot(); + const startupInfo = await this.server!.start(); + const locale = await osLocale(); + const gitRootsUnderWorkspace = await gitService.getGitRoots(); // Do not include the search string into this const fullId = `${startupInfo.port}:${BranchSelection.Current}:${fileUri ? fileUri.fsPath : ''}:${gitRoot}`; const id = md5(fullId); //Date.now().toString(); await this.serviceContainer.get(IWorkspaceQueryStateStore) - .initialize(id, workspaceFolder, gitRoot, branchName, BranchSelection.Current, '', fileUri, lineNumber); - + .initialize(id, '', gitRoot, branchName, BranchSelection.Current, '', fileUri, lineNumber); const queryArgs = [ `id=${id}`, `port=${startupInfo.port}`, diff --git a/src/common/types.ts b/src/common/types.ts index e6657193..c03b1c5d 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -1,7 +1,7 @@ // tslint:disable-next-line:max-classes-per-file // tslint:disable:max-classes-per-file -import { Command, Uri } from 'vscode'; +import { Command } from 'vscode'; import { BranchSelection, CommittedFile, LogEntry } from '../types'; export const ILogService = Symbol('ILogService'); @@ -19,7 +19,6 @@ export const IUiService = Symbol('IUiService'); export interface IUiService { getBranchSelection(): Promise; - getWorkspaceFolder(uri?: Uri): Promise<{ workspaceFolder: string; gitRoot: string } | undefined>; selectFileCommitCommandAction(fileCommit: FileCommitDetails): Promise | undefined>; selectCommitCommandAction(commit: CommitDetails): Promise | undefined>; } diff --git a/src/common/uiService.ts b/src/common/uiService.ts index 28b648f4..f48e5950 100644 --- a/src/common/uiService.ts +++ b/src/common/uiService.ts @@ -1,17 +1,14 @@ import { inject, injectable } from 'inversify'; -import * as path from 'path'; -import { CancellationTokenSource, QuickPickItem, Uri } from 'vscode'; +import { CancellationTokenSource, QuickPickItem } from 'vscode'; import { IApplicationShell } from '../application/types'; -import { IWorkspaceService } from '../application/types/workspace'; import { ICommitCommandFactory, IFileCommitCommandFactory } from '../commandFactories/types'; import { IServiceContainer } from '../ioc/types'; -import { BranchSelection, IGitServiceFactory } from '../types'; +import { BranchSelection } from '../types'; import { CommitDetails, FileCommitDetails, ICommand, IUiService } from './types'; const allBranches = '$(git-branch) All branches'; const currentBranch = '$(git-branch) Current branch'; -type WorkspaceGitRoot = { workspaceFolder: string; gitRoot: string }; @injectable() export class UiService implements IUiService { private selectionActionToken?: CancellationTokenSource; @@ -29,54 +26,6 @@ export class UiService implements IUiService { return modeChoice.label === allBranches ? BranchSelection.All : BranchSelection.Current; } - public async getWorkspaceFolder(uri?: Uri): Promise { - let workspaceFolder: Uri | undefined; - const workspaceService = this.serviceContainer.get(IWorkspaceService); - if (uri) { - const workspaceFolderUri = workspaceService.getWorkspaceFolder(uri); - if (workspaceFolderUri) { - workspaceFolder = workspaceFolderUri.uri; - } - } - if (!Array.isArray(workspaceService.workspaceFolders) || workspaceService.workspaceFolders.length === 0) { - this.serviceContainer.get(IApplicationShell).showInformationMessage('Please open a workspace folder'); - return; - } - - const firstWorkspaceFolder = workspaceService.workspaceFolders[0].uri.fsPath; - const folders = workspaceFolder ? [workspaceFolder] : workspaceService.workspaceFolders.map(item => item.uri); - const gitServices = await Promise.all(folders.map(async folder => { - const gitService = await this.serviceContainer.get(IGitServiceFactory).createGitService(folder.fsPath, folder); - return gitService.getGitRoots(folder.fsPath); - })); - const flattendGitServices = gitServices.reduce((a, b) => a.concat(b), []); - // Filter to get only those that belong to a workspace folder - const filteredGitRoots = flattendGitServices - .map(gitRoot => { - const workspaceFolderUri = workspaceService.getWorkspaceFolder(Uri.file(gitRoot)); - if (workspaceFolderUri) { - return { - workspaceFolder: workspaceFolderUri.uri.fsPath, - gitRoot - }; - } - return; - }) - .filter(item => !!item) - .map(item => item!); - - switch (filteredGitRoots.length) { - case 0: { - return { workspaceFolder: firstWorkspaceFolder, gitRoot: firstWorkspaceFolder }; - } - case 1: { - return filteredGitRoots[0]!; - } - default: { - return this.selectGitRoot(filteredGitRoots); - } - } - } public async selectFileCommitCommandAction(fileCommit: FileCommitDetails): Promise | undefined> { if (this.selectionActionToken) { this.selectionActionToken.cancel(); @@ -97,25 +46,4 @@ export class UiService implements IUiService { return this.application.showQuickPick(commands, options); } - private async selectGitRoot(workspaceGitRoots: WorkspaceGitRoot[]) { - const app = this.serviceContainer.get(IApplicationShell); - type itemType = QuickPickItem & WorkspaceGitRoot; - const pickList: itemType[] = workspaceGitRoots.map(item => { - return { - ...item, - label: path.basename(item.gitRoot), - detail: item.gitRoot - }; - }); - const options = { - canPickMany: false, matchOnDescription: true, - matchOnDetail: true, placeHolder: 'Select a Git Repository' - }; - const selectedItem = await app.showQuickPick(pickList, options); - if (selectedItem) { - return selectedItem; - } - return; - } - } diff --git a/src/server/apiController.ts b/src/server/apiController.ts index 10e1ca09..5682f963 100644 --- a/src/server/apiController.ts +++ b/src/server/apiController.ts @@ -248,6 +248,7 @@ export class ApiController implements IApiRouteHandler { private handleRequest = (handler: (request: Request, response: Response) => void) => { return async (request: Request, response: Response) => { try { + // tslint:disable-next-line:await-promise await handler(request, response); } catch (err) { response.status(500).send(err); @@ -261,7 +262,6 @@ export class ApiController implements IApiRouteHandler { return this.stateStore.getState(id)!.gitRoot; } private async getRepository(id: string): Promise { - const workspaceFolder = this.getWorkspace(id); - return this.gitServiceFactory.createGitService(workspaceFolder, Uri.file(this.getGitRoot(id))); + return this.gitServiceFactory.createGitService(this.getGitRoot(id)); } } diff --git a/src/server/serverHost.ts b/src/server/serverHost.ts index b497d2ee..51e6bed0 100644 --- a/src/server/serverHost.ts +++ b/src/server/serverHost.ts @@ -39,7 +39,7 @@ export class ServerHost extends EventEmitter implements IServerHost { } } - public async start(_workspaceFolder: string): Promise { + public async start(): Promise { if (this.startPromise) { return this.startPromise; } diff --git a/src/server/types.ts b/src/server/types.ts index e8ae20e0..a400ca47 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -18,7 +18,7 @@ export type StartupInfo = { export const IServerHost = Symbol('IServer'); export interface IServerHost extends Disposable { - start(workspaceFolder: string): Promise; + start(): Promise; } export type State = { diff --git a/src/types.ts b/src/types.ts index 9d5eec4c..d8b66530 100644 --- a/src/types.ts +++ b/src/types.ts @@ -52,7 +52,7 @@ export type CommittedFile = { export type AvatarResponse = { items: Avatar[]; timestamp: number; -} +}; export type Avatar = { login: string; name: string; @@ -80,13 +80,15 @@ export type LogEntriesResponse = { file?: FsUri; branchSelection?: BranchSelection; selected?: LogEntry; + isLoading?: boolean; + isLoadingCommit?: boolean; }; export type LogEntries = { items: LogEntry[]; count: number; - isLoading: boolean; - isLoadingCommit: boolean; selected?: LogEntry; + isLoading?: boolean; + isLoadingCommit?: boolean; }; export type LogEntry = { gitRoot: string; @@ -130,14 +132,12 @@ export const IOutputChannel = Symbol('IOutputChannel'); export interface IGitService { getGitRoot(): Promise; - getGitRoots(rootDirectory?: string): Promise; + getGitRoots(): Promise; getGitRelativePath(file: FsUri): Promise; - getHeadHashes(): Promise<{ ref: string; hash: string }[]>; + getHeadHashes(): Promise<{ ref?: string; hash?: string }[]>; getAuthors(): Promise; getBranches(): Promise; getCurrentBranch(): Promise; - getObjectHash(object: string): Promise; - getHash(hash: string): Promise; getRefsContainingCommit(hash: string): Promise; getLogEntries(pageIndex?: number, pageSize?: number, branch?: string, searchText?: string, file?: FsUri, lineNumber?: number, author?: string): Promise; getPreviousCommitHashForFile(hash: string, file: FsUri): Promise; @@ -165,7 +165,7 @@ export type CommitComparison = { export const IGitServiceFactory = Symbol('IGitServiceFactory'); export interface IGitServiceFactory { - createGitService(workspaceRoot: string, resource?: Uri | string): Promise; + createGitService(resource?: Uri | string): Promise; } export enum CommitInfo { diff --git a/src/viewers/file/commitFileViewer.ts b/src/viewers/file/commitFileViewer.ts index ae1d0d43..f605b880 100644 --- a/src/viewers/file/commitFileViewer.ts +++ b/src/viewers/file/commitFileViewer.ts @@ -9,7 +9,7 @@ export class CommitFileViewerProvider implements TextDocumentContentProvider { public async provideTextDocumentContent(uri: Uri, _token: CancellationToken): Promise { const query = querystring.parse(uri.query) as { workspaceFolder: string; hash: string; fsPath: string }; - const gitService = await this.svcContainer.get(IGitServiceFactory).createGitService(query.workspaceFolder, Uri.parse(query.fsPath)); + const gitService = await this.svcContainer.get(IGitServiceFactory).createGitService(Uri.parse(query.fsPath)); return gitService.getCommitFileContent(query.hash, Uri.file(query.fsPath)); } }