@@ -16,6 +16,7 @@ import {
16
16
ThemeIcon ,
17
17
ThemeColor ,
18
18
workspace ,
19
+ FileType ,
19
20
} from "vscode" ;
20
21
import { pathExists , stat , readdir , remove } from "fs-extra" ;
21
22
@@ -36,6 +37,7 @@ import {
36
37
import {
37
38
showAndLogExceptionWithTelemetry ,
38
39
showAndLogErrorMessage ,
40
+ showAndLogInformationMessage ,
39
41
} from "../common/logging" ;
40
42
import type { DatabaseFetcher } from "./database-fetcher" ;
41
43
import { asError , asyncFilter , getErrorMessage } from "../common/helpers-pure" ;
@@ -267,6 +269,8 @@ export class DatabaseUI extends DisposableObject {
267
269
"codeQL.getCurrentDatabase" : this . handleGetCurrentDatabase . bind ( this ) ,
268
270
"codeQL.chooseDatabaseFolder" :
269
271
this . handleChooseDatabaseFolderFromPalette . bind ( this ) ,
272
+ "codeQL.chooseDatabaseFoldersParent" :
273
+ this . handleChooseDatabaseFoldersParentFromPalette . bind ( this ) ,
270
274
"codeQL.chooseDatabaseArchive" :
271
275
this . handleChooseDatabaseArchiveFromPalette . bind ( this ) ,
272
276
"codeQL.chooseDatabaseInternet" :
@@ -359,6 +363,12 @@ export class DatabaseUI extends DisposableObject {
359
363
) ;
360
364
}
361
365
366
+ private async handleChooseDatabaseFoldersParentFromPalette ( ) : Promise < void > {
367
+ return withProgress ( async ( progress ) => {
368
+ await this . chooseDatabasesParentFolder ( progress ) ;
369
+ } ) ;
370
+ }
371
+
362
372
private async handleSetDefaultTourDatabase ( ) : Promise < void > {
363
373
return withProgress (
364
374
async ( ) => {
@@ -957,26 +967,22 @@ export class DatabaseUI extends DisposableObject {
957
967
}
958
968
959
969
/**
960
- * Ask the user for a database directory . Returns the chosen database, or `undefined` if the
961
- * operation was canceled.
970
+ * Import database from uri . Returns the imported database, or `undefined` if the
971
+ * operation was unsuccessful or canceled.
962
972
*/
963
- private async chooseAndSetDatabase (
973
+ private async importDatabase (
974
+ uri : Uri ,
964
975
byFolder : boolean ,
965
976
progress : ProgressCallback ,
966
977
) : Promise < DatabaseItem | undefined > {
967
- const uri = await chooseDatabaseDir ( byFolder ) ;
968
- if ( ! uri ) {
969
- return undefined ;
970
- }
971
-
972
- if ( byFolder && ! uri . fsPath . endsWith ( "testproj" ) ) {
978
+ if ( byFolder && ! uri . fsPath . endsWith ( ".testproj" ) ) {
973
979
const fixedUri = await this . fixDbUri ( uri ) ;
974
980
// we are selecting a database folder
975
981
return await this . databaseManager . openDatabase ( fixedUri , {
976
982
type : "folder" ,
977
983
} ) ;
978
984
} else {
979
- // we are selecting a database archive or a testproj.
985
+ // we are selecting a database archive or a . testproj.
980
986
// Unzip archives (if an archive) and copy into a workspace-controlled area
981
987
// before importing.
982
988
return await this . databaseFetcher . importLocalDatabase (
@@ -986,6 +992,104 @@ export class DatabaseUI extends DisposableObject {
986
992
}
987
993
}
988
994
995
+ /**
996
+ * Ask the user for a database directory. Returns the chosen database, or `undefined` if the
997
+ * operation was canceled.
998
+ */
999
+ private async chooseAndSetDatabase (
1000
+ byFolder : boolean ,
1001
+ progress : ProgressCallback ,
1002
+ ) : Promise < DatabaseItem | undefined > {
1003
+ const uri = await chooseDatabaseDir ( byFolder ) ;
1004
+ if ( ! uri ) {
1005
+ return undefined ;
1006
+ }
1007
+
1008
+ return await this . importDatabase ( uri , byFolder , progress ) ;
1009
+ }
1010
+
1011
+ /**
1012
+ * Ask the user for a parent directory that contains all databases.
1013
+ * Returns all valid databases, or `undefined` if the operation was canceled.
1014
+ */
1015
+ private async chooseDatabasesParentFolder (
1016
+ progress : ProgressCallback ,
1017
+ ) : Promise < DatabaseItem [ ] | undefined > {
1018
+ const uri = await chooseDatabaseDir ( true ) ;
1019
+ if ( ! uri ) {
1020
+ return undefined ;
1021
+ }
1022
+
1023
+ const databases : DatabaseItem [ ] = [ ] ;
1024
+ const failures : string [ ] = [ ] ;
1025
+ const entries = await workspace . fs . readDirectory ( uri ) ;
1026
+ const validFileTypes = [ FileType . File , FileType . Directory ] ;
1027
+
1028
+ for ( const [ index , entry ] of entries . entries ( ) ) {
1029
+ progress ( {
1030
+ step : index + 1 ,
1031
+ maxStep : entries . length ,
1032
+ message : `Importing '${ entry [ 0 ] } '` ,
1033
+ } ) ;
1034
+
1035
+ const subProgress : ProgressCallback = ( p ) => {
1036
+ progress ( {
1037
+ step : index + 1 ,
1038
+ maxStep : entries . length ,
1039
+ message : `Importing '${ entry [ 0 ] } ': (${ p . step } /${ p . maxStep } ) ${ p . message } ` ,
1040
+ } ) ;
1041
+ } ;
1042
+
1043
+ if ( ! validFileTypes . includes ( entry [ 1 ] ) ) {
1044
+ void this . app . logger . log (
1045
+ `Skipping import for '${ entry } ', invalid file type: ${ entry [ 1 ] } ` ,
1046
+ ) ;
1047
+ continue ;
1048
+ }
1049
+
1050
+ try {
1051
+ const databaseUri = Uri . joinPath ( uri , entry [ 0 ] ) ;
1052
+ void this . app . logger . log ( `Importing from ${ databaseUri } ` ) ;
1053
+
1054
+ const database = await this . importDatabase (
1055
+ databaseUri ,
1056
+ entry [ 1 ] === FileType . Directory ,
1057
+ subProgress ,
1058
+ ) ;
1059
+ if ( database ) {
1060
+ databases . push ( database ) ;
1061
+ } else {
1062
+ failures . push ( entry [ 0 ] ) ;
1063
+ }
1064
+ } catch ( e ) {
1065
+ failures . push ( `${ entry [ 0 ] } : ${ getErrorMessage ( e ) } ` . trim ( ) ) ;
1066
+ }
1067
+ }
1068
+
1069
+ if ( failures . length ) {
1070
+ void showAndLogErrorMessage (
1071
+ this . app . logger ,
1072
+ `Failed to import ${ failures . length } database(s), successfully imported ${ databases . length } database(s).` ,
1073
+ {
1074
+ fullMessage : `Failed to import ${ failures . length } database(s), successfully imported ${ databases . length } database(s).\nFailed databases:\n - ${ failures . join ( "\n - " ) } ` ,
1075
+ } ,
1076
+ ) ;
1077
+ } else if ( databases . length === 0 ) {
1078
+ void showAndLogErrorMessage (
1079
+ this . app . logger ,
1080
+ `No database folder to import.` ,
1081
+ ) ;
1082
+ return undefined ;
1083
+ } else {
1084
+ void showAndLogInformationMessage (
1085
+ this . app . logger ,
1086
+ `Successfully imported ${ databases . length } database(s).` ,
1087
+ ) ;
1088
+ }
1089
+
1090
+ return databases ;
1091
+ }
1092
+
989
1093
/**
990
1094
* Perform some heuristics to ensure a proper database location is chosen.
991
1095
*
0 commit comments