Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/browser/mainThreadGitExtensionService.ts
13397 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Sequencer } from '../../../base/common/async.js'; import { CancellationToken } from '../../../base/common/cancellation.js';
7
import { Disposable } from '../../../base/common/lifecycle.js';
8
import { ResourceMap } from '../../../base/common/map.js';
9
import { waitForState } from '../../../base/common/observable.js';
10
import { URI } from '../../../base/common/uri.js';
11
import { GitRepository } from '../../contrib/git/browser/gitService.js';
12
import { IGitExtensionDelegate, IGitService, GitRef, GitRefQuery, GitRefType, GitRepositoryState, GitBranch, GitChange, GitDiffChange, IGitRepository } from '../../contrib/git/common/gitService.js';
13
import { extHostNamedCustomer, IExtHostContext } from '../../services/extensions/common/extHostCustomers.js';
14
import { ExtHostContext, ExtHostGitExtensionShape, GitDiffChangeDto, GitRefTypeDto, GitRepositoryStateDto, MainContext, MainThreadGitExtensionShape } from '../common/extHost.protocol.js';
15
16
function toGitRefType(type: GitRefTypeDto): GitRefType {
17
switch (type) {
18
case GitRefTypeDto.Head: return GitRefType.Head;
19
case GitRefTypeDto.RemoteHead: return GitRefType.RemoteHead;
20
case GitRefTypeDto.Tag: return GitRefType.Tag;
21
default: throw new Error(`Unknown GitRefType: ${type}`);
22
}
23
}
24
25
function toGitDiffChange(dto: GitDiffChangeDto): GitDiffChange {
26
return {
27
uri: URI.revive(dto.uri),
28
originalUri: dto.originalUri ? URI.revive(dto.originalUri) : undefined,
29
modifiedUri: dto.modifiedUri ? URI.revive(dto.modifiedUri) : undefined,
30
insertions: dto.insertions,
31
deletions: dto.deletions,
32
};
33
}
34
35
function toGitRepositoryState(dto: GitRepositoryStateDto | undefined): GitRepositoryState {
36
return {
37
HEAD: dto?.HEAD ? {
38
type: toGitRefType(dto.HEAD.type),
39
name: dto.HEAD.name,
40
commit: dto.HEAD.commit,
41
remote: dto.HEAD.remote,
42
upstream: dto.HEAD.upstream,
43
ahead: dto.HEAD.ahead,
44
behind: dto.HEAD.behind,
45
} satisfies GitBranch : undefined,
46
remotes: dto?.remotes ?? [],
47
mergeChanges: dto?.mergeChanges?.map(c => ({
48
uri: URI.revive(c.uri),
49
originalUri: c.originalUri ? URI.revive(c.originalUri) : undefined,
50
modifiedUri: c.modifiedUri ? URI.revive(c.modifiedUri) : undefined,
51
} satisfies GitChange)) ?? [],
52
indexChanges: dto?.indexChanges?.map(c => ({
53
uri: URI.revive(c.uri),
54
originalUri: c.originalUri ? URI.revive(c.originalUri) : undefined,
55
modifiedUri: c.modifiedUri ? URI.revive(c.modifiedUri) : undefined,
56
} satisfies GitChange)) ?? [],
57
workingTreeChanges: dto?.workingTreeChanges?.map(c => ({
58
uri: URI.revive(c.uri),
59
originalUri: c.originalUri ? URI.revive(c.originalUri) : undefined,
60
modifiedUri: c.modifiedUri ? URI.revive(c.modifiedUri) : undefined,
61
} satisfies GitChange)) ?? [],
62
untrackedChanges: dto?.untrackedChanges?.map(c => ({
63
uri: URI.revive(c.uri),
64
originalUri: c.originalUri ? URI.revive(c.originalUri) : undefined,
65
modifiedUri: c.modifiedUri ? URI.revive(c.modifiedUri) : undefined,
66
} satisfies GitChange)) ?? [],
67
};
68
}
69
70
@extHostNamedCustomer(MainContext.MainThreadGitExtension)
71
export class MainThreadGitExtensionService extends Disposable implements MainThreadGitExtensionShape, IGitExtensionDelegate {
72
private readonly _proxy: ExtHostGitExtensionShape;
73
private readonly _openRepositorySequencer = new Sequencer();
74
75
private _repositoryHandles = new ResourceMap<number>();
76
private _repositories = new Map<number, IGitRepository>();
77
78
get repositories(): Iterable<IGitRepository> {
79
return this._repositories.values();
80
}
81
82
constructor(
83
extHostContext: IExtHostContext,
84
@IGitService private readonly gitService: IGitService
85
) {
86
super();
87
88
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostGitExtension);
89
this._initializeDelegate();
90
}
91
92
private async _initializeDelegate(): Promise<void> {
93
// Check whether the vscode.git extension is available in the extension host
94
// process before setting the delegate. The delegate should only be set once,
95
// for the extension host process that runs the vscode.git extension
96
const isExtensionAvailable = await this._proxy.$isGitExtensionAvailable();
97
98
if (isExtensionAvailable && !this._store.isDisposed) {
99
this._register(this.gitService.setDelegate(this));
100
}
101
}
102
103
async openRepository(uri: URI): Promise<IGitRepository | undefined> {
104
return this._openRepositorySequencer.queue(async () => {
105
// Open the repository
106
const result = await this._proxy.$openRepository(uri);
107
if (!result) {
108
return undefined;
109
}
110
111
const repositoryRootUri = URI.revive(result.rootUri);
112
113
// Create a new repository and store it in the maps
114
const state = toGitRepositoryState(result.state);
115
const repository = new GitRepository(repositoryRootUri, state, this);
116
117
this._repositories.set(result.handle, repository);
118
this._repositoryHandles.set(repositoryRootUri, result.handle);
119
120
// Wait for the repository to be fully initialized before returning it
121
await waitForState(repository.state, state => state.HEAD !== undefined);
122
123
return repository;
124
});
125
}
126
127
async getRefs(root: URI, query: GitRefQuery, token?: CancellationToken): Promise<GitRef[]> {
128
const handle = this._repositoryHandles.get(root);
129
if (handle === undefined) {
130
return [];
131
}
132
133
const result = await this._proxy.$getRefs(handle, query, token);
134
135
if (token?.isCancellationRequested) {
136
return [];
137
}
138
139
return result.map(ref => ({
140
...ref,
141
type: toGitRefType(ref.type)
142
} satisfies GitRef));
143
}
144
145
async diffBetweenWithStats(root: URI, ref1: string, ref2: string, path?: string): Promise<GitDiffChange[]> {
146
const handle = this._repositoryHandles.get(root);
147
if (handle === undefined) {
148
return [];
149
}
150
151
const result = await this._proxy.$diffBetweenWithStats(handle, ref1, ref2, path);
152
return result.map(toGitDiffChange);
153
}
154
155
async diffBetweenWithStats2(root: URI, ref: string, path?: string): Promise<GitDiffChange[]> {
156
const handle = this._repositoryHandles.get(root);
157
if (handle === undefined) {
158
return [];
159
}
160
161
const result = await this._proxy.$diffBetweenWithStats2(handle, ref, path);
162
return result.map(toGitDiffChange);
163
}
164
165
async $onDidChangeRepository(handle: number): Promise<void> {
166
const repository = this._repositories.get(handle);
167
if (!repository) {
168
return;
169
}
170
171
const state = await this._proxy.$getRepositoryState(handle);
172
if (!state) {
173
return;
174
}
175
176
// Update the repository state
177
repository.updateState(toGitRepositoryState(state));
178
}
179
}
180
181