2 # -*- coding: UTF-8 -*-
3 # vim: expandtab sw=4 ts=4 sts=4:
6 Setup script for installation using distutils
8 __author__
= 'Michal Čihař'
9 __email__
= 'michal@cihar.com'
11 Copyright © 2003 - 2009 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
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
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
41 # Optional support for py2exe
49 PYTHONGAMMU_REQUIRED
= (0, 24)
50 WXPYTHON_REQUIRED
= (2, 6, 2, 0)
52 # check if Python is called on the first line with this expression
53 first_line_re
= re
.compile('^#!.*python[0-9.]*([ \t].*)?$')
55 class build_scripts_wammu(distutils
.command
.build_scripts
.build_scripts
, object):
57 This is mostly distutils copy, it just renames script according
58 to platform (.pyw for Windows, without extension for others)
60 def copy_scripts (self
):
61 """Copy each script listed in 'self.scripts'; if it's marked as a
62 Python script in the Unix way (first line matches 'first_line_re',
63 ie. starts with "\#!" and contains "python"), then adjust the first
64 line to refer to the current Python interpreter as we copy.
66 self
.mkpath(self
.build_dir
)
68 for script
in self
.scripts
:
70 script
= distutils
.util
.convert_path(script
)
71 outfile
= os
.path
.join(self
.build_dir
, os
.path
.splitext(os
.path
.basename(script
))[0])
72 if sys
.platform
== 'win32':
73 outfile
+= os
.extsep
+ 'pyw'
74 outfiles
.append(outfile
)
76 if not self
.force
and not distutils
.dep_util
.newer(script
, outfile
):
77 distutils
.log
.debug("not copying %s (up-to-date)", script
)
80 # Always open the file, but ignore failures in dry-run mode --
81 # that way, we'll get accurate feedback if we can read the
90 first_line
= f
.readline()
92 self
.warn("%s is an empty file (skipping)" % script
)
95 match
= first_line_re
.match(first_line
)
98 post_interp
= match
.group(1) or ''
101 distutils
.log
.info("copying and adjusting %s -> %s", script
,
104 outf
= open(outfile
, "w")
105 if not distutils
.sysconfig
.python_build
:
106 outf
.write("#!%s%s\n" %
107 (os
.path
.normpath(sys
.executable
),
110 outf
.write("#!%s%s\n" %
112 distutils
.sysconfig
.get_config_var("BINDIR"),
113 "python" + distutils
.sysconfig
.get_config_var("EXE")),
115 outf
.writelines(f
.readlines())
121 self
.copy_file(script
, outfile
)
123 if os
.name
== 'posix':
124 for file in outfiles
:
126 distutils
.log
.info("changing mode of %s", file)
128 oldmode
= os
.stat(file)[ST_MODE
] & 07777
129 newmode
= (oldmode |
0555) & 07777
130 if newmode
!= oldmode
:
131 distutils
.log
.info("changing mode of %s from %o to %o",
132 file, oldmode
, newmode
)
133 os
.chmod(file, newmode
)
137 def list_message_files(package
= 'wammu', suffix
= '.po'):
139 Return list of all found message files and their installation paths.
141 _files
= glob
.glob('locale/*/' + package
+ suffix
)
144 # basename (without extension) is a locale name
145 _locale
= os
.path
.basename(os
.path
.dirname(_file
))
146 _list
.append((_locale
, _file
, os
.path
.join(
147 'share', 'locale', _locale
, 'LC_MESSAGES', '%s.mo' % package
)))
150 class build_wammu(distutils
.command
.build
.build
, object):
152 Custom build command with locales support.
155 def build_message_files (self
):
157 For each locale/*.po, build .mo file in target locale directory.
159 As a side effect we build wammu.desktop file with updated
162 desktop_translations
= {}
163 for (_locale
, _src
, _dst
) in list_message_files():
164 _build_dst
= os
.path
.join('build', _dst
)
165 destdir
= os
.path
.dirname(_build_dst
)
166 if not os
.path
.exists(destdir
):
168 distutils
.log
.info('compiling %s -> %s' % (_src
, _build_dst
))
169 msgfmt
.make(_src
, _build_dst
)
170 desktop_translations
[_locale
] = msgfmt
.DESKTOP_TRANSLATIONS
172 desktop
= os
.path
.join('build', 'wammu.desktop')
173 in_desktop
= file('wammu.desktop.in', 'r')
174 out_desktop
= file(desktop
, 'w')
175 for line
in in_desktop
:
176 if line
.startswith('_Name'):
177 out_desktop
.write('Name=%s\n' % msgfmt
.DESKTOP_NAME
)
178 for loc
in desktop_translations
.keys():
179 if desktop_translations
[loc
].has_key('Name'):
180 out_desktop
.write('Name[%s]=%s\n' % (loc
, desktop_translations
[loc
]['Name']))
181 elif line
.startswith('_GenericName'):
182 out_desktop
.write('GenericName=%s\n' % msgfmt
.DESKTOP_GENERIC_NAME
)
183 for loc
in desktop_translations
.keys():
184 if desktop_translations
[loc
].has_key('GenericName'):
185 out_desktop
.write('GenericName[%s]=%s\n' % (loc
, desktop_translations
[loc
]['GenericName']))
186 elif line
.startswith('_Comment'):
187 out_desktop
.write('Comment=%s\n' % msgfmt
.DESKTOP_COMMENT
)
188 for loc
in desktop_translations
.keys():
189 if desktop_translations
[loc
].has_key('Comment'):
190 out_desktop
.write('Comment[%s]=%s\n' % (loc
, desktop_translations
[loc
]['Comment']))
192 out_desktop
.write(line
)
195 def check_requirements(self
):
196 print 'Checking for python-gammu ...',
199 version
= gammu
.Version()
200 print 'found version %s using Gammu %s ...' % (version
[1], version
[0]),
202 pygver
= tuple(map(int, version
[1].split('.')))
203 if pygver
< PYTHONGAMMU_REQUIRED
:
205 print 'You need python-gammu at least %s!' % '.'.join(map(str, PYTHONGAMMU_REQUIRED
))
206 print 'You can get it from <http://cihar.com/gammu/python/>'
209 except ImportError, message
:
211 print 'Could not import python-gammu!'
212 print 'You can get it from <http://cihar.com/gammu/python/>'
213 print 'Import failed with following error: %s' % message
215 print 'Checking for wxPython ...',
218 print 'found version %s ...' % wx
.VERSION_STRING
,
219 if wx
.VERSION
< WXPYTHON_REQUIRED
:
221 print 'You need at least wxPython %s!' % '.'.join(map(str, WXPYTHON_REQUIRED
))
222 print 'You can get it from <http://www.wxpython.org>'
223 elif not wx
.USE_UNICODE
:
225 print 'You need at least wxPython %s with unicode enabled!' % '.'.join(map(str, WXPYTHON_REQUIRED
))
226 print 'You can get it from <http://www.wxpython.org>'
231 print 'You need wxPython!'
232 print 'You can get it from <http://www.wxpython.org>'
234 print 'Checking for Bluetooth stack ...',
240 print 'WARNING: PyBluez not found, without it you can not search for bluetooth devices'
241 print 'PyBluez can be downloaded from <http://org.csail.mit.edu/pybluez/>'
243 print 'Checking for xml stack ...',
249 print 'python-xml not found!'
251 if sys
.platform
== 'win32':
252 print 'Checking for PyWin32 ...',
254 import win32file
, win32com
, win32api
258 print 'This module is now needed for Windows!'
259 print 'PyWin32 can be downloaded from <https://sourceforge.net/projects/pywin32/>'
263 self
.build_message_files()
264 self
.check_requirements()
265 super(build_wammu
, self
).run()
267 class clean_wammu(distutils
.command
.clean
.clean
, object):
269 Custom clean command.
274 # remove share directory
275 directory
= os
.path
.join('build', 'share')
276 if os
.path
.exists(directory
):
277 distutils
.dir_util
.remove_tree(directory
, dry_run
=self
.dry_run
)
279 distutils
.log
.warn('\'%s\' does not exist -- can\'t clean it',
281 super(clean_wammu
, self
).run()
283 class install_data_wammu(distutils
.command
.install_data
.install_data
, object):
285 Install locales in addition to regullar data.
290 Install also .mo files.
292 # add .mo files to data files
293 for (_locale
, _src
, _dst
) in list_message_files():
294 _build_dst
= os
.path
.join('build', _dst
)
295 item
= [os
.path
.dirname(_dst
), [_build_dst
]]
296 self
.data_files
.append(item
)
299 super(install_data_wammu
, self
).run()
301 py2exepackages
= ['Wammu']
302 if sys
.version_info
>= (2, 5):
303 # Email module changed a lot in python 2.5 and we can not yet use new API
304 py2exepackages
.append('email')
305 py2exepackages
.append('email.mime')
307 # ModuleFinder can't handle runtime changes to __path__, but win32com uses them
309 # if this doesn't work, try import modulefinder
310 import py2exe
.mf
as modulefinder
312 for p
in win32com
.__path
__[1:]:
313 modulefinder
.AddPackagePath("win32com", p
)
314 for extra
in ["win32com.shell"]: #,"win32com.mapi"
316 m
= sys
.modules
[extra
]
317 for p
in m
.__path
__[1:]:
318 modulefinder
.AddPackagePath(extra
, p
)
320 # no build path setup, no worries.
326 addparams
['windows'] = [
328 'script': 'wammu.py',
329 'icon_resources': [(1, 'icon/wammu.ico')],
332 addparams
['zipfile'] = 'shared.lib'
335 (os
.path
.join('share','Wammu','images','icons'), glob
.glob('images/icons/*.png')),
336 (os
.path
.join('share','Wammu','images','misc'), glob
.glob('images/misc/*.png')),
339 if sys
.platform
!= 'win32':
340 data_files
.append((os
.path
.join('share','applications'), ['build/wammu.desktop']))
342 data_files
.append((os
.path
.join('share','pixmaps'), [
348 data_files
.append((os
.path
.join('share','man','man1'), ['wammu.1', 'wammu-configure.1']))
350 distutils
.core
.setup(name
="wammu",
351 version
= Wammu
.__version
__,
352 description
= "Wammu Mobile Phone Manager",
353 long_description
= "Phone manager built on top of python-gammu. Supports many phones.",
354 author
= u
"Michal Cihar",
355 author_email
= "michal@cihar.com",
356 maintainer
= u
"Michal Cihar",
357 maintainer_email
= "michal@cihar.com",
358 platforms
= ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME'],
359 keywords
= ['mobile', 'phone', 'SMS', 'contact', 'gammu', 'calendar', 'todo'],
360 url
= "http://wammu.eu/",
361 download_url
= 'http://wammu.eu/download/',
364 'Development Status :: 5 - Production/Stable',
365 'Environment :: Win32 (MS Windows)',
366 'Environment :: X11 Applications :: GTK',
367 'Intended Audience :: End Users/Desktop',
368 'License :: OSI Approved :: GNU General Public License (GPL)',
369 'Operating System :: Microsoft :: Windows :: Windows 95/98/2000',
370 'Operating System :: Microsoft :: Windows :: Windows NT/2000',
371 'Operating System :: POSIX',
372 'Operating System :: Unix',
373 'Programming Language :: Python',
374 'Topic :: Communications :: Telephony',
375 'Topic :: Office/Business :: Scheduling',
376 'Topic :: Utilities',
377 'Natural Language :: English',
378 'Natural Language :: Afrikaans',
379 'Natural Language :: Catalan',
380 'Natural Language :: Czech',
381 'Natural Language :: German',
382 'Natural Language :: Greek',
383 'Natural Language :: Spanish',
384 'Natural Language :: Estonian',
385 'Natural Language :: Finnish',
386 'Natural Language :: French',
387 'Natural Language :: Galician',
388 'Natural Language :: Hebrew',
389 'Natural Language :: Hungarian',
390 'Natural Language :: Indonesian',
391 'Natural Language :: Italian',
392 'Natural Language :: Korean',
393 'Natural Language :: Dutch',
394 'Natural Language :: Polish',
395 'Natural Language :: Portuguese (Brazilian)',
396 'Natural Language :: Russian',
397 'Natural Language :: Slovak',
398 'Natural Language :: Swedish',
399 'Natural Language :: Chinese (Simplified)',
400 'Natural Language :: Chinese (Traditional)',
402 packages
= ['Wammu'],
403 scripts
= ['wammu.py', 'wammu-configure.py'],
404 data_files
= data_files
,
405 # Override certain command classes with our own ones
407 'build': build_wammu
,
408 'build_scripts': build_scripts_wammu
,
409 'clean': clean_wammu
,
410 'install_data': install_data_wammu
,
413 options
= {'py2exe': {
415 'packages': py2exepackages
,