Example #1
0
def test_perf(params=''):
    """
    Runs the performance tests against the configured service and produce the report
    in dist/

    :params str params: Parameters to pass to Funkload bench

    Examples::

        fab dist.test_perf
        fab dist.test_perf:"-c 1:15 -D 1"

    """
    try:
        import funkload
    except ImportError:
        abort('Funkload module missing, please install it first')

    # Create report folder if needed
    report_dir = dist_join('report/html')
    if not os.path.exists(report_dir):
        os.makedirs(report_dir)

    # Run the Funkload tests in perf test folder
    with lcd(rel_join('tests/perf')):
        with settings(show('running','stdout')):
            local('fl-run-bench %s tests.py MultiprojectTestCase.test_smoke' % params)
            local('fl-build-report -o %s --html smoke-bench.xml' % report_dir)

    logger.info('Testing completed. Test report can be found in: %s' % report_dir)
Example #2
0
def test_perf(params=''):
    """
    Runs the performance tests against the configured service and produce the report
    in dist/

    :params str params: Parameters to pass to Funkload bench

    Examples::

        fab dist.test_perf
        fab dist.test_perf:"-c 1:15 -D 1"

    """
    try:
        import funkload
    except ImportError:
        abort('Funkload module missing, please install it first')

    # Create report folder if needed
    report_dir = dist_join('report/html')
    if not os.path.exists(report_dir):
        os.makedirs(report_dir)

    # Run the Funkload tests in perf test folder
    with lcd(rel_join('tests/perf')):
        with settings(show('running', 'stdout')):
            local('fl-run-bench %s tests.py MultiprojectTestCase.test_smoke' %
                  params)
            local('fl-build-report -o %s --html smoke-bench.xml' % report_dir)

    logger.info('Testing completed. Test report can be found in: %s' %
                report_dir)
Example #3
0
def test(case='', config='tests.ini'):
    """
    Runs the functional tests against the setup specified in configuration

    :param str case: Name or path to case file
    :param str config: Path to config file, relative to current directory

    Examples::

        fab dist.test:smoke
        fab dist.test:path/to/case.py
        fab dist.test:smoke,~/firefox.ini
        fab dist.test:smoke,config=path/to/config.ini

    """
    try:
        from nose.core import TestProgram
        from nose.plugins import Plugin
    except ImportError:
        TestProgram = None
        Plugin = object
        return abort('For running tests, Nose testing framework is required. Please install it first: "pip install nose"')

    if not case:
        return abort('Please provide either name or path to test case')

    # Determine the case file: name or path accepted
    webtests_dir = rel_join('tests/webtests')
    casepath = os.path.abspath(case) if case.endswith('.py') else join(webtests_dir, 'cases/%s.py' % case)
    configpath = os.path.join(os.curdir, os.path.expanduser(config))

    logger.info('Running functional tests from: %s' % casepath)
    logger.info('Reading tests configuration from: %s' % configpath)

    class TestConfigPlugin(Plugin):
        """
        Simple Nose plugin to set test configuration path to testcase::

            class MyTestcase(unittest.TestCase)
                def setUp(self):
                    self.config_path

        """
        name = 'testconfig'
        can_configure = True
        enabled = True

        def options(self, parser, env):
            pass

        def configure(self, options, conf):
            pass

        def startTest(self, test):
            test_case = test.test.__class__
            test_case.config_path = configpath

    TestProgram(argv=['fab', casepath], addplugins=[TestConfigPlugin()])
