Using virtualenvwrapper with Fabric

Virtualenvwrapper is awesome. So is Fabric.

So on a recent project I was using virtualenvwrapper on the server and deploying with Fabric. All was going well until the thought hit me that I might invoke the fabfile from the wrong environment. This can cause some fairly serious problems and having to verify that each time would make the deployment one step longer than it needs to be. I figured that it would be fairly easy to make certain the correct virtualenv was being used with a context manager:

from contextlib import contextmanager

#This is a helper to make sure that we are in the right virtualenv
@contextmanager
def virtualenvwrapper():
    with prefix("source ~/.virtualenvs/mysite/bin/activate"):
        yield

Then just change things like this:

def compile_scss():
    """ Compile the SCSS files into regular CSS and place those in the static directory.
    Requires SCSS processor to be installed."""
    with lcd('scss/'):
        local('pyscss *.scss >' + static_css_dir)

To this:

def compile_scss():
    """ Compile the SCSS files into regular CSS and place those in the static directory.
    Requires SCSS processor to be installed."""
    with virtualenvwrapper():
        with lcd('scss/'):
            local('pyscss *.scss >' + static_css_dir)

It all just seemed too easy, until I attempted to run it:

(develop)$ fab compile_scss
[localhost] local: pyscss *.scss > ../static/basic_theme/css/style.css
/bin/sh: 1: source: not found
Fatal error: local() encountered an error (return code 127) while executing 'pyscss *.scss > ../static/basic_theme/css/style.css'

Aborting.

This had me a bit perplexed at first. The hint at the problem is right there with: /bin/sh: 1: source: not found. Fabric doesn't use /bin/bash by default and source is a bash command, /bin/sh doesn't know that command and hence we get that error. To fix this you need to tell Fabric to use /bin/bash like so:

def compile_scss():
    """ Compile the SCSS files into regular CSS and place those in the static directory.
    Requires SCSS processor to be installed."""
    with virtualenvwrapper():
        with lcd('scss/'):
            local('pyscss *.scss >' + static_css_dir, shell='/bin/bash')

Now this works!

(develop)$ fab compile_scss
[localhost] local: pyscss *.scss > ../static/basic_theme/css/style.css

Done.

blogroll

social