mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
lua: Various fixes and enhancements:
- add support for events (with test) - test progress messages - update documentation to describe events - refactor handle closing code - refactor error code - use 'assert' in test code instead of 'if ... then error end'
This commit is contained in:
326
generator/lua.ml
326
generator/lua.ml
@@ -53,19 +53,41 @@ let generate_lua_c () =
|
||||
|
||||
/* This struct is managed on the Lua heap. If the GC collects it,
|
||||
* the Lua '__gc' function is called which ends up calling
|
||||
* lua_guestfs_finalizer. If we need to store other per-handle
|
||||
* data in future, that can be placed into this struct.
|
||||
* lua_guestfs_finalizer.
|
||||
*
|
||||
* There is also an entry in the Lua registry, indexed by 'g'
|
||||
* (allocated on demand) which stores per-handle Lua data. See
|
||||
* functions 'get_per_handle_table', 'free_per_handle_table'.
|
||||
*/
|
||||
struct userdata {
|
||||
guestfs_h *g; /* Libguestfs handle, NULL if closed. */
|
||||
struct event_state *es;
|
||||
};
|
||||
|
||||
/* Structure passed to event_callback_wrapper. */
|
||||
struct event_state {
|
||||
struct event_state *next; /* Stored in a linked list. */
|
||||
lua_State *L;
|
||||
struct userdata *u;
|
||||
int ref; /* Reference to closure. */
|
||||
};
|
||||
|
||||
static struct userdata *get_handle (lua_State *L, int index);
|
||||
|
||||
static void get_per_handle_table (lua_State *L, guestfs_h *g);
|
||||
static void free_per_handle_table (lua_State *L, guestfs_h *g);
|
||||
|
||||
static char **get_string_list (lua_State *L, int index);
|
||||
static void push_string_list (lua_State *L, char **strs);
|
||||
static void push_table (lua_State *L, char **table);
|
||||
static int64_t get_int64 (lua_State *L, int index);
|
||||
static void push_int64 (lua_State *L, int64_t i64);
|
||||
static void push_int64_array (lua_State *L, const int64_t *array, size_t len);
|
||||
|
||||
static void event_callback_wrapper (guestfs_h *g, void *esvp, uint64_t event, int eh, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len);
|
||||
static uint64_t get_event (lua_State *L, int index);
|
||||
static uint64_t get_event_bitmask (lua_State *L, int index);
|
||||
static void push_event (lua_State *L, uint64_t event);
|
||||
|
||||
";
|
||||
|
||||
@@ -80,6 +102,10 @@ static void push_int64 (lua_State *L, int64_t i64);
|
||||
|
||||
pr "\
|
||||
|
||||
/* On the stack at 'index' should be a table. Check if 'name' (string)
|
||||
* is a key in this table, and if so execute 'code'. While 'code' is
|
||||
* executing, the top of stack (ie. index == -1) is the value of 'name'.
|
||||
*/
|
||||
#define OPTARG_IF_SET(index, name, code) \\
|
||||
do { \\
|
||||
lua_pushliteral (L, name); \\
|
||||
@@ -123,18 +149,32 @@ lua_guestfs_create (lua_State *L)
|
||||
lua_setmetatable (L, -2);
|
||||
|
||||
u->g = g;
|
||||
u->es = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
close_handle (lua_State *L, guestfs_h *g)
|
||||
{
|
||||
guestfs_close (g);
|
||||
free_per_handle_table (L, g);
|
||||
}
|
||||
|
||||
/* Finalizer. */
|
||||
static int
|
||||
lua_guestfs_finalizer (lua_State *L)
|
||||
{
|
||||
struct userdata *u = get_handle (L, 1);
|
||||
struct event_state *es, *es_next;
|
||||
|
||||
if (u->g)
|
||||
guestfs_close (u->g);
|
||||
close_handle (L, u->g);
|
||||
|
||||
for (es = u->es; es != NULL; es = es_next) {
|
||||
es_next = es->next;
|
||||
free (es);
|
||||
}
|
||||
|
||||
/* u will be freed by Lua when we return. */
|
||||
|
||||
@@ -148,13 +188,67 @@ lua_guestfs_close (lua_State *L)
|
||||
struct userdata *u = get_handle (L, 1);
|
||||
|
||||
if (u->g) {
|
||||
guestfs_close (u->g);
|
||||
close_handle (L, u->g);
|
||||
u->g = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the last error in the handle. */
|
||||
static int
|
||||
last_error (lua_State *L, guestfs_h *g)
|
||||
{
|
||||
/* Construct an error object on the stack containing 'msg'
|
||||
* and 'code' fields.
|
||||
*/
|
||||
lua_newtable (L);
|
||||
lua_pushliteral (L, \"msg\");
|
||||
lua_pushstring (L, guestfs_last_error (g));
|
||||
lua_settable (L, -3);
|
||||
lua_pushliteral (L, \"code\");
|
||||
lua_pushinteger (L, guestfs_last_errno (g));
|
||||
lua_settable (L, -3);
|
||||
|
||||
/* Raise an exception with the error object. */
|
||||
return lua_error (L);
|
||||
}
|
||||
|
||||
/* Push the per-handle Lua table onto the stack. This is stored
|
||||
* in the global Lua registry. It is allocated on demand the first
|
||||
* time you call this function. Use luaL_ref to allocate new
|
||||
* entries in this table.
|
||||
* See also: http://www.lua.org/pil/27.3.1.html
|
||||
*/
|
||||
static void
|
||||
get_per_handle_table (lua_State *L, guestfs_h *g)
|
||||
{
|
||||
again:
|
||||
lua_pushlightuserdata (L, g);
|
||||
lua_gettable (L, LUA_REGISTRYINDEX);
|
||||
if (lua_isnil (L, -1)) {
|
||||
lua_pop (L, 1);
|
||||
/* registry[g] = {} */
|
||||
lua_pushlightuserdata (L, g);
|
||||
lua_newtable (L);
|
||||
lua_settable (L, LUA_REGISTRYINDEX);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the per-handle Lua table. It doesn't literally \"free\"
|
||||
* anything since the GC will do that. It just removes the entry
|
||||
* from the global registry.
|
||||
*/
|
||||
static void
|
||||
free_per_handle_table (lua_State *L, guestfs_h *g)
|
||||
{
|
||||
/* registry[g] = nil */
|
||||
lua_pushlightuserdata (L, g);
|
||||
lua_pushnil (L);
|
||||
lua_settable (L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
/* User cancel. */
|
||||
static int
|
||||
lua_guestfs_user_cancel (lua_State *L)
|
||||
@@ -167,8 +261,129 @@ lua_guestfs_user_cancel (lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set an event callback. */
|
||||
static int
|
||||
lua_guestfs_set_event_callback (lua_State *L)
|
||||
{
|
||||
struct userdata *u = get_handle (L, 1);
|
||||
guestfs_h *g = u->g;
|
||||
uint64_t event_bitmask;
|
||||
int eh;
|
||||
int ref;
|
||||
struct event_state *es;
|
||||
|
||||
if (g == NULL)
|
||||
return luaL_error (L, \"Guestfs.%%s: handle is closed\",
|
||||
\"set_event_callback\");
|
||||
|
||||
event_bitmask = get_event_bitmask (L, 3);
|
||||
|
||||
/* Save the function in the per-handle table, so that the GC doesn't
|
||||
* clean it up before the event fires.
|
||||
*/
|
||||
luaL_checktype (L, 2, LUA_TFUNCTION);
|
||||
get_per_handle_table (L, g);
|
||||
lua_pushvalue (L, 2);
|
||||
ref = luaL_ref (L, -2);
|
||||
lua_pop (L, 1);
|
||||
|
||||
es = malloc (sizeof *es);
|
||||
if (!es)
|
||||
return luaL_error (L, \"failed to allocate event_state\");
|
||||
es->next = u->es;
|
||||
es->L = L;
|
||||
es->u = u;
|
||||
es->ref = ref;
|
||||
u->es = es;
|
||||
|
||||
eh = guestfs_set_event_callback (g, event_callback_wrapper,
|
||||
event_bitmask, 0, es);
|
||||
if (eh == -1)
|
||||
return last_error (L, g);
|
||||
|
||||
/* Return the event handle. */
|
||||
lua_pushinteger (L, eh);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
event_callback_wrapper (guestfs_h *g,
|
||||
void *esvp,
|
||||
uint64_t event,
|
||||
int eh,
|
||||
int flags,
|
||||
const char *buf, size_t buf_len,
|
||||
const uint64_t *array, size_t array_len)
|
||||
{
|
||||
struct event_state *es = esvp;
|
||||
lua_State *L = es->L;
|
||||
struct userdata *u = es->u;
|
||||
|
||||
/* Look up the closure to call in the per-handle table. */
|
||||
get_per_handle_table (L, g);
|
||||
lua_rawgeti (L, -1, es->ref);
|
||||
|
||||
if (!lua_isfunction (L, -1)) {
|
||||
fprintf (stderr, \"lua-guestfs: %%s: internal error: no closure found for g = %%p, eh = %%d\\n\",
|
||||
__func__, g, eh);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Call the event handler: event_handler (g, event, eh, flags, buf, array) */
|
||||
lua_pushlightuserdata (L, u); /* XXX correct? */
|
||||
push_event (L, event);
|
||||
lua_pushinteger (L, eh);
|
||||
lua_pushinteger (L, flags);
|
||||
lua_pushlstring (L, buf, buf_len);
|
||||
push_int64_array (L, (const int64_t *) array, array_len);
|
||||
|
||||
switch (lua_pcall (L, 6, 0, 0)) {
|
||||
case 0: /* call ok - do nothing */
|
||||
break;
|
||||
case LUA_ERRRUN:
|
||||
fprintf (stderr, \"lua-guestfs: %%s: unexpected error in event handler\\n\",
|
||||
__func__);
|
||||
/* XXX could print the error instead of throwing it away */
|
||||
lua_pop (L, 1);
|
||||
break;
|
||||
case LUA_ERRERR: /* can probably never happen */
|
||||
fprintf (stderr, \"lua-guestfs: %%s: error calling error handler\\n\",
|
||||
__func__);
|
||||
break;
|
||||
case LUA_ERRMEM:
|
||||
fprintf (stderr, \"lua-guestfs: %%s: memory allocation failed\\n\", __func__);
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, \"lua-guestfs: %%s: unknown error\\n\", __func__);
|
||||
}
|
||||
|
||||
/* Pop the per-handle table. */
|
||||
out:
|
||||
lua_pop (L, 1);
|
||||
}
|
||||
|
||||
/* Delete an event callback. */
|
||||
static int
|
||||
lua_guestfs_delete_event_callback (lua_State *L)
|
||||
{
|
||||
struct userdata *u = get_handle (L, 1);
|
||||
guestfs_h *g = u->g;
|
||||
int eh;
|
||||
|
||||
if (g == NULL)
|
||||
return luaL_error (L, \"Guestfs.%%s: handle is closed\",
|
||||
\"delete_event_callback\");
|
||||
|
||||
eh = luaL_checkint (L, 2);
|
||||
|
||||
guestfs_delete_event_callback (g, eh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
";
|
||||
|
||||
(* Actions. *)
|
||||
List.iter (
|
||||
fun { name = name; style = (ret, args, optargs as style);
|
||||
c_function = c_function; c_optarg_prefix = c_optarg_prefix } ->
|
||||
@@ -249,7 +464,7 @@ lua_guestfs_user_cancel (lua_State *L)
|
||||
| Bool n ->
|
||||
pr " %s = lua_toboolean (L, %d);\n" n i
|
||||
| Int n ->
|
||||
pr " %s = lua_tointeger (L, %d);\n" n i
|
||||
pr " %s = luaL_checkint (L, %d);\n" n i
|
||||
| Int64 n ->
|
||||
pr " %s = get_int64 (L, %d);\n" n i
|
||||
| Pointer (t, n) -> assert false
|
||||
@@ -274,7 +489,7 @@ lua_guestfs_user_cancel (lua_State *L)
|
||||
| OBool n ->
|
||||
pr " optargs_s.%s = lua_toboolean (L, -1);\n" n
|
||||
| OInt n ->
|
||||
pr " optargs_s.%s = lua_tointeger (L, -1);\n" n
|
||||
pr " optargs_s.%s = luaL_checkint (L, -1);\n" n
|
||||
| OInt64 n ->
|
||||
pr " optargs_s.%s = get_int64 (L, -1);\n" n
|
||||
| OString n ->
|
||||
@@ -313,28 +528,15 @@ lua_guestfs_user_cancel (lua_State *L)
|
||||
) optargs;
|
||||
|
||||
(* Handle errors. *)
|
||||
let raise_error () =
|
||||
pr " lua_newtable (L);\n";
|
||||
pr " lua_pushliteral (L, \"msg\");\n";
|
||||
pr " lua_pushstring (L, guestfs_last_error (g));\n";
|
||||
pr " lua_settable (L, -3);\n";
|
||||
pr " lua_pushliteral (L, \"code\");\n";
|
||||
pr " lua_pushinteger (L, guestfs_last_errno (g));\n";
|
||||
pr " lua_settable (L, -3);\n";
|
||||
pr " return lua_error (L);\n"
|
||||
in
|
||||
|
||||
(match errcode_of_ret ret with
|
||||
| `CannotReturnError -> ()
|
||||
| `ErrorIsMinusOne ->
|
||||
pr " if (r == -1) {\n";
|
||||
raise_error ();
|
||||
pr " }\n";
|
||||
pr " if (r == -1)\n";
|
||||
pr " return last_error (L, g);\n";
|
||||
pr "\n"
|
||||
| `ErrorIsNULL ->
|
||||
pr " if (r == NULL) {\n";
|
||||
raise_error ();
|
||||
pr " }\n";
|
||||
pr " if (r == NULL)\n";
|
||||
pr " return last_error (L, g);\n";
|
||||
pr "\n"
|
||||
);
|
||||
|
||||
@@ -415,9 +617,8 @@ push_string_list (lua_State *L, char **strs)
|
||||
|
||||
lua_newtable (L);
|
||||
for (i = 0; strs[i] != NULL; ++i) {
|
||||
lua_pushinteger (L, i+1 /* because of base 1 arrays */);
|
||||
lua_pushstring (L, strs[i]);
|
||||
lua_settable (L, -3);
|
||||
lua_rawseti (L, -2, i+1 /* because of base 1 arrays */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,8 +660,78 @@ push_int64 (lua_State *L, int64_t i64)
|
||||
lua_pushstring (L, s);
|
||||
}
|
||||
|
||||
static void
|
||||
push_int64_array (lua_State *L, const int64_t *array, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
lua_newtable (L);
|
||||
for (i = 0; i < len; ++i) {
|
||||
push_int64 (L, array[i]);
|
||||
lua_rawseti (L, -2, i+1 /* because of base 1 arrays */);
|
||||
}
|
||||
}
|
||||
|
||||
";
|
||||
|
||||
(* Code to handle events. *)
|
||||
pr "\
|
||||
static uint64_t
|
||||
get_event_bitmask (lua_State *L, int index)
|
||||
{
|
||||
uint64_t bitmask;
|
||||
|
||||
if (lua_isstring (L, index))
|
||||
return get_event (L, index);
|
||||
|
||||
bitmask = 0;
|
||||
|
||||
lua_pushnil (L);
|
||||
while (lua_next (L, index) != 0) {
|
||||
bitmask |= get_event (L, -1);
|
||||
lua_pop (L, 1); /* pop value */
|
||||
}
|
||||
lua_pop (L, 1); /* pop key */
|
||||
|
||||
return bitmask;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
get_event (lua_State *L, int index)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s = luaL_checkstring (L, index);
|
||||
";
|
||||
|
||||
List.iter (
|
||||
fun (event, i) ->
|
||||
pr " if (strcmp (s, \"%s\") == 0)\n" event;
|
||||
pr " return %d;\n" i
|
||||
) events;
|
||||
|
||||
pr " return luaL_error (L, \"unknown event name '%%s'\", s);
|
||||
}
|
||||
|
||||
static void
|
||||
push_event (lua_State *L, uint64_t event)
|
||||
{
|
||||
";
|
||||
|
||||
List.iter (
|
||||
fun (event, i) ->
|
||||
pr " if (event == %d) {\n" i;
|
||||
pr " lua_pushliteral (L, \"%s\");\n" event;
|
||||
pr " return;\n";
|
||||
pr " }\n";
|
||||
) events;
|
||||
|
||||
pr " abort (); /* should never happen */
|
||||
}
|
||||
|
||||
";
|
||||
|
||||
(* Code to push structs. *)
|
||||
let generate_push_struct typ =
|
||||
pr "static void\n";
|
||||
pr "push_%s (lua_State *L, struct guestfs_%s *v)\n" typ typ;
|
||||
@@ -501,9 +772,8 @@ push_int64 (lua_State *L, int64_t i64)
|
||||
pr "\n";
|
||||
pr " lua_newtable (L);\n";
|
||||
pr " for (i = 0; i < v->len; ++i) {\n";
|
||||
pr " lua_pushinteger (L, i+1 /* because of base 1 arrays */);\n";
|
||||
pr " push_%s (L, &v->val[i]);\n" typ;
|
||||
pr " lua_settable (L, -3);\n";
|
||||
pr " lua_rawseti (L, -2, i+1 /* because of base 1 arrays */);\n";
|
||||
pr " }\n";
|
||||
pr "}\n";
|
||||
pr "\n"
|
||||
@@ -525,6 +795,8 @@ static luaL_Reg handle_methods[] = {
|
||||
{ \"create\", lua_guestfs_create },
|
||||
{ \"close\", lua_guestfs_close },
|
||||
{ \"user_cancel\", lua_guestfs_user_cancel },
|
||||
{ \"set_event_callback\", lua_guestfs_set_event_callback },
|
||||
{ \"delete_event_callback\", lua_guestfs_delete_event_callback },
|
||||
|
||||
";
|
||||
|
||||
|
||||
@@ -55,12 +55,14 @@ TESTS = \
|
||||
tests/025-create-flags.lua \
|
||||
tests/027-create-multiple.lua \
|
||||
tests/030-config.lua \
|
||||
tests/070-optargs.lua
|
||||
tests/070-optargs.lua \
|
||||
tests/400-events.lua
|
||||
|
||||
if ENABLE_APPLIANCE
|
||||
TESTS += \
|
||||
tests/050-lvcreate.lua \
|
||||
tests/060-readdir.lua
|
||||
tests/060-readdir.lua \
|
||||
tests/400-progress.lua
|
||||
endif
|
||||
|
||||
EXTRA_DIST += \
|
||||
@@ -71,7 +73,9 @@ EXTRA_DIST += \
|
||||
tests/030-config.lua \
|
||||
tests/050-lvcreate.lua \
|
||||
tests/060-readdir.lua \
|
||||
tests/070-optargs.lua
|
||||
tests/070-optargs.lua \
|
||||
tests/400-events.lua \
|
||||
tests/400-progress.lua
|
||||
|
||||
# Custom install rule.
|
||||
install-data-hook:
|
||||
|
||||
@@ -83,6 +83,33 @@ The C<errno> (corresponding to L<guestfs(3)/guestfs_last_errno>).
|
||||
Note that some errors can also be thrown as plain strings. You
|
||||
need to check the type.
|
||||
|
||||
=head2 EVENTS
|
||||
|
||||
Events can be registered by calling C<set_event_callback>:
|
||||
|
||||
eh = g:set_event_callback (cb, "close")
|
||||
|
||||
or to register a single callback for multiple events make the
|
||||
second argument a list:
|
||||
|
||||
eh = g:set_event_callback (cb, { "appliance", "library", "trace" })
|
||||
|
||||
The callback (C<cb>) is called with the following parameters:
|
||||
|
||||
function cb (g, event, eh, flags, buf, array)
|
||||
-- g is the guestfs handle
|
||||
-- event is a string which is the name of the event that fired
|
||||
-- flags is always zero
|
||||
-- buf is the data buffer (eg. log message etc)
|
||||
-- array is the array of 64 bit ints (eg. progress bar status etc)
|
||||
...
|
||||
end
|
||||
|
||||
You can also remove a callback using the event handle (C<eh>) that was
|
||||
returned when you registered the callback:
|
||||
|
||||
g:delete_event_callback (eh)
|
||||
|
||||
=head1 EXAMPLE 1: CREATE A DISK IMAGE
|
||||
|
||||
@EXAMPLE1@
|
||||
|
||||
@@ -27,15 +27,6 @@ g1:set_path ("1")
|
||||
g2:set_path ("2")
|
||||
g3:set_path ("3")
|
||||
|
||||
if g1:get_path () ~= "1" then
|
||||
error (string.format ("incorrect path in g1, expected '1', got '%s'",
|
||||
g1:get_path ()))
|
||||
end
|
||||
if g2:get_path () ~= "2" then
|
||||
error (string.format ("incorrect path in g2, expected '2', got '%s'",
|
||||
g2:get_path ()))
|
||||
end
|
||||
if g3:get_path () ~= "3" then
|
||||
error (string.format ("incorrect path in g3, expected '3', got '%s'",
|
||||
g3:get_path ()))
|
||||
end
|
||||
assert (g1:get_path () == "1", "incorrect path in g1, expected '1'")
|
||||
assert (g2:get_path () == "2", "incorrect path in g2, expected '2'")
|
||||
assert (g3:get_path () == "3", "incorrect path in g3, expected '3'")
|
||||
|
||||
@@ -28,9 +28,7 @@ g:set_autosync (false)
|
||||
g:set_autosync (true)
|
||||
|
||||
g:set_path (".")
|
||||
if g:get_path () ~= "." then
|
||||
error ()
|
||||
end
|
||||
assert (g:get_path () == ".")
|
||||
|
||||
g:add_drive ("/dev/null")
|
||||
|
||||
|
||||
@@ -35,10 +35,9 @@ g:lvcreate ("LV1", "VG", 200)
|
||||
g:lvcreate ("LV2", "VG", 200)
|
||||
|
||||
local lvs = g:lvs ()
|
||||
if table.getn (lvs) ~= 2 or lvs[1] ~= "/dev/VG/LV1" or lvs[2] ~= "/dev/VG/LV2"
|
||||
then
|
||||
error ("g:lvs returned incorrect result")
|
||||
end
|
||||
assert (table.getn (lvs) == 2 and
|
||||
lvs[1] == "/dev/VG/LV1" and lvs[2] == "/dev/VG/LV2",
|
||||
"g:lvs returned incorrect result")
|
||||
|
||||
g:shutdown ()
|
||||
|
||||
|
||||
@@ -51,12 +51,8 @@ print_dirs (dirs)
|
||||
|
||||
-- Slots 1, 2, 3 contain "." and ".." and "lost+found" respectively.
|
||||
|
||||
if (dirs[4]["name"] ~= "p") then
|
||||
error "incorrect name in slot 4"
|
||||
end
|
||||
if (dirs[5]["name"] ~= "q") then
|
||||
error "incorrect name in slot 5"
|
||||
end
|
||||
assert (dirs[4]["name"] == "p", "incorrect name in slot 4")
|
||||
assert (dirs[5]["name"] == "q", "incorrect name in slot 5")
|
||||
|
||||
g:shutdown ()
|
||||
|
||||
|
||||
49
lua/tests/400-events.lua
Executable file
49
lua/tests/400-events.lua
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/lua
|
||||
-- libguestfs Lua bindings -*- lua -*-
|
||||
-- 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.
|
||||
|
||||
require "guestfs"
|
||||
|
||||
g = Guestfs.create ()
|
||||
|
||||
function log_callback (g, event, eh, flags, buf, array)
|
||||
io.write (string.format ("lua event logged: event=%s eh=%d buf='%s'\n",
|
||||
event, eh, buf))
|
||||
end
|
||||
|
||||
close_invoked = 0
|
||||
function close_callback (g, event, eh, flags, buf, array)
|
||||
close_invoked = close_invoked+1
|
||||
log_callback (g, event, eh, flags, buf, array)
|
||||
end
|
||||
|
||||
-- Register an event callback for all log messages.
|
||||
g:set_event_callback (log_callback, { "appliance", "library", "trace" })
|
||||
|
||||
-- Register an event callback for the close event.
|
||||
g:set_event_callback (close_callback, "close")
|
||||
|
||||
-- Make sure we see some messages.
|
||||
g:set_trace (true)
|
||||
g:set_verbose (true)
|
||||
|
||||
-- Do some stuff.
|
||||
g:add_drive_ro ("/dev/null")
|
||||
|
||||
-- Close the handle. The close callback should be invoked.
|
||||
g:close ()
|
||||
assert (close_invoked == 1, "close callback was not invoked")
|
||||
44
lua/tests/400-progress.lua
Executable file
44
lua/tests/400-progress.lua
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/lua
|
||||
-- libguestfs Lua bindings -*- lua -*-
|
||||
-- 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.
|
||||
|
||||
require "guestfs"
|
||||
|
||||
g = Guestfs.create ()
|
||||
|
||||
g:add_drive ("/dev/null")
|
||||
g:launch ()
|
||||
|
||||
calls = 0
|
||||
function cb ()
|
||||
calls = calls+1
|
||||
end
|
||||
|
||||
eh = g:set_event_callback (cb, "progress")
|
||||
assert (g:debug ("progress", {"5"}) == "ok", "debug progress command failed")
|
||||
assert (calls > 0, "progress callback was not invoked")
|
||||
|
||||
calls = 0
|
||||
g:delete_event_callback (eh)
|
||||
assert (g:debug ("progress", {"5"}) == "ok", "debug progress command failed")
|
||||
assert (calls == 0, "progress callback was invoked when deleted")
|
||||
|
||||
g:set_event_callback (cb, "progress")
|
||||
assert (g:debug ("progress", {"5"}) == "ok", "debug progress command failed")
|
||||
assert (calls > 0, "progress callback was not invoked")
|
||||
|
||||
g:close ()
|
||||
Reference in New Issue
Block a user