gdbus-codegen: Emit GUnixFDLists if an arg has type h w/ min-version

This is a reimplementation of commit
4aba03562b from Will Thompson, but
conditional on the caller passing `--glib-min-version 2.64` to
`gdbus-codegen` to explicitly opt-in to the new behaviour.

From the commit message for that commit:

Previously, if a method was not annotated with org.gtk.GDBus.C.UnixFD
then the generated code would never contain GUnixFDList parameters, even
if the method has 'h' (file descriptor) parameters. However, in this
case, the generated code is essentially useless: the method cannot be
called or handled except in degenerate cases where the file descriptors
are missing or ignored.

Check the argument types for 'h', and if present, generate code as if
org.gtk.GDBus.C.UnixFD annotation were specified.

Includes a unit test too.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Fixes: #1726
This commit is contained in:
Philip Withnall 2019-12-02 16:20:16 +00:00
parent 90f0733858
commit e3f80b9254
4 changed files with 69 additions and 6 deletions

View File

@ -256,12 +256,17 @@ def codegen_main():
else:
glib_min_version = (2, 30)
glib_min_version_is_2_64 = (glib_min_version[0] > 2 or
(glib_min_version[0] == 2 and
glib_min_version[1] >= 64))
all_ifaces = []
input_files_basenames = []
for fname in sorted(args.files + args.xml_files):
with open(fname, 'rb') as f:
xml_data = f.read()
parsed_ifaces = parser.parse_dbus_xml(xml_data)
parsed_ifaces = parser.parse_dbus_xml(xml_data,
h_type_implies_unix_fd=glib_min_version_is_2_64)
all_ifaces.extend(parsed_ifaces)
input_files_basenames.append(os.path.basename(fname))

View File

@ -252,8 +252,9 @@ class Arg:
a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
class Method:
def __init__(self, name):
def __init__(self, name, h_type_implies_unix_fd=True):
self.name = name
self.h_type_implies_unix_fd = h_type_implies_unix_fd
self.in_args = []
self.out_args = []
self.annotations = []
@ -284,10 +285,14 @@ class Method:
for a in self.in_args:
a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count)
arg_count += 1
if self.h_type_implies_unix_fd and 'h' in a.signature:
self.unix_fd = True
for a in self.out_args:
a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count)
arg_count += 1
if self.h_type_implies_unix_fd and 'h' in a.signature:
self.unix_fd = True
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True

View File

@ -36,7 +36,7 @@ class DBusXMLParser:
STATE_ANNOTATION = 'annotation'
STATE_IGNORED = 'ignored'
def __init__(self, xml_data):
def __init__(self, xml_data, h_type_implies_unix_fd=True):
self._parser = xml.parsers.expat.ParserCreate()
self._parser.CommentHandler = self.handle_comment
self._parser.CharacterDataHandler = self.handle_char_data
@ -53,6 +53,8 @@ class DBusXMLParser:
self.doc_comment_last_symbol = ''
self._h_type_implies_unix_fd = h_type_implies_unix_fd
self._parser.Parse(xml_data)
COMMENT_STATE_BEGIN = 'begin'
@ -163,7 +165,8 @@ class DBusXMLParser:
elif self.state == DBusXMLParser.STATE_INTERFACE:
if name == DBusXMLParser.STATE_METHOD:
self.state = DBusXMLParser.STATE_METHOD
method = dbustypes.Method(attrs['name'])
method = dbustypes.Method(attrs['name'],
h_type_implies_unix_fd=self._h_type_implies_unix_fd)
self._cur_object.methods.append(method)
self._cur_object = method
elif name == DBusXMLParser.STATE_SIGNAL:
@ -288,6 +291,6 @@ class DBusXMLParser:
self.state = self.state_stack.pop()
self._cur_object = self._cur_object_stack.pop()
def parse_dbus_xml(xml_data):
parser = DBusXMLParser(xml_data)
def parse_dbus_xml(xml_data, h_type_implies_unix_fd):
parser = DBusXMLParser(xml_data, h_type_implies_unix_fd)
return parser.parsed_interfaces

View File

@ -397,6 +397,56 @@ G_END_DECLS
self.assertEqual('', result.err)
self.assertNotEqual('', result.out.strip())
def test_unix_fd_types_and_annotations(self):
"""Test an interface with `h` arguments, no annotation, and GLib < 2.64.
See issue #1726.
"""
interface_xml = '''
<node>
<interface name="FDPassing">
<method name="HelloFD">
<annotation name="org.gtk.GDBus.C.UnixFD" value="1"/>
<arg name="greeting" direction="in" type="s"/>
<arg name="response" direction="out" type="s"/>
</method>
<method name="NoAnnotation">
<arg name="greeting" direction="in" type="h"/>
<arg name="greeting_locale" direction="in" type="s"/>
<arg name="response" direction="out" type="h"/>
<arg name="response_locale" direction="out" type="s"/>
</method>
<method name="NoAnnotationNested">
<arg name="files" type="a{sh}" direction="in"/>
</method>
</interface>
</node>'''
# Try without specifying --glib-min-version.
result = self.runCodegenWithInterface(interface_xml,
'--output', '/dev/stdout',
'--header')
self.assertEqual('', result.err)
self.assertEqual(result.out.strip().count('GUnixFDList'), 6)
# Specify an old --glib-min-version.
result = self.runCodegenWithInterface(interface_xml,
'--output', '/dev/stdout',
'--header',
'--glib-min-version', '2.32')
self.assertEqual('', result.err)
self.assertEqual(result.out.strip().count('GUnixFDList'), 6)
# Specify a --glib-min-version ≥ 2.64. There should be more
# mentions of `GUnixFDList` now, since the annotation is not needed to
# trigger its use.
result = self.runCodegenWithInterface(interface_xml,
'--output', '/dev/stdout',
'--header',
'--glib-min-version', '2.64')
self.assertEqual('', result.err)
self.assertEqual(result.out.strip().count('GUnixFDList'), 18)
if __name__ == '__main__':
unittest.main(testRunner=taptestrunner.TAPTestRunner())