เปิดใช้งาน Virtualenv ผ่านแฟบริคในฐานะผู้ใช้ปรับใช้


130

ฉันต้องการเรียกใช้สคริปต์แฟบริคของฉันในเครื่องซึ่งจะเข้าสู่ระบบเซิร์ฟเวอร์ของฉันเปลี่ยนผู้ใช้เพื่อปรับใช้เปิดใช้งานโปรเจ็กต์. virtualenv ซึ่งจะเปลี่ยน dir ให้กับโปรเจ็กต์และออก git pull

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

ฉันมักจะใช้คำสั่ง workon จาก Virtualenvwrapper ซึ่งเป็นแหล่งที่มาของไฟล์เปิดใช้งานและไฟล์ postactivate จะทำให้ฉันอยู่ในโฟลเดอร์โครงการ ในกรณีนี้ดูเหมือนว่าเนื่องจากผ้าทำงานจากภายในเชลล์การควบคุมจึงมอบให้กับผ้าดังนั้นฉันจึงไม่สามารถใช้แหล่งที่มาของ bash ในตัวเป็น '$ source ~ / .virtualenv / myvenv / bin / enable'

ใครมีตัวอย่างและคำอธิบายว่าพวกเขาทำอย่างไร


1
ด้วยความอยากรู้ทำไมคุณไม่ใช้workonเป็น a 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วิธีนี้อาจทำให้คุณระเบิดได้เช่นเมื่อcommand1ล้มเหลว ( command2จะไม่ทำงาน) หรือหากcommand1ไม่ได้รับการหลีกเลี่ยงอย่างถูกต้องและมีอักขระเชลล์พิเศษเป็นต้น


7
แต่workonไม่เป็นที่รู้จักโดยsh. เราจะบอกให้ fabric ใช้ bash แทนได้อย่างไร?
Pierre de LESPINAY

18
IMHO source venv/bin/activateคุณก็ควรจะใช้ ง่ายขึ้นและทำงานนอกกรอบ workonเป็นการพึ่งพาเพิ่มเติมและแม้ว่าจะติดตั้งแล้วคุณต้องเพิ่มเข้าไป.bashrc- ซับซ้อนเกินไปสำหรับการปรับใช้ Fabric
Dave Halter

@PierredeLESPINAY ดูstackoverflow.com/questions/11272372/…สำหรับวิธีแก้ปัญหาของคุณ
dukebody

137

เป็นการอัปเดตการคาดการณ์ของ bitprophet: ด้วย Fabric 1.0 คุณสามารถใช้ประโยชน์จากคำนำหน้า ()และตัวจัดการบริบทของคุณเองได้

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 และรวมทั้งคำนำหน้าและคำสั่งภายในอาร์กิวเมนต์ -c สำหรับ bash ดูด้านล่าง
Dave

5
แต่sourceไม่เป็นที่รู้จักโดยsh. เราจะบอกให้ fabric ใช้ bash แทนได้อย่างไร?
Pierre de LESPINAY

2
@PierredeLESPINAY คุณสามารถใช้.แทนsource
katy lavallee

ทำไมคุณใช้cd()เมื่อคุณระบุอย่างเต็มที่เส้นทางไปactivateในprefix()?
Nick T

@NickT เพราะprefix()ดูเหมือนจะไม่มีซีดีที่นั่น - ดูเอกสารเหล่านี้ที่ทำเช่นเดียวกัน เราต้องการไปที่cdนั่นเพื่อที่ว่าเมื่อเราyieldเรียกใช้คำสั่งอื่น ๆ ( pip freezeในตัวอย่างของฉัน) คำสั่งเหล่านั้นสามารถสัมพันธ์กับไดเร็กทอรีนั้น
nh2

18

ฉันแค่ใช้ฟังก์ชัน wrapper อย่างง่าย 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)

9

virtualenvwrapper สามารถทำให้ง่ายขึ้นเล็กน้อย

  1. ใช้วิธีการของ @ nh2 (วิธีนี้ใช้ได้เช่นกันเมื่อใช้localแต่สำหรับการติดตั้ง Virtualenvwrapper ที่workonอยู่ใน$PATHกล่าวอีกนัยหนึ่งคือ 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 สำหรับคำสั่งภายในหรือระยะไกล แนวทางนี้มีประสิทธิภาพเนื่องจาก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 การประกาศ contextmanager ของ Virtualenv สามารถทำได้ใน 5 บรรทัดบน Python 2.6+ อย่างไรก็ตามไม่รับประกันว่านามแฝง 'workon' จะถูกนำเข้าอย่างถูกต้องเสมอและการใช้ `` source ... / enable '' น่าเชื่อถือกว่ามาก คำสั่ง
Alex Volkov

8

นี่คือแนวทางของฉันในการใช้virtualenvกับการปรับใช้ในพื้นที่

การใช้ตัวจัดการบริบทpath ()ของ fabric คุณสามารถเรียกใช้pipหรือpythonด้วยไบนารีจาก 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')

ฉันชอบสิ่งนี้มาก - ฉันไม่เห็นข้อเสียที่ชัดเจนของแนวทางนี้และมันก็สะอาดมาก ขอบคุณ :)
simon

ยังคงเป็นคำตอบที่ดีที่สุดและสะอาดที่สุดที่นี่
n1_

4

ขอบคุณสำหรับคำตอบทั้งหมดที่โพสต์และฉันต้องการเพิ่มอีกหนึ่งทางเลือกสำหรับสิ่งนี้ มีโมดูลfabric-Virtualenvซึ่งสามารถให้ฟังก์ชันเป็นรหัสเดียวกัน:

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

fabric-Virtualenv ใช้ประโยชน์fabric.context_managers.prefixซึ่งอาจเป็นวิธีที่ดี :)


น่าสนใจ แต่ฉันไม่ชอบความจริงที่ว่าไม่มีลิงก์ไปยัง SCM / ตัวติดตามปัญหา แพ็คเกจที่เผยแพร่บน PYPI โดยไม่มีลิงก์ไปยังซอร์สโค้ดและตัวติดตามปัญหาไม่ได้สร้างแรงบันดาลใจให้เกิดความไว้วางใจมากนัก .... แต่แก้ไขได้ง่าย
sorin

2

หากคุณต้องการติดตั้งแพ็กเกจเข้ากับสภาพแวดล้อมหรือต้องการเรียกใช้คำสั่งตามแพ็กเกจที่คุณมีในสภาพแวดล้อมฉันพบว่าแฮ็คนี้ช่วยแก้ปัญหาของฉันแทนที่จะเขียนวิธีการแฟบริกที่ซับซ้อนหรือติดตั้งแพ็กเกจระบบปฏิบัติการใหม่:

/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

นี่คือรหัสสำหรับมัณฑนากรที่จะส่งผลให้มีการใช้ Virtual Environment สำหรับการเรียก 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")

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.