Pull progress to separate file

This commit is contained in:
Robert 2023-03-20 10:52:28 +00:00
Родитель 8a66bb4017
Коммит b914b97be7
28 изменённых файлов: 169 добавлений и 178 удалений

Просмотреть файл

@ -1,11 +1,4 @@
import {
CancellationToken,
ProgressOptions as VSCodeProgressOptions,
window as Window,
commands,
Disposable,
ProgressLocation,
} from "vscode";
import { CancellationToken, commands, Disposable } from "vscode";
import {
showAndLogExceptionWithTelemetry,
showAndLogWarningMessage,
@ -14,51 +7,22 @@ import { extLogger } from "./common";
import { asError, getErrorMessage, getErrorStack } from "./pure/helpers-pure";
import { telemetryListener } from "./telemetry";
import { redactableError } from "./pure/errors";
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;
// Make certain properties within a type optional
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
export type ProgressOptions = Optional<VSCodeProgressOptions, "location">;
import {
UserCancellationException,
withProgress,
ProgressOptions,
ProgressCallback,
} from "./progress";
/**
* A task that reports progress.
* A task that handles command invocations from `commandRunner`.
* Arguments passed to the command handler are passed along,
* untouched to this `NoProgressTask` 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 cancellation token
* @param args arguments passed to this task passed on from
* `commands.registerCommand`.
*/
export type ProgressTask<R> = (
progress: ProgressCallback,
token: CancellationToken,
) => Thenable<R>;
export type NoProgressTask = (...args: any[]) => Promise<any>;
/**
* A task that handles command invocations from `commandRunner`
@ -75,64 +39,12 @@ export type ProgressTask<R> = (
* @param args arguments passed to this task passed on from
* `commands.registerCommand`.
*/
export type ProgressTaskWithArgs<R> = (
type ProgressTaskWithArgs<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`.
*/
export 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>(
task: ProgressTask<R>,
{
location = ProgressLocation.Notification,
title,
cancellable,
}: ProgressOptions = {},
): Thenable<R> {
let progressAchieved = 0;
return Window.withProgress(
{
location,
title,
cancellable,
},
(progress, token) => {
return task((p) => {
const { message, step, maxStep } = p;
const increment = (100 * (step - progressAchieved)) / maxStep;
progressAchieved = step;
progress.report({ message, increment });
}, token);
},
);
}
/**
* A generic wrapper for command registration. This wrapper adds uniform error handling for commands.
*
@ -216,48 +128,3 @@ export function commandRunnerWithProgress<R>(
outputLogger,
);
}
/**
* 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)`,
});
}
}

Просмотреть файл

