#86681 Change API to access conflict settings in sync way
This commit is contained in:
parent
4cfb719aa1
commit
cd4472ed5f
4 changed files with 47 additions and 23 deletions
|
@ -19,6 +19,8 @@ import { startsWith } from 'vs/base/common/strings';
|
|||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { computeRemoteContent, merge } from 'vs/platform/userDataSync/common/settingsMerge';
|
||||
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
|
||||
interface ISyncPreviewResult {
|
||||
readonly fileContent: IFileContent | null;
|
||||
|
@ -41,6 +43,11 @@ export class SettingsSynchroniser extends Disposable implements ISettingsSyncSer
|
|||
private _onDidChangStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
|
||||
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangStatus.event;
|
||||
|
||||
private _conflicts: IConflictSetting[] = [];
|
||||
get conflicts(): IConflictSetting[] { return this._conflicts; }
|
||||
private _onDidChangeConflicts: Emitter<IConflictSetting[]> = this._register(new Emitter<IConflictSetting[]>());
|
||||
readonly onDidChangeConflicts: Event<IConflictSetting[]> = this._onDidChangeConflicts.event;
|
||||
|
||||
private _onDidChangeLocal: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeLocal: Event<void> = this._onDidChangeLocal.event;
|
||||
|
||||
|
@ -65,6 +72,18 @@ export class SettingsSynchroniser extends Disposable implements ISettingsSyncSer
|
|||
this._status = status;
|
||||
this._onDidChangStatus.fire(status);
|
||||
}
|
||||
if (this._status !== SyncStatus.HasConflicts) {
|
||||
this.setConflicts([]);
|
||||
}
|
||||
}
|
||||
|
||||
private setConflicts(conflicts: IConflictSetting[]): void {
|
||||
if (!arrays.equals(this.conflicts, conflicts,
|
||||
(a, b) => a.key === b.key && objects.equals(a.localValue, b.localValue) && objects.equals(a.remoteValue, b.remoteValue))
|
||||
) {
|
||||
this._conflicts = conflicts;
|
||||
this._onDidChangeConflicts.fire(conflicts);
|
||||
}
|
||||
}
|
||||
|
||||
async sync(_continue?: boolean): Promise<boolean> {
|
||||
|
@ -83,6 +102,8 @@ export class SettingsSynchroniser extends Disposable implements ISettingsSyncSer
|
|||
return false;
|
||||
}
|
||||
|
||||
this.logService.trace('Settings: Started synchronizing settings...');
|
||||
this.setStatus(SyncStatus.Syncing);
|
||||
return this.doSync([]);
|
||||
}
|
||||
|
||||
|
@ -96,28 +117,15 @@ export class SettingsSynchroniser extends Disposable implements ISettingsSyncSer
|
|||
this.setStatus(SyncStatus.Idle);
|
||||
}
|
||||
|
||||
async getConflicts(): Promise<IConflictSetting[]> {
|
||||
if (!this.syncPreviewResultPromise) {
|
||||
return [];
|
||||
}
|
||||
if (this.status !== SyncStatus.HasConflicts) {
|
||||
return [];
|
||||
}
|
||||
const preview = await this.syncPreviewResultPromise;
|
||||
return preview.conflicts;
|
||||
}
|
||||
|
||||
async resolveConflicts(resolvedConflicts: { key: string, value: any | undefined }[]): Promise<void> {
|
||||
if (this.status === SyncStatus.HasConflicts) {
|
||||
this.stop();
|
||||
this.syncPreviewResultPromise!.cancel();
|
||||
this.syncPreviewResultPromise = null;
|
||||
await this.doSync(resolvedConflicts);
|
||||
}
|
||||
}
|
||||
|
||||
private async doSync(resolvedConflicts: { key: string, value: any | undefined }[]): Promise<boolean> {
|
||||
this.logService.trace('Settings: Started synchronizing settings...');
|
||||
this.setStatus(SyncStatus.Syncing);
|
||||
|
||||
try {
|
||||
const result = await this.getPreview(resolvedConflicts);
|
||||
if (result.conflicts.length) {
|
||||
|
@ -222,12 +230,13 @@ export class SettingsSynchroniser extends Disposable implements ISettingsSyncSer
|
|||
|
||||
if (remoteContent) {
|
||||
const localContent: string = fileContent ? fileContent.value.toString() : '{}';
|
||||
|
||||
// No action when there are errors
|
||||
if (this.hasErrors(localContent)) {
|
||||
this.logService.error('Settings: Unable to sync settings as there are errors/warning in settings file.');
|
||||
return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, conflicts };
|
||||
}
|
||||
|
||||
if (!lastSyncData // First time sync
|
||||
else if (!lastSyncData // First time sync
|
||||
|| lastSyncData.content !== localContent // Local has forwarded
|
||||
|| lastSyncData.content !== remoteContent // Remote has forwarded
|
||||
) {
|
||||
|
@ -255,6 +264,7 @@ export class SettingsSynchroniser extends Disposable implements ISettingsSyncSer
|
|||
await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(previewContent));
|
||||
}
|
||||
|
||||
this.setConflicts(conflicts);
|
||||
return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, conflicts };
|
||||
}
|
||||
|
||||
|
|
|
@ -200,7 +200,8 @@ export interface IConflictSetting {
|
|||
export const ISettingsSyncService = createDecorator<ISettingsSyncService>('ISettingsSyncService');
|
||||
export interface ISettingsSyncService extends ISynchroniser {
|
||||
_serviceBrand: any;
|
||||
getConflicts(): Promise<IConflictSetting[]>;
|
||||
readonly onDidChangeConflicts: Event<IConflictSetting[]>;
|
||||
readonly conflicts: IConflictSetting[];
|
||||
resolveConflicts(resolvedConflicts: { key: string, value: any | undefined }[]): Promise<void>;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ export class SettingsSyncChannel implements IServerChannel {
|
|||
switch (event) {
|
||||
case 'onDidChangeStatus': return this.service.onDidChangeStatus;
|
||||
case 'onDidChangeLocal': return this.service.onDidChangeLocal;
|
||||
case 'onDidChangeConflicts': return this.service.onDidChangeConflicts;
|
||||
}
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
@ -50,8 +51,8 @@ export class SettingsSyncChannel implements IServerChannel {
|
|||
switch (command) {
|
||||
case 'sync': return this.service.sync(args[0]);
|
||||
case '_getInitialStatus': return Promise.resolve(this.service.status);
|
||||
case '_getInitialConflicts': return Promise.resolve(this.service.conflicts);
|
||||
case 'stop': this.service.stop(); return Promise.resolve();
|
||||
case 'getConflicts': return this.service.getConflicts();
|
||||
case 'resolveConflicts': return this.service.resolveConflicts(args[0]);
|
||||
}
|
||||
throw new Error('Invalid call');
|
||||
|
|
|
@ -21,6 +21,11 @@ export class SettingsSyncService extends Disposable implements ISettingsSyncServ
|
|||
private _onDidChangeStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
|
||||
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangeStatus.event;
|
||||
|
||||
private _conflicts: IConflictSetting[] = [];
|
||||
get conflicts(): IConflictSetting[] { return this._conflicts; }
|
||||
private _onDidChangeConflicts: Emitter<IConflictSetting[]> = this._register(new Emitter<IConflictSetting[]>());
|
||||
readonly onDidChangeConflicts: Event<IConflictSetting[]> = this._onDidChangeConflicts.event;
|
||||
|
||||
get onDidChangeLocal(): Event<void> { return this.channel.listen('onDidChangeLocal'); }
|
||||
|
||||
constructor(
|
||||
|
@ -32,6 +37,12 @@ export class SettingsSyncService extends Disposable implements ISettingsSyncServ
|
|||
this.updateStatus(status);
|
||||
this._register(this.channel.listen<SyncStatus>('onDidChangeStatus')(status => this.updateStatus(status)));
|
||||
});
|
||||
this.channel.call<IConflictSetting[]>('_getInitialConflicts').then(conflicts => {
|
||||
if (conflicts.length) {
|
||||
this.updateConflicts(conflicts);
|
||||
}
|
||||
this._register(this.channel.listen<IConflictSetting[]>('onDidChangeConflicts')(conflicts => this.updateConflicts(conflicts)));
|
||||
});
|
||||
}
|
||||
|
||||
sync(_continue?: boolean): Promise<boolean> {
|
||||
|
@ -42,10 +53,6 @@ export class SettingsSyncService extends Disposable implements ISettingsSyncServ
|
|||
this.channel.call('stop');
|
||||
}
|
||||
|
||||
getConflicts(): Promise<IConflictSetting[]> {
|
||||
return this.channel.call<IConflictSetting[]>('getConflicts');
|
||||
}
|
||||
|
||||
resolveConflicts(conflicts: { key: string, value: any | undefined }[]): Promise<void> {
|
||||
return this.channel.call('resolveConflicts', [conflicts]);
|
||||
}
|
||||
|
@ -55,6 +62,11 @@ export class SettingsSyncService extends Disposable implements ISettingsSyncServ
|
|||
this._onDidChangeStatus.fire(status);
|
||||
}
|
||||
|
||||
private async updateConflicts(conflicts: IConflictSetting[]): Promise<void> {
|
||||
this._conflicts = conflicts;
|
||||
this._onDidChangeConflicts.fire(conflicts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(ISettingsSyncService, SettingsSyncService);
|
||||
|
|
Loading…
Reference in a new issue