Ruby bindings.

This commit is contained in:
Richard Jones
2009-04-16 22:13:20 +01:00
parent 5a6da98c94
commit a5f68bd57d
16 changed files with 2648 additions and 7 deletions

3
.gitignore vendored
View File

@@ -63,6 +63,9 @@ perl/Makefile.PL
perl/blib
perl/pm_to_blib
python/guestfs.pyc
ruby/Rakefile
ruby/ext/guestfs/extconf.h
ruby/ext/guestfs/mkmf.log
pod2htm?.tmp
stamp-h1
test*.img

View File

@@ -28,6 +28,9 @@ endif
if HAVE_PYTHON
SUBDIRS += python
endif
if HAVE_RUBY
SUBDIRS += ruby
endif
EXTRA_DIST = \
make-initramfs.sh update-initramfs.sh \

2
README
View File

@@ -50,6 +50,8 @@ also to build the OCaml bindings
- (Optional) Python if you want to build the python bindings
- (Optional) Ruby, rake if you want to build the ruby bindings
Running ./configure will check you have all the requirements installed
on your machine.

4
TODO
View File

@@ -3,10 +3,6 @@ https://www.redhat.com/archives/fedora-virt/2009-April/msg00114.html
----------------------------------------------------------------------
Several people have asked for Ruby bindings.
----------------------------------------------------------------------
We badly need to actually implement the FTP server mentioned in the
documentation.

View File

@@ -15,7 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
AC_INIT([libguestfs],[0.9.9])
AC_INIT([libguestfs],[1.0.0])
AM_INIT_AUTOMAKE
AC_CONFIG_MACRO_DIR([m4])
@@ -188,7 +188,16 @@ AC_SUBST(PYTHON_INCLUDEDIR)
AC_SUBST(PYTHON_SITE_PACKAGES)
AM_CONDITIONAL([HAVE_PYTHON],
[test "x$PYTHON_INCLUDEDIR" != "x" && test "x$PYTHON_SITE_PACKAGES" != "x"])
[test "x$PYTHON_INCLUDEDIR" != "x" -a "x$PYTHON_SITE_PACKAGES" != "x"])
dnl Check for Ruby and rake (optional, for Ruby bindings).
old_libs="$LIBS"
AC_CHECK_LIB([ruby],[ruby_init])
LIBS="$old_libs"
AC_CHECK_PROG([RAKE],[rake],[rake],[no])
AM_CONDITIONAL([HAVE_RUBY],
[test "x$RAKE" != "xno" -a -n "x$HAVE_LIBRUBY"])
dnl Run in subdirs.
AC_CONFIG_SUBDIRS([daemon])
@@ -200,6 +209,7 @@ AC_CONFIG_FILES([Makefile src/Makefile fish/Makefile examples/Makefile
ocaml/Makefile ocaml/examples/Makefile
perl/Makefile
python/Makefile
ruby/Makefile ruby/Rakefile
make-initramfs.sh update-initramfs.sh
libguestfs.spec
ocaml/META perl/Makefile.PL])

View File

@@ -15,7 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
AC_INIT([libguestfs-daemon],[0.8.2])
AC_INIT([libguestfs-daemon],[1.0.0])
AM_INIT_AUTOMAKE
AC_CONFIG_MACRO_DIR([m4])

View File

