130

我想在本地运行我的结构脚本,然后登录到我的服务器,切换用户进行部署,激活项目 .virtualenv,这会将目录更改为项目并发出 git pull。

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

我通常使用来自 virtualenvwrapper 的 workon 命令,该命令获取激活文件,而后激活文件会将我放入项目文件夹中。在这种情况下,似乎因为结构从外壳内运行,控制权交给了结构,所以我不能使用 bash 的源内置到 '$source ~/.virtualenv/myvenv/bin/activate'

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

4

10 回答 10

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')
于 2011-03-19T04:06:46.580 回答
96

现在,你可以做我做的事,这很笨拙,但效果很好*(这种用法假设你正在使用 virtualenvwrapper——你应该使用它——但你可以很容易地替换你提到的更长的“源”调用, 如果不):

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 字符等等。

于 2009-07-24T23:32:09.870 回答
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)
于 2010-08-04T07:48:49.420 回答
9

virtualenvwrapper可以让这更简单一点

  1. 使用@nh2 的方法(这种方法在使用时也有效,但仅适用于位于 inlocal的 virtualenvwrapper 安装,换句话说——Windows)workon$PATH

    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无法运行 .bashrc 的问题,使用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")
    
于 2013-08-23T07:45:03.533 回答
8

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

使用fabric 的path()上下文管理器,您可以运行pippython使用来自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')
于 2013-09-10T11:51:45.460 回答
4

感谢发布的所有答案,我想为此添加另一种选择。有一个模块,fabric-virtualenv,它可以提供相同代码的功能:

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

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

于 2014-09-07T07:02:36.403 回答
2

如果您想将包安装到环境中或想根据环境中的包运行命令,我发现这个 hack 可以解决我的问题,而不是编写复杂的结构方法或安装新的 OS 包:

/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

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

于 2018-04-17T06:35:46.373 回答
1

这是一个装饰器的代码,它将导致对任何运行/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")
于 2014-06-27T22:38:03.310 回答
1

这种方法对我有用,你也可以应用它。

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是您的虚拟环境目录并在适当的地方添加此方法。

于 2018-10-23T09:26:07.833 回答
0

我将 pyenv 与插件 pyenv-virtualenvwrapper 一起使用。我的工作没有成功,而是使用这个(面料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或如果您AddKeysToAgent yes~/.ssh/config之后拥有git push),那么git pull不应该询问密钥的密码。

于 2021-01-06T16:17:52.423 回答