As an update to bitprophet's forecast: With Fabric 1.0 you can make use of prefix() and your own context managers.
from __future__ import with_statement
from fabric.api import *
from contextlib import contextmanager as _contextmanager
env.hosts = ['servername']
env.user = 'deploy'
env.keyfile = ['$HOME/.ssh/deploy_rsa']
env.directory = '/path/to/virtualenvs/project'
env.activate = 'source /path/to/virtualenvs/project/bin/activate'
@_contextmanager
def virtualenv():
with cd(env.directory):
with prefix(env.activate):
yield
def deploy():
with virtualenv():
run('pip freeze')
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')
Since version 1.0, Fabric has a prefix
context manager which uses this technique so you can for example:
def task():
with prefix('workon myvenv'):
run('git pull')
run('do other stuff, etc')
* 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.
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)
virtualenvwrapper
can make this a little simpler
Using @nh2's approach (this approach also works when using local
, but only for virtualenvwrapper installations where workon
is in $PATH
, in other words -- Windows)
from contextlib import contextmanager
from fabric.api import prefix
@contextmanager
def virtualenv():
with prefix("workon env1"):
yield
def deploy():
with virtualenv():
run("pip freeze > requirements.txt")
Or deploy your fab file and run this locally. This setup lets you activate the virtualenv for local or remote commands. This approach is powerful because it works around local
's inability to run .bashrc using bash -l
:
@contextmanager
def local_prefix(shell, prefix):
def local_call(command):
return local("%(sh)s \"%(pre)s && %(cmd)s\"" %
{"sh": shell, "pre": prefix, "cmd": command})
yield local_prefix
def write_requirements(shell="/bin/bash -lic", env="env1"):
with local_prefix(shell, "workon %s" % env) as local:
local("pip freeze > requirements.txt")
write_requirements() # locally
run("fab write_requirements")
This is my approach on using virtualenv
with local deployments.
Using fabric's path() context manager you can run pip
or python
with binaries from virtualenv.
from fabric.api import lcd, local, path
project_dir = '/www/my_project/sms/'
env_bin_dir = project_dir + '../env/bin/'
def deploy():
with lcd(project_dir):
local('git pull origin')
local('git checkout -f')
with path(env_bin_dir, behavior='prepend'):
local('pip freeze')
local('pip install -r requirements/staging.txt')
local('./manage.py migrate') # Django related
# Note: previous line is the same as:
local('python manage.py migrate')
# Using next line, you can make sure that python
# from virtualenv directory is used:
local('which python')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With