Source

saturnalia / setup.py

Full commit
#!/usr/bin/env python

import os
import errno
import subprocess
import shutil
import webbrowser

from setuptools        import setup, Command
from distutils.command import clean
from glob              import glob


from distutils.extension import Extension
from Cython.Distutils import build_ext



rootDir = "."


def main():
    setup(
        name="saturnalia", 
        version="0.5.0",
        description="Distributed time series database.",
        author="saturnaliadb.org",
        author_email="saturnaliadb.org",
        url="http://spinn3r.com",
        license="MIT",
        package_dir = {
            'saturnalia'                      : 'src/python/saturnalia'                      ,
            'saturnalia.tile'                 : 'src/python/saturnalia/tile'                 ,
            'saturnalia.tools'                : 'src/python/saturnalia/tools'                ,
            'saturnalia.tests'                : 'src/python/saturnalia/tests'                ,
            'saturnalia.integration'          : 'src/python/saturnalia/integration'          ,
            'saturnalia.integration.collectd' : 'src/python/saturnalia/integration/collectd' ,
            'task'                            : 'src/python/task'                            ,
            },
        packages=[
            'saturnalia'                      ,
            'saturnalia.tile'                 ,
            'saturnalia.tools'                ,
            'saturnalia.tests'                ,
            'saturnalia.integration'          ,
            'saturnalia.integration.collectd' ,
            'task'                            ,
            ],
        scripts = glob('sbin/*'),
        ext_modules = [Extension("task.fieldtypes", ["src/python/task/fieldtypes.pyx"])],
        data_files = [
            ( '/usr/share/saturnalia/configs/system'       , [ 'config/system/common.conf'                                    ] ),
            ( '/usr/share/saturnalia/configs/metricd'      , [ 'config/metricd/metricd.conf'                                  ] ),
            ( '/usr/share/saturnalia/configs/routedb'      , [ 'config/routedb/routedb.conf'                                  ] ),
            ( '/usr/share/saturnalia/configs/componentdb'  , [ 'config/componentdb/componentdb.conf'                          ] ),
            ( '/usr/share/saturnalia/configs/sclientd'     , [ 'config/sclientd/sclientd.conf'                                ] ),
            ( '/usr/share/saturnalia/configs/sweb'         , [ 'config/sweb/sweb.conf'                                        ] ),
            ( '/usr/share/saturnalia/configs/managementd'  , [ 'config/managementd/managementd.conf'                          ] ),
            ( '/usr/share/saturnalia/collectd-integration' , [ 'config/collectd/saturnalia-collectd.conf'                     ] ),
            ( '/usr/share/saturnalia/collectd-integration' , [ 'src/python/saturnalia/integration/collectd/saturnaliasock.py' ] ),
            ],
        include_package_data = True,
        package_data = {
            },
        cmdclass = {
            'build_ext'   : build_ext        ,
            'test'        : RunTrial         ,
            'build_js'    : BuildJavaScript  ,
            'cython'      : RunCython        ,
            'clean'       : SaturnaliaClean  ,
            },
        command_options = {
            'aliases': buildAliases( dict(
                prepare  =( 'build_js', 'build_ext' ),
                build    =( 'prepare', 'build'          ),
                build_ext=( 'cython', 'build_ext', '--inplace' ),
                test     =( 'prepare', 'test'         ),
                )
              )
            },
        )



def buildCommand ( command, dependencies ):

    result = []


    if command not in dependencies:
        result.append( command )
        
    else:

        for subCommand in dependencies[ command ]:

            if subCommand == command:
                result.append( subCommand )
            
            else:
                for dep in buildCommand( subCommand, dependencies ):
                    result.append( dep )

    return result


def buildAliases ( dependencies ):

    result = {}

    for command in dependencies:
        expanded = buildCommand( command, dependencies )

        result[ command ] = ('setup.py', " ".join( expanded ) )
        

    return result


def initFileLocation ( dirName, fileName ):


    try:
        os.makedirs( dirName )

    except os.error, ex:
        if ex.errno != errno.EEXIST:
            raise ex

    filePath = os.path.join( dirName, fileName )

    if fileName in os.listdir( dirName ):
        os.unlink( filePath )


    return filePath


def deleteTree ( path ):

    try:
        shutil.rmtree( path )

    except os.error, ex:
        if ex.errno != errno.ENOENT:
            raise ex
        

class SaturnaliaClean ( clean.clean ):

    def run(self):
        dirs = [
            os.path.join( rootDir, "test"  ),
            os.path.join( rootDir, "saturnalia.egg-info" ),
            os.path.join( rootDir, "_trial_temp" ),
            os.path.join( rootDir, "build" ),
            ]


        for path in dirs:

            try:
                shutil.rmtree( path )

            except os.error, ex:
                if ex.errno != errno.ENOENT:
                    raise ex


        files = [
            os.path.join( rootDir, "src", "python", "task", "fieldtypes.so" ),
            os.path.join( rootDir, "src", "python", "task", "fieldtypes.c" ),
            os.path.join( rootDir, "src", "python", "saturnalia", "saturnalia_pb2.py" ),
            os.path.join( rootDir, "src", "html", "console.js" ),
            ]

        for path in files:

            try:
                os.unlink( path )

            except os.error, ex:
                if ex.errno != errno.ENOENT:
                    raise ex


        clean.clean.run(self)

        