Example #4
0
def trac_admin(env, cmd, sudoer=None):
    """
    Runs trac-admin command on specified environment with permiss
    :param env: Name or path to the environment
    :param cmd: Command to pass to trac-admin
    :param sudoer: Optional sudo user, defaults to Apache user

    Examples::

        fab dist.trac_admin:home,help
        fab dist.trac_admin:"home","mp deploy"
        fab dist.trac_admin:env="home",cmd="mp deploy",sudoer="root"
        fab dist.trac_admin:"/var/www/trac/projects/projectx","upgrade"
        fab dist.trac_admin:"/var/www/trac/projects/projectx","upgrade","www-data"

    """
    trac_root_dir = config['trac_root']
    sudoer = sudoer or config['webserver_user']
    if sudoer == 'root':
        sudoer = None

    # Check if path is given, otherwise consider it project name
    if not exists(env):
        env = os.path.join(trac_root_dir, 'projects', env)
        if not exists(env):
            return abort('Given environment "%s" cannot be found on server' % env)

    with cd(env):
        tracadmin_cmd = 'trac-admin %s %s' % (env, cmd)
        sudo(tracadmin_cmd, user=sudoer)
Example #5
0
def trac_admin(env, cmd, sudoer=None):
    """
    Runs trac-admin command on specified environment with permiss
    :param env: Name or path to the environment
    :param cmd: Command to pass to trac-admin
    :param sudoer: Optional sudo user, defaults to Apache user

    Examples::

        fab dist.trac_admin:home,help
        fab dist.trac_admin:"home","mp deploy"
        fab dist.trac_admin:env="home",cmd="mp deploy",sudoer="root"
        fab dist.trac_admin:"/var/www/trac/projects/projectx","upgrade"
        fab dist.trac_admin:"/var/www/trac/projects/projectx","upgrade","www-data"

    """
    trac_root_dir = config['trac_root']
    sudoer = sudoer or config['webserver_user']
    if sudoer == 'root':
        sudoer = None

    # Check if path is given, otherwise consider it project name
    if not exists(env):
        env = os.path.join(trac_root_dir, 'projects', env)
        if not exists(env):
            return abort('Given environment "%s" cannot be found on server' %
                         env)

    with cd(env):
        tracadmin_cmd = 'trac-admin %s %s' % (env, cmd)
        sudo(tracadmin_cmd, user=sudoer)
Example #6
0
def deploy(package, opts=''):
    """
    Uploads the given package to remote host and deploys it there.

    :param str package:
        Path to tar.gz package in local file system. In case of wildcard, all the matched package are deployed.
        Package can be in formats: tar.gz (custom package structure, deb, rpm
    :param str opts:
        Optional parameters to pass to deploying app (easy_install, rpm, dpkg, deploy.sh)

    Examples::

        fab dist.deploy:package=../../package.tar.gz
        fab dist.deploy:package=../../package.tar.gz,opts="--theme --activate"
        fab dist.deploy:package=../../*.deb
        fab dist.deploy:package=../../*.deb,opts='--force'

    """
    # Use glob to find package from local filesystem (glob supports wildcards)
    pmatches = glob(os.path.expandvars(os.path.expanduser(package)))
    if not pmatches:
        return abort('No package can be found with name: %s' % package)

    # Iterate matched packages
    # Upload package(s) to remote host and determine the name of release folder
    for pmatch in pmatches:
        package = os.path.normpath(pmatch)

        # Get the release name from package: drop the extension and version
        packagename = os.path.basename(package)
        releasename, releaseversion, releaseextension = split_package_name(
            packagename)

        # Upload package to home directory, with same as the orig
        logger.info('Uploading the package: %s -> %s' % (package, packagename))
        put(package, packagename)

        logger.info('Release name: %s' % releasename)

        # Run the package specific deployment actions
        if releaseextension == 'tar.gz':
            deploy_targz(packagename, opts)
        elif releaseextension == 'egg':
            opts = opts or '-Z'
            sudo('easy_install %s %s' % (opts, packagename))
        elif releaseextension == 'deb':
            opts = opts or '--install'
            sudo('dpkg %s %s' % (opts, packagename))
        elif releaseextension == 'rpm':
            opts = opts or '-Uvh'
            sudo('rpm %s %s' % (opts, packagename))

        # Remove the package
        with cd('~'):
            sudo('rm -f ./%s' % packagename)

    # Restart apache
    logger.info('Restarting apache')
    apache = Apache()
    apache.restart()
