[IMP] Do not send scheduler mails to support email
[cds-indico.git] / setup.py
blob06f92d676efff7cf4588ffe2136d122c7f68d2a4
1 # -*- coding: utf-8 -*-
2 ##
3 ##
4 ## This file is part of Indico
5 ## Copyright (C) 2002 - 2013 European Organization for Nuclear Research (CERN)
6 ##
7 ## Indico is free software: you can redistribute it and/or
8 ## modify it under the terms of the GNU General Public License as
9 ## published by the Free Software Foundation, either version 3 of the
10 ## License, or (at your option) any later version.
12 ## Indico is distributed in the hope that it will be useful, but
13 ## WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ## GNU General Public License for more details.
17 ## You should have received a copy of the GNU General Public License
18 ## along with Indico. If not, see <http://www.gnu.org/licenses/>.
20 # Autoinstalls setuptools if the user doesn't have them already
21 import ez_setup
22 ez_setup.use_setuptools()
24 import commands
25 import getopt
26 import os
27 import re
28 import shutil
29 import string
30 import sys
31 import itertools
32 from distutils.sysconfig import get_python_lib, get_python_version
33 from distutils.cmd import Command
34 from distutils.command import bdist
35 from indico.util import i18n
38 import pkg_resources
39 from setuptools.command import develop, install, sdist, bdist_egg, \
40 easy_install, test
41 from setuptools import setup, find_packages, findall
44 try:
45 from babel.messages import frontend as babel
46 BABEL_PRESENT = True
47 except ImportError:
48 BABEL_PRESENT = False
51 DEPENDENCY_URLS = ["http://indico-software.org/wiki/Admin/Installation/IndicoExtras"]
53 DEVELOP_REQUIRES = ['pojson>=0.4', 'termcolor']
55 if sys.platform == 'linux2':
56 import pwd
57 import grp
60 class vars(object):
61 '''Variable holder.'''
62 packageDir = None
63 versionVal = 'None'
64 accessuser = None
65 accessgroup = None
66 dbInstalledBySetupPy = False
67 binDir = None
68 documentationDir = None
69 configurationDir = None
70 htdocsDir = None
73 ### Methods required by setup() ##############################################
75 def _generateDataPaths(x):
77 dataFilesDict = {}
79 for (baseDstDir, srcDir) in x:
80 for f in findall(srcDir):
81 dst_dir = os.path.join(baseDstDir,
82 os.path.relpath(os.path.dirname(f), srcDir))
83 if dst_dir not in dataFilesDict:
84 dataFilesDict[dst_dir] = []
85 dataFilesDict[dst_dir].append(f)
87 dataFiles = []
88 for k, v in dataFilesDict.items():
89 dataFiles.append((k, v))
91 return dataFiles
94 def _getDataFiles(x):
95 """
96 Returns a fully populated data_files ready to be fed to setup()
98 WARNING: when creating a bdist_egg we need to include files inside bin,
99 doc, config & htdocs into the egg therefore we cannot fetch indico.conf
100 values directly because they will not refer to the proper place. We
101 include those files in the egg's root folder.
104 # setup expects a list like this (('foo/bar/baz', 'wiki.py'),
105 # ('a/b/c', 'd.jpg'))
107 # What we do below is transform a list like this:
108 # (('foo', 'bar/baz/wiki.py'),
109 # ('a', 'b/c/d.jpg'))
111 # first into a dict and then into a pallatable form for setuptools.
113 # This re will be used to filter out etc/*.conf files and therefore not overwritting them
114 dataFiles = _generateDataPaths((('bin', 'bin'),
115 ('doc', 'doc'),
116 ('etc', 'etc')))
117 return dataFiles
120 def _getInstallRequires():
121 '''Returns external packages required by Indico
123 These are the ones needed for runtime.'''
125 base = ['ZODB3==3.10.5', 'zope.index', 'zope.interface',
126 'pytz', 'lxml', 'cds-indico-extras', 'zc.queue',
127 'python-dateutil<2.0', 'pypdf', 'mako>=0.4.1', 'babel',
128 'icalendar>=3.2', 'pyatom', 'jsmin', 'cssmin', 'webassets', 'pojson>=0.4',
129 'requests', 'simplejson>=2.1.0', 'reportlab']
131 #for Python older than 2.7
132 if sys.version_info[0] <= 2 and sys.version_info[1] < 7:
133 base.append('argparse')
135 return base
138 def _versionInit():
139 '''Retrieves the version number from indico/MaKaC/__init__.py and returns it'''
141 from indico.MaKaC import __version__
142 v = __version__
144 print('Indico %s' % v)
146 return v
149 ### Commands ###########################################################
150 class sdist_indico(sdist.sdist):
151 user_options = (sdist.sdist.user_options +
152 [('version=', None, 'version to distribute')])
153 version = 'dev'
155 def run(self):
156 sdist.sdist.run(self)
159 def _bdist_indico(dataFiles):
160 class bdist_indico(bdist.bdist):
161 def run(self):
162 compileAllLanguages(self)
163 bdist.bdist.run(self)
165 bdist_indico.dataFiles = dataFiles
166 return bdist_indico
169 def _bdist_egg_indico(dataFiles):
170 class bdist_egg_indico(bdist_egg.bdist_egg):
171 def run(self):
172 compileAllLanguages(self)
173 bdist_egg.bdist_egg.run(self)
175 bdist_egg_indico.dataFiles = dataFiles
176 return bdist_egg_indico
179 class develop_indico(develop.develop):
180 def run(self):
181 develop.develop.run(self)
183 # create symlink to legacy MaKaC dir
184 # this is so that the ".egg-link" created by the "develop" command works
185 if sys.platform in ["linux2", "darwin"] and not os.path.exists('MaKaC'):
186 os.symlink('indico/MaKaC', 'MaKaC')
189 class develop_config(develop_indico):
190 description = "prepares the current directory for Indico development"
191 user_options = (develop.develop.user_options +
192 [('www-uid=', None, "Set user for cache/log/db (typically apache user)"),
193 ('www-gid=', None, "Set group for cache/log/db (typically apache group)")])
195 www_uid = None
196 www_gid = None
198 def run(self):
199 # dependencies, links, etc...
200 develop_indico.run(self)
202 env = pkg_resources.Environment()
203 easy_install.main(DEVELOP_REQUIRES)
204 env.scan()
206 local = 'etc/indico.conf'
207 if os.path.exists(local):
208 print 'Upgrading existing etc/indico.conf..'
209 upgrade_indico_conf(local, 'etc/indico.conf.sample')
210 else:
211 print 'Creating new etc/indico.conf..'
212 shutil.copy('etc/indico.conf.sample', local)
214 for f in [x for x in ('etc/zdctl.conf', 'etc/zodb.conf', 'etc/logging.conf') if not os.path.exists(x)]:
215 shutil.copy('%s.sample' % f, f)
217 print """\nIndico needs to store some information in the filesystem (database, cache, temporary files, logs...)
218 Please specify the directory where you'd like it to be placed.
219 (Note that putting it outside of your sourcecode tree is recommended)"""
220 prefixDirDefault = os.path.dirname(os.getcwd())
221 prefixDir = raw_input('[%s]: ' % prefixDirDefault).strip()
223 if prefixDir == '':
224 prefixDir = prefixDirDefault
226 directories = dict((d, os.path.join(prefixDir, d)) for d in
227 ['db', 'log', 'tmp', 'cache', 'archive'])
229 print 'Creating directories...',
230 for d in directories.values():
231 if not os.path.exists(d):
232 os.makedirs(d)
233 print 'Done!'
235 directories['htdocs'] = os.path.join(os.getcwd(), 'indico', 'htdocs')
236 directories['bin'] = os.path.join(os.getcwd(), 'bin')
237 directories['etc'] = os.path.join(os.getcwd(), 'etc')
238 directories['doc'] = os.path.join(os.getcwd(), 'doc')
240 self._update_conf_dir_paths(local, directories)
242 # avoid modifying the htdocs folder permissions (it brings problems with git)
243 directories.pop('htdocs')
245 from MaKaC.consoleScripts.installBase import _databaseText, _findApacheUserGroup, _checkDirPermissions, \
246 _updateDbConfigFiles, _updateMaKaCEggCache
248 user = ''
250 sourcePath = os.getcwd()
252 # find the apache user/group
253 user, group = _findApacheUserGroup(self.www_uid, self.www_gid)
254 _checkDirPermissions(directories, dbInstalledBySetupPy=directories['db'], accessuser=user, accessgroup=group)
256 _updateDbConfigFiles(directories['db'], directories['log'], os.path.join(sourcePath, 'etc'),
257 directories['tmp'], user)
259 _updateMaKaCEggCache(os.path.join(os.path.dirname(__file__), 'indico', 'MaKaC', '__init__.py'),
260 directories['tmp'])
262 updateIndicoConfPathInsideMaKaCConfig(os.path.join(os.path.dirname(__file__), ''),
263 'indico/MaKaC/common/MaKaCConfig.py')
264 compileAllLanguages(self)
265 print '''
267 ''' % _databaseText('etc')
269 def _update_conf_dir_paths(self, filePath, dirs):
270 fdata = open(filePath).read()
271 for dir in dirs.items():
272 d = dir[1].replace("\\", "/") # For Windows users
273 fdata = re.sub('\/opt\/indico\/%s' % dir[0], d, fdata)
274 open(filePath, 'w').write(fdata)
277 class test_indico(test.test):
279 Test command for Indico
282 description = "Test Suite Framework"
283 user_options = (test.test.user_options + [('specify=', None, "Use nosetests style (file.class:testcase)"),
284 ('coverage', None, "Output coverage report in html"),
285 ('unit', None, "Run only Unit tests"),
286 ('functional', None, "Run only Functional tests"),
287 ('pylint', None, "Run python source analysis"),
288 ('jsunit', None, "Run js unit tests"),
289 ('jslint', None, "Run js source analysis"),
290 ('jscoverage', None, "Output coverage report in html for js"),
291 ('jsspecify=', None, "Use js-test-driver style (TestCaseName.testName)"),
292 ('log=', None, "Log to console, using specified level"),
293 ('browser=', None, "Browser to use for functional tests"),
294 ('mode=', None, "Mode to use for functional tests"),
295 ('server-url=', None, "Server URL to use for functional tests"),
296 ('xml', None, "XML output"),
297 ('html', None, "Make an HTML report (when possible)"),
298 ('record', None, "Record tests (for --functional)"),
299 ('silent', None, "Don't output anything in the console, just generate the report"),
300 ('killself', None,
301 "Kill this script right after the tests finished without waiting for db shutdown.")])
302 boolean_options = []
304 specify = None
305 coverage = False
306 unit = False
307 functional = False
308 browser = None
309 pylint = False
310 jsunit = False
311 jslint = False
312 jscoverage = False
313 jsspecify = None
314 silent = False
315 mode = None
316 server_url = None
317 killself = False
318 html = False
319 record = False
320 log = False
321 xml = False
323 def _wrap(self, func, *params):
324 def wrapped():
325 self.res = func(*params)
326 self.with_project_on_sys_path(wrapped)
327 return self.res
329 def finalize_options(self):
330 testsToRun = []
332 allTests = ['unit', 'functional']
334 for testType in allTests:
335 if getattr(self, testType):
336 testsToRun.append(testType)
338 if self.jsspecify and 'jsunit' not in testsToRun:
339 testsToRun.append('jsunit')
341 if testsToRun == []:
342 testsToRun = allTests
343 self.testsToRun = testsToRun
345 def run(self):
347 if self.distribution.install_requires:
348 self.distribution.fetch_build_eggs(self.distribution.install_requires)
349 if self.distribution.tests_require:
350 self.distribution.fetch_build_eggs(self.distribution.tests_require)
352 from indico.tests import TestManager
354 options = {'silent': self.silent,
355 'killself': self.killself,
356 'html': self.html,
357 'browser': self.browser,
358 'mode': self.mode,
359 'specify': self.specify,
360 'coverage': self.coverage,
361 'record': self.record,
362 'server_url': self.server_url,
363 'log': self.log,
364 'xml': self.xml}
366 # get only options that are active
367 options = dict((k, v) for (k, v) in options.iteritems() if v)
369 manager = TestManager()
370 result = self._wrap(manager.main, self.testsToRun, options)
372 sys.exit(result)
374 def download(self, url, path):
375 """Copy the contents of a file from a given URL
376 to a local file.
378 import urllib
379 webFile = urllib.urlopen(url)
380 localFile = open(os.path.join(path, url.split('/')[-1]), 'w')
381 localFile.write(webFile.read())
382 webFile.close()
383 localFile.close()
385 def unzip(self, zipPath, inZipPath, targetFile):
386 """extract the needed file from zip and then delete the zip"""
387 import zipfile
388 try:
389 zfobj = zipfile.ZipFile(zipPath)
390 outfile = open(targetFile, 'wb')
391 outfile.write(zfobj.read(inZipPath))
392 outfile.flush()
393 outfile.close()
395 #delete zip file
396 os.unlink(zipPath)
397 except NameError, e:
398 print e
401 class egg_filename(Command):
402 description = "Get the file name of the generated egg"
403 user_options = []
404 boolean_options = []
406 def initialize_options(self):
407 pass
409 def finalize_options(self):
410 ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
411 self.egg_info = ei_cmd.egg_info
413 basename = pkg_resources.Distribution(
414 None, None, ei_cmd.egg_name, ei_cmd.egg_version,
415 get_python_version(),
416 self.distribution.has_ext_modules() and pkg_utils.get_build_platform).egg_name()
418 print basename
420 def run(self):
421 pass
424 if __name__ == '__main__':
425 # Always load source from the current folder
426 sys.path = [os.path.abspath('indico')] + sys.path
428 #PWD_INDICO_CONF = 'etc/indico.conf'
429 #if not os.path.exists(PWD_INDICO_CONF):
430 # shutil.copy('etc/indico.conf.sample', PWD_INDICO_CONF)
432 from MaKaC.consoleScripts.installBase import *
434 #Dirty trick: For running tests, we need to load all the modules and get rid of unnecessary outputs
435 tempLoggingDir = None
436 if 'test' in sys.argv:
437 import logging
438 import tempfile
439 tempLoggingDir = tempfile.mkdtemp()
440 logging.basicConfig(filename=os.path.join(tempLoggingDir, 'logging'),
441 level=logging.DEBUG)
442 setIndicoInstallMode(False)
443 else:
444 setIndicoInstallMode(True)
446 x = vars()
447 x.packageDir = os.path.join(get_python_lib(), 'MaKaC')
449 x.binDir = 'bin'
450 x.documentationDir = 'doc'
451 x.configurationDir = 'etc'
452 x.htdocsDir = 'htdocs'
454 dataFiles = _getDataFiles(x)
456 foundPackages = list('MaKaC.%s' % pkg for pkg in
457 find_packages(where='indico/MaKaC'))
458 foundPackages.append('MaKaC')
459 foundPackages.append('htdocs')
461 # add our namespace package
462 foundPackages += list('indico.%s' % pkg for pkg in
463 find_packages(where='indico',
464 exclude=['htdocs*', 'MaKaC*']))
465 foundPackages.append('indico')
467 cmdclass = {'sdist': sdist_indico,
468 'bdist': _bdist_indico(dataFiles),
469 'bdist_egg': _bdist_egg_indico(dataFiles),
470 'develop_config': develop_config,
471 'develop': develop_indico,
472 'test': test_indico,
473 'egg_filename': egg_filename
476 if BABEL_PRESENT:
477 for cmdname in ['init_catalog', 'extract_messages', 'compile_catalog', 'update_catalog']:
478 cmdclass['%s_js' % cmdname] = getattr(babel, cmdname)
479 cmdclass['compile_catalog_js'] = i18n.generate_messages_js
481 setup(name="indico",
482 cmdclass=cmdclass,
483 version=_versionInit(),
484 description="Indico is a full-featured conference lifecycle management and meeting/lecture scheduling tool",
485 author="Indico Team",
486 author_email="indico-team@cern.ch",
487 url="http://indico-software.org",
488 download_url="http://indico-software.org/wiki/Releases/Indico0.99",
489 platforms=["any"],
490 long_description="Indico allows you to schedule conferences, from single talks to complex meetings with "
491 "sessions and contributions. It also includes an advanced user delegation mechanism, "
492 "allows paper reviewing, archival of conference information and electronic proceedings",
493 license="http://www.gnu.org/licenses/gpl-3.0.txt",
494 entry_points="""
495 [console_scripts]
497 indico_scheduler = indico.modules.scheduler.daemon_script:main
498 indico_initial_setup = MaKaC.consoleScripts.indicoInitialSetup:main
499 indico_ctl = MaKaC.consoleScripts.indicoCtl:main
500 indico_livesync = indico.ext.livesync.console:main
501 indico_shell = indico.util.shell:main
502 indico_admin = indico.util.admin:main
504 [indico.ext_types]
506 statistics = indico.ext.statistics
507 Collaboration = MaKaC.plugins.Collaboration
508 InstantMessaging = MaKaC.plugins.InstantMessaging
509 RoomBooking = MaKaC.plugins.RoomBooking
510 EPayment = MaKaC.plugins.EPayment
511 livesync = indico.ext.livesync
512 importer = indico.ext.importer
513 calendaring = indico.ext.calendaring
514 search = indico.ext.search
516 [indico.ext]
518 statistics.piwik = indico.ext.statistics.piwik
520 Collaboration.EVO = MaKaC.plugins.Collaboration.EVO
521 Collaboration.WebEx = MaKaC.plugins.Collaboration.WebEx
522 Collaboration.Vidyo = MaKaC.plugins.Collaboration.Vidyo
523 Collaboration.CERNMCU = MaKaC.plugins.Collaboration.CERNMCU
524 Collaboration.RecordingManager = MaKaC.plugins.Collaboration.RecordingManager
525 Collaboration.RecordingRequest = MaKaC.plugins.Collaboration.RecordingRequest
526 Collaboration.WebcastRequest = MaKaC.plugins.Collaboration.WebcastRequest
528 RoomBooking.CERN = MaKaC.plugins.RoomBooking.CERN
529 RoomBooking.default = MaKaC.plugins.RoomBooking.default
531 EPayment.payPal = MaKaC.plugins.EPayment.payPal
532 EPayment.worldPay = MaKaC.plugins.EPayment.worldPay
533 EPayment.yellowPay = MaKaC.plugins.EPayment.yellowPay
534 EPayment.skipjack = MaKaC.plugins.EPayment.skipjack
536 importer.invenio = indico.ext.importer.invenio
537 importer.dummy = indico.ext.importer.dummy
539 InstantMessaging.XMPP = MaKaC.plugins.InstantMessaging.XMPP
541 livesync.invenio = indico.ext.livesync.invenio
542 livesync.cern_search = indico.ext.livesync.cern_search
544 calendaring.outlook = indico.ext.calendaring.outlook
546 search.invenio = indico.ext.search.invenio
548 """,
549 zip_safe=False,
550 packages=foundPackages,
551 package_dir={'indico': 'indico',
552 'htdocs': os.path.join('indico', 'htdocs'),
553 'MaKaC': os.path.join('indico', 'MaKaC')},
554 package_data={'indico': ['*.*']},
555 include_package_data=True,
556 namespace_packages=['indico', 'indico.ext'],
557 install_requires=_getInstallRequires(),
558 tests_require=['nose', 'rednose', 'twill', 'selenium', 'figleaf'],
559 data_files=dataFiles,
560 dependency_links=DEPENDENCY_URLS
563 #delete the temp folder used for logging
564 if 'test' in sys.argv:
565 shutil.rmtree(tempLoggingDir)