From 1196902adc2b85b567cccc901600475d2cab956d Mon Sep 17 00:00:00 2001 From: reito Date: Thu, 7 Nov 2024 21:50:15 +0800 Subject: [PATCH 01/11] Allow import all database subfolders by selecting a folder --- extensions/ql-vscode/CHANGELOG.md | 2 + extensions/ql-vscode/package.json | 4 + extensions/ql-vscode/src/common/commands.ts | 1 + .../src/databases/local-databases-ui.ts | 92 +++++++++++++++---- 4 files changed, 81 insertions(+), 18 deletions(-) diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 6f54f563141..66738f15fc7 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -2,6 +2,8 @@ ## [UNRELEASED] +- Add a palette command that allow user to select a folder and import all database subfolders. + ## 1.16.1 - 6 November 2024 - Support result columns of type `QlBuiltins::BigInt` in quick evaluations. [#3647](https://github.com/github/vscode-codeql/pull/3647) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index e1b00099593..f6d77400444 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -839,6 +839,10 @@ "command": "codeQL.chooseDatabaseFolder", "title": "CodeQL: Choose Database from Folder" }, + { + "command": "codeQL.chooseMultipleDatabaseFolder", + "title": "CodeQL: Choose Folder contains all Database Folders to import" + }, { "command": "codeQL.chooseDatabaseArchive", "title": "CodeQL: Choose Database from Archive" diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 7b1cadcda7b..afe36d3b24d 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -211,6 +211,7 @@ export type LanguageSelectionCommands = { export type LocalDatabasesCommands = { // Command palette commands "codeQL.chooseDatabaseFolder": () => Promise; + "codeQL.chooseMultipleDatabaseFolder": () => Promise; "codeQL.chooseDatabaseArchive": () => Promise; "codeQL.chooseDatabaseInternet": () => Promise; "codeQL.chooseDatabaseGithub": () => Promise; diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index 8a12983951c..353259b5d63 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -16,6 +16,7 @@ import { ThemeIcon, ThemeColor, workspace, + FileType, } from "vscode"; import { pathExists, stat, readdir, remove } from "fs-extra"; @@ -36,6 +37,7 @@ import { import { showAndLogExceptionWithTelemetry, showAndLogErrorMessage, + showAndLogInformationMessage, } from "../common/logging"; import type { DatabaseFetcher } from "./database-fetcher"; import { asError, asyncFilter, getErrorMessage } from "../common/helpers-pure"; @@ -267,6 +269,8 @@ export class DatabaseUI extends DisposableObject { "codeQL.getCurrentDatabase": this.handleGetCurrentDatabase.bind(this), "codeQL.chooseDatabaseFolder": this.handleChooseDatabaseFolderFromPalette.bind(this), + "codeQL.chooseMultipleDatabaseFolder": + this.handleChooseMultipleDatabaseFolderFromPalette.bind(this), "codeQL.chooseDatabaseArchive": this.handleChooseDatabaseArchiveFromPalette.bind(this), "codeQL.chooseDatabaseInternet": @@ -322,10 +326,11 @@ export class DatabaseUI extends DisposableObject { } private async chooseDatabaseFolder( + subFolder: boolean, progress: ProgressCallback, ): Promise { try { - await this.chooseAndSetDatabase(true, progress); + await this.chooseAndSetDatabase(true, subFolder, progress); } catch (e) { void showAndLogExceptionWithTelemetry( this.app.logger, @@ -340,7 +345,7 @@ export class DatabaseUI extends DisposableObject { private async handleChooseDatabaseFolder(): Promise { return withProgress( async (progress) => { - await this.chooseDatabaseFolder(progress); + await this.chooseDatabaseFolder(false, progress); }, { title: "Adding database from folder", @@ -351,7 +356,7 @@ export class DatabaseUI extends DisposableObject { private async handleChooseDatabaseFolderFromPalette(): Promise { return withProgress( async (progress) => { - await this.chooseDatabaseFolder(progress); + await this.chooseDatabaseFolder(false, progress); }, { title: "Choose a Database from a Folder", @@ -359,6 +364,17 @@ export class DatabaseUI extends DisposableObject { ); } + private async handleChooseMultipleDatabaseFolderFromPalette(): Promise { + return withProgress( + async (progress) => { + await this.chooseDatabaseFolder(true, progress); + }, + { + title: "Choose a Folder contains all Database Folders", + }, + ); + } + private async handleSetDefaultTourDatabase(): Promise { return withProgress( async () => { @@ -494,7 +510,7 @@ export class DatabaseUI extends DisposableObject { progress: ProgressCallback, ): Promise { try { - await this.chooseAndSetDatabase(false, progress); + await this.chooseAndSetDatabase(false, false, progress); } catch (e: unknown) { void showAndLogExceptionWithTelemetry( this.app.logger, @@ -962,27 +978,67 @@ export class DatabaseUI extends DisposableObject { */ private async chooseAndSetDatabase( byFolder: boolean, + subFolder: boolean, progress: ProgressCallback, - ): Promise { + ): Promise { const uri = await chooseDatabaseDir(byFolder); if (!uri) { return undefined; } - if (byFolder && !uri.fsPath.endsWith("testproj")) { - const fixedUri = await this.fixDbUri(uri); - // we are selecting a database folder - return await this.databaseManager.openDatabase(fixedUri, { - type: "folder", - }); + if (subFolder) { + if (!byFolder) { + return undefined; + } + + const databases: DatabaseItem[] = []; + const failures: string[] = []; + const entries = await workspace.fs.readDirectory(uri); + for (const entry of entries) { + if (entry[1] === FileType.Directory) { + try { + const fixedUri = await this.fixDbUri(Uri.joinPath(uri, entry[0])); + const database = await this.databaseManager.openDatabase(fixedUri, { + type: "folder", + }); + databases.push(database); + } catch (e) { + failures.push(entry[0]); + } + } + } + + if (failures.length) { + void showAndLogErrorMessage( + this.app.logger, + `Failed to import ${failures.length} database(s) (${failures.join( + ", ", + )}), successfully imported ${databases.length} database(s).`, + ); + } else { + void showAndLogInformationMessage( + this.app.logger, + `Successfully imported ${databases.length} database(s).`, + ); + } + + return databases; } else { - // we are selecting a database archive or a testproj. - // Unzip archives (if an archive) and copy into a workspace-controlled area - // before importing. - return await this.databaseFetcher.importLocalDatabase( - uri.toString(true), - progress, - ); + if (byFolder && !uri.fsPath.endsWith("testproj")) { + const fixedUri = await this.fixDbUri(uri); + // we are selecting a database folder + return await this.databaseManager.openDatabase(fixedUri, { + type: "folder", + }); + } else { + // we are selecting a database archive or a testproj. + // Unzip archives (if an archive) and copy into a workspace-controlled area + // before importing. + return await this.databaseFetcher.importLocalDatabase( + uri.toString(true), + progress, + ); + } } } From b1462ffbb03c4a6c869d72da0f760530754c16c1 Mon Sep 17 00:00:00 2001 From: reito Date: Tue, 12 Nov 2024 23:46:58 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20CHANGELOG.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Eisenberg --- extensions/ql-vscode/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 66738f15fc7..1ccd70b9644 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -2,7 +2,7 @@ ## [UNRELEASED] -- Add a palette command that allow user to select a folder and import all database subfolders. +- Add a palette command that allows importing of all databases inside of a parent folder. [3797](https://github.com/github/vscode-codeql/pull/3797) ## 1.16.1 - 6 November 2024 From 7a7e4e70b61fcc177118a700d86ca414a2829edd Mon Sep 17 00:00:00 2001 From: reito Date: Tue, 12 Nov 2024 23:47:13 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20package.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Eisenberg --- extensions/ql-vscode/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index f6d77400444..a983d94f0f5 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -841,7 +841,7 @@ }, { "command": "codeQL.chooseMultipleDatabaseFolder", - "title": "CodeQL: Choose Folder contains all Database Folders to import" + "title": "CodeQL: Choose Folder to import all databases contained in it" }, { "command": "codeQL.chooseDatabaseArchive", From 42e5696584834d17369da6ca7bc92b79cb027d4c Mon Sep 17 00:00:00 2001 From: reito Date: Wed, 13 Nov 2024 11:32:30 +0800 Subject: [PATCH 04/11] feat: move import folders out of original function, optimize logs --- .../src/databases/local-databases-ui.ts | 120 ++++++++++-------- 1 file changed, 65 insertions(+), 55 deletions(-) diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index 353259b5d63..d4f3ff0d0fe 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -326,11 +326,10 @@ export class DatabaseUI extends DisposableObject { } private async chooseDatabaseFolder( - subFolder: boolean, progress: ProgressCallback, ): Promise { try { - await this.chooseAndSetDatabase(true, subFolder, progress); + await this.chooseAndSetDatabase(true, progress); } catch (e) { void showAndLogExceptionWithTelemetry( this.app.logger, @@ -345,7 +344,7 @@ export class DatabaseUI extends DisposableObject { private async handleChooseDatabaseFolder(): Promise { return withProgress( async (progress) => { - await this.chooseDatabaseFolder(false, progress); + await this.chooseDatabaseFolder(progress); }, { title: "Adding database from folder", @@ -356,7 +355,7 @@ export class DatabaseUI extends DisposableObject { private async handleChooseDatabaseFolderFromPalette(): Promise { return withProgress( async (progress) => { - await this.chooseDatabaseFolder(false, progress); + await this.chooseDatabaseFolder(progress); }, { title: "Choose a Database from a Folder", @@ -367,7 +366,7 @@ export class DatabaseUI extends DisposableObject { private async handleChooseMultipleDatabaseFolderFromPalette(): Promise { return withProgress( async (progress) => { - await this.chooseDatabaseFolder(true, progress); + await this.chooseDatabasesParentFolder(progress); }, { title: "Choose a Folder contains all Database Folders", @@ -510,7 +509,7 @@ export class DatabaseUI extends DisposableObject { progress: ProgressCallback, ): Promise { try { - await this.chooseAndSetDatabase(false, false, progress); + await this.chooseAndSetDatabase(false, progress); } catch (e: unknown) { void showAndLogExceptionWithTelemetry( this.app.logger, @@ -978,7 +977,6 @@ export class DatabaseUI extends DisposableObject { */ private async chooseAndSetDatabase( byFolder: boolean, - subFolder: boolean, progress: ProgressCallback, ): Promise { const uri = await chooseDatabaseDir(byFolder); @@ -986,60 +984,72 @@ export class DatabaseUI extends DisposableObject { return undefined; } - if (subFolder) { - if (!byFolder) { - return undefined; - } + if (byFolder && !uri.fsPath.endsWith("testproj")) { + const fixedUri = await this.fixDbUri(uri); + // we are selecting a database folder + return await this.databaseManager.openDatabase(fixedUri, { + type: "folder", + }); + } else { + // we are selecting a database archive or a testproj. + // Unzip archives (if an archive) and copy into a workspace-controlled area + // before importing. + return await this.databaseFetcher.importLocalDatabase( + uri.toString(true), + progress, + ); + } + } - const databases: DatabaseItem[] = []; - const failures: string[] = []; - const entries = await workspace.fs.readDirectory(uri); - for (const entry of entries) { - if (entry[1] === FileType.Directory) { - try { - const fixedUri = await this.fixDbUri(Uri.joinPath(uri, entry[0])); - const database = await this.databaseManager.openDatabase(fixedUri, { - type: "folder", - }); - databases.push(database); - } catch (e) { - failures.push(entry[0]); - } - } - } + /** + * Ask the user for a parent directory that contains all databases. + * Returns all valid databases, or `undefined` if the operation was canceled. + */ + private async chooseDatabasesParentFolder( + progress: ProgressCallback, + ): Promise { + const uri = await chooseDatabaseDir(true); + if (!uri) { + return undefined; + } - if (failures.length) { - void showAndLogErrorMessage( - this.app.logger, - `Failed to import ${failures.length} database(s) (${failures.join( - ", ", - )}), successfully imported ${databases.length} database(s).`, - ); - } else { - void showAndLogInformationMessage( - this.app.logger, - `Successfully imported ${databases.length} database(s).`, - ); + const databases: DatabaseItem[] = []; + const failures: string[] = []; + const entries = await workspace.fs.readDirectory(uri); + for (const [index, entry] of entries.entries()) { + progress({ + step: index + 1, + maxStep: entries.length, + message: `Importing ${entry[0]}`, + }); + + if (entry[1] === FileType.Directory) { + try { + const fixedUri = await this.fixDbUri(Uri.joinPath(uri, entry[0])); + const database = await this.databaseManager.openDatabase(fixedUri, { + type: "folder", + }); + databases.push(database); + } catch (e) { + failures.push(entry[0]); + } } + } - return databases; + if (failures.length) { + void showAndLogErrorMessage( + this.app.logger, + `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s).`, + { fullMessage: `Failed imports: \n${failures.join("\n")}` }, + ); } else { - if (byFolder && !uri.fsPath.endsWith("testproj")) { - const fixedUri = await this.fixDbUri(uri); - // we are selecting a database folder - return await this.databaseManager.openDatabase(fixedUri, { - type: "folder", - }); - } else { - // we are selecting a database archive or a testproj. - // Unzip archives (if an archive) and copy into a workspace-controlled area - // before importing. - return await this.databaseFetcher.importLocalDatabase( - uri.toString(true), - progress, - ); - } + void showAndLogInformationMessage( + this.app.logger, + `Successfully imported ${databases.length} database(s).`, + ); } + + return databases; } /** From c4233ef052e0873ba45aceecb676cf949de3b828 Mon Sep 17 00:00:00 2001 From: reito Date: Wed, 13 Nov 2024 11:38:17 +0800 Subject: [PATCH 05/11] feat: skip 0 folders --- extensions/ql-vscode/src/databases/local-databases-ui.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index d4f3ff0d0fe..66c29a88805 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -1016,6 +1016,7 @@ export class DatabaseUI extends DisposableObject { const databases: DatabaseItem[] = []; const failures: string[] = []; const entries = await workspace.fs.readDirectory(uri); + for (const [index, entry] of entries.entries()) { progress({ step: index + 1, @@ -1040,8 +1041,14 @@ export class DatabaseUI extends DisposableObject { void showAndLogErrorMessage( this.app.logger, `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s).`, - { fullMessage: `Failed imports: \n${failures.join("\n")}` }, + { fullMessage: `Failed folders to import:\n${failures.join("\n")}` }, ); + } else if (databases.length === 0) { + void showAndLogErrorMessage( + this.app.logger, + `No database folder to import.`, + ); + return undefined; } else { void showAndLogInformationMessage( this.app.logger, From db38f7236298f60bacc4dad1febbacfaea0da0d6 Mon Sep 17 00:00:00 2001 From: reito Date: Wed, 13 Nov 2024 11:45:03 +0800 Subject: [PATCH 06/11] fix: revert extra return type --- extensions/ql-vscode/src/databases/local-databases-ui.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index 66c29a88805..6263475615f 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -978,7 +978,7 @@ export class DatabaseUI extends DisposableObject { private async chooseAndSetDatabase( byFolder: boolean, progress: ProgressCallback, - ): Promise { + ): Promise { const uri = await chooseDatabaseDir(byFolder); if (!uri) { return undefined; From ce0b25feae469d7efd4f6aeef477f4dc6fb1213a Mon Sep 17 00:00:00 2001 From: reito Date: Wed, 13 Nov 2024 11:47:30 +0800 Subject: [PATCH 07/11] fix: unify naming --- extensions/ql-vscode/package.json | 2 +- extensions/ql-vscode/src/common/commands.ts | 2 +- extensions/ql-vscode/src/databases/local-databases-ui.ts | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index a983d94f0f5..d441b85de29 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -840,7 +840,7 @@ "title": "CodeQL: Choose Database from Folder" }, { - "command": "codeQL.chooseMultipleDatabaseFolder", + "command": "codeQL.chooseDatabaseFoldersParent", "title": "CodeQL: Choose Folder to import all databases contained in it" }, { diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index afe36d3b24d..14d173070f3 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -211,7 +211,7 @@ export type LanguageSelectionCommands = { export type LocalDatabasesCommands = { // Command palette commands "codeQL.chooseDatabaseFolder": () => Promise; - "codeQL.chooseMultipleDatabaseFolder": () => Promise; + "codeQL.chooseDatabaseFoldersParent": () => Promise; "codeQL.chooseDatabaseArchive": () => Promise; "codeQL.chooseDatabaseInternet": () => Promise; "codeQL.chooseDatabaseGithub": () => Promise; diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index 6263475615f..b0484a57093 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -269,8 +269,8 @@ export class DatabaseUI extends DisposableObject { "codeQL.getCurrentDatabase": this.handleGetCurrentDatabase.bind(this), "codeQL.chooseDatabaseFolder": this.handleChooseDatabaseFolderFromPalette.bind(this), - "codeQL.chooseMultipleDatabaseFolder": - this.handleChooseMultipleDatabaseFolderFromPalette.bind(this), + "codeQL.chooseDatabaseFoldersParent": + this.handleChooseDatabaseFoldersParentFromPalette.bind(this), "codeQL.chooseDatabaseArchive": this.handleChooseDatabaseArchiveFromPalette.bind(this), "codeQL.chooseDatabaseInternet": @@ -363,7 +363,7 @@ export class DatabaseUI extends DisposableObject { ); } - private async handleChooseMultipleDatabaseFolderFromPalette(): Promise { + private async handleChooseDatabaseFoldersParentFromPalette(): Promise { return withProgress( async (progress) => { await this.chooseDatabasesParentFolder(progress); From 8f81119159ac7ad19cef2e3e1a1416c34e42db14 Mon Sep 17 00:00:00 2001 From: reito Date: Thu, 14 Nov 2024 00:21:48 +0800 Subject: [PATCH 08/11] Apply suggestions from code review Co-authored-by: Andrew Eisenberg --- extensions/ql-vscode/package.json | 2 +- extensions/ql-vscode/src/databases/local-databases-ui.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index d441b85de29..0fb562f290b 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -841,7 +841,7 @@ }, { "command": "codeQL.chooseDatabaseFoldersParent", - "title": "CodeQL: Choose Folder to import all databases contained in it" + "title": "CodeQL: Choose Parent Folder and import all databases directly contained in it" }, { "command": "codeQL.chooseDatabaseArchive", diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index b0484a57093..2f720bbc1de 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -1041,7 +1041,7 @@ export class DatabaseUI extends DisposableObject { void showAndLogErrorMessage( this.app.logger, `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s).`, - { fullMessage: `Failed folders to import:\n${failures.join("\n")}` }, + { fullMessage: `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s). Failed folders to import:\n ${failures.join("\n ")}` }, ); } else if (databases.length === 0) { void showAndLogErrorMessage( From fa43f4f72ffc92fbde2b749ba32b9eaceab5a2cc Mon Sep 17 00:00:00 2001 From: reito Date: Thu, 14 Nov 2024 00:43:32 +0800 Subject: [PATCH 09/11] feat: extract common logic --- .../src/databases/local-databases-ui.ts | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index 2f720bbc1de..a28a02a18a1 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -972,18 +972,14 @@ export class DatabaseUI extends DisposableObject { } /** - * Ask the user for a database directory. Returns the chosen database, or `undefined` if the - * operation was canceled. + * Import database from uri. Returns the imported database, or `undefined` if the + * operation was unsuccessful. */ - private async chooseAndSetDatabase( + private async importDatabase( + uri: Uri, byFolder: boolean, progress: ProgressCallback, ): Promise { - const uri = await chooseDatabaseDir(byFolder); - if (!uri) { - return undefined; - } - if (byFolder && !uri.fsPath.endsWith("testproj")) { const fixedUri = await this.fixDbUri(uri); // we are selecting a database folder @@ -1001,6 +997,22 @@ export class DatabaseUI extends DisposableObject { } } + /** + * Ask the user for a database directory. Returns the chosen database, or `undefined` if the + * operation was canceled. + */ + private async chooseAndSetDatabase( + byFolder: boolean, + progress: ProgressCallback, + ): Promise { + const uri = await chooseDatabaseDir(byFolder); + if (!uri) { + return undefined; + } + + return await this.importDatabase(uri, byFolder, progress); + } + /** * Ask the user for a parent directory that contains all databases. * Returns all valid databases, or `undefined` if the operation was canceled. @@ -1024,16 +1036,28 @@ export class DatabaseUI extends DisposableObject { message: `Importing ${entry[0]}`, }); - if (entry[1] === FileType.Directory) { - try { - const fixedUri = await this.fixDbUri(Uri.joinPath(uri, entry[0])); - const database = await this.databaseManager.openDatabase(fixedUri, { - type: "folder", - }); + const subProgress: ProgressCallback = (p) => { + progress({ + step: index + 1, + maxStep: entries.length, + message: `Importing ${entry[0]} (${p.step}/${p.maxStep}): ${p.message}`, + }); + }; + + try { + const fixedUri = await this.fixDbUri(Uri.joinPath(uri, entry[0])); + const database = await this.importDatabase( + fixedUri, + entry[1] === FileType.Directory, + subProgress, + ); + if (database) { databases.push(database); - } catch (e) { + } else { failures.push(entry[0]); } + } catch (e) { + failures.push(entry[0]); } } @@ -1041,7 +1065,9 @@ export class DatabaseUI extends DisposableObject { void showAndLogErrorMessage( this.app.logger, `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s).`, - { fullMessage: `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s). Failed folders to import:\n ${failures.join("\n ")}` }, + { + fullMessage: `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s). Failed folders to import:\n - ${failures.join("\n - ")}`, + }, ); } else if (databases.length === 0) { void showAndLogErrorMessage( From 2aa0775073b164d0ba0aaf9b52bc22cdb505d511 Mon Sep 17 00:00:00 2001 From: reito Date: Thu, 14 Nov 2024 00:59:02 +0800 Subject: [PATCH 10/11] fix: testproj need to be with a dot --- .../src/databases/local-databases-ui.ts | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index a28a02a18a1..dfff074f661 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -980,14 +980,14 @@ export class DatabaseUI extends DisposableObject { byFolder: boolean, progress: ProgressCallback, ): Promise { - if (byFolder && !uri.fsPath.endsWith("testproj")) { + if (byFolder && !uri.fsPath.endsWith(".testproj")) { const fixedUri = await this.fixDbUri(uri); // we are selecting a database folder return await this.databaseManager.openDatabase(fixedUri, { type: "folder", }); } else { - // we are selecting a database archive or a testproj. + // we are selecting a database archive or a .testproj. // Unzip archives (if an archive) and copy into a workspace-controlled area // before importing. return await this.databaseFetcher.importLocalDatabase( @@ -1028,6 +1028,7 @@ export class DatabaseUI extends DisposableObject { const databases: DatabaseItem[] = []; const failures: string[] = []; const entries = await workspace.fs.readDirectory(uri); + const validFileTypes = [FileType.File, FileType.Directory]; for (const [index, entry] of entries.entries()) { progress({ @@ -1044,10 +1045,19 @@ export class DatabaseUI extends DisposableObject { }); }; + if (!validFileTypes.includes(entry[1])) { + void this.app.logger.log( + `Skip import ${entry}, invalid FileType: ${entry[1]}`, + ); + continue; + } + try { - const fixedUri = await this.fixDbUri(Uri.joinPath(uri, entry[0])); + const databaseUri = Uri.joinPath(uri, entry[0]); + void this.app.logger.log(`Importing from ${databaseUri}`); + const database = await this.importDatabase( - fixedUri, + databaseUri, entry[1] === FileType.Directory, subProgress, ); @@ -1056,7 +1066,7 @@ export class DatabaseUI extends DisposableObject { } else { failures.push(entry[0]); } - } catch (e) { + } catch { failures.push(entry[0]); } } From d45792c21f1946a1bcd712b1eb3e1272f3fd7f7a Mon Sep 17 00:00:00 2001 From: reito Date: Thu, 14 Nov 2024 01:02:48 +0800 Subject: [PATCH 11/11] fix: unify descriptions. --- extensions/ql-vscode/src/databases/local-databases-ui.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index dfff074f661..7aa1aab3824 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -369,7 +369,7 @@ export class DatabaseUI extends DisposableObject { await this.chooseDatabasesParentFolder(progress); }, { - title: "Choose a Folder contains all Database Folders", + title: "Choose a Parent Folder contains all Databases to import", }, ); } @@ -1076,7 +1076,7 @@ export class DatabaseUI extends DisposableObject { this.app.logger, `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s).`, { - fullMessage: `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s). Failed folders to import:\n - ${failures.join("\n - ")}`, + fullMessage: `Failed to import ${failures.length} database(s), successfully imported ${databases.length} database(s).\nFailed databases to import:\n - ${failures.join("\n - ")}`, }, ); } else if (databases.length === 0) {