mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-11-17 07:58:21 +01:00
gdbus-codegen: Add an extension system which allows hooking codegen
The extension points are chosen by what libdex needs to generate future based method calls.
This commit is contained in:
committed by
Philip Withnall
parent
07ba38449e
commit
4405fe5fc8
@@ -47,6 +47,7 @@ SYNOPSIS
|
||||
| [--annotate *ELEMENT* *KEY* *VALUE*]…
|
||||
| [--glib-min-required *VERSION*]
|
||||
| [--glib-max-allowed *VERSION*]
|
||||
| [--extension-path *EXTENSION_PATH*]
|
||||
| *FILE*…
|
||||
|
||||
DESCRIPTION
|
||||
@@ -392,6 +393,20 @@ The following options are supported:
|
||||
greater than or equal to that passed to ``--glib-min-required``.
|
||||
It defaults to the version of GLib which provides this ``gdbus-codegen``.
|
||||
|
||||
``--extension-path`` *EXTENSION_PATH*
|
||||
|
||||
Used to load an extension to the codegen. The *EXTENSION_PATH* is a path to
|
||||
a Python file that will be loaded as a module. The extension needs to define
|
||||
at least the function ``def init(args, options)`` where ``args`` is a
|
||||
``argparse.Namespace`` and ``options`` is a dict containing the key
|
||||
``version``.
|
||||
|
||||
All other API the extension can use are internal and thus unstable, but effort
|
||||
is made to increase the ``version`` field when those internals change. If you
|
||||
want to use this mechanism, please get in touch by
|
||||
`filing an issue <https://gitlab.gnome.org/GNOME/glib/-/issues>`_. with your
|
||||
use case.
|
||||
|
||||
SUPPORTED D-BUS ANNOTATIONS
|
||||
---------------------------
|
||||
|
||||
|
||||
@@ -41,6 +41,54 @@ LICENSE_STR = """/*
|
||||
# flake8: noqa: E501
|
||||
|
||||
|
||||
def extensionpoint(func):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
# ensures same signature
|
||||
func(*args, **kwargs)
|
||||
if not self._ext:
|
||||
return
|
||||
method = getattr(self._ext, func.__name__, None)
|
||||
if not method:
|
||||
return
|
||||
method(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class ExtensionGenerator:
|
||||
def __init__(self, ext, generator):
|
||||
if self.extending != generator.__class__.__name__:
|
||||
raise Exception("Trying to extend wrong class")
|
||||
self._ext = None
|
||||
klass = getattr(ext, self.extending, None)
|
||||
if klass:
|
||||
self._ext = klass(generator)
|
||||
|
||||
|
||||
class ExtensionHeaderCodeGenerator(ExtensionGenerator):
|
||||
extending = "HeaderCodeGenerator"
|
||||
|
||||
@extensionpoint
|
||||
def generate_includes():
|
||||
pass
|
||||
|
||||
@extensionpoint
|
||||
def declare_types():
|
||||
pass
|
||||
|
||||
|
||||
class ExtensionCodeGenerator(ExtensionGenerator):
|
||||
extending = "CodeGenerator"
|
||||
|
||||
@extensionpoint
|
||||
def generate_body_preamble():
|
||||
pass
|
||||
|
||||
@extensionpoint
|
||||
def generate():
|
||||
pass
|
||||
|
||||
|
||||
def generate_namespace(namespace):
|
||||
ns = namespace
|
||||
if len(namespace) > 0:
|
||||
@@ -84,6 +132,7 @@ class HeaderCodeGenerator:
|
||||
symbol_decorator,
|
||||
symbol_decorator_header,
|
||||
outfile,
|
||||
ext,
|
||||
):
|
||||
self.ifaces = ifaces
|
||||
self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
|
||||
@@ -96,6 +145,7 @@ class HeaderCodeGenerator:
|
||||
self.symbol_decorator = symbol_decorator
|
||||
self.symbol_decorator_header = symbol_decorator_header
|
||||
self.outfile = outfile
|
||||
self.ext = ExtensionHeaderCodeGenerator(ext, self)
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -116,6 +166,7 @@ class HeaderCodeGenerator:
|
||||
|
||||
self.outfile.write("\n")
|
||||
self.outfile.write("#include <gio/gio.h>\n")
|
||||
self.ext.generate_includes()
|
||||
self.outfile.write("\n")
|
||||
self.outfile.write("G_BEGIN_DECLS\n")
|
||||
self.outfile.write("\n")
|
||||
@@ -360,6 +411,7 @@ class HeaderCodeGenerator:
|
||||
" GError **error);\n"
|
||||
)
|
||||
self.outfile.write("\n")
|
||||
|
||||
self.outfile.write("\n")
|
||||
|
||||
# Then the property accessor declarations
|
||||
@@ -1014,6 +1066,7 @@ class HeaderCodeGenerator:
|
||||
def generate(self):
|
||||
self.generate_header_preamble()
|
||||
self.declare_types()
|
||||
self.ext.declare_types()
|
||||
self.generate_header_postamble()
|
||||
|
||||
|
||||
@@ -1458,6 +1511,7 @@ class CodeGenerator:
|
||||
glib_min_required,
|
||||
symbol_decoration_define,
|
||||
outfile,
|
||||
ext,
|
||||
):
|
||||
self.ifaces = ifaces
|
||||
self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
|
||||
@@ -1469,6 +1523,7 @@ class CodeGenerator:
|
||||
self.symbol_decoration_define = symbol_decoration_define
|
||||
self.outfile = outfile
|
||||
self.marshallers = set()
|
||||
self.ext = ExtensionCodeGenerator(ext, self)
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -5478,6 +5533,7 @@ class CodeGenerator:
|
||||
|
||||
def generate(self):
|
||||
self.generate_body_preamble()
|
||||
self.ext.generate_body_preamble()
|
||||
for i in self.ifaces:
|
||||
self.generate_generic_marshallers(i)
|
||||
for i in self.ifaces:
|
||||
@@ -5496,3 +5552,4 @@ class CodeGenerator:
|
||||
if self.generate_objmanager:
|
||||
self.generate_object()
|
||||
self.generate_object_manager_client()
|
||||
self.ext.generate()
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import importlib.util
|
||||
import traceback
|
||||
from contextlib import contextmanager
|
||||
|
||||
from . import config
|
||||
@@ -38,6 +40,16 @@ from . import codegen_rst
|
||||
from .utils import print_error, print_warning
|
||||
|
||||
|
||||
def import_from_path(module_name, file_path):
|
||||
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
||||
if not spec:
|
||||
raise Exception("Not a Python file")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[module_name] = module
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def find_arg(arg_list, arg_name):
|
||||
for a in arg_list:
|
||||
if a.name == arg_name:
|
||||
@@ -274,6 +286,12 @@ def codegen_main():
|
||||
help="Additional define required for decorator specified by "
|
||||
"--symbol-decorator",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--extension-path",
|
||||
metavar="EXTENSION_PATH",
|
||||
default="",
|
||||
help="Path to a gdbus-codegen Python extension file (unstable API)",
|
||||
)
|
||||
|
||||
group = arg_parser.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
@@ -305,6 +323,20 @@ def codegen_main():
|
||||
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
codegen_ext = {}
|
||||
if args.extension_path:
|
||||
try:
|
||||
codegen_ext = import_from_path("GDBusCodegenExt", args.extension_path)
|
||||
codegen_ext.init(
|
||||
args,
|
||||
{
|
||||
"version": 1,
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
print_warning(traceback.format_exc())
|
||||
print_error("Loading extension ‘{}’ failed".format(args.extension_path))
|
||||
|
||||
if len(args.xml_files) > 0:
|
||||
print_warning(
|
||||
'The "--xml-files" option is deprecated; use positional arguments instead'
|
||||
@@ -479,6 +511,7 @@ def codegen_main():
|
||||
args.symbol_decorator,
|
||||
args.symbol_decorator_header,
|
||||
outfile,
|
||||
codegen_ext,
|
||||
)
|
||||
gen.generate()
|
||||
|
||||
@@ -494,6 +527,7 @@ def codegen_main():
|
||||
glib_min_required,
|
||||
args.symbol_decorator_define,
|
||||
outfile,
|
||||
codegen_ext,
|
||||
)
|
||||
gen.generate()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user