remove xml.* dependencies in py2exe packages list
[odoo/odoo.git] / setup.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 ##############################################################################
4 #
5 #    OpenERP, Open Source Management Solution
6 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU Affero General Public License as
10 #    published by the Free Software Foundation, either version 3 of the
11 #    License, or (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU Affero General Public License for more details.
17 #
18 #    You should have received a copy of the GNU Affero General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 # setup from TinERP
24 #   taken from straw http://www.nongnu.org/straw/index.html
25 #   taken from gnomolicious http://www.nongnu.org/gnomolicious/
26 #   adapted by Nicolas Évrard <nicoe@altern.org>
27 #
28
29 import imp
30 import sys
31 import os
32 from os.path import join, isfile, basename
33 import glob
34
35 from distutils.core import setup, Command
36 from distutils.command.install import install
37
38 has_py2exe = False
39 if os.name == 'nt':
40     import py2exe
41     has_py2exe = True
42
43 sys.path.append(join(os.path.abspath(os.path.dirname(__file__)), "bin"))
44
45 execfile(join('bin', 'release.py'))
46
47 if sys.argv[1] == 'bdist_rpm':
48     version = version.split('-')[0]
49
50 # get python short version
51 py_short_version = '%s.%s' % sys.version_info[:2]
52
53 required_modules = [
54     ('lxml', 'lxml module: pythonic libxml2 and libxslt bindings'),
55     ('mako', 'Mako template engine'),
56     ('dateutil', "Extensions to the standard datetime module"),
57     ('psycopg2', 'PostgreSQL module'),
58     ('pychart', 'pychart module'),
59     ('pydot', 'pydot module'),
60     ('pytz', 'Timezone handling library for Python'),
61     ('reportlab', 'reportlab module'),
62 ]
63
64 def check_modules():
65     errors = []
66     for modname, desc in required_modules:
67         try:
68             imp.find_module(modname)
69         except ImportError:
70             errors.append(
71                 'Error: python module %s (%s) is required' % (modname, desc))
72
73     if errors:
74         print '\n'.join(errors)
75         sys.exit(1)
76
77 def find_addons():
78     for root, _, names in os.walk(join('bin', 'addons')):
79         if '__terp__.py' in names:
80             yield basename(root), root
81     #look for extra modules
82     try:
83         empath = os.getenv('EXTRA_MODULES_PATH', '../addons/')
84         for mname in open(join(empath, 'server_modules.list')):
85             mname = mname.strip()
86             if not mname:
87                 continue
88             if os.path.exists(join(empath, mname, '__terp__.py')):
89                 yield mname, join(empath, mname)
90             else:
91                 print "Module %s specified, but no valid path." % mname
92     except:
93         pass
94
95 def data_files():
96     '''Build list of data files to be installed'''
97     files = []
98     if os.name == 'nt':
99         for root, _, names in os.walk(join('bin','addons')):
100             files.append((root, [join(root, name) for name in names]))
101         for root, _, names in os.walk('doc'):
102             files.append((root, [join(root, name) for name in names]))
103         files.append(('.', [join('bin', 'import_xml.rng'),
104                             join('bin', 'server.pkey'),
105                             join('bin', 'server.cert')]))
106     else:
107         man_directory = join('share', 'man')
108         files.append((join(man_directory, 'man1'), ['man/openerp-server.1']))
109         files.append((join(man_directory, 'man5'), ['man/openerp_serverrc.5']))
110
111         doc_directory = join('share', 'doc', 'openerp-server-%s' % version)
112         files.append((doc_directory, filter(isfile, glob.glob('doc/*'))))
113         files.append((join(doc_directory, 'migrate', '3.3.0-3.4.0'),
114                       filter(isfile, glob.glob('doc/migrate/3.3.0-3.4.0/*'))))
115         files.append((join(doc_directory, 'migrate', '3.4.0-4.0.0'),
116                       filter(isfile, glob.glob('doc/migrate/3.4.0-4.0.0/*'))))
117
118         openerp_site_packages = join('lib', 'python%s' % py_short_version, 'site-packages', 'openerp-server')
119
120         files.append((openerp_site_packages, [join('bin', 'import_xml.rng'),
121                                               join('bin', 'server.pkey'),
122                                               join('bin', 'server.cert')]))
123
124         if sys.version_info[0:2] == (2,5):
125             files.append((openerp_site_packages, [ join('python25-compat','BaseHTTPServer.py'),
126                                                    join('python25-compat','SimpleXMLRPCServer.py'),
127                                                    join('python25-compat','SocketServer.py')]))
128
129         for addonname, add_path in find_addons():
130             addon_path = join('lib', 'python%s' % py_short_version, 'site-packages', 'openerp-server','addons', addonname)
131             for root, dirs, innerfiles in os.walk(add_path):
132                 innerfiles = filter(lambda fil: os.path.splitext(fil)[1] not in ('.pyc', '.pyd', '.pyo'), innerfiles)
133                 if innerfiles:
134                     res = os.path.normpath(join(addon_path, root.replace(join(add_path), '.')))
135                     files.extend(((res, map(lambda fil: join(root, fil),
136                                             innerfiles)),))
137
138     return files
139
140 if not os.getenv('NO_CHECK_MODULES') :
141     check_modules()
142
143 f = file('openerp-server','w')
144 f.write("""#!/bin/sh
145 echo "Error: the content of this file should have been replaced during "
146 echo "installation\n"
147 exit 1
148 """)
149 f.close()
150
151 def find_package_dirs():
152     package_dirs = {'openerp-server': 'bin'}
153     for mod, path in find_addons():
154         package_dirs['openerp-server.addons.' + mod] = path
155     return package_dirs
156
157 class openerp_server_install(install):
158     def run(self):
159         # create startup script
160         start_script = "#!/bin/sh\ncd %s\nexec %s ./openerp-server.py $@\n"\
161             % (join(self.install_libbase, "openerp-server"), sys.executable)
162         # write script
163         f = open('openerp-server', 'w')
164         f.write(start_script)
165         f.close()
166         install.run(self)
167
168 options = {
169     "py2exe": {
170         "compressed": 1,
171         "optimize": 2,
172         "dist_dir": 'dist',
173         "packages": ["lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
174                      "lxml.objectify", "decimal", "xml", "encodings",
175                      "dateutil", "wizard", "pychart", "PIL", "pyparsing",
176                      "pydot", "asyncore","asynchat", "reportlab", "vobject",
177                      "HTMLParser", "select"],
178         "excludes" : ["Tkconstants","Tkinter","tcl"],
179     }
180 }
181
182 setup(name             = name,
183       version          = version,
184       description      = description,
185       long_description = long_desc,
186       url              = url,
187       author           = author,
188       author_email     = author_email,
189       classifiers      = filter(None, classifiers.split("\n")),
190       license          = license,
191       data_files       = data_files(),
192       cmdclass         = {
193             'install' : openerp_server_install,
194       },
195       scripts          = ['openerp-server'],
196       packages         = ['openerp-server',
197                           'openerp-server.addons',
198                           'openerp-server.ir',
199                           'openerp-server.osv',
200                           'openerp-server.pychart',
201                           'openerp-server.pychart.afm',
202                           'openerp-server.report',
203                           'openerp-server.report.printscreen',
204                           'openerp-server.report.pyPdf',
205                           'openerp-server.report.render',
206                           'openerp-server.report.render.html2html',
207                           'openerp-server.report.render.makohtml2html',
208                           'openerp-server.report.render.odt2odt',
209                           'openerp-server.report.render.rml2html',
210                           'openerp-server.report.render.rml2pdf',
211                           'openerp-server.report.render.rml2txt',
212                           'openerp-server.service',
213                           'openerp-server.tools',
214                           'openerp-server.wizard',
215                           'openerp-server.workflow'] + \
216                           [('openerp-server.addons.' + name)
217                            for name, _ in find_addons()],
218       package_dir      = find_package_dirs(),
219       console = [{"script": join("bin", "openerp-server.py"),
220                   "icon_resources": [(1,join("pixmaps","openerp-icon.ico"))]
221                   }],
222       options = options,
223       )
224
225 if has_py2exe:
226   # Sometime between pytz-2008a and pytz-2008i common_timezones started to
227   # include only names of zones with a corresponding data file in zoneinfo.
228   # pytz installs the zoneinfo directory tree in the same directory
229   # as the pytz/__init__.py file. These data files are loaded using
230   # pkg_resources.resource_stream. py2exe does not copy this to library.zip so
231   # resource_stream can't find the files and common_timezones is empty when
232   # read in the py2exe executable.
233   # This manually copies zoneinfo into the zip. See also
234   # http://code.google.com/p/googletransitdatafeed/issues/detail?id=121
235   import pytz
236   import zipfile
237   # Make sure the layout of pytz hasn't changed
238   assert (pytz.__file__.endswith('__init__.pyc') or
239           pytz.__file__.endswith('__init__.py')), pytz.__file__
240   zoneinfo_dir = join(os.path.dirname(pytz.__file__), 'zoneinfo')
241   # '..\\Lib\\pytz\\__init__.py' -> '..\\Lib'
242   disk_basedir = os.path.dirname(os.path.dirname(pytz.__file__))
243   zipfile_path = join(options['py2exe']['dist_dir'], 'library.zip')
244   z = zipfile.ZipFile(zipfile_path, 'a')
245   for absdir, directories, filenames in os.walk(zoneinfo_dir):
246     assert absdir.startswith(disk_basedir), (absdir, disk_basedir)
247     zip_dir = absdir[len(disk_basedir):]
248     for f in filenames:
249       z.write(join(absdir, f), join(zip_dir, f))
250   z.close()
251