Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal
import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService';
import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage';
import { IgnoredExtensionsManagementService, IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions';
import { IUserDataSyncBackupStoreService, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncService, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, IUserDataSyncUtilService, registerConfiguration as registerUserDataSyncConfiguration } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncBackupStoreService, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncService, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, IUserDataSyncUtilService, registerConfiguration as registerUserDataSyncConfiguration, IUserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncAccountService, UserDataSyncAccountService } from 'vs/platform/userDataSync/common/userDataSyncAccount';
import { UserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSyncBackupStoreService';
import { UserDataAutoSyncChannel, UserDataSyncAccountServiceChannel, UserDataSyncMachinesServiceChannel, UserDataSyncStoreManagementServiceChannel, UserDataSyncUtilServiceClient } from 'vs/platform/userDataSync/common/userDataSyncIpc';
Expand Down Expand Up @@ -112,6 +112,7 @@ import { UserDataProfilesCleaner } from 'vs/code/electron-browser/sharedProcess/
import { RemoteTunnelService } from 'vs/platform/remoteTunnel/electron-browser/remoteTunnelService';
import { IRemoteTunnelService } from 'vs/platform/remoteTunnel/common/remoteTunnel';
import { ISharedProcessLifecycleService, SharedProcessLifecycleService } from 'vs/platform/lifecycle/electron-browser/sharedProcessLifecycleService';
import { UserDataSyncResourceProviderService } from 'vs/platform/userDataSync/common/userDataSyncResourceProvider';

class SharedProcessMain extends Disposable {

Expand Down Expand Up @@ -361,6 +362,7 @@ class SharedProcessMain extends Disposable {
services.set(IUserDataSyncEnablementService, new SyncDescriptor(UserDataSyncEnablementService, undefined, true));
services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService, undefined, false /* Initializes the Sync State */));
services.set(IUserDataSyncProfilesStorageService, new SyncDescriptor(UserDataSyncProfilesStorageService, undefined, true));
services.set(IUserDataSyncResourceProviderService, new SyncDescriptor(UserDataSyncResourceProviderService, undefined, true));

// Terminal

Expand Down
66 changes: 7 additions & 59 deletions src/vs/platform/userDataSync/common/abstractSynchronizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { FormattingOptions } from 'vs/base/common/jsonFormatter';
import { Disposable } from 'vs/base/common/lifecycle';
import { IExtUri } from 'vs/base/common/resources';
import { uppercaseFirstLetter } from 'vs/base/common/strings';
import { isString, isUndefined } from 'vs/base/common/types';
import { isUndefined } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { IHeaders } from 'vs/base/parts/request/common/request';
import { localize } from 'vs/nls';
Expand All @@ -26,7 +26,7 @@ import { getServiceMachineId } from 'vs/platform/externalServices/common/service
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
import { Change, getLastSyncResourceUri, IRemoteUserData, IResourcePreview as IBaseResourcePreview, ISyncData, ISyncResourceHandle, IUserDataSyncResourcePreview as IBaseSyncResourcePreview, IUserData, IUserDataInitializer, IUserDataSyncBackupStoreService, IUserDataSyncConfiguration, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, IUserDataSyncUtilService, MergeState, PREVIEW_DIR_NAME, SyncResource, SyncStatus, UserDataSyncError, UserDataSyncErrorCode, USER_DATA_SYNC_CONFIGURATION_SCOPE, USER_DATA_SYNC_SCHEME, IUserDataResourceManifest, getPathSegments, IUserDataSyncResourceConflicts, IUserDataSyncResource } from 'vs/platform/userDataSync/common/userDataSync';
import { Change, getLastSyncResourceUri, IRemoteUserData, IResourcePreview as IBaseResourcePreview, ISyncData, IUserDataSyncResourcePreview as IBaseSyncResourcePreview, IUserData, IUserDataInitializer, IUserDataSyncBackupStoreService, IUserDataSyncConfiguration, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, IUserDataSyncUtilService, MergeState, PREVIEW_DIR_NAME, SyncResource, SyncStatus, UserDataSyncError, UserDataSyncErrorCode, USER_DATA_SYNC_CONFIGURATION_SCOPE, USER_DATA_SYNC_SCHEME, IUserDataResourceManifest, getPathSegments, IUserDataSyncResourceConflicts, IUserDataSyncResource } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';

type IncompatibleSyncSourceClassification = {
Expand Down Expand Up @@ -242,12 +242,7 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
}
}

