배치 사용자로 패브릭을 통해 virtualenv 활성화


130

패브릭 스크립트를 로컬로 실행하여 서버에 로그인하고 사용자를 배포하여 배포하고 프로젝트 .virtualenv를 활성화하여 dir을 프로젝트로 변경하고 git pull을 발행합니다.

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

나는 일반적으로 virtualenvwrapper의 workon 명령을 사용하여 활성화 파일을 소싱하고 postactivate 파일은 나를 프로젝트 폴더에 넣습니다. 이 경우 패브릭이 쉘 내에서 실행되기 때문에 제어가 패브릭으로 전달되므로 bash의 소스 내장 기능을 '$ source ~ / .virtualenv / myvenv / bin / activate'에 내장 할 수 없습니다.

아무도 그들이 어떻게했는지에 대한 예와 설명이 있습니까?


1
호기심, 왜 사용하지 않는 workonA와 prefix?
Daniel C. Sobral

답변:


96

지금 당장 내가 할 수있는 일을 할 수는 있지만 kludgy이지만 완벽하게 잘 작동합니다 * (이 사용법은 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등 접근 방식이 폭발 할 수있는 경우 가 있습니다.command1command2command1


7
그러나 workon에 의해 알려져 있지 않다 sh. 패브릭에 대신 bash를 사용하도록 어떻게 말할 수 있습니까?
Pierre de LESPINAY

18
IMHO 당신은 그냥 사용해야 source venv/bin/activate합니다. 더 쉽고 기본적으로 작동합니다. workon추가 종속성이며 설치되어 있어도 .bashrc패브릭 배치에는 너무 복잡합니다.
Dave Halter

@PierredeLESPINAY는 문제 해결을 위해 stackoverflow.com/questions/11272372/… 를 참조하십시오 .
dukebody

137

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

@simon은 .bashrc를 호출하고 bash의 -c 인수 내에 접두사와 명령을 모두 래핑하는 고유 한 접두사 메서드를 작성합니다. 참조 아래
데이브

5
그러나 source에 의해 알려져 있지 않다 sh. 패브릭에 대신 bash를 사용하도록 어떻게 말할 수 있습니까?
Pierre de LESPINAY

2
@PierredeLESPINAY .대신 사용할 수 있습니다source
katy lavallee

왜 사용 하는가 cd()완전히의 경로를 지정할 때 activateprefix()?
Nick T

@NickT prefix()CD가없는 것 같습니다 . 동일한 문서참조하십시오 . 우리는 다른 명령을 실행할 cdyield( pip freeze내 예제에서) 해당 명령이 해당 디렉토리와 관련 이 있기를 원합니다 .
nh2

18

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)

9

virtualenvwrapper 이것을 조금 더 간단하게 만들 수 있습니다

  1. (사용하는 경우이 방법은 또한 작동 NH2의 접근 @ 사용 local하지만 설치 virtualenvwrapper에, 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")

nh2의 답변을 요약 해 주셔서 감사합니다. virtualenv contextmanager 선언은 Python 2.6 이상에서 5 줄로 이루어질 수 있지만 'workon'별칭이 항상 올바르게 가져 오기를 보장하지는 않으며`source ... / activate '를 사용하는 것이 훨씬 안정적입니다 명령
Alex Volkov

8

이것은 사용에 대한 나의 접근 방식입니다 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')

나는 이것을 매우 좋아한다-나는이 접근법에 명백한 단점을 보지 못하고 매우 깨끗하다. 감사합니다 :)
simon

여전히 가장
훌륭하고

4

게시 된 모든 답변 덕분에 이에 대한 대안을 하나 더 추가하고 싶습니다. 동일한 코드로 기능을 제공 할 수있는 fabric-virtualenv 모듈 이 있습니다.

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

패브릭 VIRTUALENV는 사용하게 fabric.context_managers.prefix좋은 방법이 될 수도 있습니다 :


흥미롭지 만 SCM / 문제 추적기에 링크가 없다는 사실이 마음에 들지 않습니다. 소스 코드 및 이슈 트래커에 대한 링크없이 PYPI에만 게시 된 패키지는 많은 신뢰를 불러 일으키지 않지만 쉽게 고칠 수 있습니다.
소린

2

환경에 패키지를 설치하거나 환경에있는 패키지에 따라 명령을 실행하려면 복잡한 패브릭 방법을 작성하거나 새 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

이 방법으로 환경을 활성화 할 필요는 없지만 환경에서 명령을 실행할 수 있습니다.


1

다음은 실행 / 스도 호출에 가상 환경을 사용하는 데코레이터 코드입니다.

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

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가상 env 디렉토리 라고 가정 하고 적절한 경우이 방법을 추가하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.