@@ -3,24 +3,18 @@ import * as fs from 'fs-extra';
33import * as path from 'path' ;
44import * as sarif from 'sarif' ;
55import * as tmp from 'tmp' ;
6+ import { promisify } from 'util' ;
67import * as vscode from 'vscode' ;
78import * as cli from './cli' ;
89import { DatabaseItem , getUpgradesDirectories } from './databases' ;
910import * as helpers from './helpers' ;
10- import { DatabaseInfo , SortState , ResultsPaths , SortedResultSetInfo , QueryMetadata } from './interface-types' ;
11+ import { DatabaseInfo , QueryMetadata , ResultsPaths , SortedResultSetInfo , SortState } from './interface-types' ;
1112import { logger } from './logging' ;
1213import * as messages from './messages' ;
13- import * as qsClient from './queryserver-client' ;
14- import { promisify } from 'util' ;
1514import { QueryHistoryItemOptions } from './query-history' ;
15+ import * as qsClient from './queryserver-client' ;
1616import { 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.
3327export 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 } ) ;
3529export const tmpDirDisposal = {
3630 dispose : ( ) => {
3731 upgradesTmpDir . removeCallback ( ) ;
3832 tmpDir . removeCallback ( ) ;
3933 }
4034} ;
4135
42-
4336export 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
209202export 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-
400209export async function clearCacheInDatabase ( qs : qsClient . QueryServerClient , dbItem : DatabaseItem ) :
401210 Promise < messages . ClearCacheResult > {
402211 if ( dbItem . contents === undefined ) {
0 commit comments