#100346 prepare for manual sync

This commit is contained in:
Sandeep Somavarapu 2020-07-10 09:21:36 +02:00
parent 5cb5e32a4e
commit 8dfdecb938
8 changed files with 82 additions and 87 deletions

View file

@ -6,7 +6,7 @@
import { Delayer, disposableTimeout, CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async';
import { Event, Emitter } from 'vs/base/common/event';
import { Disposable, toDisposable, MutableDisposable, IDisposable } from 'vs/base/common/lifecycle';
import { IUserDataSyncLogService, IUserDataSyncService, IUserDataAutoSyncService, UserDataSyncError, UserDataSyncErrorCode, IUserDataSyncResourceEnablementService, IUserDataSyncStoreService, UserDataAutoSyncError } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncLogService, IUserDataSyncService, IUserDataAutoSyncService, UserDataSyncError, UserDataSyncErrorCode, IUserDataSyncResourceEnablementService, IUserDataSyncStoreService, UserDataAutoSyncError, ISyncTask } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncAccountService } from 'vs/platform/userDataSync/common/userDataSyncAccount';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { isPromiseCanceledError } from 'vs/base/common/errors';
@ -154,7 +154,7 @@ export class UserDataAutoSyncService extends UserDataAutoSyncEnablementService i
if (pullFirst) {
await this.userDataSyncService.pull();
} else {
await this.userDataSyncService.sync();
await (await this.userDataSyncService.createSyncTask()).run();
}
this.setEnablement(true);
@ -316,6 +316,7 @@ class AutoSync extends Disposable {
private readonly _onDidFinishSync = this._register(new Emitter<Error | undefined>());
readonly onDidFinishSync = this._onDidFinishSync.event;
private syncTask: ISyncTask | undefined;
private syncPromise: CancelablePromise<void> | undefined;
constructor(
@ -337,7 +338,9 @@ class AutoSync extends Disposable {
this.logService.info('Auto sync: Canelled sync that is in progress');
this.syncPromise = undefined;
}
this.userDataSyncService.stop();
if (this.syncTask) {
this.syncTask.stop();
}
this.logService.info('Auto Sync: Stopped');
}));
this.logService.info('Auto Sync: Started');
@ -374,8 +377,11 @@ class AutoSync extends Disposable {
this._onDidStartSync.fire();
let error: Error | undefined;
try {
const syncTask = await this.userDataSyncService.createSyncTask();
let manifest = syncTask.manifest;
this.syncTask = await this.userDataSyncService.createSyncTask();
if (token.isCancellationRequested) {
return;
}
let manifest = this.syncTask.manifest;
// Server has no data but this machine was synced before
if (manifest === null && await this.userDataSyncService.hasPreviouslySynced()) {
@ -402,7 +408,7 @@ class AutoSync extends Disposable {
throw new UserDataAutoSyncError(localize('turned off machine', "Cannot sync because syncing is turned off on this machine from another machine."), UserDataSyncErrorCode.TurnedOff);
}
await syncTask.run(token);
await this.syncTask.run();
// After syncing, get the manifest if it was not available before
if (manifest === null) {

View file

@ -23,7 +23,6 @@ import { IProductService, ConfigurationSyncStore } from 'vs/platform/product/com
import { distinct } from 'vs/base/common/arrays';
import { isArray, isString, isObject } from 'vs/base/common/types';
import { IHeaders } from 'vs/base/parts/request/common/request';
import { CancellationToken } from 'vs/base/common/cancellation';
export const CONFIGURATION_SYNC_STORE_KEY = 'configurationSync.store';
@ -360,7 +359,8 @@ export type SyncResourceConflicts = { syncResource: SyncResource, conflicts: IRe
export interface ISyncTask {
manifest: IUserDataManifest | null;
run(token: CancellationToken): Promise<void>;
run(): Promise<void>;
stop(): Promise<void>;
}
export const IUserDataSyncService = createDecorator<IUserDataSyncService>('IUserDataSyncService');
@ -380,15 +380,13 @@ export interface IUserDataSyncService {
readonly lastSyncTime: number | undefined;
readonly onDidChangeLastSyncTime: Event<number>;
createSyncTask(): Promise<ISyncTask>;
pull(): Promise<void>;
sync(): Promise<void>;
stop(): Promise<void>;
replace(uri: URI): Promise<void>;
reset(): Promise<void>;
resetLocal(): Promise<void>;
createSyncTask(): Promise<ISyncTask>
isFirstTimeSyncingWithAnotherMachine(): Promise<boolean>;
hasPreviouslySynced(): Promise<boolean>;
resolveContent(resource: URI): Promise<string | null>;

View file

@ -45,8 +45,6 @@ export class UserDataSyncChannel implements IServerChannel {
switch (command) {
case '_getInitialData': return Promise.resolve([this.service.status, this.service.conflicts, this.service.lastSyncTime]);
case 'pull': return this.service.pull();
case 'sync': return this.service.sync();
case 'stop': this.service.stop(); return Promise.resolve();
case 'replace': return this.service.replace(URI.revive(args[0]));
case 'reset': return this.service.reset();
case 'resetLocal': return this.service.resetLocal();

View file

@ -21,6 +21,7 @@ import { SnippetsSynchroniser } from 'vs/platform/userDataSync/common/snippetsSy
import { CancellationToken } from 'vs/base/common/cancellation';
import { IHeaders } from 'vs/base/parts/request/common/request';
import { generateUuid } from 'vs/base/common/uuid';
import { createCancelablePromise, CancelablePromise } from 'vs/base/common/async';
type SyncErrorClassification = {
resource?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
@ -129,12 +130,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
}
}
private recoveredSettings: boolean = false;
async sync(): Promise<void> {
const syncTask = await this.createSyncTask();
return syncTask.run(CancellationToken.None);
}
async createSyncTask(): Promise<ISyncTask> {
this.telemetryService.publicLog2('sync/getmanifest');
const executionId = generateUuid();
@ -150,18 +145,27 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
let executed = false;
const that = this;
let cancellablePromise: CancelablePromise<void> | undefined;
return {
manifest,
run(token: CancellationToken): Promise<void> {
run(): Promise<void> {
if (executed) {
throw new Error('Can run a task only once');
}
return that.doSync(manifest, executionId, token);
cancellablePromise = createCancelablePromise(token => that.sync(manifest, executionId, token));
return cancellablePromise.finally(() => cancellablePromise = undefined);
},
async stop(): Promise<void> {
if (cancellablePromise) {
cancellablePromise.cancel();
return that.stop();
}
}
};
}
private async doSync(manifest: IUserDataManifest | null, executionId: string, token: CancellationToken): Promise<void> {
private recoveredSettings: boolean = false;
private async sync(manifest: IUserDataManifest | null, executionId: string, token: CancellationToken): Promise<void> {
await this.checkEnablement();
if (!this.recoveredSettings) {
@ -211,18 +215,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
}
}
async replace(uri: URI): Promise<void> {
await this.checkEnablement();
for (const synchroniser of this.synchronisers) {
if (await synchroniser.replace(uri)) {
return;
}
}
}
async stop(): Promise<void> {
await this.checkEnablement();
private async stop(): Promise<void> {
if (this.status === SyncStatus.Idle) {
return;
}
@ -239,6 +232,15 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
}
async replace(uri: URI): Promise<void> {
await this.checkEnablement();
for (const synchroniser of this.synchronisers) {
if (await synchroniser.replace(uri)) {
return;
}
}
}
async acceptPreviewContent(resource: URI, content: string): Promise<void> {
await this.checkEnablement();
const synchroniser = this.synchronisers.find(synchroniser => synchroniser.resourcePreviews.some(({ localResource, previewResource, remoteResource }) =>

View file

@ -37,7 +37,7 @@ suite('UserDataAutoSyncService', () => {
await client.setUp();
// Sync once and reset requests
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
target.reset();
const testObject: UserDataAutoSyncService = client.instantiationService.createInstance(TestUserDataAutoSyncService);
@ -59,7 +59,7 @@ suite('UserDataAutoSyncService', () => {
await client.setUp();
// Sync once and reset requests
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
target.reset();
const testObject: UserDataAutoSyncService = client.instantiationService.createInstance(TestUserDataAutoSyncService);
@ -85,7 +85,7 @@ suite('UserDataAutoSyncService', () => {
await client.setUp();
// Sync once and reset requests
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
target.reset();
const testObject: UserDataAutoSyncService = client.instantiationService.createInstance(TestUserDataAutoSyncService);
@ -107,7 +107,7 @@ suite('UserDataAutoSyncService', () => {
await client.setUp();
// Sync once and reset requests
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
target.reset();
const testObject: UserDataAutoSyncService = client.instantiationService.createInstance(TestUserDataAutoSyncService);
@ -245,7 +245,7 @@ suite('UserDataAutoSyncService', () => {
// Set up and sync from the client
const client = disposableStore.add(new UserDataSyncClient(target));
await client.setUp();
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Set up and sync from the test client
const testClient = disposableStore.add(new UserDataSyncClient(target));
@ -334,7 +334,7 @@ suite('UserDataAutoSyncService', () => {
// Set up and sync from the client
const client = disposableStore.add(new UserDataSyncClient(target));
await client.setUp();
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Set up and sync from the test client
const testClient = disposableStore.add(new UserDataSyncClient(target));
@ -346,7 +346,7 @@ suite('UserDataAutoSyncService', () => {
await client.instantiationService.get(IUserDataSyncService).reset();
// Sync again from the first client to create new session
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Sync from the test client
target.reset();
@ -383,5 +383,4 @@ suite('UserDataAutoSyncService', () => {
assert.deepEqual((<UserDataSyncStoreError>e).code, UserDataSyncErrorCode.TooManyRequests);
});
});

View file

@ -120,8 +120,8 @@ export class UserDataSyncClient extends Disposable {
await configurationService.reloadConfiguration();
}
sync(): Promise<void> {
return this.instantiationService.get(IUserDataSyncService).sync();
async sync(): Promise<void> {
await (await this.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
}
read(resource: SyncResource): Promise<IUserData> {

View file

@ -11,7 +11,6 @@ import { IFileService } from 'vs/platform/files/common/files';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { VSBuffer } from 'vs/base/common/buffer';
import { joinPath } from 'vs/base/common/resources';
import { CancellationToken } from 'vs/base/common/cancellation';
suite('UserDataSyncService', () => {
@ -27,7 +26,7 @@ suite('UserDataSyncService', () => {
const testObject = client.instantiationService.get(IUserDataSyncService);
// Sync for first time
await testObject.sync();
await (await testObject.createSyncTask()).run();
assert.deepEqual(target.requests, [
// Manifest
@ -58,7 +57,7 @@ suite('UserDataSyncService', () => {
const testObject = client.instantiationService.get(IUserDataSyncService);
// Sync for first time
await testObject.sync();
await (await testObject.createSyncTask()).run();
assert.deepEqual(target.requests, [
// Manifest
@ -83,7 +82,7 @@ suite('UserDataSyncService', () => {
// Setup and sync from the first client
const client = disposableStore.add(new UserDataSyncClient(target));
await client.setUp();
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Setup the test client
const testClient = disposableStore.add(new UserDataSyncClient(target));
@ -118,7 +117,7 @@ suite('UserDataSyncService', () => {
// Setup and sync from the first client
const client = disposableStore.add(new UserDataSyncClient(target));
await client.setUp();
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Setup the test client with changes
const testClient = disposableStore.add(new UserDataSyncClient(target));
@ -155,7 +154,7 @@ suite('UserDataSyncService', () => {
// Setup and sync from the first client
const client = disposableStore.add(new UserDataSyncClient(target));
await client.setUp();
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Setup the test client
const testClient = disposableStore.add(new UserDataSyncClient(target));
@ -165,7 +164,7 @@ suite('UserDataSyncService', () => {
// Sync (merge) from the test client
target.reset();
await testObject.isFirstTimeSyncingWithAnotherMachine();
await testObject.sync();
await (await testObject.createSyncTask()).run();
assert.deepEqual(target.requests, [
/* first time sync */
@ -191,7 +190,7 @@ suite('UserDataSyncService', () => {
// Setup and sync from the first client
const client = disposableStore.add(new UserDataSyncClient(target));
await client.setUp();
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Setup the test client with changes
const testClient = disposableStore.add(new UserDataSyncClient(target));
@ -207,7 +206,7 @@ suite('UserDataSyncService', () => {
// Sync (merge) from the test client
target.reset();
await testObject.isFirstTimeSyncingWithAnotherMachine();
await testObject.sync();
await (await testObject.createSyncTask()).run();
assert.deepEqual(target.requests, [
/* first time sync */
@ -235,11 +234,11 @@ suite('UserDataSyncService', () => {
const client = disposableStore.add(new UserDataSyncClient(target));
await client.setUp();
const testObject = client.instantiationService.get(IUserDataSyncService);
await testObject.sync();
await (await testObject.createSyncTask()).run();
// sync from the client again
target.reset();
await testObject.sync();
await (await testObject.createSyncTask()).run();
assert.deepEqual(target.requests, [
// Manifest
@ -254,7 +253,7 @@ suite('UserDataSyncService', () => {
const client = disposableStore.add(new UserDataSyncClient(target));
await client.setUp();
const testObject = client.instantiationService.get(IUserDataSyncService);
await testObject.sync();
await (await testObject.createSyncTask()).run();
target.reset();
// Do changes in the client
@ -266,7 +265,7 @@ suite('UserDataSyncService', () => {
await fileService.writeFile(environmentService.argvResource, VSBuffer.fromString(JSON.stringify({ 'locale': 'de' })));
// Sync from the client
await testObject.sync();
await (await testObject.createSyncTask()).run();
assert.deepEqual(target.requests, [
// Manifest
@ -288,13 +287,13 @@ suite('UserDataSyncService', () => {
// Sync from first client
const client = disposableStore.add(new UserDataSyncClient(target));
await client.setUp();
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Sync from test client
const testClient = disposableStore.add(new UserDataSyncClient(target));
await testClient.setUp();
const testObject = testClient.instantiationService.get(IUserDataSyncService);
await testObject.sync();
await (await testObject.createSyncTask()).run();
// Do changes in first client and sync
const fileService = client.instantiationService.get(IFileService);
@ -303,11 +302,11 @@ suite('UserDataSyncService', () => {
await fileService.writeFile(environmentService.keybindingsResource, VSBuffer.fromString(JSON.stringify([{ 'command': 'abcd', 'key': 'cmd+c' }])));
await fileService.writeFile(joinPath(environmentService.snippetsHome, 'html.json'), VSBuffer.fromString(`{ "a": "changed" }`));
await fileService.writeFile(environmentService.argvResource, VSBuffer.fromString(JSON.stringify({ 'locale': 'de' })));
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Sync from test client
target.reset();
await testObject.sync();
await (await testObject.createSyncTask()).run();
assert.deepEqual(target.requests, [
// Manifest
@ -331,7 +330,7 @@ suite('UserDataSyncService', () => {
const testClient = disposableStore.add(new UserDataSyncClient(target));
await testClient.setUp();
const testObject = testClient.instantiationService.get(IUserDataSyncService);
await testObject.sync();
await (await testObject.createSyncTask()).run();
// Reset from the client
target.reset();
@ -351,14 +350,14 @@ suite('UserDataSyncService', () => {
const testClient = disposableStore.add(new UserDataSyncClient(target));
await testClient.setUp();
const testObject = testClient.instantiationService.get(IUserDataSyncService);
await testObject.sync();
await (await testObject.createSyncTask()).run();
// Reset from the client
await testObject.reset();
// Sync again
target.reset();
await testObject.sync();
await (await testObject.createSyncTask()).run();
assert.deepEqual(target.requests, [
// Manifest
@ -392,7 +391,7 @@ suite('UserDataSyncService', () => {
// sync from the client
const actualStatuses: SyncStatus[] = [];
const disposable = testObject.onDidChangeStatus(status => actualStatuses.push(status));
await testObject.sync();
await (await testObject.createSyncTask()).run();
disposable.dispose();
assert.deepEqual(actualStatuses, [SyncStatus.Syncing, SyncStatus.Idle, SyncStatus.Syncing, SyncStatus.Idle, SyncStatus.Syncing, SyncStatus.Idle, SyncStatus.Syncing, SyncStatus.Idle, SyncStatus.Syncing, SyncStatus.Idle]);
@ -407,7 +406,7 @@ suite('UserDataSyncService', () => {
let fileService = client.instantiationService.get(IFileService);
let environmentService = client.instantiationService.get(IEnvironmentService);
await fileService.writeFile(environmentService.settingsResource, VSBuffer.fromString(JSON.stringify({ 'editor.fontSize': 14 })));
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Setup the test client
const testClient = disposableStore.add(new UserDataSyncClient(target));
@ -418,7 +417,7 @@ suite('UserDataSyncService', () => {
const testObject = testClient.instantiationService.get(IUserDataSyncService);
// sync from the client
await testObject.sync();
await (await testObject.createSyncTask()).run();
assert.deepEqual(testObject.status, SyncStatus.HasConflicts);
assert.deepEqual(testObject.conflicts.map(({ syncResource }) => syncResource), [SyncResource.Settings]);
@ -433,7 +432,7 @@ suite('UserDataSyncService', () => {
let fileService = client.instantiationService.get(IFileService);
let environmentService = client.instantiationService.get(IEnvironmentService);
await fileService.writeFile(environmentService.settingsResource, VSBuffer.fromString(JSON.stringify({ 'editor.fontSize': 14 })));
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Setup the test client and get conflicts in settings
const testClient = disposableStore.add(new UserDataSyncClient(target));
@ -442,17 +441,17 @@ suite('UserDataSyncService', () => {
let testEnvironmentService = testClient.instantiationService.get(IEnvironmentService);
await testFileService.writeFile(testEnvironmentService.settingsResource, VSBuffer.fromString(JSON.stringify({ 'editor.fontSize': 16 })));
const testObject = testClient.instantiationService.get(IUserDataSyncService);
await testObject.sync();
await (await testObject.createSyncTask()).run();
// sync from the first client with changes in keybindings
await fileService.writeFile(environmentService.keybindingsResource, VSBuffer.fromString(JSON.stringify([{ 'command': 'abcd', 'key': 'cmd+c' }])));
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// sync from the test client
target.reset();
const actualStatuses: SyncStatus[] = [];
const disposable = testObject.onDidChangeStatus(status => actualStatuses.push(status));
await testObject.sync();
await (await testObject.createSyncTask()).run();
disposable.dispose();
assert.deepEqual(actualStatuses, []);
@ -475,7 +474,7 @@ suite('UserDataSyncService', () => {
let fileService = client.instantiationService.get(IFileService);
let environmentService = client.instantiationService.get(IEnvironmentService);
await fileService.writeFile(environmentService.settingsResource, VSBuffer.fromString(JSON.stringify({ 'editor.fontSize': 14 })));
await client.instantiationService.get(IUserDataSyncService).sync();
await (await client.instantiationService.get(IUserDataSyncService).createSyncTask()).run();
// Setup the test client
const testClient = disposableStore.add(new UserDataSyncClient(target));
@ -484,10 +483,11 @@ suite('UserDataSyncService', () => {
environmentService = testClient.instantiationService.get(IEnvironmentService);
await fileService.writeFile(environmentService.settingsResource, VSBuffer.fromString(JSON.stringify({ 'editor.fontSize': 16 })));
const testObject = testClient.instantiationService.get(IUserDataSyncService);
await testObject.sync();
// sync from the client
await testObject.stop();
const syncTask = (await testObject.createSyncTask());
syncTask.run();
await syncTask.stop();
assert.deepEqual(testObject.status, SyncStatus.Idle);
assert.deepEqual(testObject.conflicts, []);
@ -500,7 +500,7 @@ suite('UserDataSyncService', () => {
await client.setUp();
const testObject = client.instantiationService.get(IUserDataSyncService);
await testObject.sync();
await (await testObject.createSyncTask()).run();
for (const request of target.requestsWithAllHeaders) {
const hasExecutionIdHeader = request.headers && request.headers['X-Execution-Id'] && request.headers['X-Execution-Id'].length > 0;
@ -517,10 +517,10 @@ suite('UserDataSyncService', () => {
const testObject = client.instantiationService.get(IUserDataSyncService);
const syncTask = await testObject.createSyncTask();
await syncTask.run(CancellationToken.None);
await syncTask.run();
try {
await syncTask.run(CancellationToken.None);
await syncTask.run();
assert.fail('Should fail running the task again');
} catch (error) {
/* expected */

View file

@ -71,18 +71,10 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
return this.channel.call('pull');
}
sync(): Promise<void> {
return this.channel.call('sync');
}
createSyncTask(): Promise<ISyncTask> {
throw new Error('not supported');
}
stop(): Promise<void> {
return this.channel.call('stop');
}
replace(uri: URI): Promise<void> {
return this.channel.call('replace', [uri]);
}