提交 e715f396 编写于 作者: S Sandeep Somavarapu

💄

上级 c13bf7ad
......@@ -4,30 +4,87 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { IFileService } from 'vs/platform/files/common/files';
import { IFileService, IFileContent } from 'vs/platform/files/common/files';
import { VSBuffer } from 'vs/base/common/buffer';
import { URI } from 'vs/base/common/uri';
import { SyncSource } from 'vs/platform/userDataSync/common/userDataSync';
import { SyncSource, SyncStatus, IUserData, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { joinPath } from 'vs/base/common/resources';
import { joinPath, dirname } from 'vs/base/common/resources';
import { toLocalISOString } from 'vs/base/common/date';
import { ThrottledDelayer } from 'vs/base/common/async';
import { Emitter, Event } from 'vs/base/common/event';
export abstract class AbstractSynchroniser extends Disposable {
protected readonly syncFolder: URI;
private cleanUpDelayer: ThrottledDelayer<void>;
private _status: SyncStatus = SyncStatus.Idle;
get status(): SyncStatus { return this._status; }
private _onDidChangStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangStatus.event;
protected readonly _onDidChangeLocal: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChangeLocal: Event<void> = this._onDidChangeLocal.event;
protected readonly lastSyncResource: URI;
constructor(
readonly source: SyncSource,
@IFileService protected readonly fileService: IFileService,
@IEnvironmentService environmentService: IEnvironmentService
@IEnvironmentService environmentService: IEnvironmentService,
@IUserDataSyncStoreService protected readonly userDataSyncStoreService: IUserDataSyncStoreService,
) {
super();
this.syncFolder = joinPath(environmentService.userDataSyncHome, source);
this.lastSyncResource = joinPath(this.syncFolder, `.lastSync${source}.json`);
this.cleanUpDelayer = new ThrottledDelayer(50);
}
protected setStatus(status: SyncStatus): void {
if (this._status !== status) {
this._status = status;
this._onDidChangStatus.fire(status);
}
}
async hasPreviouslySynced(): Promise<boolean> {
const lastSyncData = await this.getLastSyncUserData();
return !!lastSyncData;
}
async hasRemoteData(): Promise<boolean> {
const remoteUserData = await this.getRemoteUserData();
return remoteUserData.content !== null;
}
async resetLocal(): Promise<void> {
try {
await this.fileService.del(this.lastSyncResource);
} catch (e) { /* ignore */ }
}
protected async getLastSyncUserData<T extends IUserData>(): Promise<T | null> {
try {
const content = await this.fileService.readFile(this.lastSyncResource);
return JSON.parse(content.value.toString());
} catch (error) {
return null;
}
}
protected async updateLastSyncUserData<T extends IUserData>(lastSyncUserData: T): Promise<void> {
await this.fileService.writeFile(this.lastSyncResource, VSBuffer.fromString(JSON.stringify(lastSyncUserData)));
}
protected getRemoteUserData(lastSyncData?: IUserData | null): Promise<IUserData> {
return this.userDataSyncStoreService.read(this.getRemoteDataResourceKey(), lastSyncData || null, this.source);
}
protected async updateRemoteUserData(content: string, ref: string | null): Promise<string> {
return this.userDataSyncStoreService.write(this.getRemoteDataResourceKey(), content, ref, this.source);
}
protected async backupLocal(content: VSBuffer): Promise<void> {
const resource = joinPath(this.syncFolder, toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, ''));
await this.fileService.writeFile(resource, content);
......@@ -43,4 +100,40 @@ export abstract class AbstractSynchroniser extends Disposable {
}
}
protected abstract getRemoteDataResourceKey(): string;
}
export abstract class AbstractFileSynchroniser extends AbstractSynchroniser {
constructor(
protected readonly file: URI,
readonly source: SyncSource,
@IFileService fileService: IFileService,
@IEnvironmentService environmentService: IEnvironmentService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
) {
super(source, fileService, environmentService, userDataSyncStoreService);
this._register(this.fileService.watch(dirname(file)));
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(file))(() => this._onDidChangeLocal.fire()));
}
protected async getLocalFileContent(): Promise<IFileContent | null> {
try {
return await this.fileService.readFile(this.file);
} catch (error) {
return null;
}
}
protected async updateLocalFileContent(newContent: string, oldContent: IFileContent | null): Promise<void> {
if (oldContent) {
// file exists already
await this.backupLocal(oldContent.value);
await this.fileService.writeFile(this.file, VSBuffer.fromString(newContent), oldContent);
} else {
// file does not exist
await this.fileService.createFile(this.file, VSBuffer.fromString(newContent), { overwrite: false });
}
}
}
......@@ -4,16 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncSource } from 'vs/platform/userDataSync/common/userDataSync';
import { VSBuffer } from 'vs/base/common/buffer';
import { Emitter, Event } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { URI } from 'vs/base/common/uri';
import { joinPath } from 'vs/base/common/resources';
import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionType, IExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IFileService } from 'vs/platform/files/common/files';
import { Queue } from 'vs/base/common/async';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { localize } from 'vs/nls';
import { merge } from 'vs/platform/userDataSync/common/extensionsMerge';
......@@ -35,32 +31,17 @@ interface ILastSyncUserData extends IUserData {
export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
private static EXTERNAL_USER_DATA_EXTENSIONS_KEY: string = 'extensions';
private _status: SyncStatus = SyncStatus.Idle;
get status(): SyncStatus { return this._status; }
private _onDidChangStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangStatus.event;
private _onDidChangeLocal: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChangeLocal: Event<void> = this._onDidChangeLocal.event;
private readonly lastSyncExtensionsResource: URI;
private readonly replaceQueue: Queue<void>;
constructor(
@IEnvironmentService environmentService: IEnvironmentService,
@IFileService fileService: IFileService,
@IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IGlobalExtensionEnablementService private readonly extensionEnablementService: IGlobalExtensionEnablementService,
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
@IConfigurationService private readonly configurationService: IConfigurationService,
) {
super(SyncSource.Extensions, fileService, environmentService);
this.replaceQueue = this._register(new Queue());
this.lastSyncExtensionsResource = joinPath(this.syncFolder, '.lastSyncExtensions');
super(SyncSource.Extensions, fileService, environmentService, userDataSyncStoreService);
this._register(
Event.debounce(
Event.any(
......@@ -69,12 +50,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
() => undefined, 500)(() => this._onDidChangeLocal.fire()));
}
private setStatus(status: SyncStatus): void {
if (this._status !== status) {
this._status = status;
this._onDidChangStatus.fire(status);
}
}
protected getRemoteDataResourceKey(): string { return 'extensions'; }
async pull(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableExtensions')) {
......@@ -176,16 +152,6 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
throw new Error('Extensions: Conflicts should not occur');
}
async hasPreviouslySynced(): Promise<boolean> {
const lastSyncData = await this.getLastSyncUserData();
return !!lastSyncData;
}
async hasRemoteData(): Promise<boolean> {
const remoteUserData = await this.getRemoteUserData();
return remoteUserData.content !== null;
}
async hasLocalData(): Promise<boolean> {
try {
const localExtensions = await this.getLocalExtensions();
......@@ -202,30 +168,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
return null;
}
removeExtension(identifier: IExtensionIdentifier): Promise<void> {
return this.replaceQueue.queue(async () => {
const remoteData = await this.userDataSyncStoreService.read(ExtensionsSynchroniser.EXTERNAL_USER_DATA_EXTENSIONS_KEY, null);
const remoteExtensions: ISyncExtension[] = remoteData.content ? JSON.parse(remoteData.content) : [];
const ignoredExtensions = this.configurationService.getValue<string[]>('sync.ignoredExtensions') || [];
const removedExtensions = remoteExtensions.filter(e => !ignoredExtensions.some(id => areSameExtensions({ id }, e.identifier)) && areSameExtensions(e.identifier, identifier));
if (removedExtensions.length) {
for (const removedExtension of removedExtensions) {
remoteExtensions.splice(remoteExtensions.indexOf(removedExtension), 1);
}
this.logService.info(`Extensions: Removing extension '${identifier.id}' from remote.`);
await this.writeToRemote(remoteExtensions, remoteData.ref);
}
});
}
async resetLocal(): Promise<void> {
try {
await this.fileService.del(this.lastSyncExtensionsResource);
} catch (e) { /* ignore */ }
}
private async getPreview(): Promise<ISyncPreviewResult> {
const lastSyncData = await this.getLastSyncUserData();
const lastSyncData = await this.getLastSyncUserData<ILastSyncUserData>();
const lastSyncExtensions: ISyncExtension[] | null = lastSyncData ? JSON.parse(lastSyncData.content!) : null;
const skippedExtensions: ISyncExtension[] = lastSyncData ? lastSyncData.skippedExtensions || [] : [];
......@@ -262,13 +206,15 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
if (remote) {
// update remote
this.logService.info('Extensions: Updating remote extensions...');
remoteUserData = await this.writeToRemote(remote, forcePush ? null : remoteUserData.ref);
const content = JSON.stringify(remote);
const ref = await this.updateRemoteUserData(content, forcePush ? null : remoteUserData.ref);
remoteUserData = { ref, content };
}
if (remoteUserData.content) {
// update last sync
this.logService.info('Extensions: Updating last synchronised extensions...');
await this.updateLastSyncValue({ ...remoteUserData, skippedExtensions });
await this.updateLastSyncUserData<ILastSyncUserData>({ ...remoteUserData, skippedExtensions });
}
}
......@@ -331,27 +277,4 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
.map(({ identifier }) => ({ identifier, enabled: !disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier)) }));
}
private async getLastSyncUserData(): Promise<ILastSyncUserData | null> {
try {
const content = await this.fileService.readFile(this.lastSyncExtensionsResource);
return JSON.parse(content.value.toString());
} catch (error) {
return null;
}
}
private async updateLastSyncValue(lastSyncUserData: ILastSyncUserData): Promise<void> {
await this.fileService.writeFile(this.lastSyncExtensionsResource, VSBuffer.fromString(JSON.stringify(lastSyncUserData)));
}
private getRemoteUserData(lastSyncData?: IUserData | null): Promise<IUserData> {
return this.userDataSyncStoreService.read(ExtensionsSynchroniser.EXTERNAL_USER_DATA_EXTENSIONS_KEY, lastSyncData || null, this.source);
}
private async writeToRemote(extensions: ISyncExtension[], ref: string | null): Promise<IUserData> {
const content = JSON.stringify(extensions);
ref = await this.userDataSyncStoreService.write(ExtensionsSynchroniser.EXTERNAL_USER_DATA_EXTENSIONS_KEY, content, ref, this.source);
return { content, ref };
}
}
......@@ -5,10 +5,9 @@
import { IUserData, UserDataSyncError, UserDataSyncErrorCode, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState, SyncSource, IUserDataSynchroniser } from 'vs/platform/userDataSync/common/userDataSync';
import { VSBuffer } from 'vs/base/common/buffer';
import { Emitter, Event } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { URI } from 'vs/base/common/uri';
import { joinPath, dirname } from 'vs/base/common/resources';
import { dirname } from 'vs/base/common/resources';
import { IFileService } from 'vs/platform/files/common/files';
import { IStringDictionary } from 'vs/base/common/collections';
import { edit } from 'vs/platform/userDataSync/common/content';
......@@ -27,37 +26,19 @@ interface ISyncPreviewResult {
export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
private static EXTERNAL_USER_DATA_GLOBAL_STATE_KEY: string = 'globalState';
private _status: SyncStatus = SyncStatus.Idle;
get status(): SyncStatus { return this._status; }
private _onDidChangStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangStatus.event;
private _onDidChangeLocal: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChangeLocal: Event<void> = this._onDidChangeLocal.event;
private readonly lastSyncGlobalStateResource: URI;
constructor(
@IFileService fileService: IFileService,
@IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService,
) {
super(SyncSource.UIState, fileService, environmentService);
this.lastSyncGlobalStateResource = joinPath(this.syncFolder, '.lastSyncGlobalState');
super(SyncSource.GlobalState, fileService, environmentService, userDataSyncStoreService);
this._register(this.fileService.watch(dirname(this.environmentService.argvResource)));
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.environmentService.argvResource))(() => this._onDidChangeLocal.fire()));
}
private setStatus(status: SyncStatus): void {
if (this._status !== status) {
this._status = status;
this._onDidChangStatus.fire(status);
}
}
protected getRemoteDataResourceKey(): string { return 'globalState'; }
async pull(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableUIState')) {
......@@ -153,16 +134,6 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
throw new Error('UI State: Conflicts should not occur');
}
async hasPreviouslySynced(): Promise<boolean> {
const lastSyncData = await this.getLastSyncUserData();
return !!lastSyncData;
}
async hasRemoteData(): Promise<boolean> {
const remoteUserData = await this.getRemoteUserData();
return remoteUserData.content !== null;
}
async hasLocalData(): Promise<boolean> {
try {
const localGloablState = await this.getLocalGlobalState();
......@@ -179,12 +150,6 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
return null;
}
async resetLocal(): Promise<void> {
try {
await this.fileService.del(this.lastSyncGlobalStateResource);
} catch (e) { /* ignore */ }
}
private async getPreview(): Promise<ISyncPreviewResult> {
const lastSyncData = await this.getLastSyncUserData();
const lastSyncGlobalState = lastSyncData && lastSyncData.content ? JSON.parse(lastSyncData.content) : null;
......@@ -209,13 +174,15 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
if (remote) {
// update remote
this.logService.info('UI State: Updating remote ui state...');
remoteUserData = await this.writeToRemote(remote, forcePush ? null : remoteUserData.ref);
const content = JSON.stringify(remote);
const ref = await this.updateRemoteUserData(content, forcePush ? null : remoteUserData.ref);
remoteUserData = { ref, content };
}
if (remoteUserData.content) {
// update last sync
this.logService.info('UI State: Updating last synchronised ui state...');
await this.updateLastSyncValue(remoteUserData);
await this.updateLastSyncUserData(remoteUserData);
}
}
......@@ -245,27 +212,4 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
}
}
private async getLastSyncUserData(): Promise<IUserData | null> {
try {
const content = await this.fileService.readFile(this.lastSyncGlobalStateResource);
return JSON.parse(content.value.toString());
} catch (error) {
return null;
}
}
private async updateLastSyncValue(remoteUserData: IUserData): Promise<void> {
await this.fileService.writeFile(this.lastSyncGlobalStateResource, VSBuffer.fromString(JSON.stringify(remoteUserData)));
}
private getRemoteUserData(lastSyncData?: IUserData | null): Promise<IUserData> {
return this.userDataSyncStoreService.read(GlobalStateSynchroniser.EXTERNAL_USER_DATA_GLOBAL_STATE_KEY, lastSyncData || null, this.source);
}
private async writeToRemote(globalState: IGlobalState, ref: string | null): Promise<IUserData> {
const content = JSON.stringify(globalState);
ref = await this.userDataSyncStoreService.write(GlobalStateSynchroniser.EXTERNAL_USER_DATA_GLOBAL_STATE_KEY, content, ref, this.source);
return { content, ref };
}
}
......@@ -9,18 +9,15 @@ import { merge } from 'vs/platform/userDataSync/common/keybindingsMerge';
import { VSBuffer } from 'vs/base/common/buffer';
import { parse, ParseError } from 'vs/base/common/json';
import { localize } from 'vs/nls';
import { Emitter, Event } from 'vs/base/common/event';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { URI } from 'vs/base/common/uri';
import { joinPath, dirname } from 'vs/base/common/resources';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CancellationToken } from 'vs/base/common/cancellation';
import { OS, OperatingSystem } from 'vs/base/common/platform';
import { isUndefined } from 'vs/base/common/types';
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
import { AbstractFileSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
interface ISyncContent {
mac?: string;
......@@ -37,42 +34,22 @@ interface ISyncPreviewResult {
readonly hasConflicts: boolean;
}
export class KeybindingsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
private static EXTERNAL_USER_DATA_KEYBINDINGS_KEY: string = 'keybindings';
export class KeybindingsSynchroniser extends AbstractFileSynchroniser implements IUserDataSynchroniser {
private syncPreviewResultPromise: CancelablePromise<ISyncPreviewResult> | null = null;
private _status: SyncStatus = SyncStatus.Idle;
get status(): SyncStatus { return this._status; }
private _onDidChangStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangStatus.event;
private _onDidChangeLocal: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChangeLocal: Event<void> = this._onDidChangeLocal.event;
private readonly lastSyncKeybindingsResource: URI;
constructor(
@IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IFileService fileService: IFileService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IUserDataSyncUtilService private readonly userDataSyncUtilService: IUserDataSyncUtilService,
) {
super(SyncSource.Keybindings, fileService, environmentService);
this.lastSyncKeybindingsResource = joinPath(this.syncFolder, '.lastSyncKeybindings.json');
this._register(this.fileService.watch(dirname(this.environmentService.keybindingsResource)));
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.environmentService.keybindingsResource))(() => this._onDidChangeLocal.fire()));
super(environmentService.keybindingsResource, SyncSource.Keybindings, fileService, environmentService, userDataSyncStoreService);
}
private setStatus(status: SyncStatus): void {
if (this._status !== status) {
this._status = status;
this._onDidChangStatus.fire(status);
}
}
protected getRemoteDataResourceKey(): string { return 'keybindings'; }
async pull(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableKeybindings')) {
......@@ -204,16 +181,6 @@ export class KeybindingsSynchroniser extends AbstractSynchroniser implements IUs
}
}
async hasPreviouslySynced(): Promise<boolean> {
const lastSyncData = await this.getLastSyncUserData();
return !!lastSyncData;
}
async hasRemoteData(): Promise<boolean> {
const remoteUserData = await this.getRemoteUserData();
return remoteUserData.content !== null;
}
async hasLocalData(): Promise<boolean> {
try {
const localFileContent = await this.getLocalFileContent();
......@@ -243,12 +210,6 @@ export class KeybindingsSynchroniser extends AbstractSynchroniser implements IUs
return content ? this.getKeybindingsContentFromSyncContent(content) : null;
}
async resetLocal(): Promise<void> {
try {
await this.fileService.del(this.lastSyncKeybindingsResource);
} catch (e) { /* ignore */ }
}
private async doSync(): Promise<void> {
try {
const result = await this.getPreview();
......@@ -306,7 +267,7 @@ export class KeybindingsSynchroniser extends AbstractSynchroniser implements IUs
}
if (hasLocalChanged) {
this.logService.info('Keybindings: Updating local keybindings');
await this.updateLocalContent(content, fileContent);
await this.updateLocalFileContent(content, fileContent);
}
if (hasRemoteChanged) {
this.logService.info('Keybindings: Updating remote keybindings');
......@@ -400,46 +361,6 @@ export class KeybindingsSynchroniser extends AbstractSynchroniser implements IUs
return this._formattingOptions;
}
private async getLocalFileContent(): Promise<IFileContent | null> {
try {
return await this.fileService.readFile(this.environmentService.keybindingsResource);
} catch (error) {
return null;
}
}
private async updateLocalContent(newContent: string, oldContent: IFileContent | null): Promise<void> {
if (oldContent) {
// file exists already
await this.backupLocal(oldContent.value);
await this.fileService.writeFile(this.environmentService.keybindingsResource, VSBuffer.fromString(newContent), oldContent);
} else {
// file does not exist
await this.fileService.createFile(this.environmentService.keybindingsResource, VSBuffer.fromString(newContent), { overwrite: false });
}
}
private async getLastSyncUserData(): Promise<IUserData | null> {
try {
const content = await this.fileService.readFile(this.lastSyncKeybindingsResource);
return JSON.parse(content.value.toString());
} catch (error) {
return null;
}
}
private async updateLastSyncUserData(remoteUserData: IUserData): Promise<void> {
await this.fileService.writeFile(this.lastSyncKeybindingsResource, VSBuffer.fromString(JSON.stringify(remoteUserData)));
}
private async getRemoteUserData(lastSyncData?: IUserData | null): Promise<IUserData> {
return this.userDataSyncStoreService.read(KeybindingsSynchroniser.EXTERNAL_USER_DATA_KEYBINDINGS_KEY, lastSyncData || null, this.source);
}
private async updateRemoteUserData(content: string, ref: string | null): Promise<string> {
return this.userDataSyncStoreService.write(KeybindingsSynchroniser.EXTERNAL_USER_DATA_KEYBINDINGS_KEY, content, ref, this.source);
}
private getKeybindingsContentFromSyncContent(syncContent: string): string | null {
try {
const parsed = <ISyncContent>JSON.parse(syncContent);
......
......@@ -11,8 +11,6 @@ import { localize } from 'vs/nls';
import { Emitter, Event } from 'vs/base/common/event';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { URI } from 'vs/base/common/uri';
import { joinPath, dirname } from 'vs/base/common/resources';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { startsWith } from 'vs/base/common/strings';
import { CancellationToken } from 'vs/base/common/cancellation';
......@@ -22,7 +20,7 @@ import * as arrays from 'vs/base/common/arrays';
import * as objects from 'vs/base/common/objects';
import { isEmptyObject } from 'vs/base/common/types';
import { edit } from 'vs/platform/userDataSync/common/content';
import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
import { AbstractFileSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
interface ISyncPreviewResult {
readonly fileContent: IFileContent | null;
......@@ -34,49 +32,33 @@ interface ISyncPreviewResult {
readonly conflictSettings: IConflictSetting[];
}
export class SettingsSynchroniser extends AbstractSynchroniser implements ISettingsSyncService {
export class SettingsSynchroniser extends AbstractFileSynchroniser implements ISettingsSyncService {
_serviceBrand: any;
private static EXTERNAL_USER_DATA_SETTINGS_KEY: string = 'settings';
private syncPreviewResultPromise: CancelablePromise<ISyncPreviewResult> | null = null;
private _status: SyncStatus = SyncStatus.Idle;
get status(): SyncStatus { return this._status; }
private _onDidChangStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangStatus.event;
private _conflicts: IConflictSetting[] = [];
get conflicts(): IConflictSetting[] { return this._conflicts; }
private _onDidChangeConflicts: Emitter<IConflictSetting[]> = this._register(new Emitter<IConflictSetting[]>());
readonly onDidChangeConflicts: Event<IConflictSetting[]> = this._onDidChangeConflicts.event;
private _onDidChangeLocal: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChangeLocal: Event<void> = this._onDidChangeLocal.event;
private readonly lastSyncSettingsResource: URI;
constructor(
@IFileService fileService: IFileService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
@IUserDataSyncUtilService private readonly userDataSyncUtilService: IUserDataSyncUtilService,
@IConfigurationService private readonly configurationService: IConfigurationService,
) {
super(SyncSource.Settings, fileService, environmentService);
this.lastSyncSettingsResource = joinPath(this.syncFolder, '.lastSyncSettings.json');
this._register(this.fileService.watch(dirname(this.environmentService.settingsResource)));
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.environmentService.settingsResource))(() => this._onDidChangeLocal.fire()));
super(environmentService.settingsResource, SyncSource.Settings, fileService, environmentService, userDataSyncStoreService);
}
private setStatus(status: SyncStatus): void {
if (this._status !== status) {
this._status = status;
this._onDidChangStatus.fire(status);
}
if (this._status !== SyncStatus.HasConflicts) {
protected getRemoteDataResourceKey(): string { return 'settings'; }
protected setStatus(status: SyncStatus): void {
super.setStatus(status);
if (this.status !== SyncStatus.HasConflicts) {
this.setConflicts([]);
}
}
......@@ -206,16 +188,6 @@ export class SettingsSynchroniser extends AbstractSynchroniser implements ISetti
this.setStatus(SyncStatus.Idle);
}
async hasPreviouslySynced(): Promise<boolean> {
const lastSyncData = await this.getLastSyncUserData();
return !!lastSyncData;
}
async hasRemoteData(): Promise<boolean> {
const remoteUserData = await this.getRemoteUserData();
return remoteUserData.content !== null;
}
async hasLocalData(): Promise<boolean> {
try {
const localFileContent = await this.getLocalFileContent();
......@@ -279,12 +251,6 @@ export class SettingsSynchroniser extends AbstractSynchroniser implements ISetti
}
}
async resetLocal(): Promise<void> {
try {
await this.fileService.del(this.lastSyncSettingsResource);
} catch (e) { /* ignore */ }
}
private async doSync(resolvedConflicts: { key: string, value: any | undefined }[]): Promise<void> {
try {
const result = await this.getPreview(resolvedConflicts);
......@@ -343,18 +309,18 @@ export class SettingsSynchroniser extends AbstractSynchroniser implements ISetti
}
if (hasLocalChanged) {
this.logService.info('Settings: Updating local settings');
await this.writeToLocal(content, fileContent);
await this.updateLocalFileContent(content, fileContent);
}
if (hasRemoteChanged) {
const formatUtils = await this.getFormattingOptions();
const remoteContent = updateIgnoredSettings(content, remoteUserData.content || '{}', getIgnoredSettings(this.configurationService, content), formatUtils);
this.logService.info('Settings: Updating remote settings');
const ref = await this.writeToRemote(remoteContent, forcePush ? null : remoteUserData.ref);
const ref = await this.updateRemoteUserData(remoteContent, forcePush ? null : remoteUserData.ref);
remoteUserData = { ref, content };
}
if (remoteUserData.content) {
this.logService.info('Settings: Updating last synchronised sttings');
await this.updateLastSyncValue(remoteUserData);
await this.updateLastSyncUserData(remoteUserData);
}
// Delete the preview
......@@ -436,46 +402,6 @@ export class SettingsSynchroniser extends AbstractSynchroniser implements ISetti
return this._formattingOptions;
}
private async getLastSyncUserData(): Promise<IUserData | null> {
try {
const content = await this.fileService.readFile(this.lastSyncSettingsResource);
return JSON.parse(content.value.toString());
} catch (error) {
return null;
}
}
private async getLocalFileContent(): Promise<IFileContent | null> {
try {
return await this.fileService.readFile(this.environmentService.settingsResource);
} catch (error) {
return null;
}
}
private getRemoteUserData(lastSyncData?: IUserData | null): Promise<IUserData> {
return this.userDataSyncStoreService.read(SettingsSynchroniser.EXTERNAL_USER_DATA_SETTINGS_KEY, lastSyncData || null, this.source);
}
private async writeToRemote(content: string, ref: string | null): Promise<string> {
return this.userDataSyncStoreService.write(SettingsSynchroniser.EXTERNAL_USER_DATA_SETTINGS_KEY, content, ref, this.source);
}
private async writeToLocal(newContent: string, oldContent: IFileContent | null): Promise<void> {
if (oldContent) {
// file exists already
await this.backupLocal(oldContent.value);
await this.fileService.writeFile(this.environmentService.settingsResource, VSBuffer.fromString(newContent), oldContent);
} else {
// file does not exist
await this.fileService.createFile(this.environmentService.settingsResource, VSBuffer.fromString(newContent), { overwrite: false });
}
}
private async updateLastSyncValue(remoteUserData: IUserData): Promise<void> {
await this.fileService.writeFile(this.lastSyncSettingsResource, VSBuffer.fromString(JSON.stringify(remoteUserData)));
}
}
export function getIgnoredSettings(configurationService: IConfigurationService, settingsContent?: string): string[] {
......
......@@ -174,7 +174,7 @@ export const enum SyncSource {
Settings = 'Settings',
Keybindings = 'Keybindings',
Extensions = 'Extensions',
UIState = 'UI State'
GlobalState = 'GlobalState'
}
export const enum SyncStatus {
......@@ -212,7 +212,6 @@ export interface IUserDataSyncService extends ISynchroniser {
isFirstTimeSyncAndHasUserData(): Promise<boolean>;
reset(): Promise<void>;
resetLocal(): Promise<void>;
removeExtension(identifier: IExtensionIdentifier): Promise<void>;
getRemoteContent(source: SyncSource): Promise<string | null>;
resolveConflictsAndContinueSync(content: string): Promise<void>;
}
......@@ -267,5 +266,5 @@ export function toRemoteContentResource(source: SyncSource): URI {
return URI.from({ scheme: USER_DATA_SYNC_SCHEME, path: `${source}/remoteContent` });
}
export function getSyncSourceFromRemoteContentResource(uri: URI): SyncSource | undefined {
return [SyncSource.Settings, SyncSource.Keybindings, SyncSource.Extensions, SyncSource.UIState].filter(source => isEqual(uri, toRemoteContentResource(source)))[0];
return [SyncSource.Settings, SyncSource.Keybindings, SyncSource.Extensions, SyncSource.GlobalState].filter(source => isEqual(uri, toRemoteContentResource(source)))[0];
}
......@@ -30,7 +30,6 @@ export class UserDataSyncChannel implements IServerChannel {
case 'push': return this.service.push();
case '_getInitialStatus': return Promise.resolve(this.service.status);
case 'getConflictsSource': return Promise.resolve(this.service.conflictsSource);
case 'removeExtension': return this.service.removeExtension(args[0]);
case 'stop': this.service.stop(); return Promise.resolve();
case 'restart': return this.service.restart().then(() => this.service.status);
case 'reset': return this.service.reset();
......
......@@ -9,7 +9,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync';
import { Emitter, Event } from 'vs/base/common/event';
import { ExtensionsSynchroniser } from 'vs/platform/userDataSync/common/extensionsSync';
import { IExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { KeybindingsSynchroniser } from 'vs/platform/userDataSync/common/keybindingsSync';
import { GlobalStateSynchroniser } from 'vs/platform/userDataSync/common/globalStateSync';
import { toErrorMessage } from 'vs/base/common/errorMessage';
......@@ -253,10 +252,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
this.logService.info('Completed resetting local cache');
}
removeExtension(identifier: IExtensionIdentifier): Promise<void> {
return this.extensionsSynchroniser.removeExtension(identifier);
}
private updateStatus(): void {
const status = this.computeStatus();
if (this._status !== status) {
......@@ -309,7 +304,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
if (synchroniser instanceof ExtensionsSynchroniser) {
return SyncSource.Extensions;
}
return SyncSource.UIState;
return SyncSource.GlobalState;
}
private onDidChangeAuthTokenStatus(token: string | undefined): void {
......
......@@ -60,7 +60,7 @@ function getSyncAreaLabel(source: SyncSource): string {
case SyncSource.Settings: return localize('settings', "Settings");
case SyncSource.Keybindings: return localize('keybindings', "Keybindings");
case SyncSource.Extensions: return localize('extensions', "Extensions");
case SyncSource.UIState: return localize('ui state label', "UI State");
case SyncSource.GlobalState: return localize('ui state label', "UI State");
}
}
......@@ -367,7 +367,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
label: getSyncAreaLabel(SyncSource.Extensions)
}, {
id: 'sync.enableUIState',
label: getSyncAreaLabel(SyncSource.UIState),
label: getSyncAreaLabel(SyncSource.GlobalState),
description: localize('ui state description', "Display Language (Only)")
}];
}
......
......@@ -9,7 +9,6 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
export class UserDataSyncService extends Disposable implements IUserDataSyncService {
......@@ -91,10 +90,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
return this.channel.call('isFirstTimeSyncAndHasUserData');
}
removeExtension(identifier: IExtensionIdentifier): Promise<void> {
return this.channel.call('removeExtension', [identifier]);
}
private async updateStatus(status: SyncStatus): Promise<void> {
this._conflictsSource = await this.channel.call<SyncSource>('getConflictsSource');
this._status = status;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册