source: indico/setup.py @ 405840

hello-world-walkthroughipv6v0.98-seriesv0.98.2v0.98.3v0.99v1.0v1.1
Last change on this file since 405840 was 405840, checked in by Pedro Ferreira <jose.pedro.ferreira@…>, 14 months ago

[FIX] move symlink command to develop

  • Property mode set to 100644
File size: 19.8 KB
Line 
1# -*- coding: utf-8 -*-
2##
3##
4## This file is part of CDS Indico.
5## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
6##
7## CDS 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 2 of the
10## License, or (at your option) any later version.
11##
12## CDS 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 GNU
15## General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
19## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
21# Autoinstalls setuptools if the user doesn't have them already
22import ez_setup
23ez_setup.use_setuptools()
24
25import commands
26import getopt
27import os
28import re
29import shutil
30import string
31import sys
32import itertools
33from distutils.sysconfig import get_python_lib, get_python_version
34from distutils.cmd import Command
35from distutils.command import bdist
36from indico.util import i18n
37
38
39import pkg_resources
40from setuptools.command import develop, install, sdist, bdist_egg, easy_install, test
41from setuptools import setup, find_packages, findall
42
43
44try:
45    from babel.messages import frontend as babel
46    BABEL_PRESENT = True
47except ImportError:
48    BABEL_PRESENT = False
49
50
51DEPENDENCY_URLS = ["http://indico-software.org/wiki/Admin/Installation/IndicoExtras",
52                   "https://github.com/collective/icalendar/tarball/6f899869d462a23d0ebd3f54fb237e8670242bc4#egg=icalendar-3.0"]
53
54DEVELOP_REQUIRES = ['pojson', 'termcolor']
55
56if sys.platform == 'linux2':
57    import pwd
58    import grp
59
60
61class vars(object):
62    '''Variable holder.'''
63    packageDir = None
64    versionVal = 'None'
65    accessuser = None
66    accessgroup = None
67    dbInstalledBySetupPy = False
68    binDir = None
69    documentationDir = None
70    configurationDir = None
71    htdocsDir = None
72
73###  Methods required by setup() ##############################################
74
75def _generateDataPaths(x):
76
77    dataFilesDict = {}
78
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)
86
87    dataFiles = []
88    for k, v in dataFilesDict.items():
89        dataFiles.append((k, v))
90
91    return dataFiles
92
93def _getDataFiles(x):
94    """
95    Returns a fully populated data_files ready to be fed to setup()
96
97    WARNING: when creating a bdist_egg we need to include files inside bin,
98    doc, config & htdocs into the egg therefore we cannot fetch indico.conf
99    values directly because they will not refer to the proper place. We
100    include those files in the egg's root folder.
101    """
102
103    # setup expects a list like this (('foo/bar/baz', 'wiki.py'),
104    #                                 ('a/b/c', 'd.jpg'))
105    #
106    # What we do below is transform a list like this:
107    #                                (('foo', 'bar/baz/wiki.py'),
108    #                                 ('a', 'b/c/d.jpg'))
109    #
110    # first into a dict and then into a pallatable form for setuptools.
111
112    # This re will be used to filter out etc/*.conf files and therefore not overwritting them
113    dataFiles = _generateDataPaths((('bin', 'bin'),
114                                    ('doc', 'doc'),
115                                    ('etc', 'etc')))
116    return dataFiles
117
118
119def _getInstallRequires():
120    '''Returns external packages required by Indico
121
122    These are the ones needed for runtime.'''
123
124    base =  ['ZODB3>=3.8', 'pytz', 'zope.index', 'zope.interface',
125             'lxml', 'cds-indico-extras', 'zc.queue', 'python-dateutil<2.0',
126             'pypdf', 'mako>=0.4.1', 'babel', 'icalendar>=3.0', 'pyatom',
127             'simplejson', 'python-cjson']
128
129    #for Python older than 2.7
130    if sys.version_info[0] <= 2 and sys.version_info[1] < 7:
131        base.append('argparse')
132
133    return base
134
135
136def _versionInit():
137        '''Retrieves the version number from indico/MaKaC/__init__.py and returns it'''
138
139        from indico.MaKaC import __version__
140        v = __version__
141
142        print('Indico %s' % v)
143
144        return v
145
146###  Commands ###########################################################
147class sdist_indico(sdist.sdist):
148    user_options = sdist.sdist.user_options + \
149                   [('version=', None, 'version to distribute')]
150    version = 'dev'
151
152    def run(self):
153        global x
154        sdist.sdist.run(self)
155
156
157class jsdist_indico:
158    def jsCompress(self):
159        from MaKaC.consoleScripts.installBase import jsCompress
160        jsCompress()
161
162
163def _bdist_indico(dataFiles):
164    class bdist_indico(bdist.bdist, jsdist_indico):
165        def run(self):
166            self.jsCompress()
167            compileAllLanguages(self)
168            bdist.bdist.run(self)
169
170    bdist_indico.dataFiles = dataFiles
171    return bdist_indico
172
173
174def _bdist_egg_indico(dataFiles):
175    class bdist_egg_indico(bdist_egg.bdist_egg, jsdist_indico):
176        def run(self):
177            self.jsCompress()
178            compileAllLanguages(self)
179            bdist_egg.bdist_egg.run(self)
180
181    bdist_egg_indico.dataFiles = dataFiles
182    return bdist_egg_indico
183
184
185class jsbuild(Command):
186    description = "minifies and packs javascript files"
187    user_options = []
188    boolean_options = []
189
190    def initialize_options(self):
191        pass
192
193    def finalize_options(self):
194        pass
195
196    def run(self):
197        from MaKaC.consoleScripts.installBase import jsCompress
198        jsCompress()
199
200
201class develop_indico(develop.develop):
202    def run(self):
203        develop.develop.run(self)
204
205        # create symlink to legacy MaKaC dir
206        # this is so that the ".egg-link" created by the "develop" command works
207        if sys.platform in ["linux2", "darwin"] and not os.path.exists('MaKaC'):
208            os.symlink('indico/MaKaC','MaKaC')
209
210
211class develop_config(develop_indico):
212    description = "prepares the current directory for Indico development"
213    user_options = develop.develop.user_options + [('www-uid=', None, "Set user for cache/log/db (typically apache user)"),
214                    ('www-gid=', None, "Set group for cache/log/db (typically apache group)")]
215
216    www_uid = None
217    www_gid = None
218
219    def run(self):
220        # dependencies, links, etc...
221        develop_indico.run(self)
222
223        env = pkg_resources.Environment()
224        easy_install.main(DEVELOP_REQUIRES)
225        env.scan()
226
227        local = 'etc/indico.conf'
228        if os.path.exists(local):
229            print 'Upgrading existing etc/indico.conf..'
230            upgrade_indico_conf(local, 'etc/indico.conf.sample')
231        else:
232            print 'Creating new etc/indico.conf..'
233            shutil.copy('etc/indico.conf.sample', local)
234
235        for f in [x for x in ('etc/zdctl.conf', 'etc/zodb.conf', 'etc/logging.conf') if not os.path.exists(x)]:
236            shutil.copy('%s.sample' % f, f)
237
238        print """\nIndico needs to store some information in the filesystem (database, cache, temporary files, logs...)
239Please specify the directory where you'd like it to be placed.
240(Note that putting it outside of your sourcecode tree is recommended)"""
241        prefixDirDefault = os.path.dirname(os.getcwd())
242        prefixDir = raw_input('[%s]: ' % prefixDirDefault).strip()
243
244        if prefixDir == '':
245            prefixDir = prefixDirDefault
246
247        directories = dict((d, os.path.join(prefixDir, d)) for d in
248                           ['db', 'log', 'tmp', 'cache', 'archive'])
249
250        print 'Creating directories...',
251        for d in directories.values():
252            if not os.path.exists(d):
253                os.makedirs(d)
254        print 'Done!'
255
256        directories['htdocs'] = os.path.join(os.getcwd(), 'indico', 'htdocs')
257        directories['bin'] = os.path.join(os.getcwd(), 'bin')
258        directories['etc'] = os.path.join(os.getcwd(), 'etc')
259        directories['doc'] = os.path.join(os.getcwd(), 'doc')
260
261        self._update_conf_dir_paths(local, directories)
262
263        directories.pop('htdocs') #avoid modifying the htdocs folder permissions (it brings problems with git)
264
265        from MaKaC.consoleScripts.installBase import _databaseText, _findApacheUserGroup, _checkDirPermissions, _updateDbConfigFiles, _updateMaKaCEggCache
266
267        user = ''
268
269        sourcePath = os.getcwd()
270
271        # find the apache user/group
272        user, group = _findApacheUserGroup(self.www_uid, self.www_gid)
273        _checkDirPermissions(directories, dbInstalledBySetupPy=directories['db'], accessuser=user, accessgroup=group)
274
275        _updateDbConfigFiles(directories['db'], directories['log'], os.path.join(sourcePath, 'etc'), directories['tmp'], user)
276
277        _updateMaKaCEggCache(os.path.join(os.path.dirname(__file__), 'indico', 'MaKaC', '__init__.py'), directories['tmp'])
278
279        updateIndicoConfPathInsideMaKaCConfig(os.path.join(os.path.dirname(__file__), ''), 'indico/MaKaC/common/MaKaCConfig.py')
280        compileAllLanguages(self)
281        print '''
282%s
283        ''' % _databaseText('etc')
284
285    def _update_conf_dir_paths(self, filePath, dirs):
286        fdata = open(filePath).read()
287        for dir in dirs.items():
288            d = dir[1].replace("\\","/") # For Windows users
289            fdata = re.sub('\/opt\/indico\/%s'%dir[0], d, fdata)
290        open(filePath, 'w').write(fdata)
291
292class test_indico(test.test):
293    """
294    Test command for Indico
295    """
296
297    description = "Test Suite Framework"
298    user_options = test.test.user_options + [('specify=', None, "Use nosetests style (file.class:testcase)"),
299                    ('coverage', None, "Output coverage report in html"),
300                    ('unit', None, "Run only Unit tests"),
301                    ('functional', None, "Run only Functional tests"),
302                    ('pylint', None, "Run python source analysis"),
303                    ('jsunit', None, "Run js unit tests"),
304                    ('jslint', None, "Run js source analysis"),
305                    ('jscoverage', None, "Output coverage report in html for js"),
306                    ('jsspecify=', None, "Use js-test-driver style (TestCaseName.testName)"),
307                    ('log=', None, "Log to console, using specified level"),
308                    ('grid', None, "Use Selenium Grid"),
309                    ('xml', None, "XML output"),
310                    ('html', None, "Make an HTML report (when possible)"),
311                    ('record', None, "Record tests (for --functional)"),
312                    ('parallel', None, "Parallel test execution using Selenium Grid (for --functional)"),
313                    ('threads=', None, "Parallel test execution with several threads (for --functional)"),
314                    ('repeat=', None, "Number of repetitions (for --functional)"),
315                    ('silent', None, "Don't output anything in the console, just generate the report"),
316                    ('killself', None, "Kill this script right after the tests finished without waiting for db shutdown.")]
317    boolean_options = []
318
319    specify = None
320    coverage = False
321    unit = False
322    functional = False
323    pylint = False
324    jsunit = False
325    jslint = False
326    jscoverage = False
327    jsspecify = None
328    grid = None
329    silent = False
330    killself = False
331    html = False
332    record = False
333    parallel = False
334    threads = False
335    repeat = False
336    log = False
337    xml = False
338
339    def _wrap(self, func, *params):
340        def wrapped():
341            self.res = func(*params)
342        self.with_project_on_sys_path(wrapped)
343        return self.res
344
345    def finalize_options(self):
346        testsToRun = []
347
348        allTests = ['unit', 'functional']
349
350        for testType in allTests:
351            if getattr(self, testType):
352                testsToRun.append(testType)
353
354        if self.jsspecify and 'jsunit' not in testsToRun:
355            testsToRun.append('jsunit')
356
357        if testsToRun == []:
358            testsToRun = allTests
359        self.testsToRun = testsToRun
360
361    def run(self):
362
363        if self.distribution.install_requires:
364            self.distribution.fetch_build_eggs(self.distribution.install_requires)
365        if self.distribution.tests_require:
366            self.distribution.fetch_build_eggs(self.distribution.tests_require)
367
368        from indico.tests import TestManager
369
370        options = {'silent': self.silent,
371                   'killself': self.killself,
372                   'html': self.html,
373                   'specify': self.specify,
374                   'coverage': self.coverage,
375                   'record': self.record,
376                   'parallel': self.parallel,
377                   'threads': self.threads,
378                   'repeat': self.repeat,
379                   'log': self.log,
380                   'xml':self.xml}
381
382        # get only options that are active
383        options = dict((k,v) for (k,v) in options.iteritems() if v)
384
385        manager = TestManager()
386        result = self._wrap(manager.main, self.testsToRun, options)
387
388        sys.exit(result)
389
390    def download(self, url, path):
391        """Copy the contents of a file from a given URL
392        to a local file.
393        """
394        import urllib
395        webFile = urllib.urlopen(url)
396        localFile = open(os.path.join(path, url.split('/')[-1]), 'w')
397        localFile.write(webFile.read())
398        webFile.close()
399        localFile.close()
400
401    def unzip(self, zipPath, inZipPath, targetFile):
402        """extract the needed file from zip and then delete the zip"""
403        import zipfile
404        try:
405            zfobj = zipfile.ZipFile(zipPath)
406            outfile = open(targetFile, 'wb')
407            outfile.write(zfobj.read(inZipPath))
408            outfile.flush()
409            outfile.close()
410
411            #delete zip file
412            os.unlink(zipPath)
413        except NameError, e:
414            print e
415
416
417class egg_filename(Command):
418    description = "Get the file name of the generated egg"
419    user_options = []
420    boolean_options = []
421
422    def initialize_options(self):
423        pass
424
425    def finalize_options(self):
426        ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
427        self.egg_info = ei_cmd.egg_info
428
429        basename = pkg_resources.Distribution(
430            None, None, ei_cmd.egg_name, ei_cmd.egg_version,
431            get_python_version(),
432            self.distribution.has_ext_modules() and pkg_utils.get_build_platform
433            ).egg_name()
434
435        print basename
436
437
438    def run(self):
439        pass
440
441
442if __name__ == '__main__':
443    # Always load source from the current folder
444    sys.path = [os.path.abspath('indico')] + sys.path
445
446    #PWD_INDICO_CONF = 'etc/indico.conf'
447    #if not os.path.exists(PWD_INDICO_CONF):
448    #    shutil.copy('etc/indico.conf.sample', PWD_INDICO_CONF)
449
450    from MaKaC.consoleScripts.installBase import *
451
452
453    #Dirty trick: For running tests, we need to load all the modules and get rid of unnecessary outputs
454    tempLoggingDir = None
455    if 'test' in sys.argv:
456        import logging
457        import tempfile
458        tempLoggingDir = tempfile.mkdtemp()
459        logging.basicConfig(filename=os.path.join(tempLoggingDir, 'logging'),
460                            level=logging.DEBUG)
461        setIndicoInstallMode(False)
462    else:
463        setIndicoInstallMode(True)
464
465    x = vars()
466    x.packageDir = os.path.join(get_python_lib(), 'MaKaC')
467
468
469    x.binDir = 'bin'
470    x.documentationDir = 'doc'
471    x.configurationDir = 'etc'
472    x.htdocsDir = 'htdocs'
473
474    dataFiles = _getDataFiles(x)
475
476    foundPackages = list('MaKaC.%s' % pkg for pkg in
477                         find_packages(where = 'indico/MaKaC'))
478    foundPackages.append('MaKaC')
479    foundPackages.append('htdocs')
480
481    # add our namespace package
482    foundPackages += list('indico.%s' % pkg for pkg in
483                         find_packages(where = 'indico',
484                                       exclude = ['htdocs*', 'MaKaC*']))
485    foundPackages.append('indico')
486
487    cmdclass = {'sdist': sdist_indico,
488                'bdist': _bdist_indico(dataFiles),
489                'bdist_egg': _bdist_egg_indico(dataFiles),
490                'jsbuild': jsbuild,
491                'develop_config': develop_config,
492                'develop': develop_indico,
493                'test': test_indico,
494                'egg_filename': egg_filename
495                }
496
497    if BABEL_PRESENT:
498        for cmdname in ['init_catalog', 'extract_messages', 'compile_catalog', 'update_catalog']:
499            cmdclass['%s_js' % cmdname] = getattr(babel, cmdname)
500        cmdclass['compile_catalog_js'] = i18n.generate_messages_js
501
502    setup(name = "indico",
503          cmdclass = cmdclass,
504          version = _versionInit(),
505          description = "Indico is a full-featured conference lifecycle management and meeting/lecture scheduling tool",
506          author = "Indico Team",
507          author_email = "indico-team@cern.ch",
508          url = "http://indico-software.org",
509          download_url = "http://indico-software.org/wiki/Releases/Indico0.98-rc1",
510          platforms = ["any"],
511          long_description = "Indico allows you to schedule conferences, from single talks to complex meetings with sessions and contributions. It also includes an advanced user delegation mechanism, allows paper reviewing, archival of conference information and electronic proceedings",
512          license = "http://www.gnu.org/licenses/gpl-2.0.txt",
513          entry_points = """
514            [console_scripts]
515
516            indico_scheduler = indico.modules.scheduler.daemon_script:main
517            indico_initial_setup = MaKaC.consoleScripts.indicoInitialSetup:main
518            indico_ctl = MaKaC.consoleScripts.indicoCtl:main
519            indico_livesync = indico.ext.livesync.console:main
520            indico_shell = indico.util.shell:main
521
522            [indico.ext_types]
523
524            Collaboration = MaKaC.plugins.Collaboration
525            InstantMessaging = MaKaC.plugins.InstantMessaging
526            RoomBooking = MaKaC.plugins.RoomBooking
527            EPayment = MaKaC.plugins.EPayment
528            livesync = indico.ext.livesync
529            importer = indico.ext.importer
530
531
532            [indico.ext]
533
534            Collaboration.EVO = MaKaC.plugins.Collaboration.EVO
535            Collaboration.Vidyo = MaKaC.plugins.Collaboration.Vidyo
536            Collaboration.CERNMCU = MaKaC.plugins.Collaboration.CERNMCU
537            Collaboration.RecordingManager = MaKaC.plugins.Collaboration.RecordingManager
538            Collaboration.RecordingRequest = MaKaC.plugins.Collaboration.RecordingRequest
539            Collaboration.WebcastRequest = MaKaC.plugins.Collaboration.WebcastRequest
540
541            RoomBooking.CERN = MaKaC.plugins.RoomBooking.CERN
542            RoomBooking.default = MaKaC.plugins.RoomBooking.default
543
544            EPayment.payPal = MaKaC.plugins.EPayment.payPal
545            EPayment.worldPay = MaKaC.plugins.EPayment.worldPay
546            EPayment.yellowPay = MaKaC.plugins.EPayment.yellowPay
547            EPayment.skipjack = MaKaC.plugins.EPayment.skipjack
548
549            importer.invenio = indico.ext.importer.invenio
550            importer.dummy = indico.ext.importer.dummy
551
552            InstantMessaging.XMPP = MaKaC.plugins.InstantMessaging.XMPP
553
554            livesync.invenio = indico.ext.livesync.invenio
555            livesync.cern_search = indico.ext.livesync.cern_search
556
557            """,
558          zip_safe = False,
559          packages = foundPackages,
560          package_dir = { 'indico': 'indico',
561                          'htdocs': os.path.join('indico', 'htdocs'),
562                          'MaKaC' : os.path.join('indico', 'MaKaC')},
563          package_data = {'indico': ['*.*']},
564          include_package_data=True,
565          namespace_packages = ['indico', 'indico.ext'],
566          install_requires = _getInstallRequires(),
567          tests_require = ['nose', 'rednose', 'twill', 'selenium', 'figleaf'],
568          data_files = dataFiles,
569          dependency_links = DEPENDENCY_URLS
570          )
571
572    #delete the temp folder used for logging
573    if 'test' in sys.argv:
574        shutil.rmtree(tempLoggingDir)
Note: See TracBrowser for help on using the repository browser.