Skip to content

Commit 857debc

Browse files
authored
accept remote if last sync state is removed from server (microsoft#166871)
1 parent fd1a6dc commit 857debc

File tree

3 files changed

+47
-12
lines changed

3 files changed

+47
-12
lines changed

src/vs/platform/userDataSync/common/abstractSynchronizer.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -357,12 +357,25 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
357357

358358
protected async doSync(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, apply: boolean, userDataSyncConfiguration: IUserDataSyncConfiguration): Promise<SyncStatus> {
359359
try {
360+
361+
const isRemoteDataFromCurrentMachine = await this.isRemoteDataFromCurrentMachine(remoteUserData);
362+
const acceptRemote = !isRemoteDataFromCurrentMachine && lastSyncUserData === null && this.getStoredLastSyncUserDataStateContent() !== undefined;
363+
const merge = apply && !acceptRemote;
364+
360365
// generate or use existing preview
361366
if (!this.syncPreviewPromise) {
362-
this.syncPreviewPromise = createCancelablePromise(token => this.doGenerateSyncResourcePreview(remoteUserData, lastSyncUserData, apply, userDataSyncConfiguration, token));
367+
this.syncPreviewPromise = createCancelablePromise(token => this.doGenerateSyncResourcePreview(remoteUserData, lastSyncUserData, isRemoteDataFromCurrentMachine, merge, userDataSyncConfiguration, token));
368+
}
369+
370+
let preview = await this.syncPreviewPromise;
371+
372+
if (apply && acceptRemote) {
373+
this.logService.info(`${this.syncResourceLogLabel}: Accepting remote because it was synced before and the last sync data is not available.`);
374+
for (const resourcePreview of preview.resourcePreviews) {
375+
preview = (await this.accept(resourcePreview.remoteResource)) || preview;
376+
}
363377
}
364378

365-
const preview = await this.syncPreviewPromise;
366379
this.updateConflicts(preview.resourcePreviews);
367380
if (preview.resourcePreviews.some(({ mergeState }) => mergeState === MergeState.Conflict)) {
368381
return SyncStatus.HasConflicts;
@@ -532,8 +545,7 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
532545
}
533546
}
534547

535-
private async doGenerateSyncResourcePreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, apply: boolean, userDataSyncConfiguration: IUserDataSyncConfiguration, token: CancellationToken): Promise<ISyncResourcePreview> {
536-
const isRemoteDataFromCurrentMachine = await this.isRemoteDataFromCurrentMachine(remoteUserData);
548+
private async doGenerateSyncResourcePreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, isRemoteDataFromCurrentMachine: boolean, merge: boolean, userDataSyncConfiguration: IUserDataSyncConfiguration, token: CancellationToken): Promise<ISyncResourcePreview> {
537549
const resourcePreviewResults = await this.generateSyncPreview(remoteUserData, lastSyncUserData, isRemoteDataFromCurrentMachine, userDataSyncConfiguration, token);
538550

539551
const resourcePreviews: IEditableResourcePreview[] = [];
@@ -553,7 +565,7 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
553565
/* Changed -> Apply ? (Merge ? Conflict | Accept) : Preview */
554566
else {
555567
/* Merge */
556-
const mergeResult = apply ? await this.getMergeResult(resourcePreviewResult, token) : undefined;
568+
const mergeResult = merge ? await this.getMergeResult(resourcePreviewResult, token) : undefined;
557569
if (token.isCancellationRequested) {
558570
break;
559571
}
@@ -579,7 +591,7 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
579591
}
580592

581593
async getLastSyncUserData<T = IRemoteUserData & { [key: string]: any }>(): Promise<T | null> {
582-
let storedLastSyncUserDataStateContent = this.storageService.get(this.lastSyncUserDataStateKey, StorageScope.APPLICATION);
594+
let storedLastSyncUserDataStateContent = this.getStoredLastSyncUserDataStateContent();
583595
if (!storedLastSyncUserDataStateContent) {
584596
storedLastSyncUserDataStateContent = await this.migrateLastSyncUserData();
585597
}
@@ -635,7 +647,7 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
635647
await this.writeLastSyncStoredRemoteUserData({ ref: lastSyncUserDataState.ref, syncData });
636648
} catch (error) {
637649
if (error instanceof UserDataSyncError && error.code === UserDataSyncErrorCode.NotFound) {
638-
this.logService.info(`${this.syncResourceLogLabel}: .`);
650+
this.logService.info(`${this.syncResourceLogLabel}: Last sync resource does not exist remotely.`);
639651
} else {
640652
throw error;
641653
}
@@ -669,6 +681,10 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa
669681
await this.writeLastSyncStoredRemoteUserData(lastSyncRemoteUserData);
670682
}
671683

684+
private getStoredLastSyncUserDataStateContent(): string | undefined {
685+
return this.storageService.get(this.lastSyncUserDataStateKey, StorageScope.APPLICATION);
686+
}
687+
672688
private async readLastSyncStoredRemoteUserData(): Promise<IRemoteUserData | undefined> {
673689
const content = (await this.fileService.readFile(this.lastSyncResource)).value.toString();
674690
try {

src/vs/platform/userDataSync/test/common/synchronizer.test.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { isEqual, joinPath } from 'vs/base/common/resources';
1313
import { URI } from 'vs/base/common/uri';
1414
import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler';
1515
import { IFileService } from 'vs/platform/files/common/files';
16-
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
1716
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
1817
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
1918
import { AbstractSynchroniser, IAcceptResult, IMergeResult, IResourcePreview } from 'vs/platform/userDataSync/common/abstractSynchronizer';
@@ -188,7 +187,6 @@ suite('TestSynchronizer - Auto Sync', () => {
188187
await client.setUp();
189188
userDataSyncStoreService = client.instantiationService.get(IUserDataSyncStoreService);
190189
disposableStore.add(toDisposable(() => userDataSyncStoreService.clear()));
191-
client.instantiationService.get(IFileService).registerProvider(USER_DATA_SYNC_SCHEME, new InMemoryFileSystemProvider());
192190
});
193191

194192
teardown(() => disposableStore.clear());
@@ -496,7 +494,6 @@ suite('TestSynchronizer - Manual Sync', () => {
496494
await client.setUp();
497495
userDataSyncStoreService = client.instantiationService.get(IUserDataSyncStoreService);
498496
disposableStore.add(toDisposable(() => userDataSyncStoreService.clear()));
499-
client.instantiationService.get(IFileService).registerProvider(USER_DATA_SYNC_SCHEME, new InMemoryFileSystemProvider());
500497
});
501498

502499
teardown(() => disposableStore.clear());
@@ -1073,6 +1070,28 @@ suite('TestSynchronizer - Manual Sync', () => {
10731070
assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent);
10741071
}));
10751072

1073+
test('remote is accepted if last sync state does not exists in server', () => runWithFakedTimers<void>({ useFakeTimers: true }, async () => {
1074+
const fileService = client.instantiationService.get(IFileService);
1075+
const testObject: TestSynchroniser = disposableStore.add(client.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined));
1076+
testObject.syncBarrier.open();
1077+
1078+
await testObject.sync(await client.getResourceManifest());
1079+
1080+
const client2 = disposableStore.add(new UserDataSyncClient(server));
1081+
await client2.setUp();
1082+
const synchronizer2: TestSynchroniser = disposableStore.add(client2.instantiationService.createInstance(TestSynchroniser, { syncResource: SyncResource.Settings, profile: client2.instantiationService.get(IUserDataProfilesService).defaultProfile }, undefined));
1083+
synchronizer2.syncBarrier.open();
1084+
const manifest = await client2.getResourceManifest();
1085+
const expectedContent = manifest![testObject.resource];
1086+
await synchronizer2.sync(manifest);
1087+
1088+
await fileService.del(testObject.getLastSyncResource());
1089+
await testObject.sync(await client.getResourceManifest());
1090+
1091+
assert.deepStrictEqual(testObject.status, SyncStatus.Idle);
1092+
assert.strictEqual((await client.instantiationService.get(IFileService).readFile(testObject.localResource)).value.toString(), expectedContent);
1093+
}));
1094+
10761095
});
10771096

