mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 18:49:00 +01:00
@@ -5,8 +5,9 @@
|
||||
|
||||
import { Command, Disposable, Event, EventEmitter, SourceControlActionButton, Uri, workspace, l10n } from 'vscode';
|
||||
import { Branch, Status } from './api/git';
|
||||
import { OperationKind } from './operation';
|
||||
import { CommitCommandsCenter } from './postCommitCommands';
|
||||
import { Repository, OperationKind } from './repository';
|
||||
import { Repository } from './repository';
|
||||
import { dispose } from './util';
|
||||
|
||||
interface ActionButtonState {
|
||||
|
||||
@@ -4,14 +4,10 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { workspace, Disposable, EventEmitter, Memento, window, MessageItem, ConfigurationTarget, Uri, ConfigurationChangeEvent, l10n, env } from 'vscode';
|
||||
import { Repository, OperationKind } from './repository';
|
||||
import { Repository } from './repository';
|
||||
import { eventToPromise, filterEvent, onceEvent } from './util';
|
||||
import { GitErrorCodes } from './api/git';
|
||||
|
||||
function isRemoteOperation(operation: OperationKind): boolean {
|
||||
return operation === OperationKind.Pull || operation === OperationKind.Push || operation === OperationKind.Sync || operation === OperationKind.Fetch;
|
||||
}
|
||||
|
||||
export class AutoFetcher {
|
||||
|
||||
private static DidInformUser = 'autofetch.didInformUser';
|
||||
@@ -30,7 +26,7 @@ export class AutoFetcher {
|
||||
workspace.onDidChangeConfiguration(this.onConfiguration, this, this.disposables);
|
||||
this.onConfiguration();
|
||||
|
||||
const onGoodRemoteOperation = filterEvent(repository.onDidRunOperation, ({ operation, error }) => !error && isRemoteOperation(operation));
|
||||
const onGoodRemoteOperation = filterEvent(repository.onDidRunOperation, ({ operation, error }) => !error && operation.remote);
|
||||
const onFirstGoodRemoteOperation = onceEvent(onGoodRemoteOperation);
|
||||
onFirstGoodRemoteOperation(this.onFirstGoodRemoteOperation, this, this.disposables);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor, Memento, commands, LogOutputChannel, l10n, ProgressLocation } from 'vscode';
|
||||
import TelemetryReporter from '@vscode/extension-telemetry';
|
||||
import { OperationKind, Repository, RepositoryState } from './repository';
|
||||
import { Repository, RepositoryState } from './repository';
|
||||
import { memoize, sequentialize, debounce } from './decorators';
|
||||
import { dispose, anyEvent, filterEvent, isDescendant, pathEquals, toDisposable, eventToPromise } from './util';
|
||||
import { Git } from './git';
|
||||
@@ -18,6 +18,7 @@ import { IPushErrorHandlerRegistry } from './pushError';
|
||||
import { ApiRepository } from './api/api1';
|
||||
import { IRemoteSourcePublisherRegistry } from './remotePublisher';
|
||||
import { IPostCommitCommandsProviderRegistry } from './postCommitCommands';
|
||||
import { OperationKind } from './operation';
|
||||
|
||||
class RepositoryPick implements QuickPickItem {
|
||||
@memoize get label(): string {
|
||||
|
||||
249
extensions/git/src/operation.ts
Normal file
249
extensions/git/src/operation.ts
Normal file
@@ -0,0 +1,249 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { LogOutputChannel } from 'vscode';
|
||||
|
||||
export const enum OperationKind {
|
||||
Add = 'Add',
|
||||
AddNoProgress = 'AddNoProgress',
|
||||
Apply = 'Apply',
|
||||
Blame = 'Blame',
|
||||
Branch = 'Branch',
|
||||
CheckIgnore = 'CheckIgnore',
|
||||
Checkout = 'Checkout',
|
||||
CheckoutTracking = 'CheckoutTracking',
|
||||
CherryPick = 'CherryPick',
|
||||
Clean = 'Clean',
|
||||
CleanNoProgress = 'CleanNoProgress',
|
||||
Commit = 'Commit',
|
||||
Config = 'Config',
|
||||
DeleteBranch = 'DeleteBranch',
|
||||
DeleteRef = 'DeleteRef',
|
||||
DeleteTag = 'DeleteTag',
|
||||
Diff = 'Diff',
|
||||
Fetch = 'Fetch',
|
||||
FetchNoProgress = 'FetchNoProgress',
|
||||
FindTrackingBranches = 'GetTracking',
|
||||
GetBranch = 'GetBranch',
|
||||
GetBranches = 'GetBranches',
|
||||
GetCommitTemplate = 'GetCommitTemplate',
|
||||
GetObjectDetails = 'GetObjectDetails',
|
||||
HashObject = 'HashObject',
|
||||
Ignore = 'Ignore',
|
||||
Log = 'Log',
|
||||
LogFile = 'LogFile',
|
||||
Merge = 'Merge',
|
||||
MergeAbort = 'MergeAbort',
|
||||
MergeBase = 'MergeBase',
|
||||
Move = 'Move',
|
||||
PostCommitCommand = 'PostCommitCommand',
|
||||
Pull = 'Pull',
|
||||
Push = 'Push',
|
||||
Remote = 'Remote',
|
||||
RenameBranch = 'RenameBranch',
|
||||
Remove = 'Remove',
|
||||
Reset = 'Reset',
|
||||
Rebase = 'Rebase',
|
||||
RebaseAbort = 'RebaseAbort',
|
||||
RebaseContinue = 'RebaseContinue',
|
||||
RevertFiles = 'RevertFiles',
|
||||
RevertFilesNoProgress = 'RevertFilesNoProgress',
|
||||
SetBranchUpstream = 'SetBranchUpstream',
|
||||
Show = 'Show',
|
||||
Stage = 'Stage',
|
||||
Status = 'Status',
|
||||
Stash = 'Stash',
|
||||
SubmoduleUpdate = 'SubmoduleUpdate',
|
||||
Sync = 'Sync',
|
||||
Tag = 'Tag',
|
||||
}
|
||||
|
||||
export type Operation = AddOperation | ApplyOperation | BlameOperation | BranchOperation | CheckIgnoreOperation | CherryPickOperation |
|
||||
CheckoutOperation | CheckoutTrackingOperation | CleanOperation | CommitOperation | ConfigOperation | DeleteBranchOperation |
|
||||
DeleteRefOperation | DeleteTagOperation | DiffOperation | FetchOperation | FindTrackingBranchesOperation | GetBranchOperation |
|
||||
GetBranchesOperation | GetCommitTemplateOperation | GetObjectDetailsOperation | HashObjectOperation | IgnoreOperation | LogOperation |
|
||||
LogFileOperation | MergeOperation | MergeAbortOperation | MergeBaseOperation | MoveOperation | PostCommitCommandOperation |
|
||||
PullOperation | PushOperation | RemoteOperation | RenameBranchOperation | RemoveOperation | ResetOperation | RebaseOperation |
|
||||
RebaseAbortOperation | RebaseContinueOperation | RevertFilesOperation | SetBranchUpstreamOperation | ShowOperation | StageOperation |
|
||||
StatusOperation | StashOperation | SubmoduleUpdateOperation | SyncOperation | TagOperation;
|
||||
|
||||
type BaseOperation = { kind: OperationKind; readOnly: boolean; remote: boolean; retry: boolean; showProgress: boolean };
|
||||
export type AddOperation = BaseOperation & { kind: OperationKind.Add };
|
||||
export type ApplyOperation = BaseOperation & { kind: OperationKind.Apply };
|
||||
export type BlameOperation = BaseOperation & { kind: OperationKind.Blame };
|
||||
export type BranchOperation = BaseOperation & { kind: OperationKind.Branch };
|
||||
export type CheckIgnoreOperation = BaseOperation & { kind: OperationKind.CheckIgnore };
|
||||
export type CherryPickOperation = BaseOperation & { kind: OperationKind.CherryPick };
|
||||
export type CheckoutOperation = BaseOperation & { kind: OperationKind.Checkout; refLabel: string };
|
||||
export type CheckoutTrackingOperation = BaseOperation & { kind: OperationKind.CheckoutTracking; refLabel: string };
|
||||
export type CleanOperation = BaseOperation & { kind: OperationKind.Clean };
|
||||
export type CommitOperation = BaseOperation & { kind: OperationKind.Commit };
|
||||
export type ConfigOperation = BaseOperation & { kind: OperationKind.Config };
|
||||
export type DeleteBranchOperation = BaseOperation & { kind: OperationKind.DeleteBranch };
|
||||
export type DeleteRefOperation = BaseOperation & { kind: OperationKind.DeleteRef };
|
||||
export type DeleteTagOperation = BaseOperation & { kind: OperationKind.DeleteTag };
|
||||
export type DiffOperation = BaseOperation & { kind: OperationKind.Diff };
|
||||
export type FetchOperation = BaseOperation & { kind: OperationKind.Fetch };
|
||||
export type FindTrackingBranchesOperation = BaseOperation & { kind: OperationKind.FindTrackingBranches };
|
||||
export type GetBranchOperation = BaseOperation & { kind: OperationKind.GetBranch };
|
||||
export type GetBranchesOperation = BaseOperation & { kind: OperationKind.GetBranches };
|
||||
export type GetCommitTemplateOperation = BaseOperation & { kind: OperationKind.GetCommitTemplate };
|
||||
export type GetObjectDetailsOperation = BaseOperation & { kind: OperationKind.GetObjectDetails };
|
||||
export type HashObjectOperation = BaseOperation & { kind: OperationKind.HashObject };
|
||||
export type IgnoreOperation = BaseOperation & { kind: OperationKind.Ignore };
|
||||
export type LogOperation = BaseOperation & { kind: OperationKind.Log };
|
||||
export type LogFileOperation = BaseOperation & { kind: OperationKind.LogFile };
|
||||
export type MergeOperation = BaseOperation & { kind: OperationKind.Merge };
|
||||
export type MergeAbortOperation = BaseOperation & { kind: OperationKind.MergeAbort };
|
||||
export type MergeBaseOperation = BaseOperation & { kind: OperationKind.MergeBase };
|
||||
export type MoveOperation = BaseOperation & { kind: OperationKind.Move };
|
||||
export type PostCommitCommandOperation = BaseOperation & { kind: OperationKind.PostCommitCommand };
|
||||
export type PullOperation = BaseOperation & { kind: OperationKind.Pull };
|
||||
export type PushOperation = BaseOperation & { kind: OperationKind.Push };
|
||||
export type RemoteOperation = BaseOperation & { kind: OperationKind.Remote };
|
||||
export type RenameBranchOperation = BaseOperation & { kind: OperationKind.RenameBranch };
|
||||
export type RemoveOperation = BaseOperation & { kind: OperationKind.Remove };
|
||||
export type ResetOperation = BaseOperation & { kind: OperationKind.Reset };
|
||||
export type RebaseOperation = BaseOperation & { kind: OperationKind.Rebase };
|
||||
export type RebaseAbortOperation = BaseOperation & { kind: OperationKind.RebaseAbort };
|
||||
export type RebaseContinueOperation = BaseOperation & { kind: OperationKind.RebaseContinue };
|
||||
export type RevertFilesOperation = BaseOperation & { kind: OperationKind.RevertFiles };
|
||||
export type SetBranchUpstreamOperation = BaseOperation & { kind: OperationKind.SetBranchUpstream };
|
||||
export type ShowOperation = BaseOperation & { kind: OperationKind.Show };
|
||||
export type StageOperation = BaseOperation & { kind: OperationKind.Stage };
|
||||
export type StatusOperation = BaseOperation & { kind: OperationKind.Status };
|
||||
export type StashOperation = BaseOperation & { kind: OperationKind.Stash };
|
||||
export type SubmoduleUpdateOperation = BaseOperation & { kind: OperationKind.SubmoduleUpdate };
|
||||
export type SyncOperation = BaseOperation & { kind: OperationKind.Sync };
|
||||
export type TagOperation = BaseOperation & { kind: OperationKind.Tag };
|
||||
|
||||
export const Operation = {
|
||||
Add: (showProgress: boolean) => ({ kind: OperationKind.Add, readOnly: false, remote: false, retry: false, showProgress } as AddOperation),
|
||||
Apply: { kind: OperationKind.Apply, readOnly: false, remote: false, retry: false, showProgress: true } as ApplyOperation,
|
||||
Blame: { kind: OperationKind.Blame, readOnly: true, remote: false, retry: false, showProgress: true } as BlameOperation,
|
||||
Branch: { kind: OperationKind.Branch, readOnly: false, remote: false, retry: false, showProgress: true } as BranchOperation,
|
||||
CheckIgnore: { kind: OperationKind.CheckIgnore, readOnly: true, remote: false, retry: false, showProgress: false } as CheckIgnoreOperation,
|
||||
CherryPick: { kind: OperationKind.CherryPick, readOnly: false, remote: false, retry: false, showProgress: true } as CherryPickOperation,
|
||||
Checkout: (refLabel: string) => ({ kind: OperationKind.Checkout, readOnly: false, remote: false, retry: false, showProgress: true, refLabel } as CheckoutOperation),
|
||||
CheckoutTracking: (refLabel: string) => ({ kind: OperationKind.CheckoutTracking, readOnly: false, remote: false, retry: false, showProgress: true, refLabel } as CheckoutTrackingOperation),
|
||||
Clean: (showProgress: boolean) => ({ kind: OperationKind.Clean, readOnly: false, remote: false, retry: false, showProgress } as CleanOperation),
|
||||
Commit: { kind: OperationKind.Commit, readOnly: false, remote: false, retry: false, showProgress: true } as CommitOperation,
|
||||
Config: { kind: OperationKind.Config, readOnly: false, remote: false, retry: false, showProgress: true } as ConfigOperation,
|
||||
DeleteBranch: { kind: OperationKind.DeleteBranch, readOnly: false, remote: false, retry: false, showProgress: true } as DeleteBranchOperation,
|
||||
DeleteRef: { kind: OperationKind.DeleteRef, readOnly: false, remote: false, retry: false, showProgress: true } as DeleteRefOperation,
|
||||
DeleteTag: { kind: OperationKind.DeleteTag, readOnly: false, remote: false, retry: false, showProgress: true } as DeleteTagOperation,
|
||||
Diff: { kind: OperationKind.Diff, readOnly: true, remote: false, retry: false, showProgress: true } as DiffOperation,
|
||||
Fetch: (showProgress: boolean) => ({ kind: OperationKind.Fetch, readOnly: false, remote: true, retry: true, showProgress } as FetchOperation),
|
||||
FindTrackingBranches: { kind: OperationKind.FindTrackingBranches, readOnly: true, remote: false, retry: false, showProgress: true } as FindTrackingBranchesOperation,
|
||||
GetBranch: { kind: OperationKind.GetBranch, readOnly: true, remote: false, retry: false, showProgress: true } as GetBranchOperation,
|
||||
GetBranches: { kind: OperationKind.GetBranches, readOnly: true, remote: false, retry: false, showProgress: true } as GetBranchesOperation,
|
||||
GetCommitTemplate: { kind: OperationKind.GetCommitTemplate, readOnly: true, remote: false, retry: false, showProgress: true } as GetCommitTemplateOperation,
|
||||
GetObjectDetails: { kind: OperationKind.GetObjectDetails, readOnly: true, remote: false, retry: false, showProgress: false } as GetObjectDetailsOperation,
|
||||
HashObject: { kind: OperationKind.HashObject, readOnly: false, remote: false, retry: false, showProgress: true } as HashObjectOperation,
|
||||
Ignore: { kind: OperationKind.Ignore, readOnly: false, remote: false, retry: false, showProgress: true } as IgnoreOperation,
|
||||
Log: { kind: OperationKind.Log, readOnly: true, remote: false, retry: false, showProgress: true } as LogOperation,
|
||||
LogFile: { kind: OperationKind.LogFile, readOnly: true, remote: false, retry: false, showProgress: true } as LogFileOperation,
|
||||
Merge: { kind: OperationKind.Merge, readOnly: false, remote: false, retry: false, showProgress: true } as MergeOperation,
|
||||
MergeAbort: { kind: OperationKind.MergeAbort, readOnly: false, remote: false, retry: false, showProgress: true } as MergeAbortOperation,
|
||||
MergeBase: { kind: OperationKind.MergeBase, readOnly: true, remote: false, retry: false, showProgress: true } as MergeBaseOperation,
|
||||
Move: { kind: OperationKind.Move, readOnly: false, remote: false, retry: false, showProgress: true } as MoveOperation,
|
||||
PostCommitCommand: { kind: OperationKind.PostCommitCommand, readOnly: false, remote: false, retry: false, showProgress: true } as PostCommitCommandOperation,
|
||||
Pull: { kind: OperationKind.Pull, readOnly: false, remote: true, retry: true, showProgress: true } as PullOperation,
|
||||
Push: { kind: OperationKind.Push, readOnly: false, remote: true, retry: false, showProgress: true } as PushOperation,
|
||||
Remote: { kind: OperationKind.Remote, readOnly: false, remote: false, retry: false, showProgress: true } as RemoteOperation,
|
||||
RenameBranch: { kind: OperationKind.RenameBranch, readOnly: false, remote: false, retry: false, showProgress: true } as RenameBranchOperation,
|
||||
Remove: { kind: OperationKind.Remove, readOnly: false, remote: false, retry: false, showProgress: true } as RemoveOperation,
|
||||
Reset: { kind: OperationKind.Reset, readOnly: false, remote: false, retry: false, showProgress: true } as ResetOperation,
|
||||
Rebase: { kind: OperationKind.Rebase, readOnly: false, remote: false, retry: false, showProgress: true } as RebaseOperation,
|
||||
RebaseAbort: { kind: OperationKind.RebaseAbort, readOnly: false, remote: false, retry: false, showProgress: true } as RebaseAbortOperation,
|
||||
RebaseContinue: { kind: OperationKind.RebaseContinue, readOnly: false, remote: false, retry: false, showProgress: true } as RebaseContinueOperation,
|
||||
RevertFiles: (showProgress: boolean) => ({ kind: OperationKind.RevertFiles, readOnly: false, remote: false, retry: false, showProgress } as RevertFilesOperation),
|
||||
SetBranchUpstream: { kind: OperationKind.SetBranchUpstream, readOnly: false, remote: false, retry: false, showProgress: true } as SetBranchUpstreamOperation,
|
||||
Show: { kind: OperationKind.Show, readOnly: true, remote: false, retry: false, showProgress: false } as ShowOperation,
|
||||
Stage: { kind: OperationKind.Stage, readOnly: false, remote: false, retry: false, showProgress: true } as StageOperation,
|
||||
Status: { kind: OperationKind.Status, readOnly: false, remote: false, retry: false, showProgress: true } as StatusOperation,
|
||||
Stash: { kind: OperationKind.Stash, readOnly: false, remote: false, retry: false, showProgress: true } as StashOperation,
|
||||
SubmoduleUpdate: { kind: OperationKind.SubmoduleUpdate, readOnly: false, remote: false, retry: false, showProgress: true } as SubmoduleUpdateOperation,
|
||||
Sync: { kind: OperationKind.Sync, readOnly: false, remote: true, retry: true, showProgress: true } as SyncOperation,
|
||||
Tag: { kind: OperationKind.Tag, readOnly: false, remote: false, retry: false, showProgress: true } as TagOperation
|
||||
};
|
||||
|
||||
export interface OperationResult {
|
||||
operation: Operation;
|
||||
error: any;
|
||||
}
|
||||
|
||||
interface IOperationManager {
|
||||
isIdle(): boolean;
|
||||
getOperations(operationKind: OperationKind): Operation[];
|
||||
shouldShowProgress(): boolean;
|
||||
isRunning(operationKind: OperationKind): boolean;
|
||||
}
|
||||
|
||||
export class OperationManager implements IOperationManager {
|
||||
|
||||
private operations = new Map<OperationKind, Set<Operation>>();
|
||||
|
||||
constructor(private readonly logger: LogOutputChannel) { }
|
||||
|
||||
start(operation: Operation): void {
|
||||
if (this.operations.has(operation.kind)) {
|
||||
this.operations.get(operation.kind)!.add(operation);
|
||||
} else {
|
||||
this.operations.set(operation.kind, new Set([operation]));
|
||||
}
|
||||
|
||||
this.logger.trace(`Operation start: ${operation.kind} (readOnly: ${operation.readOnly}; retry: ${operation.retry}; showProgress: ${operation.showProgress})`);
|
||||
}
|
||||
|
||||
end(operation: Operation): void {
|
||||
const operationSet = this.operations.get(operation.kind);
|
||||
if (operationSet) {
|
||||
operationSet.delete(operation);
|
||||
if (operationSet.size === 0) {
|
||||
this.operations.delete(operation.kind);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.trace(`Operation end: ${operation.kind} (readOnly: ${operation.readOnly}; retry: ${operation.retry}; showProgress: ${operation.showProgress})`);
|
||||
}
|
||||
|
||||
getOperations(operationKind: OperationKind): Operation[] {
|
||||
const operationSet = this.operations.get(operationKind);
|
||||
return operationSet ? Array.from(operationSet) : [];
|
||||
}
|
||||
|
||||
isRunning(operationKind: OperationKind): boolean {
|
||||
return this.operations.has(operationKind);
|
||||
}
|
||||
|
||||
isIdle(): boolean {
|
||||
const operationSets = this.operations.values();
|
||||
|
||||
for (const operationSet of operationSets) {
|
||||
for (const operation of operationSet) {
|
||||
if (!operation.readOnly) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
shouldShowProgress(): boolean {
|
||||
const operationSets = this.operations.values();
|
||||
|
||||
for (const operationSet of operationSets) {
|
||||
for (const operation of operationSet) {
|
||||
if (operation.showProgress) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,10 @@
|
||||
|
||||
import { Command, commands, Disposable, Event, EventEmitter, Memento, Uri, workspace, l10n } from 'vscode';
|
||||
import { PostCommitCommandsProvider } from './api/git';
|
||||
import { OperationKind, Repository } from './repository';
|
||||
import { Repository } from './repository';
|
||||
import { ApiRepository } from './api/api1';
|
||||
import { dispose } from './util';
|
||||
import { OperationKind } from './operation';
|
||||
|
||||
export interface IPostCommitCommandsProviderRegistry {
|
||||
readonly onDidChangePostCommitCommandsProviders: Event<void>;
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ApiRepository } from './api/api1';
|
||||
import { IRemoteSourcePublisherRegistry } from './remotePublisher';
|
||||
import { ActionButtonCommand } from './actionButton';
|
||||
import { IPostCommitCommandsProviderRegistry, CommitCommandsCenter } from './postCommitCommands';
|
||||
import { Operation, OperationKind, OperationManager, OperationResult } from './operation';
|
||||
|
||||
const timeout = (millis: number) => new Promise(c => setTimeout(c, millis));
|
||||
|
||||
@@ -302,174 +303,6 @@ export class Resource implements SourceControlResourceState {
|
||||
}
|
||||
}
|
||||
|
||||
export const enum OperationKind {
|
||||
Status = 'Status',
|
||||
Config = 'Config',
|
||||
Diff = 'Diff',
|
||||
MergeBase = 'MergeBase',
|
||||
Add = 'Add',
|
||||
AddNoProgress = 'AddNoProgress',
|
||||
Remove = 'Remove',
|
||||
RevertFiles = 'RevertFiles',
|
||||
RevertFilesNoProgress = 'RevertFilesNoProgress',
|
||||
Commit = 'Commit',
|
||||
PostCommitCommand = 'PostCommitCommand',
|
||||
Clean = 'Clean',
|
||||
CleanNoProgress = 'CleanNoProgress',
|
||||
Branch = 'Branch',
|
||||
GetBranch = 'GetBranch',
|
||||
GetBranches = 'GetBranches',
|
||||
SetBranchUpstream = 'SetBranchUpstream',
|
||||
HashObject = 'HashObject',
|
||||
Checkout = 'Checkout',
|
||||
CheckoutTracking = 'CheckoutTracking',
|
||||
Reset = 'Reset',
|
||||
Remote = 'Remote',
|
||||
Fetch = 'Fetch',
|
||||
FetchNoProgress = 'FetchNoProgress',
|
||||
Pull = 'Pull',
|
||||
Push = 'Push',
|
||||
CherryPick = 'CherryPick',
|
||||
Sync = 'Sync',
|
||||
Show = 'Show',
|
||||
Stage = 'Stage',
|
||||
GetCommitTemplate = 'GetCommitTemplate',
|
||||
DeleteBranch = 'DeleteBranch',
|
||||
RenameBranch = 'RenameBranch',
|
||||
DeleteRef = 'DeleteRef',
|
||||
Merge = 'Merge',
|
||||
MergeAbort = 'MergeAbort',
|
||||
Rebase = 'Rebase',
|
||||
Ignore = 'Ignore',
|
||||
Tag = 'Tag',
|
||||
DeleteTag = 'DeleteTag',
|
||||
Stash = 'Stash',
|
||||
CheckIgnore = 'CheckIgnore',
|
||||
GetObjectDetails = 'GetObjectDetails',
|
||||
SubmoduleUpdate = 'SubmoduleUpdate',
|
||||
RebaseAbort = 'RebaseAbort',
|
||||
RebaseContinue = 'RebaseContinue',
|
||||
FindTrackingBranches = 'GetTracking',
|
||||
Apply = 'Apply',
|
||||
Blame = 'Blame',
|
||||
Log = 'Log',
|
||||
LogFile = 'LogFile',
|
||||
|
||||
Move = 'Move'
|
||||
}
|
||||
|
||||
function isReadOnly(operation: OperationKind): boolean {
|
||||
switch (operation) {
|
||||
case OperationKind.Blame:
|
||||
case OperationKind.CheckIgnore:
|
||||
case OperationKind.Diff:
|
||||
case OperationKind.FindTrackingBranches:
|
||||
case OperationKind.GetBranch:
|
||||
case OperationKind.GetCommitTemplate:
|
||||
case OperationKind.GetObjectDetails:
|
||||
case OperationKind.Log:
|
||||
case OperationKind.LogFile:
|
||||
case OperationKind.MergeBase:
|
||||
case OperationKind.Show:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function shouldShowProgress(operation: OperationKind): boolean {
|
||||
switch (operation) {
|
||||
case OperationKind.AddNoProgress:
|
||||
case OperationKind.CleanNoProgress:
|
||||
case OperationKind.FetchNoProgress:
|
||||
case OperationKind.RevertFilesNoProgress:
|
||||
case OperationKind.CheckIgnore:
|
||||
case OperationKind.GetObjectDetails:
|
||||
case OperationKind.Show:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export interface BaseOperation {
|
||||
readonly kind: OperationKind;
|
||||
}
|
||||
|
||||
export interface CheckoutOperation extends BaseOperation {
|
||||
readonly kind: OperationKind.Checkout | OperationKind.CheckoutTracking;
|
||||
readonly refLabel: string;
|
||||
}
|
||||
|
||||
export interface Operations {
|
||||
isIdle(): boolean;
|
||||
getOperations(operationKind: OperationKind): BaseOperation[];
|
||||
shouldShowProgress(): boolean;
|
||||
isRunning(operationKind: OperationKind): boolean;
|
||||
}
|
||||
|
||||
class OperationsImpl implements Operations {
|
||||
|
||||
private operations = new Map<OperationKind, Set<BaseOperation>>();
|
||||
|
||||
constructor(private readonly logger: LogOutputChannel) { }
|
||||
|
||||
start(operation: BaseOperation): void {
|
||||
if (this.operations.has(operation.kind)) {
|
||||
this.operations.get(operation.kind)!.add(operation);
|
||||
} else {
|
||||
this.operations.set(operation.kind, new Set([operation]));
|
||||
}
|
||||
|
||||
this.logger.trace(`Operation start: ${operation.kind}`);
|
||||
}
|
||||
|
||||
end(operation: BaseOperation): void {
|
||||
const operationSet = this.operations.get(operation.kind);
|
||||
if (operationSet) {
|
||||
operationSet.delete(operation);
|
||||
if (operationSet.size === 0) {
|
||||
this.operations.delete(operation.kind);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.trace(`Operation end: ${operation.kind}`);
|
||||
}
|
||||
|
||||
getOperations(operationKind: OperationKind): BaseOperation[] {
|
||||
const operationSet = this.operations.get(operationKind);
|
||||
return operationSet ? Array.from(operationSet) : [];
|
||||
}
|
||||
|
||||
isRunning(operationKind: OperationKind): boolean {
|
||||
return this.operations.has(operationKind);
|
||||
}
|
||||
|
||||
isIdle(): boolean {
|
||||
const operations = this.operations.keys();
|
||||
|
||||
for (const operation of operations) {
|
||||
if (!isReadOnly(operation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
shouldShowProgress(): boolean {
|
||||
const operations = this.operations.keys();
|
||||
|
||||
for (const operation of operations) {
|
||||
if (shouldShowProgress(operation)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export interface GitResourceGroup extends SourceControlResourceGroup {
|
||||
resourceStates: Resource[];
|
||||
}
|
||||
@@ -481,11 +314,6 @@ interface GitResourceGroups {
|
||||
workingTreeGroup?: Resource[];
|
||||
}
|
||||
|
||||
export interface OperationResult {
|
||||
operation: OperationKind;
|
||||
error: any;
|
||||
}
|
||||
|
||||
class ProgressManager {
|
||||
|
||||
private enabled = false;
|
||||
@@ -895,8 +723,8 @@ export class Repository implements Disposable {
|
||||
return this._mergeInProgress;
|
||||
}
|
||||
|
||||
private _operations = new OperationsImpl(this.logger);
|
||||
get operations(): Operations { return this._operations; }
|
||||
private _operations = new OperationManager(this.logger);
|
||||
get operations(): OperationManager { return this._operations; }
|
||||
|
||||
private _state = RepositoryState.Idle;
|
||||
get state(): RepositoryState { return this._state; }
|
||||
@@ -1038,7 +866,7 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/vscode/issues/39039
|
||||
const onSuccessfulPush = filterEvent(this.onDidRunOperation, e => e.operation === OperationKind.Push && !e.error);
|
||||
const onSuccessfulPush = filterEvent(this.onDidRunOperation, e => e.operation.kind === OperationKind.Push && !e.error);
|
||||
onSuccessfulPush(() => {
|
||||
const gitConfig = workspace.getConfiguration('git');
|
||||
|
||||
@@ -1170,89 +998,89 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
getConfigs(): Promise<{ key: string; value: string }[]> {
|
||||
return this.run(OperationKind.Config, () => this.repository.getConfigs('local'));
|
||||
return this.run(Operation.Config, () => this.repository.getConfigs('local'));
|
||||
}
|
||||
|
||||
getConfig(key: string): Promise<string> {
|
||||
return this.run(OperationKind.Config, () => this.repository.config('local', key));
|
||||
return this.run(Operation.Config, () => this.repository.config('local', key));
|
||||
}
|
||||
|
||||
getGlobalConfig(key: string): Promise<string> {
|
||||
return this.run(OperationKind.Config, () => this.repository.config('global', key));
|
||||
return this.run(Operation.Config, () => this.repository.config('global', key));
|
||||
}
|
||||
|
||||
setConfig(key: string, value: string): Promise<string> {
|
||||
return this.run(OperationKind.Config, () => this.repository.config('local', key, value));
|
||||
return this.run(Operation.Config, () => this.repository.config('local', key, value));
|
||||
}
|
||||
|
||||
log(options?: LogOptions): Promise<Commit[]> {
|
||||
return this.run(OperationKind.Log, () => this.repository.log(options));
|
||||
return this.run(Operation.Log, () => this.repository.log(options));
|
||||
}
|
||||
|
||||
logFile(uri: Uri, options?: LogFileOptions): Promise<Commit[]> {
|
||||
// TODO: This probably needs per-uri granularity
|
||||
return this.run(OperationKind.LogFile, () => this.repository.logFile(uri, options));
|
||||
return this.run(Operation.LogFile, () => this.repository.logFile(uri, options));
|
||||
}
|
||||
|
||||
@throttle
|
||||
async status(): Promise<void> {
|
||||
await this.run(OperationKind.Status);
|
||||
await this.run(Operation.Status);
|
||||
}
|
||||
|
||||
diff(cached?: boolean): Promise<string> {
|
||||
return this.run(OperationKind.Diff, () => this.repository.diff(cached));
|
||||
return this.run(Operation.Diff, () => this.repository.diff(cached));
|
||||
}
|
||||
|
||||
diffWithHEAD(): Promise<Change[]>;
|
||||
diffWithHEAD(path: string): Promise<string>;
|
||||
diffWithHEAD(path?: string | undefined): Promise<string | Change[]>;
|
||||
diffWithHEAD(path?: string | undefined): Promise<string | Change[]> {
|
||||
return this.run(OperationKind.Diff, () => this.repository.diffWithHEAD(path));
|
||||
return this.run(Operation.Diff, () => this.repository.diffWithHEAD(path));
|
||||
}
|
||||
|
||||
diffWith(ref: string): Promise<Change[]>;
|
||||
diffWith(ref: string, path: string): Promise<string>;
|
||||
diffWith(ref: string, path?: string | undefined): Promise<string | Change[]>;
|
||||
diffWith(ref: string, path?: string): Promise<string | Change[]> {
|
||||
return this.run(OperationKind.Diff, () => this.repository.diffWith(ref, path));
|
||||
return this.run(Operation.Diff, () => this.repository.diffWith(ref, path));
|
||||
}
|
||||
|
||||
diffIndexWithHEAD(): Promise<Change[]>;
|
||||
diffIndexWithHEAD(path: string): Promise<string>;
|
||||
diffIndexWithHEAD(path?: string | undefined): Promise<string | Change[]>;
|
||||
diffIndexWithHEAD(path?: string): Promise<string | Change[]> {
|
||||
return this.run(OperationKind.Diff, () => this.repository.diffIndexWithHEAD(path));
|
||||
return this.run(Operation.Diff, () => this.repository.diffIndexWithHEAD(path));
|
||||
}
|
||||
|
||||
diffIndexWith(ref: string): Promise<Change[]>;
|
||||
diffIndexWith(ref: string, path: string): Promise<string>;
|
||||
diffIndexWith(ref: string, path?: string | undefined): Promise<string | Change[]>;
|
||||
diffIndexWith(ref: string, path?: string): Promise<string | Change[]> {
|
||||
return this.run(OperationKind.Diff, () => this.repository.diffIndexWith(ref, path));
|
||||
return this.run(Operation.Diff, () => this.repository.diffIndexWith(ref, path));
|
||||
}
|
||||
|
||||
diffBlobs(object1: string, object2: string): Promise<string> {
|
||||
return this.run(OperationKind.Diff, () => this.repository.diffBlobs(object1, object2));
|
||||
return this.run(Operation.Diff, () => this.repository.diffBlobs(object1, object2));
|
||||
}
|
||||
|
||||
diffBetween(ref1: string, ref2: string): Promise<Change[]>;
|
||||
diffBetween(ref1: string, ref2: string, path: string): Promise<string>;
|
||||
diffBetween(ref1: string, ref2: string, path?: string | undefined): Promise<string | Change[]>;
|
||||
diffBetween(ref1: string, ref2: string, path?: string): Promise<string | Change[]> {
|
||||
return this.run(OperationKind.Diff, () => this.repository.diffBetween(ref1, ref2, path));
|
||||
return this.run(Operation.Diff, () => this.repository.diffBetween(ref1, ref2, path));
|
||||
}
|
||||
|
||||
getMergeBase(ref1: string, ref2: string): Promise<string> {
|
||||
return this.run(OperationKind.MergeBase, () => this.repository.getMergeBase(ref1, ref2));
|
||||
return this.run(Operation.MergeBase, () => this.repository.getMergeBase(ref1, ref2));
|
||||
}
|
||||
|
||||
async hashObject(data: string): Promise<string> {
|
||||
return this.run(OperationKind.HashObject, () => this.repository.hashObject(data));
|
||||
return this.run(Operation.HashObject, () => this.repository.hashObject(data));
|
||||
}
|
||||
|
||||
async add(resources: Uri[], opts?: { update?: boolean }): Promise<void> {
|
||||
await this.run(
|
||||
this.optimisticUpdateEnabled() ? OperationKind.AddNoProgress : OperationKind.Add,
|
||||
Operation.Add(!this.optimisticUpdateEnabled()),
|
||||
async () => {
|
||||
await this.repository.add(resources.map(r => r.fsPath), opts);
|
||||
this.closeDiffEditors([], [...resources.map(r => r.fsPath)]);
|
||||
@@ -1289,12 +1117,12 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
async rm(resources: Uri[]): Promise<void> {
|
||||
await this.run(OperationKind.Remove, () => this.repository.rm(resources.map(r => r.fsPath)));
|
||||
await this.run(Operation.Remove, () => this.repository.rm(resources.map(r => r.fsPath)));
|
||||
}
|
||||
|
||||
async stage(resource: Uri, contents: string): Promise<void> {
|
||||
const path = relativePath(this.repository.root, resource.fsPath).replace(/\\/g, '/');
|
||||
await this.run(OperationKind.Stage, async () => {
|
||||
await this.run(Operation.Stage, async () => {
|
||||
await this.repository.stage(path, contents);
|
||||
this.closeDiffEditors([], [...resource.fsPath]);
|
||||
});
|
||||
@@ -1303,7 +1131,7 @@ export class Repository implements Disposable {
|
||||
|
||||
async revert(resources: Uri[]): Promise<void> {
|
||||
await this.run(
|
||||
this.optimisticUpdateEnabled() ? OperationKind.RevertFilesNoProgress : OperationKind.RevertFiles,
|
||||
Operation.RevertFiles(!this.optimisticUpdateEnabled()),
|
||||
async () => {
|
||||
await this.repository.revert('HEAD', resources.map(r => r.fsPath));
|
||||
this.closeDiffEditors([...resources.length !== 0 ?
|
||||
@@ -1350,7 +1178,7 @@ export class Repository implements Disposable {
|
||||
async commit(message: string | undefined, opts: CommitOptions = Object.create(null)): Promise<void> {
|
||||
if (this.rebaseCommit) {
|
||||
await this.run(
|
||||
OperationKind.RebaseContinue,
|
||||
Operation.RebaseContinue,
|
||||
async () => {
|
||||
if (opts.all) {
|
||||
const addOpts = opts.all === 'tracked' ? { update: true } : {};
|
||||
@@ -1366,7 +1194,7 @@ export class Repository implements Disposable {
|
||||
this.commitCommandCenter.postCommitCommand = opts.postCommitCommand;
|
||||
|
||||
await this.run(
|
||||
OperationKind.Commit,
|
||||
Operation.Commit,
|
||||
async () => {
|
||||
if (opts.all) {
|
||||
const addOpts = opts.all === 'tracked' ? { update: true } : {};
|
||||
@@ -1386,7 +1214,7 @@ export class Repository implements Disposable {
|
||||
() => this.commitOperationGetOptimisticResourceGroups(opts));
|
||||
|
||||
// Execute post-commit command
|
||||
await this.run(OperationKind.PostCommitCommand, async () => {
|
||||
await this.run(Operation.PostCommitCommand, async () => {
|
||||
await this.commitCommandCenter.executePostCommitCommand(opts.postCommitCommand);
|
||||
});
|
||||
}
|
||||
@@ -1420,7 +1248,7 @@ export class Repository implements Disposable {
|
||||
|
||||
async clean(resources: Uri[]): Promise<void> {
|
||||
await this.run(
|
||||
this.optimisticUpdateEnabled() ? OperationKind.CleanNoProgress : OperationKind.Clean,
|
||||
Operation.Clean(!this.optimisticUpdateEnabled()),
|
||||
async () => {
|
||||
const toClean: string[] = [];
|
||||
const toCheckout: string[] = [];
|
||||
@@ -1508,15 +1336,15 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
async branch(name: string, _checkout: boolean, _ref?: string): Promise<void> {
|
||||
await this.run(OperationKind.Branch, () => this.repository.branch(name, _checkout, _ref));
|
||||
await this.run(Operation.Branch, () => this.repository.branch(name, _checkout, _ref));
|
||||
}
|
||||
|
||||
async deleteBranch(name: string, force?: boolean): Promise<void> {
|
||||
await this.run(OperationKind.DeleteBranch, () => this.repository.deleteBranch(name, force));
|
||||
await this.run(Operation.DeleteBranch, () => this.repository.deleteBranch(name, force));
|
||||
}
|
||||
|
||||
async renameBranch(name: string): Promise<void> {
|
||||
await this.run(OperationKind.RenameBranch, () => this.repository.renameBranch(name));
|
||||
await this.run(Operation.RenameBranch, () => this.repository.renameBranch(name));
|
||||
}
|
||||
|
||||
@throttle
|
||||
@@ -1530,7 +1358,7 @@ export class Repository implements Disposable {
|
||||
try {
|
||||
// Fast-forward the branch if possible
|
||||
const options = { remote: branch.upstream.remote, ref: `${branch.upstream.name}:${branch.name}` };
|
||||
await this.run(OperationKind.Fetch, async () => this.repository.fetch(options));
|
||||
await this.run(Operation.Fetch(true), async () => this.repository.fetch(options));
|
||||
} catch (err) {
|
||||
if (err.gitErrorCode === GitErrorCodes.BranchFastForwardRejected) {
|
||||
return;
|
||||
@@ -1541,50 +1369,49 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
async cherryPick(commitHash: string): Promise<void> {
|
||||
await this.run(OperationKind.CherryPick, () => this.repository.cherryPick(commitHash));
|
||||
await this.run(Operation.CherryPick, () => this.repository.cherryPick(commitHash));
|
||||
}
|
||||
|
||||
async move(from: string, to: string): Promise<void> {
|
||||
await this.run(OperationKind.Move, () => this.repository.move(from, to));
|
||||
await this.run(Operation.Move, () => this.repository.move(from, to));
|
||||
}
|
||||
|
||||
async getBranch(name: string): Promise<Branch> {
|
||||
return await this.run(OperationKind.GetBranch, () => this.repository.getBranch(name));
|
||||
return await this.run(Operation.GetBranch, () => this.repository.getBranch(name));
|
||||
}
|
||||
|
||||
async getBranches(query: BranchQuery): Promise<Ref[]> {
|
||||
return await this.run(OperationKind.GetBranches, () => this.repository.getBranches(query));
|
||||
return await this.run(Operation.GetBranches, () => this.repository.getBranches(query));
|
||||
}
|
||||
|
||||
async setBranchUpstream(name: string, upstream: string): Promise<void> {
|
||||
await this.run(OperationKind.SetBranchUpstream, () => this.repository.setBranchUpstream(name, upstream));
|
||||
await this.run(Operation.SetBranchUpstream, () => this.repository.setBranchUpstream(name, upstream));
|
||||
}
|
||||
|
||||
async merge(ref: string): Promise<void> {
|
||||
await this.run(OperationKind.Merge, () => this.repository.merge(ref));
|
||||
await this.run(Operation.Merge, () => this.repository.merge(ref));
|
||||
}
|
||||
|
||||
async mergeAbort(): Promise<void> {
|
||||
await this.run(OperationKind.MergeAbort, async () => await this.repository.mergeAbort());
|
||||
await this.run(Operation.MergeAbort, async () => await this.repository.mergeAbort());
|
||||
}
|
||||
|
||||
async rebase(branch: string): Promise<void> {
|
||||
await this.run(OperationKind.Rebase, () => this.repository.rebase(branch));
|
||||
await this.run(Operation.Rebase, () => this.repository.rebase(branch));
|
||||
}
|
||||
|
||||
async tag(name: string, message?: string): Promise<void> {
|
||||
await this.run(OperationKind.Tag, () => this.repository.tag(name, message));
|
||||
await this.run(Operation.Tag, () => this.repository.tag(name, message));
|
||||
}
|
||||
|
||||
async deleteTag(name: string): Promise<void> {
|
||||
await this.run(OperationKind.DeleteTag, () => this.repository.deleteTag(name));
|
||||
await this.run(Operation.DeleteTag, () => this.repository.deleteTag(name));
|
||||
}
|
||||
|
||||
async checkout(treeish: string, opts?: { detached?: boolean; pullBeforeCheckout?: boolean }): Promise<void> {
|
||||
const refLabel = this.checkoutRefLabel(treeish, opts?.detached);
|
||||
const operation: CheckoutOperation = { kind: OperationKind.Checkout, refLabel };
|
||||
|
||||
await this.run(operation,
|
||||
await this.run(Operation.Checkout(refLabel),
|
||||
async () => {
|
||||
if (opts?.pullBeforeCheckout && !opts?.detached) {
|
||||
try {
|
||||
@@ -1601,13 +1428,11 @@ export class Repository implements Disposable {
|
||||
|
||||
async checkoutTracking(treeish: string, opts: { detached?: boolean } = {}): Promise<void> {
|
||||
const refLabel = this.checkoutRefLabel(treeish, opts?.detached);
|
||||
const operation: CheckoutOperation = { kind: OperationKind.CheckoutTracking, refLabel };
|
||||
|
||||
await this.run(operation, () => this.repository.checkout(treeish, [], { ...opts, track: true }));
|
||||
await this.run(Operation.CheckoutTracking(refLabel), () => this.repository.checkout(treeish, [], { ...opts, track: true }));
|
||||
}
|
||||
|
||||
async findTrackingBranches(upstreamRef: string): Promise<Branch[]> {
|
||||
return await this.run(OperationKind.FindTrackingBranches, () => this.repository.findTrackingBranches(upstreamRef));
|
||||
return await this.run(Operation.FindTrackingBranches, () => this.repository.findTrackingBranches(upstreamRef));
|
||||
}
|
||||
|
||||
async getCommit(ref: string): Promise<Commit> {
|
||||
@@ -1615,23 +1440,23 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
async reset(treeish: string, hard?: boolean): Promise<void> {
|
||||
await this.run(OperationKind.Reset, () => this.repository.reset(treeish, hard));
|
||||
await this.run(Operation.Reset, () => this.repository.reset(treeish, hard));
|
||||
}
|
||||
|
||||
async deleteRef(ref: string): Promise<void> {
|
||||
await this.run(OperationKind.DeleteRef, () => this.repository.deleteRef(ref));
|
||||
await this.run(Operation.DeleteRef, () => this.repository.deleteRef(ref));
|
||||
}
|
||||
|
||||
async addRemote(name: string, url: string): Promise<void> {
|
||||
await this.run(OperationKind.Remote, () => this.repository.addRemote(name, url));
|
||||
await this.run(Operation.Remote, () => this.repository.addRemote(name, url));
|
||||
}
|
||||
|
||||
async removeRemote(name: string): Promise<void> {
|
||||
await this.run(OperationKind.Remote, () => this.repository.removeRemote(name));
|
||||
await this.run(Operation.Remote, () => this.repository.removeRemote(name));
|
||||
}
|
||||
|
||||
async renameRemote(name: string, newName: string): Promise<void> {
|
||||
await this.run(OperationKind.Remote, () => this.repository.renameRemote(name, newName));
|
||||
await this.run(Operation.Remote, () => this.repository.renameRemote(name, newName));
|
||||
}
|
||||
|
||||
@throttle
|
||||
@@ -1660,8 +1485,7 @@ export class Repository implements Disposable {
|
||||
options.prune = prune;
|
||||
}
|
||||
|
||||
const operation = options.silent === true ? OperationKind.FetchNoProgress : OperationKind.Fetch;
|
||||
await this.run(operation, async () => this.repository.fetch(options));
|
||||
await this.run(Operation.Fetch(options.silent !== true), async () => this.repository.fetch(options));
|
||||
}
|
||||
|
||||
@throttle
|
||||
@@ -1691,7 +1515,7 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
async pullFrom(rebase?: boolean, remote?: string, branch?: string, unshallow?: boolean): Promise<void> {
|
||||
await this.run(OperationKind.Pull, async () => {
|
||||
await this.run(Operation.Pull, async () => {
|
||||
await this.maybeAutoStash(async () => {
|
||||
const config = workspace.getConfiguration('git', Uri.file(this.root));
|
||||
const fetchOnPull = config.get<boolean>('fetchOnPull');
|
||||
@@ -1735,23 +1559,23 @@ export class Repository implements Disposable {
|
||||
branch = `${head.name}:${head.upstream.name}`;
|
||||
}
|
||||
|
||||
await this.run(OperationKind.Push, () => this._push(remote, branch, undefined, undefined, forcePushMode));
|
||||
await this.run(Operation.Push, () => this._push(remote, branch, undefined, undefined, forcePushMode));
|
||||
}
|
||||
|
||||
async pushTo(remote?: string, name?: string, setUpstream = false, forcePushMode?: ForcePushMode): Promise<void> {
|
||||
await this.run(OperationKind.Push, () => this._push(remote, name, setUpstream, undefined, forcePushMode));
|
||||
await this.run(Operation.Push, () => this._push(remote, name, setUpstream, undefined, forcePushMode));
|
||||
}
|
||||
|
||||
async pushFollowTags(remote?: string, forcePushMode?: ForcePushMode): Promise<void> {
|
||||
await this.run(OperationKind.Push, () => this._push(remote, undefined, false, true, forcePushMode));
|
||||
await this.run(Operation.Push, () => this._push(remote, undefined, false, true, forcePushMode));
|
||||
}
|
||||
|
||||
async pushTags(remote?: string, forcePushMode?: ForcePushMode): Promise<void> {
|
||||
await this.run(OperationKind.Push, () => this._push(remote, undefined, false, false, forcePushMode, true));
|
||||
await this.run(Operation.Push, () => this._push(remote, undefined, false, false, forcePushMode, true));
|
||||
}
|
||||
|
||||
async blame(path: string): Promise<string> {
|
||||
return await this.run(OperationKind.Blame, () => this.repository.blame(path));
|
||||
return await this.run(Operation.Blame, () => this.repository.blame(path));
|
||||
}
|
||||
|
||||
@throttle
|
||||
@@ -1770,7 +1594,7 @@ export class Repository implements Disposable {
|
||||
pushBranch = `${head.name}:${head.upstream.name}`;
|
||||
}
|
||||
|
||||
await this.run(OperationKind.Sync, async () => {
|
||||
await this.run(Operation.Sync, async () => {
|
||||
await this.maybeAutoStash(async () => {
|
||||
const config = workspace.getConfiguration('git', Uri.file(this.root));
|
||||
const fetchOnPull = config.get<boolean>('fetchOnPull');
|
||||
@@ -1824,7 +1648,7 @@ export class Repository implements Disposable {
|
||||
return true;
|
||||
}
|
||||
|
||||
const maybeRebased = await this.run(OperationKind.Log, async () => {
|
||||
const maybeRebased = await this.run(Operation.Log, async () => {
|
||||
try {
|
||||
const result = await this.repository.exec(['log', '--oneline', '--cherry', `${currentBranch ?? ''}...${currentBranch ?? ''}@{upstream}`, '--']);
|
||||
if (result.exitCode) {
|
||||
@@ -1865,7 +1689,7 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
async show(ref: string, filePath: string): Promise<string> {
|
||||
return await this.run(OperationKind.Show, async () => {
|
||||
return await this.run(Operation.Show, async () => {
|
||||
const path = relativePath(this.repository.root, filePath).replace(/\\/g, '/');
|
||||
const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
|
||||
const defaultEncoding = configFiles.get<string>('encoding');
|
||||
@@ -1885,22 +1709,22 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
async buffer(ref: string, filePath: string): Promise<Buffer> {
|
||||
return this.run(OperationKind.Show, () => {
|
||||
return this.run(Operation.Show, () => {
|
||||
const path = relativePath(this.repository.root, filePath).replace(/\\/g, '/');
|
||||
return this.repository.buffer(`${ref}:${path}`);
|
||||
});
|
||||
}
|
||||
|
||||
getObjectDetails(ref: string, filePath: string): Promise<{ mode: string; object: string; size: number }> {
|
||||
return this.run(OperationKind.GetObjectDetails, () => this.repository.getObjectDetails(ref, filePath));
|
||||
return this.run(Operation.GetObjectDetails, () => this.repository.getObjectDetails(ref, filePath));
|
||||
}
|
||||
|
||||
detectObjectType(object: string): Promise<{ mimetype: string; encoding?: string }> {
|
||||
return this.run(OperationKind.Show, () => this.repository.detectObjectType(object));
|
||||
return this.run(Operation.Show, () => this.repository.detectObjectType(object));
|
||||
}
|
||||
|
||||
async apply(patch: string, reverse?: boolean): Promise<void> {
|
||||
return await this.run(OperationKind.Apply, () => this.repository.apply(patch, reverse));
|
||||
return await this.run(Operation.Apply, () => this.repository.apply(patch, reverse));
|
||||
}
|
||||
|
||||
async getStashes(): Promise<Stash[]> {
|
||||
@@ -1913,30 +1737,30 @@ export class Repository implements Disposable {
|
||||
...!staged ? this.workingTreeGroup.resourceStates.map(r => r.resourceUri.fsPath) : [],
|
||||
...includeUntracked ? this.untrackedGroup.resourceStates.map(r => r.resourceUri.fsPath) : []];
|
||||
|
||||
return await this.run(OperationKind.Stash, async () => {
|
||||
return await this.run(Operation.Stash, async () => {
|
||||
await this.repository.createStash(message, includeUntracked, staged);
|
||||
this.closeDiffEditors(indexResources, workingGroupResources);
|
||||
});
|
||||
}
|
||||
|
||||
async popStash(index?: number): Promise<void> {
|
||||
return await this.run(OperationKind.Stash, () => this.repository.popStash(index));
|
||||
return await this.run(Operation.Stash, () => this.repository.popStash(index));
|
||||
}
|
||||
|
||||
async dropStash(index?: number): Promise<void> {
|
||||
return await this.run(OperationKind.Stash, () => this.repository.dropStash(index));
|
||||
return await this.run(Operation.Stash, () => this.repository.dropStash(index));
|
||||
}
|
||||
|
||||
async applyStash(index?: number): Promise<void> {
|
||||
return await this.run(OperationKind.Stash, () => this.repository.applyStash(index));
|
||||
return await this.run(Operation.Stash, () => this.repository.applyStash(index));
|
||||
}
|
||||
|
||||
async getCommitTemplate(): Promise<string> {
|
||||
return await this.run(OperationKind.GetCommitTemplate, async () => this.repository.getCommitTemplate());
|
||||
return await this.run(Operation.GetCommitTemplate, async () => this.repository.getCommitTemplate());
|
||||
}
|
||||
|
||||
async ignore(files: Uri[]): Promise<void> {
|
||||
return await this.run(OperationKind.Ignore, async () => {
|
||||
return await this.run(Operation.Ignore, async () => {
|
||||
const ignoreFile = `${this.repository.root}${path.sep}.gitignore`;
|
||||
const textToAppend = files
|
||||
.map(uri => relativePath(this.repository.root, uri.fsPath).replace(/\\/g, '/'))
|
||||
@@ -1959,11 +1783,11 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
async rebaseAbort(): Promise<void> {
|
||||
await this.run(OperationKind.RebaseAbort, async () => await this.repository.rebaseAbort());
|
||||
await this.run(Operation.RebaseAbort, async () => await this.repository.rebaseAbort());
|
||||
}
|
||||
|
||||
checkIgnore(filePaths: string[]): Promise<Set<string>> {
|
||||
return this.run(OperationKind.CheckIgnore, () => {
|
||||
return this.run(Operation.CheckIgnore, () => {
|
||||
return new Promise<Set<string>>((resolve, reject) => {
|
||||
|
||||
filePaths = filePaths
|
||||
@@ -2054,16 +1878,9 @@ export class Repository implements Disposable {
|
||||
}
|
||||
|
||||
private async run<T>(
|
||||
operation: OperationKind | BaseOperation,
|
||||
operation: Operation,
|
||||
runOperation: () => Promise<T> = () => Promise.resolve<any>(null),
|
||||
getOptimisticResourceGroups: () => GitResourceGroups | undefined = () => undefined): Promise<T> {
|
||||
return this._run<T>(typeof operation === 'object' ? operation : { kind: operation }, runOperation, getOptimisticResourceGroups);
|
||||
}
|
||||
|
||||
private async _run<T>(
|
||||
operation: BaseOperation,
|
||||
runOperation: () => Promise<T>,
|
||||
getOptimisticResourceGroups: () => GitResourceGroups | undefined): Promise<T> {
|
||||
|
||||
if (this.state !== RepositoryState.Idle) {
|
||||
throw new Error('Repository not initialized');
|
||||
@@ -2075,9 +1892,9 @@ export class Repository implements Disposable {
|
||||
this._onRunOperation.fire(operation.kind);
|
||||
|
||||
try {
|
||||
const result = await this._retryRun(operation.kind, runOperation);
|
||||
const result = await this.retryRun(operation, runOperation);
|
||||
|
||||
if (!isReadOnly(operation.kind)) {
|
||||
if (!operation.readOnly) {
|
||||
await this.updateModelState(this.optimisticUpdateEnabled() ? getOptimisticResourceGroups() : undefined);
|
||||
}
|
||||
|
||||
@@ -2092,11 +1909,11 @@ export class Repository implements Disposable {
|
||||
throw err;
|
||||
} finally {
|
||||
this._operations.end(operation);
|
||||
this._onDidRunOperation.fire({ operation: operation.kind, error });
|
||||
this._onDidRunOperation.fire({ operation: operation, error });
|
||||
}
|
||||
}
|
||||
|
||||
private async _retryRun<T>(operation: OperationKind, runOperation: () => Promise<T> = () => Promise.resolve<any>(null)): Promise<T> {
|
||||
private async retryRun<T>(operation: Operation, runOperation: () => Promise<T> = () => Promise.resolve<any>(null)): Promise<T> {
|
||||
let attempt = 0;
|
||||
|
||||
while (true) {
|
||||
@@ -2106,7 +1923,7 @@ export class Repository implements Disposable {
|
||||
} catch (err) {
|
||||
const shouldRetry = attempt <= 10 && (
|
||||
(err.gitErrorCode === GitErrorCodes.RepositoryIsLocked)
|
||||
|| ((operation === OperationKind.Pull || operation === OperationKind.Sync || operation === OperationKind.Fetch) && (err.gitErrorCode === GitErrorCodes.CantLockRef || err.gitErrorCode === GitErrorCodes.CantRebaseMultipleBranches))
|
||||
|| (operation.retry && (err.gitErrorCode === GitErrorCodes.CantLockRef || err.gitErrorCode === GitErrorCodes.CantRebaseMultipleBranches))
|
||||
);
|
||||
|
||||
if (shouldRetry) {
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, Command, EventEmitter, Event, workspace, Uri, l10n } from 'vscode';
|
||||
import { Repository, OperationKind, CheckoutOperation } from './repository';
|
||||
import { Repository } from './repository';
|
||||
import { anyEvent, dispose, filterEvent } from './util';
|
||||
import { Branch, RefType, RemoteSourcePublisher } from './api/git';
|
||||
import { IRemoteSourcePublisherRegistry } from './remotePublisher';
|
||||
import { CheckoutOperation, CheckoutTrackingOperation, OperationKind } from './operation';
|
||||
|
||||
interface CheckoutStatusBarState {
|
||||
readonly isCheckoutRunning: boolean;
|
||||
@@ -42,7 +43,7 @@ class CheckoutStatusBar {
|
||||
get command(): Command | undefined {
|
||||
const operationData = [
|
||||
...this.repository.operations.getOperations(OperationKind.Checkout) as CheckoutOperation[],
|
||||
...this.repository.operations.getOperations(OperationKind.CheckoutTracking) as CheckoutOperation[]
|
||||
...this.repository.operations.getOperations(OperationKind.CheckoutTracking) as CheckoutTrackingOperation[]
|
||||
];
|
||||
|
||||
const rebasing = !!this.repository.rebaseCommit;
|
||||
|
||||
Reference in New Issue
Block a user