Merge from vscode 1df23554b2e3d5f1efc6fbc76ee61d3f7f186c6d

This commit is contained in:
ADS Merger
2020-03-12 06:51:03 +00:00
parent a68a6b9e44
commit b5592959c7
56 changed files with 1091 additions and 558 deletions

View File

@@ -7,7 +7,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { IFileService, IFileContent, FileChangesEvent, FileSystemProviderError, FileSystemProviderErrorCode, FileOperationResult, FileOperationError } from 'vs/platform/files/common/files';
import { VSBuffer } from 'vs/base/common/buffer';
import { URI } from 'vs/base/common/uri';
import { SyncSource, SyncStatus, IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, UserDataSyncError, IUserDataSyncLogService, IUserDataSyncUtilService, ResourceKey, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { SyncResource, SyncStatus, IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, UserDataSyncError, IUserDataSyncLogService, IUserDataSyncUtilService, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { joinPath, dirname } from 'vs/base/common/resources';
import { CancelablePromise } from 'vs/base/common/async';
@@ -19,6 +19,7 @@ import { IStringDictionary } from 'vs/base/common/collections';
import { localize } from 'vs/nls';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { isString } from 'vs/base/common/types';
import { uppercaseFirstLetter } from 'vs/base/common/strings';
type SyncSourceClassification = {
source?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
@@ -54,10 +55,10 @@ export abstract class AbstractSynchroniser extends Disposable {
readonly onDidChangeLocal: Event<void> = this._onDidChangeLocal.event;
protected readonly lastSyncResource: URI;
protected readonly syncResourceLogLabel: string;
constructor(
readonly source: SyncSource,
readonly resourceKey: ResourceKey,
readonly resource: SyncResource,
@IFileService protected readonly fileService: IFileService,
@IEnvironmentService environmentService: IEnvironmentService,
@IUserDataSyncStoreService protected readonly userDataSyncStoreService: IUserDataSyncStoreService,
@@ -68,8 +69,9 @@ export abstract class AbstractSynchroniser extends Disposable {
@IConfigurationService protected readonly configurationService: IConfigurationService,
) {
super();
this.syncFolder = joinPath(environmentService.userDataSyncHome, source);
this.lastSyncResource = joinPath(this.syncFolder, `lastSync${this.resourceKey}.json`);
this.syncResourceLogLabel = uppercaseFirstLetter(this.resource);
this.syncFolder = joinPath(environmentService.userDataSyncHome, resource);
this.lastSyncResource = joinPath(this.syncFolder, `lastSync${this.resource}.json`);
}
protected setStatus(status: SyncStatus): void {
@@ -79,32 +81,32 @@ export abstract class AbstractSynchroniser extends Disposable {
this._onDidChangStatus.fire(status);
if (status === SyncStatus.HasConflicts) {
// Log to telemetry when there is a sync conflict
this.telemetryService.publicLog2<{ source: string }, SyncSourceClassification>('sync/conflictsDetected', { source: this.source });
this.telemetryService.publicLog2<{ source: string }, SyncSourceClassification>('sync/conflictsDetected', { source: this.resource });
}
if (oldStatus === SyncStatus.HasConflicts && status === SyncStatus.Idle) {
// Log to telemetry when conflicts are resolved
this.telemetryService.publicLog2<{ source: string }, SyncSourceClassification>('sync/conflictsResolved', { source: this.source });
this.telemetryService.publicLog2<{ source: string }, SyncSourceClassification>('sync/conflictsResolved', { source: this.resource });
}
}
}
protected isEnabled(): boolean { return this.userDataSyncEnablementService.isResourceEnabled(this.resourceKey); }
protected isEnabled(): boolean { return this.userDataSyncEnablementService.isResourceEnabled(this.resource); }
async sync(ref?: string): Promise<void> {
if (!this.isEnabled()) {
this.logService.info(`${this.source}: Skipped synchronizing ${this.source.toLowerCase()} as it is disabled.`);
this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing ${this.resource.toLowerCase()} as it is disabled.`);
return;
}
if (this.status === SyncStatus.HasConflicts) {
this.logService.info(`${this.source}: Skipped synchronizing ${this.source.toLowerCase()} as there are conflicts.`);
this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing ${this.resource.toLowerCase()} as there are conflicts.`);
return;
}
if (this.status === SyncStatus.Syncing) {
this.logService.info(`${this.source}: Skipped synchronizing ${this.source.toLowerCase()} as it is running already.`);
this.logService.info(`${this.syncResourceLogLabel}: Skipped synchronizing ${this.resource.toLowerCase()} as it is running already.`);
return;
}
this.logService.trace(`${this.source}: Started synchronizing ${this.source.toLowerCase()}...`);
this.logService.trace(`${this.syncResourceLogLabel}: Started synchronizing ${this.resource.toLowerCase()}...`);
this.setStatus(SyncStatus.Syncing);
const lastSyncUserData = await this.getLastSyncUserData();
@@ -114,9 +116,9 @@ export abstract class AbstractSynchroniser extends Disposable {
try {
status = await this.doSync(remoteUserData, lastSyncUserData);
if (status === SyncStatus.HasConflicts) {
this.logService.info(`${this.source}: Detected conflicts while synchronizing ${this.source.toLowerCase()}.`);
this.logService.info(`${this.syncResourceLogLabel}: Detected conflicts while synchronizing ${this.resource.toLowerCase()}.`);
} else if (status === SyncStatus.Idle) {
this.logService.trace(`${this.source}: Finished synchronizing ${this.source.toLowerCase()}.`);
this.logService.trace(`${this.syncResourceLogLabel}: Finished synchronizing ${this.resource.toLowerCase()}.`);
}
} finally {
this.setStatus(status);
@@ -126,8 +128,8 @@ export abstract class AbstractSynchroniser extends Disposable {
protected async doSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null): Promise<SyncStatus> {
if (remoteUserData.syncData && remoteUserData.syncData.version > this.version) {
// current version is not compatible with cloud version
this.telemetryService.publicLog2<{ source: string }, SyncSourceClassification>('sync/incompatible', { source: this.source });
throw new UserDataSyncError(localize('incompatible', "Cannot sync {0} as its version {1} is not compatible with cloud {2}", this.source, this.version, remoteUserData.syncData.version), UserDataSyncErrorCode.Incompatible, this.source);
this.telemetryService.publicLog2<{ source: string }, SyncSourceClassification>('sync/incompatible', { source: this.resource });
throw new UserDataSyncError(localize('incompatible', "Cannot sync {0} as its version {1} is not compatible with cloud {2}", this.resource, this.version, remoteUserData.syncData.version), UserDataSyncErrorCode.Incompatible, this.resource);
}
try {
const status = await this.performSync(remoteUserData, lastSyncUserData);
@@ -137,7 +139,7 @@ export abstract class AbstractSynchroniser extends Disposable {
switch (e.code) {
case UserDataSyncErrorCode.RemotePreconditionFailed:
// Rejected as there is a new remote version. Syncing again,
this.logService.info(`${this.source}: Failed to synchronize as there is a new remote version available. Synchronizing again...`);
this.logService.info(`${this.syncResourceLogLabel}: Failed to synchronize as there is a new remote version available. Synchronizing again...`);
// Avoid cache and get latest remote user data - https://github.com/microsoft/vscode/issues/90624
remoteUserData = await this.getRemoteUserData(null);
return this.doSync(remoteUserData, lastSyncUserData);
@@ -163,7 +165,7 @@ export abstract class AbstractSynchroniser extends Disposable {
}
async getLocalBackupContent(ref?: string): Promise<string | null> {
return this.userDataSyncBackupStoreService.resolveContent(this.resourceKey, ref);
return this.userDataSyncBackupStoreService.resolveContent(this.resource, ref);
}
async resetLocal(): Promise<void> {
@@ -225,23 +227,23 @@ export abstract class AbstractSynchroniser extends Disposable {
private async getUserData(refOrLastSyncData: string | IRemoteUserData | null): Promise<IUserData> {
if (isString(refOrLastSyncData)) {
const content = await this.userDataSyncStoreService.resolveContent(this.resourceKey, refOrLastSyncData);
const content = await this.userDataSyncStoreService.resolveContent(this.resource, refOrLastSyncData);
return { ref: refOrLastSyncData, content };
} else {
const lastSyncUserData: IUserData | null = refOrLastSyncData ? { ref: refOrLastSyncData.ref, content: refOrLastSyncData.syncData ? JSON.stringify(refOrLastSyncData.syncData) : null } : null;
return this.userDataSyncStoreService.read(this.resourceKey, lastSyncUserData, this.source);
return this.userDataSyncStoreService.read(this.resource, lastSyncUserData);
}
}
protected async updateRemoteUserData(content: string, ref: string | null): Promise<IRemoteUserData> {
const syncData: ISyncData = { version: this.version, content };
ref = await this.userDataSyncStoreService.write(this.resourceKey, JSON.stringify(syncData), ref, this.source);
ref = await this.userDataSyncStoreService.write(this.resource, JSON.stringify(syncData), ref);
return { ref, syncData };
}
protected async backupLocal(content: string): Promise<void> {
const syncData: ISyncData = { version: this.version, content };
return this.userDataSyncBackupStoreService.backup(this.resourceKey, JSON.stringify(syncData));
return this.userDataSyncBackupStoreService.backup(this.resource, JSON.stringify(syncData));
}
protected abstract readonly version: number;
@@ -264,8 +266,7 @@ export abstract class AbstractFileSynchroniser extends AbstractSynchroniser {
constructor(
protected readonly file: URI,
source: SyncSource,
resourceKey: ResourceKey,
resource: SyncResource,
@IFileService fileService: IFileService,
@IEnvironmentService environmentService: IEnvironmentService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@@ -275,14 +276,14 @@ export abstract class AbstractFileSynchroniser extends AbstractSynchroniser {
@IUserDataSyncLogService logService: IUserDataSyncLogService,
@IConfigurationService configurationService: IConfigurationService,
) {
super(source, resourceKey, fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService);
super(resource, fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService);
this._register(this.fileService.watch(dirname(file)));
this._register(this.fileService.onDidFilesChange(e => this.onFileChanges(e)));
}
async stop(): Promise<void> {
this.cancel();
this.logService.trace(`${this.source}: Stopped synchronizing ${this.source.toLowerCase()}.`);
this.logService.trace(`${this.syncResourceLogLabel}: Stopped synchronizing ${this.resource.toLowerCase()}.`);
try {
await this.fileService.del(this.conflictsPreviewResource);
} catch (e) { /* ignore */ }
@@ -362,8 +363,7 @@ export abstract class AbstractJsonFileSynchroniser extends AbstractFileSynchroni
constructor(
file: URI,
source: SyncSource,
resourceKey: ResourceKey,
resource: SyncResource,
@IFileService fileService: IFileService,
@IEnvironmentService environmentService: IEnvironmentService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@@ -374,7 +374,7 @@ export abstract class AbstractJsonFileSynchroniser extends AbstractFileSynchroni
@IUserDataSyncUtilService protected readonly userDataSyncUtilService: IUserDataSyncUtilService,
@IConfigurationService configurationService: IConfigurationService,
) {
super(file, source, resourceKey, fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService);
super(file, resource, fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService);
}
protected hasErrors(content: string): boolean {

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncSource, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncResource, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { Event } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
@@ -50,7 +50,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
@IUserDataSyncEnablementService userDataSyncEnablementService: IUserDataSyncEnablementService,
@ITelemetryService telemetryService: ITelemetryService,
) {
super(SyncSource.Extensions, 'extensions', fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService);
super(SyncResource.Extensions, fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService);
this._register(
Event.debounce(
Event.any<any>(
@@ -62,14 +62,14 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
async pull(): Promise<void> {
if (!this.isEnabled()) {
this.logService.info('Extensions: Skipped pulling extensions as it is disabled.');
this.logService.info(`${this.syncResourceLogLabel}: Skipped pulling extensions as it is disabled.`);
return;
}
this.stop();
try {
this.logService.info('Extensions: Started pulling extensions...');
this.logService.info(`${this.syncResourceLogLabel}: Started pulling extensions...`);
this.setStatus(SyncStatus.Syncing);
const lastSyncUserData = await this.getLastSyncUserData<ILastSyncUserData>();
@@ -84,10 +84,10 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
// No remote exists to pull
else {
this.logService.info('Extensions: Remote extensions does not exist.');
this.logService.info(`${this.syncResourceLogLabel}: Remote extensions does not exist.`);
}
this.logService.info('Extensions: Finished pulling extensions.');
this.logService.info(`${this.syncResourceLogLabel}: Finished pulling extensions.`);
} finally {
this.setStatus(SyncStatus.Idle);
}
@@ -95,14 +95,14 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
async push(): Promise<void> {
if (!this.isEnabled()) {
this.logService.info('Extensions: Skipped pushing extensions as it is disabled.');
this.logService.info(`${this.syncResourceLogLabel}: Skipped pushing extensions as it is disabled.`);
return;
}
this.stop();
try {
this.logService.info('Extensions: Started pushing extensions...');
this.logService.info(`${this.syncResourceLogLabel}: Started pushing extensions...`);
this.setStatus(SyncStatus.Syncing);
const localExtensions = await this.getLocalExtensions();
@@ -111,7 +111,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
await this.apply({ added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData }, true);
this.logService.info('Extensions: Finished pushing extensions.');
this.logService.info(`${this.syncResourceLogLabel}: Finished pushing extensions.`);
} finally {
this.setStatus(SyncStatus.Idle);
}
@@ -148,7 +148,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
}
accept(content: string): Promise<void> {
throw new Error('Extensions: Conflicts should not occur');
throw new Error(`${this.syncResourceLogLabel}: Conflicts should not occur`);
}
async hasLocalData(): Promise<boolean> {
@@ -177,9 +177,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
const localExtensions = await this.getLocalExtensions();
if (remoteExtensions) {
this.logService.trace('Extensions: Merging remote extensions with local extensions...');
this.logService.trace(`${this.syncResourceLogLabel}: Merging remote extensions with local extensions...`);
} else {
this.logService.trace('Extensions: Remote extensions does not exist. Synchronizing extensions for the first time.');
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, this.getIgnoredExtensions());
@@ -196,7 +196,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
const hasChanges = added.length || removed.length || updated.length || remote;
if (!hasChanges) {
this.logService.info('Extensions: No changes found during synchronizing extensions.');
this.logService.info(`${this.syncResourceLogLabel}: No changes found during synchronizing extensions.`);
}
if (added.length || removed.length || updated.length) {
@@ -208,17 +208,17 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
if (remote) {
// update remote
this.logService.trace('Extensions: Updating remote extensions...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating remote extensions...`);
const content = JSON.stringify(remote);
remoteUserData = await this.updateRemoteUserData(content, forcePush ? null : remoteUserData.ref);
this.logService.info('Extensions: Updated remote extensions');
this.logService.info(`${this.syncResourceLogLabel}: Updated remote extensions`);
}
if (lastSyncUserData?.ref !== remoteUserData.ref) {
// update last sync
this.logService.trace('Extensions: Updating last synchronized extensions...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized extensions...`);
await this.updateLastSyncUserData(remoteUserData, { skippedExtensions });
this.logService.info('Extensions: Updated last synchronized extensions');
this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized extensions`);
}
}
@@ -230,9 +230,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
const installedExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User);
const extensionsToRemove = installedExtensions.filter(({ identifier }) => removed.some(r => areSameExtensions(identifier, r)));
await Promise.all(extensionsToRemove.map(async extensionToRemove => {
this.logService.trace('Extensions: Uninstalling local extension...', extensionToRemove.identifier.id);
this.logService.trace(`${this.syncResourceLogLabel}: Uninstalling local extension...', extensionToRemove.identifier.i`);
await this.extensionManagementService.uninstall(extensionToRemove);
this.logService.info('Extensions: Uninstalled local extension.', extensionToRemove.identifier.id);
this.logService.info(`${this.syncResourceLogLabel}: Uninstalled local extension.', extensionToRemove.identifier.i`);
removeFromSkipped.push(extensionToRemove.identifier);
}));
}
@@ -245,13 +245,13 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
// Builtin Extension: Sync only enablement state
if (installedExtension && installedExtension.type === ExtensionType.System) {
if (e.disabled) {
this.logService.trace('Extensions: Disabling extension...', e.identifier.id);
this.logService.trace(`${this.syncResourceLogLabel}: Disabling extension...', e.identifier.i`);
await this.extensionEnablementService.disableExtension(e.identifier);
this.logService.info('Extensions: Disabled extension', e.identifier.id);
this.logService.info(`${this.syncResourceLogLabel}: Disabled extension', e.identifier.i`);
} else {
this.logService.trace('Extensions: Enabling extension...', e.identifier.id);
this.logService.trace(`${this.syncResourceLogLabel}: Enabling extension...', e.identifier.i`);
await this.extensionEnablementService.enableExtension(e.identifier);
this.logService.info('Extensions: Enabled extension', e.identifier.id);
this.logService.info(`${this.syncResourceLogLabel}: Enabled extension', e.identifier.i`);
}
removeFromSkipped.push(e.identifier);
return;
@@ -261,19 +261,19 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
if (extension) {
try {
if (e.disabled) {
this.logService.trace('Extensions: Disabling extension...', e.identifier.id, extension.version);
this.logService.trace(`${this.syncResourceLogLabel}: Disabling extension...', e.identifier.id, extension.versio`);
await this.extensionEnablementService.disableExtension(extension.identifier);
this.logService.info('Extensions: Disabled extension', e.identifier.id, extension.version);
this.logService.info(`${this.syncResourceLogLabel}: Disabled extension', e.identifier.id, extension.versio`);
} else {
this.logService.trace('Extensions: Enabling extension...', e.identifier.id, extension.version);
this.logService.trace(`${this.syncResourceLogLabel}: Enabling extension...', e.identifier.id, extension.versio`);
await this.extensionEnablementService.enableExtension(extension.identifier);
this.logService.info('Extensions: Enabled extension', e.identifier.id, extension.version);
this.logService.info(`${this.syncResourceLogLabel}: Enabled extension', e.identifier.id, extension.versio`);
}
// Install only if the extension does not exist
if (!installedExtension || installedExtension.manifest.version !== extension.version) {
this.logService.trace('Extensions: Installing extension...', e.identifier.id, extension.version);
this.logService.trace(`${this.syncResourceLogLabel}: Installing extension...', e.identifier.id, extension.versio`);
await this.extensionManagementService.installFromGallery(extension);
this.logService.info('Extensions: Installed extension.', e.identifier.id, extension.version);
this.logService.info(`${this.syncResourceLogLabel}: Installed extension.', e.identifier.id, extension.versio`);
removeFromSkipped.push(extension.identifier);
}
} catch (error) {

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncSource, IUserDataSynchroniser, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncResource, IUserDataSynchroniser, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { VSBuffer } from 'vs/base/common/buffer';
import { Event } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@@ -41,21 +41,21 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
@ITelemetryService telemetryService: ITelemetryService,
@IConfigurationService configurationService: IConfigurationService,
) {
super(SyncSource.GlobalState, 'globalState', fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService);
super(SyncResource.GlobalState, fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, configurationService);
this._register(this.fileService.watch(dirname(this.environmentService.argvResource)));
this._register(Event.filter(this.fileService.onDidFilesChange, e => e.contains(this.environmentService.argvResource))(() => this._onDidChangeLocal.fire()));
}
async pull(): Promise<void> {
if (!this.isEnabled()) {
this.logService.info('UI State: Skipped pulling ui state as it is disabled.');
this.logService.info(`${this.syncResourceLogLabel}: Skipped pulling ui state as it is disabled.`);
return;
}
this.stop();
try {
this.logService.info('UI State: Started pulling ui state...');
this.logService.info(`${this.syncResourceLogLabel}: Started pulling ui state...`);
this.setStatus(SyncStatus.Syncing);
const lastSyncUserData = await this.getLastSyncUserData();
@@ -69,10 +69,10 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
// No remote exists to pull
else {
this.logService.info('UI State: Remote UI state does not exist.');
this.logService.info(`${this.syncResourceLogLabel}: Remote UI state does not exist.`);
}
this.logService.info('UI State: Finished pulling UI state.');
this.logService.info(`${this.syncResourceLogLabel}: Finished pulling UI state.`);
} finally {
this.setStatus(SyncStatus.Idle);
}
@@ -80,14 +80,14 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
async push(): Promise<void> {
if (!this.isEnabled()) {
this.logService.info('UI State: Skipped pushing UI State as it is disabled.');
this.logService.info(`${this.syncResourceLogLabel}: Skipped pushing UI State as it is disabled.`);
return;
}
this.stop();
try {
this.logService.info('UI State: Started pushing UI State...');
this.logService.info(`${this.syncResourceLogLabel}: Started pushing UI State...`);
this.setStatus(SyncStatus.Syncing);
const localUserData = await this.getLocalGlobalState();
@@ -95,7 +95,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
await this.apply({ local: undefined, remote: localUserData, remoteUserData, localUserData, lastSyncUserData }, true);
this.logService.info('UI State: Finished pushing UI State.');
this.logService.info(`${this.syncResourceLogLabel}: Finished pushing UI State.`);
} finally {
this.setStatus(SyncStatus.Idle);
}
@@ -132,7 +132,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
}
accept(content: string): Promise<void> {
throw new Error('UI State: Conflicts should not occur');
throw new Error(`${this.syncResourceLogLabel}: Conflicts should not occur`);
}
async hasLocalData(): Promise<boolean> {
@@ -160,9 +160,9 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
const localGloablState = await this.getLocalGlobalState();
if (remoteGlobalState) {
this.logService.trace('UI State: Merging remote ui state with local ui state...');
this.logService.trace(`${this.syncResourceLogLabel}: Merging remote ui state with local ui state...`);
} else {
this.logService.trace('UI State: Remote ui state does not exist. Synchronizing ui state for the first time.');
this.logService.trace(`${this.syncResourceLogLabel}: Remote ui state does not exist. Synchronizing ui state for the first time.`);
}
const { local, remote } = merge(localGloablState, remoteGlobalState, lastSyncGlobalState);
@@ -175,30 +175,30 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
const hasChanges = local || remote;
if (!hasChanges) {
this.logService.info('UI State: No changes found during synchronizing ui state.');
this.logService.info(`${this.syncResourceLogLabel}: No changes found during synchronizing ui state.`);
}
if (local) {
// update local
this.logService.trace('UI State: Updating local ui state...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating local ui state...`);
await this.backupLocal(JSON.stringify(localUserData));
await this.writeLocalGlobalState(local);
this.logService.info('UI State: Updated local ui state');
this.logService.info(`${this.syncResourceLogLabel}: Updated local ui state`);
}
if (remote) {
// update remote
this.logService.trace('UI State: Updating remote ui state...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating remote ui state...`);
const content = JSON.stringify(remote);
remoteUserData = await this.updateRemoteUserData(content, forcePush ? null : remoteUserData.ref);
this.logService.info('UI State: Updated remote ui state');
this.logService.info(`${this.syncResourceLogLabel}: Updated remote ui state`);
}
if (lastSyncUserData?.ref !== remoteUserData.ref) {
// update last sync
this.logService.trace('UI State: Updating last synchronized ui state...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized ui state...`);
await this.updateLastSyncUserData(remoteUserData);
this.logService.info('UI State: Updated last synchronized ui state');
this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized ui state`);
}
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, SyncSource, IUserDataSynchroniser, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, SyncResource, IUserDataSynchroniser, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { merge } from 'vs/platform/userDataSync/common/keybindingsMerge';
import { VSBuffer } from 'vs/base/common/buffer';
import { parse } from 'vs/base/common/json';
@@ -43,19 +43,19 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
@IUserDataSyncUtilService userDataSyncUtilService: IUserDataSyncUtilService,
@ITelemetryService telemetryService: ITelemetryService,
) {
super(environmentService.keybindingsResource, SyncSource.Keybindings, 'keybindings', fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, userDataSyncUtilService, configurationService);
super(environmentService.keybindingsResource, SyncResource.Keybindings, fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, userDataSyncUtilService, configurationService);
}
async pull(): Promise<void> {
if (!this.isEnabled()) {
this.logService.info('Keybindings: Skipped pulling keybindings as it is disabled.');
this.logService.info(`${this.syncResourceLogLabel}: Skipped pulling keybindings as it is disabled.`);
return;
}
this.stop();
try {
this.logService.info('Keybindings: Started pulling keybindings...');
this.logService.info(`${this.syncResourceLogLabel}: Started pulling keybindings...`);
this.setStatus(SyncStatus.Syncing);
const lastSyncUserData = await this.getLastSyncUserData();
@@ -78,10 +78,10 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
// No remote exists to pull
else {
this.logService.info('Keybindings: Remote keybindings does not exist.');
this.logService.info(`${this.syncResourceLogLabel}: Remote keybindings does not exist.`);
}
this.logService.info('Keybindings: Finished pulling keybindings.');
this.logService.info(`${this.syncResourceLogLabel}: Finished pulling keybindings.`);
} finally {
this.setStatus(SyncStatus.Idle);
}
@@ -90,14 +90,14 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
async push(): Promise<void> {
if (!this.isEnabled()) {
this.logService.info('Keybindings: Skipped pushing keybindings as it is disabled.');
this.logService.info(`${this.syncResourceLogLabel}: Skipped pushing keybindings as it is disabled.`);
return;
}
this.stop();
try {
this.logService.info('Keybindings: Started pushing keybindings...');
this.logService.info(`${this.syncResourceLogLabel}: Started pushing keybindings...`);
this.setStatus(SyncStatus.Syncing);
const fileContent = await this.getLocalFileContent();
@@ -119,10 +119,10 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
// No local exists to push
else {
this.logService.info('Keybindings: Local keybindings does not exist.');
this.logService.info(`${this.syncResourceLogLabel}: Local keybindings does not exist.`);
}
this.logService.info('Keybindings: Finished pushing keybindings.');
this.logService.info(`${this.syncResourceLogLabel}: Finished pushing keybindings.`);
} finally {
this.setStatus(SyncStatus.Idle);
}
@@ -202,7 +202,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
switch (e.code) {
case UserDataSyncErrorCode.LocalPreconditionFailed:
// Rejected as there is a new local version. Syncing again.
this.logService.info('Keybindings: Failed to synchronize keybindings as there is a new local version available. Synchronizing again...');
this.logService.info(`${this.syncResourceLogLabel}: Failed to synchronize keybindings as there is a new local version available. Synchronizing again...`);
return this.performSync(remoteUserData, lastSyncUserData);
}
}
@@ -219,21 +219,21 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
if (content !== null) {
if (this.hasErrors(content)) {
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync keybindings as there are errors/warning in keybindings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync keybindings as there are errors/warning in keybindings file."), UserDataSyncErrorCode.LocalInvalidContent, this.resource);
}
if (hasLocalChanged) {
this.logService.trace('Keybindings: Updating local keybindings...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating local keybindings...`);
await this.backupLocal(this.toSyncContent(content, null));
await this.updateLocalFileContent(content, fileContent);
this.logService.info('Keybindings: Updated local keybindings');
this.logService.info(`${this.syncResourceLogLabel}: Updated local keybindings`);
}
if (hasRemoteChanged) {
this.logService.trace('Keybindings: Updating remote keybindings...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating remote keybindings...`);
const remoteContents = this.toSyncContent(content, remoteUserData.syncData ? remoteUserData.syncData.content : null);
remoteUserData = await this.updateRemoteUserData(remoteContents, forcePush ? null : remoteUserData.ref);
this.logService.info('Keybindings: Updated remote keybindings');
this.logService.info(`${this.syncResourceLogLabel}: Updated remote keybindings`);
}
// Delete the preview
@@ -241,14 +241,14 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
await this.fileService.del(this.conflictsPreviewResource);
} catch (e) { /* ignore */ }
} else {
this.logService.info('Keybindings: No changes found during synchronizing keybindings.');
this.logService.info(`${this.syncResourceLogLabel}: No changes found during synchronizing keybindings.`);
}
if (lastSyncUserData?.ref !== remoteUserData.ref && (content !== null || fileContent !== null)) {
this.logService.trace('Keybindings: Updating last synchronized keybindings...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized keybindings...`);
const lastSyncContent = this.toSyncContent(content !== null ? content : fileContent!.value.toString(), null);
await this.updateLastSyncUserData({ ref: remoteUserData.ref, syncData: { version: remoteUserData.syncData!.version, content: lastSyncContent } });
this.logService.info('Keybindings: Updated last synchronized keybindings');
this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized keybindings`);
}
this.syncPreviewResultPromise = null;
@@ -276,14 +276,14 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
if (remoteContent) {
const localContent: string = fileContent ? fileContent.value.toString() : '[]';
if (this.hasErrors(localContent)) {
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync keybindings as there are errors/warning in keybindings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync keybindings as there are errors/warning in keybindings file."), UserDataSyncErrorCode.LocalInvalidContent, this.resource);
}
if (!lastSyncContent // First time sync
|| lastSyncContent !== localContent // Local has forwarded
|| lastSyncContent !== remoteContent // Remote has forwarded
) {
this.logService.trace('Keybindings: Merging remote keybindings with local keybindings...');
this.logService.trace(`${this.syncResourceLogLabel}: Merging remote keybindings with local keybindings...`);
const result = await merge(localContent, remoteContent, lastSyncContent, formattingOptions, this.userDataSyncUtilService);
// Sync only if there are changes
if (result.hasChanges) {
@@ -297,7 +297,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
// First time syncing to remote
else if (fileContent) {
this.logService.trace('Keybindings: Remote keybindings does not exist. Synchronizing keybindings for the first time.');
this.logService.trace(`${this.syncResourceLogLabel}: Remote keybindings does not exist. Synchronizing keybindings for the first time.`);
content = fileContent.value.toString();
hasRemoteChanged = true;
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, IConflictSetting, ISettingsSyncService, CONFIGURATION_SYNC_STORE_KEY, SyncSource, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IUserDataSyncUtilService, IConflictSetting, ISettingsSyncService, CONFIGURATION_SYNC_STORE_KEY, SyncResource, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { VSBuffer } from 'vs/base/common/buffer';
import { parse } from 'vs/base/common/json';
import { localize } from 'vs/nls';
@@ -57,7 +57,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
@ITelemetryService telemetryService: ITelemetryService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
) {
super(environmentService.settingsResource, SyncSource.Settings, 'settings', fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, userDataSyncUtilService, configurationService);
super(environmentService.settingsResource, SyncResource.Settings, fileService, environmentService, userDataSyncStoreService, userDataSyncBackupStoreService, userDataSyncEnablementService, telemetryService, logService, userDataSyncUtilService, configurationService);
}
protected setStatus(status: SyncStatus): void {
@@ -78,14 +78,14 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
async pull(): Promise<void> {
if (!this.isEnabled()) {
this.logService.info('Settings: Skipped pulling settings as it is disabled.');
this.logService.info(`${this.syncResourceLogLabel}: Skipped pulling settings as it is disabled.`);
return;
}
this.stop();
try {
this.logService.info('Settings: Started pulling settings...');
this.logService.info(`${this.syncResourceLogLabel}: Started pulling settings...`);
this.setStatus(SyncStatus.Syncing);
const lastSyncUserData = await this.getLastSyncUserData();
@@ -113,10 +113,10 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
// No remote exists to pull
else {
this.logService.info('Settings: Remote settings does not exist.');
this.logService.info(`${this.syncResourceLogLabel}: Remote settings does not exist.`);
}
this.logService.info('Settings: Finished pulling settings.');
this.logService.info(`${this.syncResourceLogLabel}: Finished pulling settings.`);
} finally {
this.setStatus(SyncStatus.Idle);
}
@@ -124,14 +124,14 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
async push(): Promise<void> {
if (!this.isEnabled()) {
this.logService.info('Settings: Skipped pushing settings as it is disabled.');
this.logService.info(`${this.syncResourceLogLabel}: Skipped pushing settings as it is disabled.`);
return;
}
this.stop();
try {
this.logService.info('Settings: Started pushing settings...');
this.logService.info(`${this.syncResourceLogLabel}: Started pushing settings...`);
this.setStatus(SyncStatus.Syncing);
const fileContent = await this.getLocalFileContent();
@@ -159,10 +159,10 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
// No local exists to push
else {
this.logService.info('Settings: Local settings does not exist.');
this.logService.info(`${this.syncResourceLogLabel}: Local settings does not exist.`);
}
this.logService.info('Settings: Finished pushing settings.');
this.logService.info(`${this.syncResourceLogLabel}: Finished pushing settings.`);
} finally {
this.setStatus(SyncStatus.Idle);
}
@@ -268,7 +268,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
switch (e.code) {
case UserDataSyncErrorCode.LocalPreconditionFailed:
// Rejected as there is a new local version. Syncing again.
this.logService.info('Settings: Failed to synchronize settings as there is a new local version available. Synchronizing again...');
this.logService.info(`${this.syncResourceLogLabel}: Failed to synchronize settings as there is a new local version available. Synchronizing again...`);
return this.performSync(remoteUserData, lastSyncUserData, resolvedConflicts);
}
}
@@ -288,10 +288,10 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
this.validateContent(content);
if (hasLocalChanged) {
this.logService.trace('Settings: Updating local settings...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating local settings...`);
await this.backupLocal(JSON.stringify(this.toSettingsSyncContent(content)));
await this.updateLocalFileContent(content, fileContent);
this.logService.info('Settings: Updated local settings');
this.logService.info(`${this.syncResourceLogLabel}: Updated local settings`);
}
if (hasRemoteChanged) {
const formatUtils = await this.getFormattingOptions();
@@ -299,9 +299,9 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
const remoteSettingsSyncContent = this.getSettingsSyncContent(remoteUserData);
const ignoredSettings = await this.getIgnoredSettings(content);
content = updateIgnoredSettings(content, remoteSettingsSyncContent ? remoteSettingsSyncContent.settings : '{}', ignoredSettings, formatUtils);
this.logService.trace('Settings: Updating remote settings...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating remote settings...`);
remoteUserData = await this.updateRemoteUserData(JSON.stringify(this.toSettingsSyncContent(content)), forcePush ? null : remoteUserData.ref);
this.logService.info('Settings: Updated remote settings');
this.logService.info(`${this.syncResourceLogLabel}: Updated remote settings`);
}
// Delete the preview
@@ -309,13 +309,13 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
await this.fileService.del(this.conflictsPreviewResource);
} catch (e) { /* ignore */ }
} else {
this.logService.info('Settings: No changes found during synchronizing settings.');
this.logService.info(`${this.syncResourceLogLabel}: No changes found during synchronizing settings.`);
}
if (lastSyncUserData?.ref !== remoteUserData.ref) {
this.logService.trace('Settings: Updating last synchronized settings...');
this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized settings...`);
await this.updateLastSyncUserData(remoteUserData);
this.logService.info('Settings: Updated last synchronized settings');
this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized settings`);
}
this.syncPreviewResultPromise = null;
@@ -343,7 +343,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
if (remoteSettingsSyncContent) {
const localContent: string = fileContent ? fileContent.value.toString() : '{}';
this.validateContent(localContent);
this.logService.trace('Settings: Merging remote settings with local settings...');
this.logService.trace(`${this.syncResourceLogLabel}: Merging remote settings with local settings...`);
const ignoredSettings = await this.getIgnoredSettings();
const result = merge(localContent, remoteSettingsSyncContent.settings, lastSettingsSyncContent ? lastSettingsSyncContent.settings : null, ignoredSettings, resolvedConflicts, formattingOptions);
content = result.localContent || result.remoteContent;
@@ -355,7 +355,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
// First time syncing to remote
else if (fileContent) {
this.logService.trace('Settings: Remote settings does not exist. Synchronizing settings for the first time.');
this.logService.trace(`${this.syncResourceLogLabel}: Remote settings does not exist. Synchronizing settings for the first time.`);
content = fileContent.value.toString();
hasRemoteChanged = true;
}
@@ -406,7 +406,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
private validateContent(content: string): void {
if (this.hasErrors(content)) {
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.resource);
}
}
}

View File

@@ -135,11 +135,16 @@ export function getUserDataSyncStore(productService: IProductService, configurat
return undefined;
}
export const ALL_RESOURCE_KEYS: ResourceKey[] = ['settings', 'keybindings', 'extensions', 'globalState'];
export type ResourceKey = 'settings' | 'keybindings' | 'extensions' | 'globalState';
export const enum SyncResource {
Settings = 'settings',
Keybindings = 'keybindings',
Extensions = 'extensions',
GlobalState = 'globalState'
}
export const ALL_SYNC_RESOURCES: SyncResource[] = [SyncResource.Settings, SyncResource.Keybindings, SyncResource.Extensions, SyncResource.GlobalState];
export interface IUserDataManifest {
latest?: Record<ResourceKey, string>
latest?: Record<SyncResource, string>
session: string;
}
@@ -152,21 +157,21 @@ export const IUserDataSyncStoreService = createDecorator<IUserDataSyncStoreServi
export interface IUserDataSyncStoreService {
_serviceBrand: undefined;
readonly userDataSyncStore: IUserDataSyncStore | undefined;
read(key: ResourceKey, oldValue: IUserData | null, source?: SyncSource): Promise<IUserData>;
write(key: ResourceKey, content: string, ref: string | null, source?: SyncSource): Promise<string>;
read(resource: SyncResource, oldValue: IUserData | null): Promise<IUserData>;
write(resource: SyncResource, content: string, ref: string | null): Promise<string>;
manifest(): Promise<IUserDataManifest | null>;
clear(): Promise<void>;
getAllRefs(key: ResourceKey): Promise<IResourceRefHandle[]>;
resolveContent(key: ResourceKey, ref: string): Promise<string | null>;
delete(key: ResourceKey): Promise<void>;
getAllRefs(resource: SyncResource): Promise<IResourceRefHandle[]>;
resolveContent(resource: SyncResource, ref: string): Promise<string | null>;
delete(resource: SyncResource): Promise<void>;
}
export const IUserDataSyncBackupStoreService = createDecorator<IUserDataSyncBackupStoreService>('IUserDataSyncBackupStoreService');
export interface IUserDataSyncBackupStoreService {
_serviceBrand: undefined;
backup(resourceKey: ResourceKey, content: string): Promise<void>;
getAllRefs(key: ResourceKey): Promise<IResourceRefHandle[]>;
resolveContent(key: ResourceKey, ref?: string): Promise<string | null>;
backup(resource: SyncResource, content: string): Promise<void>;
getAllRefs(resource: SyncResource): Promise<IResourceRefHandle[]>;
resolveContent(resource: SyncResource, ref?: string): Promise<string | null>;
}
//#endregion
@@ -195,9 +200,9 @@ export enum UserDataSyncErrorCode {
export class UserDataSyncError extends Error {
constructor(message: string, public readonly code: UserDataSyncErrorCode, public readonly source?: SyncSource) {
constructor(message: string, public readonly code: UserDataSyncErrorCode, public readonly resource?: SyncResource) {
super(message);
this.name = `${this.code} (UserDataSyncError) ${this.source}`;
this.name = `${this.code} (UserDataSyncError) ${this.resource}`;
}
static toUserDataSyncError(error: Error): UserDataSyncError {
@@ -206,7 +211,7 @@ export class UserDataSyncError extends Error {
}
const match = /^(.+) \(UserDataSyncError\) (.+)?$/.exec(error.name);
if (match && match[1]) {
return new UserDataSyncError(error.message, <UserDataSyncErrorCode>match[1], <SyncSource>match[2]);
return new UserDataSyncError(error.message, <UserDataSyncErrorCode>match[1], <SyncResource>match[2]);
}
return new UserDataSyncError(error.message, UserDataSyncErrorCode.Unknown);
}
@@ -230,13 +235,6 @@ export interface IGlobalState {
storage: IStringDictionary<any>;
}
export const enum SyncSource {
Settings = 'Settings',
Keybindings = 'Keybindings',
Extensions = 'Extensions',
GlobalState = 'GlobalState'
}
export const enum SyncStatus {
Uninitialized = 'uninitialized',
Idle = 'idle',
@@ -246,8 +244,7 @@ export const enum SyncStatus {
export interface IUserDataSynchroniser {
readonly resourceKey: ResourceKey;
readonly source: SyncSource;
readonly resource: SyncResource;
readonly status: SyncStatus;
readonly onDidChangeStatus: Event<SyncStatus>;
readonly onDidChangeLocal: Event<void>;
@@ -276,13 +273,13 @@ export interface IUserDataSyncEnablementService {
_serviceBrand: any;
readonly onDidChangeEnablement: Event<boolean>;
readonly onDidChangeResourceEnablement: Event<[ResourceKey, boolean]>;
readonly onDidChangeResourceEnablement: Event<[SyncResource, boolean]>;
isEnabled(): boolean;
setEnablement(enabled: boolean): void;
isResourceEnabled(key: ResourceKey): boolean;
setResourceEnablement(key: ResourceKey, enabled: boolean): void;
isResourceEnabled(resource: SyncResource): boolean;
setResourceEnablement(resource: SyncResource, enabled: boolean): void;
}
export const IUserDataSyncService = createDecorator<IUserDataSyncService>('IUserDataSyncService');
@@ -292,11 +289,11 @@ export interface IUserDataSyncService {
readonly status: SyncStatus;
readonly onDidChangeStatus: Event<SyncStatus>;
readonly conflictsSources: SyncSource[];
readonly onDidChangeConflicts: Event<SyncSource[]>;
readonly conflictsSources: SyncResource[];
readonly onDidChangeConflicts: Event<SyncResource[]>;
readonly onDidChangeLocal: Event<SyncSource>;
readonly onSyncErrors: Event<[SyncSource, UserDataSyncError][]>;
readonly onDidChangeLocal: Event<SyncResource>;
readonly onSyncErrors: Event<[SyncResource, UserDataSyncError][]>;
readonly lastSyncTime: number | undefined;
readonly onDidChangeLastSyncTime: Event<number>;
@@ -309,7 +306,7 @@ export interface IUserDataSyncService {
isFirstTimeSyncWithMerge(): Promise<boolean>;
resolveContent(resource: URI): Promise<string | null>;
accept(source: SyncSource, content: string): Promise<void>;
accept(source: SyncResource, content: string): Promise<void>;
}
export const IUserDataAutoSyncService = createDecorator<IUserDataAutoSyncService>('IUserDataAutoSyncService');
@@ -351,50 +348,31 @@ export const CONTEXT_SYNC_ENABLEMENT = new RawContextKey<boolean>('syncEnabled',
export const USER_DATA_SYNC_SCHEME = 'vscode-userdata-sync';
export const PREVIEW_QUERY = 'preview=true';
export function toRemoteSyncResourceFromSource(source: SyncSource, ref?: string): URI {
return toRemoteSyncResource(getResourceKeyFromSyncSource(source), ref);
export function toRemoteSyncResource(resource: SyncResource, ref?: string): URI {
return URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'remote', path: `/${resource}/${ref ? ref : 'latest'}` });
}
export function toRemoteSyncResource(resourceKey: ResourceKey, ref?: string): URI {
return URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'remote', path: `/${resourceKey}/${ref ? ref : 'latest'}` });
}
export function toLocalBackupSyncResource(resourceKey: ResourceKey, ref?: string): URI {
return URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'local-backup', path: `/${resourceKey}/${ref ? ref : 'latest'}` });
export function toLocalBackupSyncResource(resource: SyncResource, ref?: string): URI {
return URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'local-backup', path: `/${resource}/${ref ? ref : 'latest'}` });
}
export function resolveSyncResource(resource: URI): { remote: boolean, resourceKey: ResourceKey, ref?: string } | null {
const remote = resource.authority === 'remote';
const resourceKey: ResourceKey = basename(dirname(resource)) as ResourceKey;
const ref = basename(resource);
if (resourceKey && ref) {
return { remote, resourceKey, ref: ref !== 'latest' ? ref : undefined };
export function resolveSyncResource(resource: URI): { remote: boolean, resource: SyncResource, ref?: string } | null {
if (resource.scheme === USER_DATA_SYNC_SCHEME) {
const remote = resource.authority === 'remote';
const resourceKey: SyncResource = basename(dirname(resource)) as SyncResource;
const ref = basename(resource);
if (resourceKey && ref) {
return { remote, resource: resourceKey, ref: ref !== 'latest' ? ref : undefined };
}
}
return null;
}
export function getSyncSourceFromPreviewResource(uri: URI, environmentService: IEnvironmentService): SyncSource | undefined {
export function getSyncSourceFromPreviewResource(uri: URI, environmentService: IEnvironmentService): SyncResource | undefined {
if (isEqual(uri, environmentService.settingsSyncPreviewResource)) {
return SyncSource.Settings;
return SyncResource.Settings;
}
if (isEqual(uri, environmentService.keybindingsSyncPreviewResource)) {
return SyncSource.Keybindings;
return SyncResource.Keybindings;
}
return undefined;
}
export function getResourceKeyFromSyncSource(source: SyncSource): ResourceKey {
switch (source) {
case SyncSource.Settings: return 'settings';
case SyncSource.Keybindings: return 'keybindings';
case SyncSource.Extensions: return 'extensions';
case SyncSource.GlobalState: return 'globalState';
}
}
export function getSyncSourceFromResourceKey(resourceKey: ResourceKey): SyncSource {
switch (resourceKey) {
case 'settings': return SyncSource.Settings;
case 'keybindings': return SyncSource.Keybindings;
case 'extensions': return SyncSource.Extensions;
case 'globalState': return SyncSource.GlobalState;
}
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable, } from 'vs/base/common/lifecycle';
import { IUserDataSyncLogService, ResourceKey, ALL_RESOURCE_KEYS, IUserDataSyncBackupStoreService, IResourceRefHandle } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncLogService, ALL_SYNC_RESOURCES, IUserDataSyncBackupStoreService, IResourceRefHandle, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
import { joinPath } from 'vs/base/common/resources';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IFileService, IFileStat } from 'vs/platform/files/common/files';
@@ -23,11 +23,11 @@ export class UserDataSyncBackupStoreService extends Disposable implements IUserD
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
) {
super();
ALL_RESOURCE_KEYS.forEach(resourceKey => this.cleanUpBackup(resourceKey));
ALL_SYNC_RESOURCES.forEach(resourceKey => this.cleanUpBackup(resourceKey));
}
async getAllRefs(resourceKey: ResourceKey): Promise<IResourceRefHandle[]> {
const folder = joinPath(this.environmentService.userDataSyncHome, resourceKey);
async getAllRefs(resource: SyncResource): Promise<IResourceRefHandle[]> {
const folder = joinPath(this.environmentService.userDataSyncHome, resource);
const stat = await this.fileService.resolve(folder);
if (stat.children) {
const all = stat.children.filter(stat => stat.isFile && /^\d{8}T\d{6}(\.json)?$/.test(stat.name)).sort().reverse();
@@ -39,22 +39,22 @@ export class UserDataSyncBackupStoreService extends Disposable implements IUserD
return [];
}
async resolveContent(resourceKey: ResourceKey, ref?: string): Promise<string | null> {
async resolveContent(resource: SyncResource, ref?: string): Promise<string | null> {
if (!ref) {
const refs = await this.getAllRefs(resourceKey);
const refs = await this.getAllRefs(resource);
if (refs.length) {
ref = refs[refs.length - 1].ref;
}
}
if (ref) {
const file = joinPath(this.environmentService.userDataSyncHome, resourceKey, ref);
const file = joinPath(this.environmentService.userDataSyncHome, resource, ref);
const content = await this.fileService.readFile(file);
return content.value.toString();
}
return null;
}
async backup(resourceKey: ResourceKey, content: string): Promise<void> {
async backup(resourceKey: SyncResource, content: string): Promise<void> {
const folder = joinPath(this.environmentService.userDataSyncHome, resourceKey);
const resource = joinPath(folder, `${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}.json`);
try {
@@ -67,8 +67,8 @@ export class UserDataSyncBackupStoreService extends Disposable implements IUserD
} catch (e) { /* Ignore */ }
}
private async cleanUpBackup(resourceKey: ResourceKey): Promise<void> {
const folder = joinPath(this.environmentService.userDataSyncHome, resourceKey);
private async cleanUpBackup(resource: SyncResource): Promise<void> {
const folder = joinPath(this.environmentService.userDataSyncHome, resource);
try {
try {
if (!(await this.fileService.exists(folder))) {

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IUserDataSyncEnablementService, ResourceKey, ALL_RESOURCE_KEYS } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncEnablementService, ALL_SYNC_RESOURCES, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { IStorageService, IWorkspaceStorageChangeEvent, StorageScope } from 'vs/platform/storage/common/storage';
@@ -14,7 +14,7 @@ type SyncEnablementClassification = {
};
const enablementKey = 'sync.enable';
function getEnablementKey(resourceKey: ResourceKey) { return `${enablementKey}.${resourceKey}`; }
function getEnablementKey(resource: SyncResource) { return `${enablementKey}.${resource}`; }
export class UserDataSyncEnablementService extends Disposable implements IUserDataSyncEnablementService {
@@ -23,8 +23,8 @@ export class UserDataSyncEnablementService extends Disposable implements IUserDa
private _onDidChangeEnablement = new Emitter<boolean>();
readonly onDidChangeEnablement: Event<boolean> = this._onDidChangeEnablement.event;
private _onDidChangeResourceEnablement = new Emitter<[ResourceKey, boolean]>();
readonly onDidChangeResourceEnablement: Event<[ResourceKey, boolean]> = this._onDidChangeResourceEnablement.event;
private _onDidChangeResourceEnablement = new Emitter<[SyncResource, boolean]>();
readonly onDidChangeResourceEnablement: Event<[SyncResource, boolean]> = this._onDidChangeResourceEnablement.event;
constructor(
@IStorageService private readonly storageService: IStorageService,
@@ -45,13 +45,13 @@ export class UserDataSyncEnablementService extends Disposable implements IUserDa
}
}
isResourceEnabled(resourceKey: ResourceKey): boolean {
return this.storageService.getBoolean(getEnablementKey(resourceKey), StorageScope.GLOBAL, true);
isResourceEnabled(resource: SyncResource): boolean {
return this.storageService.getBoolean(getEnablementKey(resource), StorageScope.GLOBAL, true);
}
setResourceEnablement(resourceKey: ResourceKey, enabled: boolean): void {
if (this.isResourceEnabled(resourceKey) !== enabled) {
const resourceEnablementKey = getEnablementKey(resourceKey);
setResourceEnablement(resource: SyncResource, enabled: boolean): void {
if (this.isResourceEnabled(resource) !== enabled) {
const resourceEnablementKey = getEnablementKey(resource);
this.telemetryService.publicLog2<{ enabled: boolean }, SyncEnablementClassification>(resourceEnablementKey, { enabled });
this.storageService.store(resourceEnablementKey, enabled, StorageScope.GLOBAL);
}
@@ -63,7 +63,7 @@ export class UserDataSyncEnablementService extends Disposable implements IUserDa
this._onDidChangeEnablement.fire(this.isEnabled());
return;
}
const resourceKey = ALL_RESOURCE_KEYS.filter(resourceKey => getEnablementKey(resourceKey) === workspaceStorageChangeEvent.key)[0];
const resourceKey = ALL_SYNC_RESOURCES.filter(resourceKey => getEnablementKey(resourceKey) === workspaceStorageChangeEvent.key)[0];
if (resourceKey) {
this._onDidChangeResourceEnablement.fire([resourceKey, this.isEnabled()]);
return;

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IUserDataSyncService, SyncStatus, IUserDataSyncStoreService, SyncSource, ISettingsSyncService, IUserDataSyncLogService, IUserDataSynchroniser, UserDataSyncStoreError, UserDataSyncErrorCode, UserDataSyncError, resolveSyncResource, PREVIEW_QUERY } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncService, SyncStatus, IUserDataSyncStoreService, SyncResource, ISettingsSyncService, IUserDataSyncLogService, IUserDataSynchroniser, UserDataSyncStoreError, UserDataSyncErrorCode, UserDataSyncError, resolveSyncResource, PREVIEW_QUERY } from 'vs/platform/userDataSync/common/userDataSync';
import { Disposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Emitter, Event } from 'vs/base/common/event';
@@ -35,16 +35,16 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
private _onDidChangeStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangeStatus.event;
readonly onDidChangeLocal: Event<SyncSource>;
readonly onDidChangeLocal: Event<SyncResource>;
private _conflictsSources: SyncSource[] = [];
get conflictsSources(): SyncSource[] { return this._conflictsSources; }
private _onDidChangeConflicts: Emitter<SyncSource[]> = this._register(new Emitter<SyncSource[]>());
readonly onDidChangeConflicts: Event<SyncSource[]> = this._onDidChangeConflicts.event;
private _conflictsSources: SyncResource[] = [];
get conflictsSources(): SyncResource[] { return this._conflictsSources; }
private _onDidChangeConflicts: Emitter<SyncResource[]> = this._register(new Emitter<SyncResource[]>());
readonly onDidChangeConflicts: Event<SyncResource[]> = this._onDidChangeConflicts.event;
private _syncErrors: [SyncSource, UserDataSyncError][] = [];
private _onSyncErrors: Emitter<[SyncSource, UserDataSyncError][]> = this._register(new Emitter<[SyncSource, UserDataSyncError][]>());
readonly onSyncErrors: Event<[SyncSource, UserDataSyncError][]> = this._onSyncErrors.event;
private _syncErrors: [SyncResource, UserDataSyncError][] = [];
private _onSyncErrors: Emitter<[SyncResource, UserDataSyncError][]> = this._register(new Emitter<[SyncResource, UserDataSyncError][]>());
readonly onSyncErrors: Event<[SyncResource, UserDataSyncError][]> = this._onSyncErrors.event;
private _lastSyncTime: number | undefined = undefined;
get lastSyncTime(): number | undefined { return this._lastSyncTime; }
@@ -75,7 +75,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
}
this._lastSyncTime = this.storageService.getNumber(LAST_SYNC_TIME_KEY, StorageScope.GLOBAL, undefined);
this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => Event.map(s.onDidChangeLocal, () => s.source)));
this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => Event.map(s.onDidChangeLocal, () => s.resource)));
}
async pull(): Promise<void> {
@@ -84,7 +84,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
try {
await synchroniser.pull();
} catch (e) {
this.handleSyncError(e, synchroniser.source);
this.handleSyncError(e, synchroniser.resource);
}
}
this.updateLastSyncTime();
@@ -96,7 +96,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
try {
await synchroniser.push();
} catch (e) {
this.handleSyncError(e, synchroniser.source);
this.handleSyncError(e, synchroniser.resource);
}
}
this.updateLastSyncTime();
@@ -129,10 +129,10 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
for (const synchroniser of this.synchronisers) {
try {
await synchroniser.sync(manifest && manifest.latest ? manifest.latest[synchroniser.resourceKey] : undefined);
await synchroniser.sync(manifest && manifest.latest ? manifest.latest[synchroniser.resource] : undefined);
} catch (e) {
this.handleSyncError(e, synchroniser.source);
this._syncErrors.push([synchroniser.source, UserDataSyncError.toUserDataSyncError(e)]);
this.handleSyncError(e, synchroniser.resource);
this._syncErrors.push([synchroniser.resource, UserDataSyncError.toUserDataSyncError(e)]);
}
}
@@ -171,7 +171,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
}
}
async accept(source: SyncSource, content: string): Promise<void> {
async accept(source: SyncResource, content: string): Promise<void> {
await this.checkEnablement();
const synchroniser = this.getSynchroniser(source);
await synchroniser.accept(content);
@@ -180,7 +180,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
async resolveContent(resource: URI): Promise<string | null> {
const result = resolveSyncResource(resource);
if (result) {
const synchronizer = this.synchronisers.filter(s => s.resourceKey === result.resourceKey)[0];
const synchronizer = this.synchronisers.filter(s => s.resource === result.resource)[0];
if (synchronizer) {
if (PREVIEW_QUERY === resource.query) {
return result.remote ? synchronizer.getRemoteContentFromPreview() : null;
@@ -216,7 +216,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
try {
synchroniser.resetLocal();
} catch (e) {
this.logService.error(`${synchroniser.source}: ${toErrorMessage(e)}`);
this.logService.error(`${synchroniser.resource}: ${toErrorMessage(e)}`);
this.logService.error(e);
}
}
@@ -291,7 +291,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
}
}
private handleSyncError(e: Error, source: SyncSource): void {
private handleSyncError(e: Error, source: SyncResource): void {
if (e instanceof UserDataSyncStoreError) {
switch (e.code) {
case UserDataSyncErrorCode.TooLarge:
@@ -303,12 +303,12 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
this.logService.error(`${source}: ${toErrorMessage(e)}`);
}
private computeConflictsSources(): SyncSource[] {
return this.synchronisers.filter(s => s.status === SyncStatus.HasConflicts).map(s => s.source);
private computeConflictsSources(): SyncResource[] {
return this.synchronisers.filter(s => s.status === SyncStatus.HasConflicts).map(s => s.resource);
}
getSynchroniser(source: SyncSource): IUserDataSynchroniser {
return this.synchronisers.filter(s => s.source === source)[0];
getSynchroniser(source: SyncResource): IUserDataSynchroniser {
return this.synchronisers.filter(s => s.resource === source)[0];
}
private async checkEnablement(): Promise<void> {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable, } from 'vs/base/common/lifecycle';
import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, getUserDataSyncStore, SyncSource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest, ResourceKey, IResourceRefHandle } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, getUserDataSyncStore, SyncResource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest, IResourceRefHandle } from 'vs/platform/userDataSync/common/userDataSync';
import { IRequestService, asText, isSuccess, asJson } from 'vs/platform/request/common/request';
import { joinPath, relativePath } from 'vs/base/common/resources';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -31,12 +31,12 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn
this.userDataSyncStore = getUserDataSyncStore(productService, configurationService);
}
async getAllRefs(key: ResourceKey): Promise<IResourceRefHandle[]> {
async getAllRefs(resource: SyncResource): Promise<IResourceRefHandle[]> {
if (!this.userDataSyncStore) {
throw new Error('No settings sync store url configured.');
}
const uri = joinPath(this.userDataSyncStore.url, 'resource', key);
const uri = joinPath(this.userDataSyncStore.url, 'resource', resource);
const headers: IHeaders = {};
const context = await this.request({ type: 'GET', url: uri.toString(), headers }, undefined, CancellationToken.None);
@@ -49,12 +49,12 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn
return result.map(({ url, created }) => ({ ref: relativePath(uri, URI.parse(url))!, created: created }));
}
async resolveContent(key: ResourceKey, ref: string): Promise<string | null> {
async resolveContent(resource: SyncResource, ref: string): Promise<string | null> {
if (!this.userDataSyncStore) {
throw new Error('No settings sync store url configured.');
}
const url = joinPath(this.userDataSyncStore.url, 'resource', key, ref).toString();
const url = joinPath(this.userDataSyncStore.url, 'resource', resource, ref).toString();
const headers: IHeaders = {};
const context = await this.request({ type: 'GET', url, headers }, undefined, CancellationToken.None);
@@ -67,12 +67,12 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn
return content;
}
async delete(key: ResourceKey): Promise<void> {
async delete(resource: SyncResource): Promise<void> {
if (!this.userDataSyncStore) {
throw new Error('No settings sync store url configured.');
}
const url = joinPath(this.userDataSyncStore.url, 'resource', key).toString();
const url = joinPath(this.userDataSyncStore.url, 'resource', resource).toString();
const headers: IHeaders = {};
const context = await this.request({ type: 'DELETE', url, headers }, undefined, CancellationToken.None);
@@ -82,12 +82,12 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn
}
}
async read(key: ResourceKey, oldValue: IUserData | null, source?: SyncSource): Promise<IUserData> {
async read(resource: SyncResource, oldValue: IUserData | null): Promise<IUserData> {
if (!this.userDataSyncStore) {
throw new Error('No settings sync store url configured.');
}
const url = joinPath(this.userDataSyncStore.url, 'resource', key, 'latest').toString();
const url = joinPath(this.userDataSyncStore.url, 'resource', resource, 'latest').toString();
const headers: IHeaders = {};
// Disable caching as they are cached by synchronisers
headers['Cache-Control'] = 'no-cache';
@@ -95,7 +95,7 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn
headers['If-None-Match'] = oldValue.ref;
}
const context = await this.request({ type: 'GET', url, headers }, source, CancellationToken.None);
const context = await this.request({ type: 'GET', url, headers }, resource, CancellationToken.None);
if (context.res.statusCode === 304) {
// There is no new value. Hence return the old value.
@@ -103,37 +103,37 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn
}
if (!isSuccess(context)) {
throw new UserDataSyncStoreError('Server returned ' + context.res.statusCode, UserDataSyncErrorCode.Unknown, source);
throw new UserDataSyncStoreError('Server returned ' + context.res.statusCode, UserDataSyncErrorCode.Unknown, resource);
}
const ref = context.res.headers['etag'];
if (!ref) {
throw new UserDataSyncStoreError('Server did not return the ref', UserDataSyncErrorCode.NoRef, source);
throw new UserDataSyncStoreError('Server did not return the ref', UserDataSyncErrorCode.NoRef, resource);
}
const content = await asText(context);
return { ref, content };
}
async write(key: ResourceKey, data: string, ref: string | null, source?: SyncSource): Promise<string> {
async write(resource: SyncResource, data: string, ref: string | null): Promise<string> {
if (!this.userDataSyncStore) {
throw new Error('No settings sync store url configured.');
}
const url = joinPath(this.userDataSyncStore.url, 'resource', key).toString();
const url = joinPath(this.userDataSyncStore.url, 'resource', resource).toString();
const headers: IHeaders = { 'Content-Type': 'text/plain' };
if (ref) {
headers['If-Match'] = ref;
}
const context = await this.request({ type: 'POST', url, data, headers }, source, CancellationToken.None);
const context = await this.request({ type: 'POST', url, data, headers }, resource, CancellationToken.None);
if (!isSuccess(context)) {
throw new UserDataSyncStoreError('Server returned ' + context.res.statusCode, UserDataSyncErrorCode.Unknown, source);
throw new UserDataSyncStoreError('Server returned ' + context.res.statusCode, UserDataSyncErrorCode.Unknown, resource);
}
const newRef = context.res.headers['etag'];
if (!newRef) {
throw new UserDataSyncStoreError('Server did not return the ref', UserDataSyncErrorCode.NoRef, source);
throw new UserDataSyncStoreError('Server did not return the ref', UserDataSyncErrorCode.NoRef, resource);
}
return newRef;
}
@@ -169,7 +169,7 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn
}
}
private async request(options: IRequestOptions, source: SyncSource | undefined, token: CancellationToken): Promise<IRequestContext> {
private async request(options: IRequestOptions, source: SyncResource | undefined, token: CancellationToken): Promise<IRequestContext> {
const authToken = await this.authTokenService.getToken();
if (!authToken) {
throw new UserDataSyncStoreError('No Auth Token Available', UserDataSyncErrorCode.Unauthorized, source);