Skip to content

Commit e9e726f

Browse files
committed
handle conflicts outside synchroniser
1 parent 2d6ab9c commit e9e726f

4 files changed

Lines changed: 37 additions & 45 deletions

File tree

src/vs/platform/userDataSync/common/userDataSync.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,13 @@ export const SETTINGS_PREVIEW_RESOURCE = URI.file('Settings-Preview').with({ sch
9191

9292
export interface ISynchroniser {
9393

94+
readonly conflicts: URI | null;
9495
readonly status: SyncStatus;
9596
readonly onDidChangeStatus: Event<SyncStatus>;
96-
9797
readonly onDidChangeLocal: Event<void>;
9898

9999
sync(): Promise<boolean>;
100100
continueSync(): Promise<boolean>;
101-
handleConflicts(): boolean;
102101
}
103102

104103
export const IUserDataSyncService = createDecorator<IUserDataSyncService>('IUserDataSyncService');

src/vs/workbench/contrib/userData/browser/userData.contribution.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { ResourceContextKey } from 'vs/workbench/common/resources';
2424
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
2525
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
2626
import { Event } from 'vs/base/common/event';
27+
import { IHistoryService } from 'vs/workbench/services/history/common/history';
2728

2829
const CONTEXT_SYNC_STATE = new RawContextKey<string>('syncStatus', SyncStatus.Uninitialized);
2930

@@ -93,6 +94,7 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi
9394
@IConfigurationService private readonly configurationService: IConfigurationService,
9495
@IEditorService private readonly editorService: IEditorService,
9596
@ITextFileService private readonly textFileService: ITextFileService,
97+
@IHistoryService private readonly historyService: IHistoryService,
9698
) {
9799
super();
98100
this.syncEnablementContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService);
@@ -126,7 +128,7 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi
126128
[
127129
{
128130
label: localize('resolve', "Resolve Conflicts"),
129-
run: () => this.userDataSyncService.handleConflicts()
131+
run: () => this.handleConflicts()
130132
}
131133
]);
132134
this.conflictsWarningDisposable.value = toDisposable(() => handle.close());
@@ -160,6 +162,22 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi
160162
}
161163
}
162164

165+
private async handleConflicts(): Promise<void> {
166+
const resource = this.userDataSyncService.conflicts;
167+
if (resource) {
168+
const resourceInput = {
169+
resource,
170+
options: {
171+
preserveFocus: false,
172+
pinned: false,
173+
revealIfVisible: true,
174+
},
175+
mode: 'jsonc'
176+
};
177+
this.editorService.openEditor(resourceInput).then(() => this.historyService.remove(resourceInput));
178+
}
179+
}
180+
163181
private registerActions(): void {
164182

165183
const startSyncMenuItem: IMenuItem = {
@@ -194,7 +212,7 @@ class SyncActionsContribution extends Disposable implements IWorkbenchContributi
194212
},
195213
when: CONTEXT_SYNC_STATE.isEqualTo(SyncStatus.HasConflicts),
196214
};
197-
CommandsRegistry.registerCommand(resolveConflictsMenuItem.command.id, serviceAccessor => serviceAccessor.get(IUserDataSyncService).handleConflicts());
215+
CommandsRegistry.registerCommand(resolveConflictsMenuItem.command.id, () => this.handleConflicts());
198216
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, resolveConflictsMenuItem);
199217
MenuRegistry.appendMenuItem(MenuId.CommandPalette, resolveConflictsMenuItem);
200218

src/vs/workbench/services/userData/common/settingsSync.ts

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@
66
import { Disposable } from 'vs/base/common/lifecycle';
77
import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files';
88
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
9-
import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, SETTINGS_PREVIEW_RESOURCE, ISettingsMergeService, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync';
9+
import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, SETTINGS_PREVIEW_RESOURCE } from 'vs/platform/userDataSync/common/userDataSync';
1010
import { VSBuffer } from 'vs/base/common/buffer';
1111
import { parse, ParseError } from 'vs/base/common/json';
12-
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
1312
import { localize } from 'vs/nls';
1413
import { Emitter, Event } from 'vs/base/common/event';
1514
import { ILogService } from 'vs/platform/log/common/log';
16-
import { IHistoryService } from 'vs/workbench/services/history/common/history';
1715
import { CancelablePromise, createCancelablePromise, ThrottledDelayer } from 'vs/base/common/async';
1816
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
17+
import { URI } from 'vs/base/common/uri';
1918

2019
interface ISyncPreviewResult {
2120
readonly fileContent: IFileContent | null;
@@ -41,15 +40,15 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
4140
private _onDidChangeLocal: Emitter<void> = this._register(new Emitter<void>());
4241
readonly onDidChangeLocal: Event<void> = this._onDidChangeLocal.event;
4342

43+
readonly conflicts: URI = SETTINGS_PREVIEW_RESOURCE;
44+
4445
constructor(
4546
@IFileService private readonly fileService: IFileService,
4647
@IEnvironmentService private readonly environmentService: IEnvironmentService,
4748
@IStorageService private readonly storageService: IStorageService,
4849
@IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
49-
@IEditorService private readonly editorService: IEditorService,
5050
@ISettingsMergeService private readonly settingsMergeService: ISettingsMergeService,
5151
@ILogService private readonly logService: ILogService,
52-
@IHistoryService private readonly historyService: IHistoryService,
5352
) {
5453
super();
5554
this.throttledDelayer = this._register(new ThrottledDelayer<void>(500));
@@ -111,24 +110,6 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
111110
}
112111
}
113112

