Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/git/src/autofetch.ts
3316 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 { workspace, Disposable, EventEmitter, Memento, window, MessageItem, ConfigurationTarget, Uri, ConfigurationChangeEvent, l10n, env } from 'vscode';
7
import { Repository } from './repository';
8
import { eventToPromise, filterEvent, onceEvent } from './util';
9
import { GitErrorCodes } from './api/git';
10
11
export class AutoFetcher {
12
13
private static DidInformUser = 'autofetch.didInformUser';
14
15
private _onDidChange = new EventEmitter<boolean>();
16
private onDidChange = this._onDidChange.event;
17
18
private _enabled: boolean = false;
19
private _fetchAll: boolean = false;
20
get enabled(): boolean { return this._enabled; }
21
set enabled(enabled: boolean) { this._enabled = enabled; this._onDidChange.fire(enabled); }
22
23
private disposables: Disposable[] = [];
24
25
constructor(private repository: Repository, private globalState: Memento) {
26
workspace.onDidChangeConfiguration(this.onConfiguration, this, this.disposables);
27
this.onConfiguration();
28
29
const onGoodRemoteOperation = filterEvent(repository.onDidRunOperation, ({ operation, error }) => !error && operation.remote);
30
const onFirstGoodRemoteOperation = onceEvent(onGoodRemoteOperation);
31
onFirstGoodRemoteOperation(this.onFirstGoodRemoteOperation, this, this.disposables);
32
}
33
34
private async onFirstGoodRemoteOperation(): Promise<void> {
35
const didInformUser = !this.globalState.get<boolean>(AutoFetcher.DidInformUser);
36
37
if (this.enabled && !didInformUser) {
38
this.globalState.update(AutoFetcher.DidInformUser, true);
39
}
40
41
const shouldInformUser = !this.enabled && didInformUser;
42
43
if (!shouldInformUser) {
44
return;
45
}
46
47
const yes: MessageItem = { title: l10n.t('Yes') };
48
const no: MessageItem = { isCloseAffordance: true, title: l10n.t('No') };
49
const askLater: MessageItem = { title: l10n.t('Ask Me Later') };
50
const result = await window.showInformationMessage(l10n.t('Would you like {0} to [periodically run "git fetch"]({1})?', env.appName, 'https://go.microsoft.com/fwlink/?linkid=865294'), yes, no, askLater);
51
52
if (result === askLater) {
53
return;
54
}
55
56
if (result === yes) {
57
const gitConfig = workspace.getConfiguration('git', Uri.file(this.repository.root));
58
gitConfig.update('autofetch', true, ConfigurationTarget.Global);
59
}
60
61
this.globalState.update(AutoFetcher.DidInformUser, true);
62
}
63
64
private onConfiguration(e?: ConfigurationChangeEvent): void {
65
if (e !== undefined && !e.affectsConfiguration('git.autofetch')) {
66
return;
67
}
68
69
const gitConfig = workspace.getConfiguration('git', Uri.file(this.repository.root));
70
switch (gitConfig.get<boolean | 'all'>('autofetch')) {
71
case true:
72
this._fetchAll = false;
73
this.enable();
74
break;
75
case 'all':
76
this._fetchAll = true;
77
this.enable();
78
break;
79
case false:
80
default:
81
this._fetchAll = false;
82
this.disable();
83
break;
84
}
85
}
86
87
enable(): void {
88
if (this.enabled) {
89
return;
90
}
91
92
this.enabled = true;
93
this.run();
94
}
95
96
disable(): void {
97
this.enabled = false;
98
}
99
100
private async run(): Promise<void> {
101
while (this.enabled) {
102
await this.repository.whenIdleAndFocused();
103
104
if (!this.enabled) {
105
return;
106
}
107
108
try {
109
if (this._fetchAll) {
110
await this.repository.fetchAll({ silent: true });
111
} else {
112
await this.repository.fetchDefault({ silent: true });
113
}
114
} catch (err) {
115
if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) {
116
this.disable();
117
}
118
}
119
120
if (!this.enabled) {
121
return;
122
}
123
124
const period = workspace.getConfiguration('git', Uri.file(this.repository.root)).get<number>('autofetchPeriod', 180) * 1000;
125
const timeout = new Promise(c => setTimeout(c, period));
126
const whenDisabled = eventToPromise(filterEvent(this.onDidChange, enabled => !enabled));
127
128
await Promise.race([timeout, whenDisabled]);
129
}
130
}
131
132
dispose(): void {
133
this.disable();
134
this.disposables.forEach(d => d.dispose());
135
}
136
}
137
138