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