@@ -13,14 +13,16 @@ def quote_if_needed(row):
1313 if row != "true" and row != "false" :
1414 return "\" " + row + "\" "
1515 # subtypes column
16- return row
16+ return row [ 0 ]. upper () + row [ 1 :]
1717
1818def parseData (data ):
19- rows = ""
20- for (row ) in data :
19+ rows = { }
20+
21+ for row in data :
2122 d = row [0 ].split (';' )
23+ namespace = d [0 ]
2224 d = map (quote_if_needed , d )
23- rows += " - [" + ', ' .join (d ) + ']\n '
25+ helpers . insert_update ( rows , namespace , " - [" + ', ' .join (d ) + ']\n ' )
2426
2527 return rows
2628
@@ -38,12 +40,10 @@ def __init__ (self, language):
3840
3941 def printHelp (self ):
4042 print (f"""Usage:
41- python3 GenerateFlowModel.py <library-database> <outputYml> [<friendlyFrameworkName>] [--with-sinks] [--with-sources] [--with-summaries] [--with-typebased-summaries] [--dry-run]
43+ python3 GenerateFlowModel.py <library-database> [--with-sinks] [--with-sources] [--with-summaries] [--with-typebased-summaries] [--dry-run]
4244
4345This generates summary, source and sink models for the code in the database.
44- The files will be placed in `{ self .language } /ql/lib/ext/generated/<outputYml>.model.yml` where
45- outputYml is the name (and path) of the output YAML file. Usually, models are grouped by their
46- respective frameworks.
46+ The files will be placed in `{ self .language } /ql/lib/ext/generated/`.
4747
4848Which models are generated is controlled by the flags:
4949 --with-sinks
@@ -57,28 +57,18 @@ def printHelp(self):
5757
5858Example invocations:
5959$ python3 GenerateFlowModel.py /tmp/dbs/my_library_db mylibrary
60- $ python3 GenerateFlowModel.py /tmp/dbs/my_library_db mylibrary "Friendly Name of Framework"
60+ $ python3 GenerateFlowModel.py /tmp/dbs/my_library_db mylibrary
6161$ python3 GenerateFlowModel.py /tmp/dbs/my_library_db --with-sinks
6262
6363Requirements: `codeql` should both appear on your path.
6464 """ )
6565
6666
67- def setenvironment (self , target , database , friendlyName ):
67+ def setenvironment (self , database ):
6868 self .codeQlRoot = subprocess .check_output (["git" , "rev-parse" , "--show-toplevel" ]).decode ("utf-8" ).strip ()
69- if not target .endswith (".model.yml" ):
70- target += ".model.yml"
71- filename = os .path .basename (target )
72- if friendlyName is not None :
73- self .friendlyname = friendlyName
74- else :
75- self .friendlyname = filename [:- 10 ]
76- self .shortname = filename [:- 10 ]
7769 self .database = database
7870 self .generatedFrameworks = os .path .join (
7971 self .codeQlRoot , f"{ self .language } /ql/lib/ext/generated/" )
80- self .frameworkTarget = os .path .join (self .generatedFrameworks , filename )
81- self .typeBasedFrameworkTarget = os .path .join (self .generatedFrameworks , "TypeBased" + filename )
8272 self .workDir = tempfile .mkdtemp ()
8373 os .makedirs (self .generatedFrameworks , exist_ok = True )
8474
@@ -117,15 +107,11 @@ def make(language):
117107 if not generator .generateSinks and not generator .generateSources and not generator .generateSummaries and not generator .generateNeutrals and not generator .generateTypeBasedSummaries :
118108 generator .generateSinks = generator .generateSources = generator .generateSummaries = generator .generateNeutrals = True
119109
120- if len (sys .argv ) < 3 or len ( sys . argv ) > 4 :
110+ if len (sys .argv ) < 2 :
121111 generator .printHelp ()
122112 sys .exit (1 )
123113
124- friendlyName = None
125- if len (sys .argv ) == 4 :
126- friendlyName = sys .argv [3 ]
127-
128- generator .setenvironment (sys .argv [2 ], sys .argv [1 ], friendlyName )
114+ generator .setenvironment (sys .argv [1 ])
129115 return generator
130116
131117
@@ -141,58 +127,57 @@ def runQuery(self, query):
141127
142128
143129 def asAddsTo (self , rows , predicate ):
144- if rows . strip () == "" :
145- return ""
146- return helpers .addsToTemplate .format (f"codeql/{ self .language } -all" , predicate , rows )
147-
130+ extensions = { }
131+ for key in rows :
132+ extensions [ key ] = helpers .addsToTemplate .format (f"codeql/{ self .language } -all" , predicate , rows [ key ] )
133+ return extensions
148134
149135 def getAddsTo (self , query , predicate ):
150136 data = self .runQuery (query )
151137 rows = parseData (data )
152138 return self .asAddsTo (rows , predicate )
153139
154-
155140 def makeContent (self ):
156141 if self .generateSummaries :
157142 summaryAddsTo = self .getAddsTo ("CaptureSummaryModels.ql" , helpers .summaryModelPredicate )
158143 else :
159- summaryAddsTo = ""
144+ summaryAddsTo = { }
160145
161146 if self .generateSinks :
162147 sinkAddsTo = self .getAddsTo ("CaptureSinkModels.ql" , helpers .sinkModelPredicate )
163148 else :
164- sinkAddsTo = ""
149+ sinkAddsTo = { }
165150
166151 if self .generateSources :
167152 sourceAddsTo = self .getAddsTo ("CaptureSourceModels.ql" , helpers .sourceModelPredicate )
168153 else :
169- sourceAddsTo = ""
154+ sourceAddsTo = {}
170155
171156 if self .generateNeutrals :
172157 neutralAddsTo = self .getAddsTo ("CaptureNeutralModels.ql" , helpers .neutralModelPredicate )
173158 else :
174- neutralAddsTo = ""
159+ neutralAddsTo = { }
175160
176- return f"""# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
177- # Definitions of models for the { self .friendlyname } framework.
178- extensions:
179- { sinkAddsTo } { sourceAddsTo } { summaryAddsTo } { neutralAddsTo } """
161+ return helpers .merge (summaryAddsTo , sinkAddsTo , sourceAddsTo , neutralAddsTo )
180162
181163 def makeTypeBasedContent (self ):
182164 if self .generateTypeBasedSummaries :
183- typeBasedSummaryAddsTo = self .getAddsTo ("CaptureTypeBasedSummaryModels.ql" , "extSummaryModel" )
165+ typeBasedSummaryAddsTo = self .getAddsTo ("CaptureTypeBasedSummaryModels.ql" , helpers . summaryModelPredicate )
184166 else :
185- typeBasedSummaryAddsTo = ""
167+ typeBasedSummaryAddsTo = { }
186168
187- return f"""# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
188- # Definitions of type based summaries in the { self .friendlyname } framework.
189- extensions:
190- { typeBasedSummaryAddsTo } """
169+ return typeBasedSummaryAddsTo
191170
192- def save (self , content , target ):
193- with open (target , "w" ) as targetYml :
194- targetYml .write (content )
195- print ("Models as data extensions written to " + target )
171+ def save (self , extensions , extension ):
172+ # Create a file for each namespace and save models.
173+ extensionTemplate = """# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
174+ extensions:
175+ {0}"""
176+ for entry in extensions :
177+ target = os .path .join (self .generatedFrameworks , entry + extension )
178+ with open (target , "w" ) as f :
179+ f .write (extensionTemplate .format (extensions [entry ]))
180+ print ("Models as data extensions written to " + target )
196181
197182
198183 def run (self ):
@@ -204,7 +189,7 @@ def run(self):
204189 sys .exit (0 )
205190
206191 if self .generateSinks or self .generateSinks or self .generateSummaries :
207- self .save (content , self . frameworkTarget )
192+ self .save (content , ".model.yml" )
208193
209194 if self .generateTypeBasedSummaries :
210- self .save (typeBasedContent , self . typeBasedFrameworkTarget )
195+ self .save (typeBasedContent , ".typebased.model.yml" )
0 commit comments