source: indico/setup.py @ 1cc623

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

[FIX] Small setup.py fix

  • Property mode set to 100644
File size: 22.9 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
32from distutils.sysconfig import get_python_lib, get_python_version
33from distutils.cmd import Command
34from distutils.command import bdist
35from indico.util import i18n
36
37
38import pkg_resources
39from setuptools.command import develop, install, sdist, bdist_egg, easy_install
40from setuptools import setup, find_packages, findall
41
42
43try:
44    from babel.messages import frontend as babel
45    BABEL_PRESENT = True
46except ImportError:
47    BABEL_PRESENT = False
48
49
50EXTRA_RESOURCES_URL = "http://indico-software.org/wiki/Admin/Installation/IndicoExtras"
51
52if sys.platform == 'linux2':
53    import pwd
54    import grp
55
56
57class vars(object):
58    '''Variable holder.'''
59    packageDir = None
60    versionVal = 'None'
61    accessuser = None
62    accessgroup = None
63    dbInstalledBySetupPy = False
64    binDir = None
65    documentationDir = None
66    configurationDir = None
67    htdocsDir = None
68
69###  Methods required by setup() ##############################################
70
71def _generateDataPaths(x):
72
73    dataFilesDict = {}
74
75    for (baseDstDir, srcDir) in x:
76        for f in findall(srcDir):
77            dst_dir = os.path.join(baseDstDir,
78                                   os.path.relpath(os.path.dirname(f), srcDir))
79            if dst_dir not in dataFilesDict:
80                dataFilesDict[dst_dir] = []
81            dataFilesDict[dst_dir].append(f)
82
83    dataFiles = []
84    for k, v in dataFilesDict.items():
85        dataFiles.append((k, v))
86
87    return dataFiles
88
89def _getDataFiles(x):
90    """
91    Returns a fully populated data_files ready to be fed to setup()
92
93    WARNING: when creating a bdist_egg we need to include files inside bin,
94    doc, config & htdocs into the egg therefore we cannot fetch indico.conf
95    values directly because they will not refer to the proper place. We
96    include those files in the egg's root folder.
97    """
98
99    # setup expects a list like this (('foo/bar/baz', 'wiki.py'),
100    #                                 ('a/b/c', 'd.jpg'))
101    #
102    # What we do below is transform a list like this:
103    #                                (('foo', 'bar/baz/wiki.py'),
104    #                                 ('a', 'b/c/d.jpg'))
105    #
106    # first into a dict and then into a pallatable form for setuptools.
107
108    # This re will be used to filter out etc/*.conf files and therefore not overwritting them
109    dataFiles = _generateDataPaths((('bin', 'bin'),
110                                    ('doc', 'doc'),
111                                    ('etc', 'etc')))
112    return dataFiles
113
114
115def _getInstallRequires():
116    '''Returns external packages required by Indico
117
118    These are the ones needed for runtime.'''
119
120    base =  ['ZODB3>=3.8', 'pytz', 'zope.index', 'zope.interface',
121             'lxml', 'cds-indico-extras', 'zc.queue', 'python-dateutil<2.0',
122             'pypdf', 'mako>=0.4.1', 'babel', 'icalendar', 'pyatom',
123             'simplejson']
124
125    #for Python older than 2.7
126    if sys.version_info[0] <= 2 and sys.version_info[1] < 7:
127        base.append('argparse')
128
129    return base
130
131
132def _versionInit():
133        '''Retrieves the version number from indico/MaKaC/__init__.py and returns it'''
134
135        from indico.MaKaC import __version__
136        v = __version__
137
138        print('Indico %s' % v)
139
140        return v
141
142###  Commands ###########################################################
143class sdist_indico(sdist.sdist):
144    user_options = sdist.sdist.user_options + \
145                   [('version=', None, 'version to distribute')]
146    version = 'dev'
147
148    def run(self):
149        global x
150        sdist.sdist.run(self)
151
152
153class jsdist_indico:
154    def jsCompress(self):
155        from MaKaC.consoleScripts.installBase import jsCompress
156        jsCompress()
157
158
159def _bdist_indico(dataFiles):
160    class bdist_indico(bdist.bdist, jsdist_indico):
161        def run(self):
162            self.jsCompress()
163            compileAllLanguages(self)
164            bdist.bdist.run(self)
165
166    bdist_indico.dataFiles = dataFiles
167    return bdist_indico
168
169
170def _bdist_egg_indico(dataFiles):
171    class bdist_egg_indico(bdist_egg.bdist_egg, jsdist_indico):
172        def run(self):
173            self.jsCompress()
174            compileAllLanguages(self)
175            bdist_egg.bdist_egg.run(self)
176
177    bdist_egg_indico.dataFiles = dataFiles
178    return bdist_egg_indico
179
180
181class jsbuild(Command):
182    description = "minifies and packs javascript files"
183    user_options = []
184    boolean_options = []
185
186    def initialize_options(self):
187        pass
188
189    def finalize_options(self):
190        pass
191
192    def run(self):
193        from MaKaC.consoleScripts.installBase import jsCompress
194        jsCompress()
195
196class fetchdeps:
197    def run(self):
198        print "Checking if dependencies need to be installed..."
199
200        wset = pkg_resources.working_set
201
202        wset.resolve(map(pkg_resources.Requirement.parse,
203                         filter(lambda x: x != None, _getInstallRequires())),
204                     installer=self._installMissing)
205
206        print "Done!"
207
208
209    def _installMissing(self, dist):
210        env = pkg_resources.Environment()
211        print dist, EXTRA_RESOURCES_URL
212        easy_install.main(["-f", EXTRA_RESOURCES_URL, "-U", str(dist)])
213        env.scan()
214
215        if env[str(dist)]:
216            return env[str(dist)][0]
217        else:
218            return None
219
220
221class fetchdeps_indico(fetchdeps, Command):
222    description = "fetch all the dependencies needed to run Indico"
223    user_options = []
224    boolean_options = []
225
226    def initialize_options(self):
227        pass
228
229    def finalize_options(self):
230        pass
231
232
233class develop_indico(Command):
234    description = "prepares the current directory for Indico development"
235    user_options = []
236    boolean_options = []
237
238    def initialize_options(self):
239        pass
240
241    def finalize_options(self):
242        pass
243
244    def run(self):
245
246        fetchdeps().run()
247
248        local = 'etc/indico.conf'
249        if os.path.exists(local):
250            print 'Upgrading existing etc/indico.conf..'
251            upgrade_indico_conf(local, 'etc/indico.conf.sample')
252        else:
253            print 'Creating new etc/indico.conf..'
254            shutil.copy('etc/indico.conf.sample', local)
255
256        for f in [x for x in ('etc/zdctl.conf', 'etc/zodb.conf', 'etc/logging.conf') if not os.path.exists(x)]:
257            shutil.copy('%s.sample' % f, f)
258
259        print """\nIndico needs to store some information in the filesystem (database, cache, temporary files, logs...)
260Please specify the directory where you'd like it to be placed.
261(Note that putting it outside of your sourcecode tree is recommended)"""
262        prefixDirDefault = os.path.dirname(os.getcwd())
263        prefixDir = raw_input('[%s]: ' % prefixDirDefault).strip()
264
265        if prefixDir == '':
266            prefixDir = prefixDirDefault
267
268        directories = dict((d, os.path.join(prefixDir, d)) for d in
269                           ['db', 'log', 'tmp', 'cache', 'archive'])
270
271        print 'Creating directories...',
272        for d in directories.values():
273            if not os.path.exists(d):
274                os.makedirs(d)
275        print 'Done!'
276
277        directories['htdocs'] = os.path.join(os.getcwd(), 'indico', 'htdocs')
278        directories['bin'] = os.path.join(os.getcwd(), 'bin')
279        directories['etc'] = os.path.join(os.getcwd(), 'etc')
280        directories['doc'] = os.path.join(os.getcwd(), 'doc')
281
282        self._update_conf_dir_paths(local, directories)
283
284        directories.pop('htdocs') #avoid modifying the htdocs folder permissions (it brings problems with git)
285
286        from MaKaC.consoleScripts.installBase import _databaseText, _findApacheUserGroup, _checkDirPermissions, _updateDbConfigFiles, _updateMaKaCEggCache
287
288        user = ''
289
290        sourcePath = os.getcwd()
291
292        if sys.platform == "linux2":
293            # find the apache user/group
294            user, group = _findApacheUserGroup(None, None)
295            _checkDirPermissions(directories, dbInstalledBySetupPy = directories['db'], accessuser = user, accessgroup = group)
296
297        _updateDbConfigFiles(directories['db'], directories['log'], os.path.join(sourcePath, 'etc'), directories['tmp'], user)
298
299        _updateMaKaCEggCache(os.path.join(os.path.dirname(__file__), 'indico', 'MaKaC', '__init__.py'), directories['tmp'])
300
301        updateIndicoConfPathInsideMaKaCConfig(os.path.join(os.path.dirname(__file__), ''), 'indico/MaKaC/common/MaKaCConfig.py')
302        compileAllLanguages(self)
303        print '''
304%s
305        ''' % _databaseText('etc')
306
307        if sys.platform == "linux2":
308            # create symlink to legacy MaKaC dir
309            # this is so that the ".egg-link" created by the "develop" command works
310            os.symlink('indico/MaKaC','MaKaC')
311
312    def _update_conf_dir_paths(self, filePath, dirs):
313        fdata = open(filePath).read()
314        for dir in dirs.items():
315            d = dir[1].replace("\\","/") # For Windows users
316            fdata = re.sub('\/opt\/indico\/%s'%dir[0], d, fdata)
317        open(filePath, 'w').write(fdata)
318
319class test_indico(Command):
320    """
321    Test command for Indico
322    """
323
324    description = "Test Suite Framework"
325    user_options = [('specify=', None, "Use nosetests style (file.class:testcase)"),
326                    ('coverage', None, "Output coverage report in html"),
327                    ('unit', None, "Run only Unit tests"),
328                    ('functional', None, "Run only Functional tests"),
329                    ('pylint', None, "Run python source analysis"),
330                    ('jsunit', None, "Run js unit tests"),
331                    ('jslint', None, "Run js source analysis"),
332                    ('jscoverage', None, "Output coverage report in html for js"),
333                    ('jsspecify=', None, "Use js-test-driver style (TestCaseName.testName)"),
334                    ('log=', None, "Log to console, using specified level"),
335                    ('grid', None, "Use Selenium Grid"),
336                    ('xml', None, "XML output"),
337                    ('html', None, "Make an HTML report (when possible)"),
338                    ('record', None, "Record tests (for --functional)"),
339                    ('parallel', None, "Parallel test execution using Selenium Grid (for --functional)"),
340                    ('threads=', None, "Parallel test execution with several threads (for --functional)"),
341                    ('repeat=', None, "Number of repetitions (for --functional)"),
342                    ('silent', None, "Don't output anything in the console, just generate the report"),
343                    ('killself', None, "Kill this script right after the tests finished without waiting for db shutdown.")]
344    boolean_options = []
345
346    specify = None
347    coverage = False
348    unit = False
349    functional = False
350    pylint = False
351    jsunit = False
352    jslint = False
353    jscoverage = False
354    jsspecify = None
355    grid = None
356    silent = False
357    killself = False
358    html = False
359    record = False
360    parallel = False
361    threads = False
362    repeat = False
363    log = False
364    xml = False
365
366    def initialize_options(self):
367        pass
368
369    def finalize_options(self):
370        pass
371
372    def run(self):
373
374        if not self.checkTestPackages():
375            print "Please install those missing packages before launching the tests again"
376            sys.exit(-1)
377
378        #missing jars will be downloaded automatically
379        if not self.checkTestJars():
380            print "Some jars could not be downloaded. Please download the missing jars manually"
381            sys.exit(-1)
382
383        from indico.tests import TestManager, TEST_RUNNERS
384        testsToRun = []
385
386        allTests = TEST_RUNNERS.keys()
387
388        for testType in allTests:
389            if getattr(self, testType):
390                testsToRun.append(testType)
391
392        if self.jsspecify and 'jsunit' not in testsToRun:
393            testsToRun.append('jsunit')
394
395        if testsToRun == []:
396            testsToRun = allTests
397
398
399        options = {'silent': self.silent,
400                   'killself': self.killself,
401                   'html': self.html,
402                   'specify': self.specify,
403                   'coverage': self.coverage,
404                   'record': self.record,
405                   'parallel': self.parallel,
406                   'threads': self.threads,
407                   'repeat': self.repeat,
408                   'log': self.log,
409                   'xml':self.xml}
410
411        # get only options that are active
412        options = dict((k,v) for (k,v) in options.iteritems() if v)
413
414        manager = TestManager()
415
416        result = manager.main(testsToRun, options)
417
418        sys.exit(result)
419
420    def checkTestPackages(self):
421        packagesList = ['figleaf',
422                        'nose',
423                        'rednose',
424                        'selenium',
425                        'twill']
426        validPackages = True
427
428        for package in packagesList:
429            try:
430                pkg_resources.require(package)
431            except pkg_resources.DistributionNotFound:
432                print """
433%s not found! Please install it.
434i.e. try 'easy_install %s'""" % (package, package)
435                validPackages = False
436        return validPackages
437
438    def checkTestJars(self):
439        """
440        check if needed jars are here, if not,
441        dowload them and unzip the file if necessary
442        """
443
444        from indico.tests import TestConfig
445
446        jarsList = {}
447        currentFilePath = os.path.dirname(__file__)
448        testModPath = os.path.join(currentFilePath, 'indico', 'tests')
449
450        try:
451            jarsList['jsunit'] = {'path':     os.path.join(testModPath,
452                                                           'javascript',
453                                                           'unit'),
454                                  'url':      TestConfig.getInstance().getJSUnitURL(),
455                                  'filename': TestConfig.getInstance().getJSUnitFilename()}
456
457            jarsList['jscoverage'] = {'path':     os.path.join(testModPath,
458                                                               'javascript',
459                                                               'unit',
460                                                               'plugins'),
461                                      'url':      TestConfig.getInstance().getJSCoverageURL(),
462                                      'filename': TestConfig.getInstance().getJSCoverageFilename()}
463
464            jarsList['selenium'] = {'path':      os.path.join(testModPath,
465                                                              'python',
466                                                              'functional'),
467                                    'url':       TestConfig.getInstance().getSeleniumURL(),
468                                    'filename':  TestConfig.getInstance().getSeleniumFilename()}
469        except KeyError, key:
470            print "[ERR] Please specify a value for %s in tests.conf" % key
471            sys.exit(1)
472
473        validJars = True
474
475        for name in jarsList:
476            jar = jarsList[name]
477            #check if jar is already here
478            if not os.path.exists(os.path.join(jar['path'], jar['filename'])):
479                print "Downloading %s to %s..." % (jar['url'], jar['path'])
480                try:
481                    self.download(jar['url'], jar['path'])
482                except IOError, e:
483                    validJars = validJars and False
484                    print 'Could not download %s from %s (%s)' % (jar['filename'], jar['url'], e)
485
486        return validJars
487
488    def download(self, url, path):
489        """Copy the contents of a file from a given URL
490        to a local file.
491        """
492        import urllib
493        webFile = urllib.urlopen(url)
494        localFile = open(os.path.join(path, url.split('/')[-1]), 'w')
495        localFile.write(webFile.read())
496        webFile.close()
497        localFile.close()
498
499    def unzip(self, zipPath, inZipPath, targetFile):
500        """extract the needed file from zip and then delete the zip"""
501        import zipfile
502        try:
503            zfobj = zipfile.ZipFile(zipPath)
504            outfile = open(targetFile, 'wb')
505            outfile.write(zfobj.read(inZipPath))
506            outfile.flush()
507            outfile.close()
508
509            #delete zip file
510            os.unlink(zipPath)
511        except NameError, e:
512            print e
513
514
515class egg_filename(Command):
516    description = "Get the file name of the generated egg"
517    user_options = []
518    boolean_options = []
519
520    def initialize_options(self):
521        pass
522
523    def finalize_options(self):
524        ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
525        self.egg_info = ei_cmd.egg_info
526
527        basename = pkg_resources.Distribution(
528            None, None, ei_cmd.egg_name, ei_cmd.egg_version,
529            get_python_version(),
530            self.distribution.has_ext_modules() and pkg_utils.get_build_platform
531            ).egg_name()
532
533        print basename
534
535
536    def run(self):
537        pass
538
539
540if __name__ == '__main__':
541    # Always load source from the current folder
542    sys.path = [os.path.abspath('indico')] + sys.path
543
544    #PWD_INDICO_CONF = 'etc/indico.conf'
545    #if not os.path.exists(PWD_INDICO_CONF):
546    #    shutil.copy('etc/indico.conf.sample', PWD_INDICO_CONF)
547
548    from MaKaC.consoleScripts.installBase import *
549
550
551    #Dirty trick: For running tests, we need to load all the modules and get rid of unnecessary outputs
552    tempLoggingDir = None
553    if 'test' in sys.argv:
554        import logging
555        import tempfile
556        tempLoggingDir = tempfile.mkdtemp()
557        logging.basicConfig(filename=os.path.join(tempLoggingDir, 'logging'),
558                            level=logging.DEBUG)
559        setIndicoInstallMode(False)
560    else:
561        setIndicoInstallMode(True)
562
563    x = vars()
564    x.packageDir = os.path.join(get_python_lib(), 'MaKaC')
565
566
567    x.binDir = 'bin'
568    x.documentationDir = 'doc'
569    x.configurationDir = 'etc'
570    x.htdocsDir = 'htdocs'
571
572    dataFiles = _getDataFiles(x)
573
574    foundPackages = list('MaKaC.%s' % pkg for pkg in
575                         find_packages(where = 'indico/MaKaC'))
576    foundPackages.append('MaKaC')
577    foundPackages.append('htdocs')
578
579    # add our namespace package
580    foundPackages += list('indico.%s' % pkg for pkg in
581                         find_packages(where = 'indico',
582                                       exclude = ['htdocs*', 'MaKaC*']))
583    foundPackages.append('indico')
584
585    cmdclass = {'sdist': sdist_indico,
586                'bdist': _bdist_indico(dataFiles),
587                'bdist_egg': _bdist_egg_indico(dataFiles),
588                'jsbuild': jsbuild,
589                'fetchdeps': fetchdeps_indico,
590                'develop_config': develop_indico,
591                'test': test_indico,
592                'egg_filename': egg_filename
593                }
594
595    if BABEL_PRESENT:
596        for cmdname in ['init_catalog', 'extract_messages', 'compile_catalog', 'update_catalog']:
597            cmdclass['%s_js' % cmdname] = getattr(babel, cmdname)
598        cmdclass['compile_catalog_js'] = i18n.generate_messages_js
599
600    setup(name = "indico",
601          cmdclass = cmdclass,
602          version = _versionInit(),
603          description = "Indico is a full-featured conference lifecycle management and meeting/lecture scheduling tool",
604          author = "Indico Team",
605          author_email = "indico-team@cern.ch",
606          url = "http://indico-software.org",
607          download_url = "http://indico-software.org/wiki/Releases/Indico0.98-rc1",
608          platforms = ["any"],
609          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",
610          license = "http://www.gnu.org/licenses/gpl-2.0.txt",
611          entry_points = """
612            [console_scripts]
613
614            indico_scheduler = indico.modules.scheduler.daemon_script:main
615            indico_initial_setup = MaKaC.consoleScripts.indicoInitialSetup:main
616            indico_ctl = MaKaC.consoleScripts.indicoCtl:main
617            indico_livesync = indico.ext.livesync.console:main
618            indico_shell = indico.util.shell:main
619
620            [indico.ext_types]
621
622            Collaboration = MaKaC.plugins.Collaboration
623            InstantMessaging = MaKaC.plugins.InstantMessaging
624            RoomBooking = MaKaC.plugins.RoomBooking
625            EPayment = MaKaC.plugins.EPayment
626            livesync = indico.ext.livesync
627            importer = indico.ext.importer
628
629
630            [indico.ext]
631
632            Collaboration.EVO = MaKaC.plugins.Collaboration.EVO
633            Collaboration.Vidyo = MaKaC.plugins.Collaboration.Vidyo
634            Collaboration.CERNMCU = MaKaC.plugins.Collaboration.CERNMCU
635            Collaboration.RecordingManager = MaKaC.plugins.Collaboration.RecordingManager
636            Collaboration.RecordingRequest = MaKaC.plugins.Collaboration.RecordingRequest
637            Collaboration.WebcastRequest = MaKaC.plugins.Collaboration.WebcastRequest
638
639            RoomBooking.CERN = MaKaC.plugins.RoomBooking.CERN
640            RoomBooking.default = MaKaC.plugins.RoomBooking.default
641
642            EPayment.payPal = MaKaC.plugins.EPayment.payPal
643            EPayment.worldPay = MaKaC.plugins.EPayment.worldPay
644            EPayment.yellowPay = MaKaC.plugins.EPayment.yellowPay
645            EPayment.skipjack = MaKaC.plugins.EPayment.skipjack
646
647            importer.invenio = indico.ext.importer.invenio
648            importer.dummy = indico.ext.importer.dummy
649
650            InstantMessaging.XMPP = MaKaC.plugins.InstantMessaging.XMPP
651
652            livesync.invenio = indico.ext.livesync.invenio
653            livesync.cern_search = indico.ext.livesync.cern_search
654
655            """,
656          zip_safe = False,
657          packages = foundPackages,
658          package_dir = { 'indico': 'indico',
659                          'htdocs': os.path.join('indico', 'htdocs'),
660                          'MaKaC' : os.path.join('indico', 'MaKaC')},
661          package_data = {'indico': ['*.*']},
662          include_package_data=True,
663          namespace_packages = ['indico', 'indico.ext'],
664          install_requires = _getInstallRequires(),
665          data_files = dataFiles,
666          dependency_links = [
667                              EXTRA_RESOURCES_URL
668                              ]
669          )
670
671    #delete the temp folder used for logging
672    if 'test' in sys.argv:
673        shutil.rmtree(tempLoggingDir)
Note: See TracBrowser for help on using the repository browser.