Skip to content

Commit d485071

Browse files
committed
Changes Git index handling with disposable pattern
1 parent 0e0c1c9 commit d485071

File tree

4 files changed

+92
-45
lines changed

4 files changed

+92
-45
lines changed

src/env/node/git/sub-providers/patch.ts

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { promises as fs } from 'fs';
2-
import { tmpdir } from 'os';
31
import { window } from 'vscode';
42
import type { Container } from '../../../../container';
53
import { CancellationError } from '../../../../errors';
@@ -17,7 +15,6 @@ import type { GitCommit } from '../../../../git/models/commit';
1715
import { log } from '../../../../system/decorators/log';
1816
import { Logger } from '../../../../system/logger';
1917
import { getLogScope } from '../../../../system/logger.scope';
20-
import { joinPaths } from '../../../../system/path';
2118
import type { Git } from '../git';
2219
import type { LocalGitProvider } from '../localGitProvider';
2320

@@ -175,40 +172,10 @@ export class PatchGitSubProvider implements GitPatchSubProvider {
175172
}
176173

177174
// Create a temporary index file
178-
const tempDir = await fs.mkdtemp(joinPaths(tmpdir(), 'gl-'));
179-
const tempIndex = joinPaths(tempDir, 'index');
175+
await using disposableIndex = await this.provider.staging!.createTemporaryIndex(repoPath, baseRef);
176+
const { env } = disposableIndex;
180177

181178
try {
182-
// Tell Git to use our soon to be created index file
183-
const env = { GIT_INDEX_FILE: tempIndex };
184-
185-
// Create the temp index file from a base ref/sha
186-
187-
// Get the tree of the base
188-
const newIndex = await this.git.exec<string>(
189-
{
190-
cwd: repoPath,
191-
env: env,
192-
},
193-
'ls-tree',
194-
'-z',
195-
'-r',
196-
'--full-name',
197-
baseRef,
198-
);
199-
200-
// Write the tree to our temp index
201-
await this.git.exec<string>(
202-
{
203-
cwd: repoPath,
204-
env: env,
205-
stdin: newIndex,
206-
},
207-
'update-index',
208-
'-z',
209-
'--index-info',
210-
);
211-
212179
// Apply the patch to our temp index, without touching the working directory
213180
await this.git.apply2(repoPath, { env: env, stdin: contents }, '--cached');
214181

@@ -245,13 +212,6 @@ export class PatchGitSubProvider implements GitPatchSubProvider {
245212
debugger;
246213

247214
throw ex;
248-
} finally {
249-
// Delete the temporary index file
250-
try {
251-
await fs.rm(tempDir, { recursive: true });
252-
} catch (_ex) {
253-
debugger;
254-
}
255215
}
256216
}
257217

src/env/node/git/sub-providers/staging.ts

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
import { promises as fs } from 'fs';
2+
import { tmpdir } from 'os';
13
import type { Uri } from 'vscode';
24
import type { Container } from '../../../../container';
3-
import type { GitStagingSubProvider } from '../../../../git/gitProvider';
5+
import type { DisposableTemporaryGitIndex, GitStagingSubProvider } from '../../../../git/gitProvider';
46
import { splitPath } from '../../../../system/-webview/path';
57
import { log } from '../../../../system/decorators/log';
8+
import { Logger } from '../../../../system/logger';
9+
import { joinPaths } from '../../../../system/path';
10+
import { mixinAsyncDisposable } from '../../../../system/unifiedDisposable';
11+
import { scope } from '../../../../webviews/commitDetails/protocol';
612
import type { Git } from '../git';
713

