Skip to content

Commit 2db1156

Browse files
committed
1 parent 618e9e9 commit 2db1156

15 files changed

Lines changed: 133 additions & 57 deletions

File tree

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ export abstract class AbstractSynchroniser extends Disposable {
226226

227227
async getSyncPreview(): Promise<ISyncPreviewResult> {
228228
if (!this.isEnabled()) {
229-
return { hasLocalChanged: false, hasRemoteChanged: false };
229+
return { hasLocalChanged: false, hasRemoteChanged: false, isLastSyncFromCurrentMachine: false };
230230
}
231231

232232
const lastSyncUserData = await this.getLastSyncUserData();
@@ -269,6 +269,11 @@ export abstract class AbstractSynchroniser extends Disposable {
269269
return !!lastSyncData;
270270
}
271271

272+
protected async isLastSyncFromCurrentMachine(remoteUserData: IRemoteUserData): Promise<boolean> {
273+
const machineId = await this.currentMachineIdPromise;
274+
return !!remoteUserData.syncData?.machineId && remoteUserData.syncData.machineId === machineId;
275+
}
276+
272277
async getRemoteSyncResourceHandles(): Promise<ISyncResourceHandle[]> {
273278
const handles = await this.userDataSyncStoreService.getAllRefs(this.resource);
274279
return handles.map(({ created, ref }) => ({ created, uri: this.toRemoteBackupResource(ref) }));

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

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { areSameExtensions } from 'vs/platform/extensionManagement/common/extens
1212
import { IFileService } from 'vs/platform/files/common/files';
1313
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1414
import { merge, getIgnoredExtensions } from 'vs/platform/userDataSync/common/extensionsMerge';
15-
import { isNonEmptyArray } from 'vs/base/common/arrays';
1615
import { AbstractSynchroniser, IRemoteUserData, ISyncData } from 'vs/platform/userDataSync/common/abstractSynchronizer';
1716
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
1817
import { URI } from 'vs/base/common/uri';
@@ -95,7 +94,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
9594
await this.apply({
9695
added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData,
9796
hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0,
98-
hasRemoteChanged: remote !== null
97+
hasRemoteChanged: remote !== null,
98+
isLastSyncFromCurrentMachine: false
9999
});
100100
}
101101

@@ -131,7 +131,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
131131
await this.apply({
132132
added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData,
133133
hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0,
134-
hasRemoteChanged: remote !== null
134+
hasRemoteChanged: remote !== null,
135+
isLastSyncFromCurrentMachine: false
135136
}, true);
136137

137138
this.logService.info(`${this.syncResourceLogLabel}: Finished pushing extensions.`);
@@ -196,7 +197,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
196197
try {
197198
const installedExtensions = await this.extensionManagementService.getInstalled();
198199
const localExtensions = this.getLocalExtensions(installedExtensions);
199-
if (isNonEmptyArray(localExtensions)) {
200+
if (localExtensions.some(e => e.installed || e.disabled)) {
200201
return true;
201202
}
202203
} catch (error) {
@@ -221,14 +222,23 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
221222
await this.apply({
222223
added, removed, updated, remote: syncExtensions, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData,
223224
hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0,
224-
hasRemoteChanged: true
225+
hasRemoteChanged: true,
226+
isLastSyncFromCurrentMachine: false
225227
});
226228
}
227229

228230
protected async generatePreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<IExtensionsSyncPreviewResult> {
229231
const remoteExtensions: ISyncExtension[] | null = remoteUserData.syncData ? await this.parseAndMigrateExtensions(remoteUserData.syncData) : null;
230-
const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData ? await this.parseAndMigrateExtensions(lastSyncUserData.syncData!) : null;
231232
const skippedExtensions: ISyncExtension[] = lastSyncUserData ? lastSyncUserData.skippedExtensions || [] : [];
233+
const isLastSyncFromCurrentMachine = await this.isLastSyncFromCurrentMachine(remoteUserData);
234+
let lastSyncExtensions: ISyncExtension[] | null = null;
235+
if (lastSyncUserData === null) {
236+
if (isLastSyncFromCurrentMachine) {
237+
lastSyncExtensions = await this.parseAndMigrateExtensions(remoteUserData.syncData!);
238+
}
239+
} else {
240+
lastSyncExtensions = await this.parseAndMigrateExtensions(lastSyncUserData.syncData!);
241+
}
232242

233243
const installedExtensions = await this.extensionManagementService.getInstalled();
234244
const localExtensions = this.getLocalExtensions(installedExtensions);
@@ -252,7 +262,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
252262
localExtensions,
253263
lastSyncUserData,
254264
hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0,
255-
hasRemoteChanged: remote !== null
265+
hasRemoteChanged: remote !== null,
266+
isLastSyncFromCurrentMachine
256267
};
257268
}
258269

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

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
9393
local, remote, remoteUserData, localUserData: localGlobalState, lastSyncUserData,
9494
skippedStorageKeys: skipped,
9595
hasLocalChanged: Object.keys(local.added).length > 0 || Object.keys(local.updated).length > 0 || local.removed.length > 0,
96-
hasRemoteChanged: remote !== null
96+
hasRemoteChanged: remote !== null,
97+
isLastSyncFromCurrentMachine: false
9798
});
9899
}
99100