Example #7
0
def deploy(package, opts=''):
    """
    Uploads the given package to remote host and deploys it there.

    :param str package:
        Path to tar.gz package in local file system. In case of wildcard, all the matched package are deployed.
        Package can be in formats: tar.gz (custom package structure, deb, rpm
    :param str opts:
        Optional parameters to pass to deploying app (easy_install, rpm, dpkg, deploy.sh)

    Examples::

        fab dist.deploy:package=../../package.tar.gz
        fab dist.deploy:package=../../package.tar.gz,opts="--theme --activate"
        fab dist.deploy:package=../../*.deb
        fab dist.deploy:package=../../*.deb,opts='--force'

    """
    # Use glob to find package from local filesystem (glob supports wildcards)
    pmatches = glob(os.path.expandvars(os.path.expanduser(package)))
    if not pmatches:
        return abort('No package can be found with name: %s' % package)

    # Iterate matched packages
    # Upload package(s) to remote host and determine the name of release folder
    for pmatch in pmatches:
        package = os.path.normpath(pmatch)

        # Get the release name from package: drop the extension and version
        packagename = os.path.basename(package)
        releasename, releaseversion, releaseextension = split_package_name(packagename)

        # Upload package to home directory, with same as the orig
        logger.info('Uploading the package: %s -> %s' % (package, packagename))
        put(package, packagename)

        logger.info('Release name: %s' % releasename)

        # Run the package specific deployment actions
        if releaseextension == 'tar.gz':
            deploy_targz(packagename, opts)
        elif releaseextension == 'egg':
            opts = opts or '-Z'
            sudo('easy_install %s %s' % (opts, packagename))
        elif releaseextension == 'deb':
            opts = opts or '--install'
            sudo('dpkg %s %s' % (opts, packagename))
        elif releaseextension == 'rpm':
            opts = opts or '-Uvh'
            sudo('rpm %s %s' % (opts, packagename))

        # Remove the package
        with cd('~'):
            sudo('rm -f ./%s' % packagename)

    # Restart apache
    logger.info('Restarting apache')
    apache = Apache()
    apache.restart()
Example #8
0
def upload(package, rdir=''):
    """
    Uploads the given package to remote host

    :param str package: Path to package, absolute or relative
    :param str rdir: Remote directory where to upload the package. Defaults to users home directory

    Examples::

        fab dist.upload:package.tar.gz,/tmp
        fab dist.upload:package=../../package.tar.gz
        fab dist.upload:package=../../packa*.tar.gz
        fab dist.upload:package=../../package.tar.gz,rdir=/tmp

    .. NOTE::

        Special paths, containing environment variables or tilde characters are not supported.

    """
    # Use glob to find package from local filesystem (glob supports wildcards)
    pmatches = glob(os.path.expandvars(os.path.expanduser(package)))
    if not pmatches:
        return abort('No package can be found with name: %s' % package)

    # Upload package(s) to remote host and determine the name of release folder
    for pmatch in pmatches:
        package = os.path.normpath(pmatch)

        # Get the release name from package: drop the extension and version
        packagename = os.path.basename(package)
        target_path = join(rdir, packagename)  if rdir else packagename
        target_dir = os.path.dirname(target_path)

        # Upload package to specified directory, with the same name as the orig
        logger.info('Uploading the package: %s -> %s' % (package, target_path))

        if not exists(target_dir):
            run(target_dir)

        put(package, target_path)
Example #9
0
def upload(package, rdir=''):
    """
    Uploads the given package to remote host

    :param str package: Path to package, absolute or relative
    :param str rdir: Remote directory where to upload the package. Defaults to users home directory

    Examples::

        fab dist.upload:package.tar.gz,/tmp
        fab dist.upload:package=../../package.tar.gz
        fab dist.upload:package=../../packa*.tar.gz
        fab dist.upload:package=../../package.tar.gz,rdir=/tmp

    .. NOTE::

        Special paths, containing environment variables or tilde characters are not supported.

    """
    # Use glob to find package from local filesystem (glob supports wildcards)
    pmatches = glob(os.path.expandvars(os.path.expanduser(package)))
    if not pmatches:
        return abort('No package can be found with name: %s' % package)

    # Upload package(s) to remote host and determine the name of release folder
    for pmatch in pmatches:
        package = os.path.normpath(pmatch)

        # Get the release name from package: drop the extension and version
        packagename = os.path.basename(package)
        target_path = join(rdir, packagename) if rdir else packagename
        target_dir = os.path.dirname(target_path)

        # Upload package to specified directory, with the same name as the orig
        logger.info('Uploading the package: %s -> %s' % (package, target_path))

        if not exists(target_dir):
            run(target_dir)

        put(package, target_path)