814
export class StagingGitSubProvider implements GitStagingSubProvider {
@@ -11,6 +17,68 @@ export class StagingGitSubProvider implements GitStagingSubProvider {
1117
private readonly git: Git,
1218
) {}
1319

20+
@log()
21+
async createTemporaryIndex(repoPath: string, baseRef: string): Promise<DisposableTemporaryGitIndex> {
22+
// Create a temporary index file
23+
const tempDir = await fs.mkdtemp(joinPaths(tmpdir(), 'gl-'));
24+
const tempIndex = joinPaths(tempDir, 'index');
25+
26+
async function dispose() {
27+
// Delete the temporary index file
28+
try {
29+
await fs.rm(tempDir, { recursive: true });
30+
} catch (_ex) {
31+
debugger;
32+
}
33+
}
34+
35+
try {
36+
// Tell Git to use our soon to be created index file
37+
const env = { GIT_INDEX_FILE: tempIndex };
38+
39+
// Create the temp index file from a base ref/sha
40+
41+
// Get the tree of the base
42+
const newIndex = await this.git.exec<string>(
43+
{
44+
cwd: repoPath,
45+
env: env,
46+
},
47+
'ls-tree',
48+
'-z',
49+
'-r',
50+
'--full-name',
51+
baseRef,
52+
);
53+
54+
// Write the tree to our temp index
55+
await this.git.exec<string>(
56+
{
57+
cwd: repoPath,
58+
env: env,
59+
stdin: newIndex,
60+
},
61+
'update-index',
62+
'-z',
63+
'--index-info',
64+
);
65+
66+
return mixinAsyncDisposable(
67+
{
68+
path: tempIndex,
69+
env: { GIT_INDEX_FILE: tempIndex },
70+
},
71+
dispose,
72+
);
73+
} catch (ex) {
74+
Logger.error(ex, scope);
75+
debugger;
76+
77+
void dispose();
78+
throw ex;
79+
}
80+
}
81+
1482
@log()
1583
async stageFile(repoPath: string, pathOrUri: string | Uri, options?: { intentToAdd?: boolean }): Promise<void> {
1684
await this.git.add(

src/git/gitProvider.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { GitConfigKeys } from '../constants';
55
import type { SearchQuery } from '../constants.search';
66
import type { Features } from '../features';
77
import type { HostingIntegration } from '../plus/integrations/integration';
8+
import type { UnifiedAsyncDisposable } from '../system/unifiedDisposable';
89
import type { GitUri } from './gitUri';
910
import type { GitBlame, GitBlameLine } from './models/blame';
1011
import type { GitBranch } from './models/branch';
@@ -521,7 +522,13 @@ export interface GitRemotesSubProvider {
521522
setRemoteAsDefault(repoPath: string, name: string, value?: boolean): Promise<void>;
522523
}
523524

525+
export interface DisposableTemporaryGitIndex extends UnifiedAsyncDisposable {
526+
path: string;
527+
env: { GIT_INDEX_FILE: string };
528+
}
529+
524530
export interface GitStagingSubProvider {
531+
createTemporaryIndex(repoPath: string, baseRef: string): Promise<DisposableTemporaryGitIndex>;
525532
stageFile(repoPath: string, pathOrUri: string | Uri, options?: { intentToAdd?: boolean }): Promise<void>;
526533
stageFiles(repoPath: string, pathOrUri: string[] | Uri[], options?: { intentToAdd?: boolean }): Promise<void>;
527534
stageDirectory(repoPath: string, directoryOrUri: string | Uri, options?: { intentToAdd?: boolean }): Promise<void>;

src/system/unifiedDisposable.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ export function createAsyncDisposable(
2828
};
2929
}
3030

31-
export function mixinDisposable<T extends object>(obj: T, dispose: () => void): T & UnifiedDisposable {
32-
return { ...obj, ...createDisposable(dispose) };
31+
export function mixinDisposable<T extends object>(
32+
obj: T,
33+
dispose: () => void,
34+
options?: { once?: boolean },
35+
): T & UnifiedDisposable {
36+
return { ...obj, ...createDisposable(dispose, options) };
37+
}
38+
39+
export function mixinAsyncDisposable<T extends object>(
40+
obj: T,
41+
dispose: () => Promise<any>,
42+
options?: { once?: boolean },
43+
): T & UnifiedAsyncDisposable {
44+
return { ...obj, ...createAsyncDisposable(dispose, options) };
3345
}

0 commit comments

Comments
 (0)