File: generate-version-script.py

package info (click to toggle)
libjcat 0.2.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 932 kB
  • sloc: ansic: 7,104; python: 244; sh: 82; xml: 43; makefile: 7
file content (142 lines) | stat: -rwxr-xr-x 4,594 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/python3
# pylint: disable=invalid-name,missing-docstring
#
# Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
#
# SPDX-License-Identifier: LGPL-2.1+

import sys
import argparse
import xml.etree.ElementTree as ET

XMLNS = "{http://www.gtk.org/introspection/core/1.0}"
XMLNS_C = "{http://www.gtk.org/introspection/c/1.0}"


def parse_version(ver):
    return tuple(map(int, ver.split(".")))


def usage(return_code):
    """print usage and exit with the supplied return code"""
    if return_code == 0:
        out = sys.stdout
    else:
        out = sys.stderr
    out.write("usage: %s <NAME> <INPUT> <OUTPUT>\n" % sys.argv[0])
    sys.exit(return_code)


class LdVersionScript:
    """Rasterize some text"""

    def __init__(self, library_name):
        self.library_name = library_name
        self.releases = {}
        self.overrides = {}

    def _add_node(self, node):
        identifier = node.attrib[XMLNS_C + "identifier"]
        introspectable = int(node.get("introspectable", 1))
        version = node.get("version", None)
        if introspectable and not version:
            print("No version for", identifier)
            sys.exit(1)
        if not version:
            return None
        version = node.attrib["version"]
        if version not in self.releases:
            self.releases[version] = []
        release = self.releases[version]
        if identifier not in release:
            release.append(identifier)
        return version

    def _add_cls(self, cls):

        # add all class functions
        for node in cls.findall(XMLNS + "function"):
            self._add_node(node)

        # choose the lowest version method for the _get_type symbol
        version_lowest = None

        # add all class methods
        for node in cls.findall(XMLNS + "method"):
            version_tmp = self._add_node(node)
            if version_tmp:
                if not version_lowest or parse_version(version_tmp) < parse_version(
                    version_lowest
                ):
                    version_lowest = version_tmp

        # add the constructor
        for node in cls.findall(XMLNS + "constructor"):
            version_tmp = self._add_node(node)
            if version_tmp:
                if not version_lowest or parse_version(version_tmp) < parse_version(
                    version_lowest
                ):
                    version_lowest = version_tmp

        if "{http://www.gtk.org/introspection/glib/1.0}get-type" not in cls.attrib:
            return
        type_name = cls.attrib["{http://www.gtk.org/introspection/glib/1.0}get-type"]

        # finally add the get_type symbol
        version = self.overrides.get(type_name, version_lowest)
        if version:
            self.releases[version].append(type_name)

    def import_gir(self, filename):
        tree = ET.parse(filename)
        root = tree.getroot()
        for ns in root.findall(XMLNS + "namespace"):
            for node in ns.findall(XMLNS + "function"):
                self._add_node(node)
            for cls in ns.findall(XMLNS + "record"):
                self._add_cls(cls)
            for cls in ns.findall(XMLNS + "class"):
                self._add_cls(cls)

    def render(self):

        # get a sorted list of all the versions
        versions = []
        for version in self.releases:
            versions.append(version)

        # output the version data to a file
        verout = "# generated automatically, do not edit!\n"
        oldversion = None
        for version in sorted(versions, key=parse_version):
            symbols = sorted(self.releases[version])
            verout += "\n%s_%s {\n" % (self.library_name, version)
            verout += "  global:\n"
            for symbol in symbols:
                verout += "    %s;\n" % symbol
            verout += "  local: *;\n"
            if oldversion:
                verout += "} %s_%s;\n" % (self.library_name, oldversion)
            else:
                verout += "};\n"
            oldversion = version
        return verout


if __name__ == "__main__":

    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-r", "--override", action="append", nargs=2, metavar=("symbol", "version")
    )
    args, argv = parser.parse_known_args()
    if len(argv) != 3:
        usage(1)

    ld = LdVersionScript(library_name=argv[0])
    if args.override:
        for override_symbol, override_version in args.override:
            ld.overrides[override_symbol] = override_version
    ld.import_gir(argv[1])
    open(argv[2], "w").write(ld.render())