8
8
import * as workspaceInstance from '@gitpod/gitpod-protocol/lib/workspace-instance' ;
9
9
import * as grpc from '@grpc/grpc-js' ;
10
10
import * as fs from 'fs' ;
11
+ import * as os from 'os' ;
12
+ import * as uuid from 'uuid' ;
11
13
import { GitpodPluginModel , GitpodExtensionContext , setupGitpodContext , registerTasks , registerIpcHookCli } from 'gitpod-shared' ;
12
14
import { GetTokenRequest } from '@gitpod/supervisor-api-grpc/lib/token_pb' ;
13
15
import { PortsStatus , ExposedPortInfo , PortsStatusRequest , PortsStatusResponse , PortAutoExposure , PortVisibility , OnPortExposedAction } from '@gitpod/supervisor-api-grpc/lib/status_pb' ;
@@ -19,7 +21,9 @@ import * as path from 'path';
19
21
import { URL } from 'url' ;
20
22
import * as util from 'util' ;
21
23
import * as vscode from 'vscode' ;
22
- import { ThrottledDelayer } from './async' ;
24
+ import { ThrottledDelayer } from './util/async' ;
25
+ import { download } from './util/download' ;
26
+ import { getManifest } from './util/extensionManagmentUtill' ;
23
27
24
28
let gitpodContext : GitpodExtensionContext | undefined ;
25
29
export async function activate ( context : vscode . ExtensionContext ) {
@@ -185,7 +189,7 @@ export function registerAuth(context: GitpodExtensionContext): void {
185
189
if ( ! userResponse . ok ) {
186
190
throw new Error ( `Getting GitHub account info failed: ${ userResponse . statusText } ` ) ;
187
191
}
188
- const user : { id : string , login : string } = await userResponse . json ( ) ;
192
+ const user = await ( userResponse . json ( ) as Promise < { id : string , login : string } > ) ;
189
193
return {
190
194
id : user . id ,
191
195
accountName : user . login
@@ -774,7 +778,7 @@ interface IOpenVSXQueryResult {
774
778
extensions : IOpenVSXExtensionsMetadata [ ] ;
775
779
}
776
780
777
- async function validateExtensions ( extensionsToValidate : { id : string , version ?: string } [ ] , token : vscode . CancellationToken ) {
781
+ async function validateExtensions ( extensionsToValidate : { id : string , version ?: string } [ ] , linkToValidate : string [ ] , token : vscode . CancellationToken ) {
778
782
const allUserExtensions = vscode . extensions . all . filter ( ext => ! ext . packageJSON [ 'isBuiltin' ] && ! ext . packageJSON [ 'isUserBuiltin' ] ) ;
779
783
780
784
const lookup = new Set < string > ( extensionsToValidate . map ( ( { id } ) => id ) ) ;
@@ -795,7 +799,8 @@ async function validateExtensions(extensionsToValidate: { id: string, version?:
795
799
return {
796
800
extensions : [ ] ,
797
801
missingMachined : [ ] ,
798
- uninstalled : [ ]
802
+ uninstalled : [ ] ,
803
+ links : [ ]
799
804
} ;
800
805
}
801
806
}
@@ -806,21 +811,21 @@ async function validateExtensions(extensionsToValidate: { id: string, version?:
806
811
`${ process . env . VSX_REGISTRY_URL || 'https://open-vsx.org' } /api/-/query` ,
807
812
{
808
813
method : 'POST' ,
809
- timeout : 5000 ,
810
814
headers : {
811
815
'Content-Type' : 'application/json' ,
812
816
'Accept' : 'application/json'
813
817
} ,
814
818
body : JSON . stringify ( {
815
819
extensionId : id
816
- } )
820
+ } ) ,
821
+ timeout : 2000
817
822
}
818
823
) . then ( resp => {
819
824
if ( ! resp . ok ) {
820
825
console . error ( 'Failed to query open-vsx while validating gitpod.yml' ) ;
821
826
return undefined ;
822
827
}
823
- return resp . json ( ) ;
828
+ return resp . json ( ) as Promise < IOpenVSXQueryResult > ;
824
829
} , e => {
825
830
console . error ( 'Fetch failed while querying open-vsx' , e ) ;
826
831
return undefined ;
@@ -837,17 +842,40 @@ async function validateExtensions(extensionsToValidate: { id: string, version?:
837
842
return {
838
843
extensions : [ ] ,
839
844
missingMachined : [ ] ,
840
- uninstalled : [ ]
845
+ uninstalled : [ ] ,
846
+ links : [ ]
841
847
} ;
842
848
}
843
849
}
844
850
845
- // TODO: validate links
851
+ const links = new Set < string > ( ) ;
852
+ for ( const link of linkToValidate ) {
853
+ const downloadPath = path . join ( os . tmpdir ( ) , uuid . v4 ( ) ) ;
854
+ try {
855
+ await download ( link , downloadPath , token , 10000 ) ;
856
+ const manifest = await getManifest ( downloadPath ) ;
857
+ if ( manifest . engines ?. vscode ) {
858
+ links . add ( link ) ;
859
+ }
860
+ } catch ( error ) {
861
+ console . error ( 'Failed to validate vsix url' , error ) ;
862
+ }
863
+
864
+ if ( token . isCancellationRequested ) {
865
+ return {
866
+ extensions : [ ] ,
867
+ missingMachined : [ ] ,
868
+ uninstalled : [ ] ,
869
+ links : [ ]
870
+ } ;
871
+ }
872
+ }
846
873
847
874
return {
848
875
extensions : [ ...validatedExtensions ] ,
849
876
missingMachined : [ ...missingMachined ] ,
850
- uninstalled : [ ...uninstalled ]
877
+ uninstalled : [ ...uninstalled ] ,
878
+ links : [ ...links ]
851
879
} ;
852
880
}
853
881
@@ -926,10 +954,7 @@ export function registerExtensionManagement(context: GitpodExtensionContext): vo
926
954
}
927
955
try {
928
956
const toLink = new Map < string , vscode . Range > ( ) ;
929
- const toFind = new Map < string , {
930
- version ?: string ,
931
- range : vscode . Range
932
- } > ( ) ;
957
+ const toFind = new Map < string , { version ?: string , range : vscode . Range } > ( ) ;
933
958
let document : vscode . TextDocument | undefined ;
934
959
try {
935
960
document = await vscode . workspace . openTextDocument ( gitpodFileUri ) ;
@@ -994,7 +1019,8 @@ export function registerExtensionManagement(context: GitpodExtensionContext): vo
994
1019
}
995
1020
996
1021
const extensionsToValidate = [ ...toFind . entries ( ) ] . map ( ( [ id , { version } ] ) => ( { id, version } ) ) ;
997
- const result = await validateExtensions ( extensionsToValidate , token ) ;
1022
+ const linksToValidate = [ ...toLink . keys ( ) ] ;
1023
+ const result = await validateExtensions ( extensionsToValidate , linksToValidate , token ) ;
998
1024
999
1025
if ( token . isCancellationRequested ) {
1000
1026
return ;
@@ -1016,14 +1042,14 @@ export function registerExtensionManagement(context: GitpodExtensionContext): vo
1016
1042
pushDiagnostic ( diagnostic ) ;
1017
1043
}
1018
1044
1019
- // for (const link of result.links) {
1020
- // toLink.delete(link);
1021
- // }
1022
- // for (const [link, range] of toLink) {
1023
- // const diagnostic = new vscode.Diagnostic(range, link + invalidVSIXLinkMessageSuffix, vscode.DiagnosticSeverity.Error);
1024
- // diagnostic.source = 'gitpod';
1025
- // pushDiagnostic(diagnostic);
1026
- // }
1045
+ for ( const link of result . links ) {
1046
+ toLink . delete ( link ) ;
1047
+ }
1048
+ for ( const [ link , range ] of toLink ) {
1049
+ const diagnostic = new vscode . Diagnostic ( range , link + invalidVSIXLinkMessageSuffix , vscode . DiagnosticSeverity . Error ) ;
1050
+ diagnostic . source = 'gitpod' ;
1051
+ pushDiagnostic ( diagnostic ) ;
1052
+ }
1027
1053
1028
1054
for ( const id of result . missingMachined ) {
1029
1055
const diagnostic = new vscode . Diagnostic ( new vscode . Range ( new vscode . Position ( 0 , 0 ) , new vscode . Position ( 0 , 1 ) ) , id + missingExtensionMessageSuffix , vscode . DiagnosticSeverity . Warning ) ;
@@ -1158,13 +1184,9 @@ export function registerExtensionManagement(context: GitpodExtensionContext): vo
1158
1184
return codeActions ;
1159
1185
}
1160
1186
} ) ) ;
1187
+
1161
1188
validateGitpodFile ( ) ;
1162
1189
context . subscriptions . push ( gitpodDiagnostics ) ;
1163
- context . subscriptions . push ( vscode . workspace . onDidChangeTextDocument ( e => {
1164
- if ( e . document . uri . toString ( ) === gitpodFileUri . toString ( ) ) {
1165
- validateGitpodFile ( ) ;
1166
- }
1167
- } ) ) ;
1168
1190
const gitpodFileWatcher = vscode . workspace . createFileSystemWatcher ( gitpodFileUri . fsPath ) ;
1169
1191
context . subscriptions . push ( gitpodFileWatcher ) ;
1170
1192
context . subscriptions . push ( gitpodFileWatcher . onDidCreate ( ( ) => validateGitpodFile ( ) ) ) ;
0 commit comments