@@ -9,7 +9,7 @@ import { VSBuffer } from 'vs/base/common/buffer';
99import { URI } from 'vs/base/common/uri' ;
1010import {
1111 SyncResource , SyncStatus , IUserData , IUserDataSyncStoreService , UserDataSyncErrorCode , UserDataSyncError , IUserDataSyncLogService , IUserDataSyncUtilService ,
12- IUserDataSyncResourceEnablementService , IUserDataSyncBackupStoreService , Conflict , ISyncResourceHandle , USER_DATA_SYNC_SCHEME , ISyncResourcePreview as IBaseSyncResourcePreview ,
12+ IUserDataSyncResourceEnablementService , IUserDataSyncBackupStoreService , ISyncResourceHandle , USER_DATA_SYNC_SCHEME , ISyncResourcePreview as IBaseSyncResourcePreview ,
1313 IUserDataManifest , ISyncData , IRemoteUserData , PREVIEW_DIR_NAME , IResourcePreview as IBaseResourcePreview , Change
1414} from 'vs/platform/userDataSync/common/userDataSync' ;
1515import { IEnvironmentService } from 'vs/platform/environment/common/environment' ;
@@ -78,10 +78,11 @@ export abstract class AbstractSynchroniser extends Disposable {
7878 private _onDidChangStatus : Emitter < SyncStatus > = this . _register ( new Emitter < SyncStatus > ( ) ) ;
7979 readonly onDidChangeStatus : Event < SyncStatus > = this . _onDidChangStatus . event ;
8080
81- private _conflicts : Conflict [ ] = [ ] ;
82- get conflicts ( ) : Conflict [ ] { return this . _conflicts ; }
83- private _onDidChangeConflicts : Emitter < Conflict [ ] > = this . _register ( new Emitter < Conflict [ ] > ( ) ) ;
84- readonly onDidChangeConflicts : Event < Conflict [ ] > = this . _onDidChangeConflicts . event ;
81+ private _resourcePreviews : IResourcePreview [ ] = [ ] ;
82+ get resourcePreviews ( ) : IResourcePreview [ ] { return this . _resourcePreviews ; }
83+ get conflicts ( ) : IResourcePreview [ ] { return this . _resourcePreviews . filter ( ( { hasConflicts } ) => hasConflicts ) ; }
84+ private _onDidChangeConflicts : Emitter < IResourcePreview [ ] > = this . _register ( new Emitter < IResourcePreview [ ] > ( ) ) ;
85+ readonly onDidChangeConflicts : Event < IResourcePreview [ ] > = this . _onDidChangeConflicts . event ;
8586
8687 private readonly localChangeTriggerScheduler = new RunOnceScheduler ( ( ) => this . doTriggerLocalChange ( ) , 50 ) ;
8788 private readonly _onDidChangeLocal : Emitter < void > = this . _register ( new Emitter < void > ( ) ) ;
@@ -155,16 +156,6 @@ export abstract class AbstractSynchroniser extends Disposable {
155156 // Log to telemetry when conflicts are resolved
156157 this . telemetryService . publicLog2 < { source : string } , SyncSourceClassification > ( 'sync/conflictsResolved' , { source : this . resource } ) ;
157158 }
158- if ( this . status !== SyncStatus . HasConflicts ) {
159- this . setConflicts ( [ ] ) ;
160- }
161- }
162- }
163-
164- private setConflicts ( conflicts : Conflict [ ] ) {
165- if ( ! equals ( this . _conflicts , conflicts , ( a , b ) => isEqual ( a . local , b . local ) && isEqual ( a . remote , b . remote ) ) ) {
166- this . _conflicts = conflicts ;
167- this . _onDidChangeConflicts . fire ( this . _conflicts ) ;
168159 }
169160 }
170161
@@ -364,6 +355,9 @@ export abstract class AbstractSynchroniser extends Disposable {
364355 // reset preview
365356 this . syncPreviewPromise = null ;
366357
358+ // reset resource previews
359+ await this . updateResourcePreviews ( [ ] , CancellationToken . None ) ;
360+
367361 return SyncStatus . Idle ;
368362 } catch ( error ) {
369363
@@ -374,47 +368,50 @@ export abstract class AbstractSynchroniser extends Disposable {
374368 }
375369 }
376370
377- async acceptConflict ( conflictUri : URI , conflictContent : string ) : Promise < void > {
378- let preview = this . syncPreviewPromise ? await this . syncPreviewPromise : null ;
379-
380- if ( ! preview || ! preview . resourcePreviews . some ( ( { hasConflicts } ) => hasConflicts ) ) {
371+ async acceptPreviewContent ( resource : URI , content : string ) : Promise < void > {
372+ if ( ! this . syncPreviewPromise ) {
381373 return ;
382374 }
383375
376+ let preview = await this . syncPreviewPromise ;
384377 this . syncPreviewPromise = createCancelablePromise ( async token => {
385- const newPreview = await this . updateSyncResourcePreviewWithConflict ( preview ! , conflictUri , conflictContent , token ) ;
386- await this . updateConflicts ( newPreview . resourcePreviews , token ) ;
378+ const newPreview = await this . updateSyncResourcePreviewContent ( preview , resource , content , token ) ;
379+
380+ if ( ! token . isCancellationRequested ) {
381+ await this . updateResourcePreviews ( newPreview . resourcePreviews , token ) ;
382+ }
383+
387384 return newPreview ;
388385 } ) ;
389386 preview = await this . syncPreviewPromise ;
390387
391388 if ( ! preview . resourcePreviews . some ( ( { hasConflicts } ) => hasConflicts ) ) {
392- // apply preview
389+ // Apply preview if there are no conflicts
393390 await this . applyPreview ( preview . remoteUserData , preview . lastSyncUserData , preview . resourcePreviews , false ) ;
394391
395392 // reset preview
396393 this . syncPreviewPromise = null ;
397394
395+ // reset resource previews
396+ await this . updateResourcePreviews ( [ ] , CancellationToken . None ) ;
397+
398+ // reset status
398399 this . setStatus ( SyncStatus . Idle ) ;
399400 }
400401 }
401402
402- private async updateSyncResourcePreviewWithConflict ( preview : ISyncResourcePreview , conflictResource : URI , previewContent : string , token : CancellationToken ) : Promise < ISyncResourcePreview > {
403- const conflict = this . conflicts . find ( ( { local, remote } ) => isEqual ( local , conflictResource ) || isEqual ( remote , conflictResource ) ) ;
404- if ( ! conflict ) {
405- return preview ;
406- }
407- const index = preview . resourcePreviews . findIndex ( ( { previewResource } ) => previewResource && isEqual ( previewResource , conflict . local ) ) ;
408- if ( index === - 1 ) {
409- return preview ;
403+ private async updateSyncResourcePreviewContent ( preview : ISyncResourcePreview , resource : URI , previewContent : string , token : CancellationToken ) : Promise < ISyncResourcePreview > {
404+ const index = preview . resourcePreviews . findIndex ( ( { localResource, remoteResource, previewResource } ) => isEqual ( localResource , resource ) || isEqual ( remoteResource , resource ) || isEqual ( previewResource , resource ) ) ;
405+ if ( index !== - 1 ) {
406+ const resourcePreviews = [ ...preview . resourcePreviews ] ;
407+ const resourcePreview = await this . updateResourcePreviewContent ( resourcePreviews [ index ] , resource , previewContent , token ) ;
408+ resourcePreviews [ index ] = resourcePreview ;
409+ preview = {
410+ ...preview ,
411+ resourcePreviews
412+ } ;
410413 }
411- const resourcePreviews = [ ...preview . resourcePreviews ] ;
412- const resourcePreview = await this . updateResourcePreviewContent ( resourcePreviews [ index ] , conflictResource , previewContent , token ) ;
413- resourcePreviews [ index ] = resourcePreview ;
414- return {
415- ...preview ,
416- resourcePreviews
417- } ;
414+ return preview ;
418415 }
419416
420417 protected async updateResourcePreviewContent ( resourcePreview : IResourcePreview , resource : URI , previewContent : string , token : CancellationToken ) : Promise < IResourcePreview > {
@@ -427,27 +424,25 @@ export abstract class AbstractSynchroniser extends Disposable {
427424 } ;
428425 }
429426
430- private async updateConflicts ( resourcePreviews : IResourcePreview [ ] , token : CancellationToken ) : Promise < void > {
431- const conflicts : Conflict [ ] = [ ] ;
432- for ( const resourcePreview of resourcePreviews ) {
433- if ( resourcePreview . hasConflicts ) {
434- conflicts . push ( { local : resourcePreview . previewResource ! , remote : resourcePreview . remoteResource ! } ) ;
435- }
436- }
427+ private async updateResourcePreviews ( resourcePreviews : IResourcePreview [ ] , token : CancellationToken ) : Promise < void > {
428+ const oldConflicts = this . conflicts ;
429+ const oldPreviews = this . _resourcePreviews ;
430+ this . _resourcePreviews = resourcePreviews ;
437431
438- for ( const conflict of this . conflicts ) {
439- // clear obsolete conflicts
440- if ( ! conflicts . some ( ( { local } ) => isEqual ( local , conflict . local ) ) ) {
432+ // clear obsolete previews
433+ for ( const resourcePreview of oldPreviews ) {
434+ if ( ! this . _resourcePreviews . some ( ( { previewResource } ) => isEqual ( previewResource , resourcePreview . previewResource ) ) ) {
441435 try {
442- await this . fileService . del ( conflict . local ) ;
443- } catch ( error ) {
444- // Ignore & log
445- this . logService . error ( error ) ;
446- }
436+ await this . fileService . del ( resourcePreview . previewResource ) ;
437+ } catch ( error ) { /* Ignore */ }
447438 }
448439 }
449440
450- this . setConflicts ( conflicts ) ;
441+ // update conflicts
442+ const newConflicts = this . conflicts ;
443+ if ( ! equals ( oldConflicts , newConflicts , ( a , b ) => isEqual ( a . previewResource , b . previewResource ) ) ) {
444+ this . _onDidChangeConflicts . fire ( newConflicts ) ;
445+ }
451446 }
452447
453448 async hasPreviouslySynced ( ) : Promise < boolean > {
@@ -528,7 +523,11 @@ export abstract class AbstractSynchroniser extends Disposable {
528523 // For preview, use remoteUserData if lastSyncUserData does not exists and last sync is from current machine
529524 const lastSyncUserDataForPreview = lastSyncUserData === null && isLastSyncFromCurrentMachine ? remoteUserData : lastSyncUserData ;
530525 const resourcePreviews = await this . generateSyncPreview ( remoteUserData , lastSyncUserDataForPreview , token ) ;
531- await this . updateConflicts ( resourcePreviews , token ) ;
526+
527+ if ( ! token . isCancellationRequested ) {
528+ await this . updateResourcePreviews ( resourcePreviews , token ) ;
529+ }
530+
532531 return { remoteUserData, lastSyncUserData, resourcePreviews, isLastSyncFromCurrentMachine } ;
533532 }
534533
@@ -605,23 +604,20 @@ export abstract class AbstractSynchroniser extends Disposable {
605604 }
606605
607606 async stop ( ) : Promise < void > {
608- this . logService . info ( `${ this . syncResourceLogLabel } : Stopped synchronizing ${ this . resource . toLowerCase ( ) } .` ) ;
607+ if ( this . status === SyncStatus . Idle ) {
608+ return ;
609+ }
610+
611+ this . logService . trace ( `${ this . syncResourceLogLabel } : Stopping synchronizing ${ this . resource . toLowerCase ( ) } .` ) ;
609612 if ( this . syncPreviewPromise ) {
610613 this . syncPreviewPromise . cancel ( ) ;
611614 this . syncPreviewPromise = null ;
612615 }
613- if ( this . conflicts . length ) {
614- await Promise . all ( this . conflicts . map ( async ( { local } ) => {
615- try {
616- this . fileService . del ( local ) ;
617- } catch ( error ) {
618- // Ignore & log
619- this . logService . error ( error ) ;
620- }
621- } ) ) ;
622- this . setConflicts ( [ ] ) ;
623- }
616+
617+ await this . updateResourcePreviews ( [ ] , CancellationToken . None ) ;
618+
624619 this . setStatus ( SyncStatus . Idle ) ;
620+ this . logService . info ( `${ this . syncResourceLogLabel } : Stopped synchronizing ${ this . resource . toLowerCase ( ) } .` ) ;
625621 }
626622
627623 protected abstract readonly version : number ;
0 commit comments