7
7
import sys
8
8
import pathlib
9
9
import typing
10
+ import shlex
10
11
11
12
if 'BUILD_WORKSPACE_DIRECTORY' not in os .environ :
12
13
# we are not running with `bazel run`, set up module search path
18
19
19
20
20
21
def _parse_args () -> argparse .Namespace :
22
+ dirs = [pathlib .Path ().resolve ()]
23
+ dirs .extend (dirs [0 ].parents )
24
+ for dir in dirs :
25
+ conf = dir / "codegen.conf"
26
+ if conf .exists ():
27
+ break
28
+ else :
29
+ conf = None
30
+
21
31
p = argparse .ArgumentParser (description = "Code generation suite" )
22
- p .add_argument ("--generate" , type = lambda x : x .split ("," ), default = [ "dbscheme" , "ql" ],
32
+ p .add_argument ("--generate" , type = lambda x : x .split ("," ),
23
33
help = "specify what targets to generate as a comma separated list, choosing among dbscheme, ql, trap "
24
34
"and cpp" )
25
35
p .add_argument ("--verbose" , "-v" , action = "store_true" , help = "print more information" )
26
36
p .add_argument ("--quiet" , "-q" , action = "store_true" , help = "only print errors" )
27
- p .add_argument ("--root-dir" , type = _abspath , default = paths .root_dir ,
28
- help = "the directory that should be regarded as the root of the language pack codebase. Used to"
29
- "compute QL imports and in some comments and as root for relative paths provided as options "
30
- "(default %(default)s)" )
31
- p .add_argument ("--language" , default = paths .root_dir .name ,
32
- help = "string that should replace {language} in other provided options" )
37
+ p .add_argument ("--configuration-file" , "-c" , type = _abspath , default = conf ,
38
+ help = "A configuration file to load options from. By default, the first codegen.conf file found by "
39
+ "going up directories from the current location. If present all paths provided in options are "
40
+ "considered relative to its directory" )
41
+ p .add_argument ("--root-dir" , type = _abspath ,
42
+ help = "the directory that should be regarded as the root of the language pack codebase. Used to "
43
+ "compute QL imports and in some comments and as root for relative paths provided as options. "
44
+ "If not provided it defaults to the directory of the configuration file, if any" )
33
45
path_arguments = [
34
46
p .add_argument ("--schema" , default = "schema.py" ,
35
47
help = "input schema file (default %(default)s)" ),
36
- p .add_argument ("--dbscheme" , default = "ql/lib/{language}.dbscheme" ,
37
- help = "output file for dbscheme generation, input file for trap generation (default "
38
- "%(default)s)" ),
39
- p .add_argument ("--ql-output" , default = "ql/lib/codeql/{language}/generated" ,
40
- help = "output directory for generated QL files (default %(default)s)" ),
41
- p .add_argument ("--ql-stub-output" , default = "ql/lib/codeql/{language}/elements" ,
42
- help = "output directory for QL stub/customization files (default %(default)s). Defines also the "
48
+ p .add_argument ("--dbscheme" ,
49
+ help = "output file for dbscheme generation, input file for trap generation" ),
50
+ p .add_argument ("--ql-output" ,
51
+ help = "output directory for generated QL files" ),
52
+ p .add_argument ("--ql-stub-output" ,
53
+ help = "output directory for QL stub/customization files. Defines also the "
43
54
"generated qll file importing every class file" ),
44
- p .add_argument ("--ql-test-output" , default = "ql/test/extractor-tests/generated" ,
45
- help = "output directory for QL generated extractor test files (default %(default)s) " ),
55
+ p .add_argument ("--ql-test-output" ,
56
+ help = "output directory for QL generated extractor test files" ),
46
57
p .add_argument ("--cpp-output" ,
47
58
help = "output directory for generated C++ files, required if trap or cpp is provided to "
48
59
"--generate" ),
49
- p .add_argument ("--generated-registry" , default = "ql/.generated.list" ,
60
+ p .add_argument ("--generated-registry" ,
50
61
help = "registry file containing information about checked-in generated code" ),
51
62
]
52
63
p .add_argument ("--ql-format" , action = "store_true" , default = True ,
@@ -56,11 +67,24 @@ def _parse_args() -> argparse.Namespace:
56
67
p .add_argument ("--force" , "-f" , action = "store_true" ,
57
68
help = "generate all files without skipping unchanged files and overwriting modified ones" ),
58
69
opts = p .parse_args ()
70
+ if opts .configuration_file is not None :
71
+ with open (opts .configuration_file ) as config :
72
+ defaults = p .parse_args (shlex .split (config .read (), comments = True ))
73
+ for flag , value in opts ._get_kwargs ():
74
+ if value is None :
75
+ setattr (opts , flag , getattr (defaults , flag ))
76
+ if opts .root_dir is None :
77
+ opts .root_dir = opts .configuration_file .parent
78
+ if opts .root_dir is None :
79
+ p .error ("Either --configuration-file or --root-dir must be provided, or a codegen.conf file must be in a "
80
+ "containing directory" )
81
+ if not opts .generate :
82
+ p .error ("Nothing to do, specify --generate" )
59
83
# absolutize all paths relative to --root-dir
60
84
for arg in path_arguments :
61
85
path = getattr (opts , arg .dest )
62
86
if path is not None :
63
- setattr (opts , arg .dest , opts .root_dir / path . format ( language = opts . language ) )
87
+ setattr (opts , arg .dest , opts .root_dir / path )
64
88
return opts
65
89
66
90
0 commit comments