7
7
import sys
8
8
import tempfile
9
9
import re
10
+ import argparse
10
11
11
12
def quote_if_needed (row ):
12
13
if row != "true" and row != "false" :
@@ -26,112 +27,76 @@ def parseData(data):
26
27
return rows
27
28
28
29
29
- def printHelp ():
30
- print (f"""Usage:
31
- python3 generate_mad.py <library-database> [DIR] --language LANGUAGE [--with-sinks] [--with-sources] [--with-summaries] [--with-neutrals] [--with-typebased-summaries] [--dry-run]
32
-
30
+ description = """\
33
31
This generates summary, source, sink and neutral models for the code in the database.
34
- The files will be placed in `LANGUAGE/ql/lib/ext/generated/DIR`
35
-
36
- Which models are generated is controlled by the flags:
37
- --with-sinks
38
- --with-sources
39
- --with-summaries
40
- --with-neutrals
41
- --with-typebased-summaries (Experimental)
42
- If none of these flags are specified, all models are generated except for the type based models.
43
-
44
- --dry-run: Only run the queries, but don't write to file.
32
+ The files will be placed in `LANGUAGE/ql/lib/ext/generated/DIR`"""
45
33
34
+ epilog = """\
46
35
Example invocations:
47
36
$ python3 generate_mad.py /tmp/dbs/my_library_db
48
37
$ python3 generate_mad.py /tmp/dbs/my_library_db --with-sinks
49
38
$ python3 generate_mad.py /tmp/dbs/my_library_db --with-sinks my_directory
50
39
51
-
52
- Requirements: `codeql` should appear on your path.
53
- """ )
40
+ Requirements: `codeql` should appear on your path."""
54
41
55
42
class Generator :
56
- def __init__ (self , language ):
43
+ generateSinks = False
44
+ generateSources = False
45
+ generateSummaries = False
46
+ generateNeutrals = False
47
+ generateTypeBasedSummaries = False
48
+ dryRun = False
49
+ dirname = "modelgenerator"
50
+ ram = None
51
+ threads = 0
52
+ folder = ""
53
+
54
+ def __init__ (self , language = None ):
57
55
self .language = language
58
- self .generateSinks = False
59
- self .generateSources = False
60
- self .generateSummaries = False
61
- self .generateNeutrals = False
62
- self .generateTypeBasedSummaries = False
63
- self .dryRun = False
64
- self .dirname = "modelgenerator"
65
- self .ram = 2 ** 15
66
- self .threads = 8
67
-
68
-
69
- def setenvironment (self , database , folder ):
56
+
57
+ def setenvironment (self , database = None , folder = None ):
70
58
self .codeQlRoot = subprocess .check_output (["git" , "rev-parse" , "--show-toplevel" ]).decode ("utf-8" ).strip ()
71
- self .database = database
59
+ self .database = database or self .database
60
+ self .folder = folder or self .folder
72
61
self .generatedFrameworks = os .path .join (
73
- self .codeQlRoot , f"{ self .language } /ql/lib/ext/generated/{ folder } " )
62
+ self .codeQlRoot , f"{ self .language } /ql/lib/ext/generated/{ self . folder } " )
74
63
self .workDir = tempfile .mkdtemp ()
64
+ if self .ram is None :
65
+ threads = self .threads if self .threads > 0 else os .cpu_count ()
66
+ self .ram = 2048 * threads
75
67
os .makedirs (self .generatedFrameworks , exist_ok = True )
76
68
77
69
78
70
@staticmethod
79
71
def make ():
80
- # Create a generator instance based on command line arguments.
81
- if any (s == "--help" for s in sys .argv ):
82
- printHelp ()
83
- sys .exit (0 )
84
-
85
- if "--language" in sys .argv :
86
- language = sys .argv [sys .argv .index ("--language" ) + 1 ]
87
- sys .argv .remove ("--language" )
88
- sys .argv .remove (language )
89
- else :
90
- printHelp ()
91
- sys .exit (0 )
92
-
93
- generator = Generator (language = language )
94
-
95
- if "--with-sinks" in sys .argv :
96
- sys .argv .remove ("--with-sinks" )
97
- generator .generateSinks = True
98
-
99
- if "--with-sources" in sys .argv :
100
- sys .argv .remove ("--with-sources" )
101
- generator .generateSources = True
102
-
103
- if "--with-summaries" in sys .argv :
104
- sys .argv .remove ("--with-summaries" )
105
- generator .generateSummaries = True
106
-
107
- if "--with-neutrals" in sys .argv :
108
- sys .argv .remove ("--with-neutrals" )
109
- generator .generateNeutrals = True
110
-
111
- if "--with-typebased-summaries" in sys .argv :
112
- sys .argv .remove ("--with-typebased-summaries" )
113
- generator .generateTypeBasedSummaries = True
114
-
115
- if "--dry-run" in sys .argv :
116
- sys .argv .remove ("--dry-run" )
117
- generator .dryRun = True
72
+ p = argparse .ArgumentParser (
73
+ description = description ,
74
+ formatter_class = argparse .RawTextHelpFormatter ,
75
+ epilog = epilog )
76
+ p .add_argument ("database" , help = "Path to the CodeQL database" )
77
+ p .add_argument ("folder" , nargs = "?" , default = "" , help = "Optional folder to place the generated files in" )
78
+ p .add_argument ("--language" , required = True , help = "The language for which to generate models" )
79
+ p .add_argument ("--with-sinks" , action = "store_true" , help = "Generate sink models" , dest = "generateSinks" )
80
+ p .add_argument ("--with-sources" , action = "store_true" , help = "Generate source models" , dest = "generateSources" )
81
+ p .add_argument ("--with-summaries" , action = "store_true" , help = "Generate summary models" , dest = "generateSummaries" )
82
+ p .add_argument ("--with-neutrals" , action = "store_true" , help = "Generate neutral models" , dest = "generateNeutrals" )
83
+ p .add_argument ("--with-typebased-summaries" , action = "store_true" , help = "Generate type-based summary models (experimental)" , dest = "generateTypeBasedSummaries" )
84
+ p .add_argument ("--dry-run" , action = "store_true" , help = "Do not write the generated files, just print them to stdout" , dest = "dryRun" )
85
+ p .add_argument ("--threads" , type = int , default = Generator .threads , help = "Number of threads to use for CodeQL queries (default %(default)s). `0` means use all available threads." )
86
+ p .add_argument ("--ram" , type = int , help = "Amount of RAM to use for CodeQL queries in MB. Default is to use 2048 MB per thread." )
87
+ generator = p .parse_args (namespace = Generator ())
118
88
119
89
if (not generator .generateSinks and
120
90
not generator .generateSources and
121
91
not generator .generateSummaries and
122
92
not generator .generateNeutrals and
123
93
not generator .generateTypeBasedSummaries ):
124
- generator .generateSinks = generator .generateSources = generator .generateSummaries = generator .generateNeutrals = True
125
-
126
- n = len (sys .argv )
127
- if n < 2 :
128
- printHelp ()
129
- sys .exit (1 )
130
- elif n == 2 :
131
- generator .setenvironment (sys .argv [1 ], "" )
132
- else :
133
- generator .setenvironment (sys .argv [1 ], sys .argv [2 ])
94
+ generator .generateSinks = True
95
+ generator .generateSources = True
96
+ generator .generateSummaries = True
97
+ generator .generateNeutrals = True
134
98
99
+ generator .setenvironment ()
135
100
return generator
136
101
137
102
@@ -140,11 +105,7 @@ def runQuery(self, query):
140
105
queryFile = os .path .join (self .codeQlRoot , f"{ self .language } /ql/src/utils/{ self .dirname } " , query )
141
106
resultBqrs = os .path .join (self .workDir , "out.bqrs" )
142
107
143
- cmd = ['codeql' , 'query' , 'run' , queryFile , '--database' , self .database , '--output' , resultBqrs ]
144
- if self .threads is not None :
145
- cmd += ["--threads" , str (self .threads )]
146
- if self .ram is not None :
147
- cmd += ["--ram" , str (self .ram )]
108
+ cmd = ['codeql' , 'query' , 'run' , queryFile , '--database' , self .database , '--output' , resultBqrs , "--threads" , str (self .threads ), "--ram" , str (self .ram )]
148
109
helpers .run_cmd (cmd , "Failed to generate " + query )
149
110
150
111
return helpers .readData (self .workDir , resultBqrs )
@@ -220,4 +181,4 @@ def run(self):
220
181
self .save (typeBasedContent , ".typebased.model.yml" )
221
182
222
183
if __name__ == '__main__' :
223
- Generator .make ().run ()
184
+ Generator .make ().run ()
0 commit comments