Matthew Booth
2012-Jan-25 17:19 UTC
[Libguestfs] [PATCH 1/2] gobject: Allow RConstOptString to return an error
RConstOptString cannot return an error in the C api. This makes it a special
case for the GObject api, as all other return types have a corresponding GError
**err argument to return an error. This change removes this special case, and
includes the possibility of an error return in the API. An error is indicated by
setting *err to a non-NULL value.
This change is in preparation for adding a close api. An attempt to call any
api, even RConstOptString, on a closed handle must return an error.
---
generator/generator_gobject.ml | 8 ++------
1 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/generator/generator_gobject.ml b/generator/generator_gobject.ml
index 4779f23..2b88274 100644
--- a/generator/generator_gobject.ml
+++ b/generator/generator_gobject.ml
@@ -37,10 +37,6 @@ let camel_of_name flags name a ^ String.uppercase
(Str.first_chars b 1) ^ Str.string_after b 1
) "" (Str.split (regexp "_") name)
-let returns_error = function
- | RConstOptString _ -> false
- | _ -> true
-
let generate_gobject_proto name ?(single_line = true)
(ret, args, optargs) flags let spacer = if
single_line then " " else "\n" in
@@ -109,7 +105,7 @@ let generate_gobject_proto name ?(single_line = true)
| _ -> ());
if List.exists (function Cancellable -> true | _ -> false) flags then
pr ", GCancellable *cancellable";
- if returns_error ret then pr ", GError **err";
+ pr ", GError **err";
pr ")"
let generate_gobject_header_static () @@ -780,7 +776,7 @@ let
generate_gobject_c_methods ()
(* Check return, throw error if necessary, marshall return value *)
- if returns_error ret then (
+ if match ret with RConstOptString _ -> false | _ -> true then (
pr " if (ret == %s) {\n"
(match ret with
| RErr | RInt _ | RInt64 _ | RBool _ ->
--
1.7.7.5
Matthew Booth
2012-Jan-25 17:19 UTC
[Libguestfs] [PATCH 2/2] gobject: Add an explicit close call
This change binds guestfs_close(). It consequently results in RConstOptString
being able to throw an error.
---
generator/generator_gobject.ml | 79 ++++++++++++++++++++++++++++------------
gobject/run-bindtests | 1 +
gobject/tests-misc.js | 41 +++++++++++++++++++++
3 files changed, 97 insertions(+), 24 deletions(-)
create mode 100644 gobject/tests-misc.js
diff --git a/generator/generator_gobject.ml b/generator/generator_gobject.ml
index 2b88274..b005dfe 100644
--- a/generator/generator_gobject.ml
+++ b/generator/generator_gobject.ml
@@ -156,6 +156,7 @@ struct _GuestfsSessionClass
GType guestfs_session_get_type(void);
GuestfsSession *guestfs_session_new(void);
+gboolean guestfs_session_close(GuestfsSession *session, GError **err);
/* Guestfs::Tristate */
typedef enum
@@ -304,6 +305,16 @@ let generate_gobject_c_static () * images.
*/
+/* Error quark */
+
+#define GUESTFS_ERROR guestfs_error_quark()
+
+static GQuark
+guestfs_error_quark(void)
+{
+ return g_quark_from_static_string(\"guestfs\");
+}
+
#define GUESTFS_SESSION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ( \
(obj), \
GUESTFS_TYPE_SESSION, \
@@ -357,6 +368,29 @@ guestfs_session_new(void)
return GUESTFS_SESSION(g_object_new(GUESTFS_TYPE_SESSION, NULL));
}
+/**
+ * guestfs_session_close:
+ *
+ * Close a libguestfs session.
+ *
+ * Returns: true on success, false on error
+ */
+gboolean
+guestfs_session_close(GuestfsSession *session, GError **err)
+{
+ guestfs_h *g = session->priv->g;
+
+ if (g == NULL) {
+ g_set_error_literal(err, GUESTFS_ERROR, 0, \"Session is already
closed\");
+ return FALSE;
+ }
+
+ guestfs_close(g);
+ session->priv->g = NULL;
+
+ return TRUE;
+}
+
/* Guestfs::Tristate */
GType
guestfs_tristate_get_type(void)
@@ -374,16 +408,6 @@ guestfs_tristate_get_type(void)
return etype;
}
-/* Error quark */
-
-#define GUESTFS_ERROR guestfs_error_quark()
-
-static GQuark
-guestfs_error_quark(void)
-{
- return g_quark_from_static_string(\"guestfs\");
-}
-
/* Cancellation handler */
static void
cancelled_handler(gpointer data)
@@ -598,7 +622,15 @@ let generate_gobject_c_methods () let doc =
String.concat "\n * " doc in
let camel_name = camel_of_name flags name in
let is_RBufferOut = match ret with RBufferOut _ -> true | _ ->
false in
- let error_return = match ret with
+ let guestfs_error_return = match ret with
+ | RErr | RInt _ | RInt64 _ | RBool _ ->
+ "-1"
+ | RConstString _ | RString _ | RStringList _ | RHashtable _
+ | RBufferOut _ | RStruct _ | RStructList _ ->
+ "NULL"
+ | RConstOptString _ -> "" (* We don't check
RConstOptString for error *)
+ in
+ let gobject_error_return = match ret with
| RErr ->
"FALSE"
| RInt _ | RInt64 _ | RBool _ ->
@@ -606,7 +638,9 @@ let generate_gobject_c_methods () | RConstString _ |
RString _ | RStringList _ | RHashtable _
| RBufferOut _ | RStruct _ | RStructList _ ->
"NULL"
- | RConstOptString _ -> ""
+ | RConstOptString _ ->
+ "NULL" (* NULL is a valid return for RConstOptString. Error
is
+ indicated by also setting *err to a non-NULL value *)
in
(* The comment header, including GI annotations for arguments and the
@@ -684,10 +718,16 @@ let generate_gobject_c_methods () if cancellable
then (
pr " /* Check we haven't already been cancelled */\n";
pr " if (g_cancellable_set_error_if_cancelled (cancellable,
err))\n";
- pr " return %s;\n\n" error_return;
+ pr " return %s;\n\n" gobject_error_return;
);
+ (* Get the guestfs handle, and ensure it isn't closed *)
+
pr " guestfs_h *g = session->priv->g;\n";
+ pr " if (g == NULL) {\n";
+ pr " g_set_error_literal(err, GUESTFS_ERROR, 0, \"Attempt to
call %s after the session has been closed\");\n" name;
+ pr " return %s;\n" gobject_error_return;
+ pr " }\n\n";
(* Optargs *)
@@ -777,18 +817,9 @@ let generate_gobject_c_methods () (* Check return,
throw error if necessary, marshall return value *)
if match ret with RConstOptString _ -> false | _ -> true then (
- pr " if (ret == %s) {\n"
- (match ret with
- | RErr | RInt _ | RInt64 _ | RBool _ ->
- "-1"
- | RConstString _ | RString _ | RStringList _ | RHashtable _
- | RBufferOut _ | RStruct _ | RStructList _ ->
- "NULL"
- | RConstOptString _ ->
- assert false;
- );
+ pr " if (ret == %s) {\n" guestfs_error_return;
pr " g_set_error_literal(err, GUESTFS_ERROR, 0,
guestfs_last_error(g));\n";
- pr " return %s;\n" error_return;
+ pr " return %s;\n" gobject_error_return;
pr " }\n";
);
pr "\n";
diff --git a/gobject/run-bindtests b/gobject/run-bindtests
index 55c489c..d2ce0a6 100755
--- a/gobject/run-bindtests
+++ b/gobject/run-bindtests
@@ -26,3 +26,4 @@ fi
../run $GJS $srcdir/bindtests.js > bindtests.tmp
diff -u ${srcdir}/../bindtests bindtests.tmp
../run $GJS $srcdir/bindtests-manual.js 2>/dev/null
+../run $GJS $srcdir/tests-misc.js 2>/dev/null
diff --git a/gobject/tests-misc.js b/gobject/tests-misc.js
new file mode 100644
index 0000000..aadc2f3
--- /dev/null
+++ b/gobject/tests-misc.js
@@ -0,0 +1,41 @@
+// libguestfs miscellaneous gobject binding tests
+// Copyright (C) 2012 Red Hat Inc.
+//
+// This program 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 program 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 program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+const Guestfs = imports.gi.Guestfs;
+
+var fail = false;
+
+var g = new Guestfs.Session();
+
+// Test close()
+g.close();
+var threw = false;
+try {
+ var v = g.test0rconstoptstring('1');
+} catch (error) {
+ threw = true;
+ if (!error.message.match(/closed/)) {
+ print("call after close threw unexpected error: " +
error.message);
+ fail = true;
+ }
+}
+if (!threw) {
+ print("call after closed failed to throw an error");
+ fail = true;
+}
+
+fail ? 1 : 0;
--
1.7.7.5
Richard W.M. Jones
2012-Jan-26 08:46 UTC
[Libguestfs] [PATCH 1/2] gobject: Allow RConstOptString to return an error
On Wed, Jan 25, 2012 at 05:19:41PM +0000, Matthew Booth wrote:> @@ -780,7 +776,7 @@ let generate_gobject_c_methods () > > (* Check return, throw error if necessary, marshall return value *) > > - if returns_error ret then ( > + if match ret with RConstOptString _ -> false | _ -> true then ( > pr " if (ret == %s) {\n" > (match ret with > | RErr | RInt _ | RInt64 _ | RBool _ ->This is a bit of a mouthful. You can just write: match ret with | RConstOptString _ -> () | _ -> pr (* etc *) However the rest of the patch is fine, so ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
Seemingly Similar Threads
- [PATCH] Split gobject sources into 1 file per class
- GObject bindings
- [PATCH 01/10] Revert "Revert "generator: Add CamelName flag""
- [PATCH 01/16] generator: Fix unescaped '<' and '>' in api descriptions
- [PATCH 1/3] gobject: NFC generated code formatting fix