@@ -11,8 +11,9 @@ import {
1111} from './keyType' ;
1212import { CodeQLCliServer } from '../cli' ;
1313import { DatabaseItem } from '../databases' ;
14+ import { QlPacksForLanguage } from '../helpers' ;
1415
15- export async function qlpackOfDatabase ( cli : CodeQLCliServer , db : DatabaseItem ) : Promise < string > {
16+ export async function qlpackOfDatabase ( cli : CodeQLCliServer , db : DatabaseItem ) : Promise < QlPacksForLanguage > {
1617 if ( db . contents === undefined ) {
1718 throw new Error ( 'Database is invalid and cannot infer QLPack.' ) ;
1819 }
@@ -21,28 +22,87 @@ export async function qlpackOfDatabase(cli: CodeQLCliServer, db: DatabaseItem):
2122 return await helpers . getQlPackForDbscheme ( cli , dbscheme ) ;
2223}
2324
25+ /**
26+ * Finds the contextual queries with the specified key in a list of CodeQL packs.
27+ *
28+ * @param cli The CLI instance to use.
29+ * @param qlpacks The list of packs to search.
30+ * @param keyType The contextual query key of the query to search for.
31+ * @returns The found queries from the first pack in which any matching queries were found.
32+ */
33+ async function resolveQueriesFromPacks ( cli : CodeQLCliServer , qlpacks : string [ ] , keyType : KeyType ) : Promise < string [ ] > {
34+ for ( const qlpack of qlpacks ) {
35+ const suiteFile = ( await tmp . file ( {
36+ postfix : '.qls'
37+ } ) ) . path ;
38+ const suiteYaml = {
39+ qlpack,
40+ include : {
41+ kind : kindOfKeyType ( keyType ) ,
42+ 'tags contain' : tagOfKeyType ( keyType )
43+ }
44+ } ;
45+ await fs . writeFile ( suiteFile , yaml . safeDump ( suiteYaml ) , 'utf8' ) ;
2446
25- export async function resolveQueries ( cli : CodeQLCliServer , qlpack : string , keyType : KeyType ) : Promise < string [ ] > {
26- const suiteFile = ( await tmp . file ( {
27- postfix : '.qls'
28- } ) ) . path ;
29- const suiteYaml = {
30- qlpack,
31- include : {
32- kind : kindOfKeyType ( keyType ) ,
33- 'tags contain' : tagOfKeyType ( keyType )
47+ const queries = await cli . resolveQueriesInSuite ( suiteFile , helpers . getOnDiskWorkspaceFolders ( ) ) ;
48+ if ( queries . length > 0 ) {
49+ return queries ;
3450 }
35- } ;
36- await fs . writeFile ( suiteFile , yaml . safeDump ( suiteYaml ) , 'utf8' ) ;
37-
38- const queries = await cli . resolveQueriesInSuite ( suiteFile , helpers . getOnDiskWorkspaceFolders ( ) ) ;
39- if ( queries . length === 0 ) {
40- void helpers . showAndLogErrorMessage (
41- `No ${ nameOfKeyType ( keyType ) } queries (tagged "${ tagOfKeyType ( keyType ) } ") could be found in the current library path. \
42- Try upgrading the CodeQL libraries. If that doesn't work, then ${ nameOfKeyType ( keyType ) } queries are not yet available \
43- for this language.`
44- ) ;
45- throw new Error ( `Couldn't find any queries tagged ${ tagOfKeyType ( keyType ) } for qlpack ${ qlpack } ` ) ;
4651 }
47- return queries ;
52+
53+ return [ ] ;
54+ }
55+
56+ export async function resolveQueries ( cli : CodeQLCliServer , qlpacks : QlPacksForLanguage , keyType : KeyType ) : Promise < string [ ] > {
57+ const cliCanHandleLibraryPack = await cli . cliConstraints . supportsAllowLibraryPacksInResolveQueries ( ) ;
58+ const packsToSearch : string [ ] = [ ] ;
59+ let blameCli : boolean ;
60+
61+ if ( cliCanHandleLibraryPack ) {
62+ // The CLI can handle both library packs and query packs, so search both packs in order.
63+ packsToSearch . push ( qlpacks . dbschemePack ) ;
64+ if ( qlpacks . queryPack !== undefined ) {
65+ packsToSearch . push ( qlpacks . queryPack ) ;
66+ }
67+ // If we don't find the query, it's because it's not there, not because the CLI was unable to
68+ // search the pack.
69+ blameCli = false ;
70+ } else {
71+ // Older CLIs can't handle `codeql resolve queries` with a suite that references a library pack.
72+ if ( qlpacks . dbschemePackIsLibraryPack ) {
73+ if ( qlpacks . queryPack !== undefined ) {
74+ // Just search the query pack, because some older library/query releases still had the
75+ // contextual queries in the query pack.
76+ packsToSearch . push ( qlpacks . queryPack ) ;
77+ }
78+ // If we don't find it, it's because the CLI was unable to search the library pack that
79+ // actually contains the query. Blame any failure on the CLI, not the packs.
80+ blameCli = true ;
81+ } else {
82+ // We have an old CLI, but the dbscheme pack is old enough that it's still a unified pack with
83+ // both libraries and queries. Just search that pack.
84+ packsToSearch . push ( qlpacks . dbschemePack ) ;
85+ // Any CLI should be able to search the single query pack, so if we don't find it, it's
86+ // because the language doesn't support it.
87+ blameCli = false ;
88+ }
89+ }
90+
91+ const queries = await resolveQueriesFromPacks ( cli , packsToSearch , keyType ) ;
92+ if ( queries . length > 0 ) {
93+ return queries ;
94+ }
95+
96+ // No queries found. Determine the correct error message for the various scenarios.
97+ const errorMessage = blameCli ?
98+ `Your current version of the CodeQL CLI, '${ ( await cli . getVersion ( ) ) . version } ', \
99+ is unable to use contextual queries from recent versions of the standard CodeQL libraries. \
100+ Please upgrade to the latest version of the CodeQL CLI.`
101+ :
102+ `No ${ nameOfKeyType ( keyType ) } queries (tagged "${ tagOfKeyType ( keyType ) } ") could be found in the current library path. \
103+ Try upgrading the CodeQL libraries. If that doesn't work, then ${ nameOfKeyType ( keyType ) } queries are not yet available \
104+ for this language.` ;
105+
106+ void helpers . showAndLogErrorMessage ( errorMessage ) ;
107+ throw new Error ( `Couldn't find any queries tagged ${ tagOfKeyType ( keyType ) } in any of the following packs: ${ packsToSearch . join ( ', ' ) } .` ) ;
48108}
0 commit comments