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