/
gen-mysql-api.py
144 lines (113 loc) · 4.16 KB
/
gen-mysql-api.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/env python
"""
This script should be run once on each target platform to generate the
Python API from the MySQL header files.
Prerequisites:
1) MySQL 5.1 with developer headers (libmysqlclient-dev on Unix)
2) gccxml
3) ctypeslib
For more information on this technique, visit
http://web.archive.org/web/20080115092643/starship.python.net/crew/theller/wiki/CodeGenerator
Also consider looking at the old docs:
http://starship.python.net/crew/theller/ctypes/old/codegen.html
"""
import sys
import os
import subprocess
import copy
from ctypeslib import h2xml, xml2py
import logging
setup_root = os.path.dirname(__file__)
sys.path.append(os.path.join(setup_root, 'root'))
from _mysql_api_util import get_mysql_root, get_platform_name
log = logging.getLogger(__name__)
def merge_args(common_args, variable_args):
for args in variable_args:
yield common_args + args
class LibGenerator(object):
h2xml_cmds = [
# need WIN32_LEAN_AND_MEAN to exclude most windows stuff
'mysql.h -o mysql.xml'.split(),
'-c errmsg.h -o errmsg.xml'.split(),
'-c mysql_version.h -o mysql_version.xml'.split(),
'-c mysqld_error.h -o mysqld_error.xml'.split(),
]
xml2py_cmds = [
'mysql.xml -l %(libname)s -o %(libroot)s/api.py'.split(),
# Use -s MYSQL to get the MYSQL structure and ancestral structures
'errmsg.xml -o %(libroot)s/errmsg.py'.split(),
'mysql_version.xml -o %(libroot)s/version.py'.split(),
'mysqld_error.xml -o %(libroot)s/errors.py'.split(),
]
def h2xml_cmd(self, args):
assert h2xml.compile_to_xml(args) is None, cmd + ' failed'
def xml2py_cmd(self, args):
assert xml2py.main(args) is None, cmd + ' failed'
def run(self):
print('Generating xml')
h2xml_common = ['h2xml.py', '-I', self.mysql_include]
cmds = merge_args(h2xml_common, self.h2xml_cmds)
map(self.h2xml_cmd, cmds)
print('Generating Python libs')
xml2py_common = ['xml2py.py']
xml2py_cmds = map(self.patch_cmd, self.xml2py_cmds)
cmds = merge_args(xml2py_common, xml2py_cmds)
self.create_package()
map(self.xml2py_cmd, cmds)
self.patch_mysql_api()
def patch_cmd(self, cmd):
class ObjectDict(object):
def __init__(self, object):
self.object = object
def __getitem__(self, name):
return getattr(self.object, name)
patch_part = lambda part: part % ObjectDict(self)
return map(patch_part, cmd)
@property
def libroot(self):
return 'root/_mysql_' + self.platform
def create_package(self):
if not os.path.exists(self.libroot):
os.makedirs(self.libroot)
open(os.path.join(self.libroot, '__init__.py')).close()
def fix_my_bool(self):
self.api_file = self.api_file.replace('my_bool = c_char\n', 'my_bool = c_int8\n')
def fix_lib_path(self):
pass
def fix_autocommit_arg2(self):
f = self.api_file
incorrect = 'mysql_autocommit.argtypes = [POINTER(MYSQL), c_char]'
correct = 'mysql_autocommit.argtypes = [POINTER(MYSQL), my_bool]'
f = f.replace(incorrect, correct)
if f == self.api_file:
log.info('autocommit args unchanged')
self.api_file = f
def patch_mysql_api(self):
self.api_file = open(os.path.join(self.libroot, 'api.py'), 'r').read()
self.fix_my_bool()
self.fix_lib_path()
self.fix_autocommit_arg2()
open(os.path.join(self.libroot, 'api.py',), 'w').write(self.api_file)
class WindowsLibGenerator(LibGenerator):
platform = 'windows'
libname='libmysql.dll'
mysql_include = os.path.join(get_mysql_root(), 'include')
# need WIN32_LEAN_AND_MEAN to exclude most windows stuff
h2xml_cmds = copy.deepcopy(LibGenerator.h2xml_cmds)
h2xml_cmds[0][:0] = '-D WIN32_LEAN_AND_MEAN config-win.h'.split()
def run(self):
os.environ['PATH'] += ';%s\lib\opt' % get_mysql_root()
super(WindowsLibGenerator, self).run()
def fix_lib_path(self):
f = self.api_file
f = f.replace("CDLL('libmysql.dll')", "CDLL(get_lib_path())")
f = f.replace("WinDLL('libmysql.dll')", "WinDLL(get_lib_path())")
i = f.index('_libraries = {}')
before, after = f[:i], f[i:]
new_code = 'from _mysql_api_util import get_lib_path\n'
self.api_file = ''.join((before, new_code, after))
class UnixLibGenerator(LibGenerator):
platform = 'unix'
libname='libmysqlclient.so'
mysql_include = '/usr/include/mysql'
vars()[get_platform_name().capitalize()+'LibGenerator']().run()