10781097
suite('TestSynchronizer - Last Sync Data', () => {
@@ -1086,7 +1105,6 @@ suite('TestSynchronizer - Last Sync Data', () => {
10861105
await client.setUp();
10871106
userDataSyncStoreService = client.instantiationService.get(IUserDataSyncStoreService);
10881107
disposableStore.add(toDisposable(() => userDataSyncStoreService.clear()));
1089-
client.instantiationService.get(IFileService).registerProvider(USER_DATA_SYNC_SCHEME, new InMemoryFileSystemProvider());
10901108
});
10911109

10921110
teardown(() => disposableStore.clear());

src/vs/platform/userDataSync/test/common/userDataSyncClient.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
3434
import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService';
3535
import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage';
3636
import { IgnoredExtensionsManagementService, IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions';
37-
import { ALL_SYNC_RESOURCES, getDefaultIgnoredSettings, IUserData, IUserDataSyncBackupStoreService, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncService, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, IUserDataSyncUtilService, registerConfiguration, ServerResource, SyncResource, IUserDataSynchroniser, IUserDataResourceManifest, IUserDataCollectionManifest } from 'vs/platform/userDataSync/common/userDataSync';
37+
import { ALL_SYNC_RESOURCES, getDefaultIgnoredSettings, IUserData, IUserDataSyncBackupStoreService, IUserDataSyncLogService, IUserDataSyncEnablementService, IUserDataSyncService, IUserDataSyncStoreManagementService, IUserDataSyncStoreService, IUserDataSyncUtilService, registerConfiguration, ServerResource, SyncResource, IUserDataSynchroniser, IUserDataResourceManifest, IUserDataCollectionManifest, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync';
3838
import { IUserDataSyncAccountService, UserDataSyncAccountService } from 'vs/platform/userDataSync/common/userDataSyncAccount';
3939
import { UserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSyncBackupStoreService';
4040
import { IUserDataSyncMachinesService, UserDataSyncMachinesService } from 'vs/platform/userDataSync/common/userDataSyncMachines';
@@ -83,6 +83,7 @@ export class UserDataSyncClient extends Disposable {
8383

8484
const fileService = this._register(new FileService(logService));
8585
fileService.registerProvider(Schemas.inMemory, new InMemoryFileSystemProvider());
86+
fileService.registerProvider(USER_DATA_SYNC_SCHEME, new InMemoryFileSystemProvider());
8687
this.instantiationService.stub(IFileService, fileService);
8788

8889
const uriIdentityService = this.instantiationService.createInstance(UriIdentityService);

0 commit comments

Comments
 (0)