Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ repos:
hooks:
- id: clang-format

- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v2.0.4
- repo: https://github.com/psf/black
rev: 25.1.0
hooks:
- id: autopep8
files: ^misc/codegen/.*\.py
- id: black
files: ^(misc/codegen/.*|misc/scripts/models-as-data/bulk_generate_mad)\.py$

- repo: local
hooks:
Expand Down
160 changes: 108 additions & 52 deletions misc/codegen/codegen.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
""" Driver script to run all code generation """
"""Driver script to run all code generation"""

import argparse
import logging
Expand All @@ -9,7 +9,7 @@
import typing
import shlex

if 'BUILD_WORKSPACE_DIRECTORY' not in os.environ:
if "BUILD_WORKSPACE_DIRECTORY" not in os.environ:
# we are not running with `bazel run`, set up module search path
_repo_root = pathlib.Path(__file__).resolve().parents[2]
sys.path.append(str(_repo_root))
Expand All @@ -29,57 +29,105 @@ def _parse_args() -> argparse.Namespace:
conf = None

p = argparse.ArgumentParser(description="Code generation suite")
p.add_argument("--generate", type=lambda x: x.split(","),
help="specify what targets to generate as a comma separated list, choosing among dbscheme, ql, "
"trap, cpp and rust")
p.add_argument("--verbose", "-v", action="store_true", help="print more information")
p.add_argument(
"--generate",
type=lambda x: x.split(","),
help="specify what targets to generate as a comma separated list, choosing among dbscheme, ql, "
"trap, cpp and rust",
)
p.add_argument(
"--verbose", "-v", action="store_true", help="print more information"
)
p.add_argument("--quiet", "-q", action="store_true", help="only print errors")
p.add_argument("--configuration-file", "-c", type=_abspath, default=conf,
help="A configuration file to load options from. By default, the first codegen.conf file found by "
"going up directories from the current location. If present all paths provided in options are "
"considered relative to its directory")
p.add_argument("--root-dir", type=_abspath,
help="the directory that should be regarded as the root of the language pack codebase. Used to "
"compute QL imports and in some comments and as root for relative paths provided as options. "
"If not provided it defaults to the directory of the configuration file, if any")
p.add_argument(
"--configuration-file",
"-c",
type=_abspath,
default=conf,
help="A configuration file to load options from. By default, the first codegen.conf file found by "
"going up directories from the current location. If present all paths provided in options are "
"considered relative to its directory",
)
p.add_argument(
"--root-dir",
type=_abspath,
help="the directory that should be regarded as the root of the language pack codebase. Used to "
"compute QL imports and in some comments and as root for relative paths provided as options. "
"If not provided it defaults to the directory of the configuration file, if any",
)
path_arguments = [
p.add_argument("--schema",
help="input schema file (default schema.py)"),
p.add_argument("--dbscheme",
help="output file for dbscheme generation, input file for trap generation"),
p.add_argument("--ql-output",
help="output directory for generated QL files"),
p.add_argument("--ql-stub-output",
help="output directory for QL stub/customization files. Defines also the "
"generated qll file importing every class file"),
p.add_argument("--ql-test-output",
help="output directory for QL generated extractor test files"),
p.add_argument("--ql-cfg-output",
help="output directory for QL CFG layer (optional)."),
p.add_argument("--cpp-output",
help="output directory for generated C++ files, required if trap or cpp is provided to "
"--generate"),
p.add_argument("--rust-output",
help="output directory for generated Rust files, required if rust is provided to "
"--generate"),
p.add_argument("--generated-registry",
help="registry file containing information about checked-in generated code. A .gitattributes"
"file is generated besides it to mark those files with linguist-generated=true. Must"
"be in a directory containing all generated code."),
p.add_argument("--schema", help="input schema file (default schema.py)"),
p.add_argument(
"--dbscheme",
help="output file for dbscheme generation, input file for trap generation",
),
p.add_argument("--ql-output", help="output directory for generated QL files"),
p.add_argument(
"--ql-stub-output",
help="output directory for QL stub/customization files. Defines also the "
"generated qll file importing every class file",
),
p.add_argument(
"--ql-test-output",
help="output directory for QL generated extractor test files",
),
p.add_argument(
"--ql-cfg-output", help="output directory for QL CFG layer (optional)."
),
p.add_argument(
"--cpp-output",
help="output directory for generated C++ files, required if trap or cpp is provided to "
"--generate",
),
p.add_argument(
"--rust-output",
help="output directory for generated Rust files, required if rust is provided to "
"--generate",
),
p.add_argument(
"--generated-registry",
help="registry file containing information about checked-in generated code. A .gitattributes"
"file is generated besides it to mark those files with linguist-generated=true. Must"
"be in a directory containing all generated code.",
),
]
p.add_argument("--script-name",
help="script name to put in header comments of generated files. By default, the path of this "
"script relative to the root directory")
p.add_argument("--trap-library",
help="path to the trap library from an include directory, required if generating C++ trap bindings"),
p.add_argument("--ql-format", action="store_true", default=True,
help="use codeql to autoformat QL files (which is the default)")
p.add_argument("--no-ql-format", action="store_false", dest="ql_format", help="do not format QL files")
p.add_argument("--codeql-binary", default="codeql", help="command to use for QL formatting (default %(default)s)")
p.add_argument("--force", "-f", action="store_true",
help="generate all files without skipping unchanged files and overwriting modified ones")
p.add_argument("--use-current-directory", action="store_true",
help="do not consider paths as relative to --root-dir or the configuration directory")
p.add_argument(
"--script-name",
help="script name to put in header comments of generated files. By default, the path of this "
"script relative to the root directory",
)
p.add_argument(
"--trap-library",
help="path to the trap library from an include directory, required if generating C++ trap bindings",
),
p.add_argument(
"--ql-format",
action="store_true",
default=True,
help="use codeql to autoformat QL files (which is the default)",
)
p.add_argument(
"--no-ql-format",
action="store_false",
dest="ql_format",
help="do not format QL files",
)
p.add_argument(
"--codeql-binary",
default="codeql",
help="command to use for QL formatting (default %(default)s)",
)
p.add_argument(
"--force",
"-f",
action="store_true",
help="generate all files without skipping unchanged files and overwriting modified ones",
)
p.add_argument(
"--use-current-directory",
action="store_true",
help="do not consider paths as relative to --root-dir or the configuration directory",
)
opts = p.parse_args()
if opts.configuration_file is not None:
with open(opts.configuration_file) as config:
Expand All @@ -97,7 +145,15 @@ def _parse_args() -> argparse.Namespace:
for arg in path_arguments:
path = getattr(opts, arg.dest)
if path is not None:
setattr(opts, arg.dest, _abspath(path) if opts.use_current_directory else (opts.root_dir / path))
setattr(
opts,
arg.dest,
(
_abspath(path)
if opts.use_current_directory
else (opts.root_dir / path)
),
)
if not opts.script_name:
opts.script_name = paths.exe_file.relative_to(opts.root_dir)
return opts
Expand All @@ -115,7 +171,7 @@ def run():
log_level = logging.ERROR
else:
log_level = logging.INFO
logging.basicConfig(format="{levelname} {message}", style='{', level=log_level)
logging.basicConfig(format="{levelname} {message}", style="{", level=log_level)
for target in opts.generate:
generate(target, opts, render.Renderer(opts.script_name))