@@ -127,7 +128,8 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
127128
local: { added: {}, removed: [], updated: {} }, remote: localUserData.storage, remoteUserData, localUserData, lastSyncUserData,
128129
skippedStorageKeys: [],
129130
hasLocalChanged: false,
130-
hasRemoteChanged: true
131+
hasRemoteChanged: true,
132+
isLastSyncFromCurrentMachine: false
131133
}, true);
132134

133135
this.logService.info(`${this.syncResourceLogLabel}: Finished pushing UI State.`);
@@ -208,13 +210,22 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
208210
local, remote: syncGlobalState.storage, remoteUserData, localUserData, lastSyncUserData,
209211
skippedStorageKeys: skipped,
210212
hasLocalChanged: Object.keys(local.added).length > 0 || Object.keys(local.updated).length > 0 || local.removed.length > 0,
211-
hasRemoteChanged: true
213+
hasRemoteChanged: true,
214+
isLastSyncFromCurrentMachine: false,
212215
});
213216
}
214217

215218
protected async generatePreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<IGlobalSyncPreviewResult> {
216219
const remoteGlobalState: IGlobalState = remoteUserData.syncData ? JSON.parse(remoteUserData.syncData.content) : null;
217-
const lastSyncGlobalState: IGlobalState = lastSyncUserData && lastSyncUserData.syncData ? JSON.parse(lastSyncUserData.syncData.content) : null;
220+
const isLastSyncFromCurrentMachine = await this.isLastSyncFromCurrentMachine(remoteUserData);
221+
let lastSyncGlobalState: IGlobalState | null = null;
222+
if (lastSyncUserData === null) {
223+
if (isLastSyncFromCurrentMachine) {
224+
lastSyncGlobalState = remoteUserData.syncData ? JSON.parse(remoteUserData.syncData.content) : null;
225+
}
226+
} else {
227+
lastSyncGlobalState = lastSyncUserData.syncData ? JSON.parse(lastSyncUserData.syncData.content) : null;
228+
}
218229

219230
const localGloablState = await this.getLocalGlobalState();
220231

@@ -230,7 +241,8 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
230241
local, remote, remoteUserData, localUserData: localGloablState, lastSyncUserData,
231242
skippedStorageKeys: skipped,
232243
hasLocalChanged: Object.keys(local.added).length > 0 || Object.keys(local.updated).length > 0 || local.removed.length > 0,
233-
hasRemoteChanged: remote !== null
244+
hasRemoteChanged: remote !== null,
245+
isLastSyncFromCurrentMachine
234246
};
235247
}
236248

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
7676
hasConflicts: false,
7777
hasLocalChanged: true,
7878
hasRemoteChanged: false,
79+
isLastSyncFromCurrentMachine: false
7980
}));
8081
await this.apply();
8182
}
@@ -117,6 +118,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
117118
hasLocalChanged: false,
118119
hasRemoteChanged: true,
119120
hasConflicts: false,
121+
isLastSyncFromCurrentMachine: false
120122
}));
121123
await this.apply(true);
122124
}
@@ -227,6 +229,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
227229
hasConflicts: false,
228230
hasLocalChanged: true,
229231
hasRemoteChanged: true,
232+
isLastSyncFromCurrentMachine: false
230233
}));
231234
await this.apply();
232235
}
@@ -287,7 +290,16 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
287290

