Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 312 lines (219 sloc) 10.462 kb
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
1 #!/usr/bin/python
2
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
3 import sys, os, re, platform
eb54575 @mkleehammer Issue 80: setup.py uses setuptools if available to allow building eggs
authored
4 from os.path import exists, abspath, dirname, join, isdir
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
5 from ConfigParser import SafeConfigParser
eb54575 @mkleehammer Issue 80: setup.py uses setuptools if available to allow building eggs
authored
6
7 try:
8 # Allow use of setuptools so eggs can be built.
9 from setuptools.core import setup, Command
10 except ImportError:
11 from distutils.core import setup, Command
12
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
13 from distutils.extension import Extension
14 from distutils.errors import *
15
16 OFFICIAL_BUILD = 9999
17
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
18
e82cb43 Added version command to setup.py
Michael Kleehammer authored
19 class VersionCommand(Command):
f89886e @mkleehammer Added description to setup version command
authored
20
a42975a @mkleehammer Ported setup tags command from v31 branch.
authored
21 description = "prints the pyodbc version, determined from git"
f89886e @mkleehammer Added description to setup version command
authored
22
e82cb43 Added version command to setup.py
Michael Kleehammer authored
23 user_options = []
24
25 def initialize_options(self):
26 self.verbose = 0
27
28 def finalize_options(self):
29 pass
30
31 def run(self):
32 version_str, version = get_version()
33 print version_str
34
35
a42975a @mkleehammer Ported setup tags command from v31 branch.
authored
36 class TagsCommand(Command):
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
37
a42975a @mkleehammer Ported setup tags command from v31 branch.
authored
38 description = 'runs etags'
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
39
a42975a @mkleehammer Ported setup tags command from v31 branch.
authored
40 user_options = []
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
41
a42975a @mkleehammer Ported setup tags command from v31 branch.
authored
42 def initialize_options(self):
43 pass
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
44
a42975a @mkleehammer Ported setup tags command from v31 branch.
authored
45 def finalize_options(self):
46 pass
47
48 def run(self):
49 # Windows versions of etag do not seem to expand wildcards (which Unix shells normally do for Unix utilities),
50 # so find all of the files ourselves.
51 files = [ join('src', f) for f in os.listdir('src') if f.endswith(('.h', '.cpp')) ]
52 cmd = 'etags %s' % ' '.join(files)
53 return os.system(cmd)
54
55
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
56
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
57 def main():
58
59 version_str, version = get_version()
60
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
61 settings = get_compiler_settings(version_str)
04d8111 @mkleehammer Added SQL Server 2008 date/time extensions support. Now caches connecti...
authored
62
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
63 files = [ abspath(join('src', f)) for f in os.listdir('src') if f.endswith('.cpp') ]
523aed0 @mkleehammer Issue 91: decimal fix; Completely reworked parameters; added leakcheck
authored
64
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
65 if exists('MANIFEST'):
66 os.remove('MANIFEST')
67
68 setup (name = "pyodbc",
69 version = version_str,
70 description = "DB API Module for ODBC",
71
72 long_description = ('A Python DB API 2 module for ODBC. This project provides an up-to-date, '
73 'convenient interface to ODBC using native data types like datetime and decimal.'),
74
75 maintainer = "Michael Kleehammer",
76 maintainer_email = "michael@kleehammer.com",
77
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
78 ext_modules = [Extension('pyodbc', files, **settings)],
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
79
1567234 eliminate gcc write-strings warnings; caused by Python declarations - no...
Michael Kleehammer authored
80 classifiers = ['Development Status :: 5 - Production/Stable',
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
81 'Intended Audience :: Developers',
82 'Intended Audience :: System Administrators',
83 'License :: OSI Approved :: MIT License',
84 'Operating System :: Microsoft :: Windows',
85 'Operating System :: POSIX',
86 'Programming Language :: Python',
87 'Topic :: Database',
1567234 eliminate gcc write-strings warnings; caused by Python declarations - no...
Michael Kleehammer authored
88 ],
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
89
47138be @mkleehammer Updated metadata to point to Google code hosting
authored
90 url = 'http://code.google.com/p/pyodbc',
e82cb43 Added version command to setup.py
Michael Kleehammer authored
91 download_url = 'http://code.google.com/p/pyodbc/downloads/list',
a42975a @mkleehammer Ported setup tags command from v31 branch.
authored
92 cmdclass = { 'version' : VersionCommand,
93 'tags' : TagsCommand })
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
94
95
04d8111 @mkleehammer Added SQL Server 2008 date/time extensions support. Now caches connecti...
authored
96
9dd144f @mkleehammer Added pyodbc.conf for preprocessor-time access to sizeof(SQLWCHAR)
authored
97 def get_compiler_settings(version_str):
98
99 settings = { 'libraries': [],
100 'define_macros' : [ ('PYODBC_VERSION', version_str) ] }
101
102 # This isn't the best or right way to do this, but I don't see how someone is supposed to sanely subclass the build
103 # command.
104 for option in ['assert', 'trace', 'leak-check']:
105 try:
106 sys.argv.remove('--%s' % option)
107 settings['define_macros'].append(('PYODBC_%s' % option.replace('-', '_'), 1))
108 except ValueError:
109 pass
110
111 if os.name == 'nt':
112 settings['libraries'].append('odbc32')
113
114 elif os.environ.get("OS", '').lower().startswith('windows'):
115 # Windows Cygwin (posix on windows)
116 # OS name not windows, but still on Windows
117 settings['libraries'].append('odbc32')
118
119 elif sys.platform == 'darwin':
120 # OS/X now ships with iODBC.
121 settings['libraries'].append('iodbc')
122
123 else:
124 # Other posix-like: Linux, Solaris, etc.
125
126 # Python functions take a lot of 'char *' that really should be const. gcc complains about this *a lot*
127 settings['extra_compile_args'] = ['-Wno-write-strings']
128
129 # What is the proper way to detect iODBC, MyODBC, unixODBC, etc.?
130 settings['libraries'].append('odbc')
131
132 get_config(settings, version_str)
133
134 return settings
135
136
137 def get_config(settings, version_str):
138 """
139 Adds configuration macros from pyodbc.conf to the compiler settings dictionary.
140
141 If pyodbc.conf does not exist, it will compile and run the pyodbcconf utility.
142
143 This is similar to what autoconf provides, but only uses the infrastructure provided by Python, which is important
144 for building on *nix and Windows.
145 """
146 filename = 'pyodbc.conf'
147
148 # If the file exists, make sure that the version in it is the same as the version we are compiling. Otherwise we
149 # might have added configuration items that aren't there.
150 if exists(filename):
151 try:
152 config = SafeConfigParser()
153 config.read(filename)
154
155 if (not config.has_option('define_macros', 'pyodbc_version') or
156 config.get('define_macros', 'pyodbc_version') != version_str):
157 print 'Recreating pyodbc.conf for new version'
158 os.remove(filename)
159
160 except:
161 config = None
162 # Assume the file has been corrupted. Delete and recreate
163 print 'Unable to read %s. Recreating' % filename
164 os.remove(filename)
165
166 if not exists('pyodbc.conf'):
167 # Doesn't exist, so build the pyodbcconf module and use it.
168
169 oldargv = sys.argv
170 sys.argv = [ oldargv[0], 'build' ]
171
172 setup(name="pyodbcconf",
173 ext_modules = [ Extension('pyodbcconf',
174 [join('utils', 'pyodbcconf', 'pyodbcconf.cpp')],
175 **settings) ])
176
177 sys.argv = oldargv
178
179 add_to_path()
180
181 import pyodbcconf
182 pyodbcconf.configure()
183
184 config = SafeConfigParser()
185 config.read(filename)
186
187 for section in config.sections():
188 for key, value in config.items(section):
189 settings[section].append( (key.upper(), value) )
190
191
192
193 def add_to_path():
194 """
195 Prepends the build directory to the path so pyodbcconf can be imported without installing it.
196 """
197 # Now run the utility
198
199 import imp
200 library_exts = [ t[0] for t in imp.get_suffixes() if t[-1] == imp.C_EXTENSION ]
201 library_names = [ 'pyodbcconf%s' % ext for ext in library_exts ]
202
203 # Only go into directories that match our version number.
204
205 dir_suffix = '-%s.%s' % (sys.version_info[0], sys.version_info[1])
206
207 build = join(dirname(abspath(__file__)), 'build')
208
209 for top, dirs, files in os.walk(build):
210 dirs = [ d for d in dirs if d.endswith(dir_suffix) ]
211 for name in library_names:
212 if name in files:
213 sys.path.insert(0, top)
214 return
215
216 raise SystemExit('Did not find pyodbcconf')
217
218
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
219 def get_version():
220 """
221 Returns the version of the product as (description, [major,minor,micro,beta]).
222
223 If the release is official, `beta` will be 9999 (OFFICIAL_BUILD).
224
225 1. If in a git repository, use the latest tag (git describe).
226 2. If in an unzipped source directory (from setup.py sdist),
227 read the version from the PKG-INFO file.
228 3. Use 2.1.0.0 and complain a lot.
229 """
230 # My goal is to (1) provide accurate tags for official releases but (2) not have to manage tags for every test
231 # release.
232 #
233 # Official versions are tagged using 3 numbers: major, minor, micro. A build of a tagged version should produce
234 # the version using just these pieces, such as 2.1.4.
235 #
236 # Unofficial versions are "working towards" the next version. So the next unofficial build after 2.1.4 would be a
237 # beta for 2.1.5. Using 'git describe' we can find out how many changes have been made after 2.1.4 and we'll use
238 # this count as the beta id (beta1, beta2, etc.)
239 #
c8c8fe1 fixed pyodbc.version for non-beta releases
Michael Kleehammer authored
240 # Since the 4 numbers are put into the Windows DLL, we want to make sure the beta versions sort *before* the
241 # official, so we set the official build number to 9999, but we don't show it.
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
242
243 name = None # branch/feature name. Should be None for official builds.
244 numbers = None # The 4 integers that make up the version.
245
246 # If this is a source release the version will have already been assigned and be in the PKG-INFO file.
247
248 name, numbers = _get_version_pkginfo()
249
250 # If not a source release, we should be in a git repository. Look for the latest tag.
251
252 if not numbers:
253 name, numbers = _get_version_git()
254
255 if not numbers:
256 print 'WARNING: Unable to determine version. Using 2.1.0.0'
257 name, numbers = '2.1.0-unsupported', [2,1,0,0]
258
259 return name, numbers
260
261
262 def _get_version_pkginfo():
263 filename = join(dirname(abspath(__file__)), 'PKG-INFO')
264 if exists(filename):
265 re_ver = re.compile(r'^Version: \s+ (\d+)\.(\d+)\.(\d+) (?: -beta(\d+))?', re.VERBOSE)
266 for line in open(filename):
267 match = re_ver.search(line)
268 if match:
269 name = line.split(':', 1)[1].strip()
9ff5342 @mkleehammer Issue 95: "beta0" added when building from source distribution.
authored
270 numbers = [int(n or 0) for n in match.groups()[:3]]
271 numbers.append(int(match.group(4) or OFFICIAL_BUILD)) # don't use 0 as a default for build
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
272 return name, numbers
273
274 return None, None
275
276
277 def _get_version_git():
9ff5342 @mkleehammer Issue 95: "beta0" added when building from source distribution.
authored
278 n, result = getoutput('git describe --tags --match 2.*')
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
279 if n:
280 print 'WARNING: git describe failed with: %s %s' % (n, result)
281 return None, None
282
283 match = re.match(r'(\d+).(\d+).(\d+) (?: -(\d+)-g[0-9a-z]+)?', result, re.VERBOSE)
284 if not match:
285 return None, None
286
1567234 eliminate gcc write-strings warnings; caused by Python declarations - no...
Michael Kleehammer authored
287 numbers = [int(n or OFFICIAL_BUILD) for n in match.groups()]
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
288 if numbers[-1] == OFFICIAL_BUILD:
289 name = '%s.%s.%s' % tuple(numbers[:3])
290 if numbers[-1] != OFFICIAL_BUILD:
291 # This is a beta of the next micro release, so increment the micro number to reflect this.
292 numbers[-2] += 1
691b6ba @mkleehammer Reworked Unicode; changed version format; more Py_ssize_t
authored
293 name = '%s.%s.%s-beta%02d' % tuple(numbers)
294
295 n, result = getoutput('git branch')
296 branch = re.search(r'\* (\w+)', result).group(1)
297 if branch != 'master' and not re.match('^v\d+$', branch):
298 name = branch + '-' + name
299
c3f6b46 @mkleehammer Import from Subversion 2.0.63; reworked versioning
authored
300 return name, numbers
301
302
303
304 def getoutput(cmd):
305 pipe = os.popen(cmd, 'r')
306 text = pipe.read().rstrip('\n')
307 status = pipe.close() or 0
308 return status, text
309
310 if __name__ == '__main__':
311 main()
Something went wrong with that request. Please try again.