Example #10
0
def build(release='false', compress='false', docs='', pkgs='tar', version='', ext='true',
          extbranch='master'):
    """
    Create distributable packages. Builds eggs and tar.gz compressed packages, based on
    parameters. Also capable of downloading and patching external dependencies.

    :param release:
        Make release build or not. Release sets/increments the version number. Default 'false'
    :param compress:
        Compress js/css files nor not. Default 'false'
    :param docs:
        Names of the documentation targets to build. Default '' means no doc building
    :param pkgs:
        Package formats to build sources into, separated with space. Valid values: tar deb rpm
    :param version:
        Version number to set for whole package. Default '' -> take the version from VERSION.txt
        (or default to 1.0.0)
    :param ext:
        Build and include external modules into big package. Default is 'false'.
        If ext is 'all', builds also other than own forks (GitResources).
    :param extbranch:
        Defines from which branch the fork packages are to be built from.

    Examples::

        fab dist.build
        fab dist.build:release=true,docs=html
        fab dist.build:compress=true,version=1.2.3,pkgs="deb tar rpm"

    .. NOTE:: Python modules get their version number from setup.py

    """
    # NOTE: Fabric parameters are always in string format

    # Get the list of package formats (space delimeter)
    pkg_formats = pkgs.split(' ')

    # Determine the version: parameter vs. VERSION.txt vs. default
    if not version:
        version_path = os.path.join(PROJECT_DIR, 'VERSION.txt')
        if os.path.exists(version_path):
            version = set_version_in_file(version_path, version)
        else:
            version = '1.0.0'

    # Create package name from pkg name and version
    package_name = '%s-%s' % (PKG_NAME, version)
    pkg_join = lambda *path: join(BUILD_DIR, package_name, *path)

    logger.info('Preparing build env...')

    # Copy relevant files to build dir (so that they can be edited directly)
    shutil.rmtree(BUILD_DIR, ignore_errors=True)
    del SRC_DIRS[SRC_DIRS.index('libs')]
    del SRC_DIRS[SRC_DIRS.index('etc')]
    for src_dir in SRC_DIRS:
        shutil.copytree(src_dir, pkg_join(src_dir))

    if not os.path.exists(DIST_DIR):
        os.makedirs(DIST_DIR)

    # Copy additional files
    shutil.copy('README.rst', pkg_join('README'))
    os.makedirs(pkg_join('scripts'))
    shutil.copy(rel_join('scripts/deploy.sh'), pkg_join('scripts/deploy.sh'))
    shutil.copy(rel_join('scripts/update.py'), pkg_join('scripts/update.py'))
    shutil.copytree(rel_join('scripts/hooks'), pkg_join('scripts/hooks'))
    shutil.copytree(rel_join('scripts/cron'), pkg_join('scripts/cron'))

    # Build documentation
    if docs:
        # List the target formats/builders
        builddoc(docs, pkg_join('docs'))
    else:
        # Ensure there is at least empty directory (for archive)
        os.makedirs(pkg_join('docs'))

    # Build configuration
    buildetc(outdir=pkg_join('etc'), section='DEFAULT')

    # Increment version of each plugin if making a release
    if get_bool_str(release):
        logger.info('Setting/incrementing version numbers...')
        for setuppy_path in get_files(pkg_join('plugins'), 'setup.py', recursive=True):
            # Check if plugin folder contains VERSION.txt (non-versioned file)
            version_path = os.path.join(os.path.dirname(setuppy_path), 'VERSION.txt')
            if not os.path.exists(version_path):
                logger.warning('VERSION.txt missing, using version found in setup.py')
                version_path = setuppy_path

            # Set version information in file.
            # NOTE: If version is empty, it is determined from version file (either VERSION.txt or setup.py)
            set_version_in_file(version_path, version)

    # Optional compress (edits copied files under build)
    if get_bool_str(compress):
        logger.info('Compressing files...')

        with settings(warn_only=True):
            # Compress theme resources
            for respath in get_files(pkg_join('themes'), '*.css', recursive=True):
                local('yui-compressor --charset utf-8 -o %s %s' % (respath, respath))
            for respath in get_files(pkg_join('themes'), '*.js', recursive=True):
                local('yui-compressor --charset utf-8 -o %s %s' % (respath, respath))

            # Compress plugin resources
            for respath in get_files(pkg_join('plugins'), '*.css', recursive=True):
                local('yui-compressor --charset utf-8 -o %s %s' % (respath, respath))
            for respath in get_files(pkg_join('plugins'), '*.js', recursive=True):
                local('yui-compressor --charset utf-8 -o %s %s' % (respath, respath))

        # Aggregate js+css resources into bundle
        for template_path in get_files(pkg_join('themes'), 'resources.html', recursive=True):
            logger.info('Template path: %s' % template_path)
            bundle(template_path, pkg_join('themes/default/htdocs'))

        logger.info('Compression completed.')

    # Build eggs and source packages (in build dir)
    logger.info('Laying eggs and source packages...')
    with lcd(pkg_join()):
        for plugin_dir in PLUGIN_DIRS:
            with lcd(plugin_dir):
                local('python setup.py bdist_egg')
                local('python setup.py sdist')

    # Build external plugins as well, optionally even non-fork plugins
    # Retrieve and build external plugins and copy the artifacts into plugins folder.
    # NOTE: Next egg copying will put them into correct place, no need to rerun the file copy
    allext = 'true' if ext.lower() == 'all' else 'false'
    if get_bool_str(ext) or allext:
        buildext(allext=allext,branch=extbranch)
        for egg in get_files(build_join('ext'), '*.egg', recursive=True):
            shutil.copy(egg, pkg_join('plugins', os.path.basename(egg)))

    # Copy eggs and sdisted files from plugins directory to dist and plugin directories
    for egg in get_files(pkg_join('plugins/multiproject'), '*.egg', recursive=True):
        shutil.copy(egg, dist_join(os.path.basename(egg)))
        shutil.copy(egg, pkg_join('plugins'))

    for targz in get_files(pkg_join('plugins'), '*.tar.gz', recursive=True):
        shutil.copy(targz, dist_join(os.path.basename(targz)))

    # Create dist if not available
    if not os.path.exists(DIST_DIR):
        os.makedirs(DIST_DIR)

    # Create one big package to contain 'em all
    if 'tar.gz' in pkg_formats or 'tar' in pkg_formats:
        logger.info('Creating complete .tar.gz package...')
        # TODO: Archive could be implemented in pure python
        # TODO: These patterns seem to assume build dir == project dir
        exclude_patterns = [
            '.*', 'tests', 'documents', '*.egg-info', 'ext/libs', 'ext/plugins',
            'sample', 'build', 'plugins/multiproject'
        ]
        exclude_param = ' '.join(['--exclude=%s' % pt for pt in exclude_patterns])
        with lcd(BUILD_DIR):
            #local('tar -czf %s.tar.gz --exclude-vcs %s %s' %
            #    (dist_join(package_name), exclude_param, package_name))
            local('tar -czf %s.tar.gz %s' %
                (dist_join(package_name), package_name))

    # Debian package
    if 'deb' in pkg_formats:
        logger.info('Creating .deb package...')
        try:
            from stdeb import command
        except ImportError:
            command = None
            abort('Module stddep (http://pypi.python.org/pypi/stdeb) was not found, cannot build .deb package')

        # Run setup.py bdist_deb inside each plugin. It generates deb_dist/<pkgname>/ directory
        for setuppy_path in get_files(os.path.abspath(pkg_join('plugins')), 'setup.py', recursive=True):
            plugin_dir = os.path.dirname(setuppy_path)

            with settings(hide('stdout', 'stderr')):
                with lcd(plugin_dir):
                    local('python setup.py --command-packages=stdeb.command bdist_deb')

                # Package command needs to be run inside the generated folder. Find it and run the command
                for debdist_path in get_files(os.path.join(plugin_dir, 'deb_dist'), 'setup.py', recursive=True):
                    with lcd(os.path.dirname(debdist_path)):
                        local('dpkg-buildpackage -rfakeroot -uc -us')

        # Copy .deb packages to dist
        for deb_path in get_files(pkg_join('plugins'), '*.deb', recursive=True):
            shutil.copy(deb_path, dist_join(os.path.basename(deb_path)))

    # Redhat package
    if 'rpm' in pkg_formats:
        logger.info('Creating .rpm package...')

        with settings(hide('stdout', 'running')):
            # Run setup.py bdist_rpm inside each plugin. It generates deb_dist/<pkgname>/ directory
            for setuppy_path in get_files(os.path.abspath(pkg_join('plugins')), 'setup.py', recursive=True):
                plugin_dir = os.path.dirname(setuppy_path)
                with lcd(plugin_dir):
                    local('python setup.py bdist_rpm')

            # Copy .rpm packages to dist
            for rpm_path in get_files(pkg_join('plugins'), '*.rpm', recursive=True):
                shutil.copy(rpm_path, dist_join(os.path.basename(rpm_path)))

    logger.info('Building completed.')
