[glib: 2/3] gdbus-codegen: Emit GUnixFDLists if an arg has type `h` w/ min-version



commit e3f80b925405359ed70530f5a478d0e70ed78a4d
Author: Philip Withnall <withnall endlessm com>
Date:   Mon Dec 2 16:20:16 2019 +0000

    gdbus-codegen: Emit GUnixFDLists if an arg has type `h` w/ min-version
    
    This is a reimplementation of commit
    4aba03562bc1526a1baf70ad068a9395ec64bf64 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

 gio/gdbus-2.0/codegen/codegen_main.py |  7 ++++-
 gio/gdbus-2.0/codegen/dbustypes.py    |  7 ++++-
 gio/gdbus-2.0/codegen/parser.py       | 11 +++++---
 gio/tests/codegen.py                  | 50 +++++++++++++++++++++++++++++++++++
 4 files changed, 69 insertions(+), 6 deletions(-)
---
diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py
index a9dfe0428..aecacc76d 100644
--- a/gio/gdbus-2.0/codegen/codegen_main.py
+++ b/gio/gdbus-2.0/codegen/codegen_main.py
@@ -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))
 
diff --git a/gio/gdbus-2.0/codegen/dbustypes.py b/gio/gdbus-2.0/codegen/dbustypes.py
index 16364f9b7..415a5cc7a 100644
--- a/gio/gdbus-2.0/codegen/dbustypes.py
+++ b/gio/gdbus-2.0/codegen/dbustypes.py
@@ -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
diff --git a/gio/gdbus-2.0/codegen/parser.py b/gio/gdbus-2.0/codegen/parser.py
index f49136d6e..7dcc73558 100644
--- a/gio/gdbus-2.0/codegen/parser.py
+++ b/gio/gdbus-2.0/codegen/parser.py
@@ -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
diff --git a/gio/tests/codegen.py b/gio/tests/codegen.py
index 6a01b2f00..dc2c9ff1a 100644
--- a/gio/tests/codegen.py
+++ b/gio/tests/codegen.py
@@ -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())


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]