288291
protected async generatePreview(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, token: CancellationToken = CancellationToken.None): Promise<IFileSyncPreviewResult> {
289292
const remoteContent = remoteUserData.syncData ? this.getKeybindingsContentFromSyncContent(remoteUserData.syncData.content) : null;
290-
const lastSyncContent = lastSyncUserData && lastSyncUserData.syncData ? this.getKeybindingsContentFromSyncContent(lastSyncUserData.syncData.content) : null;
293+
const isLastSyncFromCurrentMachine = await this.isLastSyncFromCurrentMachine(remoteUserData);
294+
let lastSyncContent: string | null = null;
295+
if (lastSyncUserData === null) {
296+
if (isLastSyncFromCurrentMachine) {
297+
lastSyncContent = remoteUserData.syncData ? this.getKeybindingsContentFromSyncContent(remoteUserData.syncData.content) : null;
298+
}
299+
} else {
300+
lastSyncContent = lastSyncUserData.syncData ? this.getKeybindingsContentFromSyncContent(lastSyncUserData.syncData.content) : null;
301+
}
302+
291303
// Get file content last to get the latest
292304
const fileContent = await this.getLocalFileContent();
293305
const formattingOptions = await this.getFormattingOptions();
@@ -332,7 +344,7 @@ export class KeybindingsSynchroniser extends AbstractJsonFileSynchroniser implem
332344

333345
this.setConflicts(hasConflicts && !token.isCancellationRequested ? [{ local: this.localPreviewResource, remote: this.remotePreviewResource }] : []);
334346

335-
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts };
347+
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts, isLastSyncFromCurrentMachine };
336348
}
337349

338350
getKeybindingsContentFromSyncContent(syncContent: string): string | null {

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser {
9494
hasLocalChanged: true,
9595
hasRemoteChanged: false,
9696
hasConflicts: false,
97+
isLastSyncFromCurrentMachine: false
9798
}));
9899

99100
await this.apply();
@@ -140,6 +141,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser {
140141
hasRemoteChanged: true,
141142
hasLocalChanged: false,
142143
hasConflicts: false,
144+
isLastSyncFromCurrentMachine: false
143145
}));
144146

145147
await this.apply(true);
@@ -276,6 +278,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser {
276278
hasLocalChanged: true,
277279
hasRemoteChanged: true,
278280
hasConflicts: false,
281+
isLastSyncFromCurrentMachine: false
279282
}));
280283

281284
await this.apply();
@@ -340,7 +343,15 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser {
340343
const fileContent = await this.getLocalFileContent();
341344
const formattingOptions = await this.getFormattingOptions();
342345
const remoteSettingsSyncContent = this.getSettingsSyncContent(remoteUserData);
343-
const lastSettingsSyncContent = lastSyncUserData ? this.getSettingsSyncContent(lastSyncUserData) : null;
346+
const isLastSyncFromCurrentMachine = await this.isLastSyncFromCurrentMachine(remoteUserData);
347+
let lastSettingsSyncContent: ISettingsSyncContent | null = null;
348+
if (lastSyncUserData === null) {
349+
if (isLastSyncFromCurrentMachine) {
350+
lastSettingsSyncContent = this.getSettingsSyncContent(remoteUserData);
351+
}
352+
} else {
353+
lastSettingsSyncContent = this.getSettingsSyncContent(lastSyncUserData);
354+
}
344355

345356
let content: string | null = null;
346357
let hasLocalChanged: boolean = false;
@@ -375,7 +386,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser {
375386

376387
this.setConflicts(hasConflicts && !token.isCancellationRequested ? [{ local: this.localPreviewResource, remote: this.remotePreviewResource }] : []);
377388

378-
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts };
389+
return { fileContent, remoteUserData, lastSyncUserData, content, hasLocalChanged, hasRemoteChanged, hasConflicts, isLastSyncFromCurrentMachine };
379390
}
380391

