Refactor: Move commandRunner to its own module

Also, extract related functions and types. There are no behavioral
changes in this commit. Only refactorings.
This commit is contained in:
Andrew Eisenberg
2021-01-18 11:02:01 -08:00
parent 6074a1a7c8
commit 540124478b
20 changed files with 332 additions and 298 deletions

4
.vscode/launch.json vendored
View File

@@ -8,7 +8,9 @@
"request": "launch", "request": "launch",
"runtimeExecutable": "${execPath}", "runtimeExecutable": "${execPath}",
"args": [ "args": [
"--extensionDevelopmentPath=${workspaceRoot}/extensions/ql-vscode" "--extensionDevelopmentPath=${workspaceRoot}/extensions/ql-vscode",
// Add a reference to a workspace to open. Eg-
// "${workspaceRoot}/../vscode-codeql-starter/vscode-codeql-starter.code-workspace"
], ],
"stopOnEntry": false, "stopOnEntry": false,
"sourceMaps": true, "sourceMaps": true,

View File

@@ -18,7 +18,7 @@ import { DatabaseItem } from './databases';
import { UrlValue, BqrsId } from './pure/bqrs-cli-types'; import { UrlValue, BqrsId } from './pure/bqrs-cli-types';
import { showLocation } from './interface-utils'; import { showLocation } from './interface-utils';
import { isStringLoc, isWholeFileLoc, isLineColumnLoc } from './pure/bqrs-utils'; import { isStringLoc, isWholeFileLoc, isLineColumnLoc } from './pure/bqrs-utils';
import { commandRunner } from './helpers'; import { commandRunner } from './commandRunner';
import { DisposableObject } from './vscode-utils/disposable-object'; import { DisposableObject } from './vscode-utils/disposable-object';
export interface AstItem { export interface AstItem {

View File

@@ -0,0 +1,215 @@
import {
CancellationToken,
ProgressOptions,
window as Window,
commands,
Disposable,
ProgressLocation
} from 'vscode';
import { showAndLogErrorMessage, showAndLogWarningMessage } from './helpers';
import { logger } from './logging';
export class UserCancellationException extends Error {
/**
* @param message The error message
* @param silent If silent is true, then this exception will avoid showing a warning message to the user.
*/
constructor(message?: string, public readonly silent = false) {
super(message);
}
}
export interface ProgressUpdate {
/**
* The current step
*/
step: number;
/**
* The maximum step. This *should* be constant for a single job.
*/
maxStep: number;
/**
* The current progress message
*/
message: string;
}
export type ProgressCallback = (p: ProgressUpdate) => void;
/**
* A task that handles command invocations from `commandRunner`
* and includes a progress monitor.
*
*
* Arguments passed to the command handler are passed along,
* untouched to this `ProgressTask` instance.
*
* @param progress a progress handler function. Call this
* function with a `ProgressUpdate` instance in order to
* denote some progress being achieved on this task.
* @param token a cencellation token
* @param args arguments passed to this task passed on from
* `commands.registerCommand`.
*/
export type ProgressTask<R> = (
progress: ProgressCallback,
token: CancellationToken,
...args: any[]
) => Thenable<R>;
/**
* A task that handles command invocations from `commandRunner`.
* Arguments passed to the command handler are passed along,
* untouched to this `NoProgressTask` instance.
*
* @param args arguments passed to this task passed on from
* `commands.registerCommand`.
*/
type NoProgressTask = ((...args: any[]) => Promise<any>);
/**
* This mediates between the kind of progress callbacks we want to
* write (where we *set* current progress position and give
* `maxSteps`) and the kind vscode progress api expects us to write
* (which increment progress by a certain amount out of 100%).
*
* Where possible, the `commandRunner` function below should be used
* instead of this function. The commandRunner is meant for wrapping
* top-level commands and provides error handling and other support
* automatically.
*
* Only use this function if you need a progress monitor and the
* control flow does not always come from a command (eg- during
* extension activation, or from an internal language server
* request).
*/
export function withProgress<R>(
options: ProgressOptions,
task: ProgressTask<R>,
...args: any[]
): Thenable<R> {
let progressAchieved = 0;
return Window.withProgress(options,
(progress, token) => {
return task(p => {
const { message, step, maxStep } = p;
const increment = 100 * (step - progressAchieved) / maxStep;
progressAchieved = step;
progress.report({ message, increment });
}, token, ...args);
});
}
/**
* A generic wrapper for command registration. This wrapper adds uniform error handling for commands.
*
* In this variant of the command runner, no progress monitor is used.
*
* @param commandId The ID of the command to register.
* @param task The task to run. It is passed directly to `commands.registerCommand`. Any
* arguments to the command handler are passed on to the task.
*/
export function commandRunner(
commandId: string,
task: NoProgressTask,
): Disposable {
return commands.registerCommand(commandId, async (...args: any[]) => {
try {
return await task(...args);
} catch (e) {
const errorMessage = `${e.message || e} (${commandId})`;
if (e instanceof UserCancellationException) {
// User has cancelled this action manually
if (e.silent) {
logger.log(errorMessage);
} else {
showAndLogWarningMessage(errorMessage);
}
} else {
showAndLogErrorMessage(errorMessage);
}
return undefined;
}
});
}
/**
* A generic wrapper for command registration. This wrapper adds uniform error handling,
* progress monitoring, and cancellation for commands.
*
* @param commandId The ID of the command to register.
* @param task The task to run. It is passed directly to `commands.registerCommand`. Any
* arguments to the command handler are passed on to the task after the progress callback
* and cancellation token.
* @param progressOptions Progress options to be sent to the progress monitor.
*/
export function commandRunnerWithProgress<R>(
commandId: string,
task: ProgressTask<R>,
progressOptions: Partial<ProgressOptions>
): Disposable {
return commands.registerCommand(commandId, async (...args: any[]) => {
const progressOptionsWithDefaults = {
location: ProgressLocation.Notification,
...progressOptions
};
try {
return await withProgress(progressOptionsWithDefaults, task, ...args);
} catch (e) {
const errorMessage = `${e.message || e} (${commandId})`;
if (e instanceof UserCancellationException) {
// User has cancelled this action manually
if (e.silent) {
logger.log(errorMessage);
} else {
showAndLogWarningMessage(errorMessage);
}
} else {
showAndLogErrorMessage(errorMessage);
}
return undefined;
}
});
}
/**
* Displays a progress monitor that indicates how much progess has been made
* reading from a stream.
*
* @param readable The stream to read progress from
* @param messagePrefix A prefix for displaying the message
* @param totalNumBytes Total number of bytes in this stream
* @param progress The progress callback used to set messages
*/
export function reportStreamProgress(
readable: NodeJS.ReadableStream,
messagePrefix: string,
totalNumBytes?: number,
progress?: ProgressCallback
) {
if (progress && totalNumBytes) {
let numBytesDownloaded = 0;
const bytesToDisplayMB = (numBytes: number): string => `${(numBytes / (1024 * 1024)).toFixed(1)} MB`;
const updateProgress = () => {
progress({
step: numBytesDownloaded,
maxStep: totalNumBytes,
message: `${messagePrefix} [${bytesToDisplayMB(numBytesDownloaded)} of ${bytesToDisplayMB(totalNumBytes)}]`,
});
};
// Display the progress straight away rather than waiting for the first chunk.
updateProgress();
readable.on('data', data => {
numBytesDownloaded += data.length;
updateProgress();
});
} else if (progress) {
progress({
step: 1,
maxStep: 2,
message: `${messagePrefix} (Size unknown)`,
});
}
}

View File

@@ -8,7 +8,7 @@ import fileRangeFromURI from './fileRangeFromURI';
import * as messages from '../pure/messages'; import * as messages from '../pure/messages';
import { QueryServerClient } from '../queryserver-client'; import { QueryServerClient } from '../queryserver-client';
import { QueryWithResults, compileAndRunQueryAgainstDatabase } from '../run-queries'; import { QueryWithResults, compileAndRunQueryAgainstDatabase } from '../run-queries';
import { ProgressCallback } from '../helpers'; import { ProgressCallback } from '../commandRunner';
import { KeyType } from './keyType'; import { KeyType } from './keyType';
import { qlpackOfDatabase, resolveQueries } from './queryResolver'; import { qlpackOfDatabase, resolveQueries } from './queryResolver';

View File

@@ -3,7 +3,8 @@ import * as vscode from 'vscode';
import { decodeSourceArchiveUri, encodeArchiveBasePath, zipArchiveScheme } from '../archive-filesystem-provider'; import { decodeSourceArchiveUri, encodeArchiveBasePath, zipArchiveScheme } from '../archive-filesystem-provider';
import { CodeQLCliServer } from '../cli'; import { CodeQLCliServer } from '../cli';
import { DatabaseManager } from '../databases'; import { DatabaseManager } from '../databases';
import { CachedOperation, ProgressCallback, withProgress } from '../helpers'; import { CachedOperation } from '../helpers';
import { ProgressCallback, withProgress } from '../commandRunner';
import * as messages from '../pure/messages'; import * as messages from '../pure/messages';
import { QueryServerClient } from '../queryserver-client'; import { QueryServerClient } from '../queryserver-client';
import { compileAndRunQueryAgainstDatabase, QueryWithResults } from '../run-queries'; import { compileAndRunQueryAgainstDatabase, QueryWithResults } from '../run-queries';

View File

@@ -12,10 +12,12 @@ import * as path from 'path';
import { DatabaseManager, DatabaseItem } from './databases'; import { DatabaseManager, DatabaseItem } from './databases';
import { import {
reportStreamProgress,
ProgressCallback,
showAndLogInformationMessage, showAndLogInformationMessage,
} from './helpers'; } from './helpers';
import {
reportStreamProgress,
ProgressCallback,
} from './commandRunner';
import { logger } from './logging'; import { logger } from './logging';
import { tmpDir } from './run-queries'; import { tmpDir } from './run-queries';

View File

@@ -22,8 +22,10 @@ import {
import { import {
commandRunner, commandRunner,
commandRunnerWithProgress, commandRunnerWithProgress,
getOnDiskWorkspaceFolders,
ProgressCallback, ProgressCallback,
} from './commandRunner';
import {
getOnDiskWorkspaceFolders,
showAndLogErrorMessage, showAndLogErrorMessage,
isLikelyDatabaseRoot, isLikelyDatabaseRoot,
isLikelyDbLanguageFolder isLikelyDbLanguageFolder

View File

@@ -9,9 +9,11 @@ import {
showAndLogWarningMessage, showAndLogWarningMessage,
showAndLogInformationMessage, showAndLogInformationMessage,
isLikelyDatabaseRoot, isLikelyDatabaseRoot,
} from './helpers';
import {
ProgressCallback, ProgressCallback,
withProgress withProgress
} from './helpers'; } from './commandRunner';
import { zipArchiveScheme, encodeArchiveBasePath, decodeSourceArchiveUri, encodeSourceArchiveUri } from './archive-filesystem-provider'; import { zipArchiveScheme, encodeArchiveBasePath, decodeSourceArchiveUri, encodeSourceArchiveUri } from './archive-filesystem-provider';
import { DisposableObject } from './vscode-utils/disposable-object'; import { DisposableObject } from './vscode-utils/disposable-object';
import { Logger, logger } from './logging'; import { Logger, logger } from './logging';

View File

@@ -7,10 +7,15 @@ import * as unzipper from 'unzipper';
import * as url from 'url'; import * as url from 'url';
import { ExtensionContext, Event } from 'vscode'; import { ExtensionContext, Event } from 'vscode';
import { DistributionConfig } from './config'; import { DistributionConfig } from './config';
import { InvocationRateLimiter, InvocationRateLimiterResultKind, showAndLogErrorMessage } from './helpers'; import {
InvocationRateLimiter,
InvocationRateLimiterResultKind,
showAndLogErrorMessage,
showAndLogWarningMessage
} from './helpers';
import { logger } from './logging'; import { logger } from './logging';
import * as helpers from './helpers';
import { getCodeQlCliVersion } from './cli-version'; import { getCodeQlCliVersion } from './cli-version';
import { ProgressCallback, reportStreamProgress } from './commandRunner';
/** /**
* distribution.ts * distribution.ts
@@ -221,7 +226,7 @@ export class DistributionManager implements DistributionProvider {
* Returns a failed promise if an unexpected error occurs during installation. * Returns a failed promise if an unexpected error occurs during installation.
*/ */
public installExtensionManagedDistributionRelease(release: Release, public installExtensionManagedDistributionRelease(release: Release,
progressCallback?: helpers.ProgressCallback): Promise<void> { progressCallback?: ProgressCallback): Promise<void> {
return this.extensionSpecificDistributionManager!.installDistributionRelease(release, progressCallback); return this.extensionSpecificDistributionManager!.installDistributionRelease(release, progressCallback);
} }
@@ -303,14 +308,14 @@ class ExtensionSpecificDistributionManager {
* Returns a failed promise if an unexpected error occurs during installation. * Returns a failed promise if an unexpected error occurs during installation.
*/ */
public async installDistributionRelease(release: Release, public async installDistributionRelease(release: Release,
progressCallback?: helpers.ProgressCallback): Promise<void> { progressCallback?: ProgressCallback): Promise<void> {
await this.downloadDistribution(release, progressCallback); await this.downloadDistribution(release, progressCallback);
// Store the installed release within the global extension state. // Store the installed release within the global extension state.
this.storeInstalledRelease(release); this.storeInstalledRelease(release);
} }
private async downloadDistribution(release: Release, private async downloadDistribution(release: Release,
progressCallback?: helpers.ProgressCallback): Promise<void> { progressCallback?: ProgressCallback): Promise<void> {
try { try {
await this.removeDistribution(); await this.removeDistribution();
} catch (e) { } catch (e) {
@@ -338,7 +343,7 @@ class ExtensionSpecificDistributionManager {
const contentLength = assetStream.headers.get('content-length'); const contentLength = assetStream.headers.get('content-length');
const totalNumBytes = contentLength ? parseInt(contentLength, 10) : undefined; const totalNumBytes = contentLength ? parseInt(contentLength, 10) : undefined;
helpers.reportStreamProgress(assetStream.body, 'Downloading CodeQL CLI…', totalNumBytes, progressCallback); reportStreamProgress(assetStream.body, 'Downloading CodeQL CLI…', totalNumBytes, progressCallback);
await new Promise((resolve, reject) => await new Promise((resolve, reject) =>
assetStream.body.pipe(archiveFile) assetStream.body.pipe(archiveFile)
@@ -707,7 +712,9 @@ export async function getExecutableFromDirectory(directory: string, warnWhenNotF
} }
function warnDeprecatedLauncher() { function warnDeprecatedLauncher() {
helpers.showAndLogWarningMessage(
showAndLogWarningMessage(
`The "${deprecatedCodeQlLauncherName()!}" launcher has been deprecated and will be removed in a future version. ` + `The "${deprecatedCodeQlLauncherName()!}" launcher has been deprecated and will be removed in a future version. ` +
`Please use "${codeQlLauncherName()}" instead. It is recommended to update to the latest CodeQL binaries.` `Please use "${codeQlLauncherName()}" instead. It is recommended to update to the latest CodeQL binaries.`
); );

View File

@@ -45,6 +45,7 @@ import {
GithubRateLimitedError GithubRateLimitedError
} from './distribution'; } from './distribution';
import * as helpers from './helpers'; import * as helpers from './helpers';
import { commandRunner, commandRunnerWithProgress, ProgressCallback, ProgressUpdate, withProgress } from './commandRunner';
import { assertNever } from './pure/helpers-pure'; import { assertNever } from './pure/helpers-pure';
import { spawnIdeServer } from './ide-server'; import { spawnIdeServer } from './ide-server';
import { InterfaceManager } from './interface'; import { InterfaceManager } from './interface';
@@ -108,7 +109,7 @@ function registerErrorStubs(excludedCommands: string[], stubGenerator: (command:
stubbedCommands.forEach(command => { stubbedCommands.forEach(command => {
if (excludedCommands.indexOf(command) === -1) { if (excludedCommands.indexOf(command) === -1) {
errorStubs.push(helpers.commandRunner(command, stubGenerator(command))); errorStubs.push(commandRunner(command, stubGenerator(command)));
} }
}); });
} }
@@ -194,7 +195,7 @@ export async function activate(ctx: ExtensionContext): Promise<CodeQLExtensionIn
location: ProgressLocation.Notification, location: ProgressLocation.Notification,
}; };
await helpers.withProgress(progressOptions, progress => await withProgress(progressOptions, progress =>
distributionManager.installExtensionManagedDistributionRelease(result.updatedRelease, progress)); distributionManager.installExtensionManagedDistributionRelease(result.updatedRelease, progress));
await ctx.globalState.update(shouldUpdateOnNextActivationKey, false); await ctx.globalState.update(shouldUpdateOnNextActivationKey, false);
@@ -308,7 +309,7 @@ export async function activate(ctx: ExtensionContext): Promise<CodeQLExtensionIn
shouldDisplayMessageWhenNoUpdates: false, shouldDisplayMessageWhenNoUpdates: false,
allowAutoUpdating: true allowAutoUpdating: true
}))); })));
ctx.subscriptions.push(helpers.commandRunner(checkForUpdatesCommand, () => installOrUpdateThenTryActivate({ ctx.subscriptions.push(commandRunner(checkForUpdatesCommand, () => installOrUpdateThenTryActivate({
isUserInitiated: true, isUserInitiated: true,
shouldDisplayMessageWhenNoUpdates: true, shouldDisplayMessageWhenNoUpdates: true,
allowAutoUpdating: true allowAutoUpdating: true
@@ -430,7 +431,7 @@ async function activateWithInstalledDistribution(
async function compileAndRunQuery( async function compileAndRunQuery(
quickEval: boolean, quickEval: boolean,
selectedQuery: Uri | undefined, selectedQuery: Uri | undefined,
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken, token: CancellationToken,
): Promise<void> { ): Promise<void> {
if (qs !== undefined) { if (qs !== undefined) {
@@ -491,10 +492,10 @@ async function activateWithInstalledDistribution(
logger.log('Registering top-level command palette commands.'); logger.log('Registering top-level command palette commands.');
ctx.subscriptions.push( ctx.subscriptions.push(
helpers.commandRunnerWithProgress( commandRunnerWithProgress(
'codeQL.runQuery', 'codeQL.runQuery',
async ( async (
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken, token: CancellationToken,
uri: Uri | undefined uri: Uri | undefined
) => await compileAndRunQuery(false, uri, progress, token), ) => await compileAndRunQuery(false, uri, progress, token),
@@ -505,10 +506,10 @@ async function activateWithInstalledDistribution(
) )
); );
ctx.subscriptions.push( ctx.subscriptions.push(
helpers.commandRunnerWithProgress( commandRunnerWithProgress(
'codeQL.runQueries', 'codeQL.runQueries',
async ( async (
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken, token: CancellationToken,
_: Uri | undefined, _: Uri | undefined,
multi: Uri[] multi: Uri[]
@@ -533,7 +534,7 @@ async function activateWithInstalledDistribution(
// Use a wrapped progress so that messages appear with the queries remaining in it. // Use a wrapped progress so that messages appear with the queries remaining in it.
let queriesRemaining = queryUris.length; let queriesRemaining = queryUris.length;
function wrappedProgress(update: helpers.ProgressUpdate) { function wrappedProgress(update: ProgressUpdate) {
const message = queriesRemaining > 1 const message = queriesRemaining > 1
? `${queriesRemaining} remaining. ${update.message}` ? `${queriesRemaining} remaining. ${update.message}`
: update.message; : update.message;
@@ -569,10 +570,10 @@ async function activateWithInstalledDistribution(
}) })
); );
ctx.subscriptions.push( ctx.subscriptions.push(
helpers.commandRunnerWithProgress( commandRunnerWithProgress(
'codeQL.quickEval', 'codeQL.quickEval',
async ( async (
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken, token: CancellationToken,
uri: Uri | undefined uri: Uri | undefined
) => await compileAndRunQuery(true, uri, progress, token), ) => await compileAndRunQuery(true, uri, progress, token),
@@ -582,8 +583,8 @@ async function activateWithInstalledDistribution(
}) })
); );
ctx.subscriptions.push( ctx.subscriptions.push(
helpers.commandRunnerWithProgress('codeQL.quickQuery', async ( commandRunnerWithProgress('codeQL.quickQuery', async (
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken token: CancellationToken
) => ) =>
displayQuickQuery(ctx, cliServer, databaseUI, progress, token), displayQuickQuery(ctx, cliServer, databaseUI, progress, token),
@@ -594,7 +595,7 @@ async function activateWithInstalledDistribution(
); );
ctx.subscriptions.push( ctx.subscriptions.push(
helpers.commandRunner('codeQL.restartQueryServer', async () => { commandRunner('codeQL.restartQueryServer', async () => {
await qs.restartQueryServer(); await qs.restartQueryServer();
helpers.showAndLogInformationMessage('CodeQL Query Server restarted.', { helpers.showAndLogInformationMessage('CodeQL Query Server restarted.', {
outputLogger: queryServerLogger, outputLogger: queryServerLogger,
@@ -602,24 +603,24 @@ async function activateWithInstalledDistribution(
}) })
); );
ctx.subscriptions.push( ctx.subscriptions.push(
helpers.commandRunner('codeQL.chooseDatabaseFolder', ( commandRunner('codeQL.chooseDatabaseFolder', (
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken token: CancellationToken
) => ) =>
databaseUI.handleChooseDatabaseFolder(progress, token) databaseUI.handleChooseDatabaseFolder(progress, token)
) )
); );
ctx.subscriptions.push( ctx.subscriptions.push(
helpers.commandRunner('codeQL.chooseDatabaseArchive', ( commandRunner('codeQL.chooseDatabaseArchive', (
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken token: CancellationToken
) => ) =>
databaseUI.handleChooseDatabaseArchive(progress, token) databaseUI.handleChooseDatabaseArchive(progress, token)
) )
); );
ctx.subscriptions.push( ctx.subscriptions.push(
helpers.commandRunnerWithProgress('codeQL.chooseDatabaseLgtm', ( commandRunnerWithProgress('codeQL.chooseDatabaseLgtm', (
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken token: CancellationToken
) => ) =>
databaseUI.handleChooseDatabaseLgtm(progress, token), databaseUI.handleChooseDatabaseLgtm(progress, token),
@@ -628,8 +629,8 @@ async function activateWithInstalledDistribution(
}) })
); );
ctx.subscriptions.push( ctx.subscriptions.push(
helpers.commandRunnerWithProgress('codeQL.chooseDatabaseInternet', ( commandRunnerWithProgress('codeQL.chooseDatabaseInternet', (
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken token: CancellationToken
) => ) =>
databaseUI.handleChooseDatabaseInternet(progress, token), databaseUI.handleChooseDatabaseInternet(progress, token),
@@ -656,8 +657,8 @@ async function activateWithInstalledDistribution(
const astViewer = new AstViewer(); const astViewer = new AstViewer();
ctx.subscriptions.push(astViewer); ctx.subscriptions.push(astViewer);
ctx.subscriptions.push(helpers.commandRunnerWithProgress('codeQL.viewAst', async ( ctx.subscriptions.push(commandRunnerWithProgress('codeQL.viewAst', async (
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken token: CancellationToken
) => { ) => {
const ast = await new TemplatePrintAstProvider(cliServer, qs, dbm, progress, token) const ast = await new TemplatePrintAstProvider(cliServer, qs, dbm, progress, token)

View File

@@ -3,181 +3,13 @@ import * as glob from 'glob-promise';
import * as yaml from 'js-yaml'; import * as yaml from 'js-yaml';
import * as path from 'path'; import * as path from 'path';
import { import {
CancellationToken,
ExtensionContext, ExtensionContext,
ProgressOptions,
window as Window, window as Window,
workspace, workspace
commands,
Disposable,
ProgressLocation
} from 'vscode'; } from 'vscode';
import { CodeQLCliServer } from './cli'; import { CodeQLCliServer } from './cli';
import { logger } from './logging'; import { logger } from './logging';
export class UserCancellationException extends Error {
/**
* @param message The error message
* @param silent If silent is true, then this exception will avoid showing a warning message to the user.
*/
constructor(message?: string, public readonly silent = false) {
super(message);
}
}
export interface ProgressUpdate {
/**
* The current step
*/
step: number;
/**
* The maximum step. This *should* be constant for a single job.
*/
maxStep: number;
/**
* The current progress message
*/
message: string;
}
export type ProgressCallback = (p: ProgressUpdate) => void;
/**
* A task that handles command invocations from `commandRunner`
* and includes a progress monitor.
*
*
* Arguments passed to the command handler are passed along,
* untouched to this `ProgressTask` instance.
*
* @param progress a progress handler function. Call this
* function with a `ProgressUpdate` instance in order to
* denote some progress being achieved on this task.
* @param token a cencellation token
* @param args arguments passed to this task passed on from
* `commands.registerCommand`.
*/
export type ProgressTask<R> = (
progress: ProgressCallback,
token: CancellationToken,
...args: any[]
) => Thenable<R>;
/**
* A task that handles command invocations from `commandRunner`.
* Arguments passed to the command handler are passed along,
* untouched to this `NoProgressTask` instance.
*
* @param args arguments passed to this task passed on from
* `commands.registerCommand`.
*/
type NoProgressTask = ((...args: any[]) => Promise<any>);
/**
* This mediates between the kind of progress callbacks we want to
* write (where we *set* current progress position and give
* `maxSteps`) and the kind vscode progress api expects us to write
* (which increment progress by a certain amount out of 100%).
*
* Where possible, the `commandRunner` function below should be used
* instead of this function. The commandRunner is meant for wrapping
* top-level commands and provides error handling and other support
* automatically.
*
* Only use this function if you need a progress monitor and the
* control flow does not always come from a command (eg- during
* extension activation, or from an internal language server
* request).
*/
export function withProgress<R>(
options: ProgressOptions,
task: ProgressTask<R>,
...args: any[]
): Thenable<R> {
let progressAchieved = 0;
return Window.withProgress(options,
(progress, token) => {
return task(p => {
const { message, step, maxStep } = p;
const increment = 100 * (step - progressAchieved) / maxStep;
progressAchieved = step;
progress.report({ message, increment });
}, token, ...args);
});
}
/**
* A generic wrapper for command registration. This wrapper adds uniform error handling for commands.
*
* In this variant of the command runner, no progress monitor is used.
*
* @param commandId The ID of the command to register.
* @param task The task to run. It is passed directly to `commands.registerCommand`. Any
* arguments to the command handler are passed on to the task.
*/
export function commandRunner(
commandId: string,
task: NoProgressTask,
): Disposable {
return commands.registerCommand(commandId, async (...args: any[]) => {
try {
return await task(...args);
} catch (e) {
const errorMessage = `${e.message || e} (${commandId})`;
if (e instanceof UserCancellationException) {
// User has cancelled this action manually
if (e.silent) {
logger.log(errorMessage);
} else {
showAndLogWarningMessage(errorMessage);
}
} else {
showAndLogErrorMessage(errorMessage);
}
return undefined;
}
});
}
/**
* A generic wrapper for command registration. This wrapper adds uniform error handling,
* progress monitoring, and cancellation for commands.
*
* @param commandId The ID of the command to register.
* @param task The task to run. It is passed directly to `commands.registerCommand`. Any
* arguments to the command handler are passed on to the task after the progress callback
* and cancellation token.
* @param progressOptions Progress options to be sent to the progress monitor.
*/
export function commandRunnerWithProgress<R>(
commandId: string,
task: ProgressTask<R>,
progressOptions: Partial<ProgressOptions>
): Disposable {
return commands.registerCommand(commandId, async (...args: any[]) => {
const progressOptionsWithDefaults = {
location: ProgressLocation.Notification,
...progressOptions
};
try {
return await withProgress(progressOptionsWithDefaults, task, ...args);
} catch (e) {
const errorMessage = `${e.message || e} (${commandId})`;
if (e instanceof UserCancellationException) {
// User has cancelled this action manually
if (e.silent) {
logger.log(errorMessage);
} else {
showAndLogWarningMessage(errorMessage);
}
} else {
showAndLogErrorMessage(errorMessage);
}
return undefined;
}
});
}
/** /**
* Show an error message and log it to the console * Show an error message and log it to the console
* *
@@ -532,46 +364,3 @@ export async function isLikelyDatabaseRoot(maybeRoot: string) {
export function isLikelyDbLanguageFolder(dbPath: string) { export function isLikelyDbLanguageFolder(dbPath: string) {
return !!path.basename(dbPath).startsWith('db-'); return !!path.basename(dbPath).startsWith('db-');
} }
/**
* Displays a progress monitor that indicates how much progess has been made
* reading from a stream.
*
* @param readable The stream to read progress from
* @param messagePrefix A prefix for displaying the message
* @param totalNumBytes Total number of bytes in this stream
* @param progress The progress callback used to set messages
*/
export function reportStreamProgress(
readable: NodeJS.ReadableStream,
messagePrefix: string,
totalNumBytes?: number,
progress?: ProgressCallback
) {
if (progress && totalNumBytes) {
let numBytesDownloaded = 0;
const bytesToDisplayMB = (numBytes: number): string => `${(numBytes / (1024 * 1024)).toFixed(1)} MB`;
const updateProgress = () => {
progress({
step: numBytesDownloaded,
maxStep: totalNumBytes,
message: `${messagePrefix} [${bytesToDisplayMB(numBytesDownloaded)} of ${bytesToDisplayMB(totalNumBytes)}]`,
});
};
// Display the progress straight away rather than waiting for the first chunk.
updateProgress();
readable.on('data', data => {
numBytesDownloaded += data.length;
updateProgress();
});
} else if (progress) {
progress({
step: 1,
maxStep: 2,
message: `${messagePrefix} (Size unknown)`,
});
}
}

View File

@@ -30,7 +30,7 @@ import {
RawResultsSortState, RawResultsSortState,
} from './pure/interface-types'; } from './pure/interface-types';
import { Logger } from './logging'; import { Logger } from './logging';
import { commandRunner } from './helpers'; import { commandRunner } from './commandRunner';
import * as messages from './pure/messages'; import * as messages from './pure/messages';
import { CompletedQuery, interpretResults } from './query-results'; import { CompletedQuery, interpretResults } from './query-results';
import { QueryInfo, tmpDir } from './run-queries'; import { QueryInfo, tmpDir } from './run-queries';

View File

@@ -4,7 +4,15 @@ import { window as Window } from 'vscode';
import { CompletedQuery } from './query-results'; import { CompletedQuery } from './query-results';
import { QueryHistoryConfig } from './config'; import { QueryHistoryConfig } from './config';
import { QueryWithResults } from './run-queries'; import { QueryWithResults } from './run-queries';
import * as helpers from './helpers'; import {
showAndLogErrorMessage,
showAndLogInformationMessage,
showAndLogWarningMessage,
showBinaryChoiceDialog
} from './helpers';
import {
commandRunner
} from './commandRunner';
import { logger } from './logging'; import { logger } from './logging';
import { URLSearchParams } from 'url'; import { URLSearchParams } from 'url';
import { QueryServerClient } from './queryserver-client'; import { QueryServerClient } from './queryserver-client';
@@ -207,55 +215,55 @@ export class QueryHistoryManager extends DisposableObject {
logger.log('Registering query history panel commands.'); logger.log('Registering query history panel commands.');
this.push( this.push(
helpers.commandRunner( commandRunner(
'codeQLQueryHistory.openQuery', 'codeQLQueryHistory.openQuery',
this.handleOpenQuery.bind(this) this.handleOpenQuery.bind(this)
) )
); );
this.push( this.push(
helpers.commandRunner( commandRunner(
'codeQLQueryHistory.removeHistoryItem', 'codeQLQueryHistory.removeHistoryItem',
this.handleRemoveHistoryItem.bind(this) this.handleRemoveHistoryItem.bind(this)
) )
); );
this.push( this.push(
helpers.commandRunner( commandRunner(
'codeQLQueryHistory.setLabel', 'codeQLQueryHistory.setLabel',
this.handleSetLabel.bind(this) this.handleSetLabel.bind(this)
) )
); );
this.push( this.push(
helpers.commandRunner( commandRunner(
'codeQLQueryHistory.compareWith', 'codeQLQueryHistory.compareWith',
this.handleCompareWith.bind(this) this.handleCompareWith.bind(this)
) )
); );
this.push( this.push(
helpers.commandRunner( commandRunner(
'codeQLQueryHistory.showQueryLog', 'codeQLQueryHistory.showQueryLog',
this.handleShowQueryLog.bind(this) this.handleShowQueryLog.bind(this)
) )
); );
this.push( this.push(
helpers.commandRunner( commandRunner(
'codeQLQueryHistory.showQueryText', 'codeQLQueryHistory.showQueryText',
this.handleShowQueryText.bind(this) this.handleShowQueryText.bind(this)
) )
); );
this.push( this.push(
helpers.commandRunner( commandRunner(
'codeQLQueryHistory.viewSarif', 'codeQLQueryHistory.viewSarif',
this.handleViewSarif.bind(this) this.handleViewSarif.bind(this)
) )
); );
this.push( this.push(
helpers.commandRunner( commandRunner(
'codeQLQueryHistory.viewDil', 'codeQLQueryHistory.viewDil',
this.handleViewDil.bind(this) this.handleViewDil.bind(this)
) )
); );
this.push( this.push(
helpers.commandRunner( commandRunner(
'codeQLQueryHistory.itemClicked', 'codeQLQueryHistory.itemClicked',
async (item: CompletedQuery) => { async (item: CompletedQuery) => {
return this.handleItemClicked(item, [item]); return this.handleItemClicked(item, [item]);
@@ -376,7 +384,7 @@ export class QueryHistoryManager extends DisposableObject {
this.doCompareCallback(from, to); this.doCompareCallback(from, to);
} }
} catch (e) { } catch (e) {
helpers.showAndLogErrorMessage(e.message); showAndLogErrorMessage(e.message);
} }
} }
@@ -423,7 +431,7 @@ export class QueryHistoryManager extends DisposableObject {
if (singleItem.logFileLocation) { if (singleItem.logFileLocation) {
await this.tryOpenExternalFile(singleItem.logFileLocation); await this.tryOpenExternalFile(singleItem.logFileLocation);
} else { } else {
helpers.showAndLogWarningMessage('No log file available'); showAndLogWarningMessage('No log file available');
} }
} }
@@ -468,7 +476,7 @@ export class QueryHistoryManager extends DisposableObject {
); );
} else { } else {
const label = singleItem.getLabel(); const label = singleItem.getLabel();
helpers.showAndLogInformationMessage( showAndLogInformationMessage(
`Query ${label} has no interpreted results.` `Query ${label} has no interpreted results.`
); );
} }
@@ -547,7 +555,7 @@ export class QueryHistoryManager extends DisposableObject {
) || ) ||
e.message.includes('too large to open') e.message.includes('too large to open')
) { ) {
const res = await helpers.showBinaryChoiceDialog( const res = await showBinaryChoiceDialog(
`VS Code does not allow extensions to open files >50MB. This file `VS Code does not allow extensions to open files >50MB. This file
exceeds that limit. Do you want to open it outside of VS Code? exceeds that limit. Do you want to open it outside of VS Code?
@@ -558,11 +566,11 @@ the file in the file explorer and dragging it into the workspace.`
try { try {
await vscode.commands.executeCommand('revealFileInOS', uri); await vscode.commands.executeCommand('revealFileInOS', uri);
} catch (e) { } catch (e) {
helpers.showAndLogErrorMessage(e.message); showAndLogErrorMessage(e.message);
} }
} }
} else { } else {
helpers.showAndLogErrorMessage(`Could not open file ${fileLocation}`); showAndLogErrorMessage(`Could not open file ${fileLocation}`);
logger.log(e.message); logger.log(e.message);
logger.log(e.stack); logger.log(e.stack);
} }
@@ -616,7 +624,7 @@ the file in the file explorer and dragging it into the workspace.`
private assertSingleQuery(multiSelect: CompletedQuery[] = [], message = 'Please select a single query.') { private assertSingleQuery(multiSelect: CompletedQuery[] = [], message = 'Please select a single query.') {
if (multiSelect.length > 1) { if (multiSelect.length > 1) {
helpers.showAndLogErrorMessage( showAndLogErrorMessage(
message message
); );
return false; return false;

View File

@@ -10,11 +10,13 @@ import {
getInitialQueryContents, getInitialQueryContents,
getPrimaryDbscheme, getPrimaryDbscheme,
getQlPackForDbscheme, getQlPackForDbscheme,
ProgressCallback,
showAndLogErrorMessage, showAndLogErrorMessage,
showBinaryChoiceDialog, showBinaryChoiceDialog,
UserCancellationException
} from './helpers'; } from './helpers';
import {
ProgressCallback,
UserCancellationException
} from './commandRunner';
const QUICK_QUERIES_DIR_NAME = 'quick-queries'; const QUICK_QUERIES_DIR_NAME = 'quick-queries';
const QUICK_QUERY_QUERY_NAME = 'quick-query.ql'; const QUICK_QUERY_QUERY_NAME = 'quick-query.ql';

View File

@@ -15,7 +15,8 @@ import { ErrorCodes, ResponseError } from 'vscode-languageclient';
import * as cli from './cli'; import * as cli from './cli';
import * as config from './config'; import * as config from './config';
import { DatabaseItem, getUpgradesDirectories } from './databases'; import { DatabaseItem, getUpgradesDirectories } from './databases';
import * as helpers from './helpers'; import { getOnDiskWorkspaceFolders, showAndLogErrorMessage } from './helpers';
import { ProgressCallback, UserCancellationException } from './commandRunner';
import { DatabaseInfo, QueryMetadata, ResultsPaths } from './pure/interface-types'; import { DatabaseInfo, QueryMetadata, ResultsPaths } from './pure/interface-types';
import { logger } from './logging'; import { logger } from './logging';
import * as messages from './pure/messages'; import * as messages from './pure/messages';
@@ -79,7 +80,7 @@ export class QueryInfo {
async run( async run(
qs: qsClient.QueryServerClient, qs: qsClient.QueryServerClient,
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken, token: CancellationToken,
): Promise<messages.EvaluationResult> { ): Promise<messages.EvaluationResult> {
let result: messages.EvaluationResult | null = null; let result: messages.EvaluationResult | null = null;
@@ -121,7 +122,7 @@ export class QueryInfo {
async compile( async compile(
qs: qsClient.QueryServerClient, qs: qsClient.QueryServerClient,
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken, token: CancellationToken,
): Promise<messages.CompilationMessage[]> { ): Promise<messages.CompilationMessage[]> {
let compiled: messages.CheckQueryResult | undefined; let compiled: messages.CheckQueryResult | undefined;
@@ -209,7 +210,7 @@ export interface QueryWithResults {
export async function clearCacheInDatabase( export async function clearCacheInDatabase(
qs: qsClient.QueryServerClient, qs: qsClient.QueryServerClient,
dbItem: DatabaseItem, dbItem: DatabaseItem,
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken, token: CancellationToken,
): Promise<messages.ClearCacheResult> { ): Promise<messages.ClearCacheResult> {
if (dbItem.contents === undefined) { if (dbItem.contents === undefined) {
@@ -285,10 +286,10 @@ async function checkDbschemeCompatibility(
cliServer: cli.CodeQLCliServer, cliServer: cli.CodeQLCliServer,
qs: qsClient.QueryServerClient, qs: qsClient.QueryServerClient,
query: QueryInfo, query: QueryInfo,
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken, token: CancellationToken,
): Promise<void> { ): Promise<void> {
const searchPath = helpers.getOnDiskWorkspaceFolders(); const searchPath = getOnDiskWorkspaceFolders();
if (query.dbItem.contents !== undefined && query.dbItem.contents.dbSchemeUri !== undefined) { if (query.dbItem.contents !== undefined && query.dbItem.contents.dbSchemeUri !== undefined) {
const { scripts, finalDbscheme } = await cliServer.resolveUpgrades(query.dbItem.contents.dbSchemeUri.fsPath, searchPath); const { scripts, finalDbscheme } = await cliServer.resolveUpgrades(query.dbItem.contents.dbSchemeUri.fsPath, searchPath);
@@ -364,7 +365,7 @@ async function promptUserToSaveChanges(document: TextDocument): Promise<boolean>
} }
if (chosenItem === cancelItem) { if (chosenItem === cancelItem) {
throw new helpers.UserCancellationException('Query run cancelled.', true); throw new UserCancellationException('Query run cancelled.', true);
} }
} }
} }
@@ -454,7 +455,7 @@ export async function compileAndRunQueryAgainstDatabase(
db: DatabaseItem, db: DatabaseItem,
quickEval: boolean, quickEval: boolean,
selectedQueryUri: Uri | undefined, selectedQueryUri: Uri | undefined,
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: CancellationToken, token: CancellationToken,
templates?: messages.TemplateDefinitions, templates?: messages.TemplateDefinitions,
): Promise<QueryWithResults> { ): Promise<QueryWithResults> {
@@ -474,7 +475,7 @@ export async function compileAndRunQueryAgainstDatabase(
} }
// Get the workspace folder paths. // Get the workspace folder paths.
const diskWorkspaceFolders = helpers.getOnDiskWorkspaceFolders(); const diskWorkspaceFolders = getOnDiskWorkspaceFolders();
// Figure out the library path for the query. // Figure out the library path for the query.
const packConfig = await cliServer.resolveLibraryPath(diskWorkspaceFolders, queryPath); const packConfig = await cliServer.resolveLibraryPath(diskWorkspaceFolders, queryPath);
@@ -533,7 +534,7 @@ export async function compileAndRunQueryAgainstDatabase(
if (result.resultType !== messages.QueryResultType.SUCCESS) { if (result.resultType !== messages.QueryResultType.SUCCESS) {
const message = result.message || 'Failed to run query'; const message = result.message || 'Failed to run query';
logger.log(message); logger.log(message);
helpers.showAndLogErrorMessage(message); showAndLogErrorMessage(message);
} }
return { return {
query, query,
@@ -564,9 +565,9 @@ export async function compileAndRunQueryAgainstDatabase(
qs.logger.log(formatted); qs.logger.log(formatted);
} }
if (quickEval && formattedMessages.length <= 3) { if (quickEval && formattedMessages.length <= 3) {
helpers.showAndLogErrorMessage('Quick evaluation compilation failed: \n' + formattedMessages.join('\n')); showAndLogErrorMessage('Quick evaluation compilation failed: \n' + formattedMessages.join('\n'));
} else { } else {
helpers.showAndLogErrorMessage((quickEval ? 'Quick evaluation' : 'Query') + showAndLogErrorMessage((quickEval ? 'Quick evaluation' : 'Query') +
' compilation failed. Please make sure there are no errors in the query, the database is up to date,' + ' compilation failed. Please make sure there are no errors in the query, the database is up to date,' +
' and the query and database use the same target language. For more details on the error, go to View > Output,' + ' and the query and database use the same target language. For more details on the error, go to View > Output,' +
' and choose CodeQL Query Server from the dropdown.'); ' and choose CodeQL Query Server from the dropdown.');

View File

@@ -1,6 +1,7 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { DatabaseItem } from './databases'; import { DatabaseItem } from './databases';
import * as helpers from './helpers'; import { showAndLogErrorMessage } from './helpers';
import { ProgressCallback, UserCancellationException } from './commandRunner';
import { logger } from './logging'; import { logger } from './logging';
import * as messages from './pure/messages'; import * as messages from './pure/messages';
import * as qsClient from './queryserver-client'; import * as qsClient from './queryserver-client';
@@ -24,7 +25,7 @@ async function checkAndConfirmDatabaseUpgrade(
db: DatabaseItem, db: DatabaseItem,
targetDbScheme: vscode.Uri, targetDbScheme: vscode.Uri,
upgradesDirectories: vscode.Uri[], upgradesDirectories: vscode.Uri[],
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: vscode.CancellationToken, token: vscode.CancellationToken,
): Promise<messages.UpgradeParams | undefined> { ): Promise<messages.UpgradeParams | undefined> {
if (db.contents === undefined || db.contents.dbSchemeUri === undefined) { if (db.contents === undefined || db.contents.dbSchemeUri === undefined) {
@@ -75,7 +76,7 @@ async function checkAndConfirmDatabaseUpgrade(
if (curSha != targetSha) { if (curSha != targetSha) {
// Newlines aren't rendered in notifications: https://github.com/microsoft/vscode/issues/48900 // Newlines aren't rendered in notifications: https://github.com/microsoft/vscode/issues/48900
// A modal dialog would be rendered better, but is more intrusive. // A modal dialog would be rendered better, but is more intrusive.
await helpers.showAndLogErrorMessage(`Database cannot be upgraded to the target database scheme. await showAndLogErrorMessage(`Database cannot be upgraded to the target database scheme.
Can upgrade from ${checkedUpgrades.initialSha} (current) to ${curSha}, but cannot reach ${targetSha} (target).`); Can upgrade from ${checkedUpgrades.initialSha} (current) to ${curSha}, but cannot reach ${targetSha} (target).`);
// TODO: give a more informative message if we think the DB is ahead of the target DB scheme // TODO: give a more informative message if we think the DB is ahead of the target DB scheme
return; return;
@@ -114,7 +115,7 @@ async function checkAndConfirmDatabaseUpgrade(
return params; return params;
} }
else { else {
throw new helpers.UserCancellationException('User cancelled the database upgrade.'); throw new UserCancellationException('User cancelled the database upgrade.');
} }
} }
@@ -128,7 +129,7 @@ export async function upgradeDatabase(
qs: qsClient.QueryServerClient, qs: qsClient.QueryServerClient,
db: DatabaseItem, targetDbScheme: vscode.Uri, db: DatabaseItem, targetDbScheme: vscode.Uri,
upgradesDirectories: vscode.Uri[], upgradesDirectories: vscode.Uri[],
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: vscode.CancellationToken, token: vscode.CancellationToken,
): Promise<messages.RunUpgradeResult | undefined> { ): Promise<messages.RunUpgradeResult | undefined> {
const upgradeParams = await checkAndConfirmDatabaseUpgrade(qs, db, targetDbScheme, upgradesDirectories, progress, token); const upgradeParams = await checkAndConfirmDatabaseUpgrade(qs, db, targetDbScheme, upgradesDirectories, progress, token);
@@ -142,7 +143,7 @@ export async function upgradeDatabase(
compileUpgradeResult = await compileDatabaseUpgrade(qs, upgradeParams, progress, token); compileUpgradeResult = await compileDatabaseUpgrade(qs, upgradeParams, progress, token);
} }
catch (e) { catch (e) {
helpers.showAndLogErrorMessage(`Compilation of database upgrades failed: ${e}`); showAndLogErrorMessage(`Compilation of database upgrades failed: ${e}`);
return; return;
} }
finally { finally {
@@ -151,7 +152,7 @@ export async function upgradeDatabase(
if (compileUpgradeResult.compiledUpgrades === undefined) { if (compileUpgradeResult.compiledUpgrades === undefined) {
const error = compileUpgradeResult.error || '[no error message available]'; const error = compileUpgradeResult.error || '[no error message available]';
helpers.showAndLogErrorMessage(`Compilation of database upgrades failed: ${error}`); (`Compilation of database upgrades failed: ${error}`);
return; return;
} }
@@ -168,7 +169,7 @@ export async function upgradeDatabase(
return await runDatabaseUpgrade(qs, db, compileUpgradeResult.compiledUpgrades, progress, token); return await runDatabaseUpgrade(qs, db, compileUpgradeResult.compiledUpgrades, progress, token);
} }
catch (e) { catch (e) {
helpers.showAndLogErrorMessage(`Database upgrade failed: ${e}`); showAndLogErrorMessage(`Database upgrade failed: ${e}`);
return; return;
} }
finally { finally {
@@ -179,7 +180,7 @@ export async function upgradeDatabase(
async function checkDatabaseUpgrade( async function checkDatabaseUpgrade(
qs: qsClient.QueryServerClient, qs: qsClient.QueryServerClient,
upgradeParams: messages.UpgradeParams, upgradeParams: messages.UpgradeParams,
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: vscode.CancellationToken, token: vscode.CancellationToken,
): Promise<messages.CheckUpgradeResult> { ): Promise<messages.CheckUpgradeResult> {
progress({ progress({
@@ -194,7 +195,7 @@ async function checkDatabaseUpgrade(
async function compileDatabaseUpgrade( async function compileDatabaseUpgrade(
qs: qsClient.QueryServerClient, qs: qsClient.QueryServerClient,
upgradeParams: messages.UpgradeParams, upgradeParams: messages.UpgradeParams,
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: vscode.CancellationToken, token: vscode.CancellationToken,
): Promise<messages.CompileUpgradeResult> { ): Promise<messages.CompileUpgradeResult> {
const params: messages.CompileUpgradeParams = { const params: messages.CompileUpgradeParams = {
@@ -216,7 +217,7 @@ async function runDatabaseUpgrade(
qs: qsClient.QueryServerClient, qs: qsClient.QueryServerClient,
db: DatabaseItem, db: DatabaseItem,
upgrades: messages.CompiledUpgrades, upgrades: messages.CompiledUpgrades,
progress: helpers.ProgressCallback, progress: ProgressCallback,
token: vscode.CancellationToken, token: vscode.CancellationToken,
): Promise<messages.RunUpgradeResult> { ): Promise<messages.RunUpgradeResult> {

View File

@@ -7,7 +7,7 @@ import { extensions, CancellationToken, Uri, window } from 'vscode';
import { CodeQLExtensionInterface } from '../../extension'; import { CodeQLExtensionInterface } from '../../extension';
import { DatabaseManager } from '../../databases'; import { DatabaseManager } from '../../databases';
import { promptImportLgtmDatabase, importArchiveDatabase, promptImportInternetDatabase } from '../../databaseFetcher'; import { promptImportLgtmDatabase, importArchiveDatabase, promptImportInternetDatabase } from '../../databaseFetcher';
import { ProgressCallback } from '../../helpers'; import { ProgressCallback } from '../../commandRunner';
import { dbLoc, DB_URL, storagePath } from './global.helper'; import { dbLoc, DB_URL, storagePath } from './global.helper';
/** /**

View File

@@ -17,7 +17,7 @@ import {
import { Logger } from '../../logging'; import { Logger } from '../../logging';
import { QueryServerClient } from '../../queryserver-client'; import { QueryServerClient } from '../../queryserver-client';
import { registerDatabases } from '../../pure/messages'; import { registerDatabases } from '../../pure/messages';
import { ProgressCallback } from '../../helpers'; import { ProgressCallback } from '../../commandRunner';
import { CodeQLCliServer } from '../../cli'; import { CodeQLCliServer } from '../../cli';
import { encodeArchiveBasePath, encodeSourceArchiveUri } from '../../archive-filesystem-provider'; import { encodeArchiveBasePath, encodeSourceArchiveUri } from '../../archive-filesystem-provider';

View File

@@ -7,7 +7,8 @@ import * as path from 'path';
import * as fs from 'fs-extra'; import * as fs from 'fs-extra';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import { getInitialQueryContents, InvocationRateLimiter, isLikelyDbLanguageFolder, reportStreamProgress } from '../../helpers'; import { getInitialQueryContents, InvocationRateLimiter, isLikelyDbLanguageFolder } from '../../helpers';
import { reportStreamProgress } from '../../commandRunner';
describe('helpers', () => { describe('helpers', () => {
let sandbox: sinon.SinonSandbox; let sandbox: sinon.SinonSandbox;

View File

@@ -1,6 +1,6 @@
import { TreeDataProvider, window } from 'vscode'; import { TreeDataProvider, window } from 'vscode';
import { DisposableObject } from './disposable-object'; import { DisposableObject } from './disposable-object';
import { commandRunner } from '../helpers'; import { commandRunner } from '../commandRunner';
/** /**
* A VS Code service that interacts with the UI, including handling commands. * A VS Code service that interacts with the UI, including handling commands.