export function stringify(extensions: ISyncExtension[], format: boolean): string {
if (!e1.identifier.uuid && e2.identifier.uuid) {
return -1;
Frontier kind: Code frontier
unlabeled · c_3dd23944154c
127 tests · 26401 LOC · 133 files · introduces 0 tests · 158 LOC · 5 files
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.
Every exact file and test below is linked only from the concept that introduces it.
mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/userDataSync/test/common/userDataAutoSyncService.test|title=UserDataAutoSyncService test auto sync with non sync resource change triggers sync|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/userDataSync/test/common/userDataAutoSyncService.test|title=UserDataAutoSyncService test auto sync with sync resource change triggers sync|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/userDataSync/test/common/userDataAutoSyncService.test|title=UserDataAutoSyncService test auto sync send execution id header|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/userDataSync/test/common/userDataAutoSyncService.test|title=UserDataAutoSyncService test further auto sync requests without changes|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/userDataSync/test/common/promptsSync.test|title=PromptsSync accept when there are multiple prompts with conflicts and only one prompt is accepted|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/userDataSync/test/common/promptsSync.test|title=PromptsSync first time sync when prompts exists - has multiple conflicts and accept one conflict|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/userDataSync/test/common/userDataSyncService.test|title=UserDataSyncService test first time sync ever|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/userDataSync/test/common/userDataSyncService.test|title=UserDataSyncService test sync send execution id header|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/userDataSync/test/common/userDataSyncService.test|title=UserDataSyncService test sync status|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/lifecycle.test|title=Lifecycle Action bar has broken accessibility #100273|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/lifecycle.test|title=Lifecycle dispose disposable array|occurrence=1Every collected test enters the hierarchy at exactly one concept.
No tests are introduced at this concept. Its intent tests are introduced by other concepts.
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.
export function stringify(extensions: ISyncExtension[], format: boolean): string {
if (!e1.identifier.uuid && e2.identifier.uuid) {
return -1;
}
return compare(e1.identifier.id, e2.identifier.id);
return format ? toFormattedString(extensions, {}) : JSON.stringify(extensions);
}
export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
protected async generateSyncPreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<IExtensionResourcePreview[]> {
const remoteExtensions = remoteUserData.syncData ? await parseAndMigrateExtensions(remoteUserData.syncData, this.extensionManagementService) : null;
extensionsSync.ts
const skippedExtensions = lastSyncUserData?.skippedExtensions ?? [];
const builtinExtensions = lastSyncUserData?.builtinExtensions ?? null;
const lastSyncExtensions = lastSyncUserData?.syncData ? await parseAndMigrateExtensions(lastSyncUserData.syncData, this.extensionManagementService) : null;
const { localExtensions, ignoredExtensions } = await this.localExtensionsProvider.getLocalExtensions(this.syncResource.profile);
if (remoteExtensions) {
this.logService.trace(`${this.syncResourceLogLabel}: Merging remote extensions with local extensions...`);
this.logService.trace(`${this.syncResourceLogLabel}: Remote extensions does not exist. Synchronizing extensions for the first time.`);
}
const { local, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, ignoredExtensions, builtinExtensions);
const previewResult: IExtensionResourceMergeResult = {
local, remote,
content: this.getPreviewContent(localExtensions, local.added, local.updated, local.removed),
localChange: local.added.length > 0 || local.removed.length > 0 || local.updated.length > 0 ? Change.Modified : Change.None,
remoteChange: remote !== null ? Change.Modified : Change.None,
};
const localContent = this.stringify(localExtensions, false);
return [{
skippedExtensions,
builtinExtensions,
baseResource: this.baseResource,
baseContent: lastSyncExtensions ? this.stringify(lastSyncExtensions, false) : localContent,
localResource: this.localResource,
localContent,
localExtensions,
remoteResource: this.remoteResource,
remoteExtensions,
remoteContent: remoteExtensions ? this.stringify(remoteExtensions, false) : null,
previewResource: this.previewResource,
previewResult,
localChange: previewResult.localChange,
remoteChange: previewResult.remoteChange,
acceptedResource: this.acceptedResource,
}];
}
protected async hasRemoteChanged(lastSyncUserData: ILastSyncUserData): Promise<boolean> {
private getPreviewContent(localExtensions: ISyncExtension[], added: ISyncExtension[], updated: ISyncExtension[], removed: IExtensionIdentifier[]): string {
const idsOrUUIDs: Set<string> = new Set<string>();
const addIdentifier = (identifier: IExtensionIdentifier) => {
idsOrUUIDs.add(identifier.id.toLowerCase());
if (identifier.uuid) {
}
};
removed.forEach(addIdentifier);
for (const localExtension of localExtensions) {
if (idsOrUUIDs.has(localExtension.identifier.id.toLowerCase()) || (localExtension.identifier.uuid && idsOrUUIDs.has(localExtension.identifier.uuid))) {
// skip
preview.push(localExtension);
}
return this.stringify(preview, false);
}
protected async getMergeResult(resourcePreview: IExtensionResourcePreview, token: CancellationToken): Promise<IMergeResult> {
protected async applyResult(remoteUserData: IRemoteUserData, lastSyncUserData: IRemoteUserData | null, resourcePreviews: [IExtensionResourcePreview, IExtensionResourceMergeResult][], force: boolean): Promise<void> {
let { skippedExtensions, builtinExtensions, localExtensions } = resourcePreviews[0][0];
extensionsSync.ts
const { local, remote, localChange, remoteChange } = resourcePreviews[0][1];
if (localChange === Change.None && remoteChange === Change.None) {
this.logService.info(`${this.syncResourceLogLabel}: No changes found during synchronizing extensions.`);
}
if (localChange !== Change.None) {
await this.backupLocal(JSON.stringify(localExtensions));
skippedExtensions = await this.localExtensionsProvider.updateLocalExtensions(local.added, local.removed, local.updated, skippedExtensions, this.syncResource.profile);
}
if (remote) {
// update remote
this.logService.trace(`${this.syncResourceLogLabel}: Updating remote extensions...`);
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))}.` : ''}`);
}
if (lastSyncUserData?.ref !== remoteUserData.ref) {
// update last sync
this.logService.trace(`${this.syncResourceLogLabel}: Updating last synchronized extensions...`);
builtinExtensions = this.computeBuiltinExtensions(localExtensions, builtinExtensions);
await this.updateLastSyncUserData(remoteUserData, { skippedExtensions, builtinExtensions });
this.logService.info(`${this.syncResourceLogLabel}: Updated last synchronized extensions.${skippedExtensions.length ? ` Skipped: ${JSON.stringify(skippedExtensions.map(e => e.identifier.id))}.` : ''}`);
}
}
private computeBuiltinExtensions(localExtensions: ILocalSyncExtension[], previousBuiltinExtensions: IExtensionIdentifier[] | null): IExtensionIdentifier[] {
const builtinExtensions: IExtensionIdentifier[] = [];
for (const localExtension of localExtensions) {
localExtensionsSet.add(localExtension.identifier.id.toLowerCase());
if (!localExtension.installed) {
}
}
for (const builtinExtension of previousBuiltinExtensions) {
// Add previous builtin extension if it does not exist in local extensions
}
}
}
async resolveContent(uri: URI): Promise<string | null> {
private stringify(extensions: ISyncExtension[], format: boolean): string {
}
async hasLocalData(): Promise<boolean> {
async getLocalExtensions(profile: IUserDataProfile): Promise<{ localExtensions: ILocalSyncExtension[]; ignoredExtensions: string[] }> {
const installedExtensions = await this.extensionManagementService.getInstalled(undefined, profile.extensionsResource);
extensionsSync.ts
const ignoredExtensions = this.ignoredExtensionsManagementService.getIgnoredExtensions(installedExtensions);
const localExtensions = await this.withProfileScopedServices(profile, async (extensionEnablementService, extensionStorageService) => {
const disabledExtensions = extensionEnablementService.getDisabledExtensions();
return installedExtensions
.map(extension => {
const { identifier, isBuiltin, manifest, preRelease, pinned, isApplicationScoped } = extension;
const syncExtension: ILocalSyncExtension = { identifier, preRelease, version: manifest.version, pinned: !!pinned };
}
return syncExtension;
});
return { localExtensions, ignoredExtensions };
}
async updateLocalExtensions(added: ISyncExtension[], removed: IExtensionIdentifier[], updated: ISyncExtension[], skippedExtensions: ISyncExtension[], profile: IUserDataProfile): Promise<ISyncExtension[]> {
private async withProfileScopedServices<T>(profile: IUserDataProfile, fn: (extensionEnablementService: IGlobalExtensionEnablementService, extensionStorageService: IExtensionStorageService) => Promise<T>): Promise<T> {
return this.userDataProfileStorageService.withProfileScopedStorageService(profile,
extensionsSync.ts
async storageService => {
const disposables = new DisposableStore();
const instantiationService = disposables.add(this.instantiationService.createChild(new ServiceCollection([IStorageService, storageService])));
const extensionEnablementService = disposables.add(instantiationService.createInstance(GlobalExtensionEnablementService));
const extensionStorageService = disposables.add(instantiationService.createInstance(ExtensionStorageService));
try {
return await fn(extensionEnablementService, extensionStorageService);
} finally {
disposables.dispose();
}
});
}
}
cancellablePromise = createCancelablePromise(token => that.sync(manifest, false, executionId, token));
await cancellablePromise.finally(() => cancellablePromise = undefined);
that.logService.info(`Sync done. Took ${new Date().getTime() - startTime}ms`);
userDataSyncService.ts
that.updateLastSyncTime();
},
stop(): Promise<void> {
const defaultProfileSynchronizer = this.getOrCreateActiveProfileSynchronizer(this.userDataProfilesService.defaultProfile, undefined);
this._syncErrors.push(...await this.syncProfile(defaultProfileSynchronizer, manifestOrLatestData, preview, executionId, token));
// Sync other profiles
const userDataProfileManifestSynchronizer = defaultProfileSynchronizer.enabled.find(s => s.resource === SyncResource.Profiles);
if (userDataProfileManifestSynchronizer) {
const syncProfiles = (await (userDataProfileManifestSynchronizer as UserDataProfilesManifestSynchroniser).getLastSyncedProfiles()) || [];
if (token.isCancellationRequested) {
return;
}
await this.syncRemoteProfiles(syncProfiles, manifestOrLatestData, preview, executionId, token);
userDataSyncService.ts
}
} finally {
if (this.status !== SyncStatus.HasConflicts) {
private async syncRemoteProfiles(remoteProfiles: ISyncUserDataProfile[], manifest: IUserDataManifest | IUserDataSyncLatestData | null, preview: boolean, executionId: string, token: CancellationToken): Promise<void> {
if (token.isCancellationRequested) {
return;
this._syncErrors.push(...await this.syncProfile(profileSynchronizer, manifest, preview, executionId, token));
}
for (const [key, profileSynchronizerItem] of this.activeProfileSynchronizers.entries()) {
if (this.userDataProfilesService.profiles.some(p => p.id === profileSynchronizerItem[0].profile.id)) {
continue;
}
await profileSynchronizerItem[0].resetLocal();
profileSynchronizerItem[1].dispose();
this.activeProfileSynchronizers.delete(key);
}
private async applyManualSync(manifestOrLatestData: IUserDataManifest | IUserDataSyncLatestData | null, executionId: string, token: CancellationToken): Promise<void> {
private async syncProfile(profileSynchronizer: ProfileSynchronizer, manifestOrLatestData: IUserDataManifest | IUserDataSyncLatestData | null, preview: boolean, executionId: string, token: CancellationToken): Promise<IUserDataSyncResourceError[]> {
const errors = await profileSynchronizer.sync(manifestOrLatestData, preview, executionId, token);
return errors.map(([syncResource, error]) => ({ profile: profileSynchronizer.profile, syncResource, error }));
userDataSyncService.ts
}
private updateLastSyncTime(): void {
this._lastSyncTime = new Date().getTime();
this.storageService.store(LAST_SYNC_TIME_KEY, this._lastSyncTime, StorageScope.APPLICATION, StorageTarget.MACHINE);
this._onDidChangeLastSyncTime.fire(this._lastSyncTime);
}
}
getOrCreateActiveProfileSynchronizer(profile: IUserDataProfile, syncProfile: ISyncUserDataProfile | undefined): ProfileSynchronizer {
}
}
return syncErrors;
} finally {
this.updateStatus();
getDisabledExtensions(): IExtensionIdentifier[] {
}
async getDisabledExtensionsAsync(): Promise<IExtensionIdentifier[]> {
private _getExtensions(storageId: string): IExtensionIdentifier[] {
}
private _setExtensions(storageId: string, extensions: IExtensionIdentifier[]): void {
get(key: string, scope: StorageScope): IExtensionIdentifier[] {
if (scope === StorageScope.PROFILE) {
if (isUndefinedOrNull(this.storage[key])) {
this.storage[key] = this._get(key, scope);
}
value = this.storage[key];
} else {
value = this._get(key, scope);
}
}
set(key: string, value: IExtensionIdentifier[], scope: StorageScope): void {
private _get(key: string, scope: StorageScope): string {
}
private _set(key: string, value: string | undefined, scope: StorageScope): void {
getIgnoredExtensions(installed: ILocalExtension[]): string[] {
const defaultIgnoredExtensions = installed.filter(i => i.isMachineScoped).map(i => i.identifier.id.toLowerCase());
ignoredExtensions.ts
const value = this.getConfiguredIgnoredExtensions().map(id => id.toLowerCase());
const added: string[] = [], removed: string[] = [];
if (Array.isArray(value)) {
for (const key of value) {
if (key.startsWith('-')) {
removed.push(key.substring(1));
}
}
return distinct([...defaultIgnoredExtensions, ...added,].filter(setting => !removed.includes(setting)));
}
private getConfiguredIgnoredExtensions(): ReadonlyArray<string> {
return (this.configurationService.getValue<string[]>('settingsSync.ignoredExtensions') || []).map(id => id.toLowerCase());
ignoredExtensions.ts
}
}
async getLastSyncedProfiles(): Promise<ISyncUserDataProfile[] | null> {
return lastSyncUserData?.syncData ? parseUserDataProfilesManifest(lastSyncUserData.syncData) : null;
}
async getRemoteSyncedProfiles(refOrLatestData: string | IUserData | null): Promise<ISyncUserDataProfile[] | null> {