views:

1727

answers:

2

I want to run my fabric script locally, which will in turn, log into my server, switch user to deploy, activate the projects .virtualenv, which will change dir to the project and issue a git pull.

def git_pull():
    sudo('su deploy')
    # here i need to switch to the virtualenv
    run('git pull')

I typically use the workon command from virtualenvwrapper which sources the activate file and the postactivate file will put me in the project folder. In this case, it seems that because fabric runs from within shell, control is give over to fabric, so I can't use bash's source built-in to '$source ~/.virtualenv/myvenv/bin/activate'

Anybody have an example and explanation of how they have done this?

# # # response # # #

Thanks bitprophet, that led down the right track. Using fabric 1.0 we ended up going with the following fabfile recipe which includes a call to pip requirements file:

def production():
    env.hosts = ['servername']
    env.directory = '/path/to/virtualenvs/project'
    env.activate = 'source /home/deploy/.virtualenvs/project/bin/activate'
    env.deploy_user = 'deploy'

def virtualenv(command):
    with cd(env.directory):
        sudo(env.activate + '&&' + command, user=env.deploy_user)

def git_pull():
    'Updates the repository.'
    with cd(env.directory):    
        sudo('git pull', user=env.deploy_user)

def pip_install_req():
    virtualenv('pip install -U -r ../../../requirements/external_apps.txt') 

def reload():
    sudo('/etc/init.d/apache2 reload')

def deploy_pip():
    local('git push')
    git_pull()
    pip_install_req()
    reload()
+14  A: 

Right now, you can do what I do, which is kludgy but works perfectly well* (this usage assumes you're using virtualenvwrapper -- which you should be -- but you can easily substitute in the rather longer 'source' call you mentioned, if not):

def task():
    workon = 'workon myvenv && '
    run(workon + 'git pull')
    run(workon + 'do other stuff, etc')

Fabric 0.9 (currently in beta) has a "cd" context manager which uses this technique to fake the state change of cd-ing to directories; Fabric 1.0 will have a generic version of this (haven't settled on the name yet, below is an example) that you can use with anything, so you'd be able to e.g.:

def task():
    with prefix('workon myvenv'):
        run('git pull')
        run('do other stuff, etc')

If you live on the edge and use Fabric's master branch, the prefix contextmanager is currently implemented, though its name might change prior to release.


* There are bound to be cases where using the command1 && command2 approach may blow up on you, such as when command1 fails (command2 will never run) or if command1 isn't properly escaped and contains special shell characters, and so forth.

We'll try to handle/document as much of this as possible when the generic version is implemented; that this hasn't been done yet is one reason why it's not going to be in 0.9 :)

bitprophet
+1  A: 

I'm just using a simple wrapper function virtualenv() that can be called instead of run(). It doesn't use the cd context manager, so relative paths can be used.

def virtualenv(command):
    """
    Run a command in the virtualenv. This prefixes the command with the source
    command.
    Usage:
        virtualenv('pip install django')
    """
    source = 'source %(project_directory)s/bin/activate && ' % env
    run(source + command)
ehc