@@ -35,6 +35,8 @@ BuildRequires: perl-Test-Pod
BuildRequires: perl-Test-Pod-Coverage
BuildRequires: perl-ExtUtils-MakeMaker
BuildRequires: python-devel
BuildRequires: ruby-devel
BuildRequires: rubygem-rake
# Runtime requires:
Requires: qemu >= 0.10-7
@@ -70,6 +72,8 @@ For OCaml bindings, see 'libguestfs-ocaml-devel'.
For Python bindings, see 'libguestfs-python'.
For Ruby bindings, see 'libguestfs-ruby'.
%package devel
Summary: Development tools and libraries for %{name}
@@ -143,6 +147,20 @@ Requires: %{name} = %{version}-%{release}
%{name}-python contains Python bindings for %{name}.
%package ruby
Summary: Ruby bindings for %{name}
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
Requires: ruby(abi) = 1.8
Provides: ruby(guestfs) = %{version}
%{!?ruby_sitelib: %define ruby_sitelib %(ruby -rrbconfig -e "puts Config::CONFIG['sitelibdir']")}
%{!?ruby_sitearch: %define ruby_sitearch %(ruby -rrbconfig -e "puts Config::CONFIG['sitearchdir']")}
%description ruby
%{name}-ruby contains Ruby bindings for %{name}.
%prep
%setup -q
@@ -196,6 +214,12 @@ if [ "$RPM_BUILD_ROOT%{python_sitearch}" != "$RPM_BUILD_ROOT%{python_sitelib}" ]
$RPM_BUILD_ROOT%{python_sitelib}/
fi
# Install ruby bindings by hand.
mkdir -p $RPM_BUILD_ROOT%{ruby_sitelib}
mkdir -p $RPM_BUILD_ROOT%{ruby_sitearch}
install -p -m0644 ruby/lib/libvirt.rb $RPM_BUILD_ROOT%{ruby_sitelib}
install -p -m0755 ruby/ext/libvirt/_libvirt.so $RPM_BUILD_ROOT%{ruby_sitearch}
%clean
rm -rf $RPM_BUILD_ROOT
@@ -266,6 +290,12 @@ rm -rf $RPM_BUILD_ROOT
%{python_sitelib}/*.pyo
%files ruby
%defattr(-,root,root,-)
%{ruby_sitelib}/guestfs.rb
%{ruby_sitearch}/_guestfs.so
%changelog
* Thu Apr 16 2009 Richard Jones <rjones@redhat.com> - @VERSION@-1
- New upstream version @VERSION@.

43
ruby/Makefile.am Normal file
View File

@@ -0,0 +1,43 @@
# libguestfs Ruby bindings
# Copyright (C) 2009 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., 675 Mass Ave, Cambridge, MA 02139, USA.
EXTRA_DIST = \
Rakefile.in \
ext/guestfs/_guestfs.c \
ext/guestfs/extconf.rb \
lib/guestfs.rb \
run-ruby-tests \
tests/tc_*.rb
CLEANFILES = *~ \
lib/*~ \
tests/*~ \
ext/guestfs/*~ \
ext/guestfs/extconf.h \
ext/guestfs/_guestfs.o \
ext/guestfs/_guestfs.so \
ext/guestfs/mkmf.log \
ext/guestfs/Makefile
if HAVE_RUBY
TESTS = run-ruby-tests
all:
rake build
endif

103
ruby/Rakefile.in Normal file
View File

@@ -0,0 +1,103 @@
# libguestfs Ruby bindings -*- ruby -*-
# @configure_input@
# Copyright (C) 2009 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., 675 Mass Ave, Cambridge, MA 02139, USA.
require 'rake/clean'
require 'rake/rdoctask'
require 'rake/testtask'
require 'rake/gempackagetask'
PKG_NAME='@PACKAGE_NAME@'
PKG_VERSION='@PACKAGE_VERSION@'
EXT_CONF='ext/guestfs/extconf.rb'
MAKEFILE='ext/guestfs/Makefile'
GUESTFS_MODULE='ext/guestfs/_guestfs.so'
GUESTFS_SRC='ext/guestfs/_guestfs.c'
CLEAN.include [ "ext/**/*.o", GUESTFS_MODULE,
"ext/**/depend" ]
CLOBBER.include [ "config.save", "ext/**/mkmf.log",
MAKEFILE ]
# Build locally
file MAKEFILE => EXT_CONF do |t|
Dir::chdir(File::dirname(EXT_CONF)) do
unless sh "ruby #{File::basename(EXT_CONF)}"
$stderr.puts "Failed to run extconf"
break
end
end
end
file GUESTFS_MODULE => [ MAKEFILE, GUESTFS_SRC ] do |t|
Dir::chdir(File::dirname(EXT_CONF)) do
unless sh "make"
$stderr.puts "make failed"
break
end
end
end
desc "Build the native library"
task :build => GUESTFS_MODULE
Rake::TestTask.new(:test) do |t|
t.test_files = FileList['tests/tc_*.rb']
t.libs = [ 'lib', 'ext/guestfs' ]
end
task :test => :build
Rake::RDocTask.new do |rd|
rd.main = "README.rdoc"
rd.rdoc_dir = "doc/site/api"
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb", "ext/**/*.[ch]")
end
# Package tasks
PKG_FILES = FileList[
"Rakefile", "COPYING", "README", "NEWS", "README.rdoc",
"lib/**/*.rb",
"ext/**/*.[ch]", "ext/**/MANIFEST", "ext/**/extconf.rb",
"tests/**/*",
"spec/**/*"
]
DIST_FILES = FileList[
"pkg/*.src.rpm", "pkg/*.gem", "pkg/*.zip", "pkg/*.tgz"
]
SPEC = Gem::Specification.new do |s|
s.name = PKG_NAME
s.version = PKG_VERSION
s.email = "rjones@redhat.com"
s.homepage = "http://et.redhat.com/~rjones/libguestfs/"
s.summary = "Ruby bindings for libguestfs"
s.files = PKG_FILES
s.autorequire = "guestfs"
s.required_ruby_version = '>= 1.8.1'
s.extensions = "ext/guestfs/extconf.rb"
s.description = <<EOF
Ruby bindings for libguestfs.
EOF
end
Rake::GemPackageTask.new(SPEC) do |pkg|
pkg.need_tar = true
pkg.need_zip = true
end

