summaryrefslogtreecommitdiff
path: root/utils/g-ir-merge/g-ir-merge
diff options
context:
space:
mode:
Diffstat (limited to 'utils/g-ir-merge/g-ir-merge')
-rw-r--r--utils/g-ir-merge/g-ir-merge172
1 files changed, 172 insertions, 0 deletions
diff --git a/utils/g-ir-merge/g-ir-merge b/utils/g-ir-merge/g-ir-merge
new file mode 100644
index 000000000..66dfb7cb3
--- /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
+
+
+def argument_parser():
+ parser = argparse.ArgumentParser(
+ description="Merge .gir repostories 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 contractory info.
+
+ '''
+ ns = {
+ 'core': 'http://www.gtk.org/introspection/core/1.0',
+ 'c': 'http://www.gtk.org/introspection/c/1.0'
+ }
+
+ 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(
+ '', 'http://www.gtk.org/introspection/core/1.0')
+ ElementTree.register_namespace(
+ 'c', 'http://www.gtk.org/introspection/c/1.0')
+ ElementTree.register_namespace(
+ 'glib', 'http://www.gtk.org/introspection/glib/1.0')
+ 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)