libvirt/python/generator.py

1403 lines
51 KiB
Python
Raw Normal View History

#!/usr/bin/python -u
#
# generate python wrappers from the XML API description
#
functions = {}
enums = {} # { enumType: { enumConstant: enumValue } }
import os
import sys
import string
import re
if __name__ == "__main__":
# launched as a script
srcPref = os.path.dirname(sys.argv[0])
else:
# imported
srcPref = os.path.dirname(__file__)
#######################################################################
#
# That part if purely the API acquisition phase from the
# libvirt API description
#
#######################################################################
import os
import xml.sax
debug = 0
def getparser():
# Attach parser to an unmarshalling object. return both objects.
target = docParser()
parser = xml.sax.make_parser()
parser.setContentHandler(target)
return parser, target
class docParser(xml.sax.handler.ContentHandler):
def __init__(self):
self._methodname = None
self._data = []
self.in_function = 0
self.startElement = self.start
self.endElement = self.end
self.characters = self.data
def close(self):
if debug:
print "close"
def getmethodname(self):
return self._methodname
def data(self, text):
if debug:
print "data %s" % text
self._data.append(text)
def cdata(self, text):
if debug:
print "data %s" % text
self._data.append(text)
def start(self, tag, attrs):
if debug:
print "start %s, %s" % (tag, attrs)
if tag == 'function':
self._data = []
self.in_function = 1
self.function = None
self.function_cond = None
self.function_args = []
self.function_descr = None
self.function_return = None
self.function_file = None
if attrs.has_key('name'):
self.function = attrs['name']
if attrs.has_key('file'):
self.function_file = attrs['file']
elif tag == 'cond':
self._data = []
elif tag == 'info':
self._data = []
elif tag == 'arg':
if self.in_function == 1:
self.function_arg_name = None
self.function_arg_type = None
self.function_arg_info = None
if attrs.has_key('name'):
self.function_arg_name = attrs['name']
if self.function_arg_name == 'from':
self.function_arg_name = 'frm'
if attrs.has_key('type'):
self.function_arg_type = attrs['type']
if attrs.has_key('info'):
self.function_arg_info = attrs['info']
elif tag == 'return':
if self.in_function == 1:
self.function_return_type = None
self.function_return_info = None
self.function_return_field = None
if attrs.has_key('type'):
self.function_return_type = attrs['type']
if attrs.has_key('info'):
self.function_return_info = attrs['info']
if attrs.has_key('field'):
self.function_return_field = attrs['field']
elif tag == 'enum':
enum(attrs['type'],attrs['name'],attrs['value'])
def end(self, tag):
if debug:
print "end %s" % tag
if tag == 'function':
if self.function != None:
function(self.function, self.function_descr,
self.function_return, self.function_args,
self.function_file, self.function_cond)
self.in_function = 0
elif tag == 'arg':
if self.in_function == 1:
self.function_args.append([self.function_arg_name,
self.function_arg_type,
self.function_arg_info])
elif tag == 'return':
if self.in_function == 1:
self.function_return = [self.function_return_type,
self.function_return_info,
self.function_return_field]
elif tag == 'info':
str = ''
for c in self._data:
str = str + c
if self.in_function == 1:
self.function_descr = str
elif tag == 'cond':
str = ''
for c in self._data:
str = str + c
if self.in_function == 1:
self.function_cond = str
def function(name, desc, ret, args, file, cond):
functions[name] = (desc, ret, args, file, cond)
def enum(type, name, value):
if not enums.has_key(type):
enums[type] = {}
enums[type][name] = value
#######################################################################
#
# Some filtering rukes to drop functions/types which should not
# be exposed as-is on the Python interface
#
#######################################################################
functions_failed = []
functions_skipped = [
"virConnectListDomains",
]
skipped_modules = {
}
skipped_types = {
# 'int *': "usually a return type",
'virConnectDomainEventCallback': "No function types in python",
Introduce a new public API for domain events The current API for domain events has a number of problems - Only allows for domain lifecycle change events - Does not allow the same callback to be registered multiple times - Does not allow filtering of events to a specific domain This introduces a new more general purpose domain events API typedef enum { VIR_DOMAIN_EVENT_ID_LIFECYCLE = 0, /* virConnectDomainEventCallback */ ...more events later.. } int virConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, /* Optional, to filter */ int eventID, virConnectDomainEventGenericCallback cb, void *opaque, virFreeCallback freecb); int virConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID); Since different event types can received different data in the callback, the API is defined with a generic callback. Specific events will each have a custom signature for their callback. Thus when registering an event it is neccessary to cast the callback to the generic signature eg int myDomainEventCallback(virConnectPtr conn, virDomainPtr dom, int event, int detail, void *opaque) { ... } virConnectDomainEventRegisterAny(conn, NULL, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback) NULL, NULL); The VIR_DOMAIN_EVENT_CALLBACK() macro simply does a "bad" cast to the generic signature * include/libvirt/libvirt.h.in: Define new APIs for registering domain events * src/driver.h: Internal driver entry points for new events APIs * src/libvirt.c: Wire up public API to driver API for events APIs * src/libvirt_public.syms: Export new APIs * src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_driver.c, src/phyp/phyp_driver.c, src/qemu/qemu_driver.c, src/remote/remote_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c, src/xen/xen_driver.c, src/xenapi/xenapi_driver.c: Stub out new API entries
2010-03-18 13:01:48 +00:00
'virConnectDomainEventGenericCallback': "No function types in python",
'virConnectDomainEventRTCChangeCallback': "No function types in python",
'virConnectDomainEventWatchdogCallback': "No function types in python",
Add support for an explicit IO error event This introduces a new event type VIR_DOMAIN_EVENT_ID_IO_ERROR This event includes the action that is about to be taken as a result of the watchdog triggering typedef enum { VIR_DOMAIN_EVENT_IO_ERROR_NONE = 0, VIR_DOMAIN_EVENT_IO_ERROR_PAUSE, VIR_DOMAIN_EVENT_IO_ERROR_REPORT, } virDomainEventIOErrorAction; In addition it has the source path of the disk that had the error and its unique device alias. It does not include the target device name (/dev/sda), since this would preclude triggering IO errors from other file backed devices (eg serial ports connected to a file) Thus there is a new callback definition for this event type typedef void (*virConnectDomainEventIOErrorCallback)(virConnectPtr conn, virDomainPtr dom, const char *srcPath, const char *devAlias, int action, void *opaque); This is currently wired up to the QEMU block IO error events * daemon/remote.c: Dispatch IO error events to client * examples/domain-events/events-c/event-test.c: Watch for IO error events * include/libvirt/libvirt.h.in: Define new IO error event ID and callback signature * src/conf/domain_event.c, src/conf/domain_event.h, src/libvirt_private.syms: Extend API to handle IO error events * src/qemu/qemu_driver.c: Connect to the QEMU monitor event for block IO errors and emit a libvirt IO error event * src/remote/remote_driver.c: Receive and dispatch IO error events to application * src/remote/remote_protocol.x: Wire protocol definition for IO error events * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h, src/qemu/qemu_monitor_json.c: Watch for BLOCK_IO_ERROR event from QEMU monitor
2010-03-18 19:37:44 +00:00
'virConnectDomainEventIOErrorCallback': "No function types in python",
Add domain events for graphics network clients This introduces a new event type VIR_DOMAIN_EVENT_ID_GRAPHICS The same event can be emitted in 3 scenarios typedef enum { VIR_DOMAIN_EVENT_GRAPHICS_CONNECT = 0, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT, } virDomainEventGraphicsPhase; Connect/disconnect are triggered at socket accept/close. The initialize phase is immediately after the protocol setup and authentication has completed. ie when the client is authorized and about to start interacting with the graphical desktop This event comes with *a lot* of potential information - IP address, port & address family of client - IP address, port & address family of server - Authentication scheme (arbitrary string) - Authenticated subject identity. A subject may have multiple identities with some authentication schemes. For example, vencrypt+sasl results in a x509dname and saslUsername identities. This results in a very complicated callback :-( typedef enum { VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV4, VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_IPV6, } virDomainEventGraphicsAddressType; struct _virDomainEventGraphicsAddress { int family; const char *node; const char *service; }; typedef struct _virDomainEventGraphicsAddress virDomainEventGraphicsAddress; typedef virDomainEventGraphicsAddress *virDomainEventGraphicsAddressPtr; struct _virDomainEventGraphicsSubject { int nidentity; struct { const char *type; const char *name; } *identities; }; typedef struct _virDomainEventGraphicsSubject virDomainEventGraphicsSubject; typedef virDomainEventGraphicsSubject *virDomainEventGraphicsSubjectPtr; typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn, virDomainPtr dom, int phase, virDomainEventGraphicsAddressPtr local, virDomainEventGraphicsAddressPtr remote, const char *authScheme, virDomainEventGraphicsSubjectPtr subject, void *opaque); The wire protocol is similarly complex struct remote_domain_event_graphics_address { int family; remote_nonnull_string node; remote_nonnull_string service; }; const REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX = 20; struct remote_domain_event_graphics_identity { remote_nonnull_string type; remote_nonnull_string name; }; struct remote_domain_event_graphics_msg { remote_nonnull_domain dom; int phase; remote_domain_event_graphics_address local; remote_domain_event_graphics_address remote; remote_nonnull_string authScheme; remote_domain_event_graphics_identity subject<REMOTE_DOMAIN_EVENT_GRAPHICS_IDENTITY_MAX>; }; This is currently implemented in QEMU for the VNC graphics protocol, but designed to be usable with SPICE graphics in the future too. * daemon/remote.c: Dispatch graphics events to client * examples/domain-events/events-c/event-test.c: Watch for graphics events * include/libvirt/libvirt.h.in: Define new graphics event ID and callback signature * src/conf/domain_event.c, src/conf/domain_event.h, src/libvirt_private.syms: Extend API to handle graphics events * src/qemu/qemu_driver.c: Connect to the QEMU monitor event for VNC events and emit a libvirt graphics event * src/remote/remote_driver.c: Receive and dispatch graphics events to application * src/remote/remote_protocol.x: Wire protocol definition for graphics events * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h, src/qemu/qemu_monitor_json.c: Watch for VNC_CONNECTED, VNC_INITIALIZED & VNC_DISCONNETED events from QEMU monitor
2010-03-19 13:27:45 +00:00
'virConnectDomainEventGraphicsCallback': "No function types in python",
'virEventAddHandleFunc': "No function types in python",
'virNWFilterPtr': "No function types in python",
}
#######################################################################
#
# Table of remapping to/from the python type or class to the C
# counterpart.
#
#######################################################################
py_types = {
'void': (None, None, None, None),
'int': ('i', None, "int", "int"),
'long': ('l', None, "long", "long"),
'double': ('d', None, "double", "double"),
'unsigned int': ('i', None, "int", "int"),
'unsigned long': ('l', None, "long", "long"),
'unsigned long long': ('l', None, "longlong", "long long"),
'unsigned char *': ('z', None, "charPtr", "char *"),
'char *': ('z', None, "charPtr", "char *"),
'const char *': ('z', None, "charPtrConst", "const char *"),
2008-02-20 15:26:22 +00:00
'virDomainPtr': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
'const virDomainPtr': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
'virDomain *': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
'const virDomain *': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
2008-02-20 15:26:22 +00:00
'virNetworkPtr': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
'const virNetworkPtr': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
'virNetwork *': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
'const virNetwork *': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
2008-02-20 15:26:22 +00:00
'virInterfacePtr': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
'const virInterfacePtr': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
'virInterface *': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
'const virInterface *': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
2008-02-20 15:26:22 +00:00
'virStoragePoolPtr': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
'const virStoragePoolPtr': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
'virStoragePool *': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
'const virStoragePool *': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
'virStorageVolPtr': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
'const virStorageVolPtr': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
'virStorageVol *': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
'const virStorageVol *': ('O', "virStorageVol", "virStorageVolPtr", "virStorageVolPtr"),
'virConnectPtr': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
'const virConnectPtr': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
'virConnect *': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
'const virConnect *': ('O', "virConnect", "virConnectPtr", "virConnectPtr"),
'virNodeDevicePtr': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
'const virNodeDevicePtr': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
'virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
'const virNodeDevice *': ('O', "virNodeDevice", "virNodeDevicePtr", "virNodeDevicePtr"),
'virSecretPtr': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
'const virSecretPtr': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
'virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
'const virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
'virStreamPtr': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
'const virStreamPtr': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
'virStream *': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
'const virStream *': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
'virDomainSnapshotPtr': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
'const virDomainSnapshotPtr': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
'virDomainSnapshot *': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
'const virDomainSnapshot *': ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
}
py_return_types = {
}
unknown_types = {}
foreign_encoding_args = (
)
#######################################################################
#
# This part writes the C <-> Python stubs libvirt.[ch] and
# the table libvirt-export.c to add when registrering the Python module
#
#######################################################################
# Class methods which are written by hand in libvir.c but the Python-level
# code is still automatically generated (so they are not in skip_function()).
skip_impl = (
'virConnectGetVersion',
'virConnectGetLibVersion',
'virConnectListDomainsID',
'virConnectListDefinedDomains',
'virConnectListNetworks',
'virConnectListDefinedNetworks',
'virConnectListSecrets',
'virConnectListInterfaces',
2008-02-20 15:26:22 +00:00
'virConnectListStoragePools',
'virConnectListDefinedStoragePools',
'virConnectListStorageVols',
'virConnectListDefinedStorageVols',
'virConnectListDefinedInterfaces',
'virConnectListNWFilters',
'virDomainSnapshotListNames',
'virConnGetLastError',
'virGetLastError',
'virDomainGetInfo',
'virDomainGetJobInfo',
'virNodeGetInfo',
'virDomainGetUUID',
'virDomainGetUUIDString',
'virDomainLookupByUUID',
'virNetworkGetUUID',
'virNetworkGetUUIDString',
'virNetworkLookupByUUID',
'virDomainGetAutostart',
'virNetworkGetAutostart',
'virDomainBlockStats',
'virDomainInterfaceStats',
'virDomainMemoryStats',
'virNodeGetCellsFreeMemory',
'virDomainGetSchedulerType',
'virDomainGetSchedulerParameters',
'virDomainSetSchedulerParameters',
'virDomainGetVcpus',
'virDomainPinVcpu',
'virSecretGetValue',
'virSecretSetValue',
Fix UUID handling in secrets/storage encryption APIs Convert all the secret/storage encryption APIs / wire format to handle UUIDs in raw format instead of non-canonical printable format. Guarentees data format correctness. * docs/schemas/storageencryption.rng: Make UUID mandatory for a secret and validate fully * docs/schemas/secret.rng: Fully validate UUID * include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, Add virSecretLookupByUUID and virSecretGetUUID. Make virSecretGetUUIDString follow normal API design pattern * python/generator.py: Skip generation of virSecretGetUUID, virSecretGetUUIDString and virSecretLookupByUUID * python/libvir.c, python/libvirt-python-api.xml: Manual impl of virSecretGetUUID,virSecretGetUUIDString and virSecretLookupByUUID * qemud/remote.c: s/virSecretLookupByUUIDString/virSecretLookupByUUID/ Fix get_nonnull_secret/make_nonnull_secret to use unsigned char * qemud/remote_protocol.x: Fix remote_nonnull_secret to use a remote_uuid instead of remote_nonnull_string for UUID field. Rename REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING to REMOTE_PROC_SECRET_LOOKUP_BY_UUID_STRING and make it take an remote_uuid value * qemud/remote_dispatch_args.h, qemud/remote_dispatch_prototypes.h, qemud/remote_dispatch_ret.h, qemud/remote_dispatch_table.h, qemud/remote_protocol.c, qemud/remote_protocol.h: Re-generate * src/datatypes.h, src/datatypes.c: Store UUID in raw format instead of printable. Change virGetSecret to use raw format UUID * src/driver.h: Rename virDrvSecretLookupByUUIDString to virDrvSecretLookupByUUID and use raw format UUID * src/libvirt.c: Add virSecretLookupByUUID and virSecretGetUUID and re-implement virSecretLookupByUUIDString and virSecretGetUUIDString in terms of those * src/libvirt_public.syms: Add virSecretLookupByUUID and virSecretGetUUID * src/remote_internal.c: Rename remoteSecretLookupByUUIDString to remoteSecretLookupByUUID. Fix typo in args for remoteSecretDefineXML impl. Use raw UUID format for get_nonnull_secret and make_nonnull_secret * src/storage_encryption_conf.c, src/storage_encryption_conf.h: Storage UUID in raw format, and require it to be present in XML. Use UUID parser to validate. * secret_conf.h, secret_conf.c: Generate a UUID if none is provided. Storage UUID in raw format. * src/secret_driver.c: Adjust to deal with raw UUIDs. Save secrets in a filed with printable UUID, instead of base64 UUID. * src/virsh.c: Adjust for changed public API contract of virSecretGetUUIDString. * src/storage_Backend.c: DOn't undefine secret we just generated upon successful volume creation. Fix to handle raw UUIDs. Generate a non-clashing UUID * src/qemu_driver.c: Change to use lookupByUUID instead of lookupByUUIDString
2009-09-10 16:44:12 +00:00
'virSecretGetUUID',
'virSecretGetUUIDString',
'virSecretLookupByUUID',
'virStreamRecv',
'virStreamSend',
2008-02-20 15:26:22 +00:00
'virStoragePoolGetUUID',
'virStoragePoolGetUUIDString',
2008-02-20 15:26:22 +00:00
'virStoragePoolLookupByUUID',
'virStoragePoolGetInfo',
'virStorageVolGetInfo',
'virStoragePoolGetAutostart',
'virStoragePoolListVolumes',
'virDomainBlockPeek',
'virDomainMemoryPeek',
'virEventRegisterImpl',
'virNodeListDevices',
'virNodeDeviceListCaps',
2010-01-22 13:52:41 +00:00
'virConnectBaselineCPU',
'virDomainSnapshotListNames',
)
# These are functions which the generator skips completly - no python
# or C code is generated. Generally should not be used for any more
# functions than those already listed
skip_function = (
'virConnectListDomains', # Python API is called virConectListDomainsID for unknown reasons
'virConnSetErrorFunc', # Not used in Python API XXX is this a bug ?
'virResetError', # Not used in Python API XXX is this a bug ?
'virGetVersion', # Python C code is manually written
'virSetErrorFunc', # Python API is called virRegisterErrorHandler for unknown reasons
'virConnCopyLastError', # Python API is called virConnGetLastError instead
'virCopyLastError', # Python API is called virGetLastError instead
'virConnectOpenAuth', # Python C code is manually written
'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C
'virDomainGetSecurityLabel', # Needs investigation...
'virNodeGetSecurityModel', # Needs investigation...
'virConnectDomainEventRegister', # overridden in virConnect.py
'virConnectDomainEventDeregister', # overridden in virConnect.py
Introduce a new public API for domain events The current API for domain events has a number of problems - Only allows for domain lifecycle change events - Does not allow the same callback to be registered multiple times - Does not allow filtering of events to a specific domain This introduces a new more general purpose domain events API typedef enum { VIR_DOMAIN_EVENT_ID_LIFECYCLE = 0, /* virConnectDomainEventCallback */ ...more events later.. } int virConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, /* Optional, to filter */ int eventID, virConnectDomainEventGenericCallback cb, void *opaque, virFreeCallback freecb); int virConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID); Since different event types can received different data in the callback, the API is defined with a generic callback. Specific events will each have a custom signature for their callback. Thus when registering an event it is neccessary to cast the callback to the generic signature eg int myDomainEventCallback(virConnectPtr conn, virDomainPtr dom, int event, int detail, void *opaque) { ... } virConnectDomainEventRegisterAny(conn, NULL, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback) NULL, NULL); The VIR_DOMAIN_EVENT_CALLBACK() macro simply does a "bad" cast to the generic signature * include/libvirt/libvirt.h.in: Define new APIs for registering domain events * src/driver.h: Internal driver entry points for new events APIs * src/libvirt.c: Wire up public API to driver API for events APIs * src/libvirt_public.syms: Export new APIs * src/esx/esx_driver.c, src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_driver.c, src/phyp/phyp_driver.c, src/qemu/qemu_driver.c, src/remote/remote_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c, src/xen/xen_driver.c, src/xenapi/xenapi_driver.c: Stub out new API entries
2010-03-18 13:01:48 +00:00
'virConnectDomainEventRegisterAny', # overridden in virConnect.py
'virConnectDomainEventDeregisterAny', # overridden in virConnect.py
'virSaveLastError', # We have our own python error wrapper
'virFreeError', # Only needed if we use virSaveLastError
'virStreamEventAddCallback',
'virStreamRecvAll',
'virStreamSendAll',
'virStreamRef',
'virStreamFree',
# These have no use for bindings users.
"virConnectRef",
"virDomainRef",
"virInterfaceRef",
"virNetworkRef",
"virNodeDeviceRef",
"virSecretRef",
"virStoragePoolRef",
"virStorageVolRef",
# This functions shouldn't be called via the bindings (and even the docs
# contain an explicit warning to that effect). The equivalent should be
# implemented in pure python for each class
"virDomainGetConnect",
"virInterfaceGetConnect",
"virNetworkGetConnect",
"virSecretGetConnect",
"virStoragePoolGetConnect",
"virStorageVolGetConnect",
)
def print_function_wrapper(name, output, export, include):
global py_types
global unknown_types
global functions
global skipped_modules
try:
(desc, ret, args, file, cond) = functions[name]
except:
print "failed to get function %s infos"
return
if skipped_modules.has_key(file):
return 0
if name in skip_function:
return 0
if name in skip_impl:
# Don't delete the function entry in the caller.
return 1
c_call = "";
format=""
format_args=""
c_args=""
c_return=""
c_convert=""
num_bufs=0
for arg in args:
# This should be correct
if arg[1][0:6] == "const ":
arg[1] = arg[1][6:]
c_args = c_args + " %s %s;\n" % (arg[1], arg[0])
if py_types.has_key(arg[1]):
(f, t, n, c) = py_types[arg[1]]
if (f == 'z') and (name in foreign_encoding_args) and (num_bufs == 0):
f = 't#'
if f != None:
format = format + f
if t != None:
format_args = format_args + ", &pyobj_%s" % (arg[0])
c_args = c_args + " PyObject *pyobj_%s;\n" % (arg[0])
c_convert = c_convert + \
" %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0],
arg[1], t, arg[0]);
else:
format_args = format_args + ", &%s" % (arg[0])
if f == 't#':
format_args = format_args + ", &py_buffsize%d" % num_bufs
c_args = c_args + " int py_buffsize%d;\n" % num_bufs
num_bufs = num_bufs + 1
if c_call != "":
c_call = c_call + ", ";
c_call = c_call + "%s" % (arg[0])
else:
if skipped_types.has_key(arg[1]):
return 0
if unknown_types.has_key(arg[1]):
lst = unknown_types[arg[1]]
lst.append(name)
else:
unknown_types[arg[1]] = [name]
return -1
if format != "":
format = format + ":%s" % (name)
if ret[0] == 'void':
if file == "python_accessor":
if args[1][1] == "char *":
c_call = "\n free(%s->%s);\n" % (
args[0][0], args[1][0], args[0][0], args[1][0])
c_call = c_call + " %s->%s = (%s)strdup((const xmlChar *)%s);\n" % (args[0][0],
args[1][0], args[1][1], args[1][0])
else:
c_call = "\n %s->%s = %s;\n" % (args[0][0], args[1][0],
args[1][0])
else:
c_call = "\n %s(%s);\n" % (name, c_call);
ret_convert = " Py_INCREF(Py_None);\n return(Py_None);\n"
elif py_types.has_key(ret[0]):
(f, t, n, c) = py_types[ret[0]]
c_return = " %s c_retval;\n" % (ret[0])
if file == "python_accessor" and ret[2] != None:
c_call = "\n c_retval = %s->%s;\n" % (args[0][0], ret[2])
else:
c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
ret_convert = " py_retval = libvirt_%sWrap((%s) c_retval);\n" % (n,c)
ret_convert = ret_convert + " return(py_retval);\n"
elif py_return_types.has_key(ret[0]):
(f, t, n, c) = py_return_types[ret[0]]
c_return = " %s c_retval;\n" % (ret[0])
c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
ret_convert = " py_retval = libvirt_%sWrap((%s) c_retval);\n" % (n,c)
ret_convert = ret_convert + " return(py_retval);\n"
else:
if skipped_types.has_key(ret[0]):
return 0
if unknown_types.has_key(ret[0]):
lst = unknown_types[ret[0]]
lst.append(name)
else:
unknown_types[ret[0]] = [name]
return -1
if cond != None and cond != "":
include.write("#if %s\n" % cond)
export.write("#if %s\n" % cond)
output.write("#if %s\n" % cond)
include.write("PyObject * ")
include.write("libvirt_%s(PyObject *self, PyObject *args);\n" % (name));
export.write(" { (char *)\"%s\", libvirt_%s, METH_VARARGS, NULL },\n" %
(name, name))
if file == "python":
# Those have been manually generated
if cond != None and cond != "":
include.write("#endif\n");
export.write("#endif\n");
output.write("#endif\n");
return 1
if file == "python_accessor" and ret[0] != "void" and ret[2] is None:
# Those have been manually generated
if cond != None and cond != "":
include.write("#endif\n");
export.write("#endif\n");
output.write("#endif\n");
return 1
output.write("PyObject *\n")
output.write("libvirt_%s(PyObject *self ATTRIBUTE_UNUSED," % (name))
output.write(" PyObject *args")
if format == "":
output.write(" ATTRIBUTE_UNUSED")
output.write(") {\n")
if ret[0] != 'void':
output.write(" PyObject *py_retval;\n")
if c_return != "":
output.write(c_return)
if c_args != "":
output.write(c_args)
if format != "":
output.write("\n if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" %
(format, format_args))
output.write(" return(NULL);\n")
if c_convert != "":
output.write(c_convert)
output.write("LIBVIRT_BEGIN_ALLOW_THREADS;\n");
output.write(c_call);
output.write("LIBVIRT_END_ALLOW_THREADS;\n");
output.write(ret_convert)
output.write("}\n\n")
if cond != None and cond != "":
include.write("#endif /* %s */\n" % cond)
export.write("#endif /* %s */\n" % cond)
output.write("#endif /* %s */\n" % cond)
return 1
def buildStubs():
global py_types
global py_return_types
global unknown_types
try:
f = open(os.path.join(srcPref,"libvirt-api.xml"))
data = f.read()
(parser, target) = getparser()
parser.feed(data)
parser.close()
except IOError, msg:
try:
f = open(os.path.join(srcPref,"..","docs","libvirt-api.xml"))
data = f.read()
(parser, target) = getparser()
parser.feed(data)
parser.close()
except IOError, msg:
print file, ":", msg
sys.exit(1)
n = len(functions.keys())
print "Found %d functions in libvirt-api.xml" % (n)
py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
try:
f = open(os.path.join(srcPref,"libvirt-override-api.xml"))
data = f.read()
(parser, target) = getparser()
parser.feed(data)
parser.close()
except IOError, msg:
print file, ":", msg
print "Found %d functions in libvirt-override-api.xml" % (
len(functions.keys()) - n)
nb_wrap = 0
failed = 0
skipped = 0
include = open("libvirt.h", "w")
include.write("/* Generated */\n\n")
export = open("libvirt-export.c", "w")
export.write("/* Generated */\n\n")
wrapper = open("libvirt.c", "w")
wrapper.write("/* Generated */\n\n")
wrapper.write("#include <Python.h>\n")
wrapper.write("#include <libvirt/libvirt.h>\n")
wrapper.write("#include \"typewrappers.h\"\n")
wrapper.write("#include \"libvirt.h\"\n\n")
for function in functions.keys():
ret = print_function_wrapper(function, wrapper, export, include)
if ret < 0:
failed = failed + 1
functions_failed.append(function)
del functions[function]
if ret == 0:
skipped = skipped + 1
functions_skipped.append(function)
del functions[function]
if ret == 1:
nb_wrap = nb_wrap + 1
include.close()
export.close()
wrapper.close()
print "Generated %d wrapper functions" % nb_wrap
print "Missing type converters: "
for type in unknown_types.keys():
print "%s:%d " % (type, len(unknown_types[type])),
print
for f in functions_failed:
print "ERROR: failed %s" % f
if failed > 0:
return -1
return 0
#######################################################################
#
# This part writes part of the Python front-end classes based on
# mapping rules between types and classes and also based on function
# renaming to get consistent function names at the Python level
#
#######################################################################
#
# The type automatically remapped to generated classes
#
classes_type = {
"virDomainPtr": ("._o", "virDomain(self,_obj=%s)", "virDomain"),
"virDomain *": ("._o", "virDomain(self, _obj=%s)", "virDomain"),
"virNetworkPtr": ("._o", "virNetwork(self, _obj=%s)", "virNetwork"),
"virNetwork *": ("._o", "virNetwork(self, _obj=%s)", "virNetwork"),
"virInterfacePtr": ("._o", "virInterface(self, _obj=%s)", "virInterface"),
"virInterface *": ("._o", "virInterface(self, _obj=%s)", "virInterface"),
2008-02-20 15:26:22 +00:00
"virStoragePoolPtr": ("._o", "virStoragePool(self, _obj=%s)", "virStoragePool"),
"virStoragePool *": ("._o", "virStoragePool(self, _obj=%s)", "virStoragePool"),
"virStorageVolPtr": ("._o", "virStorageVol(self, _obj=%s)", "virStorageVol"),
"virStorageVol *": ("._o", "virStorageVol(self, _obj=%s)", "virStorageVol"),
"virNodeDevicePtr": ("._o", "virNodeDevice(self, _obj=%s)", "virNodeDevice"),
"virNodeDevice *": ("._o", "virNodeDevice(self, _obj=%s)", "virNodeDevice"),
"virSecretPtr": ("._o", "virSecret(self, _obj=%s)", "virSecret"),
"virSecret *": ("._o", "virSecret(self, _obj=%s)", "virSecret"),
"virStreamPtr": ("._o", "virStream(self, _obj=%s)", "virStream"),
"virStream *": ("._o", "virStream(self, _obj=%s)", "virStream"),
"virConnectPtr": ("._o", "virConnect(_obj=%s)", "virConnect"),
"virConnect *": ("._o", "virConnect(_obj=%s)", "virConnect"),
"virDomainSnapshotPtr": ("._o", "virDomainSnapshot(self,_obj=%s)", "virDomainSnapshot"),
"virDomainSnapshot *": ("._o", "virDomainSnapshot(self, _obj=%s)", "virDomainSnapshot"),
}
converter_type = {
}
primary_classes = ["virDomain", "virNetwork", "virInterface",
"virStoragePool", "virStorageVol",
"virConnect", "virNodeDevice", "virSecret",
"virStream", "virDomainSnapshot"]
classes_ancestor = {
}
classes_destructors = {
"virDomain": "virDomainFree",
"virNetwork": "virNetworkFree",
"virInterface": "virInterfaceFree",
2008-02-20 15:26:22 +00:00
"virStoragePool": "virStoragePoolFree",
"virStorageVol": "virStorageVolFree",
"virNodeDevice" : "virNodeDeviceFree",
"virSecret": "virSecretFree",
"virDomainSnapshot": "virDomainSnapshotFree",
# We hand-craft __del__ for this one
#"virStream": "virStreamFree",
}
class_skip_connect_impl = {
"virConnect" : True
}
functions_noexcept = {
'virDomainGetID': True,
'virDomainGetName': True,
2008-02-20 15:26:22 +00:00
'virNetworkGetName': True,
'virInterfaceGetName': True,
2008-02-20 15:26:22 +00:00
'virStoragePoolGetName': True,
'virStorageVolGetName': True,
'virStorageVolGetkey': True,
'virNodeDeviceGetName': True,
'virNodeDeviceGetParent': True,
'virSecretGetUsageType': True,
'virSecretGetUsageID': True,
}
reference_keepers = {
}
function_classes = {}
function_classes["None"] = []
function_post = {}
# Functions returning an integral type which need special rules to
# check for errors and raise exceptions.
functions_int_exception_test = {
'virDomainGetMaxMemory': "%s == 0",
}
functions_int_default_test = "%s == -1"
def is_integral_type (name):
return not re.search ("^(unsigned)? ?(int|long)$", name) is None
# Functions returning lists which need special rules to check for errors
# and raise exceptions.
functions_list_exception_test = {
}
functions_list_default_test = "%s is None"
def is_list_type (name):
whitelist = [ "virDomainBlockStats",
"virDomainInterfaceStats" ]
return name[-1:] == "*" or name in whitelist
def nameFixup(name, classe, type, file):
# avoid a desastrous clash
listname = classe + "List"
ll = len(listname)
l = len(classe)
if name[0:l] == listname:
func = name[l:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:16] == "virNetworkDefine":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:19] == "virNetworkCreateXML":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:16] == "virNetworkLookup":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:18] == "virInterfaceDefine":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:21] == "virInterfaceCreateXML":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:18] == "virInterfaceLookup":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:15] == "virSecretDefine":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:15] == "virSecretLookup":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
2008-02-20 15:26:22 +00:00
elif name[0:20] == "virStoragePoolDefine":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:23] == "virStoragePoolCreateXML":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
2008-02-20 15:26:22 +00:00
elif name[0:20] == "virStoragePoolLookup":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:19] == "virStorageVolDefine":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:19] == "virStorageVolLookup":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:12] == "virDomainGet":
func = name[12:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:29] == "virDomainSnapshotLookupByName":
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:26] == "virDomainSnapshotListNames":
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:20] == "virDomainSnapshotNum":
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:26] == "virDomainSnapshotCreateXML":
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:24] == "virDomainSnapshotCurrent":
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:17] == "virDomainSnapshot":
func = name[17:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:9] == "virDomain":
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:13] == "virNetworkGet":
func = name[13:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:10] == "virNetwork":
func = name[10:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:15] == "virInterfaceGet":
func = name[15:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:12] == "virInterface":
func = name[12:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:12] == 'virSecretGet':
func = name[12:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:9] == 'virSecret':
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:12] == 'virStreamNew':
func = "newStream"
elif name[0:9] == 'virStream':
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
2008-02-20 15:26:22 +00:00
elif name[0:17] == "virStoragePoolGet":
func = name[17:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:14] == "virStoragePool":
func = name[14:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:16] == "virStorageVolGet":
func = name[16:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:13] == "virStorageVol":
func = name[13:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:13] == "virNodeDevice":
if name[13:16] == "Get":
func = string.lower(name[16]) + name[17:]
elif name[13:19] == "Lookup" or name[13:19] == "Create":
func = string.lower(name[3]) + name[4:]
else:
func = string.lower(name[13]) + name[14:]
elif name[0:7] == "virNode":
func = name[7:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:10] == "virConnect":
func = name[10:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:3] == "xml":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
else:
func = name
if func == "iD":
func = "ID"
if func == "uUID":
func = "UUID"
if func == "uUIDString":
func = "UUIDString"
if func == "oSType":
func = "OSType"
if func == "xMLDesc":
func = "XMLDesc"
if func == "mACString":
func = "MACString"
return func
def functionCompare(info1, info2):
(index1, func1, name1, ret1, args1, file1) = info1
(index2, func2, name2, ret2, args2, file2) = info2
if file1 == file2:
if func1 < func2:
return -1
if func1 > func2:
return 1
if file1 == "python_accessor":
return -1
if file2 == "python_accessor":
return 1
if file1 < file2:
return -1
if file1 > file2:
return 1
return 0
def writeDoc(name, args, indent, output):
if functions[name][0] is None or functions[name][0] == "":
return
val = functions[name][0]
val = string.replace(val, "NULL", "None");
output.write(indent)
output.write('"""')
i = string.find(val, "\n")
while i >= 0:
str = val[0:i+1]
val = val[i+1:]
output.write(str)
i = string.find(val, "\n")
output.write(indent)
output.write(val)
output.write(' """\n')
def buildWrappers():
global ctypes
global py_types
global py_return_types
global unknown_types
global functions
global function_classes
global classes_type
global classes_list
global converter_type
global primary_classes
global converter_type
global classes_ancestor
global converter_type
global primary_classes
global classes_ancestor
global classes_destructors
global functions_noexcept
for type in classes_type.keys():
function_classes[classes_type[type][2]] = []
#
# Build the list of C types to look for ordered to start
# with primary classes
#
ctypes = []
classes_list = []
ctypes_processed = {}
classes_processed = {}
for classe in primary_classes:
classes_list.append(classe)
classes_processed[classe] = ()
for type in classes_type.keys():
tinfo = classes_type[type]
if tinfo[2] == classe:
ctypes.append(type)
ctypes_processed[type] = ()
for type in classes_type.keys():
if ctypes_processed.has_key(type):
continue
tinfo = classes_type[type]
if not classes_processed.has_key(tinfo[2]):
classes_list.append(tinfo[2])
classes_processed[tinfo[2]] = ()
ctypes.append(type)
ctypes_processed[type] = ()
for name in functions.keys():
found = 0;
(desc, ret, args, file, cond) = functions[name]
for type in ctypes:
classe = classes_type[type][2]
if name[0:3] == "vir" and len(args) >= 1 and args[0][1] == type:
found = 1
func = nameFixup(name, classe, type, file)
info = (0, func, name, ret, args, file)
function_classes[classe].append(info)
elif name[0:3] == "vir" and len(args) >= 2 and args[1][1] == type \
and file != "python_accessor":
found = 1
func = nameFixup(name, classe, type, file)
info = (1, func, name, ret, args, file)
function_classes[classe].append(info)
if found == 1:
continue
func = nameFixup(name, "None", file, file)
info = (0, func, name, ret, args, file)
function_classes['None'].append(info)
classes = open("libvirt.py", "w")
extra = open(os.path.join(srcPref,"libvirt-override.py"), "r")
classes.write("#!/usr/bin/python -i\n")
classes.write("#\n")
classes.write("# WARNING WARNING WARNING WARNING\n")
classes.write("#\n")
classes.write("# This file is automatically written by generator.py. Any changes\n")
classes.write("# made here will be lost.\n")
classes.write("#\n")
classes.write("# To change the manually written methods edit libvirt-override.py\n")
classes.write("# To change the automatically written methods edit generator.py\n")
classes.write("#\n")
classes.write("# WARNING WARNING WARNING WARNING\n")
classes.write("#\n")
classes.writelines(extra.readlines())
classes.write("#\n")
classes.write("# WARNING WARNING WARNING WARNING\n")
classes.write("#\n")
classes.write("# Automatically written part of python bindings for libvirt\n")
classes.write("#\n")
classes.write("# WARNING WARNING WARNING WARNING\n")
extra.close()
if function_classes.has_key("None"):
flist = function_classes["None"]
flist.sort(functionCompare)
oldfile = ""
for info in flist:
(index, func, name, ret, args, file) = info
if file != oldfile:
classes.write("#\n# Functions from module %s\n#\n\n" % file)
oldfile = file
classes.write("def %s(" % func)
n = 0
for arg in args:
if n != 0:
classes.write(", ")
classes.write("%s" % arg[0])
n = n + 1
classes.write("):\n")
writeDoc(name, args, ' ', classes);
for arg in args:
if classes_type.has_key(arg[1]):
classes.write(" if %s is None: %s__o = None\n" %
(arg[0], arg[0]))
classes.write(" else: %s__o = %s%s\n" %
(arg[0], arg[0], classes_type[arg[1]][0]))
if ret[0] != "void":
classes.write(" ret = ");
else:
classes.write(" ");
classes.write("libvirtmod.%s(" % name)
n = 0
for arg in args:
if n != 0:
classes.write(", ");
classes.write("%s" % arg[0])
if classes_type.has_key(arg[1]):
classes.write("__o");
n = n + 1
classes.write(")\n");
if ret[0] != "void":
if classes_type.has_key(ret[0]):
#
# Raise an exception
#
if functions_noexcept.has_key(name):
classes.write(" if ret is None:return None\n");
else:
classes.write(
" if ret is None:raise libvirtError('%s() failed')\n" %
(name))
classes.write(" return ");
classes.write(classes_type[ret[0]][1] % ("ret"));
classes.write("\n");
# For functions returning an integral type there are
# several things that we can do, depending on the
# contents of functions_int_*:
elif is_integral_type (ret[0]):
if not functions_noexcept.has_key (name):
if functions_int_exception_test.has_key (name):
test = functions_int_exception_test[name]
else:
test = functions_int_default_test
classes.write ((" if " + test +
": raise libvirtError ('%s() failed')\n") %
("ret", name))
classes.write(" return ret\n")
elif is_list_type (ret[0]):
if not functions_noexcept.has_key (name):
if functions_list_exception_test.has_key (name):
test = functions_list_exception_test[name]
else:
test = functions_list_default_test
classes.write ((" if " + test +
": raise libvirtError ('%s() failed')\n") %
("ret", name))
classes.write(" return ret\n")
else:
classes.write(" return ret\n")
classes.write("\n");
for classname in classes_list:
if classname == "None":
pass
else:
if classes_ancestor.has_key(classname):
classes.write("class %s(%s):\n" % (classname,
classes_ancestor[classname]))
classes.write(" def __init__(self, _obj=None):\n")
if reference_keepers.has_key(classname):
rlist = reference_keepers[classname]
for ref in rlist:
classes.write(" self.%s = None\n" % ref[1])
classes.write(" self._o = _obj\n")
classes.write(" %s.__init__(self, _obj=_obj)\n\n" % (
classes_ancestor[classname]))
else:
classes.write("class %s:\n" % (classname))
if classname in [ "virDomain", "virNetwork", "virInterface", "virStoragePool",
"virStorageVol", "virNodeDevice", "virSecret","virStream" ]:
classes.write(" def __init__(self, conn, _obj=None):\n")
else:
classes.write(" def __init__(self, _obj=None):\n")
if reference_keepers.has_key(classname):
list = reference_keepers[classname]
for ref in list:
classes.write(" self.%s = None\n" % ref[1])
if classname in [ "virDomain", "virNetwork", "virInterface",
"virNodeDevice", "virSecret", "virStream" ]:
classes.write(" self._conn = conn\n")
elif classname in [ "virStorageVol", "virStoragePool" ]:
classes.write(" self._conn = conn\n" + \
" if not isinstance(conn, virConnect):\n" + \
" self._conn = conn._conn\n")
classes.write(" if _obj != None:self._o = _obj;return\n")
classes.write(" self._o = None\n\n");
destruct=None
if classes_destructors.has_key(classname):
classes.write(" def __del__(self):\n")
classes.write(" if self._o != None:\n")
classes.write(" libvirtmod.%s(self._o)\n" %
classes_destructors[classname]);
classes.write(" self._o = None\n\n");
destruct=classes_destructors[classname]
if not class_skip_connect_impl.has_key(classname):
# Build python safe 'connect' method
classes.write(" def connect(self):\n")
classes.write(" return self._conn\n\n")
flist = function_classes[classname]
flist.sort(functionCompare)
oldfile = ""
for info in flist:
(index, func, name, ret, args, file) = info
#
# Do not provide as method the destructors for the class
# to avoid double free
#
if name == destruct:
continue;
if file != oldfile:
if file == "python_accessor":
classes.write(" # accessors for %s\n" % (classname))
else:
classes.write(" #\n")
classes.write(" # %s functions from module %s\n" % (
classname, file))
classes.write(" #\n\n")
oldfile = file
classes.write(" def %s(self" % func)
n = 0
for arg in args:
if n != index:
classes.write(", %s" % arg[0])
n = n + 1
classes.write("):\n")
writeDoc(name, args, ' ', classes);
n = 0
for arg in args:
if classes_type.has_key(arg[1]):
if n != index:
classes.write(" if %s is None: %s__o = None\n" %
(arg[0], arg[0]))
classes.write(" else: %s__o = %s%s\n" %
(arg[0], arg[0], classes_type[arg[1]][0]))
n = n + 1
if ret[0] != "void":
classes.write(" ret = ");
else:
classes.write(" ");
classes.write("libvirtmod.%s(" % name)
n = 0
for arg in args:
if n != 0:
classes.write(", ");
if n != index:
classes.write("%s" % arg[0])
if classes_type.has_key(arg[1]):
classes.write("__o");
else:
classes.write("self");
if classes_type.has_key(arg[1]):
classes.write(classes_type[arg[1]][0])
n = n + 1
classes.write(")\n");
if name == "virConnectClose":
classes.write(" self._o = None\n")
# For functions returning object types:
if ret[0] != "void":
if classes_type.has_key(ret[0]):
#
# Raise an exception
#
if functions_noexcept.has_key(name):
classes.write(
" if ret is None:return None\n");
else:
if classname == "virConnect":
classes.write(
" if ret is None:raise libvirtError('%s() failed', conn=self)\n" %
(name))
elif classname == "virDomain":
classes.write(
" if ret is None:raise libvirtError('%s() failed', dom=self)\n" %
(name))
elif classname == "virNetwork":
classes.write(
" if ret is None:raise libvirtError('%s() failed', net=self)\n" %
(name))
elif classname == "virInterface":
classes.write(
" if ret is None:raise libvirtError('%s() failed', net=self)\n" %
(name))
2008-02-20 15:26:22 +00:00
elif classname == "virStoragePool":
classes.write(
" if ret is None:raise libvirtError('%s() failed', pool=self)\n" %
(name))
elif classname == "virStorageVol":
classes.write(
" if ret is None:raise libvirtError('%s() failed', vol=self)\n" %
(name))
else:
classes.write(
" if ret is None:raise libvirtError('%s() failed')\n" %
(name))
#
# generate the returned class wrapper for the object
#
classes.write(" __tmp = ");
classes.write(classes_type[ret[0]][1] % ("ret"));
classes.write("\n");
#
# Sometime one need to keep references of the source
# class in the returned class object.
# See reference_keepers for the list
#
tclass = classes_type[ret[0]][2]
if reference_keepers.has_key(tclass):
list = reference_keepers[tclass]
for pref in list:
if pref[0] == classname:
classes.write(" __tmp.%s = self\n" %
pref[1])
# Post-processing - just before we return.
if function_post.has_key(name):
classes.write(" %s\n" %
(function_post[name]));
#
# return the class
#
classes.write(" return __tmp\n");
elif converter_type.has_key(ret[0]):
#
# Raise an exception
#
if functions_noexcept.has_key(name):
classes.write(
" if ret is None:return None");
# Post-processing - just before we return.
if function_post.has_key(name):
classes.write(" %s\n" %
(function_post[name]));
classes.write(" return ");
classes.write(converter_type[ret[0]] % ("ret"));
classes.write("\n");
# For functions returning an integral type there
# are several things that we can do, depending on
# the contents of functions_int_*:
elif is_integral_type (ret[0]):
if not functions_noexcept.has_key (name):
if functions_int_exception_test.has_key (name):
test = functions_int_exception_test[name]
else:
test = functions_int_default_test
if classname == "virConnect":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', conn=self)\n") %
("ret", name))
elif classname == "virDomain":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', dom=self)\n") %
("ret", name))
elif classname == "virNetwork":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', net=self)\n") %
("ret", name))
elif classname == "virInterface":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', net=self)\n") %
("ret", name))
2008-02-20 15:26:22 +00:00
elif classname == "virStoragePool":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', pool=self)\n") %
("ret", name))
elif classname == "virStorageVol":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', vol=self)\n") %
("ret", name))
else:
classes.write ((" if " + test +
": raise libvirtError ('%s() failed')\n") %
("ret", name))
# Post-processing - just before we return.
if function_post.has_key(name):
classes.write(" %s\n" %
(function_post[name]));
classes.write (" return ret\n")
elif is_list_type (ret[0]):
if not functions_noexcept.has_key (name):
if functions_list_exception_test.has_key (name):
test = functions_list_exception_test[name]
else:
test = functions_list_default_test
if classname == "virConnect":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', conn=self)\n") %
("ret", name))
elif classname == "virDomain":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', dom=self)\n") %
("ret", name))
elif classname == "virNetwork":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', net=self)\n") %
("ret", name))
elif classname == "virInterface":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', net=self)\n") %
("ret", name))
2008-02-20 15:26:22 +00:00
elif classname == "virStoragePool":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', pool=self)\n") %
("ret", name))
elif classname == "virStorageVol":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', vol=self)\n") %
("ret", name))
else:
classes.write ((" if " + test +
": raise libvirtError ('%s() failed')\n") %
("ret", name))
# Post-processing - just before we return.
if function_post.has_key(name):
classes.write(" %s\n" %
(function_post[name]));
classes.write (" return ret\n")
else:
# Post-processing - just before we return.
if function_post.has_key(name):
classes.write(" %s\n" %
(function_post[name]));
classes.write(" return ret\n");
classes.write("\n");
# Append "<classname>.py" to class def, iff it exists
try:
extra = open(os.path.join(srcPref,"libvirt-override-" + classname + ".py"), "r")
classes.write (" #\n")
classes.write (" # %s methods from %s.py (hand coded)\n" % (classname,classname))
classes.write (" #\n")
classes.writelines(extra.readlines())
classes.write("\n")
extra.close()
except:
pass
#
# Generate enum constants
#
for type,enum in enums.items():
classes.write("# %s\n" % type)
items = enum.items()
items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1])))
for name,value in items:
classes.write("%s = %s\n" % (name,value))
classes.write("\n");
classes.close()
if buildStubs() < 0:
sys.exit(1)
buildWrappers()
sys.exit(0)