Skip to content

Commit 6fee8b3

Browse files
committed
Extract db upgrade code from queries.ts into its own file.
1 parent 75a15e2 commit 6fee8b3

File tree

3 files changed

+211
-203
lines changed

3 files changed

+211
-203
lines changed

extensions/ql-vscode/src/databases-ui.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import * as path from 'path';
2-
import { DisposableObject } from "semmle-vscode-utils";
3-
import { commands, Event, EventEmitter, ExtensionContext, ProviderResult, TreeDataProvider, TreeItem, Uri, window } from "vscode";
2+
import { DisposableObject } from 'semmle-vscode-utils';
3+
import { commands, Event, EventEmitter, ExtensionContext, ProviderResult, TreeDataProvider, TreeItem, Uri, window } from 'vscode';
44
import * as cli from './cli';
5-
import { DatabaseItem, DatabaseManager, getUpgradesDirectories } from "./databases";
6-
import { logger } from "./logging";
7-
import { clearCacheInDatabase, upgradeDatabase, UserCancellationException } from "./queries";
5+
import { DatabaseItem, DatabaseManager, getUpgradesDirectories } from './databases';
6+
import { getOnDiskWorkspaceFolders } from './helpers';
7+
import { logger } from './logging';
8+
import { clearCacheInDatabase, UserCancellationException } from './queries';
89
import * as qsClient from './queryserver-client';
9-
import { getOnDiskWorkspaceFolders } from "./helpers";
10+
import { upgradeDatabase } from './upgrades';
1011

1112
type ThemableIconPath = { light: string, dark: string } | string;
1213

extensions/ql-vscode/src/queries.ts

Lines changed: 6 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,18 @@ import * as fs from 'fs-extra';
33
import * as path from 'path';
44
import * as sarif from 'sarif';
55
import * as tmp from 'tmp';
6+
import { promisify } from 'util';
67
import * as vscode from 'vscode';
78
import * as cli from './cli';
89
import { DatabaseItem, getUpgradesDirectories } from './databases';
910
import * as helpers from './helpers';
10-
import { DatabaseInfo, SortState, ResultsPaths, SortedResultSetInfo, QueryMetadata } from './interface-types';
11+
import { DatabaseInfo, QueryMetadata, ResultsPaths, SortedResultSetInfo, SortState } from './interface-types';
1112
import { logger } from './logging';
1213
import * as messages from './messages';
13-
import * as qsClient from './queryserver-client';
14-
import { promisify } from 'util';
1514
import { QueryHistoryItemOptions } from './query-history';
15+
import * as qsClient from './queryserver-client';
1616
import { isQuickQueryPath } from './quick-query';
17-
18-
/**
19-
* Maximum number of lines to include from database upgrade message,
20-
* to work around the fact that we can't guarantee a scrollable text
21-
* box for it when displaying in dialog boxes.
22-
*/
23-
const MAX_UPGRADE_MESSAGE_LINES = 10;
17+
import { upgradeDatabase } from './upgrades';
2418

