mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-15 10:58:31 -05:00
Merge from vscode 1b314ab317fbff7d799b21754326b7d849889ceb
This commit is contained in:
@@ -3,7 +3,10 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IUserDataSyncService, SyncStatus, IUserDataSyncStoreService, SyncResource, IUserDataSyncLogService, IUserDataSynchroniser, UserDataSyncErrorCode, UserDataSyncError, SyncResourceConflicts, ISyncResourceHandle, IUserDataManifest, ISyncTask } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import {
|
||||
IUserDataSyncService, SyncStatus, IUserDataSyncStoreService, SyncResource, IUserDataSyncLogService, IUserDataSynchroniser, UserDataSyncErrorCode,
|
||||
UserDataSyncError, ISyncResourceHandle, IUserDataManifest, ISyncTask, IResourcePreview, IManualSyncTask, ISyncResourcePreview, HEADER_EXECUTION_ID
|
||||
} from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
@@ -21,6 +24,8 @@ import { SnippetsSynchroniser } from 'vs/platform/userDataSync/common/snippetsSy
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IHeaders } from 'vs/base/parts/request/common/request';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { createCancelablePromise, CancelablePromise } from 'vs/base/common/async';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
|
||||
type SyncErrorClassification = {
|
||||
resource?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
|
||||
@@ -29,6 +34,12 @@ type SyncErrorClassification = {
|
||||
|
||||
const LAST_SYNC_TIME_KEY = 'sync.lastSyncTime';
|
||||
|
||||
function createSyncHeaders(executionId: string): IHeaders {
|
||||
const headers: IHeaders = {};
|
||||
headers[HEADER_EXECUTION_ID] = executionId;
|
||||
return headers;
|
||||
}
|
||||
|
||||
export class UserDataSyncService extends Disposable implements IUserDataSyncService {
|
||||
|
||||
_serviceBrand: any;
|
||||
@@ -40,15 +51,12 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
private _onDidChangeStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
|
||||
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangeStatus.event;
|
||||
|
||||
private _onSynchronizeResource: Emitter<SyncResource> = this._register(new Emitter<SyncResource>());
|
||||
readonly onSynchronizeResource: Event<SyncResource> = this._onSynchronizeResource.event;
|
||||
|
||||
readonly onDidChangeLocal: Event<SyncResource>;
|
||||
|
||||
private _conflicts: SyncResourceConflicts[] = [];
|
||||
get conflicts(): SyncResourceConflicts[] { return this._conflicts; }
|
||||
private _onDidChangeConflicts: Emitter<SyncResourceConflicts[]> = this._register(new Emitter<SyncResourceConflicts[]>());
|
||||
readonly onDidChangeConflicts: Event<SyncResourceConflicts[]> = this._onDidChangeConflicts.event;
|
||||
private _conflicts: [SyncResource, IResourcePreview[]][] = [];
|
||||
get conflicts(): [SyncResource, IResourcePreview[]][] { return this._conflicts; }
|
||||
private _onDidChangeConflicts: Emitter<[SyncResource, IResourcePreview[]][]> = this._register(new Emitter<[SyncResource, IResourcePreview[]][]>());
|
||||
readonly onDidChangeConflicts: Event<[SyncResource, IResourcePreview[]][]> = this._onDidChangeConflicts.event;
|
||||
|
||||
private _syncErrors: [SyncResource, UserDataSyncError][] = [];
|
||||
private _onSyncErrors: Emitter<[SyncResource, UserDataSyncError][]> = this._register(new Emitter<[SyncResource, UserDataSyncError][]>());
|
||||
@@ -95,7 +103,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
try {
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
try {
|
||||
this._onSynchronizeResource.fire(synchroniser.resource);
|
||||
await synchroniser.pull();
|
||||
} catch (e) {
|
||||
this.handleSynchronizerError(e, synchroniser.resource);
|
||||
@@ -129,18 +136,13 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
}
|
||||
}
|
||||
|
||||
private recoveredSettings: boolean = false;
|
||||
async sync(): Promise<void> {
|
||||
const syncTask = await this.createSyncTask();
|
||||
return syncTask.run(CancellationToken.None);
|
||||
}
|
||||
|
||||
async createSyncTask(): Promise<ISyncTask> {
|
||||
this.telemetryService.publicLog2('sync/getmanifest');
|
||||
await this.checkEnablement();
|
||||
|
||||
const executionId = generateUuid();
|
||||
let manifest: IUserDataManifest | null;
|
||||
try {
|
||||
manifest = await this.userDataSyncStoreService.manifest({ 'X-Execution-Id': executionId });
|
||||
manifest = await this.userDataSyncStoreService.manifest(createSyncHeaders(executionId));
|
||||
} catch (error) {
|
||||
if (error instanceof UserDataSyncError) {
|
||||
this.telemetryService.publicLog2<{ resource?: string, executionId?: string }, SyncErrorClassification>(`sync/error/${error.code}`, { resource: error.resource, executionId });
|
||||
@@ -150,20 +152,46 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
|
||||
let executed = false;
|
||||
const that = this;
|
||||
let cancellablePromise: CancelablePromise<void> | undefined;
|
||||
return {
|
||||
manifest,
|
||||
run(token: CancellationToken): Promise<void> {
|
||||
run(): Promise<void> {
|
||||
if (executed) {
|
||||
throw new Error('Can run a task only once');
|
||||
}
|
||||
return that.doSync(manifest, executionId, token);
|
||||
cancellablePromise = createCancelablePromise(token => that.sync(manifest, executionId, token));
|
||||
return cancellablePromise.finally(() => cancellablePromise = undefined);
|
||||
},
|
||||
async stop(): Promise<void> {
|
||||
if (cancellablePromise) {
|
||||
cancellablePromise.cancel();
|
||||
return that.stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private async doSync(manifest: IUserDataManifest | null, executionId: string, token: CancellationToken): Promise<void> {
|
||||
async createManualSyncTask(): Promise<IManualSyncTask> {
|
||||
await this.checkEnablement();
|
||||
|
||||
const executionId = generateUuid();
|
||||
const syncHeaders = createSyncHeaders(executionId);
|
||||
|
||||
let manifest: IUserDataManifest | null;
|
||||
try {
|
||||
manifest = await this.userDataSyncStoreService.manifest(syncHeaders);
|
||||
} catch (error) {
|
||||
if (error instanceof UserDataSyncError) {
|
||||
this.telemetryService.publicLog2<{ resource?: string, executionId?: string }, SyncErrorClassification>(`sync/error/${error.code}`, { resource: error.resource, executionId });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
return new ManualSyncTask(executionId, manifest, syncHeaders, this.synchronisers, this.logService);
|
||||
}
|
||||
|
||||
private recoveredSettings: boolean = false;
|
||||
private async sync(manifest: IUserDataManifest | null, executionId: string, token: CancellationToken): Promise<void> {
|
||||
if (!this.recoveredSettings) {
|
||||
await this.settingsSynchroniser.recoverSettings();
|
||||
this.recoveredSettings = true;
|
||||
@@ -182,7 +210,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
this.setStatus(SyncStatus.Syncing);
|
||||
}
|
||||
|
||||
const syncHeaders: IHeaders = { 'X-Execution-Id': executionId };
|
||||
const syncHeaders = createSyncHeaders(executionId);
|
||||
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
// Return if cancellation is requested
|
||||
@@ -190,7 +218,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this._onSynchronizeResource.fire(synchroniser.resource);
|
||||
await synchroniser.sync(manifest, syncHeaders);
|
||||
} catch (e) {
|
||||
this.handleSynchronizerError(e, synchroniser.resource);
|
||||
@@ -211,18 +238,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
}
|
||||
}
|
||||
|
||||
async replace(uri: URI): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
if (await synchroniser.replace(uri)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
|
||||
private async stop(): Promise<void> {
|
||||
if (this.status === SyncStatus.Idle) {
|
||||
return;
|
||||
}
|
||||
@@ -239,15 +255,21 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
|
||||
}
|
||||
|
||||
async acceptConflict(conflict: URI, content: string): Promise<void> {
|
||||
async replace(uri: URI): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
const syncResourceConflict = this.conflicts.filter(({ conflicts }) => conflicts.some(({ local, remote }) => isEqual(conflict, local) || isEqual(conflict, remote)))[0];
|
||||
if (syncResourceConflict) {
|
||||
const synchroniser = this.getSynchroniser(syncResourceConflict.syncResource);
|
||||
await synchroniser.acceptConflict(conflict, content);
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
if (await synchroniser.replace(uri)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async acceptPreviewContent(syncResource: SyncResource, resource: URI, content: string, executionId: string = generateUuid()): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
const synchroniser = this.getSynchroniser(syncResource);
|
||||
await synchroniser.acceptPreviewContent(resource, content, false, createSyncHeaders(executionId));
|
||||
}
|
||||
|
||||
async resolveContent(resource: URI): Promise<string | null> {
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
const content = await synchroniser.resolveContent(resource);
|
||||
@@ -274,35 +296,14 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
return this.getSynchroniser(resource).getMachineId(syncResourceHandle);
|
||||
}
|
||||
|
||||
async isFirstTimeSyncingWithAnotherMachine(): Promise<boolean> {
|
||||
await this.checkEnablement();
|
||||
|
||||
if (!await this.userDataSyncStoreService.manifest()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
async hasLocalData(): Promise<boolean> {
|
||||
// skip global state synchronizer
|
||||
const synchronizers = [this.settingsSynchroniser, this.keybindingsSynchroniser, this.snippetsSynchroniser, this.extensionsSynchroniser];
|
||||
|
||||
let hasLocalData: boolean = false;
|
||||
for (const synchroniser of synchronizers) {
|
||||
if (await synchroniser.hasLocalData()) {
|
||||
hasLocalData = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasLocalData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const synchroniser of synchronizers) {
|
||||
const preview = await synchroniser.generateSyncPreview();
|
||||
if (preview && !preview.isLastSyncFromCurrentMachine && (preview.hasLocalChanged || preview.hasRemoteChanged)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -312,6 +313,16 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
await this.resetLocal();
|
||||
}
|
||||
|
||||
async resetRemote(): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
try {
|
||||
await this.userDataSyncStoreService.clear();
|
||||
this.logService.info('Cleared data on server');
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async resetLocal(): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
this.storageService.remove(LAST_SYNC_TIME_KEY, StorageScope.GLOBAL);
|
||||
@@ -335,16 +346,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
return false;
|
||||
}
|
||||
|
||||
private async resetRemote(): Promise<void> {
|
||||
await this.checkEnablement();
|
||||
try {
|
||||
await this.userDataSyncStoreService.clear();
|
||||
this.logService.info('Cleared data on server');
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private setStatus(status: SyncStatus): void {
|
||||
const oldStatus = this._status;
|
||||
if (this._status !== status) {
|
||||
@@ -364,7 +365,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
|
||||
private updateConflicts(): void {
|
||||
const conflicts = this.computeConflicts();
|
||||
if (!equals(this._conflicts, conflicts, (a, b) => a.syncResource === b.syncResource && equals(a.conflicts, b.conflicts, (a, b) => isEqual(a.local, b.local) && isEqual(a.remote, b.remote)))) {
|
||||
if (!equals(this._conflicts, conflicts, ([syncResourceA, conflictsA], [syncResourceB, conflictsB]) => syncResourceA === syncResourceA && equals(conflictsA, conflictsB, (a, b) => isEqual(a.previewResource, b.previewResource)))) {
|
||||
this._conflicts = this.computeConflicts();
|
||||
this._onDidChangeConflicts.fire(conflicts);
|
||||
}
|
||||
@@ -401,7 +402,8 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
case UserDataSyncErrorCode.LocalTooManyRequests:
|
||||
case UserDataSyncErrorCode.Gone:
|
||||
case UserDataSyncErrorCode.UpgradeRequired:
|
||||
case UserDataSyncErrorCode.Incompatible:
|
||||
case UserDataSyncErrorCode.IncompatibleRemoteContent:
|
||||
case UserDataSyncErrorCode.IncompatibleLocalContent:
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -409,13 +411,13 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
this.logService.error(`${source}: ${toErrorMessage(e)}`);
|
||||
}
|
||||
|
||||
private computeConflicts(): SyncResourceConflicts[] {
|
||||
private computeConflicts(): [SyncResource, IResourcePreview[]][] {
|
||||
return this.synchronisers.filter(s => s.status === SyncStatus.HasConflicts)
|
||||
.map(s => ({ syncResource: s.resource, conflicts: s.conflicts }));
|
||||
.map(s => ([s.resource, s.conflicts.map(toStrictResourcePreview)]));
|
||||
}
|
||||
|
||||
getSynchroniser(source: SyncResource): IUserDataSynchroniser {
|
||||
return this.synchronisers.filter(s => s.resource === source)[0];
|
||||
return this.synchronisers.find(s => s.resource === source)!;
|
||||
}
|
||||
|
||||
private async checkEnablement(): Promise<void> {
|
||||
@@ -425,3 +427,222 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ManualSyncTask extends Disposable implements IManualSyncTask {
|
||||
|
||||
private previewsPromise: CancelablePromise<[SyncResource, ISyncResourcePreview][]> | undefined;
|
||||
private previews: [SyncResource, ISyncResourcePreview][] | undefined;
|
||||
|
||||
private synchronizingResources: [SyncResource, URI[]][] = [];
|
||||
private _onSynchronizeResources = this._register(new Emitter<[SyncResource, URI[]][]>());
|
||||
readonly onSynchronizeResources = this._onSynchronizeResources.event;
|
||||
|
||||
private isDisposed: boolean = false;
|
||||
|
||||
constructor(
|
||||
readonly id: string,
|
||||
readonly manifest: IUserDataManifest | null,
|
||||
private readonly syncHeaders: IHeaders,
|
||||
private readonly synchronisers: IUserDataSynchroniser[],
|
||||
private readonly logService: IUserDataSyncLogService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async preview(): Promise<[SyncResource, ISyncResourcePreview][]> {
|
||||
if (this.isDisposed) {
|
||||
throw new Error('Disposed');
|
||||
}
|
||||
if (!this.previewsPromise) {
|
||||
this.previewsPromise = createCancelablePromise(token => this.getPreviews(token));
|
||||
}
|
||||
this.previews = await this.previewsPromise;
|
||||
return this.previews;
|
||||
}
|
||||
|
||||
async accept(resource: URI, content: string): Promise<[SyncResource, ISyncResourcePreview][]> {
|
||||
return this.mergeOrAccept(resource, (sychronizer, force) => sychronizer.acceptPreviewContent(resource, content, force, this.syncHeaders));
|
||||
}
|
||||
|
||||
async merge(resource?: URI): Promise<[SyncResource, ISyncResourcePreview][]> {
|
||||
if (resource) {
|
||||
return this.mergeOrAccept(resource, (sychronizer, force) => sychronizer.merge(resource, force, this.syncHeaders));
|
||||
} else {
|
||||
return this.mergeAll();
|
||||
}
|
||||
}
|
||||
|
||||
private async mergeOrAccept(resource: URI, mergeOrAccept: (synchroniser: IUserDataSynchroniser, force: boolean) => Promise<ISyncResourcePreview | null>): Promise<[SyncResource, ISyncResourcePreview][]> {
|
||||
if (!this.previews) {
|
||||
throw new Error('You need to create preview before merging or accepting');
|
||||
}
|
||||
|
||||
const index = this.previews.findIndex(([, preview]) => preview.resourcePreviews.some(({ localResource, previewResource, remoteResource }) =>
|
||||
isEqual(resource, localResource) || isEqual(resource, previewResource) || isEqual(resource, remoteResource)));
|
||||
if (index === -1) {
|
||||
return this.previews;
|
||||
}
|
||||
|
||||
const [syncResource, previews] = this.previews[index];
|
||||
const resourcePreview = previews.resourcePreviews.find(({ localResource, remoteResource, previewResource }) => isEqual(localResource, resource) || isEqual(remoteResource, resource) || isEqual(previewResource, resource));
|
||||
if (!resourcePreview) {
|
||||
return this.previews;
|
||||
}
|
||||
|
||||
let synchronizingResources = this.synchronizingResources.find(s => s[0] === syncResource);
|
||||
if (!synchronizingResources) {
|
||||
synchronizingResources = [syncResource, []];
|
||||
this.synchronizingResources.push(synchronizingResources);
|
||||
}
|
||||
if (!synchronizingResources[1].some(s => isEqual(s, resourcePreview.localResource))) {
|
||||
synchronizingResources[1].push(resourcePreview.localResource);
|
||||
this._onSynchronizeResources.fire(this.synchronizingResources);
|
||||
}
|
||||
|
||||
const synchroniser = this.synchronisers.find(s => s.resource === this.previews![index][0])!;
|
||||
/* force only if the resource is local or remote resource */
|
||||
const force = isEqual(resource, resourcePreview.localResource) || isEqual(resource, resourcePreview.remoteResource);
|
||||
const preview = await mergeOrAccept(synchroniser, force);
|
||||
preview ? this.previews.splice(index, 1, this.toSyncResourcePreview(synchroniser.resource, preview)) : this.previews.splice(index, 1);
|
||||
|
||||
const i = this.synchronizingResources.findIndex(s => s[0] === syncResource);
|
||||
this.synchronizingResources[i][1].splice(synchronizingResources[1].findIndex(r => isEqual(r, resourcePreview.localResource)), 1);
|
||||
if (!synchronizingResources[1].length) {
|
||||
this.synchronizingResources.splice(i, 1);
|
||||
this._onSynchronizeResources.fire(this.synchronizingResources);
|
||||
}
|
||||
|
||||
return this.previews;
|
||||
}
|
||||
|
||||
private async mergeAll(): Promise<[SyncResource, ISyncResourcePreview][]> {
|
||||
if (!this.previews) {
|
||||
throw new Error('You need to create preview before merging');
|
||||
}
|
||||
if (this.synchronizingResources.length) {
|
||||
throw new Error('Cannot merge while synchronizing resources');
|
||||
}
|
||||
const previews: [SyncResource, ISyncResourcePreview][] = [];
|
||||
for (const [syncResource, preview] of this.previews) {
|
||||
this.synchronizingResources.push([syncResource, preview.resourcePreviews.map(r => r.localResource)]);
|
||||
this._onSynchronizeResources.fire(this.synchronizingResources);
|
||||
const synchroniser = this.synchronisers.find(s => s.resource === syncResource)!;
|
||||
let syncResourcePreview = null;
|
||||
for (const resourcePreview of preview.resourcePreviews) {
|
||||
syncResourcePreview = await synchroniser.merge(resourcePreview.remoteResource, false, this.syncHeaders);
|
||||
}
|
||||
if (syncResourcePreview) {
|
||||
previews.push([syncResource, syncResourcePreview]);
|
||||
}
|
||||
this.synchronizingResources.splice(this.synchronizingResources.findIndex(s => s[0] === syncResource), 1);
|
||||
this._onSynchronizeResources.fire(this.synchronizingResources);
|
||||
}
|
||||
this.previews = previews;
|
||||
return this.previews;
|
||||
}
|
||||
|
||||
async pull(): Promise<void> {
|
||||
if (!this.previews) {
|
||||
throw new Error('You need to create preview before applying');
|
||||
}
|
||||
if (this.synchronizingResources.length) {
|
||||
throw new Error('Cannot pull while synchronizing resources');
|
||||
}
|
||||
for (const [syncResource, preview] of this.previews) {
|
||||
this.synchronizingResources.push([syncResource, preview.resourcePreviews.map(r => r.localResource)]);
|
||||
this._onSynchronizeResources.fire(this.synchronizingResources);
|
||||
const synchroniser = this.synchronisers.find(s => s.resource === syncResource)!;
|
||||
for (const resourcePreview of preview.resourcePreviews) {
|
||||
const content = await synchroniser.resolveContent(resourcePreview.remoteResource) || '';
|
||||
await synchroniser.acceptPreviewContent(resourcePreview.remoteResource, content, true, this.syncHeaders);
|
||||
}
|
||||
this.synchronizingResources.splice(this.synchronizingResources.findIndex(s => s[0] === syncResource), 1);
|
||||
this._onSynchronizeResources.fire(this.synchronizingResources);
|
||||
}
|
||||
this.previews = [];
|
||||
}
|
||||
|
||||
async push(): Promise<void> {
|
||||
if (!this.previews) {
|
||||
throw new Error('You need to create preview before applying');
|
||||
}
|
||||
if (this.synchronizingResources.length) {
|
||||
throw new Error('Cannot pull while synchronizing resources');
|
||||
}
|
||||
for (const [syncResource, preview] of this.previews) {
|
||||
this.synchronizingResources.push([syncResource, preview.resourcePreviews.map(r => r.localResource)]);
|
||||
this._onSynchronizeResources.fire(this.synchronizingResources);
|
||||
const synchroniser = this.synchronisers.find(s => s.resource === syncResource)!;
|
||||
for (const resourcePreview of preview.resourcePreviews) {
|
||||
const content = await synchroniser.resolveContent(resourcePreview.localResource) || '';
|
||||
await synchroniser.acceptPreviewContent(resourcePreview.localResource, content, true, this.syncHeaders);
|
||||
}
|
||||
this.synchronizingResources.splice(this.synchronizingResources.findIndex(s => s[0] === syncResource), 1);
|
||||
this._onSynchronizeResources.fire(this.synchronizingResources);
|
||||
}
|
||||
this.previews = [];
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
try {
|
||||
await synchroniser.stop();
|
||||
} catch (error) {
|
||||
if (!isPromiseCanceledError(error)) {
|
||||
this.logService.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.reset();
|
||||
}
|
||||
|
||||
private async getPreviews(token: CancellationToken): Promise<[SyncResource, ISyncResourcePreview][]> {
|
||||
const result: [SyncResource, ISyncResourcePreview][] = [];
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
const preview = await synchroniser.preview(this.manifest, this.syncHeaders);
|
||||
if (preview) {
|
||||
result.push(this.toSyncResourcePreview(synchroniser.resource, preview));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private toSyncResourcePreview(syncResource: SyncResource, preview: ISyncResourcePreview): [SyncResource, ISyncResourcePreview] {
|
||||
return [
|
||||
syncResource,
|
||||
{
|
||||
isLastSyncFromCurrentMachine: preview.isLastSyncFromCurrentMachine,
|
||||
resourcePreviews: preview.resourcePreviews.map(toStrictResourcePreview)
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private reset(): void {
|
||||
if (this.previewsPromise) {
|
||||
this.previewsPromise.cancel();
|
||||
this.previewsPromise = undefined;
|
||||
}
|
||||
this.previews = undefined;
|
||||
this.synchronizingResources = [];
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.reset();
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function toStrictResourcePreview(resourcePreview: IResourcePreview): IResourcePreview {
|
||||
return {
|
||||
localResource: resourcePreview.localResource,
|
||||
previewResource: resourcePreview.previewResource,
|
||||
remoteResource: resourcePreview.remoteResource,
|
||||
localChange: resourcePreview.localChange,
|
||||
remoteChange: resourcePreview.remoteChange,
|
||||
merged: resourcePreview.merged,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user