@@ -12,7 +12,7 @@ import { Event } from 'vs/base/common/event';
12
12
import { IURITransformer , transformOutgoingURIs } from 'vs/base/common/uriIpc' ;
13
13
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc' ;
14
14
import { ContextKeyDefinedExpr , ContextKeyEqualsExpr , ContextKeyExpr , ContextKeyExpression , ContextKeyGreaterEqualsExpr , ContextKeyGreaterExpr , ContextKeyInExpr , ContextKeyNotEqualsExpr , ContextKeyNotExpr , ContextKeyNotInExpr , ContextKeyRegexExpr , ContextKeySmallerEqualsExpr , ContextKeySmallerExpr , IContextKeyExprMapper } from 'vs/platform/contextkey/common/contextkey' ;
15
- import { InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement' ;
15
+ import { IExtensionGalleryService , InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement' ;
16
16
import { ExtensionManagementCLI } from 'vs/platform/extensionManagement/common/extensionManagementCLI' ;
17
17
import { IExtensionsScannerService , toExtensionDescription } from 'vs/platform/extensionManagement/common/extensionsScannerService' ;
18
18
import { ExtensionType , IExtensionDescription } from 'vs/platform/extensions/common/extensions' ;
@@ -22,6 +22,7 @@ import { IServerEnvironmentService } from 'vs/server/node/serverEnvironmentServi
22
22
import { dedupExtensions } from 'vs/workbench/services/extensions/common/extensionsUtil' ;
23
23
import { Schemas } from 'vs/base/common/network' ;
24
24
import { IRemoteExtensionsScannerService } from 'vs/platform/remote/common/remoteExtensionsScanner' ;
25
+ import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks' ;
25
26
26
27
export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerService {
27
28
@@ -30,16 +31,18 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS
30
31
private readonly _whenExtensionsReady : Promise < void > ;
31
32
32
33
constructor (
33
- extensionManagementCLI : ExtensionManagementCLI ,
34
+ private readonly _extensionManagementCLI : ExtensionManagementCLI ,
34
35
environmentService : IServerEnvironmentService ,
35
36
private readonly _userDataProfilesService : IUserDataProfilesService ,
36
37
private readonly _extensionsScannerService : IExtensionsScannerService ,
37
38
private readonly _logService : ILogService ,
39
+ private readonly _extensionGalleryService : IExtensionGalleryService ,
40
+ private readonly _languagePackService : ILanguagePackService
38
41
) {
39
42
if ( environmentService . args [ 'install-builtin-extension' ] ) {
40
43
const installOptions : InstallOptions = { isMachineScoped : ! ! environmentService . args [ 'do-not-sync' ] , installPreReleaseVersion : ! ! environmentService . args [ 'pre-release' ] } ;
41
44
performance . mark ( 'code/server/willInstallBuiltinExtensions' ) ;
42
- this . _whenExtensionsReady = extensionManagementCLI . installExtensions ( [ ] , environmentService . args [ 'install-builtin-extension' ] , installOptions , ! ! environmentService . args [ 'force' ] )
45
+ this . _whenExtensionsReady = _extensionManagementCLI . installExtensions ( [ ] , environmentService . args [ 'install-builtin-extension' ] , installOptions , ! ! environmentService . args [ 'force' ] )
43
46
. then ( ( ) => performance . mark ( 'code/server/didInstallBuiltinExtensions' ) , error => {
44
47
_logService . error ( error ) ;
45
48
} ) ;
@@ -51,7 +54,7 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS
51
54
if ( extensionsToInstall ) {
52
55
const idsOrVSIX = extensionsToInstall . map ( input => / \. v s i x $ / i. test ( input ) ? URI . file ( isAbsolute ( input ) ? input : join ( cwd ( ) , input ) ) : input ) ;
53
56
this . _whenExtensionsReady
54
- . then ( ( ) => extensionManagementCLI . installExtensions ( idsOrVSIX , [ ] , { isMachineScoped : ! ! environmentService . args [ 'do-not-sync' ] , installPreReleaseVersion : ! ! environmentService . args [ 'pre-release' ] } , ! ! environmentService . args [ 'force' ] ) )
57
+ . then ( ( ) => _extensionManagementCLI . installExtensions ( idsOrVSIX , [ ] , { isMachineScoped : ! ! environmentService . args [ 'do-not-sync' ] , installPreReleaseVersion : ! ! environmentService . args [ 'pre-release' ] } , ! ! environmentService . args [ 'force' ] ) )
55
58
. then ( null , error => {
56
59
_logService . error ( error ) ;
57
60
} ) ;
@@ -62,7 +65,7 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS
62
65
return this . _whenExtensionsReady ;
63
66
}
64
67
65
- async scanExtensions ( language ?: string , profileLocation ?: URI , extensionDevelopmentLocations ?: URI [ ] ) : Promise < IExtensionDescription [ ] > {
68
+ async scanExtensions ( language ?: string , profileLocation ?: URI , extensionDevelopmentLocations ?: URI [ ] , languagePackId ?: string ) : Promise < IExtensionDescription [ ] > {
66
69
await this . whenExtensionsReady ( ) ;
67
70
68
71
performance . mark ( 'code/server/willScanExtensions' ) ;
@@ -72,7 +75,7 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS
72
75
const extensionDevelopmentPaths = extensionDevelopmentLocations ? extensionDevelopmentLocations . filter ( url => url . scheme === Schemas . file ) . map ( url => url . fsPath ) : undefined ;
73
76
profileLocation = profileLocation ?? this . _userDataProfilesService . defaultProfile . extensionsResource ;
74
77
75
- const extensions = await this . _scanExtensions ( profileLocation , language ?? platform . language , extensionDevelopmentPaths ) ;
78
+ const extensions = await this . _scanExtensions ( profileLocation , language ?? platform . language , extensionDevelopmentPaths , languagePackId ) ;
76
79
77
80
this . _logService . trace ( 'Scanned Extensions' , extensions ) ;
78
81
this . _massageWhenConditions ( extensions ) ;
@@ -101,8 +104,8 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS
101
104
return extension ;
102
105
}
103
106
104
- private async _scanExtensions ( profileLocation : URI , language : string , extensionDevelopmentPath ? : string [ ] ) : Promise < IExtensionDescription [ ] > {
105
- // Ensure that the language packs are available
107
+ private async _scanExtensions ( profileLocation : URI , language : string , extensionDevelopmentPath : string [ ] | undefined , languagePackId : string | undefined ) : Promise < IExtensionDescription [ ] > {
108
+ await this . _ensureLanguagePackIsInstalled ( language , languagePackId ) ;
106
109
107
110
const [ builtinExtensions , installedExtensions , developedExtensions ] = await Promise . all ( [
108
111
this . _scanBuiltinExtensions ( language ) ,
@@ -139,6 +142,44 @@ export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerS
139
142
return scannedExtension ? toExtensionDescription ( scannedExtension , false ) : null ;
140
143
}
141
144
145
+ private async _ensureLanguagePackIsInstalled ( language : string , languagePackId : string | undefined ) : Promise < void > {
146
+ if (
147
+ // No need to install language packs for the default language
148
+ language === platform . LANGUAGE_DEFAULT ||
149
+ // The extension gallery service needs to be available
150
+ ! this . _extensionGalleryService . isEnabled ( )
151
+ ) {
152
+ return ;
153
+ }
154
+
155
+ try {
156
+ const installed = await this . _languagePackService . getInstalledLanguages ( ) ;
157
+ if ( installed . find ( p => p . id === language ) ) {
158
+ this . _logService . trace ( `Language Pack ${ language } is already installed. Skipping language pack installation.` ) ;
159
+ return ;
160
+ }
161
+ } catch ( err ) {
162
+ // We tried to see what is installed but failed. We can try installing anyway.
163
+ this . _logService . error ( err ) ;
164
+ }
165
+
166
+ if ( ! languagePackId ) {
167
+ this . _logService . trace ( `No language pack id provided for language ${ language } . Skipping language pack installation.` ) ;
168
+ return ;
169
+ }
170
+
171
+ this . _logService . trace ( `Language Pack ${ languagePackId } for language ${ language } is not installed. It will be installed now.` ) ;
172
+ try {
173
+ await this . _extensionManagementCLI . installExtensions ( [ languagePackId ] , [ ] , { isMachineScoped : true } , true , {
174
+ log : ( s ) => this . _logService . info ( s ) ,
175
+ error : ( s ) => this . _logService . error ( s )
176
+ } ) ;
177
+ } catch ( err ) {
178
+ // We tried to install the language pack but failed. We can continue without it thus using the default language.
179
+ this . _logService . error ( err ) ;
180
+ }
181
+ }
182
+
142
183
private _massageWhenConditions ( extensions : IExtensionDescription [ ] ) : void {
143
184
// Massage "when" conditions which mention `resourceScheme`
144
185
@@ -269,7 +310,8 @@ export class RemoteExtensionsScannerChannel implements IServerChannel {
269
310
const language = args [ 0 ] ;
270
311
const profileLocation = args [ 1 ] ? URI . revive ( uriTransformer . transformIncoming ( args [ 1 ] ) ) : undefined ;
271
312
const extensionDevelopmentPath = Array . isArray ( args [ 2 ] ) ? args [ 2 ] . map ( u => URI . revive ( uriTransformer . transformIncoming ( u ) ) ) : undefined ;
272
- const extensions = await this . service . scanExtensions ( language , profileLocation , extensionDevelopmentPath ) ;
313
+ const languagePackId : string | undefined = args [ 3 ] ;
314
+ const extensions = await this . service . scanExtensions ( language , profileLocation , extensionDevelopmentPath , languagePackId ) ;
273
315
return extensions . map ( extension => transformOutgoingURIs ( extension , uriTransformer ) ) ;
274
316
}
275
317
case 'scanSingleExtension' : {
0 commit comments