mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 1df23554b2e3d5f1efc6fbc76ee61d3f7f186c6d
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user