@ -11,7 +11,7 @@ import {
import { CodeQLCliServer } from "../cli";
import { DatabaseManager, DatabaseItem } from "../local-databases";
import fileRangeFromURI from "./fileRangeFromURI";
import { ProgressCallback } from "../commandRunner";
import { ProgressCallback } from "../progress";
import { KeyType } from "./keyType";
import {
qlpackOfDatabase,

Просмотреть файл

@ -16,7 +16,7 @@ import { DatabaseItem } from "../local-databases";
import { extLogger } from "../common";
import { createInitialQueryInfo } from "../run-queries-shared";
import { CancellationToken, Uri } from "vscode";
import { ProgressCallback } from "../commandRunner";
import { ProgressCallback } from "../progress";
import { QueryRunner } from "../queryRunner";
import { redactableError } from "../pure/errors";
import { QLPACK_FILENAMES } from "../pure/ql";

Просмотреть файл

@ -18,7 +18,7 @@ import {
import { CodeQLCliServer } from "../cli";
import { DatabaseManager } from "../local-databases";
import { CachedOperation } from "../helpers";
import { ProgressCallback, withProgress } from "../commandRunner";
import { ProgressCallback, withProgress } from "../progress";
import AstBuilder from "./astBuilder";
import { KeyType } from "./keyType";
import {

Просмотреть файл

@ -18,7 +18,7 @@ import { retry } from "@octokit/plugin-retry";
import { DatabaseManager, DatabaseItem } from "./local-databases";
import { showAndLogInformationMessage, tmpDir } from "./helpers";
import { reportStreamProgress, ProgressCallback } from "./commandRunner";
import { reportStreamProgress, ProgressCallback } from "./progress";
import { extLogger } from "./common";
import { getErrorMessage } from "./pure/helpers-pure";
import {

Просмотреть файл

@ -7,7 +7,7 @@ import {
window,
workspace,
} from "vscode";
import { UserCancellationException } from "../../commandRunner";
import { UserCancellationException } from "../../progress";
import {
getNwoFromGitHubUrl,
isValidGitHubNwo,

Просмотреть файл

@ -14,7 +14,7 @@ import {
} from "./helpers";
import { extLogger } from "./common";
import { getCodeQlCliVersion } from "./cli-version";
import { ProgressCallback, reportStreamProgress } from "./commandRunner";
import { ProgressCallback, reportStreamProgress } from "./progress";
import {
codeQlLauncherName,
deprecatedCodeQlLauncherName,

Просмотреть файл

@ -89,12 +89,8 @@ import { QLTestAdapterFactory } from "./test-adapter";
import { TestUIService } from "./test-ui";
import { CompareView } from "./compare/compare-view";
import { initializeTelemetry } from "./telemetry";
import {
commandRunner,
commandRunnerWithProgress,
ProgressCallback,
withProgress,
} from "./commandRunner";
import { commandRunner, commandRunnerWithProgress } from "./commandRunner";
import { ProgressCallback, withProgress } from "./progress";
import { CodeQlStatusBarHandler } from "./status-bar";
import { getPackagingCommands } from "./packaging";
import { HistoryItemLabelProvider } from "./query-history/history-item-label-provider";

Просмотреть файл

@ -19,7 +19,7 @@ import {
commands,
} from "vscode";
import { CodeQLCliServer, QlpacksInfo } from "./cli";
import { UserCancellationException } from "./commandRunner";
import { UserCancellationException } from "./progress";
import { extLogger, OutputChannelLogger } from "./common";
import { QueryMetadata } from "./pure/interface-types";
import { telemetryListener } from "./telemetry";

Просмотреть файл

@ -1,5 +1,5 @@
import { CancellationToken } from "vscode";
import { ProgressCallback } from "../commandRunner";
import { ProgressCallback } from "../progress";
import { DatabaseItem } from "../local-databases";
import {
Dataset,

Просмотреть файл

@ -13,7 +13,7 @@ import {
ProgressMessage,
WithProgressId,
} from "../pure/legacy-messages";
import { ProgressCallback, ProgressTask } from "../commandRunner";
import { ProgressCallback, ProgressTask } from "../progress";
import { ServerProcess } from "../json-rpc-server";
type WithProgressReporting = (

Просмотреть файл

@ -13,7 +13,7 @@ import {
tryGetQueryMetadata,
upgradesTmpDir,
} from "../helpers";
import { ProgressCallback } from "../commandRunner";
import { ProgressCallback } from "../progress";
import { QueryMetadata } from "../pure/interface-types";
import { extLogger, Logger, TeeLogger } from "../common";
import * as messages from "../pure/legacy-messages";

Просмотреть файл

@ -4,7 +4,7 @@ import {
showAndLogExceptionWithTelemetry,
tmpDir,
} from "../helpers";
import { ProgressCallback, UserCancellationException } from "../commandRunner";
import { ProgressCallback, UserCancellationException } from "../progress";
import { extLogger } from "../common";
import * as messages from "../pure/legacy-messages";
import * as qsClient from "./queryserver-client";

Просмотреть файл

@ -21,7 +21,7 @@ import {
DatabaseItem,
DatabaseManager,
} from "./local-databases";
import { ProgressCallback, withProgress } from "./commandRunner";
import { ProgressCallback, withProgress } from "./progress";
import {
isLikelyDatabaseRoot,
isLikelyDbLanguageFolder,

Просмотреть файл

@ -12,7 +12,7 @@ import {
isFolderAlreadyInWorkspace,
showBinaryChoiceDialog,
} from "./helpers";
import { ProgressCallback, withProgress } from "./commandRunner";
import { ProgressCallback, withProgress } from "./progress";
import {
zipArchiveScheme,
encodeArchiveBasePath,

Просмотреть файл

@ -9,7 +9,7 @@ import {
ProgressCallback,
UserCancellationException,
withProgress,
} from "./commandRunner";
} from "./progress";
import { extLogger } from "./common";
import { asError, getErrorStack } from "./pure/helpers-pure";
import { redactableError } from "./pure/errors";

Просмотреть файл

@ -0,0 +1,128 @@
import {
CancellationToken,
ProgressLocation,
ProgressOptions as VSCodeProgressOptions,
window as Window,
} from "vscode";
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;
// Make certain properties within a type optional
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
export type ProgressOptions = Optional<VSCodeProgressOptions, "location">;
/**
* A task that reports progress.
*
* @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 cancellation token
*/
export type ProgressTask<R> = (
progress: ProgressCallback,
token: CancellationToken,
) => Thenable<R>;
/**
* 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%).
*/
export function withProgress<R>(
task: ProgressTask<R>,
{
location = ProgressLocation.Notification,
title,
cancellable,
}: ProgressOptions = {},
): Thenable<R> {
let progressAchieved = 0;
return Window.withProgress(
{
location,
title,
cancellable,
},
(progress, token) => {
return task((p) => {
const { message, step, maxStep } = p;
const increment = (100 * (step - progressAchieved)) / maxStep;
progressAchieved = step;
progress.report({ message, increment });
}, token);
},
);
}
/**
* 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)`,
});
}
}

Просмотреть файл

@ -1,5 +1,5 @@
import { CancellationToken } from "vscode";
import { ProgressCallback, UserCancellationException } from "../commandRunner";
import { ProgressCallback, UserCancellationException } from "../progress";
import { DatabaseItem } from "../local-databases";
import {
clearCache,

Просмотреть файл

@ -11,7 +11,7 @@ import {
ProgressMessage,
WithProgressId,
} from "../pure/new-messages";
import { ProgressCallback, ProgressTask } from "../commandRunner";
import { ProgressCallback, ProgressTask } from "../progress";
import { ServerProcess } from "../json-rpc-server";
type ServerOpts = {

Просмотреть файл

@ -1,7 +1,7 @@
import { join } from "path";
import { CancellationToken } from "vscode";
import * as cli from "../cli";
import { ProgressCallback } from "../commandRunner";
import { ProgressCallback } from "../progress";
import { DatabaseItem } from "../local-databases";
import {
getOnDiskWorkspaceFolders,

Просмотреть файл

@ -1,6 +1,6 @@
import { CancellationToken } from "vscode";
import { CodeQLCliServer } from "./cli";
import { ProgressCallback } from "./commandRunner";
import { ProgressCallback } from "./progress";
import { DatabaseItem } from "./local-databases";
import { InitialQueryInfo, LocalQueryInfo } from "./query-results";
import { QueryWithResults } from "./run-queries-shared";

Просмотреть файл

@ -11,7 +11,7 @@ import {
getQlPackForDbscheme,
showBinaryChoiceDialog,
} from "./helpers";
import { ProgressCallback, UserCancellationException } from "./commandRunner";
import { ProgressCallback, UserCancellationException } from "./progress";
import { getErrorMessage } from "./pure/helpers-pure";
import { FALLBACK_QLPACK_FILENAME, getQlPackPath } from "./pure/ql";
import { App } from "./common/app";

Просмотреть файл

@ -12,7 +12,7 @@ import {
window,
} from "vscode";
import { isCanary, AUTOSAVE_SETTING } from "./config";
import { UserCancellationException } from "./commandRunner";
import { UserCancellationException } from "./progress";
import {
pathExists,
readFile,

Просмотреть файл

@ -16,7 +16,7 @@ import {
} from "./config";
import * as appInsights from "applicationinsights";
import { extLogger } from "./common";
import { UserCancellationException } from "./commandRunner";
import { UserCancellationException } from "./progress";
import { showBinaryChoiceWithUrlDialog } from "./helpers";
import { RedactableError } from "./pure/errors";

Просмотреть файл

@ -13,7 +13,7 @@ import {
ProgressCallback,
UserCancellationException,
withProgress,
} from "../commandRunner";
} from "../progress";
import { showInformationMessageWithAction } from "../helpers";
import { extLogger } from "../common";
import { createGist } from "./gh-api/gh-api-client";

Просмотреть файл

@ -1,4 +1,4 @@
import { UserCancellationException } from "../commandRunner";
import { UserCancellationException } from "../progress";
import { DbManager } from "../databases/db-manager";
import { DbItemKind } from "../databases/db-item";

Просмотреть файл

@ -18,7 +18,7 @@ import {
getRemoteControllerRepo,
setRemoteControllerRepo,
} from "../config";
import { ProgressCallback, UserCancellationException } from "../commandRunner";
import { ProgressCallback, UserCancellationException } from "../progress";
import { RequestError } from "@octokit/types/dist-types";
import { QueryMetadata } from "../pure/interface-types";
import { getErrorMessage, REPO_REGEX } from "../pure/helpers-pure";

Просмотреть файл

@ -55,7 +55,7 @@ import {
ProgressCallback,
UserCancellationException,
withProgress,
} from "../commandRunner";
} from "../progress";
import { CodeQLCliServer } from "../cli";
import {
defaultFilterSortState,