Example #11
0
def build(release='false',
          compress='false',
          docs='',
          pkgs='tar',
          version='',
          ext='true',
          extbranch='master'):
    """
    Create distributable packages. Builds eggs and tar.gz compressed packages, based on
    parameters. Also capable of downloading and patching external dependencies.

    :param release:
        Make release build or not. Release sets/increments the version number. Default 'false'
    :param compress:
        Compress js/css files nor not. Default 'false'
    :param docs:
        Names of the documentation targets to build. Default '' means no doc building
    :param pkgs:
        Package formats to build sources into, separated with space. Valid values: tar deb rpm
    :param version:
        Version number to set for whole package. Default '' -> take the version from VERSION.txt
        (or default to 1.0.0)
    :param ext:
        Build and include external modules into big package. Default is 'false'.
        If ext is 'all', builds also other than own forks (GitResources).
    :param extbranch:
        Defines from which branch the fork packages are to be built from.

    Examples::

        fab dist.build
        fab dist.build:release=true,docs=html
        fab dist.build:compress=true,version=1.2.3,pkgs="deb tar rpm"

    .. NOTE:: Python modules get their version number from setup.py

    """
    # NOTE: Fabric parameters are always in string format

    # Get the list of package formats (space delimeter)
    pkg_formats = pkgs.split(' ')

    # Determine the version: parameter vs. VERSION.txt vs. default
    if not version:
        version_path = os.path.join(PROJECT_DIR, 'VERSION.txt')
        if os.path.exists(version_path):
            version = set_version_in_file(version_path, version)
        else:
            version = '1.0.0'

    # Create package name from pkg name and version
    package_name = '%s-%s' % (PKG_NAME, version)
    pkg_join = lambda *path: join(BUILD_DIR, package_name, *path)

    logger.info('Preparing build env...')

    # Copy relevant files to build dir (so that they can be edited directly)
    shutil.rmtree(BUILD_DIR, ignore_errors=True)
    del SRC_DIRS[SRC_DIRS.index('libs')]
    del SRC_DIRS[SRC_DIRS.index('etc')]
    for src_dir in SRC_DIRS:
        shutil.copytree(src_dir, pkg_join(src_dir))

    if not os.path.exists(DIST_DIR):
        os.makedirs(DIST_DIR)

    # Copy additional files
    shutil.copy('README.rst', pkg_join('README'))
    os.makedirs(pkg_join('scripts'))
    shutil.copy(rel_join('scripts/deploy.sh'), pkg_join('scripts/deploy.sh'))
    shutil.copy(rel_join('scripts/update.py'), pkg_join('scripts/update.py'))
    shutil.copytree(rel_join('scripts/hooks'), pkg_join('scripts/hooks'))
    shutil.copytree(rel_join('scripts/cron'), pkg_join('scripts/cron'))

    # Build documentation
    if docs:
        # List the target formats/builders
        builddoc(docs, pkg_join('docs'))
    else:
        # Ensure there is at least empty directory (for archive)
        os.makedirs(pkg_join('docs'))

    # Build configuration
    buildetc(outdir=pkg_join('etc'), section='DEFAULT')

    # Increment version of each plugin if making a release
    if get_bool_str(release):
        logger.info('Setting/incrementing version numbers...')
        for setuppy_path in get_files(pkg_join('plugins'),
                                      'setup.py',
                                      recursive=True):
            # Check if plugin folder contains VERSION.txt (non-versioned file)
            version_path = os.path.join(os.path.dirname(setuppy_path),
                                        'VERSION.txt')
            if not os.path.exists(version_path):
                logger.warning(
                    'VERSION.txt missing, using version found in setup.py')
                version_path = setuppy_path

            # Set version information in file.
            # NOTE: If version is empty, it is determined from version file (either VERSION.txt or setup.py)
            set_version_in_file(version_path, version)

    # Optional compress (edits copied files under build)
    if get_bool_str(compress):
        logger.info('Compressing files...')

        with settings(warn_only=True):
            # Compress theme resources
            for respath in get_files(pkg_join('themes'),
                                     '*.css',
                                     recursive=True):
                local('yui-compressor --charset utf-8 -o %s %s' %
                      (respath, respath))
            for respath in get_files(pkg_join('themes'),
                                     '*.js',
                                     recursive=True):
                local('yui-compressor --charset utf-8 -o %s %s' %
                      (respath, respath))

            # Compress plugin resources
            for respath in get_files(pkg_join('plugins'),
                                     '*.css',
                                     recursive=True):
                local('yui-compressor --charset utf-8 -o %s %s' %
                      (respath, respath))
            for respath in get_files(pkg_join('plugins'),
                                     '*.js',
                                     recursive=True):
                local('yui-compressor --charset utf-8 -o %s %s' %
                      (respath, respath))

        # Aggregate js+css resources into bundle
        for template_path in get_files(pkg_join('themes'),
                                       'resources.html',
                                       recursive=True):
            logger.info('Template path: %s' % template_path)
            bundle(template_path, pkg_join('themes/default/htdocs'))

        logger.info('Compression completed.')

    # Build eggs and source packages (in build dir)
    logger.info('Laying eggs and source packages...')
    with lcd(pkg_join()):
        for plugin_dir in PLUGIN_DIRS:
            with lcd(plugin_dir):
                local('python setup.py bdist_egg')
                local('python setup.py sdist')

    # Build external plugins as well, optionally even non-fork plugins
    # Retrieve and build external plugins and copy the artifacts into plugins folder.
    # NOTE: Next egg copying will put them into correct place, no need to rerun the file copy
    allext = 'true' if ext.lower() == 'all' else 'false'
    if get_bool_str(ext) or allext:
        buildext(allext=allext, branch=extbranch)
        for egg in get_files(build_join('ext'), '*.egg', recursive=True):
            shutil.copy(egg, pkg_join('plugins', os.path.basename(egg)))

    # Copy eggs and sdisted files from plugins directory to dist and plugin directories
    for egg in get_files(pkg_join('plugins/multiproject'),
                         '*.egg',
                         recursive=True):
        shutil.copy(egg, dist_join(os.path.basename(egg)))
        shutil.copy(egg, pkg_join('plugins'))

    for targz in get_files(pkg_join('plugins'), '*.tar.gz', recursive=True):
        shutil.copy(targz, dist_join(os.path.basename(targz)))

    # Create dist if not available
    if not os.path.exists(DIST_DIR):
        os.makedirs(DIST_DIR)

    # Create one big package to contain 'em all
    if 'tar.gz' in pkg_formats or 'tar' in pkg_formats:
        logger.info('Creating complete .tar.gz package...')
        # TODO: Archive could be implemented in pure python
        # TODO: These patterns seem to assume build dir == project dir
        exclude_patterns = [
            '.*', 'tests', 'documents', '*.egg-info', 'ext/libs',
            'ext/plugins', 'sample', 'build', 'plugins/multiproject'
        ]
        exclude_param = ' '.join(
            ['--exclude=%s' % pt for pt in exclude_patterns])
        with lcd(BUILD_DIR):
            #local('tar -czf %s.tar.gz --exclude-vcs %s %s' %
            #    (dist_join(package_name), exclude_param, package_name))
            local('tar -czf %s.tar.gz %s' %
                  (dist_join(package_name), package_name))

    # Debian package
    if 'deb' in pkg_formats:
        logger.info('Creating .deb package...')
        try:
            from stdeb import command
        except ImportError:
            command = None
            abort(
                'Module stddep (http://pypi.python.org/pypi/stdeb) was not found, cannot build .deb package'
            )

        # Run setup.py bdist_deb inside each plugin. It generates deb_dist/<pkgname>/ directory
        for setuppy_path in get_files(os.path.abspath(pkg_join('plugins')),
                                      'setup.py',
                                      recursive=True):
            plugin_dir = os.path.dirname(setuppy_path)

            with settings(hide('stdout', 'stderr')):
                with lcd(plugin_dir):
                    local(
                        'python setup.py --command-packages=stdeb.command bdist_deb'
                    )

                # Package command needs to be run inside the generated folder. Find it and run the command
                for debdist_path in get_files(os.path.join(
                        plugin_dir, 'deb_dist'),
                                              'setup.py',
                                              recursive=True):
                    with lcd(os.path.dirname(debdist_path)):
                        local('dpkg-buildpackage -rfakeroot -uc -us')

        # Copy .deb packages to dist
        for deb_path in get_files(pkg_join('plugins'), '*.deb',
                                  recursive=True):
            shutil.copy(deb_path, dist_join(os.path.basename(deb_path)))

    # Redhat package
    if 'rpm' in pkg_formats:
        logger.info('Creating .rpm package...')

        with settings(hide('stdout', 'running')):
            # Run setup.py bdist_rpm inside each plugin. It generates deb_dist/<pkgname>/ directory
            for setuppy_path in get_files(os.path.abspath(pkg_join('plugins')),
                                          'setup.py',
                                          recursive=True):
                plugin_dir = os.path.dirname(setuppy_path)
                with lcd(plugin_dir):
                    local('python setup.py bdist_rpm')

            # Copy .rpm packages to dist
            for rpm_path in get_files(pkg_join('plugins'),
                                      '*.rpm',
                                      recursive=True):
                shutil.copy(rpm_path, dist_join(os.path.basename(rpm_path)))

    logger.info('Building completed.')
Example #12
0
    Examples::

        fab dist.test:smoke
        fab dist.test:path/to/case.py
        fab dist.test:smoke,~/firefox.ini
        fab dist.test:smoke,config=path/to/config.ini

    """
    try:
        from nose.core import TestProgram
        from nose.plugins import Plugin
    except ImportError:
        TestProgram = None
        Plugin = object
        return abort(
            'For running tests, Nose testing framework is required. Please install it first: "pip install nose"'
        )

    if not case:
        return abort('Please provide either name or path to test case')

    # Determine the case file: name or path accepted
    webtests_dir = rel_join('tests/webtests')
    casepath = os.path.abspath(case) if case.endswith('.py') else join(
        webtests_dir, 'cases/%s.py' % case)
    configpath = os.path.join(os.curdir, os.path.expanduser(config))

    logger.info('Running functional tests from: %s' % casepath)
    logger.info('Reading tests configuration from: %s' % configpath)

    class TestConfigPlugin(Plugin):