作为部署用户通过 Fabric 激活 virtualenv

发布于 2024-07-29 05:43:53 字数 430 浏览 7 评论 0原文

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

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

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

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

I want to run my fabric script locally, which will in turn, log into my server, switch user to deploy, activate the projects .virtualenv, which will change dir to the project and issue a git pull.

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

I typically use the workon command from virtualenvwrapper which sources the activate file and the postactivate file will put me in the project folder. In this case, it seems that because fabric runs from within shell, control is give over to fabric, so I can't use bash's source built-in to '$source ~/.virtualenv/myvenv/bin/activate'

Anybody have an example and explanation of how they have done this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

桃扇骨 2024-08-05 05:43:54

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

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')
偏爱你一生 2024-08-05 05:43:54

现在,你可以做我所做的,这是笨拙但工作得很好*(这种用法假设你正在使用 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 字符等等。

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.

清醇 2024-08-05 05:43:54

我只是使用一个简单的包装函数 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)

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)
笔芯 2024-08-05 05:43:54

virtualenvwrapper 可以使这变得更简单

  1. 使用 @nh2 的方法(此方法在使用 local 时也有效,但仅适用于 workon 的 virtualenvwrapper 安装> 位于 $PATH 中,换句话说 -- Windows)

    从 contextlib 导入 contextmanager 
      从fabric.api导入前缀 
    
      @contextmanager 
      def virtualenv(): 
          带前缀(“workon env1”): 
              屈服 
    
      def 部署(): 
          使用 virtualenv(): 
              运行(“点冻结>需求.txt”) 
      
  2. 或者部署您的 fab 文件并在本地运行它。 此设置允许您激活本地或远程命令的 virtualenv。 这种方法非常强大,因为它解决了 local 无法使用 bash -l 运行 .bashrc 的问题:

    <前><代码>@contextmanager
    def local_prefix(shell, 前缀):
    def local_call(命令):
    return local("%(sh)s \"%(pre)s && %(cmd)s\"" %
    {“sh”:shell,“pre”:前缀,“cmd”:命令})
    产生本地前缀

    def write_requirements(shell="/bin/bash -lic", env="env1"):
    使用 local_prefix(shell, "workon %s" % env) 作为本地:
    本地(“点冻结>需求.txt”)

    write_requirements() # 本地
    运行(“fab write_requirements”)

virtualenvwrapper can make this a little simpler

  1. 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")
    
  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")
    
心病无药医 2024-08-05 05:43:54

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

使用 Fabric 的 path() 上下文管理器可以使用 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')

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')
街角卖回忆 2024-08-05 05:43:54

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

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

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

Thanks to all answers posted and I would like to add one more alternative for this. There is an module, fabric-virtualenv, which can provide the function as the same code:

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

fabric-virtualenv makes use of fabric.context_managers.prefix, which might be a good way :)

人生戏 2024-08-05 05:43:54

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

/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

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

If you want to install the packages to environment or want to run commands according to the packages you have in environment, I have found this hack to solve my problem, instead of writing complex methods of fabric or installing new OS packages:

/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

This way you might not need to activate the environment, but you can execute commands under the environment.

謸气贵蔟 2024-08-05 05:43:54

以下是装饰器的代码,它将导致对任何 run/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")

Here is code for a decorator that will result in the use of Virtual Environment for any run/sudo calls:

# 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

and then to use the decorator, note the order of the decorators is important:

@task
@with_venv
def which_python():
  "Gets which python is being used"
  run("which python")
夢归不見 2024-08-05 05:43:54

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

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

This approach worked for me, you can apply this too.

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

Assuming venv is your virtual env directory and add this method wherever appropriate.

生生漫 2024-08-05 05:43:54

我将 pyenv 与插件 pyenv-virtualenvwrapper 一起使用。 我在 workon 上没有成功,而是使用这个(fabric 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

现在在开发计算机上,如果您在代理中有私钥(在 < code>ssh-add 或者如果您在进行 git Push 后在 ~/.ssh/config 中有 AddKeysToAgent yes),那么git pull 不应询问密钥的密码。

I use pyenv with plugin pyenv-virtualenvwrapper. I had no success with workon, instead I use this (fabric 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 ....')

For git pull agent forwarding is good, ie. ssh -A .. or better in ~/.ssh/config something like this:

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

And now on the development machine if you have a private key in the agent (after ssh-add or if you have AddKeysToAgent yes in ~/.ssh/config after you made git push) then git pull should not ask for the passphrase of the key.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文