33 * Licensed under the MIT License. See License.txt in the project root for license information.
44 *--------------------------------------------------------------------------------------------*/
55
6- import { SyncStatus , IUserDataSyncStoreService , ISyncExtension , IUserDataSyncLogService , IUserDataSynchroniser , SyncResource , IUserDataSyncEnablementService , IUserDataSyncBackupStoreService , ISyncResourceHandle , ISyncPreviewResult } from 'vs/platform/userDataSync/common/userDataSync' ;
6+ import { SyncStatus , IUserDataSyncStoreService , ISyncExtension , IUserDataSyncLogService , IUserDataSynchroniser , SyncResource , IUserDataSyncEnablementService , IUserDataSyncBackupStoreService , ISyncResourceHandle , ISyncPreviewResult , USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync' ;
77import { Event } from 'vs/base/common/event' ;
88import { IEnvironmentService } from 'vs/platform/environment/common/environment' ;
99import { IExtensionManagementService , IExtensionGalleryService , IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement' ;
@@ -16,9 +16,10 @@ import { isNonEmptyArray } from 'vs/base/common/arrays';
1616import { AbstractSynchroniser , IRemoteUserData , ISyncData } from 'vs/platform/userDataSync/common/abstractSynchronizer' ;
1717import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry' ;
1818import { URI } from 'vs/base/common/uri' ;
19- import { joinPath , dirname , basename } from 'vs/base/common/resources' ;
19+ import { joinPath , dirname , basename , isEqual } from 'vs/base/common/resources' ;
2020import { format } from 'vs/base/common/jsonFormatter' ;
2121import { applyEdits } from 'vs/base/common/jsonEdit' ;
22+ import { compare } from 'vs/base/common/strings' ;
2223
2324interface IExtensionsSyncPreviewResult extends ISyncPreviewResult {
2425 readonly localExtensions : ISyncExtension [ ] ;
@@ -35,8 +36,10 @@ interface ILastSyncUserData extends IRemoteUserData {
3536 skippedExtensions : ISyncExtension [ ] | undefined ;
3637}
3738
39+
3840export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUserDataSynchroniser {
3941
42+ private static readonly EXTENSIONS_DATA_URI = URI . from ( { scheme : USER_DATA_SYNC_SCHEME , authority : 'extensions' , path : `/data.json` } ) ;
4043 protected readonly version : number = 2 ;
4144 protected isEnabled ( ) : boolean { return super . isEnabled ( ) && this . extensionGalleryService . isEnabled ( ) ; }
4245
@@ -132,28 +135,49 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
132135 async stop ( ) : Promise < void > { }
133136
134137 async getAssociatedResources ( { uri } : ISyncResourceHandle ) : Promise < { resource : URI , comparableResource ?: URI } [ ] > {
135- return [ { resource : joinPath ( uri , 'extensions.json' ) } ] ;
138+ return [ { resource : joinPath ( uri , 'extensions.json' ) , comparableResource : ExtensionsSynchroniser . EXTENSIONS_DATA_URI } ] ;
136139 }
137140
138141 async resolveContent ( uri : URI ) : Promise < string | null > {
142+ if ( isEqual ( uri , ExtensionsSynchroniser . EXTENSIONS_DATA_URI ) ) {
143+ const localExtensions = await this . getLocalExtensions ( ) ;
144+ return this . format ( localExtensions ) ;
145+ }
146+
139147 let content = await super . resolveContent ( uri ) ;
140148 if ( content ) {
141149 return content ;
142150 }
151+
143152 content = await super . resolveContent ( dirname ( uri ) ) ;
144153 if ( content ) {
145154 const syncData = this . parseSyncData ( content ) ;
146155 if ( syncData ) {
147156 switch ( basename ( uri ) ) {
148157 case 'extensions.json' :
149- const edits = format ( syncData . content , undefined , { } ) ;
150- return applyEdits ( syncData . content , edits ) ;
158+ return this . format ( this . parseExtensions ( syncData ) ) ;
151159 }
152160 }
153161 }
162+
154163 return null ;
155164 }
156165
166+ private format ( extensions : ISyncExtension [ ] ) : string {
167+ extensions . sort ( ( e1 , e2 ) => {
168+ if ( ! e1 . identifier . uuid && e2 . identifier . uuid ) {
169+ return - 1 ;
170+ }
171+ if ( e1 . identifier . uuid && ! e2 . identifier . uuid ) {
172+ return 1 ;
173+ }
174+ return compare ( e1 . identifier . id , e2 . identifier . id ) ;
175+ } ) ;
176+ const content = JSON . stringify ( extensions ) ;
177+ const edits = format ( content , undefined , { } ) ;
178+ return applyEdits ( content , edits ) ;
179+ }
180+
157181 async acceptConflict ( conflict : URI , content : string ) : Promise < void > {
158182 throw new Error ( `${ this . syncResourceLogLabel } : Conflicts should not occur` ) ;
159183 }
@@ -216,9 +240,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
216240 }
217241
218242 if ( hasLocalChanged ) {
219- // back up all disabled or market place extensions
220- const backUpExtensions = localExtensions . filter ( e => e . disabled || ! ! e . identifier . uuid ) ;
221- await this . backupLocal ( JSON . stringify ( backUpExtensions ) ) ;
243+ await this . backupLocal ( JSON . stringify ( localExtensions ) ) ;
222244 skippedExtensions = await this . updateLocalExtensions ( added , removed , updated , skippedExtensions ) ;
223245 }
224246
0 commit comments