作为部署用户通过光纤激活一个 Virtual alenv

我想在本地运行我的光纤脚本,这将反过来,登录到我的服务器,切换用户部署,激活项目。将 dir 更改为项目并发出 git pull 命令。

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

我通常使用来自 viralenvwrapper 的 workon 命令,该命令源代码激活文件和后激活文件将把我放在项目文件夹中。在这种情况下,似乎是因为结构是在 shell 中运行的,所以控制权交给了结构,所以我不能使用 bash 的内置源代码到’$source ~/。Virtualenv/myvenv/bin/activate’

有人能举个例子解释一下他们是怎么做到的吗?

38615 次浏览

现在,你可以做我所做的事情,虽然很复杂,但是效果非常好 * (这个用法假设你正在使用 viralenvwrapper ——你应该这样做——但是你可以很容易地替换你提到的那个更长的“ 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 字符,等等。

我只是使用了一个简单的包装函式 viralenv () ,它可以被调用而不是 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)

作为对比特先知预测的更新: 使用 Fabric 1.0,您可以使用 前缀()和您自己的上下文管理器。

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

virtualenvwrapper可以使这个过程简单一点

  1. 使用@nh2的方法(这种方法也适用于使用 local的情况,但只适用于 workon位于 $PATH中的 viralenvwrapper 安装,换句话说—— 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. 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")
    

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

使用光纤的 路径()上下文管理器,您可以使用来自 viralenv 的二进制文件运行 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')

下面是修饰器的代码,它将导致对任何运行/sudo 调用使用 Virtual Environment:

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

感谢所有的回答张贴,我想添加一个替代这一点。有一个模块 织物虚拟连接,它可以提供相同的代码:

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

Fabric-viralenv 利用了 fabric.context_managers.prefix,这可能是一个很好的方法:)

如果你想把软件包安装到环境中,或者根据你在环境中的软件包运行命令,我发现这个黑客技巧可以解决我的问题,而不是编写复杂的结构方法或者安装新的操作系统软件包:

/path/to/virtualenv/bin/python manage.py migrate/runserver/makemigrations  # for running commands under virtualenv


local("/home/user/env/bin/python manage.py migrate")    # fabric command




/path/to/virtualenv/bin/pip install -r requirements.txt   # installing/upgrading virtualenv


local("/home/user/env/bin/pip install -r requirements.txt")  #  fabric command

这样,您可能不需要激活环境,但是您可以在环境下执行命令。

这个方法对我很有效,你也可以应用这个。

from fabric.api import run
# ... other code...
def install_pip_requirements():
run("/bin/bash -l -c 'source venv/bin/activate' "
"&& pip install -r requirements.txt "
"&& /bin/bash -l -c 'deactivate'")

假设 venv是您的虚拟 env 目录,并在适当的地方添加此方法。

我使用了 pyenv 和插件 pyenv-viralenvwrapper,但是在 workon 上没有成功,我使用了这个(面料2.5) :

with c.prefix('source /home/mirek/.virtualenvs/%s/bin/activate' % PROJECT):
with c.prefix('cd /home/mirek/%s/%s' % (PROJECT, PROJECT)):
c.run('python manage.py ....')

对于 git pull代理转发是好的,即 ssh -A ..或更好的在 ~/.ssh/config类似的东西:

Host forpsi
HostName xx.xx.xx.xx
IdentityFile /home/mirek/.ssh/id_ed25519_xxx
ForwardAgent yes

现在在开发机器上,如果代理中有一个私钥(在 ssh-add之后,或者在 git push之后,在 ~/.ssh/config中有 AddKeysToAgent yes) ,那么 git pull不应该询问密钥的密码短语。