381392
private getSettingsSyncContent(remoteUserData: IRemoteUserData): ISettingsSyncContent | null {

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
9999
this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<ISinppetsSyncPreviewResult>({
100100
added, removed, updated, remote, remoteUserData, local, lastSyncUserData, conflicts: [], resolvedConflicts: {},
101101
hasLocalChanged: Object.keys(added).length > 0 || removed.length > 0 || Object.keys(updated).length > 0,
102-
hasRemoteChanged: remote !== null
102+
hasRemoteChanged: remote !== null,
103+
isLastSyncFromCurrentMachine: false
103104
}));
104105
await this.apply();
105106
}
@@ -135,7 +136,8 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
135136
this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<ISinppetsSyncPreviewResult>({
136137
added, removed, updated, remote, remoteUserData, local, lastSyncUserData, conflicts: [], resolvedConflicts: {},
137138
hasLocalChanged: Object.keys(added).length > 0 || removed.length > 0 || Object.keys(updated).length > 0,
138-
hasRemoteChanged: remote !== null
139+
hasRemoteChanged: remote !== null,
140+
isLastSyncFromCurrentMachine: false
139141
}));
140142

141143
await this.apply(true);
@@ -266,7 +268,8 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
266268
this.syncPreviewResultPromise = createCancelablePromise(() => Promise.resolve<ISinppetsSyncPreviewResult>({
267269
added, removed, updated, remote: snippets, remoteUserData, local, lastSyncUserData, conflicts: [], resolvedConflicts: {},
268270
hasLocalChanged: Object.keys(added).length > 0 || removed.length > 0 || Object.keys(updated).length > 0,
269-
hasRemoteChanged: true
271+
hasRemoteChanged: true,
272+
isLastSyncFromCurrentMachine: false
270273
}));
271274
await this.apply();
272275
}
@@ -300,7 +303,16 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
300303
private async doGeneratePreview(local: IStringDictionary<IFileContent>, remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, resolvedConflicts: IStringDictionary<string | null> = {}, token: CancellationToken = CancellationToken.None): Promise<ISinppetsSyncPreviewResult> {
301304
const localSnippets = this.toSnippetsContents(local);
302305
const remoteSnippets: IStringDictionary<string> | null = remoteUserData.syncData ? this.parseSnippets(remoteUserData.syncData) : null;
303-
const lastSyncSnippets: IStringDictionary<string> | null = lastSyncUserData && lastSyncUserData.syncData ? this.parseSnippets(lastSyncUserData.syncData) : null;
306+
const isLastSyncFromCurrentMachine = await this.isLastSyncFromCurrentMachine(remoteUserData);
307+
308+
let lastSyncSnippets: IStringDictionary<string> | null = null;
309+
if (lastSyncUserData === null) {
310+
if (isLastSyncFromCurrentMachine) {
311+
lastSyncSnippets = remoteUserData.syncData ? this.parseSnippets(remoteUserData.syncData) : null;
312+
}
313+
} else {
314+
lastSyncSnippets = lastSyncUserData.syncData ? this.parseSnippets(lastSyncUserData.syncData) : null;
315+
}
304316

305317
if (remoteSnippets) {
306318
this.logService.trace(`${this.syncResourceLogLabel}: Merging remote snippets with local snippets...`);
@@ -342,7 +354,8 @@ export class SnippetsSynchroniser extends AbstractSynchroniser implements IUserD
342354
remote: mergeResult.remote,
343355
resolvedConflicts,
344356
hasLocalChanged: Object.keys(mergeResult.added).length > 0 || mergeResult.removed.length > 0 || Object.keys(mergeResult.updated).length > 0,
345-
hasRemoteChanged: mergeResult.remote !== null
357+
hasRemoteChanged: mergeResult.remote !== null,
358+
isLastSyncFromCurrentMachine
346359
};
347360
}
348361

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ export interface ISyncResourceHandle {
267267
export type Conflict = { remote: URI, local: URI };
268268

269269
export interface ISyncPreviewResult {
270+
readonly isLastSyncFromCurrentMachine: boolean;
270271
readonly hasLocalChanged: boolean;
271272
readonly hasRemoteChanged: boolean;
272273
}
@@ -344,7 +345,7 @@ export interface IUserDataSyncService {
344345
reset(): Promise<void>;
345346
resetLocal(): Promise<void>;
346347

347-
isFirstTimeSyncWithMerge(): Promise<boolean>;
348+
isFirstTimeSyncingWithAnotherMachine(): Promise<boolean>;
348349
resolveContent(resource: URI): Promise<string | null>;
349350
acceptConflict(conflictResource: URI, content: string): Promise<void>;
350351

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export class UserDataSyncChannel implements IServerChannel {
4848
case 'replace': return this.service.replace(URI.revive(args[0]));
4949
case 'reset': return this.service.reset();
5050
case 'resetLocal': return this.service.resetLocal();
51-
case 'isFirstTimeSyncWithMerge': return this.service.isFirstTimeSyncWithMerge();
51+
case 'isFirstTimeSyncingWithAnotherMachine': return this.service.isFirstTimeSyncingWithAnotherMachine();
5252
case 'acceptConflict': return this.service.acceptConflict(URI.revive(args[0]), args[1]);
5353
case 'resolveContent': return this.service.resolveContent(URI.revive(args[0]));
5454
case 'getLocalSyncResourceHandles': return this.service.getLocalSyncResourceHandles(args[0]);

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

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -277,23 +277,35 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
277277
return this.getSynchroniser(resource).getMachineId(syncResourceHandle);
278278
}
279279

280-
async isFirstTimeSyncWithMerge(): Promise<boolean> {
280+
async isFirstTimeSyncingWithAnotherMachine(): Promise<boolean> {
281281
await this.checkEnablement();
282+
282283
if (!await this.userDataSyncStoreService.manifest()) {
283284
return false;
284285
}
285-
if (await this.hasPreviouslySynced()) {
286-
return false;
286+
287+
// skip global state synchronizer
288+
const synchronizers = [this.settingsSynchroniser, this.keybindingsSynchroniser, this.snippetsSynchroniser, this.extensionsSynchroniser];
289+
290+
let hasLocalData: boolean = false;
291+
for (const synchroniser of synchronizers) {
292+
if (await synchroniser.hasLocalData()) {
293+
hasLocalData = true;
294+
break;
295+
}
287296
}
288-
if (!(await this.hasLocalData())) {
297+
298+
if (!hasLocalData) {
289299
return false;
290300
}
291-
for (const synchroniser of [this.settingsSynchroniser, this.keybindingsSynchroniser, this.snippetsSynchroniser, this.extensionsSynchroniser]) {
301+
302+
for (const synchroniser of synchronizers) {
292303
const preview = await synchroniser.getSyncPreview();
293-
if (preview.hasLocalChanged || preview.hasRemoteChanged) {
304+
if (!preview.isLastSyncFromCurrentMachine && (preview.hasLocalChanged || preview.hasRemoteChanged)) {
294305
return true;
295306
}
296307
}
308+
297309
return false;
298310
}
299311

@@ -329,15 +341,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
329341
return false;
330342
}
331343

332-
private async hasLocalData(): Promise<boolean> {
333-
for (const synchroniser of this.synchronisers) {
334-
if (await synchroniser.hasLocalData()) {
335-
return true;
336-
}
337-
}
338-
return false;
339-
}
340-
341344
private async resetRemote(): Promise<void> {
342345
await this.checkEnablement();
343346
try {

0 commit comments

Comments
 (0)