2519
/**
2620
* queries.ts
@@ -31,15 +25,14 @@ const MAX_UPGRADE_MESSAGE_LINES = 10;
3125

3226
// XXX: Tmp directory should be configuarble.
3327
export const tmpDir = tmp.dirSync({ prefix: 'queries_', keep: false, unsafeCleanup: true });
34-
const upgradesTmpDir = tmp.dirSync({ dir: tmpDir.name, prefix: 'upgrades_', keep: false, unsafeCleanup: true });
28+
export const upgradesTmpDir = tmp.dirSync({ dir: tmpDir.name, prefix: 'upgrades_', keep: false, unsafeCleanup: true });
3529
export const tmpDirDisposal = {
3630
dispose: () => {
3731
upgradesTmpDir.removeCallback();
3832
tmpDir.removeCallback();
3933
}
4034
};
4135

42-
4336
export class UserCancellationException extends Error { }
4437

4538
/**
@@ -203,7 +196,7 @@ export async function interpretResults(server: cli.CodeQLCliServer, metadata: Qu
203196
// SARIF format does, so in the absence of one, we use a dummy id.
204197
id = "dummy-id";
205198
}
206-
return await server.interpretBqrs( { kind, id }, resultsInfo.resultsPath, resultsInfo.interpretedResultsPath, sourceInfo);
199+
return await server.interpretBqrs({ kind, id }, resultsInfo.resultsPath, resultsInfo.interpretedResultsPath, sourceInfo);
207200
}
208201

209202
export interface EvaluationInfo {
@@ -213,190 +206,6 @@ export interface EvaluationInfo {
213206
historyItemOptions: QueryHistoryItemOptions;
214207
}
215208

216-
/**
217-
* Checks whether the given database can be upgraded to the given target DB scheme,
218-
* and whether the user wants to proceed with the upgrade.
219-
* Reports errors to both the user and the console.
220-
* @returns the `UpgradeParams` needed to start the upgrade, if the upgrade is possible and was confirmed by the user, or `undefined` otherwise.
221-
*/
222-
async function checkAndConfirmDatabaseUpgrade(qs: qsClient.QueryServerClient, db: DatabaseItem, targetDbScheme: vscode.Uri, upgradesDirectories: vscode.Uri[]):
223-
Promise<messages.UpgradeParams | undefined> {
224-
if (db.contents === undefined || db.contents.dbSchemeUri === undefined) {
225-
helpers.showAndLogErrorMessage("Database is invalid, and cannot be upgraded.");
226-
return;
227-
}
228-
const params: messages.UpgradeParams = {
229-
fromDbscheme: db.contents.dbSchemeUri.fsPath,
230-
toDbscheme: targetDbScheme.fsPath,
231-
additionalUpgrades: upgradesDirectories.map(uri => uri.fsPath)
232-
};
233-
234-
let checkUpgradeResult: messages.CheckUpgradeResult;
235-
try {
236-
qs.logger.log('Checking database upgrade...');
237-
checkUpgradeResult = await checkDatabaseUpgrade(qs, params);
238-
}
239-
catch (e) {
240-
helpers.showAndLogErrorMessage(`Database cannot be upgraded: ${e}`);
241-
return;
242-
}
243-
finally {
244-
qs.logger.log('Done checking database upgrade.');
245-
}
246-
247-
const checkedUpgrades = checkUpgradeResult.checkedUpgrades;
248-
if (checkedUpgrades === undefined) {
249-
const error = checkUpgradeResult.upgradeError || '[no error message available]';
250-
await helpers.showAndLogErrorMessage(`Database cannot be upgraded: ${error}`);
251-
return;
252-
}
253-
254-
if (checkedUpgrades.scripts.length === 0) {
255-
await helpers.showAndLogInformationMessage('Database is already up to date; nothing to do.');
256-
return;
257-
}
258-
259-
let curSha = checkedUpgrades.initialSha;
260-
let descriptionMessage = '';
261-
for (const script of checkedUpgrades.scripts) {
262-
descriptionMessage += `Would perform upgrade: ${script.description}\n`;
263-
descriptionMessage += `\t-> Compatibility: ${script.compatibility}\n`;
264-
curSha = script.newSha;
265-
}
266-
267-
const targetSha = checkedUpgrades.targetSha;
268-
if (curSha != targetSha) {
269-
// Newlines aren't rendered in notifications: https://github.com/microsoft/vscode/issues/48900
270-
// A modal dialog would be rendered better, but is more intrusive.
271-
await helpers.showAndLogErrorMessage(`Database cannot be upgraded to the target database scheme.
272-
Can upgrade from ${checkedUpgrades.initialSha} (current) to ${curSha}, but cannot reach ${targetSha} (target).`);
273-
// TODO: give a more informative message if we think the DB is ahead of the target DB scheme
274-
return;
275-
}
276-
277-
logger.log(descriptionMessage);
278-
// Ask the user to confirm the upgrade.
279-
280-
const showLogItem: vscode.MessageItem = { title: 'No, Show Changes', isCloseAffordance: true };
281-
const yesItem = { title: 'Yes', isCloseAffordance: false };
282-
const noItem = { title: 'No', isCloseAffordance: true }
283-
let dialogOptions: vscode.MessageItem[] = [yesItem, noItem];
284-
285-
let messageLines = descriptionMessage.split('\n');
286-
if (messageLines.length > MAX_UPGRADE_MESSAGE_LINES) {
287-
messageLines = messageLines.slice(0, MAX_UPGRADE_MESSAGE_LINES);
288-
messageLines.push(`The list of upgrades was truncated, click "No, Show Changes" to see the full list.`);
289-
dialogOptions.push(showLogItem);
290-
}
291-
292-
const message = `Should the database ${db.databaseUri.fsPath} be upgraded?\n\n${messageLines.join("\n")}`;
293-
const chosenItem = await vscode.window.showInformationMessage(message, { modal: true }, ...dialogOptions);
294-
295-
if (chosenItem === showLogItem) {
296-
logger.outputChannel.show();
297-
}
298-
299-
if (chosenItem === yesItem) {
300-
return params;
301-
}
302-
else {
303-
throw new UserCancellationException('User cancelled the database upgrade.');
304-
}
305-
}
306-
307-
/**
308-
* Command handler for 'Upgrade Database'.
309-
* Attempts to upgrade the given database to the given target DB scheme, using the given directory of upgrades.
310-
* First performs a dry-run and prompts the user to confirm the upgrade.
311-
* Reports errors during compilation and evaluation of upgrades to the user.
312-
*/
313-
export async function upgradeDatabase(qs: qsClient.QueryServerClient, db: DatabaseItem, targetDbScheme: vscode.Uri, upgradesDirectories: vscode.Uri[]):
314-
Promise<messages.RunUpgradeResult | undefined> {
315-
const upgradeParams = await checkAndConfirmDatabaseUpgrade(qs, db, targetDbScheme, upgradesDirectories);
316-
317-
if (upgradeParams === undefined) {
318-
return;
319-
}
320-
321-
let compileUpgradeResult: messages.CompileUpgradeResult;
322-
try {
323-
compileUpgradeResult = await compileDatabaseUpgrade(qs, upgradeParams);
324-
}
325-
catch (e) {
326-
helpers.showAndLogErrorMessage(`Compilation of database upgrades failed: ${e}`);
327-
return;
328-
}
329-
finally {
330-
qs.logger.log('Done compiling database upgrade.')
331-
}
332-
333-
if (compileUpgradeResult.compiledUpgrades === undefined) {
334-
const error = compileUpgradeResult.error || '[no error message available]';
335-
helpers.showAndLogErrorMessage(`Compilation of database upgrades failed: ${error}`);
336-
return;
337-
}
338-
339-
try {
340-
qs.logger.log('Running the following database upgrade:');
341-
qs.logger.log(compileUpgradeResult.compiledUpgrades.scripts.map(s => s.description.description).join('\n'));
342-
return await runDatabaseUpgrade(qs, db, compileUpgradeResult.compiledUpgrades);
343-
}
344-
catch (e) {
345-
helpers.showAndLogErrorMessage(`Database upgrade failed: ${e}`);
346-
return;
347-
}
348-
finally {
349-
qs.logger.log('Done running database upgrade.')
350-
}
351-
}
352-
353-
async function checkDatabaseUpgrade(qs: qsClient.QueryServerClient, upgradeParams: messages.UpgradeParams):
354-
Promise<messages.CheckUpgradeResult> {
355-
return helpers.withProgress({
356-
location: vscode.ProgressLocation.Notification,
357-
title: "Checking for database upgrades",
358-
cancellable: true,
359-
}, (progress, token) => qs.sendRequest(messages.checkUpgrade, upgradeParams, token, progress));
360-
}
361-
362-
async function compileDatabaseUpgrade(qs: qsClient.QueryServerClient, upgradeParams: messages.UpgradeParams):
363-
Promise<messages.CompileUpgradeResult> {
364-
const params: messages.CompileUpgradeParams = {
365-
upgrade: upgradeParams,
366-
upgradeTempDir: upgradesTmpDir.name
367-
}
368-
369-
return helpers.withProgress({
370-
location: vscode.ProgressLocation.Notification,
371-
title: "Compiling database upgrades",
372-
cancellable: true,
373-
}, (progress, token) => qs.sendRequest(messages.compileUpgrade, params, token, progress));
374-
}
375-
376-
async function runDatabaseUpgrade(qs: qsClient.QueryServerClient, db: DatabaseItem, upgrades: messages.CompiledUpgrades):
377-
Promise<messages.RunUpgradeResult> {
378-
379-
if (db.contents === undefined || db.contents.datasetUri === undefined) {
380-
throw new Error('Can\'t upgrade an invalid database.');
381-
}
382-
const database: messages.Dataset = {
383-
dbDir: db.contents.datasetUri.fsPath,
384-
workingSet: 'default'
385-
};
386-
387-
const params: messages.RunUpgradeParams = {
388-
db: database,
389-
timeoutSecs: qs.config.timeoutSecs,
390-
toRun: upgrades
391-
};
392-
393-
return helpers.withProgress({
394-
location: vscode.ProgressLocation.Notification,
395-
title: "Running database upgrades",
396-
cancellable: true,
397-
}, (progress, token) => qs.sendRequest(messages.runUpgrade, params, token, progress));
398-
}
399-
400209
export async function clearCacheInDatabase(qs: qsClient.QueryServerClient, dbItem: DatabaseItem):
401210
Promise<messages.ClearCacheResult> {
402211
if (dbItem.contents === undefined) {

0 commit comments

Comments
 (0)