web-dev-qa-db-ja.com

デプロイユーザーとしてファブリック経由でvirtualenvをアクティブ化する

ファブリックスクリプトをローカルで実行し、サーバーにログインし、ユーザーをデプロイに切り替え、プロジェクト.virtualenvをアクティブにします。これにより、dirがプロジェクトに変更され、git pullが発行されます。

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

通常、virtualenvwrapperのworkonコマンドを使用します。このコマンドは、アクティベートファイルとポストアクティベートファイルを取得し、プロジェクトフォルダーに配置します。この場合、ファブリックはシェル内から実行されるため、制御はファブリックに渡されるため、「$ source〜/ .virtualenv/myvenv/bin/activate」にbashのソースビルトインを使用することはできません

誰かがこれをどのように行ったかの例と説明がありますか?

128

今、あなたは私がしていることをすることができます、それは気味が悪いですが、完全にうまく動作します* 、そうでない場合):

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が 'n'でない場合など、command1アプローチを使用すると破裂する場合がありますt適切にエスケープされ、特殊なシェル文字などが含まれています。

95
bitprophet

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

Run()の代わりに呼び出すことができる単純なラッパー関数virtualenv()を使用しています。 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)
17
ehc

virtualenvwrapperは、これをもう少しシンプルにすることができます

  1. @ nh2のアプローチの使用(このアプローチはlocalを使用する場合にも機能しますが、workon$PATHにあるvirtualenvwrapperインストール、つまり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をアクティブにできます。このアプローチは、localbash -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")
    
8
Dave

これは、ローカル展開でvirtualenvを使用する私のアプローチです。

ファブリックの path() コンテキストマネージャーを使用すると、virtualenvのバイナリでpipまたはpythonを実行できます。

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

投稿されたすべての回答に感謝します。これに対してもう1つの選択肢を追加したいと思います。モジュール fabric-virtualenv があり、同じコードとして機能を提供できます。

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

fabric-virtualenvはfabric.context_managers.prefix、これは良い方法かもしれません:)

4
Drake Guan

パッケージを環境にインストールする場合、または環境内のパッケージに従ってコマンドを実行する場合、複雑なファブリックのメソッドを記述したり、新しい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

この方法では、環境をアクティブにする必要はないかもしれませんが、環境の下でコマンドを実行できます。

2
vikas0713

このアプローチは私のために働いた、あなたもこれを適用することができます。

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ディレクトリであると仮定し、必要に応じてこのメソッドを追加します。

1
Manikanta

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.__= func.__name__
  wrapped.__doc__ = func.__doc__
  return wrapped

デコレータを使用するには、デコレータの順序が重要であることに注意してください。

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