2064
ruby/ext/guestfs/_guestfs.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
# libguestfs Ruby bindings -*- ruby -*-
# @configure_input@
# Copyright (C) 2009 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., 675 Mass Ave, Cambridge, MA 02139, USA.
require 'mkmf'
extension_name = '_guestfs'
dir_config(extension_name)
unless have_library("guestfs", "guestfs_create")
raise "libguestfs not found"
end
create_header
create_makefile(extension_name)

18
ruby/lib/guestfs.rb Normal file
View File

@@ -0,0 +1,18 @@
# libvirt Ruby bindings
# Copyright (C) 2009 Red Hat Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
require '_guestfs'

22
ruby/run-ruby-tests Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/sh -
# libguestfs Ruby bindings
# Copyright (C) 2009 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., 675 Mass Ave, Cambridge, MA 02139, USA.
export LD_LIBRARY_PATH=../src/.libs
export LIBGUESTFS_PATH=$(cd .. && pwd)
rake test "$@"

28
ruby/tests/tc_010_load.rb Normal file
View File

@@ -0,0 +1,28 @@
# libguestfs Ruby bindings -*- ruby -*-
# Copyright (C) 2009 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., 675 Mass Ave, Cambridge, MA 02139, USA.
require 'test/unit'
$:.unshift(File::join(File::dirname(__FILE__), "..", "lib"))
$:.unshift(File::join(File::dirname(__FILE__), "..", "ext", "guestfs"))
require 'guestfs'
class TestLoad < Test::Unit::TestCase
def test_load
g = Guestfs::create()
assert_not_nil (g)
end
end

View File

@@ -0,0 +1,49 @@
# libguestfs Ruby bindings -*- ruby -*-
# Copyright (C) 2009 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., 675 Mass Ave, Cambridge, MA 02139, USA.
require 'test/unit'
$:.unshift(File::join(File::dirname(__FILE__), "..", "lib"))
$:.unshift(File::join(File::dirname(__FILE__), "..", "ext", "guestfs"))
require 'guestfs'
class TestLoad < Test::Unit::TestCase
def test_lvcreate
g = Guestfs::create()
File.open("test.img", "w") {
|f| f.seek(500*1024*1024); f.write("\0")
}
g.add_drive("test.img")
g.launch()
g.wait_ready()
g.pvcreate("/dev/sda")
g.vgcreate("VG", ["/dev/sda"]);
g.lvcreate("LV1", "VG", 200);
g.lvcreate("LV2", "VG", 200);
lvs = g.lvs()
if lvs != ["/dev/VG/LV1", "/dev/VG/LV2"]
raise "incorrect lvs returned"
end
g.sync()
File.unlink("test.img")
end
end

View File

