Move UI-related code from QueryRunner into LocalQueries
This commit is contained in:
@@ -5,31 +5,18 @@ import {
|
||||
TemplatePrintAstProvider,
|
||||
TemplatePrintCfgProvider,
|
||||
} from "./contextual/templateProvider";
|
||||
import { compileAndRunQuery } from "./local-queries";
|
||||
import { QueryRunner } from "./queryRunner";
|
||||
import { QueryHistoryManager } from "./query-history/query-history-manager";
|
||||
import { DatabaseUI } from "./local-databases-ui";
|
||||
import { ResultsView } from "./interface";
|
||||
import { AstCfgCommands } from "./common/commands";
|
||||
import { LocalQueries } from "./local-queries";
|
||||
|
||||
type AstCfgOptions = {
|
||||
queryRunner: QueryRunner;
|
||||
queryHistoryManager: QueryHistoryManager;
|
||||
databaseUI: DatabaseUI;
|
||||
localQueryResultsView: ResultsView;
|
||||
queryStorageDir: string;
|
||||
|
||||
localQueries: LocalQueries;
|
||||
astViewer: AstViewer;
|
||||
astTemplateProvider: TemplatePrintAstProvider;
|
||||
cfgTemplateProvider: TemplatePrintCfgProvider;
|
||||
};
|
||||
|
||||
export function getAstCfgCommands({
|
||||
queryRunner,
|
||||
queryHistoryManager,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
localQueries,
|
||||
astViewer,
|
||||
astTemplateProvider,
|
||||
cfgTemplateProvider,
|
||||
@@ -59,12 +46,7 @@ export function getAstCfgCommands({
|
||||
window.activeTextEditor?.document,
|
||||
);
|
||||
if (res) {
|
||||
await compileAndRunQuery(
|
||||
queryRunner,
|
||||
queryHistoryManager,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
await localQueries.compileAndRunQuery(
|
||||
false,
|
||||
res[0],
|
||||
progress,
|
||||
|
||||
@@ -115,10 +115,7 @@ import {
|
||||
QueryServerCommands,
|
||||
TestUICommands,
|
||||
} from "./common/commands";
|
||||
import {
|
||||
getLocalQueryCommands,
|
||||
showResultsForCompletedQuery,
|
||||
} from "./local-queries";
|
||||
import { LocalQueries } from "./local-queries";
|
||||
import { getAstCfgCommands } from "./ast-cfg-commands";
|
||||
import { getQueryEditorCommands } from "./query-editor";
|
||||
import { App } from "./common/app";
|
||||
@@ -712,12 +709,6 @@ async function activateWithInstalledDistribution(
|
||||
void extLogger.log("Initializing query history manager.");
|
||||
const queryHistoryConfigurationListener = new QueryHistoryConfigListener();
|
||||
ctx.subscriptions.push(queryHistoryConfigurationListener);
|
||||
const showResults = async (item: CompletedLocalQueryInfo) =>
|
||||
showResultsForCompletedQuery(
|
||||
localQueryResultsView,
|
||||
item,
|
||||
WebviewReveal.Forced,
|
||||
);
|
||||
const queryStorageDir = join(ctx.globalStorageUri.fsPath, "queries");
|
||||
await ensureDir(queryStorageDir);
|
||||
|
||||
@@ -791,8 +782,10 @@ async function activateWithInstalledDistribution(
|
||||
ctx,
|
||||
queryHistoryConfigurationListener,
|
||||
labelProvider,
|
||||
async (from: CompletedLocalQueryInfo, to: CompletedLocalQueryInfo) =>
|
||||
showResultsForComparison(compareView, from, to),
|
||||
async (
|
||||
from: CompletedLocalQueryInfo,
|
||||
to: CompletedLocalQueryInfo,
|
||||
): Promise<void> => showResultsForComparison(compareView, from, to),
|
||||
);
|
||||
|
||||
ctx.subscriptions.push(qhm);
|
||||
@@ -813,7 +806,8 @@ async function activateWithInstalledDistribution(
|
||||
cliServer,
|
||||
queryServerLogger,
|
||||
labelProvider,
|
||||
showResults,
|
||||
async (item: CompletedLocalQueryInfo) =>
|
||||
localQueries.showResultsForCompletedQuery(item, WebviewReveal.Forced),
|
||||
);
|
||||
ctx.subscriptions.push(compareView);
|
||||
|
||||
@@ -849,6 +843,18 @@ async function activateWithInstalledDistribution(
|
||||
true,
|
||||
);
|
||||
|
||||
const localQueries = new LocalQueries(
|
||||
app,
|
||||
qs,
|
||||
qhm,
|
||||
dbm,
|
||||
cliServer,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
);
|
||||
ctx.subscriptions.push(localQueries);
|
||||
|
||||
void extLogger.log("Initializing QLTest interface.");
|
||||
const testExplorerExtension = extensions.getExtension<TestHub>(
|
||||
testExplorerExtensionId,
|
||||
@@ -902,11 +908,7 @@ async function activateWithInstalledDistribution(
|
||||
...databaseUI.getCommands(),
|
||||
...dbModule.getCommands(),
|
||||
...getAstCfgCommands({
|
||||
queryRunner: qs,
|
||||
queryHistoryManager: qhm,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
localQueries,
|
||||
astViewer,
|
||||
astTemplateProvider,
|
||||
cfgTemplateProvider,
|
||||
@@ -926,16 +928,7 @@ async function activateWithInstalledDistribution(
|
||||
}
|
||||
|
||||
const queryServerCommands: QueryServerCommands = {
|
||||
...getLocalQueryCommands({
|
||||
app,
|
||||
queryRunner: qs,
|
||||
queryHistoryManager: qhm,
|
||||
databaseManager: dbm,
|
||||
cliServer,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
}),
|
||||
...localQueries.getCommands(),
|
||||
};
|
||||
|
||||
for (const [commandName, command] of Object.entries(queryServerCommands)) {
|
||||
|
||||
@@ -57,7 +57,7 @@ export class LegacyQueryRunner extends QueryRunner {
|
||||
await clearCacheInDatabase(this.qs, dbItem, progress, token);
|
||||
}
|
||||
|
||||
protected async compileAndRunQueryAgainstDatabaseCore(
|
||||
public async compileAndRunQueryAgainstDatabaseCore(
|
||||
dbPath: string,
|
||||
query: CoreQueryTarget,
|
||||
additionalPacks: string[],
|
||||
|
||||
@@ -7,384 +7,508 @@ import {
|
||||
Uri,
|
||||
window,
|
||||
} from "vscode";
|
||||
import { extLogger } from "./common";
|
||||
import { BaseLogger, extLogger, TeeLogger } from "./common";
|
||||
import { MAX_QUERIES } from "./config";
|
||||
import { gatherQlFiles } from "./pure/files";
|
||||
import { basename } from "path";
|
||||
import {
|
||||
createTimestampFile,
|
||||
findLanguage,
|
||||
getOnDiskWorkspaceFolders,
|
||||
showAndLogErrorMessage,
|
||||
showAndLogExceptionWithTelemetry,
|
||||
showAndLogWarningMessage,
|
||||
showBinaryChoiceDialog,
|
||||
tryGetQueryMetadata,
|
||||
} from "./helpers";
|
||||
import { displayQuickQuery } from "./quick-query";
|
||||
import { QueryRunner } from "./queryRunner";
|
||||
import { CoreQueryResults, CoreQueryTarget, QueryRunner } from "./queryRunner";
|
||||
import { QueryHistoryManager } from "./query-history/query-history-manager";
|
||||
import { DatabaseUI } from "./local-databases-ui";
|
||||
import { ResultsView } from "./interface";
|
||||
import { DatabaseItem, DatabaseManager } from "./local-databases";
|
||||
import { createInitialQueryInfo } from "./run-queries-shared";
|
||||
import { CompletedLocalQueryInfo, LocalQueryInfo } from "./query-results";
|
||||
import {
|
||||
createInitialQueryInfo,
|
||||
EvaluatorLogPaths,
|
||||
generateEvalLogSummaries,
|
||||
logEndSummary,
|
||||
QueryEvaluationInfo,
|
||||
QueryOutputDir,
|
||||
QueryWithResults,
|
||||
} from "./run-queries-shared";
|
||||
import {
|
||||
CompletedLocalQueryInfo,
|
||||
InitialQueryInfo,
|
||||
LocalQueryInfo,
|
||||
} from "./query-results";
|
||||
import { WebviewReveal } from "./interface-utils";
|
||||
import { asError, getErrorMessage } from "./pure/helpers-pure";
|
||||
import { CodeQLCliServer } from "./cli";
|
||||
import { LocalQueryCommands } from "./common/commands";
|
||||
import { App } from "./common/app";
|
||||
|
||||
type LocalQueryOptions = {
|
||||
app: App;
|
||||
queryRunner: QueryRunner;
|
||||
queryHistoryManager: QueryHistoryManager;
|
||||
databaseManager: DatabaseManager;
|
||||
cliServer: CodeQLCliServer;
|
||||
databaseUI: DatabaseUI;
|
||||
localQueryResultsView: ResultsView;
|
||||
queryStorageDir: string;
|
||||
};
|
||||
|
||||
export function getLocalQueryCommands({
|
||||
app,
|
||||
queryRunner,
|
||||
queryHistoryManager,
|
||||
databaseManager,
|
||||
cliServer,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
}: LocalQueryOptions): LocalQueryCommands {
|
||||
const runQuery = async (uri: Uri | undefined) =>
|
||||
withProgress(
|
||||
async (progress, token) => {
|
||||
await compileAndRunQuery(
|
||||
queryRunner,
|
||||
queryHistoryManager,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
false,
|
||||
uri,
|
||||
progress,
|
||||
token,
|
||||
undefined,
|
||||
);
|
||||
},
|
||||
{
|
||||
title: "Running query",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const runQueryOnMultipleDatabases = async (uri: Uri | undefined) =>
|
||||
withProgress(
|
||||
async (progress, token) =>
|
||||
await compileAndRunQueryOnMultipleDatabases(
|
||||
cliServer,
|
||||
queryRunner,
|
||||
queryHistoryManager,
|
||||
databaseManager,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
progress,
|
||||
token,
|
||||
uri,
|
||||
),
|
||||
{
|
||||
title: "Running query on selected databases",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const runQueries = async (_: Uri | undefined, multi: Uri[]) =>
|
||||
withProgress(
|
||||
async (progress, token) => {
|
||||
const maxQueryCount = MAX_QUERIES.getValue() as number;
|
||||
const [files, dirFound] = await gatherQlFiles(
|
||||
multi.map((uri) => uri.fsPath),
|
||||
);
|
||||
if (files.length > maxQueryCount) {
|
||||
throw new Error(
|
||||
`You tried to run ${files.length} queries, but the maximum is ${maxQueryCount}. Try selecting fewer queries or changing the 'codeQL.runningQueries.maxQueries' setting.`,
|
||||
);
|
||||
}
|
||||
// warn user and display selected files when a directory is selected because some ql
|
||||
// files may be hidden from the user.
|
||||
if (dirFound) {
|
||||
const fileString = files.map((file) => basename(file)).join(", ");
|
||||
const res = await showBinaryChoiceDialog(
|
||||
`You are about to run ${files.length} queries: ${fileString} Do you want to continue?`,
|
||||
);
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const queryUris = files.map((path) => Uri.parse(`file:${path}`, true));
|
||||
|
||||
// Use a wrapped progress so that messages appear with the queries remaining in it.
|
||||
let queriesRemaining = queryUris.length;
|
||||
|
||||
function wrappedProgress(update: ProgressUpdate) {
|
||||
const message =
|
||||
queriesRemaining > 1
|
||||
? `${queriesRemaining} remaining. ${update.message}`
|
||||
: update.message;
|
||||
progress({
|
||||
...update,
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
wrappedProgress({
|
||||
maxStep: queryUris.length,
|
||||
step: queryUris.length - queriesRemaining,
|
||||
message: "",
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
queryUris.map(async (uri) =>
|
||||
compileAndRunQuery(
|
||||
queryRunner,
|
||||
queryHistoryManager,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
false,
|
||||
uri,
|
||||
wrappedProgress,
|
||||
token,
|
||||
undefined,
|
||||
).then(() => queriesRemaining--),
|
||||
),
|
||||
);
|
||||
},
|
||||
{
|
||||
title: "Running queries",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const quickEval = async (uri: Uri) =>
|
||||
withProgress(
|
||||
async (progress, token) => {
|
||||
await compileAndRunQuery(
|
||||
queryRunner,
|
||||
queryHistoryManager,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
true,
|
||||
uri,
|
||||
progress,
|
||||
token,
|
||||
undefined,
|
||||
);
|
||||
},
|
||||
{
|
||||
title: "Running query",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const codeLensQuickEval = async (uri: Uri, range: Range) =>
|
||||
withProgress(
|
||||
async (progress, token) =>
|
||||
await compileAndRunQuery(
|
||||
queryRunner,
|
||||
queryHistoryManager,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
true,
|
||||
uri,
|
||||
progress,
|
||||
token,
|
||||
undefined,
|
||||
range,
|
||||
),
|
||||
{
|
||||
title: "Running query",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const quickQuery = async () =>
|
||||
withProgress(
|
||||
async (progress, token) =>
|
||||
displayQuickQuery(app, cliServer, databaseUI, progress, token),
|
||||
{
|
||||
title: "Run Quick Query",
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
"codeQL.runQuery": runQuery,
|
||||
"codeQL.runQueryContextEditor": runQuery,
|
||||
"codeQL.runQueryOnMultipleDatabases": runQueryOnMultipleDatabases,
|
||||
"codeQL.runQueryOnMultipleDatabasesContextEditor":
|
||||
runQueryOnMultipleDatabases,
|
||||
"codeQL.runQueries": runQueries,
|
||||
"codeQL.quickEval": quickEval,
|
||||
"codeQL.quickEvalContextEditor": quickEval,
|
||||
"codeQL.codeLensQuickEval": codeLensQuickEval,
|
||||
"codeQL.quickQuery": quickQuery,
|
||||
};
|
||||
}
|
||||
|
||||
export async function compileAndRunQuery(
|
||||
qs: QueryRunner,
|
||||
qhm: QueryHistoryManager,
|
||||
databaseUI: DatabaseUI,
|
||||
localQueryResultsView: ResultsView,
|
||||
queryStorageDir: string,
|
||||
quickEval: boolean,
|
||||
selectedQuery: Uri | undefined,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
databaseItem: DatabaseItem | undefined,
|
||||
range?: Range,
|
||||
): Promise<void> {
|
||||
if (qs !== undefined) {
|
||||
// If no databaseItem is specified, use the database currently selected in the Databases UI
|
||||
databaseItem =
|
||||
databaseItem || (await databaseUI.getDatabaseItem(progress, token));
|
||||
if (databaseItem === undefined) {
|
||||
throw new Error("Can't run query without a selected database");
|
||||
}
|
||||
const databaseInfo = {
|
||||
name: databaseItem.name,
|
||||
databaseUri: databaseItem.databaseUri.toString(),
|
||||
};
|
||||
|
||||
// handle cancellation from the history view.
|
||||
const source = new CancellationTokenSource();
|
||||
token.onCancellationRequested(() => source.cancel());
|
||||
|
||||
const initialInfo = await createInitialQueryInfo(
|
||||
selectedQuery,
|
||||
databaseInfo,
|
||||
quickEval,
|
||||
range,
|
||||
);
|
||||
const item = new LocalQueryInfo(initialInfo, source);
|
||||
qhm.addQuery(item);
|
||||
try {
|
||||
const completedQueryInfo = await qs.compileAndRunQueryAgainstDatabase(
|
||||
databaseItem,
|
||||
initialInfo,
|
||||
queryStorageDir,
|
||||
progress,
|
||||
source.token,
|
||||
undefined,
|
||||
item,
|
||||
);
|
||||
qhm.completeQuery(item, completedQueryInfo);
|
||||
await showResultsForCompletedQuery(
|
||||
localQueryResultsView,
|
||||
item as CompletedLocalQueryInfo,
|
||||
WebviewReveal.Forced,
|
||||
);
|
||||
// Note we must update the query history view after showing results as the
|
||||
// display and sorting might depend on the number of results
|
||||
} catch (e) {
|
||||
const err = asError(e);
|
||||
err.message = `Error running query: ${err.message}`;
|
||||
item.failureReason = err.message;
|
||||
throw e;
|
||||
} finally {
|
||||
await qhm.refreshTreeView();
|
||||
source.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
import { DisposableObject } from "./pure/disposable-object";
|
||||
import { QueryResultType } from "./pure/new-messages";
|
||||
import { redactableError } from "./pure/errors";
|
||||
|
||||
interface DatabaseQuickPickItem extends QuickPickItem {
|
||||
databaseItem: DatabaseItem;
|
||||
}
|
||||
|
||||
async function compileAndRunQueryOnMultipleDatabases(
|
||||
cliServer: CodeQLCliServer,
|
||||
qs: QueryRunner,
|
||||
qhm: QueryHistoryManager,
|
||||
dbm: DatabaseManager,
|
||||
databaseUI: DatabaseUI,
|
||||
localQueryResultsView: ResultsView,
|
||||
queryStorageDir: string,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
uri: Uri | undefined,
|
||||
): Promise<void> {
|
||||
let filteredDBs = dbm.databaseItems;
|
||||
if (filteredDBs.length === 0) {
|
||||
void showAndLogErrorMessage(
|
||||
"No databases found. Please add a suitable database to your workspace.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
// If possible, only show databases with the right language (otherwise show all databases).
|
||||
const queryLanguage = await findLanguage(cliServer, uri);
|
||||
if (queryLanguage) {
|
||||
filteredDBs = dbm.databaseItems.filter(
|
||||
(db) => db.language === queryLanguage,
|
||||
);
|
||||
if (filteredDBs.length === 0) {
|
||||
void showAndLogErrorMessage(
|
||||
`No databases found for language ${queryLanguage}. Please add a suitable database to your workspace.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const quickPickItems = filteredDBs.map<DatabaseQuickPickItem>((dbItem) => ({
|
||||
databaseItem: dbItem,
|
||||
label: dbItem.name,
|
||||
description: dbItem.language,
|
||||
}));
|
||||
/**
|
||||
* Databases that were selected in the quick pick menu.
|
||||
*/
|
||||
const quickpick = await window.showQuickPick<DatabaseQuickPickItem>(
|
||||
quickPickItems,
|
||||
{ canPickMany: true, ignoreFocusOut: true },
|
||||
);
|
||||
if (quickpick !== undefined) {
|
||||
// Collect all skipped databases and display them at the end (instead of popping up individual errors)
|
||||
const skippedDatabases = [];
|
||||
const errors = [];
|
||||
for (const item of quickpick) {
|
||||
try {
|
||||
await compileAndRunQuery(
|
||||
qs,
|
||||
qhm,
|
||||
databaseUI,
|
||||
localQueryResultsView,
|
||||
queryStorageDir,
|
||||
false,
|
||||
uri,
|
||||
progress,
|
||||
token,
|
||||
item.databaseItem,
|
||||
);
|
||||
} catch (e) {
|
||||
skippedDatabases.push(item.label);
|
||||
errors.push(getErrorMessage(e));
|
||||
}
|
||||
}
|
||||
if (skippedDatabases.length > 0) {
|
||||
void extLogger.log(`Errors:\n${errors.join("\n")}`);
|
||||
void showAndLogWarningMessage(
|
||||
`The following databases were skipped:\n${skippedDatabases.join(
|
||||
"\n",
|
||||
)}.\nFor details about the errors, see the logs.`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
void showAndLogErrorMessage("No databases selected.");
|
||||
function formatResultMessage(result: CoreQueryResults): string {
|
||||
switch (result.resultType) {
|
||||
case QueryResultType.CANCELLATION:
|
||||
return `cancelled after ${Math.round(
|
||||
result.evaluationTime / 1000,
|
||||
)} seconds`;
|
||||
case QueryResultType.OOM:
|
||||
return "out of memory";
|
||||
case QueryResultType.SUCCESS:
|
||||
return `finished in ${Math.round(result.evaluationTime / 1000)} seconds`;
|
||||
case QueryResultType.COMPILATION_ERROR:
|
||||
return `compilation failed: ${result.message}`;
|
||||
case QueryResultType.OTHER_ERROR:
|
||||
default:
|
||||
return result.message ? `failed: ${result.message}` : "failed";
|
||||
}
|
||||
}
|
||||
|
||||
export async function showResultsForCompletedQuery(
|
||||
localQueryResultsView: ResultsView,
|
||||
query: CompletedLocalQueryInfo,
|
||||
forceReveal: WebviewReveal,
|
||||
): Promise<void> {
|
||||
await localQueryResultsView.showResults(query, forceReveal, false);
|
||||
export class LocalQueries extends DisposableObject {
|
||||
public constructor(
|
||||
private readonly app: App,
|
||||
private readonly queryRunner: QueryRunner,
|
||||
private readonly queryHistoryManager: QueryHistoryManager,
|
||||
private readonly databaseManager: DatabaseManager,
|
||||
private readonly cliServer: CodeQLCliServer,
|
||||
private readonly databaseUI: DatabaseUI,
|
||||
private readonly localQueryResultsView: ResultsView,
|
||||
private readonly queryStorageDir: string,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public getCommands(): LocalQueryCommands {
|
||||
const runQuery = async (uri: Uri | undefined) =>
|
||||
withProgress(
|
||||
async (progress, token) => {
|
||||
await this.compileAndRunQuery(false, uri, progress, token, undefined);
|
||||
},
|
||||
{
|
||||
title: "Running query",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const runQueryOnMultipleDatabases = async (uri: Uri | undefined) =>
|
||||
withProgress(
|
||||
async (progress, token) =>
|
||||
await this.compileAndRunQueryOnMultipleDatabases(
|
||||
progress,
|
||||
token,
|
||||
uri,
|
||||
),
|
||||
{
|
||||
title: "Running query on selected databases",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const runQueries = async (_: Uri | undefined, multi: Uri[]) =>
|
||||
withProgress(
|
||||
async (progress, token) => {
|
||||
const maxQueryCount = MAX_QUERIES.getValue() as number;
|
||||
const [files, dirFound] = await gatherQlFiles(
|
||||
multi.map((uri) => uri.fsPath),
|
||||
);
|
||||
if (files.length > maxQueryCount) {
|
||||
throw new Error(
|
||||
`You tried to run ${files.length} queries, but the maximum is ${maxQueryCount}. Try selecting fewer queries or changing the 'codeQL.runningQueries.maxQueries' setting.`,
|
||||
);
|
||||
}
|
||||
// warn user and display selected files when a directory is selected because some ql
|
||||
// files may be hidden from the user.
|
||||
if (dirFound) {
|
||||
const fileString = files.map((file) => basename(file)).join(", ");
|
||||
const res = await showBinaryChoiceDialog(
|
||||
`You are about to run ${files.length} queries: ${fileString} Do you want to continue?`,
|
||||
);
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const queryUris = files.map((path) =>
|
||||
Uri.parse(`file:${path}`, true),
|
||||
);
|
||||
|
||||
// Use a wrapped progress so that messages appear with the queries remaining in it.
|
||||
let queriesRemaining = queryUris.length;
|
||||
|
||||
function wrappedProgress(update: ProgressUpdate) {
|
||||
const message =
|
||||
queriesRemaining > 1
|
||||
? `${queriesRemaining} remaining. ${update.message}`
|
||||
: update.message;
|
||||
progress({
|
||||
...update,
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
wrappedProgress({
|
||||
maxStep: queryUris.length,
|
||||
step: queryUris.length - queriesRemaining,
|
||||
message: "",
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
queryUris.map(async (uri) =>
|
||||
this.compileAndRunQuery(
|
||||
false,
|
||||
uri,
|
||||
wrappedProgress,
|
||||
token,
|
||||
undefined,
|
||||
).then(() => queriesRemaining--),
|
||||
),
|
||||
);
|
||||
},
|
||||
{
|
||||
title: "Running queries",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const quickEval = async (uri: Uri) =>
|
||||
withProgress(
|
||||
async (progress, token) => {
|
||||
await this.compileAndRunQuery(true, uri, progress, token, undefined);
|
||||
},
|
||||
{
|
||||
title: "Running query",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const codeLensQuickEval = async (uri: Uri, range: Range) =>
|
||||
withProgress(
|
||||
async (progress, token) =>
|
||||
await this.compileAndRunQuery(
|
||||
true,
|
||||
uri,
|
||||
progress,
|
||||
token,
|
||||
undefined,
|
||||
range,
|
||||
),
|
||||
{
|
||||
title: "Running query",
|
||||
cancellable: true,
|
||||
},
|
||||
);
|
||||
|
||||
const quickQuery = async () =>
|
||||
withProgress(
|
||||
async (progress, token) =>
|
||||
displayQuickQuery(
|
||||
this.app,
|
||||
this.cliServer,
|
||||
this.databaseUI,
|
||||
progress,
|
||||
token,
|
||||
),
|
||||
{
|
||||
title: "Run Quick Query",
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
"codeQL.runQuery": runQuery,
|
||||
"codeQL.runQueryContextEditor": runQuery,
|
||||
"codeQL.runQueryOnMultipleDatabases": runQueryOnMultipleDatabases,
|
||||
"codeQL.runQueryOnMultipleDatabasesContextEditor":
|
||||
runQueryOnMultipleDatabases,
|
||||
"codeQL.runQueries": runQueries,
|
||||
"codeQL.quickEval": quickEval,
|
||||
"codeQL.quickEvalContextEditor": quickEval,
|
||||
"codeQL.codeLensQuickEval": codeLensQuickEval,
|
||||
"codeQL.quickQuery": quickQuery,
|
||||
};
|
||||
}
|
||||
|
||||
async compileAndRunQuery(
|
||||
quickEval: boolean,
|
||||
selectedQuery: Uri | undefined,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
databaseItem: DatabaseItem | undefined,
|
||||
range?: Range,
|
||||
): Promise<void> {
|
||||
if (this.queryRunner !== undefined) {
|
||||
// If no databaseItem is specified, use the database currently selected in the Databases UI
|
||||
databaseItem =
|
||||
databaseItem ||
|
||||
(await this.databaseUI.getDatabaseItem(progress, token));
|
||||
if (databaseItem === undefined) {
|
||||
throw new Error("Can't run query without a selected database");
|
||||
}
|
||||
const databaseInfo = {
|
||||
name: databaseItem.name,
|
||||
databaseUri: databaseItem.databaseUri.toString(),
|
||||
};
|
||||
|
||||
// handle cancellation from the history view.
|
||||
const source = new CancellationTokenSource();
|
||||
token.onCancellationRequested(() => source.cancel());
|
||||
|
||||
const initialInfo = await createInitialQueryInfo(
|
||||
selectedQuery,
|
||||
databaseInfo,
|
||||
quickEval,
|
||||
range,
|
||||
);
|
||||
const item = new LocalQueryInfo(initialInfo, source);
|
||||
this.queryHistoryManager.addQuery(item);
|
||||
try {
|
||||
const completedQueryInfo = await this.compileAndRunQueryAgainstDatabase(
|
||||
databaseItem,
|
||||
initialInfo,
|
||||
this.queryStorageDir,
|
||||
progress,
|
||||
source.token,
|
||||
undefined,
|
||||
item,
|
||||
);
|
||||
this.queryHistoryManager.completeQuery(item, completedQueryInfo);
|
||||
await this.showResultsForCompletedQuery(
|
||||
item as CompletedLocalQueryInfo,
|
||||
WebviewReveal.Forced,
|
||||
);
|
||||
// Note we must update the query history view after showing results as the
|
||||
// display and sorting might depend on the number of results
|
||||
} catch (e) {
|
||||
const err = asError(e);
|
||||
err.message = `Error running query: ${err.message}`;
|
||||
item.failureReason = err.message;
|
||||
throw e;
|
||||
} finally {
|
||||
await this.queryHistoryManager.refreshTreeView();
|
||||
source.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async compileAndRunQueryOnMultipleDatabases(
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
uri: Uri | undefined,
|
||||
): Promise<void> {
|
||||
let filteredDBs = this.databaseManager.databaseItems;
|
||||
if (filteredDBs.length === 0) {
|
||||
void showAndLogErrorMessage(
|
||||
"No databases found. Please add a suitable database to your workspace.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
// If possible, only show databases with the right language (otherwise show all databases).
|
||||
const queryLanguage = await findLanguage(this.cliServer, uri);
|
||||
if (queryLanguage) {
|
||||
filteredDBs = this.databaseManager.databaseItems.filter(
|
||||
(db) => db.language === queryLanguage,
|
||||
);
|
||||
if (filteredDBs.length === 0) {
|
||||
void showAndLogErrorMessage(
|
||||
`No databases found for language ${queryLanguage}. Please add a suitable database to your workspace.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const quickPickItems = filteredDBs.map<DatabaseQuickPickItem>((dbItem) => ({
|
||||
databaseItem: dbItem,
|
||||
label: dbItem.name,
|
||||
description: dbItem.language,
|
||||
}));
|
||||
/**
|
||||
* Databases that were selected in the quick pick menu.
|
||||
*/
|
||||
const quickpick = await window.showQuickPick<DatabaseQuickPickItem>(
|
||||
quickPickItems,
|
||||
{ canPickMany: true, ignoreFocusOut: true },
|
||||
);
|
||||
if (quickpick !== undefined) {
|
||||
// Collect all skipped databases and display them at the end (instead of popping up individual errors)
|
||||
const skippedDatabases = [];
|
||||
const errors = [];
|
||||
for (const item of quickpick) {
|
||||
try {
|
||||
await this.compileAndRunQuery(
|
||||
false,
|
||||
uri,
|
||||
progress,
|
||||
token,
|
||||
item.databaseItem,
|
||||
);
|
||||
} catch (e) {
|
||||
skippedDatabases.push(item.label);
|
||||
errors.push(getErrorMessage(e));
|
||||
}
|
||||
}
|
||||
if (skippedDatabases.length > 0) {
|
||||
void extLogger.log(`Errors:\n${errors.join("\n")}`);
|
||||
void showAndLogWarningMessage(
|
||||
`The following databases were skipped:\n${skippedDatabases.join(
|
||||
"\n",
|
||||
)}.\nFor details about the errors, see the logs.`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
void showAndLogErrorMessage("No databases selected.");
|
||||
}
|
||||
}
|
||||
|
||||
async showResultsForCompletedQuery(
|
||||
query: CompletedLocalQueryInfo,
|
||||
forceReveal: WebviewReveal,
|
||||
): Promise<void> {
|
||||
await this.localQueryResultsView.showResults(query, forceReveal, false);
|
||||
}
|
||||
|
||||
private async compileAndRunQueryAgainstDatabase(
|
||||
db: DatabaseItem,
|
||||
initialInfo: InitialQueryInfo,
|
||||
queryStorageDir: string,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
templates?: Record<string, string>,
|
||||
queryInfo?: LocalQueryInfo, // May be omitted for queries not initiated by the user. If omitted we won't create a structured log for the query.
|
||||
): Promise<QueryWithResults> {
|
||||
const queryTarget: CoreQueryTarget = {
|
||||
queryPath: initialInfo.queryPath,
|
||||
quickEvalPosition: initialInfo.quickEvalPosition,
|
||||
};
|
||||
|
||||
const diskWorkspaceFolders = getOnDiskWorkspaceFolders();
|
||||
const queryRun = this.queryRunner.createQueryRun(
|
||||
db.databaseUri.fsPath,
|
||||
queryTarget,
|
||||
queryInfo !== undefined,
|
||||
diskWorkspaceFolders,
|
||||
queryStorageDir,
|
||||
initialInfo.id,
|
||||
templates,
|
||||
);
|
||||
|
||||
await createTimestampFile(queryRun.outputDir.querySaveDir);
|
||||
|
||||
const logPath = queryRun.outputDir.logPath;
|
||||
if (this.queryRunner.customLogDirectory) {
|
||||
void showAndLogWarningMessage(
|
||||
`Custom log directories are no longer supported. The "codeQL.runningQueries.customLogDirectory" setting is deprecated. Unset the setting to stop seeing this message. Query logs saved to ${logPath}`,
|
||||
);
|
||||
}
|
||||
|
||||
const logger = new TeeLogger(this.queryRunner.logger, logPath);
|
||||
const coreResults = await queryRun.evaluate(progress, token, logger);
|
||||
if (queryInfo !== undefined) {
|
||||
const evalLogPaths = await this.summarizeEvalLog(
|
||||
coreResults.resultType,
|
||||
queryRun.outputDir,
|
||||
logger,
|
||||
);
|
||||
if (evalLogPaths !== undefined) {
|
||||
queryInfo.setEvaluatorLogPaths(evalLogPaths);
|
||||
}
|
||||
}
|
||||
|
||||
return await this.getCompletedQueryInfo(
|
||||
db,
|
||||
queryTarget,
|
||||
queryRun.outputDir,
|
||||
coreResults,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate summaries of the structured evaluator log.
|
||||
*/
|
||||
public async summarizeEvalLog(
|
||||
resultType: QueryResultType,
|
||||
outputDir: QueryOutputDir,
|
||||
logger: BaseLogger,
|
||||
): Promise<EvaluatorLogPaths | undefined> {
|
||||
const evalLogPaths = await generateEvalLogSummaries(
|
||||
this.cliServer,
|
||||
outputDir,
|
||||
);
|
||||
if (evalLogPaths !== undefined) {
|
||||
if (evalLogPaths.endSummary !== undefined) {
|
||||
void logEndSummary(evalLogPaths.endSummary, logger); // Logged asynchrnously
|
||||
}
|
||||
} else {
|
||||
// Raw evaluator log was not found. Notify the user, unless we know why it wasn't found.
|
||||
switch (resultType) {
|
||||
case QueryResultType.COMPILATION_ERROR:
|
||||
case QueryResultType.DBSCHEME_MISMATCH_NAME:
|
||||
case QueryResultType.DBSCHEME_NO_UPGRADE:
|
||||
// In these cases, the evaluator was never invoked anyway, so don't bother warning.
|
||||
break;
|
||||
|
||||
default:
|
||||
void showAndLogWarningMessage(
|
||||
`Failed to write structured evaluator log to ${outputDir.evalLogPath}.`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return evalLogPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `QueryWithResults` containing information about the evaluation of the query and its
|
||||
* result, in the form expected by the query history UI.
|
||||
*/
|
||||
public async getCompletedQueryInfo(
|
||||
dbItem: DatabaseItem,
|
||||
queryTarget: CoreQueryTarget,
|
||||
outputDir: QueryOutputDir,
|
||||
results: CoreQueryResults,
|
||||
): Promise<QueryWithResults> {
|
||||
// Read the query metadata if possible, to use in the UI.
|
||||
const metadata = await tryGetQueryMetadata(
|
||||
this.cliServer,
|
||||
queryTarget.queryPath,
|
||||
);
|
||||
const query = new QueryEvaluationInfo(
|
||||
outputDir.querySaveDir,
|
||||
dbItem.databaseUri.fsPath,
|
||||
await dbItem.hasMetadataFile(),
|
||||
queryTarget.quickEvalPosition,
|
||||
metadata,
|
||||
);
|
||||
|
||||
if (results.resultType !== QueryResultType.SUCCESS) {
|
||||
const message = results.message
|
||||
? redactableError`${results.message}`
|
||||
: redactableError`Failed to run query`;
|
||||
void extLogger.log(message.fullMessage);
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
redactableError`Failed to run query: ${message}`,
|
||||
);
|
||||
}
|
||||
const message = formatResultMessage(results);
|
||||
const successful = results.resultType === QueryResultType.SUCCESS;
|
||||
return {
|
||||
query,
|
||||
result: {
|
||||
evaluationTime: results.evaluationTime,
|
||||
queryId: 0,
|
||||
resultType: successful
|
||||
? QueryResultType.SUCCESS
|
||||
: QueryResultType.OTHER_ERROR,
|
||||
runId: 0,
|
||||
message,
|
||||
},
|
||||
message,
|
||||
successful,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export class NewQueryRunner extends QueryRunner {
|
||||
await this.qs.sendRequest(clearCache, params, token, progress);
|
||||
}
|
||||
|
||||
protected async compileAndRunQueryAgainstDatabaseCore(
|
||||
public async compileAndRunQueryAgainstDatabaseCore(
|
||||
dbPath: string,
|
||||
query: CoreQueryTarget,
|
||||
additionalPacks: string[],
|
||||
|
||||
@@ -2,26 +2,10 @@ import { CancellationToken } from "vscode";
|
||||
import { CodeQLCliServer } from "./cli";
|
||||
import { ProgressCallback } from "./progress";
|
||||
import { DatabaseItem } from "./local-databases";
|
||||
import { InitialQueryInfo, LocalQueryInfo } from "./query-results";
|
||||
import {
|
||||
EvaluatorLogPaths,
|
||||
generateEvalLogSummaries,
|
||||
logEndSummary,
|
||||
QueryEvaluationInfo,
|
||||
QueryOutputDir,
|
||||
QueryWithResults,
|
||||
} from "./run-queries-shared";
|
||||
import { QueryOutputDir } from "./run-queries-shared";
|
||||
import { Position, QueryResultType } from "./pure/new-messages";
|
||||
import {
|
||||
createTimestampFile,
|
||||
getOnDiskWorkspaceFolders,
|
||||
showAndLogExceptionWithTelemetry,
|
||||
showAndLogWarningMessage,
|
||||
tryGetQueryMetadata,
|
||||
} from "./helpers";
|
||||
import { BaseLogger, Logger } from "./common";
|
||||
import { basename, join } from "path";
|
||||
import { BaseLogger, extLogger, Logger, TeeLogger } from "./common";
|
||||
import { redactableError } from "./pure/errors";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
export interface CoreQueryTarget {
|
||||
@@ -57,24 +41,6 @@ export interface CoreQueryRun {
|
||||
export type CoreCompletedQuery = CoreQueryResults &
|
||||
Omit<CoreQueryRun, "evaluate">;
|
||||
|
||||
function formatResultMessage(result: CoreQueryResults): string {
|
||||
switch (result.resultType) {
|
||||
case QueryResultType.CANCELLATION:
|
||||
return `cancelled after ${Math.round(
|
||||
result.evaluationTime / 1000,
|
||||
)} seconds`;
|
||||
case QueryResultType.OOM:
|
||||
return "out of memory";
|
||||
case QueryResultType.SUCCESS:
|
||||
return `finished in ${Math.round(result.evaluationTime / 1000)} seconds`;
|
||||
case QueryResultType.COMPILATION_ERROR:
|
||||
return `compilation failed: ${result.message}`;
|
||||
case QueryResultType.OTHER_ERROR:
|
||||
default:
|
||||
return result.message ? `failed: ${result.message}` : "failed";
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class QueryRunner {
|
||||
abstract restartQueryServer(
|
||||
progress: ProgressCallback,
|
||||
@@ -97,146 +63,40 @@ export abstract class QueryRunner {
|
||||
token: CancellationToken,
|
||||
): Promise<void>;
|
||||
|
||||
public async compileAndRunQueryAgainstDatabase(
|
||||
db: DatabaseItem,
|
||||
initialInfo: InitialQueryInfo,
|
||||
queryStorageDir: string,
|
||||
/**
|
||||
* Overridden in subclasses to evaluate the query via the query server and return the results.
|
||||
*/
|
||||
public abstract compileAndRunQueryAgainstDatabaseCore(
|
||||
dbPath: string,
|
||||
query: CoreQueryTarget,
|
||||
additionalPacks: string[],
|
||||
generateEvalLog: boolean,
|
||||
outputDir: QueryOutputDir,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
templates?: Record<string, string>,
|
||||
queryInfo?: LocalQueryInfo, // May be omitted for queries not initiated by the user. If omitted we won't create a structured log for the query.
|
||||
): Promise<QueryWithResults> {
|
||||
const queryTarget: CoreQueryTarget = {
|
||||
queryPath: initialInfo.queryPath,
|
||||
quickEvalPosition: initialInfo.quickEvalPosition,
|
||||
};
|
||||
|
||||
const diskWorkspaceFolders = getOnDiskWorkspaceFolders();
|
||||
const queryRun = this.createQueryRun(
|
||||
db.databaseUri.fsPath,
|
||||
queryTarget,
|
||||
queryInfo !== undefined,
|
||||
diskWorkspaceFolders,
|
||||
queryStorageDir,
|
||||
initialInfo.id,
|
||||
templates,
|
||||
);
|
||||
|
||||
await createTimestampFile(queryRun.outputDir.querySaveDir);
|
||||
|
||||
const logPath = queryRun.outputDir.logPath;
|
||||
if (this.customLogDirectory) {
|
||||
void showAndLogWarningMessage(
|
||||
`Custom log directories are no longer supported. The "codeQL.runningQueries.customLogDirectory" setting is deprecated. Unset the setting to stop seeing this message. Query logs saved to ${logPath}`,
|
||||
);
|
||||
}
|
||||
|
||||
const logger = new TeeLogger(this.logger, logPath);
|
||||
const coreResults = await queryRun.evaluate(progress, token, logger);
|
||||
if (queryInfo !== undefined) {
|
||||
const evalLogPaths = await this.summarizeEvalLog(
|
||||
coreResults.resultType,
|
||||
queryRun.outputDir,
|
||||
logger,
|
||||
);
|
||||
if (evalLogPaths !== undefined) {
|
||||
queryInfo.setEvaluatorLogPaths(evalLogPaths);
|
||||
}
|
||||
}
|
||||
|
||||
return await this.getCompletedQueryInfo(
|
||||
db,
|
||||
queryTarget,
|
||||
queryRun.outputDir,
|
||||
coreResults,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate summaries of the structured evaluator log.
|
||||
*/
|
||||
public async summarizeEvalLog(
|
||||
resultType: QueryResultType,
|
||||
outputDir: QueryOutputDir,
|
||||
templates: Record<string, string> | undefined,
|
||||
logger: BaseLogger,
|
||||
): Promise<EvaluatorLogPaths | undefined> {
|
||||
const evalLogPaths = await generateEvalLogSummaries(
|
||||
this.cliServer,
|
||||
outputDir,
|
||||
);
|
||||
if (evalLogPaths !== undefined) {
|
||||
if (evalLogPaths.endSummary !== undefined) {
|
||||
void logEndSummary(evalLogPaths.endSummary, logger); // Logged asynchrnously
|
||||
}
|
||||
} else {
|
||||
// Raw evaluator log was not found. Notify the user, unless we know why it wasn't found.
|
||||
switch (resultType) {
|
||||
case QueryResultType.COMPILATION_ERROR:
|
||||
case QueryResultType.DBSCHEME_MISMATCH_NAME:
|
||||
case QueryResultType.DBSCHEME_NO_UPGRADE:
|
||||
// In these cases, the evaluator was never invoked anyway, so don't bother warning.
|
||||
break;
|
||||
): Promise<CoreQueryResults>;
|
||||
|
||||
default:
|
||||
void showAndLogWarningMessage(
|
||||
`Failed to write structured evaluator log to ${outputDir.evalLogPath}.`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return evalLogPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `QueryWithResults` containing information about the evaluation of the query and its
|
||||
* result, in the form expected by the query history UI.
|
||||
*/
|
||||
public async getCompletedQueryInfo(
|
||||
abstract deregisterDatabase(
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
dbItem: DatabaseItem,
|
||||
queryTarget: CoreQueryTarget,
|
||||
outputDir: QueryOutputDir,
|
||||
results: CoreQueryResults,
|
||||
): Promise<QueryWithResults> {
|
||||
// Read the query metadata if possible, to use in the UI.
|
||||
const metadata = await tryGetQueryMetadata(
|
||||
this.cliServer,
|
||||
queryTarget.queryPath,
|
||||
);
|
||||
const query = new QueryEvaluationInfo(
|
||||
outputDir.querySaveDir,
|
||||
dbItem.databaseUri.fsPath,
|
||||
await dbItem.hasMetadataFile(),
|
||||
queryTarget.quickEvalPosition,
|
||||
metadata,
|
||||
);
|
||||
): Promise<void>;
|
||||
|
||||
if (results.resultType !== QueryResultType.SUCCESS) {
|
||||
const message = results.message
|
||||
? redactableError`${results.message}`
|
||||
: redactableError`Failed to run query`;
|
||||
void extLogger.log(message.fullMessage);
|
||||
void showAndLogExceptionWithTelemetry(
|
||||
redactableError`Failed to run query: ${message}`,
|
||||
);
|
||||
}
|
||||
const message = formatResultMessage(results);
|
||||
const successful = results.resultType === QueryResultType.SUCCESS;
|
||||
return {
|
||||
query,
|
||||
result: {
|
||||
evaluationTime: results.evaluationTime,
|
||||
queryId: 0,
|
||||
resultType: successful
|
||||
? QueryResultType.SUCCESS
|
||||
: QueryResultType.OTHER_ERROR,
|
||||
runId: 0,
|
||||
message,
|
||||
},
|
||||
message,
|
||||
successful,
|
||||
};
|
||||
}
|
||||
abstract registerDatabase(
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
dbItem: DatabaseItem,
|
||||
): Promise<void>;
|
||||
|
||||
abstract upgradeDatabaseExplicit(
|
||||
dbItem: DatabaseItem,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
): Promise<void>;
|
||||
|
||||
abstract clearPackCache(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Create a `CoreQueryRun` object. This creates an object whose `evaluate()` function can be
|
||||
@@ -286,39 +146,4 @@ export abstract class QueryRunner {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden in subclasses to evaluate the query via the query server and return the results.
|
||||
*/
|
||||
protected abstract compileAndRunQueryAgainstDatabaseCore(
|
||||
dbPath: string,
|
||||
query: CoreQueryTarget,
|
||||
additionalPacks: string[],
|
||||
generateEvalLog: boolean,
|
||||
outputDir: QueryOutputDir,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
templates: Record<string, string> | undefined,
|
||||
logger: BaseLogger,
|
||||
): Promise<CoreQueryResults>;
|
||||
|
||||
abstract deregisterDatabase(
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
dbItem: DatabaseItem,
|
||||
): Promise<void>;
|
||||
|
||||
abstract registerDatabase(
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
dbItem: DatabaseItem,
|
||||
): Promise<void>;
|
||||
|
||||
abstract upgradeDatabaseExplicit(
|
||||
dbItem: DatabaseItem,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
): Promise<void>;
|
||||
|
||||
abstract clearPackCache(): Promise<void>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user