Fix session.timezone
[cds-indico.git] / setup.py
blob38f15a008e82adc082210b20d74d6e5411af7f78
1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 # Autoinstalls setuptools if the user doesn't have them already
18 import ez_setup
19 ez_setup.use_setuptools()
21 import os
22 import getpass
23 import re
24 import shutil
25 import sys
26 from distutils.sysconfig import get_python_lib, get_python_version
27 from distutils.cmd import Command
28 from distutils.command import bdist
31 import pkg_resources
32 from setuptools.command import develop, sdist, bdist_egg, easy_install, test
33 from setuptools import setup, find_packages, findall
36 DEPENDENCY_URLS = ["http://indico-software.org/wiki/Admin/Installation/IndicoExtras"]
39 class vars(object):
40 '''Variable holder.'''
41 packageDir = None
42 versionVal = 'None'
43 accessuser = None
44 accessgroup = None
45 dbInstalledBySetupPy = False
46 binDir = None
47 documentationDir = None
48 configurationDir = None
49 htdocsDir = None
52 def compile_languages(cmd):
53 """
54 Compile all language files
55 Needed to generate binary distro
56 """
57 from babel.messages import frontend
59 compile_cmd = frontend.compile_catalog(cmd.distribution)
60 cmd.distribution._set_command_options(compile_cmd)
61 compile_cmd.finalize_options()
62 compile_cmd.run()
65 def read_requirements_file(fname):
66 with open(fname, 'r') as f:
67 return [dep.strip() for dep in f.readlines() if not (dep.startswith('-') or '://' in dep)]
70 def _generateDataPaths(x):
72 dataFilesDict = {}
74 for (baseDstDir, srcDir) in x:
75 for f in findall(srcDir):
76 dst_dir = os.path.join(baseDstDir,
77 os.path.relpath(os.path.dirname(f), srcDir))
78 if dst_dir not in dataFilesDict:
79 dataFilesDict[dst_dir] = []
80 dataFilesDict[dst_dir].append(f)
82 dataFiles = []
83 for k, v in dataFilesDict.items():
84 dataFiles.append((k, v))
86 return dataFiles
89 def _getInstallRequires():
90 """Returns external packages required by Indico
92 These are the ones needed for runtime."""
94 return read_requirements_file(os.path.join(os.path.dirname(__file__), 'requirements.txt'))
97 def _versionInit():
98 """Retrieves the version number from indico/MaKaC/__init__.py and returns it"""
100 from indico.MaKaC import __version__
101 v = __version__
103 print 'Indico %s' % v
105 return v
108 # Commands
109 class sdist_indico(sdist.sdist):
110 user_options = (sdist.sdist.user_options +
111 [('version=', None, 'version to distribute')])
112 version = 'dev'
114 def run(self):
115 sdist.sdist.run(self)
118 def _bdist_indico(dataFiles):
119 class bdist_indico(bdist.bdist):
120 def run(self):
121 compile_languages(self)
122 bdist.bdist.run(self)
124 bdist_indico.dataFiles = dataFiles
125 return bdist_indico
128 def _bdist_egg_indico(dataFiles):
129 class bdist_egg_indico(bdist_egg.bdist_egg):
130 def run(self):
131 compile_languages(self)
132 bdist_egg.bdist_egg.run(self)
134 bdist_egg_indico.dataFiles = dataFiles
135 return bdist_egg_indico
138 class develop_indico(develop.develop):
139 def run(self):
140 develop.develop.run(self)
142 # create symlink to legacy MaKaC dir
143 # this is so that the ".egg-link" created by the "develop" command works
144 if sys.platform in ["linux2", "darwin"] and not os.path.exists('MaKaC'):
145 os.symlink('indico/MaKaC', 'MaKaC')
147 # install dev dependencies
148 env = pkg_resources.Environment()
149 easy_install.main(read_requirements_file(os.path.join(os.path.dirname(__file__), 'requirements.dev.txt')))
150 env.scan()
153 class develop_config(develop_indico):
154 description = "prepares the current directory for Indico development"
155 user_options = (develop.develop.user_options +
156 [('www-uid=', None, "Set user for cache/log/db (typically apache user)"),
157 ('www-gid=', None, "Set group for cache/log/db (typically apache group)"),
158 ('http-port=', None, "Set port used by HTTP server"),
159 ('https-port=', None, "Set port used by HTTP server in HTTPS mode"),
160 ('zodb-port=', None, "Set port used by ZODB"),
161 ('smtp-port=', None, "Set port used for SMTP (e-mail sending)"),
162 ('use-apache', None, "Use apache (will chmod directories accordingly)")])
164 www_uid = None
165 www_gid = None
166 http_port = 8000
167 https_port = 8443
168 zodb_port = 9675
169 use_apache = False
170 smtp_port = 8025
172 def run(self):
173 # dependencies, links, etc...
174 develop_indico.run(self)
176 local = 'etc/indico.conf'
177 if os.path.exists(local):
178 print 'Upgrading existing etc/indico.conf...'
179 else:
180 print 'Creating new etc/indico.conf..'
181 shutil.copy('etc/indico.conf.sample', local)
183 upgrade_indico_conf(local, 'etc/indico.conf.sample', {
184 'BaseURL': 'http://localhost:{0}'.format(self.http_port),
185 'BaseSecureURL': 'https://localhost:{0}'.format(self.https_port),
186 'DBConnectionParams': ("localhost", int(self.zodb_port)),
187 'SmtpServer': ("localhost", int(self.smtp_port))
190 for f in [x for x in ('etc/zdctl.conf', 'etc/zodb.conf', 'etc/logging.conf') if not os.path.exists(x)]:
191 shutil.copy('%s.sample' % f, f)
193 print """\nIndico needs to store some information in the filesystem (database, cache, temporary files, logs...)
194 Please specify the directory where you'd like it to be placed.
195 (Note that putting it outside of your sourcecode tree is recommended)"""
196 prefixDirDefault = os.path.dirname(os.getcwd())
197 prefixDir = raw_input('Full path [%s]: ' % prefixDirDefault).strip()
199 if prefixDir == '':
200 prefixDir = prefixDirDefault
202 directories = dict((d, os.path.join(prefixDir, d)) for d in
203 ['db', 'log', 'tmp', 'cache', 'archive'])
205 print 'Creating directories...',
206 for d in directories.values():
207 if not os.path.exists(d):
208 os.makedirs(d)
209 print 'Done!'
211 # add existing dirs
212 directories.update(dict((d, os.path.join(os.getcwd(), 'indico', d)) for d in ['htdocs', 'bin', 'etc', 'doc']))
214 self._update_conf_dir_paths(local, directories)
216 # avoid modifying the htdocs folder permissions (it brings problems with git)
217 directories.pop('htdocs')
219 from MaKaC.consoleScripts.installBase import _databaseText, _findApacheUserGroup, _checkDirPermissions, \
220 _updateDbConfigFiles, _updateMaKaCEggCache
222 user = getpass.getuser()
223 sourcePath = os.getcwd()
225 if self.use_apache:
226 # find the apache user/group
227 user, group = _findApacheUserGroup(self.www_uid, self.www_gid)
228 _checkDirPermissions(directories, dbInstalledBySetupPy=directories['db'], accessuser=user, accessgroup=group)
230 _updateDbConfigFiles(os.path.join(sourcePath, 'etc'),
231 db=directories['db'],
232 log=directories['log'],
233 tmp=directories['tmp'],
234 port=self.zodb_port,
235 uid=user)
237 _updateMaKaCEggCache(os.path.join(os.path.dirname(__file__), 'indico', 'MaKaC', '__init__.py'),
238 directories['tmp'])
240 compile_languages(self)
241 print '''
243 ''' % _databaseText('etc')
245 def _update_conf_dir_paths(self, filePath, dirs):
246 fdata = open(filePath).read()
247 for dir in dirs.items():
248 d = dir[1].replace("\\", "/") # For Windows users
249 fdata = re.sub('\/opt\/indico\/%s' % dir[0], d, fdata)
250 open(filePath, 'w').write(fdata)
253 class test_indico(test.test):
255 Test command for Indico
258 description = "Test Suite Framework"
259 user_options = (test.test.user_options + [('specify=', None, "Use nosetests style (file.class:testcase)"),
260 ('coverage', None, "Output coverage report in html"),
261 ('unit', None, "Run only Unit tests"),
262 ('functional', None, "Run only Functional tests"),
263 ('pylint', None, "Run python source analysis"),
264 ('jsunit', None, "Run js unit tests"),
265 ('jslint', None, "Run js source analysis"),
266 ('jscoverage', None, "Output coverage report in html for js"),
267 ('jsspecify=', None, "Use js-test-driver style (TestCaseName.testName)"),
268 ('log=', None, "Log to console, using specified level"),
269 ('browser=', None, "Browser to use for functional tests"),
270 ('mode=', None, "Mode to use for functional tests"),
271 ('server-url=', None, "Server URL to use for functional tests"),
272 ('xml', None, "XML output"),
273 ('html', None, "Make an HTML report (when possible)"),
274 ('record', None, "Record tests (for --functional)"),
275 ('silent', None, "Don't output anything in the console, just generate the report"),
276 ('clean-shutdown', None,
277 "Do not kill this script right after the tests finished without waiting for db shutdown.")])
278 boolean_options = []
280 specify = None
281 coverage = False
282 unit = False
283 functional = False
284 browser = None
285 pylint = False
286 jsunit = False
287 jslint = False
288 jscoverage = False
289 jsspecify = None
290 silent = False
291 mode = None
292 server_url = None
293 clean_shutdown = False
294 html = False
295 record = False
296 log = False
297 xml = False
299 def _wrap(self, func, *params):
300 def wrapped():
301 self.res = func(*params)
302 self.with_project_on_sys_path(wrapped)
303 return self.res
305 def finalize_options(self):
306 testsToRun = []
308 allTests = ['unit', 'functional']
310 for testType in allTests:
311 if getattr(self, testType):
312 testsToRun.append(testType)
314 if self.jsspecify and 'jsunit' not in testsToRun:
315 testsToRun.append('jsunit')
317 if not testsToRun:
318 testsToRun = allTests
319 self.testsToRun = testsToRun
321 def run(self):
323 if self.distribution.install_requires:
324 self.distribution.fetch_build_eggs(self.distribution.install_requires)
325 if self.distribution.tests_require:
326 self.distribution.fetch_build_eggs(self.distribution.tests_require)
328 from indico.tests import TestManager
330 options = {'silent': self.silent,
331 'killself': not self.clean_shutdown,
332 'html': self.html,
333 'browser': self.browser,
334 'mode': self.mode,
335 'specify': self.specify,
336 'coverage': self.coverage,
337 'record': self.record,
338 'server_url': self.server_url,
339 'log': self.log,
340 'xml': self.xml}
342 # get only options that are active
343 options = dict((k, v) for (k, v) in options.iteritems() if v)
345 manager = TestManager()
346 result = self._wrap(manager.main, self.testsToRun, options)
348 sys.exit(result)
350 def download(self, url, path):
351 """Copy the contents of a file from a given URL
352 to a local file.
354 import urllib
355 webFile = urllib.urlopen(url)
356 localFile = open(os.path.join(path, url.split('/')[-1]), 'w')
357 localFile.write(webFile.read())
358 webFile.close()
359 localFile.close()
361 def unzip(self, zipPath, inZipPath, targetFile):
362 """extract the needed file from zip and then delete the zip"""
363 import zipfile
364 try:
365 zfobj = zipfile.ZipFile(zipPath)
366 outfile = open(targetFile, 'wb')
367 outfile.write(zfobj.read(inZipPath))
368 outfile.flush()
369 outfile.close()
371 #delete zip file
372 os.unlink(zipPath)
373 except NameError, e:
374 print e
377 class egg_filename(Command):
378 description = "Get the file name of the generated egg"
379 user_options = []
380 boolean_options = []
382 def initialize_options(self):
383 pass
385 def finalize_options(self):
386 ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
387 self.egg_info = ei_cmd.egg_info
389 basename = pkg_resources.Distribution(
390 None, None, ei_cmd.egg_name, ei_cmd.egg_version,
391 get_python_version(),
392 self.distribution.has_ext_modules() and pkg_utils.get_build_platform).egg_name()
394 print basename
396 def run(self):
397 pass
400 if __name__ == '__main__':
401 # Always load source from the current folder
402 sys.path = [os.path.abspath('indico')] + sys.path
404 #PWD_INDICO_CONF = 'etc/indico.conf'
405 #if not os.path.exists(PWD_INDICO_CONF):
406 # shutil.copy('etc/indico.conf.sample', PWD_INDICO_CONF)
408 from MaKaC.consoleScripts.installBase import setIndicoInstallMode, upgrade_indico_conf
410 #Dirty trick: For running tests, we need to load all the modules and get rid of unnecessary outputs
411 tempLoggingDir = None
412 if 'test' in sys.argv:
413 import logging
414 import tempfile
415 tempLoggingDir = tempfile.mkdtemp()
416 logging.basicConfig(filename=os.path.join(tempLoggingDir, 'logging'),
417 level=logging.DEBUG)
418 setIndicoInstallMode(False)
419 else:
420 setIndicoInstallMode(True)
422 x = vars()
423 x.packageDir = os.path.join(get_python_lib(), 'MaKaC')
425 x.binDir = 'bin'
426 x.documentationDir = 'doc'
427 x.configurationDir = 'etc'
428 x.htdocsDir = 'htdocs'
430 dataFiles = _generateDataPaths((('bin', 'bin'), ('doc', 'doc'), ('etc', 'etc'), ('migrations', 'migrations')))
432 foundPackages = list('MaKaC.%s' % pkg for pkg in
433 find_packages(where='indico/MaKaC'))
434 foundPackages.append('MaKaC')
435 foundPackages.append('htdocs')
437 # add our namespace package
438 foundPackages += list('indico.%s' % pkg for pkg in
439 find_packages(where='indico',
440 exclude=['htdocs*', 'MaKaC*']))
441 foundPackages.append('indico')
442 foundPackages += list('indico_zodbimport.' + pkg for pkg in find_packages(where='indico_zodbimport'))
443 foundPackages.append('indico_zodbimport')
445 cmdclass = {'sdist': sdist_indico,
446 'bdist': _bdist_indico(dataFiles),
447 'bdist_egg': _bdist_egg_indico(dataFiles),
448 'develop_config': develop_config,
449 'develop': develop_indico,
450 'test': test_indico,
451 'egg_filename': egg_filename
454 setup(name="indico",
455 cmdclass=cmdclass,
456 version=_versionInit(),
457 description="Indico is a full-featured conference lifecycle management and meeting/lecture scheduling tool",
458 author="Indico Team",
459 author_email="indico-team@cern.ch",
460 url="http://indico-software.org",
461 download_url="http://indico-software.org/wiki/Releases/Indico1.2",
462 platforms=["any"],
463 long_description="Indico allows you to schedule conferences, from single talks to complex meetings with "
464 "sessions and contributions. It also includes an advanced user delegation mechanism, "
465 "allows paper reviewing, archival of conference information and electronic proceedings",
466 license="http://www.gnu.org/licenses/gpl-3.0.txt",
467 entry_points="""
468 [console_scripts]
469 indico_scheduler = indico.modules.scheduler.daemon_script:main
470 indico_initial_setup = MaKaC.consoleScripts.indicoInitialSetup:main
471 indico_ctl = MaKaC.consoleScripts.indicoCtl:main
472 indico = indico.cli.manage:main
473 indico-zodbimport = indico_zodbimport.cli:main
475 [pytest11]
476 indico = indico.testing.pytest_plugin
478 [indico.zodb_importers]
479 roombooking = indico_zodbimport.modules.roombooking:RoomBookingImporter
480 payment = indico_zodbimport.modules.payment:PaymentImporter
481 api = indico_zodbimport.modules.api:APIImporter
482 users = indico_zodbimport.modules.users:UserImporter
483 groups = indico_zodbimport.modules.groups:GroupImporter
484 evaluation_alarms = indico_zodbimport.modules.evaluation_alarms:EvaluationAlarmImporter
485 static_sites = indico_zodbimport.modules.static_sites:StaticSitesImporter
486 """,
487 zip_safe=False,
488 packages=foundPackages,
489 package_dir={'indico': 'indico',
490 'htdocs': os.path.join('indico', 'htdocs'),
491 'MaKaC': os.path.join('indico', 'MaKaC')},
492 package_data={'indico': ['*.*']},
493 include_package_data=True,
494 namespace_packages=['indico'],
495 install_requires=_getInstallRequires(),
496 tests_require=['nose', 'rednose', 'twill', 'selenium', 'figleaf', 'contextlib2'],
497 data_files=dataFiles,
498 dependency_links=DEPENDENCY_URLS
501 #delete the temp folder used for logging
502 if 'test' in sys.argv:
503 shutil.rmtree(tempLoggingDir)