@@ -22,25 +22,23 @@ import {
2222 tryGetQueryMetadata ,
2323} from "./helpers" ;
2424import { displayQuickQuery } from "./quick-query" ;
25- import { CoreQueryResults , CoreQueryTarget , QueryRunner } from "./queryRunner" ;
25+ import { CoreQueryResults , QueryRunner } from "./queryRunner" ;
2626import { QueryHistoryManager } from "./query-history/query-history-manager" ;
2727import { DatabaseUI } from "./local-databases-ui" ;
2828import { ResultsView } from "./interface" ;
2929import { DatabaseItem , DatabaseManager } from "./local-databases" ;
3030import {
3131 createInitialQueryInfo ,
32+ determineSelectedQuery ,
3233 EvaluatorLogPaths ,
3334 generateEvalLogSummaries ,
3435 logEndSummary ,
3536 QueryEvaluationInfo ,
3637 QueryOutputDir ,
3738 QueryWithResults ,
39+ SelectedQuery ,
3840} from "./run-queries-shared" ;
39- import {
40- CompletedLocalQueryInfo ,
41- InitialQueryInfo ,
42- LocalQueryInfo ,
43- } from "./query-results" ;
41+ import { CompletedLocalQueryInfo , LocalQueryInfo } from "./query-results" ;
4442import { WebviewReveal } from "./interface-utils" ;
4543import { asError , getErrorMessage } from "./pure/helpers-pure" ;
4644import { CodeQLCliServer } from "./cli" ;
@@ -87,7 +85,7 @@ export class LocalQueryRun {
8785 public constructor (
8886 private readonly outputDir : QueryOutputDir ,
8987 private readonly localQueries : LocalQueries ,
90- private readonly queryInfo : LocalQueryInfo ,
88+ public readonly queryInfo : LocalQueryInfo ,
9189 private readonly dbItem : DatabaseItem ,
9290 public readonly logger : Logger ,
9391 ) { }
@@ -101,7 +99,7 @@ export class LocalQueryRun {
10199 * successful or not.
102100 * */
103101 public async complete ( results : CoreQueryResults ) : Promise < void > {
104- const evalLogPaths = await this . localQueries . summarizeEvalLog (
102+ const evalLogPaths = await this . summarizeEvalLog (
105103 results . resultType ,
106104 this . outputDir ,
107105 this . logger ,
@@ -123,6 +121,38 @@ export class LocalQueryRun {
123121 await this . localQueries . queryHistoryManager . refreshTreeView ( ) ;
124122 }
125123
124+ /**
125+ * Generate summaries of the structured evaluator log.
126+ */
127+ private async summarizeEvalLog (
128+ resultType : QueryResultType ,
129+ outputDir : QueryOutputDir ,
130+ logger : BaseLogger ,
131+ ) : Promise < EvaluatorLogPaths | undefined > {
132+ const evalLogPaths = await generateEvalLogSummaries (
133+ this . localQueries . cliServer ,
134+ outputDir ,
135+ ) ;
136+ if ( evalLogPaths !== undefined ) {
137+ if ( evalLogPaths . endSummary !== undefined ) {
138+ void logEndSummary ( evalLogPaths . endSummary , logger ) ; // Logged asynchrnously
139+ }
140+ } else {
141+ // Raw evaluator log was not found. Notify the user, unless we know why it wasn't found.
142+ if ( resultType === QueryResultType . SUCCESS ) {
143+ void showAndLogWarningMessage (
144+ `Failed to write structured evaluator log to ${ outputDir . evalLogPath } .` ,
145+ ) ;
146+ } else {
147+ // Don't bother notifying the user if there's no log. For some errors, like compilation
148+ // errors, we don't expect a log. For cancellations and OOM errors, whether or not we have
149+ // a log depends on how far execution got before termination.
150+ }
151+ }
152+
153+ return evalLogPaths ;
154+ }
155+
126156 /**
127157 * Gets a `QueryWithResults` containing information about the evaluation of the query and its
128158 * result, in the form expected by the query history UI.
@@ -342,93 +372,94 @@ export class LocalQueries extends DisposableObject {
342372 * object to update the UI based on the results of the query.
343373 */
344374 public async createLocalQueryRun (
345- queryPath : string ,
346- quickEval : boolean ,
347- range : Range | undefined ,
375+ selectedQuery : SelectedQuery ,
348376 dbItem : DatabaseItem ,
349- outputDir : string ,
377+ outputDir : QueryOutputDir ,
350378 tokenSource : CancellationTokenSource ,
351379 ) : Promise < LocalQueryRun > {
352- const queryOutputDir = new QueryOutputDir ( outputDir ) ;
380+ await createTimestampFile ( outputDir . querySaveDir ) ;
353381
354- await createTimestampFile ( outputDir ) ;
382+ if ( this . queryRunner . customLogDirectory ) {
383+ void showAndLogWarningMessage (
384+ `Custom log directories are no longer supported. The "codeQL.runningQueries.customLogDirectory" setting is deprecated. Unset the setting to stop seeing this message. Query logs saved to ${ outputDir . logPath } ` ,
385+ ) ;
386+ }
355387
356- const initialInfo = await createInitialQueryInfo (
357- Uri . file ( queryPath ) ,
358- {
359- databaseUri : dbItem . databaseUri . toString ( ) ,
360- name : dbItem . name ,
361- } ,
362- quickEval ,
363- range ,
364- ) ;
388+ const initialInfo = await createInitialQueryInfo ( selectedQuery , {
389+ databaseUri : dbItem . databaseUri . toString ( ) ,
390+ name : dbItem . name ,
391+ } ) ;
365392
366393 // When cancellation is requested from the query history view, we just stop the debug session.
367394 const queryInfo = new LocalQueryInfo ( initialInfo , tokenSource ) ;
368395 this . queryHistoryManager . addQuery ( queryInfo ) ;
369396
370- const logger = new TeeLogger (
371- this . queryRunner . logger ,
372- queryOutputDir . logPath ,
373- ) ;
374- return new LocalQueryRun ( queryOutputDir , this , queryInfo , dbItem , logger ) ;
397+ const logger = new TeeLogger ( this . queryRunner . logger , outputDir . logPath ) ;
398+ return new LocalQueryRun ( outputDir , this , queryInfo , dbItem , logger ) ;
375399 }
376400
377401 public async compileAndRunQuery (
378402 quickEval : boolean ,
379- selectedQuery : Uri | undefined ,
403+ queryUri : Uri | undefined ,
380404 progress : ProgressCallback ,
381405 token : CancellationToken ,
382406 databaseItem : DatabaseItem | undefined ,
383407 range ?: Range ,
384408 ) : Promise < void > {
385409 if ( this . queryRunner !== undefined ) {
410+ const selectedQuery = await determineSelectedQuery (
411+ queryUri ,
412+ quickEval ,
413+ range ,
414+ ) ;
415+
386416 // If no databaseItem is specified, use the database currently selected in the Databases UI
387417 databaseItem =
388418 databaseItem ||
389419 ( await this . databaseUI . getDatabaseItem ( progress , token ) ) ;
390420 if ( databaseItem === undefined ) {
391421 throw new Error ( "Can't run query without a selected database" ) ;
392422 }
393- const databaseInfo = {
394- name : databaseItem . name ,
395- databaseUri : databaseItem . databaseUri . toString ( ) ,
396- } ;
423+
424+ const coreQueryRun = this . queryRunner . createQueryRun (
425+ databaseItem . databaseUri . fsPath ,
426+ {
427+ queryPath : selectedQuery . queryPath ,
428+ quickEvalPosition : selectedQuery . quickEvalPosition ,
429+ } ,
430+ true ,
431+ getOnDiskWorkspaceFolders ( ) ,
432+ this . queryStorageDir ,
433+ undefined ,
434+ undefined ,
435+ ) ;
397436
398437 // handle cancellation from the history view.
399438 const source = new CancellationTokenSource ( ) ;
400- token . onCancellationRequested ( ( ) => source . cancel ( ) ) ;
401-
402- const initialInfo = await createInitialQueryInfo (
403- selectedQuery ,
404- databaseInfo ,
405- quickEval ,
406- range ,
407- ) ;
408- const item = new LocalQueryInfo ( initialInfo , source ) ;
409- this . queryHistoryManager . addQuery ( item ) ;
410439 try {
411- const completedQueryInfo = await this . compileAndRunQueryAgainstDatabase (
440+ token . onCancellationRequested ( ( ) => source . cancel ( ) ) ;
441+
442+ const localQueryRun = await this . createLocalQueryRun (
443+ selectedQuery ,
412444 databaseItem ,
413- initialInfo ,
414- this . queryStorageDir ,
415- progress ,
416- source . token ,
417- undefined ,
418- item ,
445+ coreQueryRun . outputDir ,
446+ source ,
419447 ) ;
420- this . queryHistoryManager . completeQuery ( item , completedQueryInfo ) ;
421- await this . showResultsForCompletedQuery (
422- item as CompletedLocalQueryInfo ,
423- WebviewReveal . Forced ,
424- ) ;
425- // Note we must update the query history view after showing results as the
426- // display and sorting might depend on the number of results
427- } catch ( e ) {
428- const err = asError ( e ) ;
429- err . message = `Error running query: ${ err . message } ` ;
430- item . failureReason = err . message ;
431- throw e ;
448+
449+ try {
450+ const results = await coreQueryRun . evaluate (
451+ progress ,
452+ source . token ,
453+ localQueryRun . logger ,
454+ ) ;
455+
456+ await localQueryRun . complete ( results ) ;
457+ } catch ( e ) {
458+ const err = asError ( e ) ;
459+ err . message = `Error running query: ${ err . message } ` ;
460+ localQueryRun . queryInfo . failureReason = err . message ;
461+ throw e ;
462+ }
432463 } finally {
433464 await this . queryHistoryManager . refreshTreeView ( ) ;
434465 source . dispose ( ) ;
@@ -510,145 +541,4 @@ export class LocalQueries extends DisposableObject {
510541 ) : Promise < void > {
511542 await this . localQueryResultsView . showResults ( query , forceReveal , false ) ;
512543 }
513-
514- private async compileAndRunQueryAgainstDatabase (
515- db : DatabaseItem ,
516- initialInfo : InitialQueryInfo ,
517- queryStorageDir : string ,
518- progress : ProgressCallback ,
519- token : CancellationToken ,
520- templates ?: Record < string , string > ,
521- queryInfo ?: LocalQueryInfo , // May be omitted for queries not initiated by the user. If omitted we won't create a structured log for the query.
522- ) : Promise < QueryWithResults > {
523- const queryTarget : CoreQueryTarget = {
524- queryPath : initialInfo . queryPath ,
525- quickEvalPosition : initialInfo . quickEvalPosition ,
526- } ;
527-
528- const diskWorkspaceFolders = getOnDiskWorkspaceFolders ( ) ;
529- const queryRun = this . queryRunner . createQueryRun (
530- db . databaseUri . fsPath ,
531- queryTarget ,
532- queryInfo !== undefined ,
533- diskWorkspaceFolders ,
534- queryStorageDir ,
535- initialInfo . id ,
536- templates ,
537- ) ;
538-
539- await createTimestampFile ( queryRun . outputDir . querySaveDir ) ;
540-
541- const logPath = queryRun . outputDir . logPath ;
542- if ( this . queryRunner . customLogDirectory ) {
543- void showAndLogWarningMessage (
544- `Custom log directories are no longer supported. The "codeQL.runningQueries.customLogDirectory" setting is deprecated. Unset the setting to stop seeing this message. Query logs saved to ${ logPath } ` ,
545- ) ;
546- }
547-
548- const logger = new TeeLogger ( this . queryRunner . logger , logPath ) ;
549- const coreResults = await queryRun . evaluate ( progress , token , logger ) ;
550- if ( queryInfo !== undefined ) {
551- const evalLogPaths = await this . summarizeEvalLog (
552- coreResults . resultType ,
553- queryRun . outputDir ,
554- logger ,
555- ) ;
556- if ( evalLogPaths !== undefined ) {
557- queryInfo . setEvaluatorLogPaths ( evalLogPaths ) ;
558- }
559- }
560-
561- return await this . getCompletedQueryInfo (
562- db ,
563- queryTarget ,
564- queryRun . outputDir ,
565- coreResults ,
566- ) ;
567- }
568-
569- /**
570- * Generate summaries of the structured evaluator log.
571- */
572- public async summarizeEvalLog (
573- resultType : QueryResultType ,
574- outputDir : QueryOutputDir ,
575- logger : BaseLogger ,
576- ) : Promise < EvaluatorLogPaths | undefined > {
577- const evalLogPaths = await generateEvalLogSummaries (
578- this . cliServer ,
579- outputDir ,
580- ) ;
581- if ( evalLogPaths !== undefined ) {
582- if ( evalLogPaths . endSummary !== undefined ) {
583- void logEndSummary ( evalLogPaths . endSummary , logger ) ; // Logged asynchrnously
584- }
585- } else {
586- // Raw evaluator log was not found. Notify the user, unless we know why it wasn't found.
587- switch ( resultType ) {
588- case QueryResultType . COMPILATION_ERROR :
589- case QueryResultType . DBSCHEME_MISMATCH_NAME :
590- case QueryResultType . DBSCHEME_NO_UPGRADE :
591- // In these cases, the evaluator was never invoked anyway, so don't bother warning.
592- break ;
593-
594- default :
595- void showAndLogWarningMessage (
596- `Failed to write structured evaluator log to ${ outputDir . evalLogPath } .` ,
597- ) ;
598- break ;
599- }
600- }
601-
602- return evalLogPaths ;
603- }
604-
605- /**
606- * Gets a `QueryWithResults` containing information about the evaluation of the query and its
607- * result, in the form expected by the query history UI.
608- */
609- private async getCompletedQueryInfo (
610- dbItem : DatabaseItem ,
611- queryTarget : CoreQueryTarget ,
612- outputDir : QueryOutputDir ,
613- results : CoreQueryResults ,
614- ) : Promise < QueryWithResults > {
615- // Read the query metadata if possible, to use in the UI.
616- const metadata = await tryGetQueryMetadata (
617- this . cliServer ,
618- queryTarget . queryPath ,
619- ) ;
620- const query = new QueryEvaluationInfo (
621- outputDir . querySaveDir ,
622- dbItem . databaseUri . fsPath ,
623- await dbItem . hasMetadataFile ( ) ,
624- queryTarget . quickEvalPosition ,
625- metadata ,
626- ) ;
627-
628- if ( results . resultType !== QueryResultType . SUCCESS ) {
629- const message = results . message
630- ? redactableError `${ results . message } `
631- : redactableError `Failed to run query` ;
632- void extLogger . log ( message . fullMessage ) ;
633- void showAndLogExceptionWithTelemetry (
634- redactableError `Failed to run query: ${ message } ` ,
635- ) ;
636- }
637- const message = formatResultMessage ( results ) ;
638- const successful = results . resultType === QueryResultType . SUCCESS ;
639- return {
640- query,
641- result : {
642- evaluationTime : results . evaluationTime ,
643- queryId : 0 ,
644- resultType : successful
645- ? QueryResultType . SUCCESS
646- : QueryResultType . OTHER_ERROR ,
647- runId : 0 ,
648- message,
649- } ,
650- message,
651- successful,
652- } ;
653- }
654544}
0 commit comments