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