mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-28 17:23:19 -05:00
Merge from vscode 2cd495805cf99b31b6926f08ff4348124b2cf73d
This commit is contained in:
committed by
AzureDataStudio
parent
a8a7559229
commit
1388493cc1
@@ -9,7 +9,7 @@ import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import {
|
||||
SyncResource, SyncStatus, IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, UserDataSyncError, IUserDataSyncLogService, IUserDataSyncUtilService,
|
||||
IUserDataSyncResourceEnablementService, IUserDataSyncBackupStoreService, Conflict, ISyncResourceHandle, USER_DATA_SYNC_SCHEME, ISyncPreview, IUserDataManifest, ISyncData, IRemoteUserData
|
||||
IUserDataSyncResourceEnablementService, IUserDataSyncBackupStoreService, Conflict, ISyncResourceHandle, USER_DATA_SYNC_SCHEME, ISyncResourcePreview as IBaseSyncResourcePreview, IUserDataManifest, ISyncData, IRemoteUserData, PREVIEW_DIR_NAME
|
||||
} from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { joinPath, dirname, isEqual, basename } from 'vs/base/common/resources';
|
||||
@@ -52,11 +52,17 @@ function isSyncData(thing: any): thing is ISyncData {
|
||||
return false;
|
||||
}
|
||||
|
||||
export interface ISyncResourcePreview extends IBaseSyncResourcePreview {
|
||||
readonly remoteUserData: IRemoteUserData;
|
||||
readonly lastSyncUserData: IRemoteUserData | null;
|
||||
}
|
||||
|
||||
export abstract class AbstractSynchroniser extends Disposable {
|
||||
|
||||
private syncPreviewPromise: CancelablePromise<ISyncPreview> | null = null;
|
||||
private syncPreviewPromise: CancelablePromise<ISyncResourcePreview> | null = null;
|
||||
|
||||
protected readonly syncFolder: URI;
|
||||
protected readonly syncPreviewFolder: URI;
|
||||
private readonly currentMachineIdPromise: Promise<string>;
|
||||
|
||||
private _status: SyncStatus = SyncStatus.Idle;
|
||||
@@ -93,6 +99,7 @@ export abstract class AbstractSynchroniser extends Disposable {
|
||||
super();
|
||||
this.syncResourceLogLabel = uppercaseFirstLetter(this.resource);
|
||||
this.syncFolder = joinPath(environmentService.userDataSyncHome, resource);
|
||||
this.syncPreviewFolder = joinPath(this.syncFolder, PREVIEW_DIR_NAME);
|
||||
this.lastSyncResource = joinPath(this.syncFolder, `lastSync${this.resource}.json`);
|
||||
this.currentMachineIdPromise = getServiceMachineId(environmentService, fileService, storageService);
|
||||
}
|
||||
@@ -287,7 +294,7 @@ export abstract class AbstractSynchroniser extends Disposable {
|
||||
return this.getRemoteUserData(lastSyncUserData);
|
||||
}
|
||||
|
||||
async generateSyncPreview(): Promise<ISyncPreview | null> {
|
||||
async generateSyncPreview(): Promise<ISyncResourcePreview | null> {
|
||||
if (this.isEnabled()) {
|
||||
const lastSyncUserData = await this.getLastSyncUserData();
|
||||
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
||||
@@ -360,7 +367,7 @@ export abstract class AbstractSynchroniser extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
protected async getSyncPreviewInProgress(): Promise<ISyncPreview | null> {
|
||||
protected async getSyncPreviewInProgress(): Promise<ISyncResourcePreview | null> {
|
||||
return this.syncPreviewPromise ? this.syncPreviewPromise : null;
|
||||
}
|
||||
|
||||
@@ -528,15 +535,15 @@ export abstract class AbstractSynchroniser extends Disposable {
|
||||
}
|
||||
|
||||
protected abstract readonly version: number;
|
||||
protected abstract generatePullPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ISyncPreview>;
|
||||
protected abstract generatePushPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ISyncPreview>;
|
||||
protected abstract generateReplacePreview(syncData: ISyncData, remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise<ISyncPreview>;
|
||||
protected abstract generatePreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ISyncPreview>;
|
||||
protected abstract updatePreviewWithConflict(preview: ISyncPreview, conflictResource: URI, content: string, token: CancellationToken): Promise<ISyncPreview>;
|
||||
protected abstract applyPreview(preview: ISyncPreview, forcePush: boolean): Promise<void>;
|
||||
protected abstract generatePullPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ISyncResourcePreview>;
|
||||
protected abstract generatePushPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ISyncResourcePreview>;
|
||||
protected abstract generateReplacePreview(syncData: ISyncData, remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise<ISyncResourcePreview>;
|
||||
protected abstract generatePreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ISyncResourcePreview>;
|
||||
protected abstract updatePreviewWithConflict(preview: ISyncResourcePreview, conflictResource: URI, content: string, token: CancellationToken): Promise<ISyncResourcePreview>;
|
||||
protected abstract applyPreview(preview: ISyncResourcePreview, forcePush: boolean): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IFileSyncPreview extends ISyncPreview {
|
||||
export interface IFileSyncPreview extends ISyncResourcePreview {
|
||||
readonly fileContent: IFileContent | null;
|
||||
readonly content: string | null;
|
||||
}
|
||||
@@ -568,7 +575,7 @@ export abstract class AbstractFileSynchroniser extends AbstractSynchroniser {
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
protected async getConflictContent(conflictResource: URI): Promise<string | null> {
|
||||
protected async resolvePreviewContent(conflictResource: URI): Promise<string | null> {
|
||||
if (isEqual(this.remotePreviewResource, conflictResource) || isEqual(this.localPreviewResource, conflictResource)) {
|
||||
const syncPreview = await this.getSyncPreviewInProgress();
|
||||
if (syncPreview) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import {
|
||||
IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncResource, IUserDataSyncResourceEnablementService,
|
||||
IUserDataSyncBackupStoreService, ISyncResourceHandle, ISyncPreview, USER_DATA_SYNC_SCHEME, IRemoteUserData, ISyncData
|
||||
IUserDataSyncBackupStoreService, ISyncResourceHandle, USER_DATA_SYNC_SCHEME, IRemoteUserData, ISyncData, IResourcePreview
|
||||
} from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
@@ -14,8 +14,8 @@ import { ExtensionType, IExtensionIdentifier } from 'vs/platform/extensions/comm
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { merge, getIgnoredExtensions } from 'vs/platform/userDataSync/common/extensionsMerge';
|
||||
import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { merge, getIgnoredExtensions, IMergeResult } from 'vs/platform/userDataSync/common/extensionsMerge';
|
||||
import { AbstractSynchroniser, ISyncResourcePreview } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { joinPath, dirname, basename, isEqual } from 'vs/base/common/resources';
|
||||
@@ -25,9 +25,8 @@ import { compare } from 'vs/base/common/strings';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
interface IExtensionsSyncPreview extends ISyncPreview {
|
||||
interface IExtensionsSyncPreview extends ISyncResourcePreview {
|
||||
readonly localExtensions: ISyncExtension[];
|
||||
readonly remoteUserData: IRemoteUserData;
|
||||
readonly lastSyncUserData: ILastSyncUserData | null;
|
||||
readonly added: ISyncExtension[];
|
||||
readonly removed: IExtensionIdentifier[];
|
||||
@@ -48,6 +47,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
*/
|
||||
protected readonly version: number = 3;
|
||||
protected isEnabled(): boolean { return super.isEnabled() && this.extensionGalleryService.isEnabled(); }
|
||||
private readonly localPreviewResource: URI = joinPath(this.syncPreviewFolder, 'extensions.json');
|
||||
private readonly remotePreviewResource: URI = this.localPreviewResource.with({ scheme: USER_DATA_SYNC_SCHEME });
|
||||
|
||||
constructor(
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@@ -79,14 +80,17 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
const ignoredExtensions = getIgnoredExtensions(installedExtensions, this.configurationService);
|
||||
if (remoteUserData.syncData !== null) {
|
||||
const remoteExtensions = await this.parseAndMigrateExtensions(remoteUserData.syncData);
|
||||
const { added, updated, remote, removed } = merge(localExtensions, remoteExtensions, localExtensions, [], ignoredExtensions);
|
||||
const mergeResult = merge(localExtensions, remoteExtensions, localExtensions, [], ignoredExtensions);
|
||||
const { added, removed, updated, remote } = mergeResult;
|
||||
const resourcePreviews: IResourcePreview[] = this.getResourcePreviews(mergeResult);
|
||||
return {
|
||||
remoteUserData, lastSyncUserData,
|
||||
added, removed, updated, remote, localExtensions, skippedExtensions: [],
|
||||
hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0,
|
||||
hasRemoteChanged: remote !== null,
|
||||
hasLocalChanged: resourcePreviews.some(({ hasLocalChanged }) => hasLocalChanged),
|
||||
hasRemoteChanged: resourcePreviews.some(({ hasRemoteChanged }) => hasRemoteChanged),
|
||||
hasConflicts: false,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
@@ -96,6 +100,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
hasRemoteChanged: false,
|
||||
hasConflicts: false,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -104,13 +109,16 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
const installedExtensions = await this.extensionManagementService.getInstalled();
|
||||
const localExtensions = this.getLocalExtensions(installedExtensions);
|
||||
const ignoredExtensions = getIgnoredExtensions(installedExtensions, this.configurationService);
|
||||
const { added, removed, updated, remote } = merge(localExtensions, null, null, [], ignoredExtensions);
|
||||
const mergeResult = merge(localExtensions, null, null, [], ignoredExtensions);
|
||||
const { added, removed, updated, remote } = mergeResult;
|
||||
const resourcePreviews: IResourcePreview[] = this.getResourcePreviews(mergeResult);
|
||||
return {
|
||||
added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData,
|
||||
hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0,
|
||||
hasRemoteChanged: remote !== null,
|
||||
hasLocalChanged: resourcePreviews.some(({ hasLocalChanged }) => hasLocalChanged),
|
||||
hasRemoteChanged: resourcePreviews.some(({ hasRemoteChanged }) => hasRemoteChanged),
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
hasConflicts: false,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
@@ -119,14 +127,16 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
const localExtensions = this.getLocalExtensions(installedExtensions);
|
||||
const syncExtensions = await this.parseAndMigrateExtensions(syncData);
|
||||
const ignoredExtensions = getIgnoredExtensions(installedExtensions, this.configurationService);
|
||||
const { added, updated, removed } = merge(localExtensions, syncExtensions, localExtensions, [], ignoredExtensions);
|
||||
|
||||
const mergeResult = merge(localExtensions, syncExtensions, localExtensions, [], ignoredExtensions);
|
||||
const { added, removed, updated } = mergeResult;
|
||||
const resourcePreviews: IResourcePreview[] = this.getResourcePreviews(mergeResult);
|
||||
return {
|
||||
added, removed, updated, remote: syncExtensions, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData,
|
||||
hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0,
|
||||
hasLocalChanged: resourcePreviews.some(({ hasLocalChanged }) => hasLocalChanged),
|
||||
hasRemoteChanged: true,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
hasConflicts: false,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
@@ -153,7 +163,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
this.logService.trace(`${this.syncResourceLogLabel}: Remote extensions does not exist. Synchronizing extensions for the first time.`);
|
||||
}
|
||||
|
||||
const { added, removed, updated, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, ignoredExtensions);
|
||||
const mergeResult = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, ignoredExtensions);
|
||||
const { added, removed, updated, remote } = mergeResult;
|
||||
const resourcePreviews: IResourcePreview[] = this.getResourcePreviews(mergeResult);
|
||||
|
||||
return {
|
||||
added,
|
||||
@@ -164,10 +176,11 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
remoteUserData,
|
||||
localExtensions,
|
||||
lastSyncUserData,
|
||||
hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0,
|
||||
hasRemoteChanged: remote !== null,
|
||||
hasLocalChanged: resourcePreviews.some(({ hasLocalChanged }) => hasLocalChanged),
|
||||
hasRemoteChanged: resourcePreviews.some(({ hasRemoteChanged }) => hasRemoteChanged),
|
||||
isLastSyncFromCurrentMachine,
|
||||
hasConflicts: false
|
||||
hasConflicts: false,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
@@ -202,6 +215,18 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
}
|
||||
}
|
||||
|
||||
private getResourcePreviews({ added, removed, updated, remote }: IMergeResult): IResourcePreview[] {
|
||||
const hasLocalChanged = added.length > 0 || removed.length > 0 || updated.length > 0;
|
||||
const hasRemoteChanged = remote !== null;
|
||||
return [{
|
||||
hasLocalChanged,
|
||||
hasConflicts: false,
|
||||
hasRemoteChanged,
|
||||
localResouce: ExtensionsSynchroniser.EXTENSIONS_DATA_URI,
|
||||
remoteResource: this.remotePreviewResource
|
||||
}];
|
||||
}
|
||||
|
||||
async getAssociatedResources({ uri }: ISyncResourceHandle): Promise<{ resource: URI, comparableResource?: URI }[]> {
|
||||
return [{ resource: joinPath(uri, 'extensions.json'), comparableResource: ExtensionsSynchroniser.EXTENSIONS_DATA_URI }];
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import {
|
||||
IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncResource, IUserDataSynchroniser, IUserDataSyncResourceEnablementService,
|
||||
IUserDataSyncBackupStoreService, ISyncResourceHandle, IStorageValue, ISyncPreview, USER_DATA_SYNC_SCHEME, IRemoteUserData, ISyncData
|
||||
IUserDataSyncBackupStoreService, ISyncResourceHandle, IStorageValue, USER_DATA_SYNC_SCHEME, IRemoteUserData, ISyncData, IResourcePreview
|
||||
} from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
@@ -14,9 +14,9 @@ import { dirname, joinPath, basename, isEqual } from 'vs/base/common/resources';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { edit } from 'vs/platform/userDataSync/common/content';
|
||||
import { merge } from 'vs/platform/userDataSync/common/globalStateMerge';
|
||||
import { merge, IMergeResult } from 'vs/platform/userDataSync/common/globalStateMerge';
|
||||
import { parse } from 'vs/base/common/json';
|
||||
import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { AbstractSynchroniser, ISyncResourcePreview } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -30,12 +30,11 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
const argvStoragePrefx = 'globalState.argv.';
|
||||
const argvProperties: string[] = ['locale'];
|
||||
|
||||
interface IGlobalStateSyncPreview extends ISyncPreview {
|
||||
interface IGlobalStateSyncPreview extends ISyncResourcePreview {
|
||||
readonly local: { added: IStringDictionary<IStorageValue>, removed: string[], updated: IStringDictionary<IStorageValue> };
|
||||
readonly remote: IStringDictionary<IStorageValue> | null;
|
||||
readonly skippedStorageKeys: string[];
|
||||
readonly localUserData: IGlobalState;
|
||||
readonly remoteUserData: IRemoteUserData;
|
||||
readonly lastSyncUserData: ILastSyncUserData | null;
|
||||
}
|
||||
|
||||
@@ -47,6 +46,8 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
|
||||
private static readonly GLOBAL_STATE_DATA_URI = URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'globalState', path: `/current.json` });
|
||||
protected readonly version: number = 1;
|
||||
private readonly localPreviewResource: URI = joinPath(this.syncPreviewFolder, 'globalState.json');
|
||||
private readonly remotePreviewResource: URI = this.localPreviewResource.with({ scheme: USER_DATA_SYNC_SCHEME });
|
||||
|
||||
constructor(
|
||||
@IFileService fileService: IFileService,
|
||||
@@ -78,14 +79,17 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
const localGlobalState = await this.getLocalGlobalState();
|
||||
if (remoteUserData.syncData !== null) {
|
||||
const remoteGlobalState: IGlobalState = JSON.parse(remoteUserData.syncData.content);
|
||||
const { local, remote, skipped } = merge(localGlobalState.storage, remoteGlobalState.storage, null, this.getSyncStorageKeys(), lastSyncUserData?.skippedStorageKeys || [], this.logService);
|
||||
const mergeResult = merge(localGlobalState.storage, remoteGlobalState.storage, null, this.getSyncStorageKeys(), lastSyncUserData?.skippedStorageKeys || [], this.logService);
|
||||
const { local, remote, skipped } = mergeResult;
|
||||
const resourcePreviews: IResourcePreview[] = this.getResourcePreviews(mergeResult);
|
||||
return {
|
||||
remoteUserData, lastSyncUserData,
|
||||
local, remote, localUserData: localGlobalState, skippedStorageKeys: skipped,
|
||||
hasLocalChanged: Object.keys(local.added).length > 0 || Object.keys(local.updated).length > 0 || local.removed.length > 0,
|
||||
hasRemoteChanged: remote !== null,
|
||||
hasLocalChanged: resourcePreviews.some(({ hasLocalChanged }) => hasLocalChanged),
|
||||
hasRemoteChanged: resourcePreviews.some(({ hasRemoteChanged }) => hasRemoteChanged),
|
||||
hasConflicts: false,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
@@ -95,6 +99,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
hasRemoteChanged: false,
|
||||
hasConflicts: false,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews: []
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -107,21 +112,25 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
hasLocalChanged: false,
|
||||
hasRemoteChanged: true,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
hasConflicts: false
|
||||
hasConflicts: false,
|
||||
resourcePreviews: this.getResourcePreviews({ local: { added: {}, removed: [], updated: {} }, remote: localUserData.storage, skipped: [] })
|
||||
};
|
||||
}
|
||||
|
||||
protected async generateReplacePreview(syncData: ISyncData, remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<IGlobalStateSyncPreview> {
|
||||
const localUserData = await this.getLocalGlobalState();
|
||||
const syncGlobalState: IGlobalState = JSON.parse(syncData.content);
|
||||
const { local, skipped } = merge(localUserData.storage, syncGlobalState.storage, localUserData.storage, this.getSyncStorageKeys(), lastSyncUserData?.skippedStorageKeys || [], this.logService);
|
||||
const mergeResult = merge(localUserData.storage, syncGlobalState.storage, localUserData.storage, this.getSyncStorageKeys(), lastSyncUserData?.skippedStorageKeys || [], this.logService);
|
||||
const { local, skipped } = mergeResult;
|
||||
const resourcePreviews: IResourcePreview[] = this.getResourcePreviews(mergeResult);
|
||||
return {
|
||||
local, remote: syncGlobalState.storage, remoteUserData, localUserData, lastSyncUserData,
|
||||
skippedStorageKeys: skipped,
|
||||
hasLocalChanged: Object.keys(local.added).length > 0 || Object.keys(local.updated).length > 0 || local.removed.length > 0,
|
||||
hasLocalChanged: resourcePreviews.some(({ hasLocalChanged }) => hasLocalChanged),
|
||||
hasRemoteChanged: true,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
hasConflicts: false
|
||||
hasConflicts: false,
|
||||
resourcePreviews: [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -145,15 +154,18 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
this.logService.trace(`${this.syncResourceLogLabel}: Remote ui state does not exist. Synchronizing ui state for the first time.`);
|
||||
}
|
||||
|
||||
const { local, remote, skipped } = merge(localGloablState.storage, remoteGlobalState ? remoteGlobalState.storage : null, lastSyncGlobalState ? lastSyncGlobalState.storage : null, this.getSyncStorageKeys(), lastSyncUserData?.skippedStorageKeys || [], this.logService);
|
||||
const mergeResult = merge(localGloablState.storage, remoteGlobalState ? remoteGlobalState.storage : null, lastSyncGlobalState ? lastSyncGlobalState.storage : null, this.getSyncStorageKeys(), lastSyncUserData?.skippedStorageKeys || [], this.logService);
|
||||
const { local, remote, skipped } = mergeResult;
|
||||
const resourcePreviews: IResourcePreview[] = this.getResourcePreviews(mergeResult);
|
||||
|
||||
return {
|
||||
local, remote, remoteUserData, localUserData: localGloablState, lastSyncUserData,
|
||||
skippedStorageKeys: skipped,
|
||||
hasLocalChanged: Object.keys(local.added).length > 0 || Object.keys(local.updated).length > 0 || local.removed.length > 0,
|
||||
hasRemoteChanged: remote !== null,
|
||||
hasLocalChanged: resourcePreviews.some(({ hasLocalChanged }) => hasLocalChanged),
|
||||
hasRemoteChanged: resourcePreviews.some(({ hasRemoteChanged }) => hasRemoteChanged),
|
||||
isLastSyncFromCurrentMachine,
|
||||
hasConflicts: false
|
||||
hasConflicts: false,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
@@ -191,6 +203,18 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
}
|
||||
}
|
||||
|
||||
private getResourcePreviews({ local, remote }: IMergeResult): IResourcePreview[] {
|
||||
const hasLocalChanged = Object.keys(local.added).length > 0 || Object.keys(local.updated).length > 0 || local.removed.length > 0;
|
||||
const hasRemoteChanged = remote !== null;
|
||||
return [{
|
||||
hasLocalChanged,
|
||||
hasConflicts: false,
|
||||
hasRemoteChanged,
|
||||
localResouce: GlobalStateSynchroniser.GLOBAL_STATE_DATA_URI,
|
||||
remoteResource: this.remotePreviewResource
|
||||
}];
|
||||
}
|
||||
|
||||
async getAssociatedResources({ uri }: ISyncResourceHandle): Promise<{ resource: URI, comparableResource?: URI }[]> {
|
||||
return [{ resource: joinPath(uri, 'globalState.json'), comparableResource: GlobalStateSynchroniser.GLOBAL_STATE_DATA_URI }];
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import {
|
||||
UserDataSyncError, UserDataSyncErrorCode, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, SyncResource,
|
||||
IUserDataSynchroniser, IUserDataSyncResourceEnablementService, IUserDataSyncBackupStoreService, USER_DATA_SYNC_SCHEME, PREVIEW_DIR_NAME, ISyncResourceHandle,
|
||||
IRemoteUserData, ISyncData
|
||||
IUserDataSynchroniser, IUserDataSyncResourceEnablementService, IUserDataSyncBackupStoreService, USER_DATA_SYNC_SCHEME, ISyncResourceHandle,
|
||||
IRemoteUserData, ISyncData, IResourcePreview
|
||||
} from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { merge } from 'vs/platform/userDataSync/common/keybindingsMerge';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
@@ -35,7 +35,7 @@ interface ISyncContent {
|
||||
export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implements IUserDataSynchroniser {
|
||||
|
||||
protected readonly version: number = 1;
|
||||
protected readonly localPreviewResource: URI = joinPath(this.syncFolder, PREVIEW_DIR_NAME, 'keybindings.json');
|
||||
protected readonly localPreviewResource: URI = joinPath(this.syncPreviewFolder, 'keybindings.json');
|
||||
protected readonly remotePreviewResource: URI = this.localPreviewResource.with({ scheme: USER_DATA_SYNC_SCHEME });
|
||||
|
||||
constructor(
|
||||
@@ -57,45 +57,81 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
|
||||
const fileContent = await this.getLocalFileContent();
|
||||
const content = remoteUserData.syncData !== null ? this.getKeybindingsContentFromSyncContent(remoteUserData.syncData.content) : null;
|
||||
const hasLocalChanged = content !== null;
|
||||
const hasRemoteChanged = false;
|
||||
const hasConflicts = false;
|
||||
|
||||
const resourcePreviews: IResourcePreview[] = [{
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
localResouce: this.file,
|
||||
remoteResource: this.remotePreviewResource,
|
||||
}];
|
||||
|
||||
return {
|
||||
fileContent,
|
||||
remoteUserData,
|
||||
lastSyncUserData,
|
||||
content,
|
||||
hasConflicts: false,
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged: false,
|
||||
isLastSyncFromCurrentMachine: false
|
||||
hasRemoteChanged,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
protected async generatePushPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<IFileSyncPreview> {
|
||||
const fileContent = await this.getLocalFileContent();
|
||||
const content: string | null = fileContent ? fileContent.value.toString() : null;
|
||||
const hasLocalChanged = false;
|
||||
const hasRemoteChanged = content !== null;
|
||||
const hasConflicts = false;
|
||||
|
||||
const resourcePreviews: IResourcePreview[] = [{
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
localResouce: this.file,
|
||||
remoteResource: this.remotePreviewResource,
|
||||
}];
|
||||
return {
|
||||
fileContent,
|
||||
remoteUserData,
|
||||
lastSyncUserData,
|
||||
content,
|
||||
hasLocalChanged: false,
|
||||
hasRemoteChanged: content !== null,
|
||||
hasConflicts: false,
|
||||
isLastSyncFromCurrentMachine: false
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
hasConflicts,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
protected async generateReplacePreview(syncData: ISyncData, remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise<IFileSyncPreview> {
|
||||
const fileContent = await this.getLocalFileContent();
|
||||
const content = this.getKeybindingsContentFromSyncContent(syncData.content);
|
||||
const hasLocalChanged = content !== null;
|
||||
const hasRemoteChanged = content !== null;
|
||||
const hasConflicts = false;
|
||||
|
||||
const resourcePreviews: IResourcePreview[] = [{
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
localResouce: this.file,
|
||||
remoteResource: this.remotePreviewResource,
|
||||
}];
|
||||
return {
|
||||
fileContent,
|
||||
remoteUserData,
|
||||
lastSyncUserData,
|
||||
content,
|
||||
hasConflicts: false,
|
||||
hasLocalChanged: content !== null,
|
||||
hasRemoteChanged: content !== null,
|
||||
isLastSyncFromCurrentMachine: false
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
@@ -154,8 +190,16 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
|
||||
}
|
||||
|
||||
this.setConflicts(hasConflicts && !token.isCancellationRequested ? [{ local: this.localPreviewResource, remote: this.remotePreviewResource }] : []);
|
||||
const resourcePreviews: IResourcePreview[] = [{
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
localResouce: this.file,
|
||||
remoteResource: this.remotePreviewResource,
|
||||
previewResource: this.localPreviewResource
|
||||
}];
|
||||
|
||||
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts, isLastSyncFromCurrentMachine };
|
||||
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts, isLastSyncFromCurrentMachine, resourcePreviews };
|
||||
}
|
||||
|
||||
protected async updatePreviewWithConflict(preview: IFileSyncPreview, conflictResource: URI, conflictContent: string, token: CancellationToken): Promise<IFileSyncPreview> {
|
||||
@@ -229,7 +273,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
|
||||
|
||||
async resolveContent(uri: URI): Promise<string | null> {
|
||||
if (isEqual(this.remotePreviewResource, uri)) {
|
||||
return this.getConflictContent(uri);
|
||||
return this.resolvePreviewContent(uri);
|
||||
}
|
||||
let content = await super.resolveContent(uri);
|
||||
if (content) {
|
||||
@@ -248,8 +292,8 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
|
||||
return null;
|
||||
}
|
||||
|
||||
protected async getConflictContent(conflictResource: URI): Promise<string | null> {
|
||||
const content = await super.getConflictContent(conflictResource);
|
||||
protected async resolvePreviewContent(conflictResource: URI): Promise<string | null> {
|
||||
const content = await super.resolvePreviewContent(conflictResource);
|
||||
return content !== null ? this.getKeybindingsContentFromSyncContent(content) : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import {
|
||||
UserDataSyncError, UserDataSyncErrorCode, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, CONFIGURATION_SYNC_STORE_KEY,
|
||||
SyncResource, IUserDataSyncResourceEnablementService, IUserDataSyncBackupStoreService, USER_DATA_SYNC_SCHEME, PREVIEW_DIR_NAME, ISyncResourceHandle, IUserDataSynchroniser,
|
||||
IRemoteUserData, ISyncData
|
||||
SyncResource, IUserDataSyncResourceEnablementService, IUserDataSyncBackupStoreService, USER_DATA_SYNC_SCHEME, ISyncResourceHandle, IUserDataSynchroniser,
|
||||
IRemoteUserData, ISyncData, IResourcePreview
|
||||
} from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -39,7 +39,7 @@ function isSettingsSyncContent(thing: any): thing is ISettingsSyncContent {
|
||||
export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implements IUserDataSynchroniser {
|
||||
|
||||
protected readonly version: number = 1;
|
||||
protected readonly localPreviewResource: URI = joinPath(this.syncFolder, PREVIEW_DIR_NAME, 'settings.json');
|
||||
protected readonly localPreviewResource: URI = joinPath(this.syncPreviewFolder, 'settings.json');
|
||||
protected readonly remotePreviewResource: URI = this.localPreviewResource.with({ scheme: USER_DATA_SYNC_SCHEME });
|
||||
|
||||
constructor(
|
||||
@@ -71,15 +71,28 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
||||
content = updateIgnoredSettings(remoteSettingsSyncContent.settings, fileContent ? fileContent.value.toString() : '{}', ignoredSettings, formatUtils);
|
||||
}
|
||||
|
||||
const hasLocalChanged = content !== null;
|
||||
const hasRemoteChanged = false;
|
||||
const hasConflicts = false;
|
||||
|
||||
const resourcePreviews: IResourcePreview[] = [{
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
localResouce: this.file,
|
||||
remoteResource: this.remotePreviewResource,
|
||||
}];
|
||||
|
||||
return {
|
||||
fileContent,
|
||||
remoteUserData,
|
||||
lastSyncUserData,
|
||||
content,
|
||||
hasLocalChanged: content !== null,
|
||||
hasRemoteChanged: false,
|
||||
hasConflicts: false,
|
||||
isLastSyncFromCurrentMachine: false
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
hasConflicts,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
@@ -95,15 +108,28 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
||||
content = updateIgnoredSettings(fileContent.value.toString(), '{}', ignoredSettings, formatUtils);
|
||||
}
|
||||
|
||||
const hasLocalChanged = false;
|
||||
const hasRemoteChanged = content !== null;
|
||||
const hasConflicts = false;
|
||||
|
||||
const resourcePreviews: IResourcePreview[] = [{
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
localResouce: this.file,
|
||||
remoteResource: this.remotePreviewResource,
|
||||
}];
|
||||
|
||||
return {
|
||||
fileContent,
|
||||
remoteUserData,
|
||||
lastSyncUserData,
|
||||
content,
|
||||
hasLocalChanged: false,
|
||||
hasRemoteChanged: content !== null,
|
||||
hasConflicts: false,
|
||||
isLastSyncFromCurrentMachine: false
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
hasConflicts,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
@@ -119,14 +145,27 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
||||
content = updateIgnoredSettings(settingsSyncContent.settings, fileContent ? fileContent.value.toString() : '{}', ignoredSettings, formatUtils);
|
||||
}
|
||||
|
||||
const hasLocalChanged = content !== null;
|
||||
const hasRemoteChanged = content !== null;
|
||||
const hasConflicts = false;
|
||||
|
||||
const resourcePreviews: IResourcePreview[] = [{
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
localResouce: this.file,
|
||||
remoteResource: this.remotePreviewResource,
|
||||
}];
|
||||
|
||||
return {
|
||||
fileContent,
|
||||
remoteUserData,
|
||||
lastSyncUserData,
|
||||
content,
|
||||
hasLocalChanged: content !== null,
|
||||
hasRemoteChanged: content !== null,
|
||||
hasConflicts: false,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
hasConflicts,
|
||||
resourcePreviews,
|
||||
isLastSyncFromCurrentMachine: false
|
||||
};
|
||||
}
|
||||
@@ -177,8 +216,16 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
||||
}
|
||||
|
||||
this.setConflicts(hasConflicts && !token.isCancellationRequested ? [{ local: this.localPreviewResource, remote: this.remotePreviewResource }] : []);
|
||||
const resourcePreviews: IResourcePreview[] = [{
|
||||
hasConflicts,
|
||||
hasLocalChanged,
|
||||
hasRemoteChanged,
|
||||
localResouce: this.file,
|
||||
remoteResource: this.remotePreviewResource,
|
||||
previewResource: this.localPreviewResource
|
||||
}];
|
||||
|
||||
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts, isLastSyncFromCurrentMachine };
|
||||
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts, isLastSyncFromCurrentMachine, resourcePreviews };
|
||||
}
|
||||
|
||||
protected async updatePreviewWithConflict(preview: IFileSyncPreview, conflictResource: URI, conflictContent: string, token: CancellationToken): Promise<IFileSyncPreview> {
|
||||
@@ -256,7 +303,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
||||
|
||||
async resolveContent(uri: URI): Promise<string | null> {
|
||||
if (isEqual(this.remotePreviewResource, uri)) {
|
||||
return this.getConflictContent(uri);
|
||||
return this.resolvePreviewContent(uri);
|
||||
}
|
||||
let content = await super.resolveContent(uri);
|
||||
if (content) {
|
||||
@@ -278,8 +325,8 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
||||
return null;
|
||||
}
|
||||
|
||||
protected async getConflictContent(conflictResource: URI): Promise<string | null> {
|
||||
let content = await super.getConflictContent(conflictResource);
|
||||
protected async resolvePreviewContent(conflictResource: URI): Promise<string | null> {
|
||||
let content = await super.resolvePreviewContent(conflictResource);
|
||||
if (content !== null) {
|
||||
const settingsSyncContent = this.parseSettingsSyncContent(content);
|
||||
content = settingsSyncContent ? settingsSyncContent.settings : null;
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
|
||||
import {
|
||||
IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSynchroniser, SyncResource, IUserDataSyncResourceEnablementService, IUserDataSyncBackupStoreService,
|
||||
Conflict, USER_DATA_SYNC_SCHEME, PREVIEW_DIR_NAME, ISyncResourceHandle, IRemoteUserData, ISyncData, ISyncPreview
|
||||
Conflict, USER_DATA_SYNC_SCHEME, ISyncResourceHandle, IRemoteUserData, ISyncData, IResourcePreview
|
||||
} from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IFileService, FileChangesEvent, IFileStat, IFileContent, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { AbstractSynchroniser, ISyncResourcePreview } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { joinPath, extname, relativePath, isEqualOrParent, isEqual, basename, dirname } from 'vs/base/common/resources';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { merge } from 'vs/platform/userDataSync/common/snippetsMerge';
|
||||
import { merge, IMergeResult } from 'vs/platform/userDataSync/common/snippetsMerge';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
|
||||
interface ISinppetsSyncPreview extends ISyncPreview {
|
||||
interface ISinppetsSyncPreview extends ISyncResourcePreview {
|
||||
readonly local: IStringDictionary<IFileContent>;
|
||||
readonly added: IStringDictionary<string>;
|
||||
readonly updated: IStringDictionary<string>;
|
||||
@@ -34,7 +34,6 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
|
||||
protected readonly version: number = 1;
|
||||
private readonly snippetsFolder: URI;
|
||||
private readonly snippetsPreviewFolder: URI;
|
||||
|
||||
constructor(
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@@ -49,7 +48,6 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
) {
|
||||
super(SyncResource.Snippets, fileService, environmentService, storageService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncResourceEnablementService, telemetryService, logService, configurationService);
|
||||
this.snippetsFolder = environmentService.snippetsHome;
|
||||
this.snippetsPreviewFolder = joinPath(this.syncFolder, PREVIEW_DIR_NAME);
|
||||
this._register(this.fileService.watch(environmentService.userRoamingDataHome));
|
||||
this._register(this.fileService.watch(this.snippetsFolder));
|
||||
this._register(this.fileService.onDidFilesChange(e => this.onFileChanges(e)));
|
||||
@@ -67,7 +65,8 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
const local = await this.getSnippetsFileContents();
|
||||
const localSnippets = this.toSnippetsContents(local);
|
||||
const remoteSnippets = this.parseSnippets(remoteUserData.syncData);
|
||||
const { added, updated, remote, removed } = merge(localSnippets, remoteSnippets, localSnippets);
|
||||
const mergeResult = merge(localSnippets, remoteSnippets, localSnippets);
|
||||
const { added, updated, remote, removed } = mergeResult;
|
||||
return {
|
||||
remoteUserData, lastSyncUserData,
|
||||
added, removed, updated, remote, local,
|
||||
@@ -75,6 +74,7 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
hasRemoteChanged: remote !== null,
|
||||
conflicts: [], resolvedConflicts: {}, hasConflicts: false,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews: this.getResourcePreviews(mergeResult)
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
@@ -84,6 +84,7 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
hasRemoteChanged: false,
|
||||
conflicts: [], resolvedConflicts: {}, hasConflicts: false,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews: []
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -91,13 +92,15 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
protected async generatePushPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ISinppetsSyncPreview> {
|
||||
const local = await this.getSnippetsFileContents();
|
||||
const localSnippets = this.toSnippetsContents(local);
|
||||
const { added, removed, updated, remote } = merge(localSnippets, null, null);
|
||||
const mergeResult = merge(localSnippets, null, null);
|
||||
const { added, updated, remote, removed } = mergeResult;
|
||||
return {
|
||||
added, removed, updated, remote, remoteUserData, local, lastSyncUserData, conflicts: [], resolvedConflicts: {},
|
||||
hasLocalChanged: Object.keys(added).length > 0 || removed.length > 0 || Object.keys(updated).length > 0,
|
||||
hasRemoteChanged: remote !== null,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
hasConflicts: false,
|
||||
resourcePreviews: this.getResourcePreviews(mergeResult)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -105,12 +108,14 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
const local = await this.getSnippetsFileContents();
|
||||
const localSnippets = this.toSnippetsContents(local);
|
||||
const snippets = this.parseSnippets(syncData);
|
||||
const { added, updated, removed } = merge(localSnippets, snippets, localSnippets);
|
||||
const mergeResult = merge(localSnippets, snippets, localSnippets);
|
||||
const { added, updated, removed } = mergeResult;
|
||||
return {
|
||||
added, removed, updated, remote: snippets, remoteUserData, local, lastSyncUserData, conflicts: [], resolvedConflicts: {}, hasConflicts: false,
|
||||
hasLocalChanged: Object.keys(added).length > 0 || removed.length > 0 || Object.keys(updated).length > 0,
|
||||
hasRemoteChanged: true,
|
||||
isLastSyncFromCurrentMachine: false,
|
||||
resourcePreviews: this.getResourcePreviews(mergeResult)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -140,10 +145,11 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
}
|
||||
|
||||
const mergeResult = merge(localSnippets, remoteSnippets, lastSyncSnippets, resolvedConflicts);
|
||||
const resourcePreviews = this.getResourcePreviews(mergeResult);
|
||||
|
||||
const conflicts: Conflict[] = [];
|
||||
for (const key of mergeResult.conflicts) {
|
||||
const localPreview = joinPath(this.snippetsPreviewFolder, key);
|
||||
const localPreview = joinPath(this.syncPreviewFolder, key);
|
||||
conflicts.push({ local: localPreview, remote: localPreview.with({ scheme: USER_DATA_SYNC_SCHEME }) });
|
||||
const content = local[key];
|
||||
if (!token.isCancellationRequested) {
|
||||
@@ -177,14 +183,15 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
resolvedConflicts,
|
||||
hasLocalChanged: Object.keys(mergeResult.added).length > 0 || mergeResult.removed.length > 0 || Object.keys(mergeResult.updated).length > 0,
|
||||
hasRemoteChanged: mergeResult.remote !== null,
|
||||
isLastSyncFromCurrentMachine
|
||||
isLastSyncFromCurrentMachine,
|
||||
resourcePreviews
|
||||
};
|
||||
}
|
||||
|
||||
protected async updatePreviewWithConflict(preview: ISinppetsSyncPreview, conflictResource: URI, content: string, token: CancellationToken): Promise<ISinppetsSyncPreview> {
|
||||
const conflict = this.conflicts.filter(({ local, remote }) => isEqual(local, conflictResource) || isEqual(remote, conflictResource))[0];
|
||||
if (conflict) {
|
||||
const key = relativePath(this.snippetsPreviewFolder, conflict.local)!;
|
||||
const key = relativePath(this.syncPreviewFolder, conflict.local)!;
|
||||
preview.resolvedConflicts[key] = content || null;
|
||||
preview = await this.doGeneratePreview(preview.local, preview.remoteUserData, preview.lastSyncUserData, preview.resolvedConflicts, token);
|
||||
}
|
||||
@@ -221,6 +228,47 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
|
||||
}
|
||||
|
||||
private getResourcePreviews(mergeResult: IMergeResult): IResourcePreview[] {
|
||||
const resourcePreviews: IResourcePreview[] = [];
|
||||
for (const key of Object.keys(mergeResult.added)) {
|
||||
resourcePreviews.push({
|
||||
remoteResource: joinPath(this.syncPreviewFolder, key).with({ scheme: USER_DATA_SYNC_SCHEME }),
|
||||
hasConflicts: false,
|
||||
hasLocalChanged: true,
|
||||
hasRemoteChanged: false
|
||||
});
|
||||
}
|
||||
for (const key of Object.keys(mergeResult.updated)) {
|
||||
resourcePreviews.push({
|
||||
remoteResource: joinPath(this.syncPreviewFolder, key).with({ scheme: USER_DATA_SYNC_SCHEME }),
|
||||
localResouce: joinPath(this.snippetsFolder, key),
|
||||
hasConflicts: false,
|
||||
hasLocalChanged: true,
|
||||
hasRemoteChanged: true
|
||||
});
|
||||
}
|
||||
for (const key of mergeResult.removed) {
|
||||
resourcePreviews.push({
|
||||
localResouce: joinPath(this.snippetsFolder, key),
|
||||
hasConflicts: false,
|
||||
hasLocalChanged: true,
|
||||
hasRemoteChanged: false
|
||||
});
|
||||
}
|
||||
for (const key of mergeResult.conflicts) {
|
||||
resourcePreviews.push({
|
||||
localResouce: joinPath(this.snippetsFolder, key),
|
||||
remoteResource: joinPath(this.syncPreviewFolder, key).with({ scheme: USER_DATA_SYNC_SCHEME }),
|
||||
previewResource: joinPath(this.syncPreviewFolder, key),
|
||||
hasConflicts: true,
|
||||
hasLocalChanged: true,
|
||||
hasRemoteChanged: true
|
||||
});
|
||||
}
|
||||
|
||||
return resourcePreviews;
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
await this.clearConflicts();
|
||||
return super.stop();
|
||||
@@ -246,8 +294,8 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
}
|
||||
|
||||
async resolveContent(uri: URI): Promise<string | null> {
|
||||
if (isEqualOrParent(uri.with({ scheme: this.syncFolder.scheme }), this.snippetsPreviewFolder)) {
|
||||
return this.getConflictContent(uri);
|
||||
if (isEqualOrParent(uri.with({ scheme: this.syncFolder.scheme }), this.syncPreviewFolder)) {
|
||||
return this.resolvePreviewContent(uri);
|
||||
}
|
||||
let content = await super.resolveContent(uri);
|
||||
if (content) {
|
||||
@@ -264,11 +312,11 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
|
||||
return null;
|
||||
}
|
||||
|
||||
private async getConflictContent(conflictResource: URI): Promise<string | null> {
|
||||
private async resolvePreviewContent(conflictResource: URI): Promise<string | null> {
|
||||
const syncPreview = await this.getSyncPreviewInProgress();
|
||||
if (syncPreview) {
|
||||
const key = relativePath(this.snippetsPreviewFolder, conflictResource.with({ scheme: this.snippetsPreviewFolder.scheme }))!;
|
||||
if (conflictResource.scheme === this.snippetsPreviewFolder.scheme) {
|
||||
const key = relativePath(this.syncPreviewFolder, conflictResource.with({ scheme: this.syncPreviewFolder.scheme }))!;
|
||||
if (conflictResource.scheme === this.syncPreviewFolder.scheme) {
|
||||
return (syncPreview as ISinppetsSyncPreview).local[key] ? (syncPreview as ISinppetsSyncPreview).local[key].value.toString() : null;
|
||||
} else if (syncPreview.remoteUserData && syncPreview.remoteUserData.syncData) {
|
||||
const snippets = this.parseSnippets(syncPreview.remoteUserData.syncData);
|
||||
|
||||
@@ -81,6 +81,12 @@ export class UserDataAutoSyncService extends UserDataAutoSyncEnablementService i
|
||||
private readonly _onError: Emitter<UserDataSyncError> = this._register(new Emitter<UserDataSyncError>());
|
||||
readonly onError: Event<UserDataSyncError> = this._onError.event;
|
||||
|
||||
private readonly _onTurnOnSync: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onTurnOnSync: Event<void> = this._onTurnOnSync.event;
|
||||
|
||||
private readonly _onDidTurnOnSync: Emitter<UserDataSyncError | undefined> = this._register(new Emitter<UserDataSyncError | undefined>());
|
||||
readonly onDidTurnOnSync: Event<UserDataSyncError | undefined> = this._onDidTurnOnSync.event;
|
||||
|
||||
constructor(
|
||||
@IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
|
||||
@IUserDataSyncResourceEnablementService private readonly userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService,
|
||||
@@ -140,22 +146,30 @@ export class UserDataAutoSyncService extends UserDataAutoSyncEnablementService i
|
||||
}
|
||||
|
||||
async turnOn(pullFirst: boolean): Promise<void> {
|
||||
this.stopDisableMachineEventually();
|
||||
this._onTurnOnSync.fire();
|
||||
|
||||
if (pullFirst) {
|
||||
await this.userDataSyncService.pull();
|
||||
} else {
|
||||
await this.userDataSyncService.sync();
|
||||
try {
|
||||
this.stopDisableMachineEventually();
|
||||
|
||||
if (pullFirst) {
|
||||
await this.userDataSyncService.pull();
|
||||
} else {
|
||||
await this.userDataSyncService.sync();
|
||||
}
|
||||
|
||||
this.setEnablement(true);
|
||||
this._onDidTurnOnSync.fire(undefined);
|
||||
} catch (error) {
|
||||
this._onDidTurnOnSync.fire(error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.setEnablement(true);
|
||||
}
|
||||
|
||||
async turnOff(everywhere: boolean, softTurnOffOnError?: boolean, donotRemoveMachine?: boolean): Promise<void> {
|
||||
try {
|
||||
|
||||
// Remove machine
|
||||
if (!donotRemoveMachine) {
|
||||
if (this.userDataSyncAccountService.account && !donotRemoveMachine) {
|
||||
await this.userDataSyncMachinesService.removeCurrentMachine();
|
||||
}
|
||||
|
||||
|
||||
@@ -293,13 +293,21 @@ export interface ISyncData {
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface ISyncPreview {
|
||||
readonly remoteUserData: IRemoteUserData;
|
||||
readonly lastSyncUserData: IRemoteUserData | null;
|
||||
export interface IResourcePreview {
|
||||
readonly remoteResource?: URI;
|
||||
readonly localResouce?: URI;
|
||||
readonly previewResource?: URI;
|
||||
readonly hasLocalChanged: boolean;
|
||||
readonly hasRemoteChanged: boolean;
|
||||
readonly hasConflicts: boolean;
|
||||
}
|
||||
|
||||
export interface ISyncResourcePreview {
|
||||
readonly isLastSyncFromCurrentMachine: boolean;
|
||||
readonly hasLocalChanged: boolean;
|
||||
readonly hasRemoteChanged: boolean;
|
||||
readonly hasConflicts: boolean;
|
||||
readonly resourcePreviews: IResourcePreview[];
|
||||
}
|
||||
|
||||
export interface IUserDataSynchroniser {
|
||||
@@ -317,7 +325,7 @@ export interface IUserDataSynchroniser {
|
||||
replace(uri: URI): Promise<boolean>;
|
||||
stop(): Promise<void>;
|
||||
|
||||
generateSyncPreview(): Promise<ISyncPreview | null>
|
||||
generateSyncPreview(): Promise<ISyncResourcePreview | null>
|
||||
hasPreviouslySynced(): Promise<boolean>
|
||||
hasLocalData(): Promise<boolean>;
|
||||
resetLocal(): Promise<void>;
|
||||
@@ -357,6 +365,7 @@ export interface IUserDataSyncService {
|
||||
|
||||
readonly status: SyncStatus;
|
||||
readonly onDidChangeStatus: Event<SyncStatus>;
|
||||
readonly onSynchronizeResource: Event<SyncResource>;
|
||||
|
||||
readonly conflicts: SyncResourceConflicts[];
|
||||
readonly onDidChangeConflicts: Event<SyncResourceConflicts[]>;
|
||||
@@ -390,6 +399,8 @@ export interface IUserDataSyncService {
|
||||
export const IUserDataAutoSyncService = createDecorator<IUserDataAutoSyncService>('IUserDataAutoSyncService');
|
||||
export interface IUserDataAutoSyncService {
|
||||
_serviceBrand: any;
|
||||
readonly onTurnOnSync: Event<void>
|
||||
readonly onDidTurnOnSync: Event<UserDataSyncError | undefined>
|
||||
readonly onError: Event<UserDataSyncError>;
|
||||
readonly onDidChangeEnablement: Event<boolean>;
|
||||
isEnabled(): boolean;
|
||||
|
||||
@@ -22,6 +22,7 @@ export class UserDataSyncChannel implements IServerChannel {
|
||||
listen(_: unknown, event: string): Event<any> {
|
||||
switch (event) {
|
||||
case 'onDidChangeStatus': return this.service.onDidChangeStatus;
|
||||
case 'onSynchronizeResource': return this.service.onSynchronizeResource;
|
||||
case 'onDidChangeConflicts': return this.service.onDidChangeConflicts;
|
||||
case 'onDidChangeLocal': return this.service.onDidChangeLocal;
|
||||
case 'onDidChangeLastSyncTime': return this.service.onDidChangeLastSyncTime;
|
||||
@@ -68,6 +69,8 @@ export class UserDataAutoSyncChannel implements IServerChannel {
|
||||
|
||||
listen(_: unknown, event: string): Event<any> {
|
||||
switch (event) {
|
||||
case 'onTurnOnSync': return this.service.onTurnOnSync;
|
||||
case 'onDidTurnOnSync': return this.service.onDidTurnOnSync;
|
||||
case 'onError': return this.service.onError;
|
||||
}
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
|
||||
@@ -22,8 +22,9 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IHeaders } from 'vs/base/parts/request/common/request';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
type SyncClassification = {
|
||||
type SyncErrorClassification = {
|
||||
resource?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
|
||||
executionId?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
|
||||
};
|
||||
|
||||
const LAST_SYNC_TIME_KEY = 'sync.lastSyncTime';
|
||||
@@ -39,6 +40,9 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
private _onDidChangeStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
|
||||
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangeStatus.event;
|
||||
|
||||
private _onSynchronizeResource: Emitter<SyncResource> = this._register(new Emitter<SyncResource>());
|
||||
readonly onSynchronizeResource: Event<SyncResource> = this._onSynchronizeResource.event;
|
||||
|
||||
readonly onDidChangeLocal: Event<SyncResource>;
|
||||
|
||||
private _conflicts: SyncResourceConflicts[] = [];
|
||||
@@ -91,6 +95,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
try {
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
try {
|
||||
this._onSynchronizeResource.fire(synchroniser.resource);
|
||||
await synchroniser.pull();
|
||||
} catch (e) {
|
||||
this.handleSynchronizerError(e, synchroniser.resource);
|
||||
@@ -99,7 +104,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
this.updateLastSyncTime();
|
||||
} catch (error) {
|
||||
if (error instanceof UserDataSyncError) {
|
||||
this.telemetryService.publicLog2<{ resource?: string }, SyncClassification>(`sync/error/${error.code}`, { resource: error.resource });
|
||||
this.telemetryService.publicLog2<{ resource?: string, executionId?: string }, SyncErrorClassification>(`sync/error/${error.code}`, { resource: error.resource });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
@@ -118,7 +123,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
this.updateLastSyncTime();
|
||||
} catch (error) {
|
||||
if (error instanceof UserDataSyncError) {
|
||||
this.telemetryService.publicLog2<{ resource?: string }, SyncClassification>(`sync/error/${error.code}`, { resource: error.resource });
|
||||
this.telemetryService.publicLog2<{ resource?: string, executionId?: string }, SyncErrorClassification>(`sync/error/${error.code}`, { resource: error.resource });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
@@ -132,8 +137,16 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
|
||||
async createSyncTask(): Promise<ISyncTask> {
|
||||
this.telemetryService.publicLog2('sync/getmanifest');
|
||||
const syncHeaders: IHeaders = { 'X-Execution-Id': generateUuid() };
|
||||
const manifest = await this.userDataSyncStoreService.manifest(syncHeaders);
|
||||
const executionId = generateUuid();
|
||||
let manifest: IUserDataManifest | null;
|
||||
try {
|
||||
manifest = await this.userDataSyncStoreService.manifest({ 'X-Execution-Id': executionId });
|
||||
} catch (error) {
|
||||
if (error instanceof UserDataSyncError) {
|
||||
this.telemetryService.publicLog2<{ resource?: string, executionId?: string }, SyncErrorClassification>(`sync/error/${error.code}`, { resource: error.resource, executionId });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
let executed = false;
|
||||
const that = this;
|
||||
@@ -143,12 +156,12 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
if (executed) {
|
||||
throw new Error('Can run a task only once');
|
||||
}
|
||||
return that.doSync(manifest, syncHeaders, token);
|
||||
return that.doSync(manifest, executionId, token);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private async doSync(manifest: IUserDataManifest | null, syncHeaders: IHeaders, token: CancellationToken): Promise<void> {
|
||||
private async doSync(manifest: IUserDataManifest | null, executionId: string, token: CancellationToken): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
|
||||
if (!this.recoveredSettings) {
|
||||
@@ -169,12 +182,15 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
this.setStatus(SyncStatus.Syncing);
|
||||
}
|
||||
|
||||
const syncHeaders: IHeaders = { 'X-Execution-Id': executionId };
|
||||
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
// Return if cancellation is requested
|
||||
if (token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this._onSynchronizeResource.fire(synchroniser.resource);
|
||||
await synchroniser.sync(manifest, syncHeaders);
|
||||
} catch (e) {
|
||||
this.handleSynchronizerError(e, synchroniser.resource);
|
||||
@@ -186,7 +202,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
this.updateLastSyncTime();
|
||||
} catch (error) {
|
||||
if (error instanceof UserDataSyncError) {
|
||||
this.telemetryService.publicLog2<{ resource?: string }, SyncClassification>(`sync/error/${error.code}`, { resource: error.resource });
|
||||
this.telemetryService.publicLog2<{ resource?: string, executionId?: string }, SyncErrorClassification>(`sync/error/${error.code}`, { resource: error.resource, executionId });
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { IUserDataSyncStoreService, SyncResource, SyncStatus, IUserDataSyncResourceEnablementService, IRemoteUserData, ISyncData, ISyncPreview } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncStoreService, SyncResource, SyncStatus, IUserDataSyncResourceEnablementService, IRemoteUserData, ISyncData } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { UserDataSyncClient, UserDataSyncTestServer } from 'vs/platform/userDataSync/test/common/userDataSyncClient';
|
||||
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { AbstractSynchroniser, ISyncResourcePreview } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
interface ITestSyncPreview extends ISyncPreview {
|
||||
interface ITestSyncPreview extends ISyncResourcePreview {
|
||||
ref?: string;
|
||||
}
|
||||
|
||||
@@ -41,25 +41,25 @@ class TestSynchroniser extends AbstractSynchroniser {
|
||||
}
|
||||
|
||||
protected async generatePullPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ITestSyncPreview> {
|
||||
return { hasLocalChanged: false, hasRemoteChanged: false, isLastSyncFromCurrentMachine: false, hasConflicts: this.syncResult.hasConflicts, remoteUserData, lastSyncUserData };
|
||||
return { hasLocalChanged: false, hasRemoteChanged: false, isLastSyncFromCurrentMachine: false, hasConflicts: this.syncResult.hasConflicts, remoteUserData, lastSyncUserData, resourcePreviews: [] };
|
||||
}
|
||||
|
||||
protected async generatePushPreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ITestSyncPreview> {
|
||||
return { hasLocalChanged: false, hasRemoteChanged: false, isLastSyncFromCurrentMachine: false, hasConflicts: this.syncResult.hasConflicts, remoteUserData, lastSyncUserData };
|
||||
return { hasLocalChanged: false, hasRemoteChanged: false, isLastSyncFromCurrentMachine: false, hasConflicts: this.syncResult.hasConflicts, remoteUserData, lastSyncUserData, resourcePreviews: [] };
|
||||
}
|
||||
|
||||
protected async generateReplacePreview(syncData: ISyncData, remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise<ITestSyncPreview> {
|
||||
return { hasLocalChanged: false, hasRemoteChanged: false, isLastSyncFromCurrentMachine: false, hasConflicts: this.syncResult.hasConflicts, remoteUserData, lastSyncUserData };
|
||||
return { hasLocalChanged: false, hasRemoteChanged: false, isLastSyncFromCurrentMachine: false, hasConflicts: this.syncResult.hasConflicts, remoteUserData, lastSyncUserData, resourcePreviews: [] };
|
||||
}
|
||||
|
||||
protected async generatePreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken): Promise<ITestSyncPreview> {
|
||||
if (this.syncResult.hasError) {
|
||||
throw new Error('failed');
|
||||
}
|
||||
return { ref: remoteUserData.ref, hasLocalChanged: false, hasRemoteChanged: false, isLastSyncFromCurrentMachine: false, hasConflicts: this.syncResult.hasConflicts, remoteUserData, lastSyncUserData };
|
||||
return { ref: remoteUserData.ref, hasLocalChanged: false, hasRemoteChanged: false, isLastSyncFromCurrentMachine: false, hasConflicts: this.syncResult.hasConflicts, remoteUserData, lastSyncUserData, resourcePreviews: [] };
|
||||
}
|
||||
|
||||
protected async updatePreviewWithConflict(preview: ISyncPreview, conflictResource: URI, conflictContent: string): Promise<ISyncPreview> {
|
||||
protected async updatePreviewWithConflict(preview: ISyncResourcePreview, conflictResource: URI, conflictContent: string): Promise<ISyncResourcePreview> {
|
||||
return preview;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user