@@ -4,15 +4,16 @@ import * as child_process from 'child_process';
44import * as fs from 'fs-extra' ;
55import * as path from 'path' ;
66import * as sarif from 'sarif' ;
7+ import { SemVer } from 'semver' ;
78import { Readable } from 'stream' ;
89import { StringDecoder } from 'string_decoder' ;
910import * as tk from 'tree-kill' ;
10- import * as util from 'util' ;
11+ import { promisify } from 'util' ;
1112import { CancellationToken , Disposable } from 'vscode' ;
1213
1314import { BQRSInfo , DecodedBqrsChunk } from './bqrs-cli-types' ;
1415import { CliConfig } from './config' ;
15- import { DistributionProvider } from './distribution' ;
16+ import { DistributionProvider , FindDistributionResultKind } from './distribution' ;
1617import { assertNever } from './helpers-pure' ;
1718import { QueryMetadata , SortDirection } from './interface-types' ;
1819import { Logger , ProgressReporter } from './logging' ;
@@ -115,6 +116,11 @@ interface BqrsDecodeOptions {
115116 */
116117export class CodeQLCliServer implements Disposable {
117118
119+ /**
120+ * CLI version where --kind=DIL was introduced
121+ */
122+ private static CLI_VERSION_WITH_DECOMPILE_KIND_DIL = new SemVer ( '2.3.0' ) ;
123+
118124 /** The process for the cli server, or undefined if one doesn't exist yet */
119125 process ?: child_process . ChildProcessWithoutNullStreams ;
120126 /** Queue of future commands*/
@@ -124,6 +130,12 @@ export class CodeQLCliServer implements Disposable {
124130 /** A buffer with a single null byte. */
125131 nullBuffer : Buffer ;
126132
133+ /** Version of current cli, lazily computed by the `getVersion()` method */
134+ _version : SemVer | undefined ;
135+
136+ /** Path to current codeQL executable, or undefined if not running yet. */
137+ codeQlPath : string | undefined ;
138+
127139 constructor (
128140 private distributionProvider : DistributionProvider ,
129141 private cliConfig : CliConfig ,
@@ -140,11 +152,11 @@ export class CodeQLCliServer implements Disposable {
140152 if ( this . cliConfig . onDidChangeConfiguration ) {
141153 this . cliConfig . onDidChangeConfiguration ( ( ) => {
142154 this . restartCliServer ( ) ;
155+ this . _version = undefined ;
143156 } ) ;
144157 }
145158 }
146159
147-
148160 dispose ( ) : void {
149161 this . killProcessIfRunning ( ) ;
150162 }
@@ -210,9 +222,9 @@ export class CodeQLCliServer implements Disposable {
210222 * Launch the cli server
211223 */
212224 private async launchProcess ( ) : Promise < child_process . ChildProcessWithoutNullStreams > {
213- const config = await this . getCodeQlPath ( ) ;
214- return spawnServer (
215- config ,
225+ const codeQlPath = await this . getCodeQlPath ( ) ;
226+ return await spawnServer (
227+ codeQlPath ,
216228 'CodeQL CLI Server' ,
217229 [ 'execute' , 'cli-server' ] ,
218230 [ ] ,
@@ -671,12 +683,37 @@ export class CodeQLCliServer implements Disposable {
671683 }
672684
673685 async generateDil ( qloFile : string , outFile : string ) : Promise < void > {
686+ const extraArgs = ( await this . getVersion ( ) ) . compare ( CodeQLCliServer . CLI_VERSION_WITH_DECOMPILE_KIND_DIL ) >= 0
687+ ? [ '--kind' , 'dil' , '-o' , outFile , qloFile ]
688+ : [ '-o' , outFile , qloFile ] ;
674689 await this . runCodeQlCliCommand (
675690 [ 'query' , 'decompile' ] ,
676- [ '-o' , outFile , qloFile ] ,
691+ extraArgs ,
677692 'Generating DIL' ,
678693 ) ;
679694 }
695+
696+ private async getVersion ( ) {
697+ if ( ! this . _version ) {
698+ this . _version = await this . refreshVersion ( ) ;
699+ }
700+ return this . _version ;
701+ }
702+
703+ private async refreshVersion ( ) {
704+ const distribution = await this . distributionProvider . getDistribution ( ) ;
705+ switch ( distribution . kind ) {
706+ case FindDistributionResultKind . CompatibleDistribution :
707+ // eslint-disable-next-line no-fallthrough
708+ case FindDistributionResultKind . IncompatibleDistribution :
709+ return distribution . version ;
710+
711+ default :
712+ // We should not get here because if no distributions are available, then
713+ // the cli class is never instantiated.
714+ throw new Error ( 'No distribution found' ) ;
715+ }
716+ }
680717}
681718
682719/**
@@ -734,15 +771,22 @@ export function spawnServer(
734771
735772/**
736773 * Runs a CodeQL CLI command without invoking the CLI server, returning the output as a string.
737- * @param config The configuration containing the path to the CLI.
774+ * @param codeQlPath The path to the CLI.
738775 * @param command The `codeql` command to be run, provided as an array of command/subcommand names.
739776 * @param commandArgs The arguments to pass to the `codeql` command.
740777 * @param description Description of the action being run, to be shown in log and error messages.
741778 * @param logger Logger to write command log messages, e.g. to an output channel.
742779 * @param progressReporter Used to output progress messages, e.g. to the status bar.
743780 * @returns The contents of the command's stdout, if the command succeeded.
744781 */
745- export async function runCodeQlCliCommand ( codeQlPath : string , command : string [ ] , commandArgs : string [ ] , description : string , logger : Logger , progressReporter ?: ProgressReporter ) : Promise < string > {
782+ export async function runCodeQlCliCommand (
783+ codeQlPath : string ,
784+ command : string [ ] ,
785+ commandArgs : string [ ] ,
786+ description : string ,
787+ logger : Logger ,
788+ progressReporter ?: ProgressReporter
789+ ) : Promise < string > {
746790 // Add logging arguments first, in case commandArgs contains positional parameters.
747791 const args = command . concat ( LOGGING_FLAGS ) . concat ( commandArgs ) ;
748792 const argsString = args . join ( ' ' ) ;
@@ -751,7 +795,7 @@ export async function runCodeQlCliCommand(codeQlPath: string, command: string[],
751795 progressReporter . report ( { message : description } ) ;
752796 }
753797 logger . log ( `${ description } using CodeQL CLI: ${ codeQlPath } ${ argsString } ...` ) ;
754- const result = await util . promisify ( child_process . execFile ) ( codeQlPath , args ) ;
798+ const result = await promisify ( child_process . execFile ) ( codeQlPath , args ) ;
755799 logger . log ( result . stderr ) ;
756800 logger . log ( 'CLI command succeeded.' ) ;
757801 return result . stdout ;
0 commit comments