11import * as cpp from 'child-process-promise' ;
22import * as child_process from 'child_process' ;
3+ import * as fs from 'fs-extra' ;
34import * as path from 'path' ;
45import * as sarif from 'sarif' ;
56import { SemVer } from 'semver' ;
@@ -17,7 +18,7 @@ import { QueryMetadata, SortDirection } from './pure/interface-types';
1718import { Logger , ProgressReporter } from './logging' ;
1819import { CompilationMessage } from './pure/messages' ;
1920import { sarifParser } from './sarif-parser' ;
20- import { dbSchemeToLanguage } from './helpers' ;
21+ import { dbSchemeToLanguage , walkDirectory } from './helpers' ;
2122
2223/**
2324 * The version of the SARIF format that we are using.
@@ -687,20 +688,13 @@ export class CodeQLCliServer implements Disposable {
687688 return await this . runJsonCodeQlCliCommand < DecodedBqrsChunk > ( [ 'bqrs' , 'decode' ] , subcommandArgs , 'Reading bqrs data' ) ;
688689 }
689690
690- async runInterpretCommand ( format : string , metadata : QueryMetadata , resultsPath : string , interpretedResultsPath : string , sourceInfo ?: SourceInfo ) {
691+ async runInterpretCommand ( format : string , additonalArgs : string [ ] , metadata : QueryMetadata , resultsPath : string , interpretedResultsPath : string , sourceInfo ?: SourceInfo ) {
691692 const args = [
692693 '--output' , interpretedResultsPath ,
693694 '--format' , format ,
694695 // Forward all of the query metadata.
695696 ...Object . entries ( metadata ) . map ( ( [ key , value ] ) => `-t=${ key } =${ value } ` )
696- ] ;
697- if ( format == SARIF_FORMAT ) {
698- // TODO: This flag means that we don't group interpreted results
699- // by primary location. We may want to revisit whether we call
700- // interpretation with and without this flag, or do some
701- // grouping client-side.
702- args . push ( '--no-group-results' ) ;
703- }
697+ ] . concat ( additonalArgs ) ;
704698 if ( sourceInfo !== undefined ) {
705699 args . push (
706700 '--source-archive' , sourceInfo . sourceArchive ,
@@ -722,13 +716,47 @@ export class CodeQLCliServer implements Disposable {
722716 await this . runCodeQlCliCommand ( [ 'bqrs' , 'interpret' ] , args , 'Interpreting query results' ) ;
723717 }
724718
725- async interpretBqrs ( metadata : QueryMetadata , resultsPath : string , interpretedResultsPath : string , sourceInfo ?: SourceInfo ) : Promise < sarif . Log > {
726- await this . runInterpretCommand ( SARIF_FORMAT , metadata , resultsPath , interpretedResultsPath , sourceInfo ) ;
719+ async interpretBqrsSarif ( metadata : QueryMetadata , resultsPath : string , interpretedResultsPath : string , sourceInfo ?: SourceInfo ) : Promise < sarif . Log > {
720+ const additionalArgs = [
721+ // TODO: This flag means that we don't group interpreted results
722+ // by primary location. We may want to revisit whether we call
723+ // interpretation with and without this flag, or do some
724+ // grouping client-side.
725+ '--no-group-results'
726+ ] ;
727+
728+ await this . runInterpretCommand ( SARIF_FORMAT , additionalArgs , metadata , resultsPath , interpretedResultsPath , sourceInfo ) ;
727729 return await sarifParser ( interpretedResultsPath ) ;
728730 }
729731
732+ // Warning: this function is untenable for large dot files,
733+ async readDotFiles ( dir : string ) : Promise < string [ ] > {
734+ const dotFiles : Promise < string > [ ] = [ ] ;
735+ for await ( const file of walkDirectory ( dir ) ) {
736+ if ( file . endsWith ( '.dot' ) ) {
737+ dotFiles . push ( fs . readFile ( file , 'utf8' ) ) ;
738+ }
739+ }
740+ return Promise . all ( dotFiles ) ;
741+ }
742+
743+ async interpretBqrsGraph ( metadata : QueryMetadata , resultsPath : string , interpretedResultsPath : string , sourceInfo ?: SourceInfo ) : Promise < string [ ] > {
744+ const additionalArgs = sourceInfo
745+ ? [ '--dot-location-url-format' , 'file://' + sourceInfo . sourceLocationPrefix + '{path}:{start:line}:{start:column}:{end:line}:{end:column}' ]
746+ : [ ] ;
747+
748+ await this . runInterpretCommand ( 'dot' , additionalArgs , metadata , resultsPath , interpretedResultsPath , sourceInfo ) ;
749+
750+ try {
751+ const dot = await this . readDotFiles ( interpretedResultsPath ) ;
752+ return dot ;
753+ } catch ( err ) {
754+ throw new Error ( `Reading output of interpretation failed: ${ err . stderr || err } ` ) ;
755+ }
756+ }
757+
730758 async generateResultsCsv ( metadata : QueryMetadata , resultsPath : string , csvPath : string , sourceInfo ?: SourceInfo ) : Promise < void > {
731- await this . runInterpretCommand ( CSV_FORMAT , metadata , resultsPath , csvPath , sourceInfo ) ;
759+ await this . runInterpretCommand ( CSV_FORMAT , [ ] , metadata , resultsPath , csvPath , sourceInfo ) ;
732760 }
733761
734762 async sortBqrs ( resultsPath : string , sortedResultsPath : string , resultSet : string , sortKeys : number [ ] , sortDirections : SortDirection [ ] ) : Promise < void > {
@@ -1224,9 +1252,9 @@ export class CliVersionConstraint {
12241252
12251253 /**
12261254 * CLI version where the `--evaluator-log` and related options to the query server were introduced,
1227- * on a per-query server basis.
1255+ * on a per-query server basis.
12281256 */
1229- public static CLI_VERSION_WITH_STRUCTURED_EVAL_LOG = new SemVer ( '2.8.2' ) ;
1257+ public static CLI_VERSION_WITH_STRUCTURED_EVAL_LOG = new SemVer ( '2.8.2' ) ;
12301258
12311259 constructor ( private readonly cli : CodeQLCliServer ) {
12321260 /**/
0 commit comments