Kích hoạt virtualenv qua vải khi người dùng triển khai


130

Tôi muốn chạy tập lệnh cấu trúc cục bộ của mình, nó sẽ lần lượt đăng nhập vào máy chủ của tôi, chuyển người dùng để triển khai, kích hoạt các dự án .virtualenv, sẽ thay đổi dir thành dự án và đưa ra lệnh git.

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

Tôi thường sử dụng lệnh workon từ virtualenvwrapper để lấy tệp kích hoạt và tệp postactivate sẽ đưa tôi vào thư mục dự án. Trong trường hợp này, có vẻ như do vải chạy từ bên trong vỏ, nên quyền kiểm soát được trao cho vải, vì vậy tôi không thể sử dụng nguồn bash được tích hợp sẵn để '$ source ~ / .virtualenv / myvenv / bin / activ'

Bất cứ ai cũng có một ví dụ và giải thích về cách họ đã làm điều này?


1
Vì tò mò, tại sao bạn không sử dụng workonnhư một prefix?
Daniel C. Sobral

Câu trả lời:


96

Ngay bây giờ, bạn có thể làm những gì tôi làm, không có gì nhưng hoạt động hoàn toàn tốt * (cách sử dụng này giả sử bạn đang sử dụng virtualenvwrapper - mà bạn nên - nhưng bạn có thể dễ dàng thay thế trong cuộc gọi 'nguồn' dài hơn mà bạn đã đề cập , nếu không):

def task():
    workon = 'workon myvenv && '
    run(workon + 'git pull')
    run(workon + 'do other stuff, etc')

Kể từ phiên bản 1.0, Fabric có trình prefixquản lý bối cảnh sử dụng kỹ thuật này để bạn có thể lấy ví dụ:

def task():
    with prefix('workon myvenv'):
        run('git pull')
        run('do other stuff, etc')

* Chắc chắn sẽ có trường hợp sử dụng command1 && command2phương pháp tiếp cận có thể làm bạn thất vọng, chẳng hạn như khi command1thất bại ( command2sẽ không bao giờ chạy) hoặc nếu command1không thoát đúng cách và chứa các ký tự vỏ đặc biệt, v.v.


7
Nhưng workonlà không biết bởi sh. Làm thế nào chúng ta có thể nói với vải để sử dụng bash thay thế?
Pierre de LESPINAY

18
IMHO bạn chỉ nên sử dụng source venv/bin/activate. Nó dễ dàng hơn và làm việc ra khỏi hộp. workonlà một phụ thuộc bổ sung và ngay cả khi nó được cài đặt, bạn phải thêm nó vào .bashrc- quá phức tạp đối với việc triển khai vải.
Dave Halter

@PierredeLESPINAY xem stackoverflow.com/questions/11272372/ cho một giải pháp cho vấn đề của bạn.
tước

137

Là một bản cập nhật cho dự báo của bitprophet: Với Fabric 1.0, bạn có thể sử dụng tiền tố () và trình quản lý bối cảnh của riêng bạn.

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, bằng cách viết phương thức tiền tố của riêng bạn gọi .bashrc và bao bọc cả tiền tố và lệnh trong đối số -c cho bash. Xem bên dưới
Dave

5
Nhưng sourcelà không biết bởi sh. Làm thế nào chúng ta có thể nói với vải để sử dụng bash thay thế?
Pierre de LESPINAY

2
@PierredeLESPINAY bạn có thể sử dụng .thay vìsource
katy lavallee

Tại sao bạn sử dụng cd()khi bạn đang hoàn toàn xác định đường dẫn đến activatetrong prefix()?
Nick T

@NickT Bởi vì prefix()dường như không cd ở đó - hãy xem những tài liệu này làm tương tự. Chúng tôi muốn cdở đó để khi chúng tôi yieldthực hiện các lệnh khác ( pip freezetrong ví dụ của tôi), các lệnh đó có thể liên quan đến thư mục đó.
nh2

18

Tôi chỉ đang sử dụng một hàm bao bọc đơn giản virtualenv () có thể được gọi thay vì run (). Nó không sử dụng trình quản lý bối cảnh cd, vì vậy các đường dẫn tương đối có thể được sử dụng.

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 có thể làm điều này đơn giản hơn một chút

  1. Sử dụng cách tiếp cận @ NH2 của (phương pháp này cũng làm việc khi sử dụng local, nhưng chỉ cho virtualenvwrapper cài đặt ở đâu workonlà trong $PATH, nói cách khác - 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. Hoặc triển khai tệp fab của bạn và chạy tệp này cục bộ. Thiết lập này cho phép bạn kích hoạt virtualenv cho các lệnh cục bộ hoặc từ xa. Cách tiếp cận này rất hữu ích vì nó hoạt động xung quanh việc localkhông thể chạy .bashrc bằng cách sử dụng 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")

Cảm ơn bạn đã tóm tắt câu trả lời của nh2, khai báo bối cảnh virtualenv có thể được thực hiện trong 5 dòng trên Python 2.6+, tuy nhiên không bao giờ đảm bảo rằng bí danh 'workon' luôn được nhập chính xác và đáng tin cậy hơn khi sử dụng 'nguồn ... / kích hoạt' chỉ huy
Alex Volkov

8

Đây là cách tiếp cận của tôi về việc sử dụng virtualenvvới các triển khai địa phương.

Sử dụng trình quản lý bối cảnh path () của vải, bạn có thể chạy piphoặc pythonvới các tệp nhị phân từ 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')

Tôi rất thích điều này - tôi không thấy bất kỳ nhược điểm rõ ràng nào đối với phương pháp này và nó rất sạch sẽ. Cảm ơn :)
simon

vẫn là câu trả lời hay nhất và rõ ràng nhất ở đây
n1_

4

Cảm ơn tất cả các câu trả lời được đăng và tôi muốn thêm một thay thế cho điều này. Có một mô-đun, Fabric-virtualenv , có thể cung cấp chức năng như cùng một mã:

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

vải-virtualenv sử dụng fabric.context_managers.prefix, đó có thể là một cách tốt :)


Thú vị nhưng tôi không thích thực tế là không có liên kết đến SCM / bộ theo dõi vấn đề. Một gói chỉ được xuất bản trên PYPI mà không có liên kết đến mã nguồn và trình theo dõi vấn đề không truyền cảm hứng cho nhiều sự tin tưởng .... nhưng rất dễ sửa.
sorin

2

Nếu bạn muốn cài đặt các gói vào môi trường hoặc muốn chạy các lệnh theo các gói bạn có trong môi trường, tôi đã tìm thấy bản hack này để giải quyết vấn đề của tôi, thay vì viết các phương thức phức tạp của vải hoặc cài đặt các gói hệ điều hành mới:

/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

Bằng cách này, bạn có thể không cần kích hoạt môi trường, nhưng bạn có thể thực thi các lệnh trong môi trường.


1

Đây là mã cho một trình trang trí sẽ dẫn đến việc sử dụng Môi trường ảo cho bất kỳ cuộc gọi chạy / sudo nào:

# 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

và sau đó để sử dụng trang trí, lưu ý thứ tự của các trang trí là quan trọng:

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

1

Cách tiếp cận này hiệu quả với tôi, bạn cũng có thể áp dụng điều này.

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

Giả sử venvlà thư mục env ảo của bạn và thêm phương thức này bất cứ khi nào thích hợp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.