作为部署用户通过结构激活一个virtualenv

我想在本地运行我的结构脚本,这将反过来,login到我的服务器,切换用户部署,激活项目.virtualenv,这将改变目录到项目和发出git拉。

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

我通常使用来自virtualenvwrapper的workon命令,它来源激活文件和postactivate文件将把我放在项目文件夹。 在这种情况下,由于织物从shell运行,控制权交给织物,所以我不能使用内置到$ source〜/ .virtualenv / myvenv / bin / activate中的bash源代码。

任何人都有一个例子和解释他们如何做到这一点?

现在,你可以做我所做的事情,但是非常好用(这个用法假定你使用的是virtualenvwrapper,你应该这样做),但是你可以很容易地用你提到的更长的“源代码” , 如果不):

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

从版本1.0开始,Fabric有一个使用这种技术的prefix上下文pipe理器 ,所以你可以例如:

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

*必然会出现使用command1 && command2方法的情况,比如command1失败( command2永远不会运行),或者command1没有正确转义并且包含特殊的shell字符,等等。

作为bitprophet预测的更新:使用Fabric 1.0,您可以使用prefix()和您自己的上下文pipe理器。

 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') 

我只是使用一个简单的包装函数virtualenv(),可以调用,而不是run()。 它不使用cd上下文pipe理器,所以可以使用相对path。

 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可以使这个更简单一点

  1. 使用@ nh2的方法(这种方法也适用于使用local ,但只适用于virtualenvwrapper安装,其中workon$PATH ,换句话说 – 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") 
  2. 或者部署你的fab文件并在本地运行。 通过此设置,可以激活本地或远程命令的virtualenv。 这种方法是强大的,因为它围绕local无法使用bash -l运行.bashrc:

     @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") 

这是我在本地部署中使用virtualenv方法。

使用fabric的path()上下文pipe理器,你可以用virtualenv的二进制文件运行pippython

 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') 

感谢所有发布的答案,我想为此添加一个替代scheme。 有一个模块, fabric-virtualenv ,它可以提供相同的代码function:

 >>> from fabvenv import virtualenv >>> with virtualenv('/home/me/venv/'): ... run('python foo') 

fabric-virtualenv使用fabric.context_managers.prefix ,这可能是一个好方法:)

这里是一个装饰器的代码,将导致使用虚拟环境进行任何运行/ sudo调用:

 # This is the bash code to update the $PATH as activate does UPDATE_PYTHON_PATH = r'PATH="{}:$PATH"'.format(VIRTUAL_ENV_BIN_DIR) def with_venv(func, *args, **kwargs): "Use Virtual Environment for the command" def wrapped(*args, **kwargs): with prefix(UPDATE_PYTHON_PATH): return func(*args, **kwargs) wrapped.__name__ = func.__name__ wrapped.__doc__ = func.__doc__ return wrapped 

然后使用装饰器,注意装饰器的顺序是重要的:

 @task @with_venv def which_python(): "Gets which python is being used" run("which python")