async replace(uri: URI): Promise<boolean> {
const content = await this.resolveContent(uri);
if (!content) {
return false;
}

async replace(content: string): Promise<boolean> {
const syncData = this.parseSyncData(content);
if (!syncData) {
return false;
Expand Down Expand Up @@ -490,48 +485,6 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
return !!lastSyncData && lastSyncData.syncData !== null /* `null` sync data implies resource is not synced */;
}

async getRemoteSyncResourceHandles(): Promise<ISyncResourceHandle[]> {
const handles = await this.userDataSyncStoreService.getAllResourceRefs(this.resource, this.collection);
return handles.map(({ created, ref }) => ({ created, uri: this.toRemoteBackupResource(ref) }));
}

async getLocalSyncResourceHandles(): Promise<ISyncResourceHandle[]> {
const handles = await this.userDataSyncBackupStoreService.getAllRefs(this.syncResource.profile, this.resource);
return handles.map(({ created, ref }) => ({ created, uri: this.toLocalBackupResource(ref) }));
}

private toRemoteBackupResource(ref: string): URI {
return URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'remote-backup', path: `/${this.syncResource.profile.isDefault ? '' : `${this.syncResource.profile.id}/`}${this.resource}/${ref}` });
}

private toLocalBackupResource(ref: string): URI {
return URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'local-backup', path: `/${this.syncResource.profile.id}/${this.resource}/${ref}` });
}

async getMachineId({ uri }: ISyncResourceHandle): Promise<string | undefined> {
const ref = this.extUri.basename(uri);
if (this.extUri.isEqual(uri, this.toRemoteBackupResource(ref))) {
const { content } = await this.getUserData(ref);
if (content) {
const syncData = this.parseSyncData(content);
return syncData?.machineId;
}
}
return undefined;
}

async resolveContent(uri: URI): Promise<string | null> {
const ref = this.extUri.basename(uri);
if (this.extUri.isEqual(uri, this.toRemoteBackupResource(ref))) {
const { content } = await this.getUserData(ref);
return content;
}
if (this.extUri.isEqual(uri, this.toLocalBackupResource(ref))) {
return this.userDataSyncBackupStoreService.resolveContent(this.syncResource.profile, this.resource, ref);
}
return null;
}