@@ -4863,6 +4863,242 @@ and pod2text ~width name longdesc =
| Unix.WSIGNALED i | Unix.WSTOPPED i ->
failwithf "pod2text: process signalled or stopped by signal %d" i
(* Generate ruby bindings. *)
and generate_ruby_c () =
generate_header CStyle LGPLv2;
pr "\
#include <stdio.h>
#include <stdlib.h>
#include <ruby.h>
#include \"guestfs.h\"
#include \"extconf.h\"
static VALUE m_guestfs; /* guestfs module */
static VALUE c_guestfs; /* guestfs_h handle */
static VALUE e_Error; /* used for all errors */
static void ruby_guestfs_free (void *p)
{
if (!p) return;
guestfs_close ((guestfs_h *) p);
}
static VALUE ruby_guestfs_create (VALUE m)
{
guestfs_h *g;
g = guestfs_create ();
if (!g)
rb_raise (e_Error, \"failed to create guestfs handle\");
/* Don't print error messages to stderr by default. */
guestfs_set_error_handler (g, NULL, NULL);
/* Wrap it, and make sure the close function is called when the
* handle goes away.
*/
return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
}
static VALUE ruby_guestfs_close (VALUE gv)
{
guestfs_h *g;
Data_Get_Struct (gv, guestfs_h, g);
ruby_guestfs_free (g);
DATA_PTR (gv) = NULL;
return Qnil;
}
";
List.iter (
fun (name, style, _, _, _, _, _) ->
pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
pr ")\n";
pr "{\n";
pr " guestfs_h *g;\n";
pr " Data_Get_Struct (gv, guestfs_h, g);\n";
pr " if (!g)\n";
pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
name;
pr "\n";
List.iter (
function
| String n ->
pr " const char *%s = StringValueCStr (%sv);\n" n n;
pr " if (!%s)\n" n;
pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
pr " \"%s\", \"%s\");\n" n name
| OptString n ->
pr " const char *%s = StringValueCStr (%sv);\n" n n
| StringList n ->
pr " char **%s;" n;
pr " {\n";
pr " int i, len;\n";
pr " len = RARRAY_LEN (%sv);\n" n;
pr " %s = malloc (sizeof (char *) * (len+1));\n" n;
pr " for (i = 0; i < len; ++i) {\n";
pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
pr " %s[i] = StringValueCStr (v);\n" n;
pr " }\n";
pr " }\n";
| Bool n
| Int n ->
pr " int %s = NUM2INT (%sv);\n" n n
) (snd style);
pr "\n";
let error_code =
match fst style with
| RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
| RInt64 _ -> pr " int64_t r;\n"; "-1"
| RConstString _ -> pr " const char *r;\n"; "NULL"
| RString _ -> pr " char *r;\n"; "NULL"
| RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
| RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
| RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
| RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
| RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
| RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
| RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
pr "\n";
pr " r = guestfs_%s " name;
generate_call_args ~handle:"g" style;
pr ";\n";
List.iter (
function
| String _ | OptString _ | Bool _ | Int _ -> ()
| StringList n ->
pr " free (%s);\n" n
) (snd style);
pr " if (r == %s)\n" error_code;
pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
pr "\n";
(match fst style with
| RErr ->
pr " return Qnil;\n"
| RInt _ | RBool _ ->
pr " return INT2NUM (r);\n"
| RInt64 _ ->
pr " return ULL2NUM (r);\n"
| RConstString _ ->
pr " return rb_str_new2 (r);\n";
| RString _ ->
pr " VALUE rv = rb_str_new2 (r);\n";
pr " free (r);\n";
pr " return rv;\n";
| RStringList _ ->
pr " int i, len = 0;\n";
pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
pr " VALUE rv = rb_ary_new2 (len);\n";
pr " for (i = 0; r[i] != NULL; ++i) {\n";
pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
pr " free (r[i]);\n";
pr " }\n";
pr " free (r);\n";
pr " return rv;\n"
| RIntBool _ ->
pr " VALUE rv = rb_ary_new2 (2);\n";
pr " rb_ary_push (rv, INT2NUM (r->i));\n";
pr " rb_ary_push (rv, INT2NUM (r->b));\n";
pr " guestfs_free_int_bool (r);\n";
pr " return rv;\n"
| RPVList n ->
generate_ruby_lvm_code "pv" pv_cols
| RVGList n ->
generate_ruby_lvm_code "vg" vg_cols
| RLVList n ->
generate_ruby_lvm_code "lv" lv_cols
| RStat n ->
pr " VALUE rv = rb_hash_new ();\n";
List.iter (
function
| name, `Int ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
) stat_cols;
pr " free (r);\n";
pr " return rv;\n"
| RStatVFS n ->
pr " VALUE rv = rb_hash_new ();\n";
List.iter (
function
| name, `Int ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
) statvfs_cols;
pr " free (r);\n";
pr " return rv;\n"
| RHashtable _ ->
pr " VALUE rv = rb_hash_new ();\n";
pr " int i;\n";
pr " for (i = 0; r[i] != NULL; i+=2) {\n";
pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
pr " free (r[i]);\n";
pr " free (r[i+1]);\n";
pr " }\n";
pr " free (r);\n";
pr " return rv;\n"
);
pr "}\n";
pr "\n"
) all_functions;
pr "\
/* Initialize the module. */
void Init__guestfs ()
{
m_guestfs = rb_define_module (\"Guestfs\");
c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
";
(* Define the rest of the methods. *)
List.iter (
fun (name, style, _, _, _, _, _) ->
pr " rb_define_method (c_guestfs, \"%s\",\n" name;
pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
) all_functions;
pr "}\n"
(* Ruby code to return an LVM struct list. *)
and generate_ruby_lvm_code typ cols =
pr " VALUE rv = rb_ary_new2 (r->len);\n";
pr " int i;\n";
pr " for (i = 0; i < r->len; ++i) {\n";
pr " VALUE hv = rb_hash_new ();\n";
List.iter (
function
| name, `String ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
| name, `UUID ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
| name, `Bytes
| name, `Int ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
| name, `OptPercent ->
pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
) cols;
pr " rb_ary_push (rv, hv);\n";
pr " }\n";
pr " guestfs_free_lvm_%s_list (r);\n" typ;
pr " return rv;\n"
let output_to filename =
let filename_new = filename ^ ".new" in
chan := open_out filename_new;
@@ -4962,3 +5198,7 @@ Run it from the top source directory using the command
let close = output_to "python/guestfs.py" in
generate_python_py ();
close ();
let close = output_to "ruby/ext/guestfs/_guestfs.c" in
generate_ruby_c ();
close ();