[FIX] setup.py: add the missing librairies for the windows packaging
[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     ('yaml', 'YAML parser and emitter for Python'),
63 ]
64
65 def check_modules():
66     errors = []
67     for modname, desc in required_modules:
68         try:
69             imp.find_module(modname)
70         except ImportError:
71             errors.append(
72                 'Error: python module %s (%s) is required' % (modname, desc))
73
74     if errors:
75         print '\n'.join(errors)
76         sys.exit(1)
77
78 def find_addons():
79     for root, _, names in os.walk(join('bin', 'addons')):
80         if '__openerp__.py' in names or '__terp__.py' in names:
81             yield basename(root), root
82     #look for extra modules
83     try:
84         empath = os.getenv('EXTRA_MODULES_PATH', '../addons/')
85         for mname in open(join(empath, 'server_modules.list')):
86             mname = mname.strip()
87             if not mname:
88                 continue
89
90             terp = join(empath, mname, '__openerp__.py')
91             if not os.path.exists(terp):
92                 terp = join(empath, mname, '__terp__.py')
93
94             if os.path.exists(terp):
95                 yield mname, join(empath, mname)
96             else:
97                 print "Module %s specified, but no valid path." % mname
98     except:
99         pass
100
101 def data_files():
102     '''Build list of data files to be installed'''
103     files = []
104     if os.name == 'nt':
105         for root, _, names in os.walk(join('bin','addons')):
106             files.append((root, [join(root, name) for name in names]))
107         for root, _, names in os.walk('doc'):
108             files.append((root, [join(root, name) for name in names]))
109         files.append(('.', [join('bin', 'import_xml.rng'),
110                             join('bin', 'server.pkey'),
111                             join('bin', 'server.cert')]))
112     else:
113         man_directory = join('share', 'man')
114         files.append((join(man_directory, 'man1'), ['man/openerp-server.1']))
115         files.append((join(man_directory, 'man5'), ['man/openerp_serverrc.5']))
116
117         doc_directory = join('share', 'doc', 'openerp-server-%s' % version)
118         files.append((doc_directory, filter(isfile, glob.glob('doc/*'))))
119         files.append((join(doc_directory, 'migrate', '3.3.0-3.4.0'),
120                       filter(isfile, glob.glob('doc/migrate/3.3.0-3.4.0/*'))))
121         files.append((join(doc_directory, 'migrate', '3.4.0-4.0.0'),
122                       filter(isfile, glob.glob('doc/migrate/3.4.0-4.0.0/*'))))
123
124         openerp_site_packages = join('lib', 'python%s' % py_short_version, 'site-packages', 'openerp-server')
125
126         files.append((openerp_site_packages, [join('bin', 'import_xml.rng'),
127                                               join('bin', 'server.pkey'),
128                                               join('bin', 'server.cert')]))
129
130         if sys.version_info[0:2] == (2,5):
131             files.append((openerp_site_packages, [ join('python25-compat','BaseHTTPServer.py'),
132                                                    join('python25-compat','SimpleXMLRPCServer.py'),
133                                                    join('python25-compat','SocketServer.py')]))
134
135         for addonname, add_path in find_addons():
136             addon_path = join('lib', 'python%s' % py_short_version, 'site-packages', 'openerp-server','addons', addonname)
137             for root, dirs, innerfiles in os.walk(add_path):
138                 innerfiles = filter(lambda fil: os.path.splitext(fil)[1] not in ('.pyc', '.pyd', '.pyo'), innerfiles)
139                 if innerfiles:
140                     res = os.path.normpath(join(addon_path, root.replace(join(add_path), '.')))
141                     files.extend(((res, map(lambda fil: join(root, fil),
142                                             innerfiles)),))
143
144     return files
145
146 if not os.getenv('NO_CHECK_MODULES') :
147     check_modules()
148
149 f = file('openerp-server','w')
150 f.write("""#!/bin/sh
151 echo "Error: the content of this file should have been replaced during "
152 echo "installation\n"
153 exit 1
154 """)
155 f.close()
156
157 def find_package_dirs():
158     package_dirs = {'openerp-server': 'bin'}
159     for mod, path in find_addons():
160         package_dirs['openerp-server.addons.' + mod] = path
161     return package_dirs
162
163 class openerp_server_install(install):
164     def run(self):
165         # create startup script
166         start_script = "#!/bin/sh\ncd %s\nexec %s ./openerp-server.py $@\n"\
167             % (join(self.install_libbase, "openerp-server"), sys.executable)
168         # write script
169         f = open('openerp-server', 'w')
170         f.write(start_script)
171         f.close()
172         install.run(self)
173
174 options = {
175     "py2exe": {
176         "compressed": 1,
177         "optimize": 2,
178         "dist_dir": 'dist',
179         "packages": [
180                  "lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
181                  "lxml.objectify", "decimal", "xml", "xml", "xml.dom", "xml.xpath",
182                  "encodings", "dateutil", "wizard", "pychart", "PIL", "pyparsing",
183                  "pydot", "asyncore","asynchat", "reportlab", "vobject",
184                  "HTMLParser", "select", "libxslt", "libxml2", "mako", "poplib",
185                  "imaplib", "smtplib", "email", "yaml",
186                  ],
187         "excludes" : ["Tkconstants","Tkinter","tcl"],
188     }
189 }
190
191 setup(name             = name,
192       version          = version,
193       description      = description,
194       long_description = long_desc,
195       url              = url,
196       author           = author,
197       author_email     = author_email,
198       classifiers      = filter(None, classifiers.split("\n")),
199       license          = license,
200       data_files       = data_files(),
201       cmdclass         = {
202             'install' : openerp_server_install,
203       },
204       scripts          = ['openerp-server'],
205       packages         = ['openerp-server',
206                           'openerp-server.addons',
207                           'openerp-server.ir',
208                           'openerp-server.osv',
209                           'openerp-server.pychart',
210                           'openerp-server.pychart.afm',
211                           'openerp-server.report',
212                           'openerp-server.report.printscreen',
213                           'openerp-server.report.pyPdf',
214                           'openerp-server.report.render',
215                           'openerp-server.report.render.html2html',
216                           'openerp-server.report.render.makohtml2html',
217                           'openerp-server.report.render.odt2odt',
218                           'openerp-server.report.render.rml2html',
219                           'openerp-server.report.render.rml2pdf',
220                           'openerp-server.report.render.rml2txt',
221                           'openerp-server.service',
222                           'openerp-server.tools',
223                           'openerp-server.wizard',
224                           'openerp-server.workflow'] + \
225                           [('openerp-server.addons.' + name)
226                            for name, _ in find_addons()],
227       package_dir      = find_package_dirs(),
228       console = [{"script": join("bin", "openerp-server.py"),
229                   "icon_resources": [(1,join("pixmaps","openerp-icon.ico"))]
230                   }],
231       options = options,
232       )
233
234 if has_py2exe:
235   # Sometime between pytz-2008a and pytz-2008i common_timezones started to
236   # include only names of zones with a corresponding data file in zoneinfo.
237   # pytz installs the zoneinfo directory tree in the same directory
238   # as the pytz/__init__.py file. These data files are loaded using
239   # pkg_resources.resource_stream. py2exe does not copy this to library.zip so
240   # resource_stream can't find the files and common_timezones is empty when
241   # read in the py2exe executable.
242   # This manually copies zoneinfo into the zip. See also
243   # http://code.google.com/p/googletransitdatafeed/issues/detail?id=121
244   import pytz
245   import zipfile
246   # Make sure the layout of pytz hasn't changed
247   assert (pytz.__file__.endswith('__init__.pyc') or
248           pytz.__file__.endswith('__init__.py')), pytz.__file__
249   zoneinfo_dir = join(os.path.dirname(pytz.__file__), 'zoneinfo')
250   # '..\\Lib\\pytz\\__init__.py' -> '..\\Lib'
251   disk_basedir = os.path.dirname(os.path.dirname(pytz.__file__))
252   zipfile_path = join(options['py2exe']['dist_dir'], 'library.zip')
253   z = zipfile.ZipFile(zipfile_path, 'a')
254   for absdir, directories, filenames in os.walk(zoneinfo_dir):
255     assert absdir.startswith(disk_basedir), (absdir, disk_basedir)
256     zip_dir = absdir[len(disk_basedir):]
257     for f in filenames:
258       z.write(join(absdir, f), join(zip_dir, f))
259   z.close()
260