Merge pull request #2742 from github/starcke/flow-queries-refactor
Starcke/flow queries refactor
This commit is contained in:
@@ -22,7 +22,7 @@ import {
|
|||||||
import { DatabaseItem, DatabaseManager } from "../databases/local-databases";
|
import { DatabaseItem, DatabaseManager } from "../databases/local-databases";
|
||||||
import { CodeQLCliServer } from "../codeql-cli/cli";
|
import { CodeQLCliServer } from "../codeql-cli/cli";
|
||||||
import { asError, assertNever, getErrorMessage } from "../common/helpers-pure";
|
import { asError, assertNever, getErrorMessage } from "../common/helpers-pure";
|
||||||
import { generateFlowModel } from "./flow-model-queries";
|
import { runFlowModelQueries } from "./flow-model-queries";
|
||||||
import { promptImportGithubDatabase } from "../databases/database-fetcher";
|
import { promptImportGithubDatabase } from "../databases/database-fetcher";
|
||||||
import { App } from "../common/app";
|
import { App } from "../common/app";
|
||||||
import { showResolvableLocation } from "../databases/local-databases/locations";
|
import { showResolvableLocation } from "../databases/local-databases/locations";
|
||||||
@@ -389,7 +389,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await generateFlowModel({
|
await runFlowModelQueries({
|
||||||
cliServer: this.cliServer,
|
cliServer: this.cliServer,
|
||||||
queryRunner: this.queryRunner,
|
queryRunner: this.queryRunner,
|
||||||
queryStorageDir: this.queryStorageDir,
|
queryStorageDir: this.queryStorageDir,
|
||||||
|
|||||||
@@ -3,19 +3,16 @@ import { DatabaseItem } from "../databases/local-databases";
|
|||||||
import { basename } from "path";
|
import { basename } from "path";
|
||||||
import { QueryRunner } from "../query-server";
|
import { QueryRunner } from "../query-server";
|
||||||
import { CodeQLCliServer } from "../codeql-cli/cli";
|
import { CodeQLCliServer } from "../codeql-cli/cli";
|
||||||
import { showAndLogExceptionWithTelemetry, TeeLogger } from "../common/logging";
|
import { showAndLogExceptionWithTelemetry } from "../common/logging";
|
||||||
import { extLogger } from "../common/logging/vscode";
|
import { extLogger } from "../common/logging/vscode";
|
||||||
import { extensiblePredicateDefinitions } from "./predicates";
|
import { extensiblePredicateDefinitions } from "./predicates";
|
||||||
import { ProgressCallback } from "../common/vscode/progress";
|
import { ProgressCallback } from "../common/vscode/progress";
|
||||||
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
|
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
|
||||||
import { ModeledMethod, ModeledMethodType } from "./modeled-method";
|
import { ModeledMethod, ModeledMethodType } from "./modeled-method";
|
||||||
import { redactableError } from "../common/errors";
|
import { redactableError } from "../common/errors";
|
||||||
import { QueryResultType } from "../query-server/new-messages";
|
import { qlpackOfDatabase, resolveQueries } from "../local-queries";
|
||||||
import { file } from "tmp-promise";
|
|
||||||
import { writeFile } from "fs-extra";
|
|
||||||
import { dump } from "js-yaml";
|
|
||||||
import { qlpackOfDatabase } from "../local-queries";
|
|
||||||
import { telemetryListener } from "../common/vscode/telemetry";
|
import { telemetryListener } from "../common/vscode/telemetry";
|
||||||
|
import { runQuery } from "../local-queries/run-query";
|
||||||
|
|
||||||
type FlowModelOptions = {
|
type FlowModelOptions = {
|
||||||
cliServer: CodeQLCliServer;
|
cliServer: CodeQLCliServer;
|
||||||
@@ -27,44 +24,73 @@ type FlowModelOptions = {
|
|||||||
onResults: (results: ModeledMethod[]) => void | Promise<void>;
|
onResults: (results: ModeledMethod[]) => void | Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function resolveQueries(
|
export async function runFlowModelQueries({
|
||||||
|
onResults,
|
||||||
|
...options
|
||||||
|
}: FlowModelOptions) {
|
||||||
|
const queries = await resolveFlowQueries(
|
||||||
|
options.cliServer,
|
||||||
|
options.databaseItem,
|
||||||
|
);
|
||||||
|
|
||||||
|
const queriesByBasename: Record<string, string> = {};
|
||||||
|
for (const query of queries) {
|
||||||
|
queriesByBasename[basename(query)] = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
const summaryResults = await runSingleFlowQuery(
|
||||||
|
"summary",
|
||||||
|
queriesByBasename["CaptureSummaryModels.ql"],
|
||||||
|
0,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
if (summaryResults) {
|
||||||
|
await onResults(summaryResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sinkResults = await runSingleFlowQuery(
|
||||||
|
"sink",
|
||||||
|
queriesByBasename["CaptureSinkModels.ql"],
|
||||||
|
1,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
if (sinkResults) {
|
||||||
|
await onResults(sinkResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourceResults = await runSingleFlowQuery(
|
||||||
|
"source",
|
||||||
|
queriesByBasename["CaptureSourceModels.ql"],
|
||||||
|
2,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
if (sourceResults) {
|
||||||
|
await onResults(sourceResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
const neutralResults = await runSingleFlowQuery(
|
||||||
|
"neutral",
|
||||||
|
queriesByBasename["CaptureNeutralModels.ql"],
|
||||||
|
3,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
if (neutralResults) {
|
||||||
|
await onResults(neutralResults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveFlowQueries(
|
||||||
cliServer: CodeQLCliServer,
|
cliServer: CodeQLCliServer,
|
||||||
databaseItem: DatabaseItem,
|
databaseItem: DatabaseItem,
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
const qlpacks = await qlpackOfDatabase(cliServer, databaseItem);
|
const qlpacks = await qlpackOfDatabase(cliServer, databaseItem);
|
||||||
|
|
||||||
const packsToSearch: string[] = [];
|
return await resolveQueries(cliServer, qlpacks, "flow model generator", {
|
||||||
|
"tags contain": ["modelgenerator"],
|
||||||
// The CLI can handle both library packs and query packs, so search both packs in order.
|
});
|
||||||
packsToSearch.push(qlpacks.dbschemePack);
|
|
||||||
if (qlpacks.queryPack !== undefined) {
|
|
||||||
packsToSearch.push(qlpacks.queryPack);
|
|
||||||
}
|
|
||||||
|
|
||||||
const suiteFile = (
|
|
||||||
await file({
|
|
||||||
postfix: ".qls",
|
|
||||||
})
|
|
||||||
).path;
|
|
||||||
const suiteYaml = [];
|
|
||||||
for (const qlpack of packsToSearch) {
|
|
||||||
suiteYaml.push({
|
|
||||||
from: qlpack,
|
|
||||||
queries: ".",
|
|
||||||
include: {
|
|
||||||
"tags contain": "modelgenerator",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await writeFile(suiteFile, dump(suiteYaml), "utf8");
|
|
||||||
|
|
||||||
return await cliServer.resolveQueriesInSuite(
|
|
||||||
suiteFile,
|
|
||||||
getOnDiskWorkspaceFolders(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getModeledMethodsFromFlow(
|
async function runSingleFlowQuery(
|
||||||
type: Exclude<ModeledMethodType, "none">,
|
type: Exclude<ModeledMethodType, "none">,
|
||||||
queryPath: string | undefined,
|
queryPath: string | undefined,
|
||||||
queryStep: number,
|
queryStep: number,
|
||||||
@@ -77,6 +103,7 @@ async function getModeledMethodsFromFlow(
|
|||||||
token,
|
token,
|
||||||
}: Omit<FlowModelOptions, "onResults">,
|
}: Omit<FlowModelOptions, "onResults">,
|
||||||
): Promise<ModeledMethod[]> {
|
): Promise<ModeledMethod[]> {
|
||||||
|
// Check that the right query was found
|
||||||
if (queryPath === undefined) {
|
if (queryPath === undefined) {
|
||||||
void showAndLogExceptionWithTelemetry(
|
void showAndLogExceptionWithTelemetry(
|
||||||
extLogger,
|
extLogger,
|
||||||
@@ -86,45 +113,32 @@ async function getModeledMethodsFromFlow(
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const definition = extensiblePredicateDefinitions[type];
|
// Run the query
|
||||||
|
const completedQuery = await runQuery({
|
||||||
const queryRun = queryRunner.createQueryRun(
|
cliServer,
|
||||||
databaseItem.databaseUri.fsPath,
|
queryRunner,
|
||||||
{
|
databaseItem,
|
||||||
queryPath,
|
queryPath,
|
||||||
quickEvalPosition: undefined,
|
|
||||||
quickEvalCountOnly: false,
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
getOnDiskWorkspaceFolders(),
|
|
||||||
undefined,
|
|
||||||
queryStorageDir,
|
queryStorageDir,
|
||||||
undefined,
|
additionalPacks: getOnDiskWorkspaceFolders(),
|
||||||
undefined,
|
extensionPacks: undefined,
|
||||||
);
|
progress: ({ step, message }) =>
|
||||||
|
|
||||||
const queryResult = await queryRun.evaluate(
|
|
||||||
({ step, message }) =>
|
|
||||||
progress({
|
progress({
|
||||||
message: `Generating ${type} model: ${message}`,
|
message: `Generating ${type} model: ${message}`,
|
||||||
step: queryStep * 1000 + step,
|
step: queryStep * 1000 + step,
|
||||||
maxStep: 4000,
|
maxStep: 4000,
|
||||||
}),
|
}),
|
||||||
token,
|
token,
|
||||||
new TeeLogger(queryRunner.logger, queryRun.outputDir.logPath),
|
});
|
||||||
);
|
|
||||||
if (queryResult.resultType !== QueryResultType.SUCCESS) {
|
if (!completedQuery) {
|
||||||
void showAndLogExceptionWithTelemetry(
|
|
||||||
extLogger,
|
|
||||||
telemetryListener,
|
|
||||||
redactableError`Failed to run ${basename(queryPath)} query: ${
|
|
||||||
queryResult.message ?? "No message"
|
|
||||||
}`,
|
|
||||||
);
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const bqrsPath = queryResult.outputDir.bqrsPath;
|
// Interpret the results
|
||||||
|
const definition = extensiblePredicateDefinitions[type];
|
||||||
|
|
||||||
|
const bqrsPath = completedQuery.outputDir.bqrsPath;
|
||||||
|
|
||||||
const bqrsInfo = await cliServer.bqrsInfo(bqrsPath);
|
const bqrsInfo = await cliServer.bqrsInfo(bqrsPath);
|
||||||
if (bqrsInfo["result-sets"].length !== 1) {
|
if (bqrsInfo["result-sets"].length !== 1) {
|
||||||
@@ -154,55 +168,3 @@ async function getModeledMethodsFromFlow(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateFlowModel({
|
|
||||||
onResults,
|
|
||||||
...options
|
|
||||||
}: FlowModelOptions) {
|
|
||||||
const queries = await resolveQueries(options.cliServer, options.databaseItem);
|
|
||||||
|
|
||||||
const queriesByBasename: Record<string, string> = {};
|
|
||||||
for (const query of queries) {
|
|
||||||
queriesByBasename[basename(query)] = query;
|
|
||||||
}
|
|
||||||
|
|
||||||
const summaryResults = await getModeledMethodsFromFlow(
|
|
||||||
"summary",
|
|
||||||
queriesByBasename["CaptureSummaryModels.ql"],
|
|
||||||
0,
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
if (summaryResults) {
|
|
||||||
await onResults(summaryResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sinkResults = await getModeledMethodsFromFlow(
|
|
||||||
"sink",
|
|
||||||
queriesByBasename["CaptureSinkModels.ql"],
|
|
||||||
1,
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
if (sinkResults) {
|
|
||||||
await onResults(sinkResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sourceResults = await getModeledMethodsFromFlow(
|
|
||||||
"source",
|
|
||||||
queriesByBasename["CaptureSourceModels.ql"],
|
|
||||||
2,
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
if (sourceResults) {
|
|
||||||
await onResults(sourceResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
const neutralResults = await getModeledMethodsFromFlow(
|
|
||||||
"neutral",
|
|
||||||
queriesByBasename["CaptureNeutralModels.ql"],
|
|
||||||
3,
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
if (neutralResults) {
|
|
||||||
await onResults(neutralResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user