[glib: 1/3] gdbus-codegen: Add a --glib-min-version argument



commit 90f0733858f42e595c499893ea70d5c78b86f8d8
Author: Philip Withnall <withnall endlessm com>
Date:   Mon Dec 2 15:53:14 2019 +0000

    gdbus-codegen: Add a --glib-min-version argument
    
    This can be used by callers to opt-in to backwards-incompatible changes
    to the behaviour or output of `gdbus-codegen` in future. This commit
    doesn’t introduce any such changes, though.
    
    Documentation and unit tests included.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>
    
    Helps: #1726

 docs/reference/gio/gdbus-codegen.xml  | 25 +++++++++++++++++++++++++
 gio/gdbus-2.0/codegen/codegen.py      | 12 ++++++++----
 gio/gdbus-2.0/codegen/codegen_main.py | 27 +++++++++++++++++++++++++++
 gio/tests/codegen.py                  | 35 +++++++++++++++++++++++++++++++++++
 4 files changed, 95 insertions(+), 4 deletions(-)
---
diff --git a/docs/reference/gio/gdbus-codegen.xml b/docs/reference/gio/gdbus-codegen.xml
index fdd367bc5..a0615cb8b 100644
--- a/docs/reference/gio/gdbus-codegen.xml
+++ b/docs/reference/gio/gdbus-codegen.xml
@@ -50,6 +50,7 @@
         <replaceable>VALUE</replaceable>
       </arg>
     </group>
+    <arg><option>--glib-min-version</option> <replaceable>VERSION</replaceable></arg>
     <arg choice="plain">FILE</arg>
     <arg>
       <arg choice="plain" rep="repeat">FILE</arg>
@@ -420,6 +421,30 @@ gdbus-codegen --c-namespace MyApp                           \
       </listitem>
     </varlistentry>
 
+    <varlistentry>
+      <term><option>--glib-min-version</option> <replaceable>VERSION</replaceable></term>
+      <listitem>
+        <para>
+          Specifies the minimum version of GLib which the code generated by
+          <command>gdbus-codegen</command> can depend on. This may be used to
+          make backwards-incompatible changes in the output or behaviour of
+          <command>gdbus-codegen</command> in future, which users may opt in to
+          by increasing the value they pass for <option>--glib-min-version</option>.
+          If this option is not passed, the output from <command>gdbus-codegen</command>
+          is guaranteed to be compatible with all versions of GLib from 2.30
+          upwards, as that is when <command>gdbus-codegen</command> was first
+          released.
+        </para>
+        <para>
+          The version number must be of the form
+          
<literal><replaceable>MAJOR</replaceable>.<replaceable>MINOR</replaceable>.<replaceable>MICRO</replaceable></literal>,
+          where all parts are integers. <replaceable>MINOR</replaceable> and
+          <replaceable>MICRO</replaceable> are optional. The version number may not be smaller
+          than <literal>2.30</literal>.
+        </para>
+      </listitem>
+    </varlistentry>
+
   </variablelist>
 </refsect1>
 
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index 3b3afe611..92622e2c2 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -62,7 +62,7 @@ def generate_header_guard(header_name):
 class HeaderCodeGenerator:
     def __init__(self, ifaces, namespace, generate_objmanager,
                  generate_autocleanup, header_name, input_files_basenames,
-                 use_pragma, outfile):
+                 use_pragma, glib_min_version, outfile):
         self.ifaces = ifaces
         self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
         self.generate_objmanager = generate_objmanager
@@ -70,6 +70,7 @@ class HeaderCodeGenerator:
         self.header_guard = generate_header_guard(header_name)
         self.input_files_basenames = input_files_basenames
         self.use_pragma = use_pragma
+        self.glib_min_version = glib_min_version
         self.outfile = outfile
 
     # ----------------------------------------------------------------------------------------------------
@@ -618,12 +619,13 @@ class HeaderCodeGenerator:
 # ----------------------------------------------------------------------------------------------------
 
 class InterfaceInfoHeaderCodeGenerator:
-    def __init__(self, ifaces, namespace, header_name, input_files_basenames, use_pragma, outfile):
+    def __init__(self, ifaces, namespace, header_name, input_files_basenames, use_pragma, glib_min_version, 
outfile):
         self.ifaces = ifaces
         self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
         self.header_guard = generate_header_guard(header_name)
         self.input_files_basenames = input_files_basenames
         self.use_pragma = use_pragma
+        self.glib_min_version = glib_min_version
         self.outfile = outfile
 
     # ----------------------------------------------------------------------------------------------------
@@ -671,11 +673,12 @@ class InterfaceInfoHeaderCodeGenerator:
 # ----------------------------------------------------------------------------------------------------
 
 class InterfaceInfoBodyCodeGenerator:
-    def __init__(self, ifaces, namespace, header_name, input_files_basenames, outfile):
+    def __init__(self, ifaces, namespace, header_name, input_files_basenames, glib_min_version, outfile):
         self.ifaces = ifaces
         self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
         self.header_name = header_name
         self.input_files_basenames = input_files_basenames
+        self.glib_min_version = glib_min_version
         self.outfile = outfile
 
     # ----------------------------------------------------------------------------------------------------
