diff options
author | Sam Thursfield <sam@afuera.me.uk> | 2017-06-23 16:25:05 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2017-06-28 11:53:54 +0200 |
commit | 796e025156d5176afd3a76907d0f881a6069fd25 (patch) | |
tree | 3249002514251c1605e5cb6fd90fa44d8b1dcfbc /utils | |
parent | 1ef2fb92c66078b9604ca7a1026f8e324f4495c3 (diff) | |
download | tracker-796e025156d5176afd3a76907d0f881a6069fd25.tar.gz |
Fix missing introspection data for libtracker-sparql (when using Meson)
Up til now only the Tracker.SparqlConnection and Tracker.SparqlBuilder
resources were introspectable. This is because we only used the
introspection output from `valac`, but other bits of libtracker-sparql
have since been added that are written in C.
There seems to be no way to generate a single .gir for a combined C and
Vala codebase, so instead I have written a simple `g-ir-merge` script
which can combine two different namespaces into a single .gir.
This is currently tested and working with the Meson build instructions.
It would be possible to implement this for the Autotools build
instructions as well.
https://bugzilla.gnome.org/show_bug.cgi?id=782091
Diffstat (limited to 'utils')
-rw-r--r-- | utils/Makefile.am | 2 | ||||
-rwxr-xr-x | utils/g-ir-merge/g-ir-merge | 172 |
2 files changed, 173 insertions, 1 deletions
diff --git a/utils/Makefile.am b/utils/Makefile.am index caf0f72f4..88dcffd10 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -9,4 +9,4 @@ if HAVE_TRACKER_RESDUMP SUBDIRS += tracker-resdump endif -EXTRA_DIST = meson.build +EXTRA_DIST = meson.build g-ir-merge/g-ir-merge diff --git a/utils/g-ir-merge/g-ir-merge b/utils/g-ir-merge/g-ir-merge new file mode 100755 index 000000000..45ed5f535 --- /dev/null +++ b/utils/g-ir-merge/g-ir-merge @@ -0,0 +1,172 @@ +#!/usr/bin/python3 +# +# Copyright 2017, Sam Thursfield <sam@afuera.me.uk> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + + +'''g-ir-merge: combine multiple GObject Introspection namespaces together. + +This tool exists to solve a problem in Tracker: we have code for +libtracker-sparql written in both C and Vala. It's not possible to generate +a single .gir for all of this code as `g-ir-scanner` can't deal with Vala's +generated .c code, and `valac` only handles .vala code. + +The only workable solution seems to be to generate two different .gir files +and manually combine them. Thankfully it's not too difficult to do this. + +For more discussion, see: https://bugzilla.gnome.org/show_bug.cgi?id=782091 + +''' + + +import argparse +import sys +from xml.etree import ElementTree + +CORE_NAMESPACE = 'http://www.gtk.org/introspection/core/1.0' +C_NAMESPACE = 'http://www.gtk.org/introspection/c/1.0' +GLIB_NAMESPACE = 'http://www.gtk.org/introspection/glib/1.0' + +def argument_parser(): + parser = argparse.ArgumentParser( + description="Merge .gir repositories together.") + + parser.add_argument('--namespace', '-n', metavar='NAMESPACE_NAME', type=str, required=True, + help="name for combined .gir namespace") + parser.add_argument('--nsversion', metavar='NAMESPACE_VERSION', type=str, required=True, + help="version for combined .gir namespace") + + parser.add_argument('--c-include', metavar='C_INCLUDES', type=list, + help="override list of C includes") + + parser.add_argument('files', metavar="GIR_FILE", type=str, nargs='+', + help="input .gir file") + return parser + + +def parse_inputs(files): + '''Read the important contents from one or more .gir files and return all. + + This does no post-processing of the data, it simply returns everything + including any duplicate or contradictory info. + + ''' + ns = { + 'core': CORE_NAMESPACE, + 'c': C_NAMESPACE + } + + includes = [] + namespaces = [] + c_includes = [] + + for file in files: + gi_repository = ElementTree.parse(file).getroot() + + for gi_include in gi_repository.findall('core:include', ns): + includes.append(gi_include) + + for gi_namespace in gi_repository.findall('core:namespace', ns): + namespaces.append(gi_namespace) + + for gi_c_include in gi_repository.findall('c:include', ns): + c_includes.append(gi_c_include) + + return includes, namespaces, c_includes + + +def merge_includes(all_includes): + merged = {} + for element in all_includes: + name = element.get('name') + version = element.get('version') + if name not in merged: + merged[name] = element + return merged.values() + + +def merge_namespaces(all_namespaces): + identifier_prefixes = set() + symbol_prefixes = set() + shared_libraries = set() + + contents = [] + + for element in all_namespaces: + if element.get('c:identifier_prefixes', None): + identifier_prefixes.update(element.get('c:identifier_prefixes').split(',')) + if element.get('c:symbol_prefixes', None): + symbol_prefixes.update(element.get('c:symbol_prefixes').split(',')) + identifier_prefixes.update(element.get('c:prefix', [])) + symbol_prefixes.update(element.get('c:prefix', [])) + + if element.get('shared-library', None): + shared_libraries.update(element.get('shared-library', '').split(',')) + + contents.extend(element) + + return (contents, + ','.join(sorted(identifier_prefixes)), + ','.join(sorted(symbol_prefixes)), + ','.join(sorted(shared_libraries))) + + +def create_repository(namespace_name, namespace_version, shared_libraries, + c_identifier_prefixes, c_symbol_prefixes, includes, namespace_contents): + '''Create a new GI repository with a single namespace.''' + ElementTree.register_namespace('', CORE_NAMESPACE) + ElementTree.register_namespace('c', C_NAMESPACE) + ElementTree.register_namespace('glib', GLIB_NAMESPACE) + gir_version = '1.2' + + repository = ElementTree.Element('repository', attrib={'version': gir_version}) + repository.extend(includes) + + namespace = ElementTree.SubElement(repository, 'namespace', attrib={ + 'name': namespace_name, + 'version': namespace_version, + 'shared-library': shared_libraries, + 'c:identifier-prefixes': c_identifier_prefixes, + 'c:symbol-prefixes': c_symbol_prefixes, + }) + namespace.extend(namespace_contents) + + return repository + + +def main(): + args = argument_parser().parse_args() + + all_includes, all_namespaces, all_c_includes = parse_inputs(args.files) + + includes = merge_includes(all_includes) + + namespace_contents, identifier_prefixes, symbol_prefixes, shared_libraries \ + = merge_namespaces(all_namespaces) + + repository = create_repository(args.namespace, args.nsversion, shared_libraries, + identifier_prefixes, symbol_prefixes, + includes, namespace_contents) + + print(ElementTree.tostring(repository, encoding="unicode")) + + +try: + main() +except RuntimeError as e: + sys.stderr.write("{}\n".format(e)) + sys.exit(1) |