extensionsSync.ts ×17

Frontier kind: Code frontier

unlabeled · c_3dd23944154c

127 tests · 26401 LOC · 133 files · introduces 0 tests · 158 LOC · 5 files

Introduces — evidence that enters the hierarchy at this concept

Code
35 ranges158 lines · 5 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
4289 ranges26401 lines · 133 files · Browse complete extent
All tests (intent)
127 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

5 files ranked by introduced lines: 158 introduced LOC across 35 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/userDataSync/common/extensionsSync.ts 104 introduced LOC · 17 ranges

Open complete file

83
84 export function stringify(extensions: ISyncExtension[], format: boolean): string {
85 > extensions.sort((e1, e2) => { extensionsSync.ts
86 if (!e1.identifier.uuid && e2.identifier.uuid) {
87 return -1;
91 }
92 return compare(e1.identifier.id, e2.identifier.id);
94 > return format ? toFormattedString(extensions, {}) : JSON.stringify(extensions);
95 > }
96
97 export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
145
146 protected async generateSyncPreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<IExtensionResourcePreview[]> {
147 > const remoteExtensions = remoteUserData.syncData ? await parseAndMigrateExtensions(remoteUserData.syncData, this.extensionManagementService) : null; extensionsSync.ts
148 > const skippedExtensions = lastSyncUserData?.skippedExtensions ?? [];
149 > const builtinExtensions = lastSyncUserData?.builtinExtensions ?? null;
150 > const lastSyncExtensions = lastSyncUserData?.syncData ? await parseAndMigrateExtensions(lastSyncUserData.syncData, this.extensionManagementService) : null;
151 >
152 > const { localExtensions, ignoredExtensions } = await this.localExtensionsProvider.getLocalExtensions(this.syncResource.profile);
153 >
154 > if (remoteExtensions) {
155 this.logService.trace(`${this.syncResourceLogLabel}: Merging remote extensions with local extensions...`);
156 > } else { extensionsSync.ts
157 > this.logService.trace(`${this.syncResourceLogLabel}: Remote extensions does not exist. Synchronizing extensions for the first time.`);
158 > }
159 >
160 > const { local, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, ignoredExtensions, builtinExtensions);
161 > const previewResult: IExtensionResourceMergeResult = {
162 > local, remote,
163 > content: this.getPreviewContent(localExtensions, local.added, local.updated, local.removed),
164 > localChange: local.added.length > 0 || local.removed.length > 0 || local.updated.length > 0 ? Change.Modified : Change.None,
165 > remoteChange: remote !== null ? Change.Modified : Change.None,
166 > };
167 >
168 > const localContent = this.stringify(localExtensions, false);
169 > return [{
170 > skippedExtensions,
171 > builtinExtensions,
172 > baseResource: this.baseResource,
173 > baseContent: lastSyncExtensions ? this.stringify(lastSyncExtensions, false) : localContent,
174 > localResource: this.localResource,
175 > localContent,
176 > localExtensions,
177 > remoteResource: this.remoteResource,
178 > remoteExtensions,
179 > remoteContent: remoteExtensions ? this.stringify(remoteExtensions, false) : null,
180 > previewResource: this.previewResource,
181 > previewResult,
182 > localChange: previewResult.localChange,
183 > remoteChange: previewResult.remoteChange,
184 > acceptedResource: this.acceptedResource,
185 > }];
186 > }
187
188 protected async hasRemoteChanged(lastSyncUserData: ILastSyncUserData): Promise<boolean> {
194
195 private getPreviewContent(localExtensions: ISyncExtension[], added: ISyncExtension[], updated: ISyncExtension[], removed: IExtensionIdentifier[]): string {
196 > const preview: ISyncExtension[] = [...added, ...updated]; extensionsSync.ts
197 >
198 > const idsOrUUIDs: Set<string> = new Set<string>();
199 > const addIdentifier = (identifier: IExtensionIdentifier) => {
200 idsOrUUIDs.add(identifier.id.toLowerCase());
201 if (identifier.uuid) {
203 }
204 };
205 > preview.forEach(({ identifier }) => addIdentifier(identifier)); extensionsSync.ts
206 > removed.forEach(addIdentifier);
207 >
208 > for (const localExtension of localExtensions) {
209 if (idsOrUUIDs.has(localExtension.identifier.id.toLowerCase()) || (localExtension.identifier.uuid && idsOrUUIDs.has(localExtension.identifier.uuid))) {
210 // skip
213 preview.push(localExtension);
214 }
216 > return this.stringify(preview, false);
217 > }
218
219 protected async getMergeResult(resourcePreview: IExtensionResourcePreview, token: CancellationToken): Promise<IMergeResult> {
282
283 protected async applyResult(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, resourcePreviews: [IExtensionResourcePreview, IExtensionResourceMergeResult][], force: boolean): Promise<void> {
284 > let { skippedExtensions, builtinExtensions, localExtensions } = resourcePreviews[0][0]; extensionsSync.ts
285 > const { local, remote, localChange, remoteChange } = resourcePreviews[0][1];
286 >
287 > if (localChange === Change.None && remoteChange === Change.None) {
288 > this.logService.info(`${this.syncResourceLogLabel}: No changes found during synchronizing extensions.`);
289 > }
290 >
291 > if (localChange !== Change.None) {
292 await this.backupLocal(JSON.stringify(localExtensions));
293 skippedExtensions = await this.localExtensionsProvider.updateLocalExtensions(local.added, local.removed, local.updated, skippedExtensions, this.syncResource.profile);
294 }
296 > if (remote) {
297 // update remote
298 this.logService.trace(`${this.syncResourceLogLabel}: Updating remote extensions...`);
301 this.logService.info(`${this.syncResourceLogLabel}: Updated remote extensions.${remote.added.length ? ` Added: ${JSON.stringify(remote.added.map(e => e.identifier.id))}.` : ''}${remote.updated.length ? ` Updated: ${JSON.stringify(remote.updated.map(e => e.identifier.id))}.` : ''}${remote.removed.length ? ` Removed: ${JSON.stringify(remote.removed.map(e => e.identifier.id))}.` : ''}`);
302 }
304 > if (lastSyncUserData?.ref !== remoteUserData.ref) {
305 > // update last sync
306 > this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized extensions...`);
307 > builtinExtensions = this.computeBuiltinExtensions(localExtensions, builtinExtensions);
308 > await this.updateLastSyncUserData(remoteUserData, { skippedExtensions, builtinExtensions });
309 > this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized extensions.${skippedExtensions.length ? ` Skipped: ${JSON.stringify(skippedExtensions.map(e => e.identifier.id))}.` : ''}`);
310 > }
311 > }
312
313 private computeBuiltinExtensions(localExtensions: ILocalSyncExtension[], previousBuiltinExtensions: IExtensionIdentifier[] | null): IExtensionIdentifier[] {
314 > const localExtensionsSet = new Set<string>(); extensionsSync.ts
315 > const builtinExtensions: IExtensionIdentifier[] = [];
316 > for (const localExtension of localExtensions) {
317 localExtensionsSet.add(localExtension.identifier.id.toLowerCase());
318 if (!localExtension.installed) {
320 }
321 }
322 > if (previousBuiltinExtensions) { extensionsSync.ts
323 for (const builtinExtension of previousBuiltinExtensions) {
324 // Add previous builtin extension if it does not exist in local extensions
328 }
329 }
330 > return builtinExtensions; extensionsSync.ts
331 > }
332
333 async resolveContent(uri: URI): Promise<string | null> {
344
345 private stringify(extensions: ISyncExtension[], format: boolean): string {
346 > return stringify(extensions, format); extensionsSync.ts
347 > }
348
349 async hasLocalData(): Promise<boolean> {
374
375 async getLocalExtensions(profile: IUserDataProfile): Promise<{ localExtensions: ILocalSyncExtension[]; ignoredExtensions: string[] }> {
376 > const installedExtensions = await this.extensionManagementService.getInstalled(undefined, profile.extensionsResource); extensionsSync.ts
377 > const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions);
378 > const localExtensions = await this.withProfileScopedServices(profile, async (extensionEnablementService, extensionStorageService) => {
379 > const disabledExtensions = extensionEnablementService.getDisabledExtensions();
380 > return installedExtensions
381 > .map(extension => {
382 const { identifier, isBuiltin, manifest, preRelease, pinned, isApplicationScoped } = extension;
383 const syncExtension: ILocalSyncExtension = { identifier, preRelease, version: manifest.version, pinned: !!pinned };
409 }
410 return syncExtension;
411 > }); extensionsSync.ts
412 > });
413 > return { localExtensions, ignoredExtensions };
414 > }
415
416 async updateLocalExtensions(added: ISyncExtension[], removed: IExtensionIdentifier[], updated: ISyncExtension[], skippedExtensions: ISyncExtension[], profile: IUserDataProfile): Promise<ISyncExtension[]> {
575
576 private async withProfileScopedServices<T>(profile: IUserDataProfile, fn: (extensionEnablementService: IGlobalExtensionEnablementService, extensionStorageService: IExtensionStorageService) => Promise<T>): Promise<T> {
577 > return this.userDataProfileStorageService.withProfileScopedStorageService(profile, extensionsSync.ts
578 > async storageService => {
579 > const disposables = new DisposableStore();
580 > const instantiationService = disposables.add(this.instantiationService.createChild(new ServiceCollection([IStorageService, storageService])));
581 > const extensionEnablementService = disposables.add(instantiationService.createInstance(GlobalExtensionEnablementService));
582 > const extensionStorageService = disposables.add(instantiationService.createInstance(ExtensionStorageService));
583 > try {
584 > return await fn(extensionEnablementService, extensionStorageService);
585 > } finally {
586 > disposables.dispose();
587 > }
588 > });
589 > }
590
591 }
src/vs/platform/userDataSync/common/userDataSyncService.ts 26 introduced LOC · 9 ranges

Open complete file

146 cancellablePromise = createCancelablePromise(token => that.sync(manifest, false, executionId, token));
147 await cancellablePromise.finally(() => cancellablePromise = undefined);
148 > that.logService.info(`Sync done. Took ${new Date().getTime() - startTime}ms`); userDataSyncService.ts
149 > that.updateLastSyncTime();
150 },
151 stop(): Promise<void> {
241 const defaultProfileSynchronizer = this.getOrCreateActiveProfileSynchronizer(this.userDataProfilesService.defaultProfile, undefined);
242 this._syncErrors.push(...await this.syncProfile(defaultProfileSynchronizer, manifestOrLatestData, preview, executionId, token));
244 > // Sync other profiles
245 > const userDataProfileManifestSynchronizer = defaultProfileSynchronizer.enabled.find(s => s.resource === SyncResource.Profiles);
246 > if (userDataProfileManifestSynchronizer) {
247 > const syncProfiles = (await (userDataProfileManifestSynchronizer as UserDataProfilesManifestSynchroniser).getLastSyncedProfiles()) || [];
248 > if (token.isCancellationRequested) {
249 return;
250 }
251 > await this.syncRemoteProfiles(syncProfiles, manifestOrLatestData, preview, executionId, token); userDataSyncService.ts
252 > }
253 } finally {
254 if (this.status !== SyncStatus.HasConflicts) {
260
261 private async syncRemoteProfiles(remoteProfiles: ISyncUserDataProfile[], manifest: IUserDataManifest | IUserDataSyncLatestData | null, preview: boolean, executionId: string, token: CancellationToken): Promise<void> {
262 > for (const syncProfile of remoteProfiles) { userDataSyncService.ts
263 if (token.isCancellationRequested) {
264 return;
273 this._syncErrors.push(...await this.syncProfile(profileSynchronizer, manifest, preview, executionId, token));
274 }
275 > // Dispose & Delete profile synchronizers which do not exist anymore userDataSyncService.ts
276 > for (const [key, profileSynchronizerItem] of this.activeProfileSynchronizers.entries()) {
277 > if (this.userDataProfilesService.profiles.some(p => p.id === profileSynchronizerItem[0].profile.id)) {
278 > continue;
279 > }
280 await profileSynchronizerItem[0].resetLocal();
281 profileSynchronizerItem[1].dispose();
282 this.activeProfileSynchronizers.delete(key);
283 }
285
286 private async applyManualSync(manifestOrLatestData: IUserDataManifest | IUserDataSyncLatestData | null, executionId: string, token: CancellationToken): Promise<void> {
318 private async syncProfile(profileSynchronizer: ProfileSynchronizer, manifestOrLatestData: IUserDataManifest | IUserDataSyncLatestData | null, preview: boolean, executionId: string, token: CancellationToken): Promise<IUserDataSyncResourceError[]> {
319 const errors = await profileSynchronizer.sync(manifestOrLatestData, preview, executionId, token);
320 > return errors.map(([syncResource, error]) => ({ profile: profileSynchronizer.profile, syncResource, error })); userDataSyncService.ts
321 }
322
598
599 private updateLastSyncTime(): void {
600 > if (this.status === SyncStatus.Idle) { userDataSyncService.ts
601 > this._lastSyncTime = new Date().getTime();
602 > this.storageService.store(LAST_SYNC_TIME_KEY, this._lastSyncTime, StorageScope.APPLICATION, StorageTarget.MACHINE);
603 > this._onDidChangeLastSyncTime.fire(this._lastSyncTime);
604 > }
605 > }
606
607 getOrCreateActiveProfileSynchronizer(profile: IUserDataProfile, syncProfile: ISyncUserDataProfile | undefined): ProfileSynchronizer {
src/vs/platform/extensionManagement/common/extensionEnablementService.ts 15 introduced LOC · 5 ranges

Open complete file

50
51 getDisabledExtensions(): IExtensionIdentifier[] {
52 > return this._getExtensions(DISABLED_EXTENSIONS_STORAGE_PATH); extensionEnablementService.ts
53 > }
54
55 async getDisabledExtensionsAsync(): Promise<IExtensionIdentifier[]> {
85
86 private _getExtensions(storageId: string): IExtensionIdentifier[] {
87 > return this.storageManager.get(storageId, StorageScope.PROFILE); extensionEnablementService.ts
88 > }
89
90 private _setExtensions(storageId: string, extensions: IExtensionIdentifier[]): void {
107
108 get(key: string, scope: StorageScope): IExtensionIdentifier[] {
109 > let value: string; extensionEnablementService.ts
110 > if (scope === StorageScope.PROFILE) {
111 > if (isUndefinedOrNull(this.storage[key])) {
112 > this.storage[key] = this._get(key, scope);
113 > }
114 > value = this.storage[key];
115 > } else {
116 value = this._get(key, scope);
117 }
118 > return JSON.parse(value); extensionEnablementService.ts
119 > }
120
121 set(key: string, value: IExtensionIdentifier[], scope: StorageScope): void {
151
152 private _get(key: string, scope: StorageScope): string {
153 > return this.storageService.get(key, scope, '[]'); extensionEnablementService.ts
154 > }
155
156 private _set(key: string, value: string | undefined, scope: StorageScope): void {
src/vs/platform/userDataSync/common/ignoredExtensions.ts 10 introduced LOC · 3 ranges

Open complete file

67
68 getIgnoredExtensions(installed: ILocalExtension[]): string[] {
69 > const defaultIgnoredExtensions = installed.filter(i => i.isMachineScoped).map(i => i.identifier.id.toLowerCase()); ignoredExtensions.ts
70 > const value = this.getConfiguredIgnoredExtensions().map(id => id.toLowerCase());
71 > const added: string[] = [], removed: string[] = [];
72 > if (Array.isArray(value)) {
73 > for (const key of value) {
74 if (key.startsWith('-')) {
75 removed.push(key.substring(1));
78 }
79 }
81 > return distinct([...defaultIgnoredExtensions, ...added,].filter(setting => !removed.includes(setting)));
82 > }
83
84 private getConfiguredIgnoredExtensions(): ReadonlyArray<string> {
85 > return (this.configurationService.getValue<string[]>('settingsSync.ignoredExtensions') || []).map(id => id.toLowerCase()); ignoredExtensions.ts
86 > }
87 }
src/vs/platform/userDataSync/common/userDataProfilesManifestSync.ts 3 introduced LOC · 1 range

Open complete file

57
58 async getLastSyncedProfiles(): Promise<ISyncUserDataProfile[] | null> {
59 > const lastSyncUserData = await this.getLastSyncUserData(); userDataProfilesManifestSync.ts
60 > return lastSyncUserData?.syncData ? parseUserDataProfilesManifest(lastSyncUserData.syncData) : null;
61 > }
62
63 async getRemoteSyncedProfiles(refOrLatestData: string | IUserData | null): Promise<ISyncUserDataProfile[] | null> {