@@ -903,13 +906,14 @@ class InterfaceInfoBodyCodeGenerator:
 
 class CodeGenerator:
     def __init__(self, ifaces, namespace, generate_objmanager, header_name,
-                 input_files_basenames, docbook_gen, outfile):
+                 input_files_basenames, docbook_gen, glib_min_version, outfile):
         self.ifaces = ifaces
         self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
         self.generate_objmanager = generate_objmanager
         self.header_name = header_name
         self.input_files_basenames = input_files_basenames
         self.docbook_gen = docbook_gen
+        self.glib_min_version = glib_min_version
         self.outfile = outfile
 
     # ----------------------------------------------------------------------------------------------------
diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py
index e77ad5569..a9dfe0428 100644
--- a/gio/gdbus-2.0/codegen/codegen_main.py
+++ b/gio/gdbus-2.0/codegen/codegen_main.py
@@ -167,6 +167,8 @@ def codegen_main():
                             help='Use "pragma once" as the inclusion guard')
     arg_parser.add_argument('--annotate', nargs=3, action='append', metavar='WHAT KEY VALUE',
                             help='Add annotation (may be used several times)')
+    arg_parser.add_argument('--glib-min-version', metavar='VERSION',
+                            help='Minimum version of GLib to be supported by the outputted code (default: 
2.30)')
 
     group = arg_parser.add_mutually_exclusive_group()
     group.add_argument('--generate-c-code', metavar='OUTFILES',
@@ -233,6 +235,27 @@ def codegen_main():
         c_file = args.output
         header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h'
 
+    # Check the minimum GLib version. The minimum --glib-min-version is 2.30,
+    # because that’s when gdbus-codegen was introduced. Support 1, 2 or 3
+    # component versions, but ignore the micro component if it’s present.
+    if args.glib_min_version:
+        try:
+            parts = args.glib_min_version.split('.', 3)
+            glib_min_version = (int(parts[0]),
+                                int(parts[1] if len(parts) > 1 else 0))
+            # Ignore micro component, but still validate it:
+            _ = int(parts[2] if len(parts) > 2 else 0)
+        except (ValueError, IndexError):
+            print_error('Unrecognized --glib-min-version string ‘{}’'.format(
+                args.glib_min_version))
+
+        if glib_min_version[0] < 2 or \
+           (glib_min_version[0] == 2 and glib_min_version[1] < 30):
+            print_error('Invalid --glib-min-version string ‘{}’: minimum '
+                        'version is 2.30'.format(args.glib_min_version))
+    else:
+        glib_min_version = (2, 30)
+
     all_ifaces = []
     input_files_basenames = []
     for fname in sorted(args.files + args.xml_files):
@@ -262,6 +285,7 @@ def codegen_main():
                                               header_name,
                                               input_files_basenames,
                                               args.pragma_once,
+                                              glib_min_version,
                                               outfile)
             gen.generate()
 
@@ -273,6 +297,7 @@ def codegen_main():
                                         header_name,
                                         input_files_basenames,
                                         docbook_gen,
+                                        glib_min_version,
                                         outfile)
             gen.generate()
 
@@ -283,6 +308,7 @@ def codegen_main():
                                                            header_name,
                                                            input_files_basenames,
                                                            args.pragma_once,
+                                                           glib_min_version,
                                                            outfile)
             gen.generate()
 
@@ -292,6 +318,7 @@ def codegen_main():
                                                          args.c_namespace,
                                                          header_name,
                                                          input_files_basenames,
+                                                         glib_min_version,
                                                          outfile)
             gen.generate()
 
diff --git a/gio/tests/codegen.py b/gio/tests/codegen.py
index bffe6f342..6a01b2f00 100644
--- a/gio/tests/codegen.py
+++ b/gio/tests/codegen.py
@@ -362,6 +362,41 @@ G_END_DECLS
                 # The output should be the same.
                 self.assertEqual(result1.out, result2.out)
 
+    def test_glib_min_version_invalid(self):
+        """Test running with an invalid --glib-min-version."""
+        with self.assertRaises(subprocess.CalledProcessError):
+            self.runCodegenWithInterface('',
+                                         '--output', '/dev/stdout',
+                                         '--body',
+                                         '--glib-min-version', 'hello mum')
+
+    def test_glib_min_version_too_low(self):
+        """Test running with a --glib-min-version which is too low (and hence
+        probably a typo)."""
+        with self.assertRaises(subprocess.CalledProcessError):
+            self.runCodegenWithInterface('',
+                                         '--output', '/dev/stdout',
+                                         '--body',
+                                         '--glib-min-version', '2.6')
+
+    def test_glib_min_version_major_only(self):
+        """Test running with a --glib-min-version which contains only a major version."""
+        result = self.runCodegenWithInterface('',
+                                              '--output', '/dev/stdout',
+                                              '--header',
+                                              '--glib-min-version', '3')
+        self.assertEqual('', result.err)
+        self.assertNotEqual('', result.out.strip())
+
+    def test_glib_min_version_with_micro(self):
+        """Test running with a --glib-min-version which contains a micro version."""
+        result = self.runCodegenWithInterface('',
+                                              '--output', '/dev/stdout',
+                                              '--header',
+                                              '--glib-min-version', '2.46.2')
+        self.assertEqual('', result.err)
+        self.assertNotEqual('', result.out.strip())
+
 
 if __name__ == '__main__':
     unittest.main(testRunner=taptestrunner.TAPTestRunner())


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