From 706c6b8a7aa8030f42586797fac598ad65bc86a2 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 12 Jun 2023 10:59:42 +0200 Subject: [PATCH] Move qlpacks helpers to separate file --- extensions/ql-vscode/src/databases/qlpack.ts | 130 ++++++++++++++++++ extensions/ql-vscode/src/helpers.ts | 126 +---------------- .../contextual/query-resolver.ts | 8 +- .../src/local-queries/quick-query.ts | 8 +- .../cli-integration/run-cli.test.ts | 2 +- .../contextual/query-resolver.test.ts | 9 +- 6 files changed, 144 insertions(+), 139 deletions(-) create mode 100644 extensions/ql-vscode/src/databases/qlpack.ts diff --git a/extensions/ql-vscode/src/databases/qlpack.ts b/extensions/ql-vscode/src/databases/qlpack.ts new file mode 100644 index 000000000..357ef49c4 --- /dev/null +++ b/extensions/ql-vscode/src/databases/qlpack.ts @@ -0,0 +1,130 @@ +import { window } from "vscode"; +import { glob } from "glob"; +import { basename } from "path"; +import { load } from "js-yaml"; +import { readFile } from "fs-extra"; +import { getQlPackPath } from "../pure/ql"; +import { CodeQLCliServer, QlpacksInfo } from "../codeql-cli/cli"; +import { extLogger } from "../common"; +import { getOnDiskWorkspaceFolders } from "../helpers"; + +export interface QlPacksForLanguage { + /** The name of the pack containing the dbscheme. */ + dbschemePack: string; + /** `true` if `dbschemePack` is a library pack. */ + dbschemePackIsLibraryPack: boolean; + /** + * The name of the corresponding standard query pack. + * Only defined if `dbschemePack` is a library pack. + */ + queryPack?: string; +} + +interface QlPackWithPath { + packName: string; + packDir: string | undefined; +} + +async function findDbschemePack( + packs: QlPackWithPath[], + dbschemePath: string, +): Promise<{ name: string; isLibraryPack: boolean }> { + for (const { packDir, packName } of packs) { + if (packDir !== undefined) { + const qlpackPath = await getQlPackPath(packDir); + + if (qlpackPath !== undefined) { + const qlpack = load(await readFile(qlpackPath, "utf8")) as { + dbscheme?: string; + library?: boolean; + }; + if ( + qlpack.dbscheme !== undefined && + basename(qlpack.dbscheme) === basename(dbschemePath) + ) { + return { + name: packName, + isLibraryPack: qlpack.library === true, + }; + } + } + } + } + throw new Error(`Could not find qlpack file for dbscheme ${dbschemePath}`); +} + +function findStandardQueryPack( + qlpacks: QlpacksInfo, + dbschemePackName: string, +): string | undefined { + const matches = dbschemePackName.match(/^codeql\/(?[a-z]+)-all$/); + if (matches) { + const queryPackName = `codeql/${matches.groups!.language}-queries`; + if (qlpacks[queryPackName] !== undefined) { + return queryPackName; + } + } + + // Either the dbscheme pack didn't look like one where the queries might be in the query pack, or + // no query pack was found in the search path. Either is OK. + return undefined; +} + +export async function getQlPackForDbscheme( + cliServer: Pick, + dbschemePath: string, +): Promise { + const qlpacks = await cliServer.resolveQlpacks(getOnDiskWorkspaceFolders()); + const packs: QlPackWithPath[] = Object.entries(qlpacks).map( + ([packName, dirs]) => { + if (dirs.length < 1) { + void extLogger.log( + `In getQlPackFor ${dbschemePath}, qlpack ${packName} has no directories`, + ); + return { packName, packDir: undefined }; + } + if (dirs.length > 1) { + void extLogger.log( + `In getQlPackFor ${dbschemePath}, qlpack ${packName} has more than one directory; arbitrarily choosing the first`, + ); + } + return { + packName, + packDir: dirs[0], + }; + }, + ); + const dbschemePack = await findDbschemePack(packs, dbschemePath); + const queryPack = dbschemePack.isLibraryPack + ? findStandardQueryPack(qlpacks, dbschemePack.name) + : undefined; + return { + dbschemePack: dbschemePack.name, + dbschemePackIsLibraryPack: dbschemePack.isLibraryPack, + queryPack, + }; +} + +export async function getPrimaryDbscheme( + datasetFolder: string, +): Promise { + const dbschemes = await glob("*.dbscheme", { + cwd: datasetFolder, + }); + + if (dbschemes.length < 1) { + throw new Error( + `Can't find dbscheme for current database in ${datasetFolder}`, + ); + } + + dbschemes.sort(); + const dbscheme = dbschemes[0]; + + if (dbschemes.length > 1) { + void window.showErrorMessage( + `Found multiple dbschemes in ${datasetFolder} during quick query; arbitrarily choosing the first, ${dbscheme}, to decide what library to use.`, + ); + } + return dbscheme; +} diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index 780512f0f..17a58c3da 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -1,23 +1,20 @@ import { ensureDirSync, - readFile, pathExists, ensureDir, writeFile, opendir, } from "fs-extra"; import { glob } from "glob"; -import { load } from "js-yaml"; import { join, basename, dirname } from "path"; import { dirSync } from "tmp-promise"; import { Uri, window as Window, workspace, env, WorkspaceFolder } from "vscode"; -import { CodeQLCliServer, QlpacksInfo } from "./codeql-cli/cli"; +import { CodeQLCliServer } from "./codeql-cli/cli"; import { UserCancellationException } from "./common/vscode/progress"; import { extLogger, OutputChannelLogger } from "./common"; import { QueryMetadata } from "./pure/interface-types"; import { telemetryListener } from "./telemetry"; import { RedactableError } from "./pure/errors"; -import { getQlPackPath } from "./pure/ql"; import { dbSchemeToLanguage, QueryLanguage } from "./common/query-language"; import { isCodespacesTemplate } from "./config"; import { AppCommandManager } from "./common/commands"; @@ -356,127 +353,6 @@ export async function prepareCodeTour( } } -export interface QlPacksForLanguage { - /** The name of the pack containing the dbscheme. */ - dbschemePack: string; - /** `true` if `dbschemePack` is a library pack. */ - dbschemePackIsLibraryPack: boolean; - /** - * The name of the corresponding standard query pack. - * Only defined if `dbschemePack` is a library pack. - */ - queryPack?: string; -} - -interface QlPackWithPath { - packName: string; - packDir: string | undefined; -} - -async function findDbschemePack( - packs: QlPackWithPath[], - dbschemePath: string, -): Promise<{ name: string; isLibraryPack: boolean }> { - for (const { packDir, packName } of packs) { - if (packDir !== undefined) { - const qlpackPath = await getQlPackPath(packDir); - - if (qlpackPath !== undefined) { - const qlpack = load(await readFile(qlpackPath, "utf8")) as { - dbscheme?: string; - library?: boolean; - }; - if ( - qlpack.dbscheme !== undefined && - basename(qlpack.dbscheme) === basename(dbschemePath) - ) { - return { - name: packName, - isLibraryPack: qlpack.library === true, - }; - } - } - } - } - throw new Error(`Could not find qlpack file for dbscheme ${dbschemePath}`); -} - -function findStandardQueryPack( - qlpacks: QlpacksInfo, - dbschemePackName: string, -): string | undefined { - const matches = dbschemePackName.match(/^codeql\/(?[a-z]+)-all$/); - if (matches) { - const queryPackName = `codeql/${matches.groups!.language}-queries`; - if (qlpacks[queryPackName] !== undefined) { - return queryPackName; - } - } - - // Either the dbscheme pack didn't look like one where the queries might be in the query pack, or - // no query pack was found in the search path. Either is OK. - return undefined; -} - -export async function getQlPackForDbscheme( - cliServer: Pick, - dbschemePath: string, -): Promise { - const qlpacks = await cliServer.resolveQlpacks(getOnDiskWorkspaceFolders()); - const packs: QlPackWithPath[] = Object.entries(qlpacks).map( - ([packName, dirs]) => { - if (dirs.length < 1) { - void extLogger.log( - `In getQlPackFor ${dbschemePath}, qlpack ${packName} has no directories`, - ); - return { packName, packDir: undefined }; - } - if (dirs.length > 1) { - void extLogger.log( - `In getQlPackFor ${dbschemePath}, qlpack ${packName} has more than one directory; arbitrarily choosing the first`, - ); - } - return { - packName, - packDir: dirs[0], - }; - }, - ); - const dbschemePack = await findDbschemePack(packs, dbschemePath); - const queryPack = dbschemePack.isLibraryPack - ? findStandardQueryPack(qlpacks, dbschemePack.name) - : undefined; - return { - dbschemePack: dbschemePack.name, - dbschemePackIsLibraryPack: dbschemePack.isLibraryPack, - queryPack, - }; -} - -export async function getPrimaryDbscheme( - datasetFolder: string, -): Promise { - const dbschemes = await glob("*.dbscheme", { - cwd: datasetFolder, - }); - - if (dbschemes.length < 1) { - throw new Error( - `Can't find dbscheme for current database in ${datasetFolder}`, - ); - } - - dbschemes.sort(); - const dbscheme = dbschemes[0]; - - if (dbschemes.length > 1) { - void Window.showErrorMessage( - `Found multiple dbschemes in ${datasetFolder} during quick query; arbitrarily choosing the first, ${dbscheme}, to decide what library to use.`, - ); - } - return dbscheme; -} - /** * The following functions al heuristically determine metadata about databases. */ diff --git a/extensions/ql-vscode/src/language-support/contextual/query-resolver.ts b/extensions/ql-vscode/src/language-support/contextual/query-resolver.ts index 7cb3f398b..d5c79fde7 100644 --- a/extensions/ql-vscode/src/language-support/contextual/query-resolver.ts +++ b/extensions/ql-vscode/src/language-support/contextual/query-resolver.ts @@ -4,12 +4,14 @@ import { file } from "tmp-promise"; import { basename, dirname, resolve } from "path"; import { - getPrimaryDbscheme, - getQlPackForDbscheme, getOnDiskWorkspaceFolders, - QlPacksForLanguage, showAndLogExceptionWithTelemetry, } from "../../helpers"; +import { + getPrimaryDbscheme, + getQlPackForDbscheme, + QlPacksForLanguage, +} from "../../databases/qlpack"; import { KeyType, kindOfKeyType, diff --git a/extensions/ql-vscode/src/local-queries/quick-query.ts b/extensions/ql-vscode/src/local-queries/quick-query.ts index cdf392330..e62fed2b3 100644 --- a/extensions/ql-vscode/src/local-queries/quick-query.ts +++ b/extensions/ql-vscode/src/local-queries/quick-query.ts @@ -5,12 +5,8 @@ import { CancellationToken, window as Window, workspace, Uri } from "vscode"; import { LSPErrorCodes, ResponseError } from "vscode-languageclient"; import { CodeQLCliServer } from "../codeql-cli/cli"; import { DatabaseUI } from "../databases/local-databases-ui"; -import { - getInitialQueryContents, - getPrimaryDbscheme, - getQlPackForDbscheme, - showBinaryChoiceDialog, -} from "../helpers"; +import { getInitialQueryContents, showBinaryChoiceDialog } from "../helpers"; +import { getPrimaryDbscheme, getQlPackForDbscheme } from "../databases/qlpack"; import { ProgressCallback, UserCancellationException, diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/run-cli.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/run-cli.test.ts index 71908530c..e52026dc5 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/run-cli.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/run-cli.test.ts @@ -9,13 +9,13 @@ import { import { itWithCodeQL } from "../cli"; import { getOnDiskWorkspaceFolders, - getQlPackForDbscheme, languageToDbScheme, } from "../../../src/helpers"; import { KeyType, resolveQueries } from "../../../src/language-support"; import { faker } from "@faker-js/faker"; import { getActivatedExtension } from "../global.helper"; import { BaseLogger } from "../../../src/common"; +import { getQlPackForDbscheme } from "../../../src/databases/qlpack"; /** * Perform proper integration tests by running the CLI diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/language-support/contextual/query-resolver.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/language-support/contextual/query-resolver.test.ts index 54448246e..52e19460d 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/language-support/contextual/query-resolver.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/language-support/contextual/query-resolver.test.ts @@ -4,6 +4,7 @@ import * as fs from "fs-extra"; import { getErrorMessage } from "../../../../../src/pure/helpers-pure"; import * as helpers from "../../../../../src/helpers"; +import * as qlpack from "../../../../../src/databases/qlpack"; import { KeyType, qlpackOfDatabase, @@ -14,10 +15,10 @@ import { mockDatabaseItem, mockedObject } from "../../../utils/mocking.helpers"; describe("queryResolver", () => { let getQlPackForDbschemeSpy: jest.SpiedFunction< - typeof helpers.getQlPackForDbscheme + typeof qlpack.getQlPackForDbscheme >; let getPrimaryDbschemeSpy: jest.SpiedFunction< - typeof helpers.getPrimaryDbscheme + typeof qlpack.getPrimaryDbscheme >; const resolveQueriesInSuite = jest.fn(); @@ -28,13 +29,13 @@ describe("queryResolver", () => { beforeEach(() => { getQlPackForDbschemeSpy = jest - .spyOn(helpers, "getQlPackForDbscheme") + .spyOn(qlpack, "getQlPackForDbscheme") .mockResolvedValue({ dbschemePack: "dbschemePack", dbschemePackIsLibraryPack: false, }); getPrimaryDbschemeSpy = jest - .spyOn(helpers, "getPrimaryDbscheme") + .spyOn(qlpack, "getPrimaryDbscheme") .mockResolvedValue("primaryDbscheme"); jest.spyOn(helpers, "getOnDiskWorkspaceFolders").mockReturnValue([]);