protected async resolvePreviewContent(uri: URI): Promise<string | null> {
const syncPreview = this.syncPreviewPromise ? await this.syncPreviewPromise : null;
if (syncPreview) {
Expand Down Expand Up @@ -670,14 +623,9 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
throw new UserDataSyncError(localize('incompatible sync data', "Cannot parse sync data as it is not compatible with the current version."), UserDataSyncErrorCode.IncompatibleRemoteContent, this.resource);
}

private async getUserData(refOrLastSyncData: string | IRemoteUserData | null): Promise<IUserData> {
if (isString(refOrLastSyncData)) {
const content = await this.userDataSyncStoreService.resolveResourceContent(this.resource, refOrLastSyncData, this.collection);
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.readResource(this.resource, lastSyncUserData, this.collection, this.syncHeaders);
}
private async getUserData(lastSyncData: IRemoteUserData | null): Promise<IUserData> {
const lastSyncUserData: IUserData | null = lastSyncData ? { ref: lastSyncData.ref, content: lastSyncData.syncData ? JSON.stringify(lastSyncData.syncData) : null } : null;
return this.userDataSyncStoreService.readResource(this.resource, lastSyncUserData, this.collection, this.syncHeaders);
}

protected async updateRemoteUserData(content: string, ref: string | null): Promise<IRemoteUserData> {
Expand Down Expand Up @@ -729,7 +677,7 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
protected abstract hasRemoteChanged(lastSyncUserData: IRemoteUserData): Promise<boolean>;

abstract hasLocalData(): Promise<boolean>;
abstract getAssociatedResources(syncResourceHandle: ISyncResourceHandle): Promise<{ resource: URI; comparableResource: URI }[]>;
abstract resolveContent(uri: URI): Promise<string | null>;
}

export interface IFileResourcePreview extends IResourcePreview {
Expand Down
64 changes: 20 additions & 44 deletions src/vs/platform/userDataSync/common/extensionsSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userData
import { AbstractInitializer, AbstractSynchroniser, getSyncResourceLogLabel, IAcceptResult, IMergeResult, IResourcePreview } from 'vs/platform/userDataSync/common/abstractSynchronizer';
import { IMergeResult as IExtensionMergeResult, merge } from 'vs/platform/userDataSync/common/extensionsMerge';
import { IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions';
import { Change, IRemoteUserData, ISyncData, ISyncExtension, ISyncExtensionWithVersion, ISyncResourceHandle, IUserDataSyncBackupStoreService, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, SyncResource, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync';
import { Change, IRemoteUserData, ISyncData, ISyncExtension, ISyncExtensionWithVersion, IUserDataSyncBackupStoreService, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, SyncResource, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService';

type IExtensionResourceMergeResult = IAcceptResult & IExtensionMergeResult;
Expand Down Expand Up @@ -76,9 +76,24 @@ async function parseAndMigrateExtensions(syncData: ISyncData, extensionManagemen
return extensions;
}

export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
export function parseExtensions(syncData: ISyncData): ISyncExtension[] {
return JSON.parse(syncData.content);
}

export function stringify(extensions: ISyncExtension[], format: boolean): string {
extensions.sort((e1, e2) => {
if (!e1.identifier.uuid && e2.identifier.uuid) {
return -1;
}
if (e1.identifier.uuid && !e2.identifier.uuid) {
return 1;
}
return compare(e1.identifier.id, e2.identifier.id);
});
return format ? toFormattedString(extensions, {}) : JSON.stringify(extensions);
}

private static readonly EXTENSIONS_DATA_URI = URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'extensions', path: `/extensions.json` });
export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {

/*
Version 3 - Introduce installed property to skip installing built in extensions
Expand Down Expand Up @@ -292,16 +307,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
}
}

async getAssociatedResources({ uri }: ISyncResourceHandle): Promise<{ resource: URI; comparableResource: URI }[]> {
return [{ resource: this.extUri.joinPath(uri, 'extensions.json'), comparableResource: ExtensionsSynchroniser.EXTENSIONS_DATA_URI }];
}

override async resolveContent(uri: URI): Promise<string | null> {
if (this.extUri.isEqual(uri, ExtensionsSynchroniser.EXTENSIONS_DATA_URI)) {
const { localExtensions, ignoredExtensions } = await this.localExtensionsProvider.getLocalExtensions(this.profile);
return this.stringify(localExtensions.filter(e => !ignoredExtensions.some(id => areSameExtensions({ id }, e.identifier))), true);
}

async resolveContent(uri: URI): Promise<string | null> {
if (this.extUri.isEqual(this.remoteResource, uri)
|| this.extUri.isEqual(this.baseResource, uri)
|| this.extUri.isEqual(this.localResource, uri)
Expand All @@ -310,37 +316,11 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
const content = await this.resolvePreviewContent(uri);
return content ? this.stringify(JSON.parse(content), true) : content;
}

let content = await super.resolveContent(uri);
if (content) {
return content;
}

content = await super.resolveContent(this.extUri.dirname(uri));
if (content) {
const syncData = this.parseSyncData(content);
if (syncData) {
switch (this.extUri.basename(uri)) {
case 'extensions.json':
return this.stringify(this.parseExtensions(syncData), true);
}
}
}

return null;
}

private stringify(extensions: ISyncExtension[], format: boolean): string {
extensions.sort((e1, e2) => {
if (!e1.identifier.uuid && e2.identifier.uuid) {
return -1;
}
if (e1.identifier.uuid && !e2.identifier.uuid) {
return 1;
}
return compare(e1.identifier.id, e2.identifier.id);
});
return format ? toFormattedString(extensions, {}) : JSON.stringify(extensions);
return stringify(extensions, format);
}

async hasLocalData(): Promise<boolean> {
Expand All @@ -355,10 +335,6 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
return false;
}

private parseExtensions(syncData: ISyncData): ISyncExtension[] {
return JSON.parse(syncData.content);
}

}

export class LocalExtensionsProvider {
Expand Down
33 changes: 3 additions & 30 deletions src/vs/platform/userDataSync/common/globalStateSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
import { AbstractInitializer, AbstractSynchroniser, getSyncResourceLogLabel, IAcceptResult, IMergeResult, IResourcePreview, isSyncData } from 'vs/platform/userDataSync/common/abstractSynchronizer';
import { edit } from 'vs/platform/userDataSync/common/content';
import { merge } from 'vs/platform/userDataSync/common/globalStateMerge';
import { ALL_SYNC_RESOURCES, Change, createSyncHeaders, getEnablementKey, IGlobalState, IRemoteUserData, IStorageValue, ISyncData, ISyncResourceHandle, IUserData, IUserDataSyncBackupStoreService, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, SyncResource, SYNC_SERVICE_URL_TYPE, UserDataSyncError, UserDataSyncErrorCode, UserDataSyncStoreType, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync';
import { ALL_SYNC_RESOURCES, Change, createSyncHeaders, getEnablementKey, IGlobalState, IRemoteUserData, IStorageValue, ISyncData, IUserData, IUserDataSyncBackupStoreService, IUserDataSynchroniser, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncStoreService, SyncResource, SYNC_SERVICE_URL_TYPE, UserDataSyncError, UserDataSyncErrorCode, UserDataSyncStoreType, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { IUserDataSyncProfilesStorageService } from 'vs/platform/userDataSync/common/userDataSyncProfilesStorageService';
Expand All @@ -47,7 +47,7 @@ export interface IGlobalStateResourcePreview extends IResourcePreview {
readonly storageKeys: StorageKeys;
}

function stringify(globalState: IGlobalState, format: boolean): string {
export function stringify(globalState: IGlobalState, format: boolean): string {
const storageKeys = globalState.storage ? Object.keys(globalState.storage).sort() : [];
const storage: IStringDictionary<IStorageValue> = {};
storageKeys.forEach(key => storage[key] = globalState.storage[key]);
Expand All @@ -68,7 +68,6 @@ const GLOBAL_STATE_DATA_VERSION = 1;
*/
export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {

private static readonly GLOBAL_STATE_DATA_URI = URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority: 'globalState', path: `/globalState.json` });
protected readonly version: number = GLOBAL_STATE_DATA_VERSION;
private readonly previewResource: URI = this.extUri.joinPath(this.syncPreviewFolder, 'globalState.json');
private readonly baseResource: URI = this.previewResource.with({ scheme: USER_DATA_SYNC_SCHEME, authority: 'base' });
Expand Down Expand Up @@ -258,16 +257,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
}
}

async getAssociatedResources({ uri }: ISyncResourceHandle): Promise<{ resource: URI; comparableResource: URI }[]> {
return [{ resource: this.extUri.joinPath(uri, 'globalState.json'), comparableResource: GlobalStateSynchroniser.GLOBAL_STATE_DATA_URI }];
}

override async resolveContent(uri: URI): Promise<string | null> {
if (this.extUri.isEqual(uri, GlobalStateSynchroniser.GLOBAL_STATE_DATA_URI)) {
const localGlobalState = await this.localGlobalStateProvider.getLocalGlobalState(this.syncResource.profile);
return stringify(localGlobalState, true);
}

async resolveContent(uri: URI): Promise<string | null> {
if (this.extUri.isEqual(this.remoteResource, uri)
|| this.extUri.isEqual(this.baseResource, uri)
|| this.extUri.isEqual(this.localResource, uri)
Expand All @@ -276,23 +266,6 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
const content = await this.resolvePreviewContent(uri);
return content ? stringify(JSON.parse(content), true) : content;
}

let content = await super.resolveContent(uri);
if (content) {
return content;
}

content = await super.resolveContent(this.extUri.dirname(uri));
if (content) {
const syncData = this.parseSyncData(content);
if (syncData) {
switch (this.extUri.basename(uri)) {
case 'globalState.json':
return stringify(JSON.parse(syncData.content), true);
}
}
}

return null;
}

Expand Down
Loading