sussudio
Version:
An unofficial VS Code Internal API
410 lines (409 loc) • 20 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
import { URI } from "../../../base/common/uri.mjs";
import { localize } from "../../../nls.mjs";
import { IEnvironmentService } from "../../environment/common/environment.mjs";
import { IFileService } from "../../files/common/files.mjs";
import { getServiceMachineId } from "../../externalServices/common/serviceMachineId.mjs";
import { IStorageService } from "../../storage/common/storage.mjs";
import { IUriIdentityService } from "../../uriIdentity/common/uriIdentity.mjs";
import { IUserDataSyncBackupStoreService, IUserDataSyncLogService, IUserDataSyncStoreService, UserDataSyncError, USER_DATA_SYNC_SCHEME, CONFIG_SYNC_KEYBINDINGS_PER_PLATFORM } from "./userDataSync.mjs";
import { IUserDataProfilesService } from "../../userDataProfile/common/userDataProfile.mjs";
import { isSyncData } from "./abstractSynchronizer.mjs";
import { parseSnippets } from "./snippetsSync.mjs";
import { parseSettingsSyncContent } from "./settingsSync.mjs";
import { getKeybindingsContentFromSyncContent } from "./keybindingsSync.mjs";
import { IConfigurationService } from "../../configuration/common/configuration.mjs";
import { getTasksContentFromSyncContent } from "./tasksSync.mjs";
import { LocalExtensionsProvider, parseExtensions, stringify as stringifyExtensions } from "./extensionsSync.mjs";
import { LocalGlobalStateProvider, stringify as stringifyGlobalState } from "./globalStateSync.mjs";
import { IInstantiationService } from "../../instantiation/common/instantiation.mjs";
import { parseUserDataProfilesManifest, stringifyLocalProfiles } from "./userDataProfilesManifestSync.mjs";
import { toFormattedString } from "../../../base/common/jsonFormatter.mjs";
let UserDataSyncResourceProviderService = class UserDataSyncResourceProviderService {
userDataSyncStoreService;
userDataSyncBackupStoreService;
logService;
environmentService;
storageService;
fileService;
userDataProfilesService;
configurationService;
instantiationService;
_serviceBrand;
static NOT_EXISTING_RESOURCE = 'not-existing-resource';
static REMOTE_BACKUP_AUTHORITY = 'remote-backup';
static LOCAL_BACKUP_AUTHORITY = 'local-backup';
extUri;
constructor(userDataSyncStoreService, userDataSyncBackupStoreService, logService, uriIdentityService, environmentService, storageService, fileService, userDataProfilesService, configurationService, instantiationService) {
this.userDataSyncStoreService = userDataSyncStoreService;
this.userDataSyncBackupStoreService = userDataSyncBackupStoreService;
this.logService = logService;
this.environmentService = environmentService;
this.storageService = storageService;
this.fileService = fileService;
this.userDataProfilesService = userDataProfilesService;
this.configurationService = configurationService;
this.instantiationService = instantiationService;
this.extUri = uriIdentityService.extUri;
}
async getRemoteSyncedProfiles() {
const userData = await this.userDataSyncStoreService.readResource("profiles" /* SyncResource.Profiles */, null, undefined);
if (userData.content) {
const syncData = this.parseSyncData(userData.content, "profiles" /* SyncResource.Profiles */);
return parseUserDataProfilesManifest(syncData);
}
return [];
}
async getRemoteSyncResourceHandles(syncResource, profile) {
const handles = await this.userDataSyncStoreService.getAllResourceRefs(syncResource, profile?.collection);
return handles.map(({ created, ref }) => ({
created,
uri: this.toUri({
remote: true,
syncResource,
profile: profile?.id ?? this.userDataProfilesService.defaultProfile.id,
collection: profile?.collection,
ref,
node: undefined,
})
}));
}
async getLocalSyncResourceHandles(syncResource, profile) {
const handles = await this.userDataSyncBackupStoreService.getAllRefs(profile, syncResource);
return handles.map(({ created, ref }) => ({
created,
uri: this.toUri({
remote: false,
syncResource,
profile: profile.id,
collection: undefined,
ref,
node: undefined,
})
}));
}
resolveUserDataSyncResource({ uri }) {
const resolved = this.resolveUri(uri);
const profile = resolved ? this.userDataProfilesService.profiles.find(p => p.id === resolved.profile) : undefined;
return resolved && profile ? { profile, syncResource: resolved?.syncResource } : undefined;
}
async getAssociatedResources({ uri }) {
const resolved = this.resolveUri(uri);
if (!resolved) {
return [];
}
const profile = this.userDataProfilesService.profiles.find(p => p.id === resolved.profile);
switch (resolved.syncResource) {
case "settings" /* SyncResource.Settings */: return this.getSettingsAssociatedResources(uri, profile);
case "keybindings" /* SyncResource.Keybindings */: return this.getKeybindingsAssociatedResources(uri, profile);
case "tasks" /* SyncResource.Tasks */: return this.getTasksAssociatedResources(uri, profile);
case "snippets" /* SyncResource.Snippets */: return this.getSnippetsAssociatedResources(uri, profile);
case "globalState" /* SyncResource.GlobalState */: return this.getGlobalStateAssociatedResources(uri, profile);
case "extensions" /* SyncResource.Extensions */: return this.getExtensionsAssociatedResources(uri, profile);
case "profiles" /* SyncResource.Profiles */: return this.getProfilesAssociatedResources(uri, profile);
}
}
async getMachineId({ uri }) {
const resolved = this.resolveUri(uri);
if (!resolved) {
return undefined;
}
if (resolved.remote) {
if (resolved.ref) {
const { content } = await this.getUserData(resolved.syncResource, resolved.ref, resolved.collection);
if (content) {
const syncData = this.parseSyncData(content, resolved.syncResource);
return syncData?.machineId;
}
}
return undefined;
}
return getServiceMachineId(this.environmentService, this.fileService, this.storageService);
}
async resolveContent(uri) {
const resolved = this.resolveUri(uri);
if (!resolved) {
return null;
}
if (resolved.node === UserDataSyncResourceProviderService.NOT_EXISTING_RESOURCE) {
return null;
}
if (resolved.ref) {
const content = await this.getContentFromStore(resolved.remote, resolved.syncResource, resolved.profile, resolved.collection, resolved.ref);
if (resolved.node && content) {
return this.resolveNodeContent(resolved.syncResource, content, resolved.node);
}
return content;
}
if (!resolved.remote && !resolved.node) {
return this.resolveLatestContent(resolved.syncResource, resolved.profile);
}
return null;
}
async getContentFromStore(remote, syncResource, profileId, collection, ref) {
if (remote) {
const { content } = await this.getUserData(syncResource, ref, collection);
return content;
}
const profile = this.userDataProfilesService.profiles.find(p => p.id === profileId);
if (profile) {
return this.userDataSyncBackupStoreService.resolveContent(profile, syncResource, ref);
}
return null;
}
resolveNodeContent(syncResource, content, node) {
const syncData = this.parseSyncData(content, syncResource);
switch (syncResource) {
case "settings" /* SyncResource.Settings */: return this.resolveSettingsNodeContent(syncData, node);
case "keybindings" /* SyncResource.Keybindings */: return this.resolveKeybindingsNodeContent(syncData, node);
case "tasks" /* SyncResource.Tasks */: return this.resolveTasksNodeContent(syncData, node);
case "snippets" /* SyncResource.Snippets */: return this.resolveSnippetsNodeContent(syncData, node);
case "globalState" /* SyncResource.GlobalState */: return this.resolveGlobalStateNodeContent(syncData, node);
case "extensions" /* SyncResource.Extensions */: return this.resolveExtensionsNodeContent(syncData, node);
case "profiles" /* SyncResource.Profiles */: return this.resolveProfileNodeContent(syncData, node);
}
}
async resolveLatestContent(syncResource, profileId) {
const profile = this.userDataProfilesService.profiles.find(p => p.id === profileId);
if (!profile) {
return null;
}
switch (syncResource) {
case "globalState" /* SyncResource.GlobalState */: return this.resolveLatestGlobalStateContent(profile);
case "extensions" /* SyncResource.Extensions */: return this.resolveLatestExtensionsContent(profile);
case "profiles" /* SyncResource.Profiles */: return this.resolveLatestProfilesContent(profile);
case "settings" /* SyncResource.Settings */: return null;
case "keybindings" /* SyncResource.Keybindings */: return null;
case "tasks" /* SyncResource.Tasks */: return null;
case "snippets" /* SyncResource.Snippets */: return null;
}
}
getSettingsAssociatedResources(uri, profile) {
const resource = this.extUri.joinPath(uri, 'settings.json');
const comparableResource = profile ? profile.settingsResource : this.extUri.joinPath(uri, UserDataSyncResourceProviderService.NOT_EXISTING_RESOURCE);
return [{ resource, comparableResource }];
}
resolveSettingsNodeContent(syncData, node) {
switch (node) {
case 'settings.json':
return parseSettingsSyncContent(syncData.content).settings;
}
return null;
}
getKeybindingsAssociatedResources(uri, profile) {
const resource = this.extUri.joinPath(uri, 'keybindings.json');
const comparableResource = profile ? profile.keybindingsResource : this.extUri.joinPath(uri, UserDataSyncResourceProviderService.NOT_EXISTING_RESOURCE);
return [{ resource, comparableResource }];
}
resolveKeybindingsNodeContent(syncData, node) {
switch (node) {
case 'keybindings.json':
return getKeybindingsContentFromSyncContent(syncData.content, !!this.configurationService.getValue(CONFIG_SYNC_KEYBINDINGS_PER_PLATFORM), this.logService);
}
return null;
}
getTasksAssociatedResources(uri, profile) {
const resource = this.extUri.joinPath(uri, 'tasks.json');
const comparableResource = profile ? profile.tasksResource : this.extUri.joinPath(uri, UserDataSyncResourceProviderService.NOT_EXISTING_RESOURCE);
return [{ resource, comparableResource }];
}
resolveTasksNodeContent(syncData, node) {
switch (node) {
case 'tasks.json':
return getTasksContentFromSyncContent(syncData.content, this.logService);
}
return null;
}
async getSnippetsAssociatedResources(uri, profile) {
const content = await this.resolveContent(uri);
if (content) {
const syncData = this.parseSyncData(content, "snippets" /* SyncResource.Snippets */);
if (syncData) {
const snippets = parseSnippets(syncData);
const result = [];
for (const snippet of Object.keys(snippets)) {
const resource = this.extUri.joinPath(uri, snippet);
const comparableResource = profile ? this.extUri.joinPath(profile.snippetsHome, snippet) : this.extUri.joinPath(uri, UserDataSyncResourceProviderService.NOT_EXISTING_RESOURCE);
result.push({ resource, comparableResource });
}
return result;
}
}
return [];
}
resolveSnippetsNodeContent(syncData, node) {
return parseSnippets(syncData)[node] || null;
}
getExtensionsAssociatedResources(uri, profile) {
const resource = this.extUri.joinPath(uri, 'extensions.json');
const comparableResource = profile
? this.toUri({
remote: false,
syncResource: "extensions" /* SyncResource.Extensions */,
profile: profile.id,
collection: undefined,
ref: undefined,
node: undefined,
})
: this.extUri.joinPath(uri, UserDataSyncResourceProviderService.NOT_EXISTING_RESOURCE);
return [{ resource, comparableResource }];
}
resolveExtensionsNodeContent(syncData, node) {
switch (node) {
case 'extensions.json':
return stringifyExtensions(parseExtensions(syncData), true);
}
return null;
}
async resolveLatestExtensionsContent(profile) {
const { localExtensions } = await this.instantiationService.createInstance(LocalExtensionsProvider).getLocalExtensions(profile);
return stringifyExtensions(localExtensions, true);
}
getGlobalStateAssociatedResources(uri, profile) {
const resource = this.extUri.joinPath(uri, 'globalState.json');
const comparableResource = profile
? this.toUri({
remote: false,
syncResource: "globalState" /* SyncResource.GlobalState */,
profile: profile.id,
collection: undefined,
ref: undefined,
node: undefined,
})
: this.extUri.joinPath(uri, UserDataSyncResourceProviderService.NOT_EXISTING_RESOURCE);
return [{ resource, comparableResource }];
}
resolveGlobalStateNodeContent(syncData, node) {
switch (node) {
case 'globalState.json':
return stringifyGlobalState(JSON.parse(syncData.content), true);
}
return null;
}
async resolveLatestGlobalStateContent(profile) {
const localGlobalState = await this.instantiationService.createInstance(LocalGlobalStateProvider).getLocalGlobalState(profile);
return stringifyGlobalState(localGlobalState, true);
}
getProfilesAssociatedResources(uri, profile) {
const resource = this.extUri.joinPath(uri, 'profiles.json');
const comparableResource = this.toUri({
remote: false,
syncResource: "profiles" /* SyncResource.Profiles */,
profile: this.userDataProfilesService.defaultProfile.id,
collection: undefined,
ref: undefined,
node: undefined,
});
return [{ resource, comparableResource }];
}
resolveProfileNodeContent(syncData, node) {
switch (node) {
case 'profiles.json':
return toFormattedString(JSON.parse(syncData.content), {});
}
return null;
}
async resolveLatestProfilesContent(profile) {
return stringifyLocalProfiles(this.userDataProfilesService.profiles.filter(p => !p.isDefault && !p.isTransient), true);
}
toUri(syncResourceUriInfo) {
const authority = syncResourceUriInfo.remote ? UserDataSyncResourceProviderService.REMOTE_BACKUP_AUTHORITY : UserDataSyncResourceProviderService.LOCAL_BACKUP_AUTHORITY;
const paths = [
syncResourceUriInfo.syncResource,
syncResourceUriInfo.profile,
];
if (syncResourceUriInfo.collection) {
paths.push(`collection:${syncResourceUriInfo.collection}`);
}
if (syncResourceUriInfo.ref) {
paths.push(`ref:${syncResourceUriInfo.ref}`);
}
if (syncResourceUriInfo.node) {
paths.push(syncResourceUriInfo.node);
}
return this.extUri.joinPath(URI.from({ scheme: USER_DATA_SYNC_SCHEME, authority, path: `/` }), ...paths);
}
resolveUri(uri) {
if (uri.scheme !== USER_DATA_SYNC_SCHEME) {
return undefined;
}
if (uri.authority !== UserDataSyncResourceProviderService.LOCAL_BACKUP_AUTHORITY && uri.authority !== UserDataSyncResourceProviderService.REMOTE_BACKUP_AUTHORITY) {
return undefined;
}
const paths = [];
while (uri.path !== '/') {
paths.unshift(this.extUri.basename(uri));
uri = this.extUri.dirname(uri);
}
if (paths.length < 2) {
return undefined;
}
const remote = uri.authority === UserDataSyncResourceProviderService.REMOTE_BACKUP_AUTHORITY;
const syncResource = paths.shift();
const profile = paths.shift();
let collection;
let ref;
let node;
while (paths.length) {
const path = paths.shift();
if (path.startsWith('collection:')) {
collection = path.substring('collection:'.length);
}
else if (path.startsWith('ref:')) {
ref = path.substring('ref:'.length);
}
else {
node = path;
}
}
return {
remote,
syncResource,
profile,
collection,
ref,
node,
};
}
parseSyncData(content, syncResource) {
try {
const syncData = JSON.parse(content);
if (isSyncData(syncData)) {
return syncData;
}
}
catch (error) {
this.logService.error(error);
}
throw new UserDataSyncError(localize('incompatible sync data', "Cannot parse sync data as it is not compatible with the current version."), "IncompatibleRemoteContent" /* UserDataSyncErrorCode.IncompatibleRemoteContent */, syncResource);
}
async getUserData(syncResource, ref, collection) {
const content = await this.userDataSyncStoreService.resolveResourceContent(syncResource, ref, collection);
return { ref, content };
}
};
UserDataSyncResourceProviderService = __decorate([
__param(0, IUserDataSyncStoreService),
__param(1, IUserDataSyncBackupStoreService),
__param(2, IUserDataSyncLogService),
__param(3, IUriIdentityService),
__param(4, IEnvironmentService),
__param(5, IStorageService),
__param(6, IFileService),
__param(7, IUserDataProfilesService),
__param(8, IConfigurationService),
__param(9, IInstantiationService)
], UserDataSyncResourceProviderService);
export { UserDataSyncResourceProviderService };