Skip to content

Commit

Permalink
[git] locate repositories in 2 phases + execute 2nd phase in the
Browse files Browse the repository at this point in the history
separate process

Signed-off-by: Anton Kosiakov <anton.kosyakov@typefox.io>
  • Loading branch information
akosyakov committed Nov 29, 2017
1 parent dff5b9c commit 29e17e5
Show file tree
Hide file tree
Showing 20 changed files with 269 additions and 148 deletions.
8 changes: 7 additions & 1 deletion packages/core/src/common/disposable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,19 @@ export class DisposableCollection implements Disposable {
push(disposable: Disposable): Disposable {
const disposables = this.disposables;
disposables.push(disposable);
return Disposable.create(() => {
const originalDispose = disposable.dispose.bind(disposable);
const toRemove = Disposable.create(() => {
const index = disposables.indexOf(disposable);
if (index !== -1) {
disposables.splice(index, 1);
}
this.checkDisposed();
});
disposable.dispose = () => {
toRemove.dispose();
originalDispose();
};
return toRemove;
}

pushAll(disposables: Disposable[]): Disposable[] {
Expand Down
3 changes: 1 addition & 2 deletions packages/git/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"@theia/filesystem": "^0.2.3",
"@theia/preferences-api": "^0.2.3",
"@theia/workspace": "^0.2.3",
"abs": "^1.3.8",
"dugite-extra": "0.0.1-alpha.15",
"findit2": "^2.2.3",
"ignore": "^3.3.7"
Expand Down Expand Up @@ -52,4 +51,4 @@
"nyc": {
"extends": "../../configs/nyc.json"
}
}
}
3 changes: 1 addition & 2 deletions packages/git/src/browser/git-quick-open-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import { injectable, inject } from "inversify";
import { QuickOpenItem, QuickOpenMode, QuickOpenModel } from '@theia/core/lib/browser/quick-open/quick-open-model';
import { QuickOpenService, QuickOpenOptions } from '@theia/core/lib/browser/quick-open/quick-open-service';
import { Git } from '../common';
import { Repository, Branch, BranchType } from '../common/model';
import { Git, Repository, Branch, BranchType } from '../common';
import { GitRepositoryProvider } from './git-repository-provider';

/**
Expand Down
62 changes: 43 additions & 19 deletions packages/git/src/browser/git-repository-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import { Event, Emitter } from '@theia/core';
export class GitRepositoryProvider {

protected _selectedRepository: Repository | undefined;
protected _allRepositories: Repository[];
protected containingRepository: Repository | undefined;
protected _allRepositories: Repository[] = [];
protected readonly onDidChangeRepositoryEmitter = new Emitter<Repository | undefined>();

constructor(
@inject(Git) protected readonly git: Git,
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService
) {
this._allRepositories = [];
this.refresh();
}

Expand All @@ -45,38 +45,62 @@ export class GitRepositoryProvider {
return this.onDidChangeRepositoryEmitter.event;
}

protected fireOnDidChangeRepository(repository: Repository | undefined): void {
this.onDidChangeRepositoryEmitter.fire(repository);
}

/**
* Returns with all know repositories.
*/
get allRepositories(): Repository[] {
return this._allRepositories;
}

/**
* Refreshes the state of this Git repository provider.
* - Retrieves all known repositories from the backend, discards the current state of [all known repositories](GitRepositoryProvider.allRepositories).
* - If no repository was [selected](GitRepositoryProvider.selectedRepository), then selects the first items from all known ones.
* - If no repositories are available, leaves the selected one as `undefined`.
* - If the previously selected one, does not exist among the most recently discovered one, selects the first one.
* - This method blocks, if the workspace root is not yet set.
*/
async refresh(): Promise<void> {
const root = await this.workspaceService.root;
if (!root) {
return;
}
const repositories = await this.git.repositories(root.uri);
await this.refreshContainingRepository(root.uri);
await this.refreshAllRepositories(root.uri);
}

protected async refreshAllRepositories(workspaceUri: string): Promise<void> {
const repositories = await this.git.repositories(workspaceUri, { shallow: false });
this._allRepositories = repositories;
// If no repository is selected or the selected one does not exist on the backend anymore, update the selected one.
if (this._selectedRepository === undefined
|| this._selectedRepository && !repositories.map(r => r.localUri.toString()).some(uri => uri === this._selectedRepository!.localUri.toString())
) {
this.refreshSelectedRepository();
}

protected async refreshContainingRepository(workspaceUri: string): Promise<void> {
const repositories = await this.git.repositories(workspaceUri, { shallow: true });
const containingRepository = <Repository | undefined>repositories[0];
if (Repository.equal(this.containingRepository, containingRepository)) {
return;
}
this.remove(this.containingRepository);
this.containingRepository = containingRepository;
this.add(containingRepository);
this.refreshSelectedRepository();
}

protected refreshSelectedRepository(): void {
const selectedRepository = this._selectedRepository;
if (!selectedRepository || !this.exists(selectedRepository)) {
this.selectedRepository = this._allRepositories[0];
}
}

protected add(repository: Repository | undefined): void {
if (!!repository && !this.exists(repository)) {
this._allRepositories.unshift(repository);
}
}
protected remove(repository: Repository | undefined): void {
if (repository) {
const index = this._allRepositories.findIndex(repository2 => Repository.equal(repository, repository2));
if (index !== -1) {
this._allRepositories.splice(index, 1);
}
}
}
protected exists(repository: Repository): boolean {
return this._allRepositories.some(repository2 => Repository.equal(repository, repository2));
}

}
3 changes: 1 addition & 2 deletions packages/git/src/browser/git-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
*/

import { injectable, inject } from 'inversify';
import { Git } from '../common/git';
import { Git, GitFileChange, GitFileStatus, Repository, WorkingDirectoryStatus } from '../common';
import { GIT_CONTEXT_MENU } from './git-context-menu';
import { GitFileChange, GitFileStatus, Repository, WorkingDirectoryStatus } from '../common/model';
import { GitWatcher, GitStatusChangeEvent } from '../common/git-watcher';
import { GIT_RESOURCE_SCHEME } from './git-resource';
import { GitRepositoryProvider } from './git-repository-provider';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@ export interface Repository {

}

export namespace Repository {
export function equal(repository: Repository | undefined, repository2: Repository | undefined): boolean {
if (repository && repository2) {
return repository.localUri === repository2.localUri;
}
return repository === repository2;
}
}

/**
* The branch type. Either local or remote.
* The order matters.
Expand Down
2 changes: 1 addition & 1 deletion packages/git/src/common/git-watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import { injectable, inject } from "inversify";
import { JsonRpcServer, JsonRpcProxy } from '@theia/core';
import { Repository, WorkingDirectoryStatus } from './model';
import { Repository, WorkingDirectoryStatus } from './git-model';
import { Disposable, DisposableCollection, Emitter, Event } from '@theia/core/lib/common';

/**
Expand Down
19 changes: 16 additions & 3 deletions packages/git/src/common/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { Repository, WorkingDirectoryStatus, Branch } from './model';
import { Disposable } from '@theia/core';
import { Repository, WorkingDirectoryStatus, Branch } from './git-model';

/**
* The WS endpoint path to the Git service.
Expand Down Expand Up @@ -129,6 +130,18 @@ export namespace Git {

}

/**
* Git repositories options.
*/
export interface Repositories {

/**
* Whether the deep search should be performed to find git repositories.
*/
readonly shallow: boolean;

}

/**
* Options for further `git checkout` refinements.
*/
Expand Down Expand Up @@ -331,7 +344,7 @@ export namespace Git {
/**
* Provides basic functionality for Git.
*/
export interface Git {
export interface Git extends Disposable {

/**
* Clones a remote repository into the desired local location.
Expand All @@ -344,7 +357,7 @@ export interface Git {
/**
* Resolves to an array of repositories discovered in the workspace given with the workspace root URI.
*/
repositories(workspaceRootUri: string): Promise<Repository[]>;
repositories(workspaceRootUri: string, options: Git.Options.Repositories): Promise<Repository[]>;

/**
* Returns with the working directory status of the given Git repository.
Expand Down
2 changes: 1 addition & 1 deletion packages/git/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
*/

export * from './git';
export * from './model';
export * from './git-model';
10 changes: 5 additions & 5 deletions packages/git/src/node/dugite-git-watcher.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*
* Copyright (C) 2017 TypeFox and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
* Copyright (C) 2017 TypeFox and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { injectable, inject } from "inversify";
import { Disposable, DisposableCollection } from "@theia/core";
Expand Down
21 changes: 12 additions & 9 deletions packages/git/src/node/dugite-git.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*
* Copyright (C) 2017 TypeFox and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
* Copyright (C) 2017 TypeFox and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import * as path from 'path';
import * as temp from 'temp';
Expand All @@ -13,13 +13,15 @@ import { Container } from 'inversify';
import { DugiteGit } from './dugite-git';
import { git as gitExec } from 'dugite-extra/lib/core/git';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { WorkingDirectoryStatus, Repository } from '../common/model';
import { WorkingDirectoryStatus, Repository } from '../common';
import { initRepository, createTestRepository } from 'dugite-extra/lib/command/test-helper';
import { WorkspaceServer } from '@theia/workspace/lib/common/workspace-protocol';
import { bindGit } from './git-backend-module';
import { bindLogger } from '@theia/core/lib/node/logger-backend-module';
import { ILoggerServer } from '@theia/core/lib/common/logger-protocol';
import { ConsoleLoggerServer } from '@theia/core/lib/common/console-logger-server';
import { GitLocatorImpl } from './git-locator/git-locator-impl';
import { GitLocator } from './git-locator/git-locator-protocol';

const track = temp.track();

Expand All @@ -45,7 +47,7 @@ describe('git', async function () {
const git = await createGit();
const workspace = await createWorkspace(root);
const workspaceRootUri = await workspace.getRoot();
const repositories = await git.repositories(workspaceRootUri!);
const repositories = await git.repositories(workspaceRootUri!, { shallow: false });
expect(repositories.map(r => path.basename(FileUri.fsPath(r.localUri))).sort()).to.deep.equal(['A', 'B', 'C']);

});
Expand All @@ -64,7 +66,7 @@ describe('git', async function () {
const git = await createGit();
const workspace = await createWorkspace(path.join(root, 'BASE'));
const workspaceRootUri = await workspace.getRoot();
const repositories = await git.repositories(workspaceRootUri!);
const repositories = await git.repositories(workspaceRootUri!, { shallow: false });
expect(repositories.map(r => path.basename(FileUri.fsPath(r.localUri))).sort()).to.deep.equal(['A', 'B', 'BASE', 'C']);

});
Expand All @@ -84,7 +86,7 @@ describe('git', async function () {
const git = await createGit();
const workspace = await createWorkspace(path.join(root, 'BASE', 'WS_ROOT'));
const workspaceRootUri = await workspace.getRoot();
const repositories = await git.repositories(workspaceRootUri!);
const repositories = await git.repositories(workspaceRootUri!, { shallow: false });
const repositoryNames = repositories.map(r => path.basename(FileUri.fsPath(r.localUri)));
expect(repositoryNames.shift()).to.equal('BASE'); // The first must be the container repository.
expect(repositoryNames.sort()).to.deep.equal(['A', 'B', 'C']);
Expand Down Expand Up @@ -278,6 +280,7 @@ async function createGit(fsRoot: string = ''): Promise<DugiteGit> {
bindLogger(bind);
container.rebind(ILoggerServer).to(ConsoleLoggerServer).inSingletonScope();
bindGit(bind);
container.rebind(GitLocator).toConstantValue(new GitLocatorImpl());
return container.get(DugiteGit);
}

Expand Down
Loading

0 comments on commit 29e17e5

Please sign in to comment.