"""
Deployment Fabric file

A fabric deployment script for Helios that assumes the following:
- locally, development is /web/helios-server
- remotely, a number of production setups 
- remotely, a number of staging setups
- all of these directories are git checkouts that have a proper origin pointer

Other assumptions that should probably change:
- both staging and production run under the same apache instance

Deployment is git and tag based, so:

fab staging_deploy:tag=v3.0.4,hosts="vote.heliosvoting.org"
fab production_deploy:tag=v3.0.5,hosts="vote.heliosvoting.org"

also to get the latest

fab production_deploy:tag=latest,hosts="vote.heliosvoting.org"

IMPORTANT: settings file may need to be tweaked manually
"""

from fabric.api import local, settings, abort, cd, run, sudo
from fabric.contrib.console import confirm

STAGING_SETUP = {
    'root' : "/web/staging/helios-server",
    'celery' : "/etc/init.d/staging-celeryd",
    'dbname' : "helios-staging"
    }

PRODUCTION_SETUPS = [
    {
        'root' : "/web/production/helios-server",
        'celery' : "/etc/init.d/celeryd",
        'dbname' : "helios"
        },
    {
        'root' : "/web/princeton/helios-server",
        'celery' : "/etc/init.d/princeton-celeryd",
        'dbname' : "princeton-helios"
        }
]
        
def run_tests():
    result = local("python manage.py test", capture=False)
    if result.failed:
        abort("tests failed, will not deploy.")

def check_tag(tag, path):
    result = local('git tag')
    if tag not in result.split("\n"):
        abort("no local tag %s" % tag)

    with cd(path):
        run('git pull origin master')
        run('git fetch --tags')
        result = run('git tag')
        if tag not in result.split("\n"):
            abort("no remote tag %s" % tag)

def get_latest(path):
    with cd(path):
        result = run('git pull')
        if result.failed:
            abort("on remote: could not get latest")

        result = run('git submodule init')
        if result.failed:
            abort("on remote: could not init submodules")

        result = run('git submodule update')
        if result.failed:
            abort("on remote: could not update submodules")
    
def checkout_tag(tag, path):
    with cd(path):
        result = run('git checkout %s' % tag)
        if result.failed:
            abort("on remote: could not check out tag %s" % tag)

        result = run('git submodule init')
        if result.failed:
            abort("on remote: could not init submodules")

        result = run('git submodule update')
        if result.failed:
            abort("on remote: could not update submodules")

def migrate_db(path):
    with cd(path):
        result = run('python manage.py migrate')
        if result.failed:
            abort("could not migrate")

def restart_apache():
    result = sudo('/etc/init.d/apache2 restart')
    if result.failed:
        abort("could not restart apache")

def restart_celeryd(path):
    result = sudo('%s restart' % path)
    if result.failed:
        abort("could not restart celeryd - %s " % path)

def deploy(tag, path):
    if tag == 'latest':
        get_latest(path=path)
    else:
        check_tag(tag, path=path)
        checkout_tag(tag, path=path)
    migrate_db(path=path)
    restart_apache()
    
def staging_deploy(tag):
    deploy(tag, path=STAGING_SETUP['root'])
    restart_celeryd(path = STAGING_SETUP['celery'])

def production_deploy(tag):
    production_roots = ",".join([p['root'] for p in PRODUCTION_SETUPS])
    if not confirm("Ready to deploy %s to %s?" % (tag, production_roots)):
        return
    run_tests()
    for prod_setup in PRODUCTION_SETUPS:
        deploy(tag, path = prod_setup['root'])
        restart_celeryd(path = prod_setup['celery'])