class RunCython (Command):
    description = 'generate .c from .pyx files'

    user_options = []

    

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):

        inputdir  = os.path.join( rootDir, 'src', 'python', 'task' )
        inputpath = os.path.join( inputdir, 'fieldtypes.pyx' )

        systemWorker('cython',  inputpath )

        
class BuildJavaScript (Command):

    description = 'generate java script files'

    user_options = []

    dependencies = {
        'DataContainer.js'      : [ 'saturnalia.js' ],
        'EventBus.js'           : [ 'saturnalia.js' ],
        'TaskHandle.js'         : [ 'saturnalia.js' ],
        'ComponentDB.js'        : [ 'saturnalia.js' ],
        'MessageCoordinator.js' : [ 'saturnalia.js' ],
        'Colors.js'             : [ 'saturnalia.js' ],
        'DataConfig.js'         : [ 'saturnalia.js' ],
        'LineChart.js'          : [ 'Colors.js' ],
        'ChartComponent.js'     : [ 'saturnalia.js' , 'DataConfig.js' ],
        'HeaderComponent.js'    : [ 'saturnalia.js' ],
        'ContextChart.js'       : [ 'saturnalia.js', 'i18n.js', 'Select.js', 'Drag.js', 'RegionSelector.js', 'DataSelector.js' ],
        'widget.js'             : [ 'DataContainer.js', 'PieChart.js', 'StackedChart.js', 'ContextChart.js', ],
        'boot_console.js'       : [ 'saturnalia.js', 'EventBus.js', 'TaskHandle.js', 'ComponentDB.js', 'widget.js', 'MessageCoordinator.js', 'cleave.js', 'LineChart.js', 'components.js', 'ChartComponent.js', 'HeaderComponent.js'  ],
        'console.js'            : [ 'boot_console.js' ],
        }
    

    def initialize_options ( self ):
        pass

    def finalize_options ( self ):
        pass

    def buildIncludes ( self, targetName, dependencies ):

        result = []

        if targetName in dependencies:

            for subTargetName in dependencies[ targetName ]:

                if subTargetName not in result:

                    if subTargetName in dependencies:

                        for dep in self.buildIncludes( subTargetName, dependencies ):

                            if dep not in result:
                                result.append( dep )


                if targetName in result:
                    raise ValueError ( "Circular dependencies not supported. Found for %s" % ( targetName, ) )

                result.append( subTargetName )


        return result
        


    def run ( self ):

        outFile     = "console.js"
        buildDir    = os.path.join( rootDir, "src", "html" )
        outFilePath = initFileLocation( buildDir, outFile )

        outHandle  = open( outFilePath, 'w' )

        includes = self.buildIncludes( outFile, self.dependencies )

        for fileName in includes:
            path = os.path.join('.', 'src', 'js', fileName )

            subFile = open( path )

            for line in subFile:
                outHandle.write( line )



class RunTrial (Command):

    description = 'run unittests with trial'

    __slots__ = ['coverage', 'target', 'skip_pyflakes']
    
    user_options = [

        ('skip-pyflakes', None,
         "don't run pyflakes before running tests"),
        
        ('coverage', None,
         'generate --coverage from trial tests'),
        
        ('target=', None,
         'specify a test target instead of default of "saturnalia"'),
        
        ]

    def initialize_options(self):
        self.skip_pyflakes = False
        self.coverage      = False
        self.target        = None

    def finalize_options(self):
        pass

    def run(self):
        deleteTree( "test" )
        shutil.copytree( "src", "test", symlinks=True )

        if self.coverage:
            self._run_coverage()
        else:
            self._run_trial()

            
    def _run_coverage(self):
        if self.target != None:
            raise SystemExit('Options --coverage and --target are mutually exclusive.')

        path = os.path.join( ".", "test", "python" )

        system('coverage', 'run', '--branch', '--source', path, find_exec('trial'), 'saturnalia')
        system('coverage', 'html')
        indexpath = os.path.join('htmlcov', 'index.html')
        print 'Coverage index: %r' % (indexpath,)
        webbrowser.open(indexpath)

    def _run_trial(self):

        target = self.target

        targets = ['saturnalia', 'task']

        if target != None:
            targets = [target]

        if not self.skip_pyflakes:
            path = os.path.join( ".", "test", "python" )

            system('pyflakes', path )

        for work in targets:
            system('trial', work)


def system(*argv, **kwargs):
    _tweak_pythonpath()

    print 'Executing: %r' % (argv,)

    systemWorker( *argv, **kwargs )


def systemWorker(*argv, **kwargs):

    r = subprocess.call(argv, **kwargs)
    if r != 0:
        raise SystemExit(r)


def _tweak_pythonpath():
    if not _tweak_pythonpath.completed:
        pysrc = os.path.join( ".", "test", "python" )
        ppath = os.environ.get('PYTHONPATH', '')
        ppath = '%s:%s' % (pysrc, ppath)
        os.environ['PYTHONPATH'] = ppath
        print 'PYTHONPATH=%r' % (ppath,)
        _tweak_pythonpath.completed = True

_tweak_pythonpath.completed = False


def find_exec(name):
    for d in os.environ.get('PATH', []).split(os.pathsep):
        path = os.path.join(d, name)
        print 'DEBUG', `path`
        if os.access(path, os.X_OK):
            return path
    raise SystemExit('Could not find executable: %r' % (name,))


if __name__ == '__main__':
    main()