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,44 +16,83 @@ 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+ export 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 ,
56- { queryPath : query , quickEvalPosition : undefined } ,
95+ { queryPath, quickEvalPosition : undefined } ,
5796 false ,
5897 getOnDiskWorkspaceFolders ( ) ,
5998 undefined ,
@@ -74,7 +113,7 @@ async function getModeledMethodsFromFlow(
74113 ) ;
75114 if ( queryResult . resultType !== QueryResultType . SUCCESS ) {
76115 void showAndLogExceptionWithTelemetry (
77- redactableError `Failed to run ${ queryName } query: ${
116+ redactableError `Failed to run ${ basename ( queryPath ) } query: ${
78117 queryResult . message ?? "No message"
79118 } `,
80119 ) ;
@@ -86,7 +125,9 @@ async function getModeledMethodsFromFlow(
86125 const bqrsInfo = await cliServer . bqrsInfo ( bqrsPath ) ;
87126 if ( bqrsInfo [ "result-sets" ] . length !== 1 ) {
88127 void showAndLogExceptionWithTelemetry (
89- redactableError `Expected exactly one result set, got ${ bqrsInfo [ "result-sets" ] . length } for ${ queryName } ` ,
128+ redactableError `Expected exactly one result set, got ${
129+ bqrsInfo [ "result-sets" ] . length
130+ } for ${ basename ( queryPath ) } `,
90131 ) ;
91132 }
92133
@@ -112,9 +153,16 @@ export async function generateFlowModel({
112153 onResults,
113154 ...options
114155} : FlowModelOptions ) {
156+ const queries = await resolveQueries ( options . cliServer , options . databaseItem ) ;
157+
158+ const queriesByBasename : Record < string , string > = { } ;
159+ for ( const query of queries ) {
160+ queriesByBasename [ basename ( query ) ] = query ;
161+ }
162+
115163 const summaryResults = await getModeledMethodsFromFlow (
116164 "summary" ,
117- "CaptureSummaryModels.ql" ,
165+ queriesByBasename [ "CaptureSummaryModels.ql" ] ,
118166 0 ,
119167 options ,
120168 ) ;
@@ -124,7 +172,7 @@ export async function generateFlowModel({
124172
125173 const sinkResults = await getModeledMethodsFromFlow (
126174 "sink" ,
127- "CaptureSinkModels.ql" ,
175+ queriesByBasename [ "CaptureSinkModels.ql" ] ,
128176 1 ,
129177 options ,
130178 ) ;
@@ -134,7 +182,7 @@ export async function generateFlowModel({
134182
135183 const sourceResults = await getModeledMethodsFromFlow (
136184 "source" ,
137- "CaptureSourceModels.ql" ,
185+ queriesByBasename [ "CaptureSourceModels.ql" ] ,
138186 2 ,
139187 options ,
140188 ) ;
@@ -144,7 +192,7 @@ export async function generateFlowModel({
144192
145193 const neutralResults = await getModeledMethodsFromFlow (
146194 "neutral" ,
147- "CaptureNeutralModels.ql" ,
195+ queriesByBasename [ "CaptureNeutralModels.ql" ] ,
148196 3 ,
149197 options ,
150198 ) ;
0 commit comments