Merge from vscode 3c6f6af7347d38e87bc6406024e8dcf9e9bce229 (#8962)

* Merge from vscode 3c6f6af7347d38e87bc6406024e8dcf9e9bce229

* skip failing tests

* update mac build image
This commit is contained in:
Anthony Dresser
2020-01-27 15:28:17 -08:00
committed by Karl Burtram
parent 0eaee18dc4
commit fefe1454de
481 changed files with 12764 additions and 7836 deletions

View File

@@ -3,61 +3,42 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, IUserDataSyncStoreService, IUserDataSyncLogService, IGlobalState } from 'vs/platform/userDataSync/common/userDataSync';
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';
import { merge } from 'vs/platform/userDataSync/common/globalStateMerge';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { parse } from 'vs/base/common/json';
import { AbstractSynchroniser } from 'vs/platform/userDataSync/common/abstractSynchronizer';
const argvProperties: string[] = ['locale'];
interface ISyncPreviewResult {
readonly local: IGlobalState | undefined;
readonly remote: IGlobalState | undefined;
readonly remoteUserData: IUserData | null;
readonly remoteUserData: IUserData;
}
export class GlobalStateSynchroniser extends Disposable implements ISynchroniser {
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;
export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
constructor(
@IFileService private readonly fileService: IFileService,
@IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
@IFileService fileService: IFileService,
@IUserDataSyncStoreService userDataSyncStoreService: IUserDataSyncStoreService,
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService,
) {
super();
this.lastSyncGlobalStateResource = joinPath(environmentService.userRoamingDataHome, '.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')) {
@@ -102,7 +83,8 @@ export class GlobalStateSynchroniser extends Disposable implements ISynchroniser
this.setStatus(SyncStatus.Syncing);
const remote = await this.getLocalGlobalState();
await this.apply({ local: undefined, remote, remoteUserData: null });
const remoteUserData = await this.getRemoteUserData();
await this.apply({ local: undefined, remote, remoteUserData }, true);
this.logService.info('UI State: Finished pushing UI State.');
} finally {
@@ -111,15 +93,15 @@ export class GlobalStateSynchroniser extends Disposable implements ISynchroniser
}
async sync(): Promise<boolean> {
async sync(): Promise<void> {
if (!this.configurationService.getValue<boolean>('sync.enableUIState')) {
this.logService.trace('UI State: Skipping synchronizing UI state as it is disabled.');
return false;
return;
}
if (this.status !== SyncStatus.Idle) {
this.logService.trace('UI State: Skipping synchronizing ui state as it is running already.');
return false;
return;
}
this.logService.trace('UI State: Started synchronizing ui state...');
@@ -128,11 +110,10 @@ export class GlobalStateSynchroniser extends Disposable implements ISynchroniser
try {
const result = await this.getPreview();
await this.apply(result);
this.logService.trace('UI State: Finised synchronizing ui state.');
return true;
this.logService.trace('UI State: Finished synchronizing ui state.');
} catch (e) {
this.setStatus(SyncStatus.Idle);
if (e instanceof UserDataSyncStoreError && e.code === UserDataSyncStoreErrorCode.Rejected) {
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.Rejected) {
// Rejected as there is a new remote version. Syncing again,
this.logService.info('UI State: Failed to synchronise ui state as there is a new remote version available. Synchronizing again...');
return this.sync();
@@ -143,16 +124,14 @@ export class GlobalStateSynchroniser extends Disposable implements ISynchroniser
}
}
stop(): void { }
async stop(): Promise<void> { }
async hasPreviouslySynced(): Promise<boolean> {
const lastSyncData = await this.getLastSyncUserData();
return !!lastSyncData;
async restart(): Promise<void> {
throw new Error('UI State: Conflicts should not occur');
}
async hasRemoteData(): Promise<boolean> {
const remoteUserData = await this.getRemoteUserData();
return remoteUserData.content !== null;
resolveConflicts(content: string): Promise<void> {
throw new Error('UI State: Conflicts should not occur');
}
async hasLocalData(): Promise<boolean> {
@@ -167,10 +146,8 @@ export class GlobalStateSynchroniser extends Disposable implements ISynchroniser
return false;
}
async resetLocal(): Promise<void> {
try {
await this.fileService.del(this.lastSyncGlobalStateResource);
} catch (e) { /* ignore */ }
async getRemoteContent(): Promise<string | null> {
return null;
}
private async getPreview(): Promise<ISyncPreviewResult> {
@@ -187,7 +164,7 @@ export class GlobalStateSynchroniser extends Disposable implements ISynchroniser
return { local, remote, remoteUserData };
}
private async apply({ local, remote, remoteUserData }: ISyncPreviewResult): Promise<void> {
private async apply({ local, remote, remoteUserData }: ISyncPreviewResult, forcePush?: boolean): Promise<void> {
if (local) {
// update local
this.logService.info('UI State: Updating local ui state...');
@@ -197,13 +174,15 @@ export class GlobalStateSynchroniser extends Disposable implements ISynchroniser
if (remote) {
// update remote
this.logService.info('UI State: Updating remote ui state...');
remoteUserData = await this.writeToRemote(remote, remoteUserData ? remoteUserData.ref : null);
const content = JSON.stringify(remote);
const ref = await this.updateRemoteUserData(content, forcePush ? null : remoteUserData.ref);
remoteUserData = { ref, content };
}
if (remoteUserData?.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);
}
}
@@ -233,27 +212,4 @@ export class GlobalStateSynchroniser extends Disposable implements ISynchroniser
}
}
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);
}
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);
return { content, ref };
}
}