regressions: Enable both tests for bug 576879 (not fixed).
[libguestfs.git] / generator / generator_python.ml
1 (* libguestfs
2  * Copyright (C) 2009-2010 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *)
18
19 (* Please read generator/README first. *)
20
21 open Printf
22
23 open Generator_types
24 open Generator_utils
25 open Generator_pr
26 open Generator_docstrings
27 open Generator_optgroups
28 open Generator_actions
29 open Generator_structs
30 open Generator_c
31
32 (* Generate Python C module. *)
33 let rec generate_python_c () =
34   generate_header CStyle LGPLv2plus;
35
36   pr "\
37 #define PY_SSIZE_T_CLEAN 1
38 #include <Python.h>
39
40 #if PY_VERSION_HEX < 0x02050000
41 typedef int Py_ssize_t;
42 #define PY_SSIZE_T_MAX INT_MAX
43 #define PY_SSIZE_T_MIN INT_MIN
44 #endif
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <assert.h>
49
50 #include \"guestfs.h\"
51
52 #ifndef HAVE_PYCAPSULE_NEW
53 typedef struct {
54   PyObject_HEAD
55   guestfs_h *g;
56 } Pyguestfs_Object;
57 #endif
58
59 static guestfs_h *
60 get_handle (PyObject *obj)
61 {
62   assert (obj);
63   assert (obj != Py_None);
64 #ifndef HAVE_PYCAPSULE_NEW
65   return ((Pyguestfs_Object *) obj)->g;
66 #else
67   return (guestfs_h*) PyCapsule_GetPointer(obj, \"guestfs_h\");
68 #endif
69 }
70
71 static PyObject *
72 put_handle (guestfs_h *g)
73 {
74   assert (g);
75 #ifndef HAVE_PYCAPSULE_NEW
76   return
77     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
78 #else
79   return PyCapsule_New ((void *) g, \"guestfs_h\", NULL);
80 #endif
81 }
82
83 /* This list should be freed (but not the strings) after use. */
84 static char **
85 get_string_list (PyObject *obj)
86 {
87   size_t i, len;
88   char **r;
89
90   assert (obj);
91
92   if (!PyList_Check (obj)) {
93     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
94     return NULL;
95   }
96
97   Py_ssize_t slen = PyList_Size (obj);
98   if (slen == -1) {
99     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: PyList_Size failure\");
100     return NULL;
101   }
102   len = (size_t) slen;
103   r = malloc (sizeof (char *) * (len+1));
104   if (r == NULL) {
105     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
106     return NULL;
107   }
108
109   for (i = 0; i < len; ++i)
110     r[i] = PyString_AsString (PyList_GetItem (obj, i));
111   r[len] = NULL;
112
113   return r;
114 }
115
116 static PyObject *
117 put_string_list (char * const * const argv)
118 {
119   PyObject *list;
120   int argc, i;
121
122   for (argc = 0; argv[argc] != NULL; ++argc)
123     ;
124
125   list = PyList_New (argc);
126   for (i = 0; i < argc; ++i)
127     PyList_SetItem (list, i, PyString_FromString (argv[i]));
128
129   return list;
130 }
131
132 static PyObject *
133 put_table (char * const * const argv)
134 {
135   PyObject *list, *item;
136   int argc, i;
137
138   for (argc = 0; argv[argc] != NULL; ++argc)
139     ;
140
141   list = PyList_New (argc >> 1);
142   for (i = 0; i < argc; i += 2) {
143     item = PyTuple_New (2);
144     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
145     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
146     PyList_SetItem (list, i >> 1, item);
147   }
148
149   return list;
150 }
151
152 static void
153 free_strings (char **argv)
154 {
155   int argc;
156
157   for (argc = 0; argv[argc] != NULL; ++argc)
158     free (argv[argc]);
159   free (argv);
160 }
161
162 static PyObject *
163 py_guestfs_create (PyObject *self, PyObject *args)
164 {
165   guestfs_h *g;
166
167   g = guestfs_create ();
168   if (g == NULL) {
169     PyErr_SetString (PyExc_RuntimeError,
170                      \"guestfs.create: failed to allocate handle\");
171     return NULL;
172   }
173   guestfs_set_error_handler (g, NULL, NULL);
174   /* This can return NULL, but in that case put_handle will have
175    * set the Python error string.
176    */
177   return put_handle (g);
178 }
179
180 static PyObject *
181 py_guestfs_close (PyObject *self, PyObject *args)
182 {
183   PyObject *py_g;
184   guestfs_h *g;
185
186   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
187     return NULL;
188   g = get_handle (py_g);
189
190   guestfs_close (g);
191
192   Py_INCREF (Py_None);
193   return Py_None;
194 }
195
196 ";
197
198   let emit_put_list_function typ =
199     pr "static PyObject *\n";
200     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
201     pr "{\n";
202     pr "  PyObject *list;\n";
203     pr "  size_t i;\n";
204     pr "\n";
205     pr "  list = PyList_New (%ss->len);\n" typ;
206     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
207     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
208     pr "  return list;\n";
209     pr "};\n";
210     pr "\n"
211   in
212
213   (* Structures, turned into Python dictionaries. *)
214   List.iter (
215     fun (typ, cols) ->
216       pr "static PyObject *\n";
217       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
218       pr "{\n";
219       pr "  PyObject *dict;\n";
220       pr "\n";
221       pr "  dict = PyDict_New ();\n";
222       List.iter (
223         function
224         | name, FString ->
225             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
226             pr "                        PyString_FromString (%s->%s));\n"
227               typ name
228         | name, FBuffer ->
229             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
230             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
231               typ name typ name
232         | name, FUUID ->
233             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
234             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
235               typ name
236         | name, (FBytes|FUInt64) ->
237             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
238             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
239               typ name
240         | name, FInt64 ->
241             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
242             pr "                        PyLong_FromLongLong (%s->%s));\n"
243               typ name
244         | name, FUInt32 ->
245             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
246             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
247               typ name
248         | name, FInt32 ->
249             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
250             pr "                        PyLong_FromLong (%s->%s));\n"
251               typ name
252         | name, FOptPercent ->
253             pr "  if (%s->%s >= 0)\n" typ name;
254             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
255             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
256               typ name;
257             pr "  else {\n";
258             pr "    Py_INCREF (Py_None);\n";
259             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
260             pr "  }\n"
261         | name, FChar ->
262             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
263             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
264       ) cols;
265       pr "  return dict;\n";
266       pr "};\n";
267       pr "\n";
268
269   ) structs;
270
271   (* Emit a put_TYPE_list function definition only if that function is used. *)
272   List.iter (
273     function
274     | typ, (RStructListOnly | RStructAndList) ->
275         (* generate the function for typ *)
276         emit_put_list_function typ
277     | typ, _ -> () (* empty *)
278   ) (rstructs_used_by all_functions);
279
280   (* Python wrapper functions. *)
281   List.iter (
282     fun (name, (ret, args, optargs as style), _, _, _, _, _) ->
283       pr "static PyObject *\n";
284       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
285       pr "{\n";
286
287       pr "  PyObject *py_g;\n";
288       pr "  guestfs_h *g;\n";
289       pr "  PyObject *py_r;\n";
290
291       if optargs <> [] then (
292         pr "  struct guestfs_%s_argv optargs_s;\n" name;
293         pr "  struct guestfs_%s_argv *optargs = &optargs_s;\n" name;
294       );
295
296       (match ret with
297        | RErr | RInt _ | RBool _ -> pr "  int r;\n"
298        | RInt64 _ -> pr "  int64_t r;\n"
299        | RConstString _ | RConstOptString _ ->
300            pr "  const char *r;\n"
301        | RString _ -> pr "  char *r;\n"
302        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
303        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
304        | RStructList (_, typ) ->
305            pr "  struct guestfs_%s_list *r;\n" typ
306        | RBufferOut _ ->
307            pr "  char *r;\n";
308            pr "  size_t size;\n"
309       );
310
311       List.iter (
312         function
313         | Pathname n | Device n | Dev_or_Path n | String n | Key n
314         | FileIn n | FileOut n ->
315             pr "  const char *%s;\n" n
316         | OptString n -> pr "  const char *%s;\n" n
317         | BufferIn n ->
318             pr "  const char *%s;\n" n;
319             pr "  Py_ssize_t %s_size;\n" n
320         | StringList n | DeviceList n ->
321             pr "  PyObject *py_%s;\n" n;
322             pr "  char **%s;\n" n
323         | Bool n -> pr "  int %s;\n" n
324         | Int n -> pr "  int %s;\n" n
325         | Int64 n -> pr "  long long %s;\n" n
326         | Pointer (t, n) ->
327             pr "  long long %s_int64;\n" n;
328             pr "  %s %s;\n" t n
329       ) args;
330
331       if optargs <> [] then (
332         (* XXX This is horrible.  We have to use sentinel values on the
333          * Python side to denote values not set.
334          *)
335         (* Since we don't know if Python types will exactly match
336          * structure types, declare some local variables here.
337          *)
338         List.iter (
339           function
340           | Bool n
341           | Int n -> pr "  int optargs_t_%s = -1;\n" n
342           | Int64 n -> pr "  long long optargs_t_%s = -1;\n" n
343           | String n -> pr "  const char *optargs_t_%s = NULL;\n" n
344           | _ -> assert false
345         ) optargs
346       );
347
348       pr "\n";
349
350       if optargs <> [] then (
351         pr "  optargs_s.bitmask = 0;\n";
352         pr "\n"
353       );
354
355       (* Convert the required parameters. *)
356       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
357       List.iter (
358         function
359         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
360         | FileIn _ | FileOut _ -> pr "s"
361         | OptString _ -> pr "z"
362         | StringList _ | DeviceList _ -> pr "O"
363         | Bool _ -> pr "i" (* XXX Python has booleans? *)
364         | Int _ -> pr "i"
365         | Int64 _ | Pointer _ ->
366             (* XXX Whoever thought it was a good idea to
367              * emulate C's int/long/long long in Python?
368              *)
369             pr "L"
370         | BufferIn _ -> pr "s#"
371       ) args;
372
373       (* Optional parameters. *)
374       if optargs <> [] then (
375         List.iter (
376           function
377           | Bool _ | Int _ -> pr "i"
378           | Int64 _ -> pr "L"
379           | String _ -> pr "z" (* because we use None to mean not set *)
380           | _ -> assert false
381         ) optargs;
382       );
383
384       pr ":guestfs_%s\",\n" name;
385       pr "                         &py_g";
386       List.iter (
387         function
388         | Pathname n | Device n | Dev_or_Path n | String n | Key n
389         | FileIn n | FileOut n -> pr ", &%s" n
390         | OptString n -> pr ", &%s" n
391         | StringList n | DeviceList n -> pr ", &py_%s" n
392         | Bool n -> pr ", &%s" n
393         | Int n -> pr ", &%s" n
394         | Int64 n -> pr ", &%s" n
395         | Pointer (_, n) -> pr ", &%s_int64" n
396         | BufferIn n -> pr ", &%s, &%s_size" n n
397       ) args;
398
399       List.iter (
400         function
401         | Bool n | Int n | Int64 n | String n -> pr ", &optargs_t_%s" n
402         | _ -> assert false
403       ) optargs;
404
405       pr "))\n";
406       pr "    return NULL;\n";
407
408       pr "  g = get_handle (py_g);\n";
409       List.iter (
410         function
411         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
412         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
413         | BufferIn _ -> ()
414         | StringList n | DeviceList n ->
415             pr "  %s = get_string_list (py_%s);\n" n n;
416             pr "  if (!%s) return NULL;\n" n
417         | Pointer (t, n) ->
418             pr "  %s = (%s) (intptr_t) %s_int64;\n" n t n
419       ) args;
420
421       pr "\n";
422
423       if optargs <> [] then (
424         let uc_name = String.uppercase name in
425         List.iter (
426           fun argt ->
427             let n = name_of_argt argt in
428             let uc_n = String.uppercase n in
429             pr "  if (optargs_t_%s != " n;
430             (match argt with
431              | Bool _ | Int _ | Int64 _ -> pr "-1"
432              | String _ -> pr "NULL"
433              | _ -> assert false
434             );
435             pr ") {\n";
436             pr "    optargs_s.%s = optargs_t_%s;\n" n n;
437             pr "    optargs_s.bitmask |= GUESTFS_%s_%s_BITMASK;\n" uc_name uc_n;
438             pr "  }\n"
439         ) optargs;
440         pr "\n"
441       );
442
443       if optargs = [] then
444         pr "  r = guestfs_%s " name
445       else
446         pr "  r = guestfs_%s_argv " name;
447       generate_c_call_args ~handle:"g" style;
448       pr ";\n";
449
450       List.iter (
451         function
452         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
453         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
454         | BufferIn _ | Pointer _ -> ()
455         | StringList n | DeviceList n ->
456             pr "  free (%s);\n" n
457       ) args;
458
459       (match errcode_of_ret ret with
460        | `CannotReturnError -> ()
461        | `ErrorIsMinusOne ->
462            pr "  if (r == -1) {\n";
463            pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
464            pr "    return NULL;\n";
465            pr "  }\n"
466        | `ErrorIsNULL ->
467            pr "  if (r == NULL) {\n";
468            pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
469            pr "    return NULL;\n";
470            pr "  }\n"
471       );
472       pr "\n";
473
474       (match ret with
475        | RErr ->
476            pr "  Py_INCREF (Py_None);\n";
477            pr "  py_r = Py_None;\n"
478        | RInt _
479        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
480        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
481        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
482        | RConstOptString _ ->
483            pr "  if (r)\n";
484            pr "    py_r = PyString_FromString (r);\n";
485            pr "  else {\n";
486            pr "    Py_INCREF (Py_None);\n";
487            pr "    py_r = Py_None;\n";
488            pr "  }\n"
489        | RString _ ->
490            pr "  py_r = PyString_FromString (r);\n";
491            pr "  free (r);\n"
492        | RStringList _ ->
493            pr "  py_r = put_string_list (r);\n";
494            pr "  free_strings (r);\n"
495        | RStruct (_, typ) ->
496            pr "  py_r = put_%s (r);\n" typ;
497            pr "  guestfs_free_%s (r);\n" typ
498        | RStructList (_, typ) ->
499            pr "  py_r = put_%s_list (r);\n" typ;
500            pr "  guestfs_free_%s_list (r);\n" typ
501        | RHashtable n ->
502            pr "  py_r = put_table (r);\n";
503            pr "  free_strings (r);\n"
504        | RBufferOut _ ->
505            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
506            pr "  free (r);\n"
507       );
508
509       pr "  return py_r;\n";
510       pr "}\n";
511       pr "\n"
512   ) all_functions;
513
514   (* Table of functions. *)
515   pr "static PyMethodDef methods[] = {\n";
516   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
517   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
518   List.iter (
519     fun (name, _, _, _, _, _, _) ->
520       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
521         name name
522   ) all_functions;
523   pr "  { NULL, NULL, 0, NULL }\n";
524   pr "};\n";
525   pr "\n";
526
527   (* Init function. *)
528   pr "\
529 void
530 initlibguestfsmod (void)
531 {
532   static int initialized = 0;
533
534   if (initialized) return;
535   Py_InitModule ((char *) \"libguestfsmod\", methods);
536   initialized = 1;
537 }
538 "
539
540 (* Generate Python module. *)
541 and generate_python_py () =
542   generate_header HashStyle LGPLv2plus;
543
544   pr "\
545 u\"\"\"Python bindings for libguestfs
546
547 import guestfs
548 g = guestfs.GuestFS ()
549 g.add_drive_opts (\"guest.img\", format=\"raw\")
550 g.launch ()
551 parts = g.list_partitions ()
552
553 The guestfs module provides a Python binding to the libguestfs API
554 for examining and modifying virtual machine disk images.
555
556 Amongst the things this is good for: making batch configuration
557 changes to guests, getting disk used/free statistics (see also:
558 virt-df), migrating between virtualization systems (see also:
559 virt-p2v), performing partial backups, performing partial guest
560 clones, cloning guests and changing registry/UUID/hostname info, and
561 much else besides.
562
563 Libguestfs uses Linux kernel and qemu code, and can access any type of
564 guest filesystem that Linux and qemu can, including but not limited
565 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
566 schemes, qcow, qcow2, vmdk.
567
568 Libguestfs provides ways to enumerate guest storage (eg. partitions,
569 LVs, what filesystem is in each LV, etc.).  It can also run commands
570 in the context of the guest.  Also you can access filesystems over
571 FUSE.
572
573 Errors which happen while using the API are turned into Python
574 RuntimeError exceptions.
575
576 To create a guestfs handle you usually have to perform the following
577 sequence of calls:
578
579 # Create the handle, call add_drive* at least once, and possibly
580 # several times if the guest has multiple block devices:
581 g = guestfs.GuestFS ()
582 g.add_drive_opts (\"guest.img\", format=\"raw\")
583
584 # Launch the qemu subprocess and wait for it to become ready:
585 g.launch ()
586
587 # Now you can issue commands, for example:
588 logvols = g.lvs ()
589
590 \"\"\"
591
592 import libguestfsmod
593
594 class GuestFS:
595     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
596
597     def __init__ (self):
598         \"\"\"Create a new libguestfs handle.\"\"\"
599         self._o = libguestfsmod.create ()
600
601     def __del__ (self):
602         libguestfsmod.close (self._o)
603
604 ";
605
606   List.iter (
607     fun (name, (ret, args, optargs), _, flags, _, _, longdesc) ->
608       pr "    def %s (self" name;
609       List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
610       List.iter (
611         function
612         | Bool n | Int n | Int64 n -> pr ", %s=-1" n
613         | String n -> pr ", %s=None" n
614         | _ -> assert false
615       ) optargs;
616       pr "):\n";
617
618       if not (List.mem NotInDocs flags) then (
619         let doc = replace_str longdesc "C<guestfs_" "C<g." in
620         let doc =
621           match ret with
622           | RErr | RInt _ | RInt64 _ | RBool _
623           | RConstOptString _ | RConstString _
624           | RString _ | RBufferOut _ -> doc
625           | RStringList _ ->
626               doc ^ "\n\nThis function returns a list of strings."
627           | RStruct (_, typ) ->
628               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
629           | RStructList (_, typ) ->
630               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
631           | RHashtable _ ->
632               doc ^ "\n\nThis function returns a dictionary." in
633         let doc =
634           if List.mem ProtocolLimitWarning flags then
635             doc ^ "\n\n" ^ protocol_limit_warning
636           else doc in
637         let doc =
638           if List.mem DangerWillRobinson flags then
639             doc ^ "\n\n" ^ danger_will_robinson
640           else doc in
641         let doc =
642           match deprecation_notice flags with
643           | None -> doc
644           | Some txt -> doc ^ "\n\n" ^ txt in
645         let doc = pod2text ~width:60 name doc in
646         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
647         let doc = String.concat "\n        " doc in
648         pr "        u\"\"\"%s\"\"\"\n" doc;
649       );
650       pr "        return libguestfsmod.%s (self._o" name;
651       List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (args@optargs);
652       pr ")\n\n";
653   ) all_functions