11import { CancellationToken } from "vscode" ;
22import { DatabaseItem } from "../databases/local-databases" ;
3- import { join } from "path" ;
3+ import { basename } from "path" ;
44import { QueryRunner } from "../query-server" ;
55import { CodeQLCliServer } from "../codeql-cli/cli" ;
66import { TeeLogger } from "../common" ;
@@ -16,45 +16,84 @@ import {
1616} from "./modeled-method" ;
1717import { redactableError } from "../pure/errors" ;
1818import { QueryResultType } from "../pure/new-messages" ;
19+ import { file } from "tmp-promise" ;
20+ import { writeFile } from "fs-extra" ;
21+ import { dump } from "js-yaml" ;
22+ import { qlpackOfDatabase } from "../language-support" ;
1923
2024type FlowModelOptions = {
2125 cliServer : CodeQLCliServer ;
2226 queryRunner : QueryRunner ;
2327 queryStorageDir : string ;
24- qlDir : string ;
2528 databaseItem : DatabaseItem ;
2629 progress : ProgressCallback ;
2730 token : CancellationToken ;
2831 onResults : ( results : ModeledMethodWithSignature [ ] ) => void | Promise < void > ;
2932} ;
3033
34+ async function resolveQueries (
35+ cliServer : CodeQLCliServer ,
36+ databaseItem : DatabaseItem ,
37+ ) : Promise < string [ ] > {
38+ const qlpacks = await qlpackOfDatabase ( cliServer , databaseItem ) ;
39+
40+ const packsToSearch : string [ ] = [ ] ;
41+
42+ // The CLI can handle both library packs and query packs, so search both packs in order.
43+ packsToSearch . push ( qlpacks . dbschemePack ) ;
44+ if ( qlpacks . queryPack !== undefined ) {
45+ packsToSearch . push ( qlpacks . queryPack ) ;
46+ }
47+
48+ const suiteFile = (
49+ await file ( {
50+ postfix : ".qls" ,
51+ } )
52+ ) . path ;
53+ const suiteYaml = [ ] ;
54+ for ( const qlpack of packsToSearch ) {
55+ suiteYaml . push ( {
56+ from : qlpack ,
57+ queries : "." ,
58+ include : {
59+ "tags contain" : "modelgenerator" ,
60+ } ,
61+ } ) ;
62+ }
63+ await writeFile ( suiteFile , dump ( suiteYaml ) , "utf8" ) ;
64+
65+ return await cliServer . resolveQueriesInSuite (
66+ suiteFile ,
67+ getOnDiskWorkspaceFolders ( ) ,
68+ ) ;
69+ }
70+
3171async function getModeledMethodsFromFlow (
3272 type : Exclude < ModeledMethodType , "none" > ,
33- queryName : string ,
73+ queryPath : string | undefined ,
3474 queryStep : number ,
3575 {
3676 cliServer,
3777 queryRunner,
3878 queryStorageDir,
39- qlDir,
4079 databaseItem,
4180 progress,
4281 token,
4382 } : Omit < FlowModelOptions , "onResults" > ,
4483) : Promise < ModeledMethodWithSignature [ ] > {
45- const definition = extensiblePredicateDefinitions [ type ] ;
84+ if ( queryPath === undefined ) {
85+ void showAndLogExceptionWithTelemetry (
86+ redactableError `Failed to find ${ type } query` ,
87+ ) ;
88+ return [ ] ;
89+ }
4690
47- const query = join (
48- qlDir ,
49- databaseItem . language ,
50- "ql/src/utils/modelgenerator" ,
51- queryName ,
52- ) ;
91+ const definition = extensiblePredicateDefinitions [ type ] ;
5392
5493 const queryRun = queryRunner . createQueryRun (
5594 databaseItem . databaseUri . fsPath ,
5695 {
57- queryPath : query ,
96+ queryPath,
5897 quickEvalPosition : undefined ,
5998 quickEvalCountOnly : false ,
6099 } ,
@@ -78,7 +117,7 @@ async function getModeledMethodsFromFlow(
78117 ) ;
79118 if ( queryResult . resultType !== QueryResultType . SUCCESS ) {
80119 void showAndLogExceptionWithTelemetry (
81- redactableError `Failed to run ${ queryName } query: ${
120+ redactableError `Failed to run ${ basename ( queryPath ) } query: ${
82121 queryResult . message ?? "No message"
83122 } `,
84123 ) ;
@@ -90,7 +129,9 @@ async function getModeledMethodsFromFlow(
90129 const bqrsInfo = await cliServer . bqrsInfo ( bqrsPath ) ;
91130 if ( bqrsInfo [ "result-sets" ] . length !== 1 ) {
92131 void showAndLogExceptionWithTelemetry (
93- redactableError `Expected exactly one result set, got ${ bqrsInfo [ "result-sets" ] . length } for ${ queryName } ` ,
132+ redactableError `Expected exactly one result set, got ${
133+ bqrsInfo [ "result-sets" ] . length
134+ } for ${ basename ( queryPath ) } `,
94135 ) ;
95136 }
96137
@@ -116,9 +157,16 @@ export async function generateFlowModel({
116157 onResults,
117158 ...options
118159} : FlowModelOptions ) {
160+ const queries = await resolveQueries ( options . cliServer , options . databaseItem ) ;
161+
162+ const queriesByBasename : Record < string , string > = { } ;
163+ for ( const query of queries ) {
164+ queriesByBasename [ basename ( query ) ] = query ;
165+ }
166+
119167 const summaryResults = await getModeledMethodsFromFlow (
120168 "summary" ,
121- "CaptureSummaryModels.ql" ,
169+ queriesByBasename [ "CaptureSummaryModels.ql" ] ,
122170 0 ,
123171 options ,
124172 ) ;
@@ -128,7 +176,7 @@ export async function generateFlowModel({
128176
129177 const sinkResults = await getModeledMethodsFromFlow (
130178 "sink" ,
131- "CaptureSinkModels.ql" ,
179+ queriesByBasename [ "CaptureSinkModels.ql" ] ,
132180 1 ,
133181 options ,
134182 ) ;
@@ -138,7 +186,7 @@ export async function generateFlowModel({
138186
139187 const sourceResults = await getModeledMethodsFromFlow (
140188 "source" ,
141- "CaptureSourceModels.ql" ,
189+ queriesByBasename [ "CaptureSourceModels.ql" ] ,
142190 2 ,
143191 options ,
144192 ) ;
@@ -148,7 +196,7 @@ export async function generateFlowModel({
148196
149197 const neutralResults = await getModeledMethodsFromFlow (
150198 "neutral" ,
151- "CaptureNeutralModels.ql" ,
199+ queriesByBasename [ "CaptureNeutralModels.ql" ] ,
152200 3 ,
153201 options ,
154202 ) ;
0 commit comments