Expand Down
23 changes: 17 additions & 6 deletions misc/codegen/generators/cppgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ def _get_trap_name(cls: schema.Class, p: schema.Property) -> str | None:
return inflection.pluralize(trap_name)


def _get_field(cls: schema.Class, p: schema.Property, add_or_none_except: typing.Optional[str] = None) -> cpp.Field:
def _get_field(
cls: schema.Class,
p: schema.Property,
add_or_none_except: typing.Optional[str] = None,
) -> cpp.Field:
args = dict(
field_name=p.name + ("_" if p.name in cpp.cpp_keywords else ""),
base_type=_get_type(p.type, add_or_none_except),
Expand Down Expand Up @@ -83,14 +87,15 @@ def _get_class(self, name: str) -> cpp.Class:
bases=[self._get_class(b) for b in cls.bases],
fields=[
_get_field(cls, p, self._add_or_none_except)
for p in cls.properties if "cpp_skip" not in p.pragmas and not p.synth
for p in cls.properties
if "cpp_skip" not in p.pragmas and not p.synth
],
final=not cls.derived,
trap_name=trap_name,
)

def get_classes(self):
ret = {'': []}
ret = {"": []}
for k, cls in self._classmap.items():
if not cls.synth:
ret.setdefault(cls.group, []).append(self._get_class(cls.name))
Expand All @@ -102,6 +107,12 @@ def generate(opts, renderer):
processor = Processor(schemaloader.load_file(opts.schema))
out = opts.cpp_output
for dir, classes in processor.get_classes().items():
renderer.render(cpp.ClassList(classes, opts.schema,
include_parent=bool(dir),
trap_library=opts.trap_library), out / dir / "TrapClasses")
renderer.render(
cpp.ClassList(
classes,
opts.schema,
include_parent=bool(dir),
trap_library=opts.trap_library,
),
out / dir / "TrapClasses",
)
Loading
Loading