import os

from fabric.api import cd, env, run


def alpheus():
    """Select the ohoh server for future commands."""
    env.hosts = ['represent-alpheus.opennorth.ca']
    env.user = 'represent'
    _env_init()


def tempeh():
    """Select the tofu server for future commands."""
    env.hosts = ['represent-tempeh.opennorth.ca']
    env.user = 'represent'
    _env_init()


def _env_init():
    env.home_dir = '/home/' + env.user
    env.python = os.path.join(env.home_dir, 'represent-env', 'bin', 'python')
    env.base_dir = os.path.join(env.home_dir)
    env.django_dir = os.path.join(env.base_dir, 'app')
    env.pip = env.python.replace('bin/python', 'bin/pip')
    env.data_dir = os.path.join(env.django_dir, 'data')


def deploy(ref='master'):
    """Perform all the steps in a standard deployment"""
    pull(ref)
    update_requirements()
    if env.host != 'represent-tempeh.opennorth.ca':
        migrate()
    update_statics()
    restart()


def pull(ref='master'):
    """Update the git repository to the given branch or tag"""
    with cd(env.django_dir):
        run('git fetch')
        run('git fetch --tags')
        run('git checkout %s' % ref)

        is_tag = (ref == run('git describe --all %s' % ref).strip())
        if not is_tag:
            run('git pull origin %s' % ref)


def update_requirements():
    """Update dependencies."""
    with cd(env.django_dir):
        run(env.pip + ' install -r requirements.txt')


def migrate():
    """Update database schema."""
    with cd(env.django_dir):
        run(env.python + ' manage.py migrate')


def update_statics():
    """Update static files."""
    with cd(env.django_dir):
        run(env.python + ' manage.py collectstatic --noinput')


def restart():
    """Restart gunicorn."""
    with cd(env.base_dir):
        run('kill -HUP `cat gunicorn.pid`')


def update_boundaries(args=''):
    """Pull data repositories and load shapefiles."""
    _recursive_pull(env.data_dir)
    with cd(env.django_dir):
        run(env.python + ' manage.py loadshapefiles ' + args)


def update_representatives():
    """Update all representatives."""
    with cd(env.django_dir):
        run(env.python + ' manage.py updaterepresentatives')


def update_concordances(args=''):
    """Pull data repositories and load postcode concordances."""
    _recursive_pull(env.data_dir)
    with cd(env.django_dir):
        run(env.python + ' manage.py loadpostcodeconcordance ' + args)


def update_postcodes(args=''):
    """Pull data repositories and load postcodes."""
    _recursive_pull(env.data_dir)
    with cd(env.django_dir):
        run(env.python + ' manage.py loadpostcodes ' + args)


def _recursive_pull(base_dir):
    """Find and pull all git repositories in a directory tree."""
    with cd(base_dir):
        dirs = [
            d.strip()[:-1] for d in
            run('ls -aFL1').split('\n')
            if d.strip().endswith('/') and d.strip() not in ('./', '../')
        ]
        if '.git' in dirs:
            # This is a git repo, update it
            run('git pull')
        else:
            # Continue exploring
            for dir in dirs:
                _recursive_pull(os.path.join(base_dir, dir))

@@ -2,16 +2,44 @@
 mport os
+%0Afrom functools import wraps
 %0A%0Afrom f
@@ -67,18 +67,29 @@
 env, run
-%0A%0A
+, task%0A%0A@task
 %0Adef alp
@@ -220,32 +220,61 @@
 r = 'represent'%0A
+    env.read_only_db = False%0A
     _env_init()%0A
@@ -270,24 +270,29 @@
 env_init()%0A%0A
+@task
 %0Adef tempeh(
@@ -421,24 +421,52 @@
 'represent'%0A
+    env.read_only_db = True%0A
     _env_ini
@@ -818,24 +818,30 @@
 , 'data')%0A%0A%0A
+@task%0A
 def deploy(r
@@ -962,51 +962,28 @@
  if 
-env.host != 'represent-tempeh.opennorth.ca'
+not env.read_only_db
 :%0A  
@@ -1030,24 +1030,345 @@
  restart()%0A%0A
+def _require_db(target):%0A    %22%22%22Decorator to enforce env.read_only_db%22%22%22%0A    @wraps(target)%0A    def inner(*args, **kwargs):%0A        if env.read_only_db:%0A            raise Exception(%22This task cannot be performed on an environment with a read-only database.%22)%0A        return target(*args, **kwargs)%0A    return inner%0A%0A@task
 %0Adef pull(re
@@ -1701,24 +1701,30 @@
 s' %25 ref)%0A%0A%0A
+@task%0A
 def update_r
@@ -1850,24 +1850,43 @@
 nts.txt')%0A%0A%0A
+@task%0A@_require_db%0A
 def migrate(
@@ -1996,24 +1996,30 @@
 migrate')%0A%0A%0A
+@task%0A
 def update_s
@@ -2149,24 +2149,30 @@
 noinput')%0A%0A%0A
+@task%0A
 def restart(
@@ -2271,24 +2271,43 @@
 rn.pid%60')%0A%0A%0A
+@task%0A@_require_db%0A
 def update_b
@@ -2499,32 +2499,51 @@
 les ' + args)%0A%0A%0A
+@task%0A@_require_db%0A
 def update_repre
@@ -2682,24 +2682,43 @@
 tatives')%0A%0A%0A
+@task%0A@_require_db%0A
 def update_c
@@ -2936,24 +2936,43 @@
 ' + args)%0A%0A%0A
+@task%0A@_require_db%0A
 def update_p

Update fabfile to avoid illegal DB tasks on failover server