通过fabric以部署用户身份激活虚拟环境

130 投票
10 回答
39114 浏览
提问于 2025-04-15 13:08

我想在本地运行我的fabric脚本,这个脚本会登录到我的服务器,切换用户到deploy,激活项目的虚拟环境,这样就能进入项目目录并执行git pull命令。

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

我通常使用virtualenvwrapper中的workon命令,这个命令会加载激活文件,而postactivate文件会让我进入项目文件夹。不过在这种情况下,似乎因为fabric是在shell内部运行的,所以控制权交给了fabric,这样我就不能使用bash的source命令来执行'$source ~/.virtualenv/myvenv/bin/activate'了。

有没有人能给我一个例子,并解释一下他们是怎么做到的?

10 个回答

18

我只是用一个简单的包装函数 virtualenv(),可以用来代替 run()。这个函数不使用 cd 上下文管理器,所以可以使用相对路径。

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

关于bitprophet的预测更新:在Fabric 1.0中,你可以使用prefix()以及你自己创建的上下文管理器。

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

现在,你可以像我一样做,虽然方法有点笨拙,但效果很好*(这里假设你在使用virtualenvwrapper——你应该使用这个——如果没有,你也可以用你提到的那个比较长的'source'命令来替代):

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

从1.0版本开始,Fabric有一个prefix上下文管理器,它使用了这个技巧,所以你可以例如:

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

* 有些情况下,使用command1 && command2的方法可能会出问题,比如当command1失败时(command2就不会执行),或者如果command1没有正确处理,里面包含了特殊的shell字符等等。

撰写回答