77import sys
88import pathlib
99import typing
10+ import shlex
1011
1112if 'BUILD_WORKSPACE_DIRECTORY' not in os .environ :
1213 # we are not running with `bazel run`, set up module search path
1819
1920
2021def _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+
2131 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 ("," ),
2333 help = "specify what targets to generate as a comma separated list, choosing among dbscheme, ql, trap "
2434 "and cpp" )
2535 p .add_argument ("--verbose" , "-v" , action = "store_true" , help = "print more information" )
2636 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" )
3345 path_arguments = [
3446 p .add_argument ("--schema" , default = "schema.py" ,
3547 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 "
4354 "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" ),
4657 p .add_argument ("--cpp-output" ,
4758 help = "output directory for generated C++ files, required if trap or cpp is provided to "
4859 "--generate" ),
49- p .add_argument ("--generated-registry" , default = "ql/.generated.list" ,
60+ p .add_argument ("--generated-registry" ,
5061 help = "registry file containing information about checked-in generated code" ),
5162 ]
5263 p .add_argument ("--ql-format" , action = "store_true" , default = True ,
@@ -56,11 +67,24 @@ def _parse_args() -> argparse.Namespace:
5667 p .add_argument ("--force" , "-f" , action = "store_true" ,
5768 help = "generate all files without skipping unchanged files and overwriting modified ones" ),
5869 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" )
5983 # absolutize all paths relative to --root-dir
6084 for arg in path_arguments :
6185 path = getattr (opts , arg .dest )
6286 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 )
6488 return opts
6589
6690
0 commit comments