114-
handleConflicts(): boolean {
115-
if (this.status !== SyncStatus.HasConflicts) {
116-
return false;
117-
}
118-
const resourceInput = {
119-
resource: SETTINGS_PREVIEW_RESOURCE,
120-
label: localize('Settings Conflicts', "Local ↔ Remote (Settings Conflicts)"),
121-
options: {
122-
preserveFocus: false,
123-
pinned: false,
124-
revealIfVisible: true,
125-
},
126-
mode: 'jsonc'
127-
};
128-
this.editorService.openEditor(resourceInput).then(() => this.historyService.remove(resourceInput));
129-
return true;
130-
}
131-
132113
async continueSync(): Promise<boolean> {
133114
if (this.status !== SyncStatus.HasConflicts) {
134115
return false;
@@ -142,8 +123,8 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
142123
return;
143124
}
144125

145-
if (await this.fileService.exists(SETTINGS_PREVIEW_RESOURCE)) {
146-
const settingsPreivew = await this.fileService.readFile(SETTINGS_PREVIEW_RESOURCE);
126+
if (await this.fileService.exists(this.conflicts)) {
127+
const settingsPreivew = await this.fileService.readFile(this.conflicts);
147128
const content = settingsPreivew.value.toString();
148129
if (this.hasErrors(content)) {
149130
return Promise.reject(localize('errorInvalidSettings', "Unable to sync settings. Please resolve conflicts without any errors/warnings and try again."));
@@ -162,7 +143,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
162143
}
163144

164145
// Delete the preview
165-
await this.fileService.del(SETTINGS_PREVIEW_RESOURCE);
146+
await this.fileService.del(this.conflicts);
166147
}
167148

168149
this.syncPreviewResultPromise = null;
@@ -194,15 +175,15 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
194175
if (fileContent && !remoteUserData) {
195176
this.logService.trace('Settings Sync: Remote contents does not exist. So sync with settings file.');
196177
hasRemoteChanged = true;
197-
await this.fileService.writeFile(SETTINGS_PREVIEW_RESOURCE, VSBuffer.fromString(fileContent.value.toString()));
178+
await this.fileService.writeFile(this.conflicts, VSBuffer.fromString(fileContent.value.toString()));
198179
return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts };
199180
}
200181

201182
// Settings file does not exist, so sync with remote contents.
202183
if (remoteUserData && !fileContent) {
203184
this.logService.trace('Settings Sync: Settings file does not exist. So sync with remote contents');
204185
hasLocalChanged = true;
205-
await this.fileService.writeFile(SETTINGS_PREVIEW_RESOURCE, VSBuffer.fromString(remoteUserData.content));
186+
await this.fileService.writeFile(this.conflicts, VSBuffer.fromString(remoteUserData.content));
206187
return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts };
207188
}
208189

@@ -221,7 +202,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
221202
if (hasLocalChanged || hasRemoteChanged) {
222203
// Sync only if there are changes
223204
hasConflicts = this.hasErrors(mergeContent);
224-
await this.fileService.writeFile(SETTINGS_PREVIEW_RESOURCE, VSBuffer.fromString(mergeContent));
205+
await this.fileService.writeFile(this.conflicts, VSBuffer.fromString(mergeContent));
225206
return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts };
226207
}
227208
}

src/vs/workbench/services/userData/common/userDataSyncService.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { SettingsSynchroniser } from 'vs/workbench/services/userData/common/sett
1111
import { Emitter, Event } from 'vs/base/common/event';
1212
import { IFileService } from 'vs/platform/files/common/files';
1313
import { InMemoryFileSystemProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
14+
import { URI } from 'vs/base/common/uri';
1415

1516
export class UserDataSyncService extends Disposable implements IUserDataSyncService {
1617

@@ -40,6 +41,11 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
4041
this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => s.onDidChangeLocal));
4142
}
4243

44+
get conflicts(): URI | null {
45+
const synchroniser = this.synchronisers.filter(s => s.status === SyncStatus.HasConflicts)[0];
46+
return synchroniser ? synchroniser.conflicts : null;
47+
}
48+
4349
async sync(): Promise<boolean> {
4450
if (!this.userDataSyncStoreService.enabled) {
4551
throw new Error('Not enabled');
@@ -64,18 +70,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
6470
return false;
6571
}
6672

67-
handleConflicts(): boolean {
68-
if (!this.userDataSyncStoreService.enabled) {
69-
throw new Error('Not enabled');
70-
}
71-
for (const synchroniser of this.synchronisers) {
72-
if (synchroniser.handleConflicts()) {
73-
return true;
74-
}
75-
}
76-
return false;
77-
}
78-
7973
private updateStatus(): void {
8074
this.setStatus(this.computeStatus());
8175
}

0 commit comments

Comments
 (0)