Small code cleanup.
[wammu.git] / setup.py
blob5634166d3dc86c6876622277326a33420028c3d2
1 #!/usr/bin/env python
2 # -*- coding: UTF-8 -*-
3 # vim: expandtab sw=4 ts=4 sts=4:
4 '''
5 Wammu - Phone manager
6 Setup script for installation using distutils
7 '''
8 __author__ = 'Michal Čihař'
9 __email__ = 'michal@cihar.com'
10 __license__ = '''
11 Copyright (c) 2003 - 2007 Michal Čihař
13 This program is free software; you can redistribute it and/or modify it
14 under the terms of the GNU General Public License version 2 as published by
15 the Free Software Foundation.
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 more details.
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 '''
27 import distutils
28 import distutils.command.build
29 import distutils.command.build_scripts
30 import distutils.command.clean
31 import distutils.command.install
32 import distutils.command.install_data
33 from stat import ST_MODE
34 from wammu_setup import msgfmt
35 import sys
36 import glob
37 import Wammu
38 import os.path
39 import os
40 import re
41 # Optional support for py2exe
42 try:
43 import py2exe
44 except:
45 pass
47 # used for passing state for skiping dependency check
48 skip_dependencies = False
50 # some defines
51 PYTHONGAMMU_REQUIRED = (0, 20)
52 WXPYTHON_REQUIRED = (2, 6, 2, 0)
54 # check if Python is called on the first line with this expression
55 first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$')
57 class build_scripts_wammu(distutils.command.build_scripts.build_scripts, object):
58 '''
59 This is mostly distutils copy, it just renames script according
60 to platform (.pyw for Windows, without extension for others)
61 '''
62 def copy_scripts (self):
63 """Copy each script listed in 'self.scripts'; if it's marked as a
64 Python script in the Unix way (first line matches 'first_line_re',
65 ie. starts with "\#!" and contains "python"), then adjust the first
66 line to refer to the current Python interpreter as we copy.
67 """
68 self.mkpath(self.build_dir)
69 outfiles = []
70 for script in self.scripts:
71 adjust = 0
72 script = distutils.util.convert_path(script)
73 outfile = os.path.join(self.build_dir, os.path.splitext(os.path.basename(script))[0])
74 if sys.platform == 'win32':
75 outfile += os.extsep + 'pyw'
76 outfiles.append(outfile)
78 if not self.force and not distutils.dep_util.newer(script, outfile):
79 distutils.log.debug("not copying %s (up-to-date)", script)
80 continue
82 # Always open the file, but ignore failures in dry-run mode --
83 # that way, we'll get accurate feedback if we can read the
84 # script.
85 try:
86 f = open(script, "r")
87 except IOError:
88 if not self.dry_run:
89 raise
90 f = None
91 else:
92 first_line = f.readline()
93 if not first_line:
94 self.warn("%s is an empty file (skipping)" % script)
95 continue
97 match = first_line_re.match(first_line)
98 if match:
99 adjust = 1
100 post_interp = match.group(1) or ''
102 if adjust:
103 distutils.log.info("copying and adjusting %s -> %s", script,
104 self.build_dir)
105 if not self.dry_run:
106 outf = open(outfile, "w")
107 if not distutils.sysconfig.python_build:
108 outf.write("#!%s%s\n" %
109 (os.path.normpath(sys.executable),
110 post_interp))
111 else:
112 outf.write("#!%s%s\n" %
113 (os.path.join(
114 distutils.sysconfig.get_config_var("BINDIR"),
115 "python" + distutils.sysconfig.get_config_var("EXE")),
116 post_interp))
117 outf.writelines(f.readlines())
118 outf.close()
119 if f:
120 f.close()
121 else:
122 f.close()
123 self.copy_file(script, outfile)
125 if os.name == 'posix':
126 for file in outfiles:
127 if self.dry_run:
128 distutils.log.info("changing mode of %s", file)
129 else:
130 oldmode = os.stat(file)[ST_MODE] & 07777
131 newmode = (oldmode | 0555) & 07777
132 if newmode != oldmode:
133 distutils.log.info("changing mode of %s from %o to %o",
134 file, oldmode, newmode)
135 os.chmod(file, newmode)
137 # copy_scripts ()
139 def list_message_files(package = 'wammu', suffix = '.po'):
141 Return list of all found message files and their installation paths.
143 _files = glob.glob('locale/*/' + package + suffix)
144 _list = []
145 for _file in _files:
146 # basename (without extension) is a locale name
147 _locale = os.path.basename(os.path.dirname(_file))
148 _list.append((_file, os.path.join(
149 'share', 'locale', _locale, 'LC_MESSAGES', '%s.mo' % package)))
150 return _list
152 class build_wammu(distutils.command.build.build, object):
154 Custom build command with locales support.
156 user_options = distutils.command.build.build.user_options + [('skip-deps', 's', 'skip checking for dependencies')]
157 boolean_options = distutils.command.build.build.boolean_options + ['skip-deps']
159 def initialize_options(self):
160 global skip_dependencies
161 super(build_wammu, self).initialize_options()
162 self.skip_deps = skip_dependencies
164 def finalize_options(self):
165 global skip_dependencies
166 super(build_wammu, self).finalize_options()
167 if self.skip_deps:
168 skip_dependencies = self.skip_deps
170 def build_message_files (self):
172 For each locale/*.po, build .mo file in target locale directory.
174 for (_src, _dst) in list_message_files(self.distribution.get_name()):
175 _build_dst = os.path.join('build', _dst)
176 destdir = os.path.dirname(_build_dst)
177 if not os.path.exists(destdir):
178 self.mkpath(destdir)
179 if not os.path.exists(_build_dst) or \
180 (os.path.getmtime(_build_dst) < os.path.getmtime(_src)):
181 distutils.log.info('compiling %s -> %s' % (_src, _build_dst))
182 msgfmt.make(_src, _build_dst)
184 def check_requirements(self):
185 if os.getenv('SKIPGAMMUCHECK') == 'yes':
186 print 'Skipping Gammu check, expecting you know what you are doing!'
187 else:
188 print 'Checking for python-gammu ...',
189 try:
190 import gammu
191 version = gammu.Version()
192 print 'found version %s using Gammu %s ...' % (version[1], version[0]),
194 pygver = tuple(map(int, version[1].split('.')))
195 if pygver < PYTHONGAMMU_REQUIRED:
196 print 'too old!'
197 print 'You need python-gammu at least %s!' % '.'.join(map(str, PYTHONGAMMU_REQUIRED))
198 print 'You can get it from <http://cihar.com/gammu/python/>'
199 sys.exit(1)
200 print 'OK'
201 except ImportError, message:
202 print 'Could not import python-gammu!'
203 print 'You can get it from <http://cihar.com/gammu/python/>'
204 print 'Import failed with following error: %s' % message
205 sys.exit(1)
207 if os.getenv('SKIPWXCHECK') == 'yes':
208 print 'Skipping wxPython check, expecting you know what you are doing!'
209 else:
210 print 'Checking for wxPython ...',
211 try:
212 import wx
213 print 'found version %s ...' % wx.VERSION_STRING,
214 if wx.VERSION < WXPYTHON_REQUIRED:
215 print 'too old!'
216 print 'You need at least wxPython %s!' % '.'.join(map(str, WXPYTHON_REQUIRED))
217 print 'You can get it from <http://www.wxpython.org>'
218 sys.exit(1)
219 if not wx.USE_UNICODE:
220 print 'not unicode!'
221 print 'You need at least wxPython %s with unicode enabled!' % '.'.join(map(str, WXPYTHON_REQUIRED))
222 print 'You can get it from <http://www.wxpython.org>'
223 sys.exit(1)
224 print 'OK'
225 except ImportError:
226 print 'You need wxPython!'
227 print 'You can get it from <http://www.wxpython.org>'
228 sys.exit(1)
230 print 'Checking for Bluetooth stack ...',
231 try:
232 import bluetooth
233 print 'PyBluez found'
234 except ImportError:
235 try:
236 import gnomebt.controller
237 print 'GNOME Bluetooth found'
238 print 'WARNING: GNOME Bluetooth support is limited, consider installing PyBluez'
239 except ImportError:
240 print 'WARNING: neither GNOME Bluetooth nor PyBluez found, without those you can not search for bluetooth devices'
241 print 'PyBluez can be downloaded from <http://org.csail.mit.edu/pybluez/>'
243 if sys.platform == 'win32':
244 print 'Checking for PyWin32 ...',
245 try:
246 import win32file, win32com, win32api
247 print 'found'
248 except ImportError:
249 print 'not found!'
250 print 'This module is now needed for Windows!'
251 print 'PyWin32 can be downloaded from <https://sourceforge.net/projects/pywin32/>'
252 sys.exit(1)
254 def run (self):
255 global skip_dependencies
256 self.build_message_files()
257 if not skip_dependencies:
258 self.check_requirements()
259 super(build_wammu, self).run()
261 class clean_wammu(distutils.command.clean.clean, object):
263 Custom clean command.
266 def run (self):
267 if self.all:
268 # remove share directory
269 directory = os.path.join('build', 'share')
270 if os.path.exists(directory):
271 distutils.dir_util.remove_tree(directory, dry_run=self.dry_run)
272 else:
273 distutils.log.warn('\'%s\' does not exist -- can\'t clean it',
274 directory)
275 super(clean_wammu, self).run()
277 class install_wammu(distutils.command.install.install, object):
279 Install wrapper to support option for skipping deps
282 user_options = distutils.command.install.install.user_options + [('skip-deps', 's', 'skip checking for dependencies')]
283 boolean_options = distutils.command.install.install.boolean_options + ['skip-deps']
285 def initialize_options(self):
286 global skip_dependencies
287 super(install_wammu, self).initialize_options()
288 self.skip_deps = skip_dependencies
290 def finalize_options(self):
291 global skip_dependencies
292 super(install_wammu, self).finalize_options()
293 if self.skip_deps:
294 skip_dependencies = self.skip_deps
296 class install_data_wammu(distutils.command.install_data.install_data, object):
298 Install locales in addition to regullar data.
301 def run (self):
303 Install also .mo files.
305 # add .mo files to data files
306 for (_src, _dst) in list_message_files(self.distribution.get_name()):
307 _build_dst = os.path.join('build', _dst)
308 item = [os.path.dirname(_dst), [_build_dst]]
309 self.data_files.append(item)
310 # install data files
311 super(install_data_wammu, self).run()
313 py2exepackages = ['Wammu']
314 if sys.version_info >= (2, 5):
315 # Email module changed a lot in python 2.5 and we can not yet use new API
316 py2exepackages.append('email')
317 py2exepackages.append('email.mime')
319 distutils.core.setup(name="wammu",
320 version = Wammu.__version__,
321 description = "Wammu",
322 long_description = "Phone manager built on top of python-gammu. Supports many phones.",
323 author = "Michal Čihař",
324 author_email = "michal@cihar.com",
325 maintainer = "Michal Čihař",
326 maintainer_email = "michal@cihar.com",
327 url = "http://wammu.eu/",
328 download_url = 'http://wammu.eu/download/',
329 license = "GPL",
330 classifiers = [
331 'Development Status :: 5 - Production/Stable',
332 'Environment :: Win32 (MS Windows)',
333 'Environment :: X11 Applications :: GTK',
334 'Intended Audience :: End Users/Desktop',
335 'License :: OSI Approved :: GNU General Public License (GPL)',
336 'Operating System :: Microsoft :: Windows :: Windows 95/98/2000',
337 'Operating System :: Microsoft :: Windows :: Windows NT/2000',
338 'Operating System :: POSIX',
339 'Operating System :: Unix',
340 'Programming Language :: Python',
341 'Topic :: Communications :: Telephony',
342 'Topic :: Office/Business :: Scheduling',
343 'Topic :: Utilities',
344 'Natural Language :: Afrikaans',
345 'Natural Language :: English',
346 'Natural Language :: Catalan',
347 'Natural Language :: Czech',
348 'Natural Language :: Dutch',
349 # 'Natural Language :: Estonian',
350 'Natural Language :: Finnish',
351 'Natural Language :: French',
352 'Natural Language :: German',
353 'Natural Language :: Hungarian',
354 'Natural Language :: Italian',
355 'Natural Language :: Korean',
356 'Natural Language :: Polish',
357 'Natural Language :: Portuguese (Brazilian)',
358 'Natural Language :: Russian',
359 'Natural Language :: Slovak',
360 'Natural Language :: Spanish',
361 'Natural Language :: Swedish',
363 packages = ['Wammu', 'Wammu.wxcomp'],
364 scripts = ['wammu.py'],
365 data_files = [
366 (os.path.join('share','Wammu','images','icons'), glob.glob('images/icons/*.png')),
367 (os.path.join('share','Wammu','images','misc'), glob.glob('images/misc/*.png')),
368 (os.path.join('share','applications'), ['wammu.desktop']),
369 (os.path.join('share','pixmaps'), ['icon/wammu.png', 'icon/wammu.xpm', 'icon/wammu.ico']),
370 (os.path.join('share','man','man1'), ['wammu.1'])
372 # Override certain command classes with our own ones
373 cmdclass = {
374 'build': build_wammu,
375 'build_scripts': build_scripts_wammu,
376 'clean': clean_wammu,
377 'install': install_wammu,
378 'install_data': install_data_wammu,
380 # py2exe options
381 options = {'py2exe': {
382 'optimize': 2,
383 'packages': py2exepackages,
385 windows = [
387 'script': 'wammu.py',
388 'icon_resources': [(1, 'icon/wammu.ico')],
391 zipfile = "shared.lib"