mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode e6a45f4242ebddb7aa9a229f85555e8a3bd987e2 (#9253)
* Merge from vscode e6a45f4242ebddb7aa9a229f85555e8a3bd987e2 * skip failing tests * remove github-authentication extensions * ignore github compile steps * ignore github compile steps * check in compiled files
This commit is contained in:
@@ -3,11 +3,24 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IUserDataAuthTokenService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
|
||||
export class UserDataAuthTokenService extends Disposable implements IUserDataAuthTokenService {
|
||||
export const IAuthenticationTokenService = createDecorator<IAuthenticationTokenService>('IAuthenticationTokenService');
|
||||
|
||||
export interface IAuthenticationTokenService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
readonly onDidChangeToken: Event<string | undefined>;
|
||||
readonly onTokenFailed: Event<void>;
|
||||
|
||||
getToken(): Promise<string | undefined>;
|
||||
setToken(accessToken: string | undefined): Promise<void>;
|
||||
sendTokenFailed(): void;
|
||||
}
|
||||
|
||||
export class AuthenticationTokenService extends Disposable implements IAuthenticationTokenService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
@@ -38,3 +51,4 @@ export class UserDataAuthTokenService extends Disposable implements IUserDataAut
|
||||
this._onTokenFailed.fire();
|
||||
}
|
||||
}
|
||||
|
||||
29
src/vs/platform/authentication/common/authenticationIpc.ts
Normal file
29
src/vs/platform/authentication/common/authenticationIpc.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||
|
||||
|
||||
export class AuthenticationTokenServiceChannel implements IServerChannel {
|
||||
constructor(private readonly service: IAuthenticationTokenService) { }
|
||||
|
||||
listen(_: unknown, event: string): Event<any> {
|
||||
switch (event) {
|
||||
case 'onDidChangeToken': return this.service.onDidChangeToken;
|
||||
case 'onTokenFailed': return this.service.onTokenFailed;
|
||||
}
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
||||
call(context: any, command: string, args?: any): Promise<any> {
|
||||
switch (command) {
|
||||
case 'setToken': return this.service.setToken(args);
|
||||
case 'getToken': return this.service.getToken();
|
||||
}
|
||||
throw new Error('Invalid call');
|
||||
}
|
||||
}
|
||||
@@ -113,6 +113,7 @@ export interface IConfigurationPropertySchema extends IJSONSchema {
|
||||
scope?: ConfigurationScope;
|
||||
included?: boolean;
|
||||
tags?: string[];
|
||||
disallowSyncIgnore?: boolean;
|
||||
}
|
||||
|
||||
export interface IConfigurationExtensionInfo {
|
||||
|
||||
@@ -228,6 +228,11 @@ export const enum TextEditorSelectionRevealType {
|
||||
* Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top.
|
||||
*/
|
||||
NearTop = 2,
|
||||
/**
|
||||
* Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top.
|
||||
* Only if it lies outside the viewport
|
||||
*/
|
||||
NearTopIfOutsideViewport = 3,
|
||||
}
|
||||
|
||||
export interface ITextEditorOptions extends IEditorOptions {
|
||||
|
||||
@@ -59,6 +59,8 @@ export interface IssueReporterData extends WindowData {
|
||||
enabledExtensions: IssueReporterExtensionData[];
|
||||
issueType?: IssueType;
|
||||
extensionId?: string;
|
||||
readonly issueTitle?: string;
|
||||
readonly issueBody?: string;
|
||||
}
|
||||
|
||||
export interface ISettingSearchResult {
|
||||
|
||||
@@ -35,6 +35,7 @@ export enum RemoteAuthorityResolverErrorCode {
|
||||
Unknown = 'Unknown',
|
||||
NotAvailable = 'NotAvailable',
|
||||
TemporarilyNotAvailable = 'TemporarilyNotAvailable',
|
||||
NoResolverFound = 'NoResolverFound'
|
||||
}
|
||||
|
||||
export class RemoteAuthorityResolverError extends Error {
|
||||
@@ -50,10 +51,11 @@ export class RemoteAuthorityResolverError extends Error {
|
||||
}
|
||||
|
||||
public static isTemporarilyNotAvailable(err: any): boolean {
|
||||
if (err instanceof RemoteAuthorityResolverError) {
|
||||
return err._code === RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable;
|
||||
}
|
||||
return false;
|
||||
return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable;
|
||||
}
|
||||
|
||||
public static isNoResolverFound(err: any): boolean {
|
||||
return (err instanceof RemoteAuthorityResolverError) && err._code === RemoteAuthorityResolverErrorCode.NoResolverFound;
|
||||
}
|
||||
|
||||
public readonly _message: string | undefined;
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface IUndoRedoElement {
|
||||
/**
|
||||
* None, one or multiple resources that this undo/redo element impacts.
|
||||
*/
|
||||
readonly resources: URI[];
|
||||
readonly resources: readonly URI[];
|
||||
|
||||
/**
|
||||
* The label of the undo/redo element.
|
||||
@@ -43,7 +43,7 @@ export interface IUndoRedoElement {
|
||||
* Invalidate the edits concerning `resource`.
|
||||
* i.e. the undo/redo stack for that particular resource has been destroyed.
|
||||
*/
|
||||
invalidate(resource: URI): boolean;
|
||||
invalidate(resource: URI): void;
|
||||
}
|
||||
|
||||
export interface IUndoRedoService {
|
||||
|
||||
@@ -7,11 +7,12 @@ import { IUndoRedoService, IUndoRedoElement } from 'vs/platform/undoRedo/common/
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { getComparisonKey as uriGetComparisonKey } from 'vs/base/common/resources';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
class StackElement {
|
||||
public readonly actual: IUndoRedoElement;
|
||||
public readonly label: string;
|
||||
public readonly resources: URI[];
|
||||
public readonly resources: readonly URI[];
|
||||
public readonly strResources: string[];
|
||||
|
||||
constructor(actual: IUndoRedoElement) {
|
||||
@@ -179,7 +180,7 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
return false;
|
||||
}
|
||||
|
||||
redo(resource: URI): void {
|
||||
public redo(resource: URI): void {
|
||||
const strResource = uriGetComparisonKey(resource);
|
||||
if (!this._editStacks.has(strResource)) {
|
||||
return;
|
||||
@@ -239,3 +240,5 @@ export class UndoRedoService implements IUndoRedoService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IUndoRedoService, UndoRedoService);
|
||||
|
||||
@@ -19,6 +19,8 @@ import { FormattingOptions } from 'vs/base/common/jsonFormatter';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
const BACK_UP_MAX_AGE = 1000 * 60 * 60 * 24 * 30; /* 30 days */
|
||||
|
||||
type SyncSourceClassification = {
|
||||
source?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
|
||||
};
|
||||
@@ -68,6 +70,7 @@ export abstract class AbstractSynchroniser extends Disposable {
|
||||
this.syncFolder = joinPath(environmentService.userDataSyncHome, source);
|
||||
this.lastSyncResource = joinPath(this.syncFolder, `.lastSync${source}.json`);
|
||||
this.cleanUpDelayer = new ThrottledDelayer(50);
|
||||
this.cleanUpBackup();
|
||||
}
|
||||
|
||||
protected setStatus(status: SyncStatus): void {
|
||||
@@ -195,9 +198,24 @@ export abstract class AbstractSynchroniser extends Disposable {
|
||||
private async cleanUpBackup(): Promise<void> {
|
||||
const stat = await this.fileService.resolve(this.syncFolder);
|
||||
if (stat.children) {
|
||||
const all = stat.children.filter(stat => stat.isFile && /^\d{8}T\d{6}$/.test(stat.name)).sort();
|
||||
const toDelete = all.slice(0, Math.max(0, all.length - 9));
|
||||
await Promise.all(toDelete.map(stat => this.fileService.del(stat.resource)));
|
||||
const toDelete = stat.children.filter(stat => {
|
||||
if (stat.isFile && /^\d{8}T\d{6}$/.test(stat.name)) {
|
||||
const ctime = stat.ctime || new Date(
|
||||
parseInt(stat.name.substring(0, 4)),
|
||||
parseInt(stat.name.substring(4, 6)) - 1,
|
||||
parseInt(stat.name.substring(6, 8)),
|
||||
parseInt(stat.name.substring(9, 11)),
|
||||
parseInt(stat.name.substring(11, 13)),
|
||||
parseInt(stat.name.substring(13, 15))
|
||||
).getTime();
|
||||
return Date.now() - ctime > BACK_UP_MAX_AGE;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
await Promise.all(toDelete.map(stat => {
|
||||
this.logService.info('Deleting from backup', stat.resource.path);
|
||||
this.fileService.del(stat.resource);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,12 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
||||
};
|
||||
}
|
||||
|
||||
// massage incoming extension - add disabled property
|
||||
const massageIncomingExtension = (extension: ISyncExtension): ISyncExtension => ({ ...extension, ...{ disabled: !!extension.disabled } });
|
||||
localExtensions = localExtensions.map(massageIncomingExtension);
|
||||
remoteExtensions = remoteExtensions.map(massageIncomingExtension);
|
||||
lastSyncExtensions = lastSyncExtensions ? lastSyncExtensions.map(massageIncomingExtension) : null;
|
||||
|
||||
const uuids: Map<string, string> = new Map<string, string>();
|
||||
const addUUID = (identifier: IExtensionIdentifier) => { if (identifier.uuid) { uuids.set(identifier.id.toLowerCase(), identifier.uuid); } };
|
||||
localExtensions.forEach(({ identifier }) => addUUID(identifier));
|
||||
@@ -37,10 +43,12 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
||||
lastSyncExtensions.forEach(({ identifier }) => addUUID(identifier));
|
||||
}
|
||||
|
||||
const addExtensionToMap = (map: Map<string, ISyncExtension>, extension: ISyncExtension) => {
|
||||
const getKey = (extension: ISyncExtension): string => {
|
||||
const uuid = extension.identifier.uuid || uuids.get(extension.identifier.id.toLowerCase());
|
||||
const key = uuid ? `uuid:${uuid}` : `id:${extension.identifier.id.toLowerCase()}`;
|
||||
map.set(key, extension);
|
||||
return uuid ? `uuid:${uuid}` : `id:${extension.identifier.id.toLowerCase()}`;
|
||||
};
|
||||
const addExtensionToMap = (map: Map<string, ISyncExtension>, extension: ISyncExtension) => {
|
||||
map.set(getKey(extension), extension);
|
||||
return map;
|
||||
};
|
||||
const localExtensionsMap = localExtensions.reduce(addExtensionToMap, new Map<string, ISyncExtension>());
|
||||
@@ -62,14 +70,17 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
||||
const baseToLocal = compare(lastSyncExtensionsMap, localExtensionsMap, ignoredExtensionsSet);
|
||||
const baseToRemote = compare(lastSyncExtensionsMap, remoteExtensionsMap, ignoredExtensionsSet);
|
||||
|
||||
const massageSyncExtension = (extension: ISyncExtension, key: string): ISyncExtension => {
|
||||
// massage outgoing extension - remove disabled property
|
||||
const massageOutgoingExtension = (extension: ISyncExtension, key: string): ISyncExtension => {
|
||||
const massagedExtension: ISyncExtension = {
|
||||
identifier: {
|
||||
id: extension.identifier.id,
|
||||
uuid: startsWith(key, 'uuid:') ? key.substring('uuid:'.length) : undefined
|
||||
},
|
||||
enabled: extension.enabled,
|
||||
};
|
||||
if (extension.disabled) {
|
||||
massagedExtension.disabled = true;
|
||||
}
|
||||
if (extension.version) {
|
||||
massagedExtension.version = extension.version;
|
||||
}
|
||||
@@ -90,25 +101,25 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
||||
if (baseToLocal.added.has(key)) {
|
||||
// Is different from local to remote
|
||||
if (localToRemote.updated.has(key)) {
|
||||
updated.push(massageSyncExtension(remoteExtensionsMap.get(key)!, key));
|
||||
updated.push(massageOutgoingExtension(remoteExtensionsMap.get(key)!, key));
|
||||
}
|
||||
} else {
|
||||
// Add to local
|
||||
added.push(massageSyncExtension(remoteExtensionsMap.get(key)!, key));
|
||||
added.push(massageOutgoingExtension(remoteExtensionsMap.get(key)!, key));
|
||||
}
|
||||
}
|
||||
|
||||
// Remotely updated extensions
|
||||
for (const key of values(baseToRemote.updated)) {
|
||||
// Update in local always
|
||||
updated.push(massageSyncExtension(remoteExtensionsMap.get(key)!, key));
|
||||
updated.push(massageOutgoingExtension(remoteExtensionsMap.get(key)!, key));
|
||||
}
|
||||
|
||||
// Locally added extensions
|
||||
for (const key of values(baseToLocal.added)) {
|
||||
// Not there in remote
|
||||
if (!baseToRemote.added.has(key)) {
|
||||
newRemoteExtensionsMap.set(key, massageSyncExtension(localExtensionsMap.get(key)!, key));
|
||||
newRemoteExtensionsMap.set(key, localExtensionsMap.get(key)!);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +132,7 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
||||
|
||||
// If not updated in remote
|
||||
if (!baseToRemote.updated.has(key)) {
|
||||
newRemoteExtensionsMap.set(key, massageSyncExtension(localExtensionsMap.get(key)!, key));
|
||||
newRemoteExtensionsMap.set(key, localExtensionsMap.get(key)!);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,9 +144,13 @@ export function merge(localExtensions: ISyncExtension[], remoteExtensions: ISync
|
||||
}
|
||||
}
|
||||
|
||||
const remote: ISyncExtension[] = [];
|
||||
const remoteChanges = compare(remoteExtensionsMap, newRemoteExtensionsMap, new Set<string>());
|
||||
const remote = remoteChanges.added.size > 0 || remoteChanges.updated.size > 0 || remoteChanges.removed.size > 0 ? values(newRemoteExtensionsMap) : null;
|
||||
return { added, removed, updated, remote };
|
||||
if (remoteChanges.added.size > 0 || remoteChanges.updated.size > 0 || remoteChanges.removed.size > 0) {
|
||||
newRemoteExtensionsMap.forEach((value, key) => remote.push(massageOutgoingExtension(value, key)));
|
||||
}
|
||||
|
||||
return { added, removed, updated, remote: remote.length ? remote : null };
|
||||
}
|
||||
|
||||
function compare(from: Map<string, ISyncExtension> | null, to: Map<string, ISyncExtension>, ignoredExtensions: Set<string>): { added: Set<string>, removed: Set<string>, updated: Set<string> } {
|
||||
@@ -152,7 +167,7 @@ function compare(from: Map<string, ISyncExtension> | null, to: Map<string, ISync
|
||||
const fromExtension = from!.get(key)!;
|
||||
const toExtension = to.get(key);
|
||||
if (!toExtension
|
||||
|| fromExtension.enabled !== toExtension.enabled
|
||||
|| fromExtension.disabled !== toExtension.disabled
|
||||
|| fromExtension.version !== toExtension.version
|
||||
) {
|
||||
updated.add(key);
|
||||
|
||||
@@ -14,17 +14,19 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { localize } from 'vs/nls';
|
||||
import { merge } from 'vs/platform/userDataSync/common/extensionsMerge';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { AbstractSynchroniser, IRemoteUserData } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { AbstractSynchroniser, IRemoteUserData, ISyncData } from 'vs/platform/userDataSync/common/abstractSynchronizer';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
interface ISyncPreviewResult {
|
||||
readonly localExtensions: ISyncExtension[];
|
||||
readonly remoteUserData: IRemoteUserData;
|
||||
readonly lastSyncUserData: ILastSyncUserData | null;
|
||||
readonly added: ISyncExtension[];
|
||||
readonly removed: IExtensionIdentifier[];
|
||||
readonly updated: ISyncExtension[];
|
||||
readonly remote: ISyncExtension[] | null;
|
||||
readonly remoteUserData: IRemoteUserData;
|
||||
readonly skippedExtensions: ISyncExtension[];
|
||||
readonly lastSyncUserData: ILastSyncUserData | null;
|
||||
}
|
||||
|
||||
interface ILastSyncUserData extends IRemoteUserData {
|
||||
@@ -34,7 +36,7 @@ interface ILastSyncUserData extends IRemoteUserData {
|
||||
export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
|
||||
|
||||
readonly resourceKey: ResourceKey = 'extensions';
|
||||
protected readonly version: number = 1;
|
||||
protected readonly version: number = 2;
|
||||
|
||||
constructor(
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@@ -75,9 +77,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
|
||||
if (remoteUserData.syncData !== null) {
|
||||
const localExtensions = await this.getLocalExtensions();
|
||||
const remoteExtensions: ISyncExtension[] = JSON.parse(remoteUserData.syncData.content);
|
||||
const { added, updated, remote } = merge(localExtensions, remoteExtensions, [], [], this.getIgnoredExtensions());
|
||||
await this.apply({ added, removed: [], updated, remote, remoteUserData, skippedExtensions: [], lastSyncUserData });
|
||||
const remoteExtensions = this.parseExtensions(remoteUserData.syncData);
|
||||
const { added, updated, remote, removed } = merge(localExtensions, remoteExtensions, localExtensions, [], this.getIgnoredExtensions());
|
||||
await this.apply({ added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData });
|
||||
}
|
||||
|
||||
// No remote exists to pull
|
||||
@@ -107,7 +109,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
const { added, removed, updated, remote } = merge(localExtensions, null, null, [], this.getIgnoredExtensions());
|
||||
const lastSyncUserData = await this.getLastSyncUserData<ILastSyncUserData>();
|
||||
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
||||
await this.apply({ added, removed, updated, remote, remoteUserData, skippedExtensions: [], lastSyncUserData }, true);
|
||||
await this.apply({ added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData }, true);
|
||||
|
||||
this.logService.info('Extensions: Finished pushing extensions.');
|
||||
} finally {
|
||||
@@ -165,8 +167,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
}
|
||||
|
||||
private async getPreview(remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<ISyncPreviewResult> {
|
||||
const remoteExtensions: ISyncExtension[] = remoteUserData.syncData ? JSON.parse(remoteUserData.syncData.content) : null;
|
||||
const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData ? JSON.parse(lastSyncUserData.syncData!.content) : null;
|
||||
const remoteExtensions: ISyncExtension[] | null = remoteUserData.syncData ? this.parseExtensions(remoteUserData.syncData) : null;
|
||||
const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData ? this.parseExtensions(lastSyncUserData.syncData!) : null;
|
||||
const skippedExtensions: ISyncExtension[] = lastSyncUserData ? lastSyncUserData.skippedExtensions || [] : [];
|
||||
|
||||
const localExtensions = await this.getLocalExtensions();
|
||||
@@ -179,14 +181,14 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
|
||||
const { added, removed, updated, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, this.getIgnoredExtensions());
|
||||
|
||||
return { added, removed, updated, remote, skippedExtensions, remoteUserData, lastSyncUserData };
|
||||
return { added, removed, updated, remote, skippedExtensions, remoteUserData, localExtensions, lastSyncUserData };
|
||||
}
|
||||
|
||||
private getIgnoredExtensions() {
|
||||
return this.configurationService.getValue<string[]>('sync.ignoredExtensions') || [];
|
||||
}
|
||||
|
||||
private async apply({ added, removed, updated, remote, remoteUserData, skippedExtensions, lastSyncUserData }: ISyncPreviewResult, forcePush?: boolean): Promise<void> {
|
||||
private async apply({ added, removed, updated, remote, remoteUserData, skippedExtensions, lastSyncUserData, localExtensions }: ISyncPreviewResult, forcePush?: boolean): Promise<void> {
|
||||
|
||||
const hasChanges = added.length || removed.length || updated.length || remote;
|
||||
|
||||
@@ -195,6 +197,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
}
|
||||
|
||||
if (added.length || removed.length || updated.length) {
|
||||
// back up all disabled or market place extensions
|
||||
const backUpExtensions = localExtensions.filter(e => e.disabled || !!e.identifier.uuid);
|
||||
await this.backupLocal(VSBuffer.fromString(JSON.stringify(backUpExtensions)));
|
||||
skippedExtensions = await this.updateLocalExtensions(added, removed, updated, skippedExtensions);
|
||||
}
|
||||
|
||||
@@ -236,14 +241,14 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
|
||||
// Builtin Extension: Sync only enablement state
|
||||
if (installedExtension && installedExtension.type === ExtensionType.System) {
|
||||
if (e.enabled) {
|
||||
this.logService.trace('Extensions: Enabling extension...', e.identifier.id);
|
||||
await this.extensionEnablementService.enableExtension(e.identifier);
|
||||
this.logService.info('Extensions: Enabled extension', e.identifier.id);
|
||||
} else {
|
||||
if (e.disabled) {
|
||||
this.logService.trace('Extensions: Disabling extension...', e.identifier.id);
|
||||
await this.extensionEnablementService.disableExtension(e.identifier);
|
||||
this.logService.info('Extensions: Disabled extension', e.identifier.id);
|
||||
} else {
|
||||
this.logService.trace('Extensions: Enabling extension...', e.identifier.id);
|
||||
await this.extensionEnablementService.enableExtension(e.identifier);
|
||||
this.logService.info('Extensions: Enabled extension', e.identifier.id);
|
||||
}
|
||||
removeFromSkipped.push(e.identifier);
|
||||
return;
|
||||
@@ -252,14 +257,14 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
const extension = await this.extensionGalleryService.getCompatibleExtension(e.identifier, e.version);
|
||||
if (extension) {
|
||||
try {
|
||||
if (e.enabled) {
|
||||
this.logService.trace('Extensions: Enabling extension...', e.identifier.id, extension.version);
|
||||
await this.extensionEnablementService.enableExtension(extension.identifier);
|
||||
this.logService.info('Extensions: Enabled extension', e.identifier.id, extension.version);
|
||||
} else {
|
||||
if (e.disabled) {
|
||||
this.logService.trace('Extensions: Disabling extension...', e.identifier.id, extension.version);
|
||||
await this.extensionEnablementService.disableExtension(extension.identifier);
|
||||
this.logService.info('Extensions: Disabled extension', e.identifier.id, extension.version);
|
||||
} else {
|
||||
this.logService.trace('Extensions: Enabling extension...', e.identifier.id, extension.version);
|
||||
await this.extensionEnablementService.enableExtension(extension.identifier);
|
||||
this.logService.info('Extensions: Enabled extension', e.identifier.id, extension.version);
|
||||
}
|
||||
// Install only if the extension does not exist
|
||||
if (!installedExtension || installedExtension.manifest.version !== extension.version) {
|
||||
@@ -293,11 +298,33 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
|
||||
return newSkippedExtensions;
|
||||
}
|
||||
|
||||
private parseExtensions(syncData: ISyncData): ISyncExtension[] {
|
||||
let extensions: ISyncExtension[] = JSON.parse(syncData.content);
|
||||
if (syncData.version !== this.version) {
|
||||
extensions = extensions.map(e => {
|
||||
// #region Migration from v1 (enabled -> disabled)
|
||||
if (!(<any>e).enabled) {
|
||||
e.disabled = true;
|
||||
}
|
||||
delete (<any>e).enabled;
|
||||
// #endregion
|
||||
return e;
|
||||
});
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
private async getLocalExtensions(): Promise<ISyncExtension[]> {
|
||||
const installedExtensions = await this.extensionManagementService.getInstalled();
|
||||
const disabledExtensions = await this.extensionEnablementService.getDisabledExtensions();
|
||||
const disabledExtensions = this.extensionEnablementService.getDisabledExtensions();
|
||||
return installedExtensions
|
||||
.map(({ identifier }) => ({ identifier, enabled: !disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier)) }));
|
||||
.map(({ identifier }) => {
|
||||
const syncExntesion: ISyncExtension = { identifier };
|
||||
if (disabledExtensions.some(disabledExtension => areSameExtensions(disabledExtension, identifier))) {
|
||||
syncExntesion.disabled = true;
|
||||
}
|
||||
return syncExntesion;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ const argvProperties: string[] = ['locale'];
|
||||
interface ISyncPreviewResult {
|
||||
readonly local: IGlobalState | undefined;
|
||||
readonly remote: IGlobalState | undefined;
|
||||
readonly localUserData: IGlobalState;
|
||||
readonly remoteUserData: IRemoteUserData;
|
||||
readonly lastSyncUserData: IRemoteUserData | null;
|
||||
}
|
||||
@@ -59,8 +60,9 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
||||
|
||||
if (remoteUserData.syncData !== null) {
|
||||
const localUserData = await this.getLocalGlobalState();
|
||||
const local: IGlobalState = JSON.parse(remoteUserData.syncData.content);
|
||||
await this.apply({ local, remote: undefined, remoteUserData, lastSyncUserData });
|
||||
await this.apply({ local, remote: undefined, remoteUserData, localUserData, lastSyncUserData });
|
||||
}
|
||||
|
||||
// No remote exists to pull
|
||||
@@ -86,10 +88,10 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
this.logService.info('UI State: Started pushing UI State...');
|
||||
this.setStatus(SyncStatus.Syncing);
|
||||
|
||||
const remote = await this.getLocalGlobalState();
|
||||
const localUserData = await this.getLocalGlobalState();
|
||||
const lastSyncUserData = await this.getLastSyncUserData();
|
||||
const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
|
||||
await this.apply({ local: undefined, remote, remoteUserData, lastSyncUserData }, true);
|
||||
await this.apply({ local: undefined, remote: localUserData, remoteUserData, localUserData, lastSyncUserData }, true);
|
||||
|
||||
this.logService.info('UI State: Finished pushing UI State.');
|
||||
} finally {
|
||||
@@ -152,10 +154,10 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
|
||||
const { local, remote } = merge(localGloablState, remoteGlobalState, lastSyncGlobalState);
|
||||
|
||||
return { local, remote, remoteUserData, lastSyncUserData };
|
||||
return { local, remote, remoteUserData, localUserData: localGloablState, lastSyncUserData };
|
||||
}
|
||||
|
||||
private async apply({ local, remote, remoteUserData, lastSyncUserData }: ISyncPreviewResult, forcePush?: boolean): Promise<void> {
|
||||
private async apply({ local, remote, remoteUserData, lastSyncUserData, localUserData }: ISyncPreviewResult, forcePush?: boolean): Promise<void> {
|
||||
|
||||
const hasChanges = local || remote;
|
||||
|
||||
@@ -166,6 +168,7 @@ export class GlobalStateSynchroniser extends AbstractSynchroniser implements IUs
|
||||
if (local) {
|
||||
// update local
|
||||
this.logService.trace('UI State: Updating local ui state...');
|
||||
await this.backupLocal(VSBuffer.fromString(JSON.stringify(localUserData)));
|
||||
await this.writeLocalGlobalState(local);
|
||||
this.logService.info('UI State: Updated local ui state');
|
||||
}
|
||||
|
||||
@@ -260,9 +260,7 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
||||
|
||||
if (content !== null) {
|
||||
|
||||
if (this.hasErrors(content)) {
|
||||
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
|
||||
}
|
||||
this.validateContent(content);
|
||||
|
||||
if (hasLocalChanged) {
|
||||
this.logService.trace('Settings: Updating local settings...');
|
||||
@@ -317,21 +315,14 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
||||
|
||||
if (remoteSettingsSyncContent) {
|
||||
const localContent: string = fileContent ? fileContent.value.toString() : '{}';
|
||||
|
||||
// No action when there are errors
|
||||
if (this.hasErrors(localContent)) {
|
||||
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
|
||||
}
|
||||
|
||||
else {
|
||||
this.logService.trace('Settings: Merging remote settings with local settings...');
|
||||
const result = merge(localContent, remoteSettingsSyncContent.settings, lastSettingsSyncContent ? lastSettingsSyncContent.settings : null, getIgnoredSettings(this.configurationService), resolvedConflicts, formattingOptions);
|
||||
content = result.localContent || result.remoteContent;
|
||||
hasLocalChanged = result.localContent !== null;
|
||||
hasRemoteChanged = result.remoteContent !== null;
|
||||
hasConflicts = result.hasConflicts;
|
||||
conflictSettings = result.conflictsSettings;
|
||||
}
|
||||
this.validateContent(localContent);
|
||||
this.logService.trace('Settings: Merging remote settings with local settings...');
|
||||
const result = merge(localContent, remoteSettingsSyncContent.settings, lastSettingsSyncContent ? lastSettingsSyncContent.settings : null, getIgnoredSettings(this.configurationService), resolvedConflicts, formattingOptions);
|
||||
content = result.localContent || result.remoteContent;
|
||||
hasLocalChanged = result.localContent !== null;
|
||||
hasRemoteChanged = result.remoteContent !== null;
|
||||
hasConflicts = result.hasConflicts;
|
||||
conflictSettings = result.conflictsSettings;
|
||||
}
|
||||
|
||||
// First time syncing to remote
|
||||
@@ -364,4 +355,10 @@ export class SettingsSynchroniser extends AbstractJsonFileSynchroniser implement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private validateContent(content: string): void {
|
||||
if (this.hasErrors(content)) {
|
||||
throw new UserDataSyncError(localize('errorInvalidSettings', "Unable to sync settings as there are errors/warning in settings file."), UserDataSyncErrorCode.LocalInvalidContent, this.source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
import { timeout, Delayer } from 'vs/base/common/async';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IUserDataSyncLogService, IUserDataSyncService, SyncStatus, IUserDataAuthTokenService, IUserDataAutoSyncService, UserDataSyncError, UserDataSyncErrorCode, SyncSource, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncLogService, IUserDataSyncService, SyncStatus, IUserDataAutoSyncService, UserDataSyncError, UserDataSyncErrorCode, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||
|
||||
export class UserDataAutoSyncService extends Disposable implements IUserDataAutoSyncService {
|
||||
|
||||
@@ -16,19 +17,19 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto
|
||||
private successiveFailures: number = 0;
|
||||
private readonly syncDelayer: Delayer<void>;
|
||||
|
||||
private readonly _onError: Emitter<{ code: UserDataSyncErrorCode, source?: SyncSource }> = this._register(new Emitter<{ code: UserDataSyncErrorCode, source?: SyncSource }>());
|
||||
readonly onError: Event<{ code: UserDataSyncErrorCode, source?: SyncSource }> = this._onError.event;
|
||||
private readonly _onError: Emitter<UserDataSyncError> = this._register(new Emitter<UserDataSyncError>());
|
||||
readonly onError: Event<UserDataSyncError> = this._onError.event;
|
||||
|
||||
constructor(
|
||||
@IUserDataSyncEnablementService private readonly userDataSyncEnablementService: IUserDataSyncEnablementService,
|
||||
@IUserDataSyncService private readonly userDataSyncService: IUserDataSyncService,
|
||||
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
|
||||
@IUserDataAuthTokenService private readonly userDataAuthTokenService: IUserDataAuthTokenService,
|
||||
@IAuthenticationTokenService private readonly authTokenService: IAuthenticationTokenService,
|
||||
) {
|
||||
super();
|
||||
this.updateEnablement(false, true);
|
||||
this.syncDelayer = this._register(new Delayer<void>(0));
|
||||
this._register(Event.any<any>(userDataAuthTokenService.onDidChangeToken)(() => this.updateEnablement(true, true)));
|
||||
this._register(Event.any<any>(authTokenService.onDidChangeToken)(() => this.updateEnablement(true, true)));
|
||||
this._register(Event.any<any>(userDataSyncService.onDidChangeStatus)(() => this.updateEnablement(true, true)));
|
||||
this._register(this.userDataSyncEnablementService.onDidChangeEnablement(() => this.updateEnablement(true, false)));
|
||||
this._register(this.userDataSyncEnablementService.onDidChangeResourceEnablement(() => this.triggerAutoSync()));
|
||||
@@ -61,27 +62,23 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto
|
||||
await this.userDataSyncService.sync();
|
||||
this.resetFailures();
|
||||
} catch (e) {
|
||||
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.TurnedOff) {
|
||||
const error = UserDataSyncError.toUserDataSyncError(e);
|
||||
if (error.code === UserDataSyncErrorCode.TurnedOff || error.code === UserDataSyncErrorCode.SessionExpired) {
|
||||
this.logService.info('Auto Sync: Sync is turned off in the cloud.');
|
||||
this.logService.info('Auto Sync: Resetting the local sync state.');
|
||||
await this.userDataSyncService.resetLocal();
|
||||
this.logService.info('Auto Sync: Completed resetting the local sync state.');
|
||||
if (auto) {
|
||||
return this.userDataSyncEnablementService.setEnablement(false);
|
||||
this.userDataSyncEnablementService.setEnablement(false);
|
||||
this._onError.fire(error);
|
||||
return;
|
||||
} else {
|
||||
return this.sync(loop, auto);
|
||||
}
|
||||
}
|
||||
if (e instanceof UserDataSyncError && e.code === UserDataSyncErrorCode.SessionExpired) {
|
||||
this.logService.info('Auto Sync: Cloud has new session');
|
||||
this.logService.info('Auto Sync: Resetting the local sync state.');
|
||||
await this.userDataSyncService.resetLocal();
|
||||
this.logService.info('Auto Sync: Completed resetting the local sync state.');
|
||||
return this.sync(loop, auto);
|
||||
}
|
||||
this.logService.error(e);
|
||||
this.logService.error(error);
|
||||
this.successiveFailures++;
|
||||
this._onError.fire(e instanceof UserDataSyncError ? { code: e.code, source: e.source } : { code: UserDataSyncErrorCode.Unknown });
|
||||
this._onError.fire(error);
|
||||
}
|
||||
if (loop) {
|
||||
await timeout(1000 * 60 * 5);
|
||||
@@ -95,7 +92,7 @@ export class UserDataAutoSyncService extends Disposable implements IUserDataAuto
|
||||
private async isAutoSyncEnabled(): Promise<boolean> {
|
||||
return this.userDataSyncEnablementService.isEnabled()
|
||||
&& this.userDataSyncService.status !== SyncStatus.Uninitialized
|
||||
&& !!(await this.userDataAuthTokenService.getToken());
|
||||
&& !!(await this.authTokenService.getToken());
|
||||
}
|
||||
|
||||
private resetFailures(): void {
|
||||
|
||||
@@ -38,6 +38,7 @@ export interface ISyncConfiguration {
|
||||
|
||||
export function registerConfiguration(): IDisposable {
|
||||
const ignoredSettingsSchemaId = 'vscode://schemas/ignoredSettings';
|
||||
const ignoredExtensionsSchemaId = 'vscode://schemas/ignoredExtensions';
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||
configurationRegistry.registerConfiguration({
|
||||
id: 'sync',
|
||||
@@ -84,14 +85,11 @@ export function registerConfiguration(): IDisposable {
|
||||
'sync.ignoredExtensions': {
|
||||
'type': 'array',
|
||||
'description': localize('sync.ignoredExtensions', "List of extensions to be ignored while synchronizing. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp."),
|
||||
items: {
|
||||
type: 'string',
|
||||
pattern: EXTENSION_IDENTIFIER_PATTERN,
|
||||
errorMessage: localize('app.extension.identifier.errorMessage', "Expected format '${publisher}.${name}'. Example: 'vscode.csharp'.")
|
||||
},
|
||||
$ref: ignoredExtensionsSchemaId,
|
||||
'default': [],
|
||||
'scope': ConfigurationScope.APPLICATION,
|
||||
uniqueItems: true
|
||||
uniqueItems: true,
|
||||
disallowSyncIgnore: true
|
||||
},
|
||||
'sync.ignoredSettings': {
|
||||
'type': 'array',
|
||||
@@ -100,12 +98,13 @@ export function registerConfiguration(): IDisposable {
|
||||
'scope': ConfigurationScope.APPLICATION,
|
||||
$ref: ignoredSettingsSchemaId,
|
||||
additionalProperties: true,
|
||||
uniqueItems: true
|
||||
uniqueItems: true,
|
||||
disallowSyncIgnore: true
|
||||
}
|
||||
}
|
||||
});
|
||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||
const registerIgnoredSettingsSchema = () => {
|
||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||
const ignoredSettingsSchema: IJSONSchema = {
|
||||
items: {
|
||||
type: 'string',
|
||||
@@ -114,6 +113,11 @@ export function registerConfiguration(): IDisposable {
|
||||
};
|
||||
jsonRegistry.registerSchema(ignoredSettingsSchemaId, ignoredSettingsSchema);
|
||||
};
|
||||
jsonRegistry.registerSchema(ignoredExtensionsSchemaId, {
|
||||
type: 'string',
|
||||
pattern: EXTENSION_IDENTIFIER_PATTERN,
|
||||
errorMessage: localize('app.extension.identifier.errorMessage', "Expected format '${publisher}.${name}'. Example: 'vscode.csharp'.")
|
||||
});
|
||||
return configurationRegistry.onDidUpdateConfiguration(() => registerIgnoredSettingsSchema());
|
||||
}
|
||||
|
||||
@@ -210,7 +214,7 @@ export class UserDataSyncStoreError extends UserDataSyncError { }
|
||||
export interface ISyncExtension {
|
||||
identifier: IExtensionIdentifier;
|
||||
version?: string;
|
||||
enabled: boolean;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export interface IGlobalState {
|
||||
@@ -283,6 +287,9 @@ export interface IUserDataSyncService {
|
||||
|
||||
readonly onDidChangeLocal: Event<void>;
|
||||
|
||||
readonly lastSyncTime: number | undefined;
|
||||
readonly onDidChangeLastSyncTime: Event<number>;
|
||||
|
||||
pull(): Promise<void>;
|
||||
sync(): Promise<void>;
|
||||
stop(): Promise<void>;
|
||||
@@ -297,7 +304,7 @@ export interface IUserDataSyncService {
|
||||
export const IUserDataAutoSyncService = createDecorator<IUserDataAutoSyncService>('IUserDataAutoSyncService');
|
||||
export interface IUserDataAutoSyncService {
|
||||
_serviceBrand: any;
|
||||
readonly onError: Event<{ code: UserDataSyncErrorCode, source?: SyncSource }>;
|
||||
readonly onError: Event<UserDataSyncError>;
|
||||
triggerAutoSync(): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -308,19 +315,6 @@ export interface IUserDataSyncUtilService {
|
||||
resolveFormattingOptions(resource: URI): Promise<FormattingOptions>;
|
||||
}
|
||||
|
||||
export const IUserDataAuthTokenService = createDecorator<IUserDataAuthTokenService>('IUserDataAuthTokenService');
|
||||
|
||||
export interface IUserDataAuthTokenService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
readonly onDidChangeToken: Event<string | undefined>;
|
||||
readonly onTokenFailed: Event<void>;
|
||||
|
||||
getToken(): Promise<string | undefined>;
|
||||
setToken(accessToken: string | undefined): Promise<void>;
|
||||
sendTokenFailed(): void;
|
||||
}
|
||||
|
||||
export const IUserDataSyncLogService = createDecorator<IUserDataSyncLogService>('IUserDataSyncLogService');
|
||||
export interface IUserDataSyncLogService extends ILogService { }
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { IServerChannel, IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IUserDataSyncService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAuthTokenService, IUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
|
||||
@@ -19,13 +19,14 @@ export class UserDataSyncChannel implements IServerChannel {
|
||||
case 'onDidChangeStatus': return this.service.onDidChangeStatus;
|
||||
case 'onDidChangeConflicts': return this.service.onDidChangeConflicts;
|
||||
case 'onDidChangeLocal': return this.service.onDidChangeLocal;
|
||||
case 'onDidChangeLastSyncTime': return this.service.onDidChangeLastSyncTime;
|
||||
}
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
||||
call(context: any, command: string, args?: any): Promise<any> {
|
||||
switch (command) {
|
||||
case '_getInitialData': return Promise.resolve([this.service.status, this.service.conflictsSources]);
|
||||
case '_getInitialData': return Promise.resolve([this.service.status, this.service.conflictsSources, this.service.lastSyncTime]);
|
||||
case 'sync': return this.service.sync();
|
||||
case 'accept': return this.service.accept(args[0], args[1]);
|
||||
case 'pull': return this.service.pull();
|
||||
@@ -90,26 +91,6 @@ export class UserDataAutoSyncChannel implements IServerChannel {
|
||||
}
|
||||
}
|
||||
|
||||
export class UserDataAuthTokenServiceChannel implements IServerChannel {
|
||||
constructor(private readonly service: IUserDataAuthTokenService) { }
|
||||
|
||||
listen(_: unknown, event: string): Event<any> {
|
||||
switch (event) {
|
||||
case 'onDidChangeToken': return this.service.onDidChangeToken;
|
||||
case 'onTokenFailed': return this.service.onTokenFailed;
|
||||
}
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
||||
call(context: any, command: string, args?: any): Promise<any> {
|
||||
switch (command) {
|
||||
case 'setToken': return this.service.setToken(args);
|
||||
case 'getToken': return this.service.getToken();
|
||||
}
|
||||
throw new Error('Invalid call');
|
||||
}
|
||||
}
|
||||
|
||||
export class UserDataSycnUtilServiceChannel implements IServerChannel {
|
||||
|
||||
constructor(private readonly service: IUserDataSyncUtilService) { }
|
||||
|
||||
@@ -21,6 +21,7 @@ type SyncErrorClassification = {
|
||||
};
|
||||
|
||||
const SESSION_ID_KEY = 'sync.sessionId';
|
||||
const LAST_SYNC_TIME_KEY = 'sync.lastSyncTime';
|
||||
|
||||
export class UserDataSyncService extends Disposable implements IUserDataSyncService {
|
||||
|
||||
@@ -40,6 +41,11 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
private _onDidChangeConflicts: Emitter<SyncSource[]> = this._register(new Emitter<SyncSource[]>());
|
||||
readonly onDidChangeConflicts: Event<SyncSource[]> = this._onDidChangeConflicts.event;
|
||||
|
||||
private _lastSyncTime: number | undefined = undefined;
|
||||
get lastSyncTime(): number | undefined { return this._lastSyncTime; }
|
||||
private _onDidChangeLastSyncTime: Emitter<number> = this._register(new Emitter<number>());
|
||||
readonly onDidChangeLastSyncTime: Event<number> = this._onDidChangeLastSyncTime.event;
|
||||
|
||||
private readonly keybindingsSynchroniser: KeybindingsSynchroniser;
|
||||
private readonly extensionsSynchroniser: ExtensionsSynchroniser;
|
||||
private readonly globalStateSynchroniser: GlobalStateSynchroniser;
|
||||
@@ -63,6 +69,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
this._register(Event.any(...this.synchronisers.map(s => Event.map(s.onDidChangeStatus, () => undefined)))(() => this.updateStatus()));
|
||||
}
|
||||
|
||||
this._lastSyncTime = this.storageService.getNumber(LAST_SYNC_TIME_KEY, StorageScope.GLOBAL, undefined);
|
||||
this.onDidChangeLocal = Event.any(...this.synchronisers.map(s => s.onDidChangeLocal));
|
||||
}
|
||||
|
||||
@@ -156,7 +163,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
async accept(source: SyncSource, content: string): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
const synchroniser = this.getSynchroniser(source);
|
||||
return synchroniser.accept(content);
|
||||
await synchroniser.accept(content);
|
||||
}
|
||||
|
||||
async getRemoteContent(source: SyncSource, preview: boolean): Promise<string | null> {
|
||||
@@ -189,6 +196,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
async resetLocal(): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
this.storageService.remove(SESSION_ID_KEY, StorageScope.GLOBAL);
|
||||
this.storageService.remove(LAST_SYNC_TIME_KEY, StorageScope.GLOBAL);
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
try {
|
||||
synchroniser.resetLocal();
|
||||
@@ -227,9 +235,13 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
}
|
||||
|
||||
private setStatus(status: SyncStatus): void {
|
||||
const oldStatus = this._status;
|
||||
if (this._status !== status) {
|
||||
this._status = status;
|
||||
this._onDidChangeStatus.fire(status);
|
||||
if (oldStatus !== SyncStatus.Uninitialized && this.status === SyncStatus.Idle) {
|
||||
this.updateLastSyncTime(new Date().getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,6 +268,14 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
return SyncStatus.Idle;
|
||||
}
|
||||
|
||||
private updateLastSyncTime(lastSyncTime: number): void {
|
||||
if (this._lastSyncTime !== lastSyncTime) {
|
||||
this._lastSyncTime = lastSyncTime;
|
||||
this.storageService.store(LAST_SYNC_TIME_KEY, lastSyncTime, StorageScope.GLOBAL);
|
||||
this._onDidChangeLastSyncTime.fire(lastSyncTime);
|
||||
}
|
||||
}
|
||||
|
||||
private handleSyncError(e: Error, source: SyncSource): void {
|
||||
if (e instanceof UserDataSyncStoreError) {
|
||||
switch (e.code) {
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, } from 'vs/base/common/lifecycle';
|
||||
import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, getUserDataSyncStore, IUserDataAuthTokenService, SyncSource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IUserData, IUserDataSyncStoreService, UserDataSyncErrorCode, IUserDataSyncStore, getUserDataSyncStore, SyncSource, UserDataSyncStoreError, IUserDataSyncLogService, IUserDataManifest } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IRequestService, asText, isSuccess, asJson } from 'vs/platform/request/common/request';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IHeaders, IRequestOptions, IRequestContext } from 'vs/base/parts/request/common/request';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||
|
||||
export class UserDataSyncStoreService extends Disposable implements IUserDataSyncStoreService {
|
||||
|
||||
@@ -20,7 +21,7 @@ export class UserDataSyncStoreService extends Disposable implements IUserDataSyn
|
||||
constructor(
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IRequestService private readonly requestService: IRequestService,
|
||||
@IUserDataAuthTokenService private readonly authTokenService: IUserDataAuthTokenService,
|
||||
@IAuthenticationTokenService private readonly authTokenService: IAuthenticationTokenService,
|
||||
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IUserDataSyncService, IUserDataSyncLogService, IUserDataAuthTokenService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IUserDataSyncService, IUserDataSyncLogService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { UserDataAutoSyncService as BaseUserDataAutoSyncService } from 'vs/platform/userDataSync/common/userDataAutoSyncService';
|
||||
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||
|
||||
export class UserDataAutoSyncService extends BaseUserDataAutoSyncService {
|
||||
|
||||
@@ -15,7 +16,7 @@ export class UserDataAutoSyncService extends BaseUserDataAutoSyncService {
|
||||
@IUserDataSyncService userDataSyncService: IUserDataSyncService,
|
||||
@IElectronService electronService: IElectronService,
|
||||
@IUserDataSyncLogService logService: IUserDataSyncLogService,
|
||||
@IUserDataAuthTokenService authTokenService: IUserDataAuthTokenService,
|
||||
@IAuthenticationTokenService authTokenService: IAuthenticationTokenService,
|
||||
) {
|
||||
super(userDataSyncEnablementService, userDataSyncService, logService, authTokenService);
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge returns local extension if remote does not exist', async () => {
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, null, null, [], []);
|
||||
@@ -26,13 +26,13 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge returns local extension if remote does not exist with ignored extensions', async () => {
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, null, null, [], ['a']);
|
||||
@@ -45,13 +45,13 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge returns local extension if remote does not exist with ignored extensions (ignore case)', async () => {
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, null, null, [], ['A']);
|
||||
@@ -64,17 +64,17 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge returns local extension if remote does not exist with skipped extensions', async () => {
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const skippedExtension: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, null, null, skippedExtension, []);
|
||||
@@ -87,16 +87,16 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge returns local extension if remote does not exist with skipped and ignored extensions', async () => {
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const skippedExtension: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, null, null, skippedExtension, ['a']);
|
||||
@@ -109,23 +109,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when there is no base', async () => {
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, null, [], []);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||
assert.deepEqual(actual.removed, []);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.deepEqual(actual.remote, expected);
|
||||
@@ -133,22 +133,22 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when there is no base and with ignored extensions', async () => {
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, null, [], ['a']);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||
assert.deepEqual(actual.removed, []);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.deepEqual(actual.remote, expected);
|
||||
@@ -156,43 +156,66 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when remote is moved forwarded', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||
assert.deepEqual(actual.removed, [{ id: 'a', uuid: 'a' }, { id: 'd', uuid: 'd' }]);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.equal(actual.remote, null);
|
||||
});
|
||||
|
||||
test('merge local and remote extensions when remote moved forwarded with ignored extensions', async () => {
|
||||
test('merge local and remote extensions when remote is moved forwarded with disabled extension', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, disabled: true },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||
assert.deepEqual(actual.removed, [{ id: 'a', uuid: 'a' }]);
|
||||
assert.deepEqual(actual.updated, [{ identifier: { id: 'd', uuid: 'd' }, disabled: true }]);
|
||||
assert.equal(actual.remote, null);
|
||||
});
|
||||
|
||||
test('merge local and remote extensions when remote moved forwarded with ignored extensions', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a']);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||
assert.deepEqual(actual.removed, [{ id: 'd', uuid: 'd' }]);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.equal(actual.remote, null);
|
||||
@@ -200,23 +223,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when remote is moved forwarded with skipped extensions', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const skippedExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' }, enabled: true }, { identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'b', uuid: 'b' } }, { identifier: { id: 'c', uuid: 'c' } }]);
|
||||
assert.deepEqual(actual.removed, [{ id: 'd', uuid: 'd' }]);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.equal(actual.remote, null);
|
||||
@@ -224,23 +247,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when remote is moved forwarded with skipped and ignored extensions', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const skippedExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['b']);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'c', uuid: 'c' }, enabled: true }]);
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'c', uuid: 'c' } }]);
|
||||
assert.deepEqual(actual.removed, [{ id: 'd', uuid: 'd' }]);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.equal(actual.remote, null);
|
||||
@@ -248,16 +271,39 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when local is moved forwarded', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||
|
||||
assert.deepEqual(actual.added, []);
|
||||
assert.deepEqual(actual.removed, []);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.deepEqual(actual.remote, localExtensions);
|
||||
});
|
||||
|
||||
test('merge local and remote extensions when local is moved forwarded with disabled extensions', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, disabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||
@@ -270,16 +316,16 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when local is moved forwarded with ignored settings', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['b']);
|
||||
@@ -288,30 +334,30 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
assert.deepEqual(actual.removed, []);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.deepEqual(actual.remote, [
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
]);
|
||||
});
|
||||
|
||||
test('merge local and remote extensions when local is moved forwarded with skipped extensions', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const skippedExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []);
|
||||
@@ -324,23 +370,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when local is moved forwarded with skipped and ignored extensions', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const skippedExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['c']);
|
||||
@@ -353,28 +399,28 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when both moved forwarded', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'e', uuid: 'e' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'e', uuid: 'e' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], []);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'e', uuid: 'e' }, enabled: true }]);
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'e', uuid: 'e' } }]);
|
||||
assert.deepEqual(actual.removed, [{ id: 'a', uuid: 'a' }]);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.deepEqual(actual.remote, expected);
|
||||
@@ -382,23 +428,23 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when both moved forwarded with ignored extensions', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'e', uuid: 'e' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'e', uuid: 'e' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, [], ['a', 'e']);
|
||||
@@ -411,30 +457,30 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when both moved forwarded with skipped extensions', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const skippedExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'e', uuid: 'e' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'e', uuid: 'e' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, []);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'e', uuid: 'e' }, enabled: true }]);
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'e', uuid: 'e' } }]);
|
||||
assert.deepEqual(actual.removed, []);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.deepEqual(actual.remote, expected);
|
||||
@@ -442,25 +488,25 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge local and remote extensions when both moved forwarded with skipped and ignoredextensions', async () => {
|
||||
const baseExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const skippedExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
];
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'e', uuid: 'e' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'e', uuid: 'e' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'e', uuid: 'e' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, baseExtensions, skippedExtensions, ['e']);
|
||||
@@ -473,24 +519,24 @@ suite('ExtensionsMerge - No Conflicts', () => {
|
||||
|
||||
test('merge when remote extension has no uuid and different extension id case', async () => {
|
||||
const localExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'a', uuid: 'a' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'a', uuid: 'a' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
const remoteExtensions: ISyncExtension[] = [
|
||||
{ identifier: { id: 'A' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'A' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
];
|
||||
const expected: ISyncExtension[] = [
|
||||
{ identifier: { id: 'A' }, enabled: true },
|
||||
{ identifier: { id: 'd', uuid: 'd' }, enabled: true },
|
||||
{ identifier: { id: 'b', uuid: 'b' }, enabled: true },
|
||||
{ identifier: { id: 'c', uuid: 'c' }, enabled: true },
|
||||
{ identifier: { id: 'A', uuid: 'a' } },
|
||||
{ identifier: { id: 'd', uuid: 'd' } },
|
||||
{ identifier: { id: 'b', uuid: 'b' } },
|
||||
{ identifier: { id: 'c', uuid: 'c' } },
|
||||
];
|
||||
|
||||
const actual = merge(localExtensions, remoteExtensions, null, [], []);
|
||||
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'd', uuid: 'd' }, enabled: true }]);
|
||||
assert.deepEqual(actual.added, [{ identifier: { id: 'd', uuid: 'd' } }]);
|
||||
assert.deepEqual(actual.removed, []);
|
||||
assert.deepEqual(actual.updated, []);
|
||||
assert.deepEqual(actual.remote, expected);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { IRequestOptions, IRequestContext, IHeaders } from 'vs/base/parts/request/common/request';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IUserData, ResourceKey, IUserDataManifest, ALL_RESOURCE_KEYS, IUserDataAuthTokenService, IUserDataSyncLogService, IUserDataSyncStoreService, IUserDataSyncUtilService, IUserDataSyncEnablementService, ISettingsSyncService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IUserData, ResourceKey, IUserDataManifest, ALL_RESOURCE_KEYS, IUserDataSyncLogService, IUserDataSyncStoreService, IUserDataSyncUtilService, IUserDataSyncEnablementService, ISettingsSyncService, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { bufferToStream, VSBuffer } from 'vs/base/common/buffer';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
|
||||
@@ -33,6 +33,7 @@ import { ConfigurationService } from 'vs/platform/configuration/common/configura
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IAuthenticationTokenService } from 'vs/platform/authentication/common/authentication';
|
||||
|
||||
export class UserDataSyncClient extends Disposable {
|
||||
|
||||
@@ -76,7 +77,7 @@ export class UserDataSyncClient extends Disposable {
|
||||
this.instantiationService.stub(IConfigurationService, configurationService);
|
||||
|
||||
this.instantiationService.stub(IRequestService, this.testServer);
|
||||
this.instantiationService.stub(IUserDataAuthTokenService, <Partial<IUserDataAuthTokenService>>{
|
||||
this.instantiationService.stub(IAuthenticationTokenService, <Partial<IAuthenticationTokenService>>{
|
||||
onDidChangeToken: new Emitter<string | undefined>().event,
|
||||
async getToken() { return 'token'; }
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
suite('UserDataSyncService', () => {
|
||||
suite.skip('UserDataSyncService', () => { // {{SQL CARBON EDIT}} skip failing tests
|
||||
|
||||
const disposableStore = new DisposableStore();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user