Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Git - extract code into UnsafeRepositoryManager #184896

Merged
merged 1 commit into from Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions extensions/git/src/commands.ts
Expand Up @@ -3503,10 +3503,10 @@ export class CommandCenter {

const allRepositoriesLabel = l10n.t('All Repositories');
const allRepositoriesQuickPickItem: QuickPickItem = { label: allRepositoriesLabel };
const repositoriesQuickPickItems: QuickPickItem[] = Array.from(this.model.unsafeRepositories.keys())
const repositoriesQuickPickItems: QuickPickItem[] = this.model.unsafeRepositories
.sort(compareRepositoryLabel).map(r => new RepositoryItem(r));

quickpick.items = this.model.unsafeRepositories.size === 1 ? [...repositoriesQuickPickItems] :
quickpick.items = this.model.unsafeRepositories.length === 1 ? [...repositoriesQuickPickItems] :
[...repositoriesQuickPickItems, { label: '', kind: QuickPickItemKind.Separator }, allRepositoriesQuickPickItem];

quickpick.show();
Expand All @@ -3523,19 +3523,19 @@ export class CommandCenter {

if (repositoryItem.label === allRepositoriesLabel) {
// All Repositories
unsafeRepositories.push(...this.model.unsafeRepositories.keys());
unsafeRepositories.push(...this.model.unsafeRepositories);
} else {
// One Repository
unsafeRepositories.push((repositoryItem as RepositoryItem).path);
}

for (const unsafeRepository of unsafeRepositories) {
// Mark as Safe
await this.git.addSafeDirectory(this.model.unsafeRepositories.get(unsafeRepository)!);
await this.git.addSafeDirectory(this.model.getUnsafeRepositoryPath(unsafeRepository)!);

// Open Repository
await this.model.openRepository(unsafeRepository);
this.model.unsafeRepositories.delete(unsafeRepository);
this.model.deleteUnsafeRepository(unsafeRepository);
}
}

Expand Down
96 changes: 55 additions & 41 deletions extensions/git/src/model.ts
Expand Up @@ -34,40 +34,6 @@ class RepositoryPick implements QuickPickItem {
constructor(public readonly repository: Repository, public readonly index: number) { }
}

abstract class RepositoryMap<T = void> extends Map<string, T> {
constructor() {
super();
this.updateContextKey();
}

override set(key: string, value: T): this {
const result = super.set(key, value);
this.updateContextKey();

return result;
}

override delete(key: string): boolean {
const result = super.delete(key);
this.updateContextKey();

return result;
}

abstract updateContextKey(): void;
}

/**
* Key - normalized path used in user interface
* Value - path extracted from the output of the `git status` command
* used when calling `git config --global --add safe.directory`
*/
class UnsafeRepositoryMap extends RepositoryMap<string> {
updateContextKey(): void {
commands.executeCommand('setContext', 'git.unsafeRepositoryCount', this.size);
}
}

export interface ModelChangeEvent {
repository: Repository;
uri: Uri;
Expand Down Expand Up @@ -159,6 +125,45 @@ class ParentRepositoriesManager {
}
}

class UnsafeRepositoriesManager {

/**
* Key - normalized path used in user interface
* Value - path extracted from the output of the `git status` command
* used when calling `git config --global --add safe.directory`
*/
private _repositories = new Map<string, string>();
get repositories(): string[] {
return [...this._repositories.keys()];
}

addRepository(repository: string, path: string): void {
this._repositories.set(repository, path);
this.onDidChangeRepositories();
}

deleteRepository(repository: string): boolean {
const result = this._repositories.delete(repository);
if (result) {
this.onDidChangeRepositories();
}

return result;
}

getRepositoryPath(repository: string): string | undefined {
return this._repositories.get(repository);
}

hasRepository(repository: string): boolean {
return this._repositories.has(repository);
}

private onDidChangeRepositories(): void {
commands.executeCommand('setContext', 'git.unsafeRepositoryCount', this._repositories.size);
}
}

export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePublisherRegistry, IPostCommitCommandsProviderRegistry, IPushErrorHandlerRegistry {

private _onDidOpenRepository = new EventEmitter<Repository>();
Expand Down Expand Up @@ -226,9 +231,9 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu

private pushErrorHandlers = new Set<PushErrorHandler>();

private _unsafeRepositories = new UnsafeRepositoryMap();
get unsafeRepositories(): UnsafeRepositoryMap {
return this._unsafeRepositories;
private _unsafeRepositoriesManager: UnsafeRepositoriesManager;
get unsafeRepositories(): string[] {
return this._unsafeRepositoriesManager.repositories;
}

private _parentRepositoriesManager: ParentRepositoriesManager;
Expand Down Expand Up @@ -257,6 +262,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
// Repositories managers
this._closedRepositoriesManager = new ClosedRepositoriesManager(workspaceState);
this._parentRepositoriesManager = new ParentRepositoriesManager(globalState);
this._unsafeRepositoriesManager = new UnsafeRepositoriesManager();

workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables);
window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables);
Expand Down Expand Up @@ -296,7 +302,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
parentRepositoryConfig === 'prompt') {
// Parent repositories notification
this.showParentRepositoryNotification();
} else if (this._unsafeRepositories.size !== 0) {
} else if (this.unsafeRepositories.length !== 0) {
// Unsafe repositories notification
this.showUnsafeRepositoryNotification();
}
Expand Down Expand Up @@ -547,11 +553,11 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
this.logger.trace(`Unsafe repository: ${repositoryRoot}`);

// Show a notification if the unsafe repository is opened after the initial scan
if (this._state === 'initialized' && !this._unsafeRepositories.has(repositoryRoot)) {
if (this._state === 'initialized' && !this._unsafeRepositoriesManager.hasRepository(repositoryRoot)) {
this.showUnsafeRepositoryNotification();
}

this._unsafeRepositories.set(repositoryRoot, unsafeRepositoryMatch[2]);
this._unsafeRepositoriesManager.addRepository(repositoryRoot, unsafeRepositoryMatch[2]);

return;
}
Expand Down Expand Up @@ -903,6 +909,14 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
return [...this.pushErrorHandlers];
}

getUnsafeRepositoryPath(repository: string): string | undefined {
return this._unsafeRepositoriesManager.getRepositoryPath(repository);
}

deleteUnsafeRepository(repository: string): boolean {
return this._unsafeRepositoriesManager.deleteRepository(repository);
}

private async isRepositoryOutsideWorkspace(repositoryPath: string): Promise<boolean> {
const workspaceFolders = (workspace.workspaceFolders || [])
.filter(folder => folder.uri.scheme === 'file');
Expand Down Expand Up @@ -969,7 +983,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
return;
}

const message = this._unsafeRepositories.size === 1 ?
const message = this.unsafeRepositories.length === 1 ?
l10n.t('The git repository in the current folder is potentially unsafe as the folder is owned by someone other than the current user.') :
l10n.t('The git repositories in the current folder are potentially unsafe as the folders are owned by someone other than the current user.');

Expand Down