Dağıtım kullanıcısı olarak yapı aracılığıyla bir virtualenv'i etkinleştirin


130

Fabric betiğimi yerel olarak çalıştırmak istiyorum, bu da sırayla sunucumda oturum açacak, kullanıcıyı dağıtmak için değiştirecek, projeleri .virtualenv'i etkinleştirecek, bu da projeye direk değiştirecek ve bir git pull gönderecek.

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

Ben genellikle virtualenvwrapper'daki workon komutunu kullanırım, hangi etkinleştirme dosyası kaynaklanır ve postactivate dosyası beni proje klasörüne koyar. Bu durumda, kumaş kabuğun içinden çalıştığı için kontrol kumaşa devredilmiş gibi görünüyor, bu nedenle bash'ın yerleşik kaynağını '$ source ~ / .virtualenv / myvenv / bin / activ' için kullanamıyorum.

Bunu nasıl yaptıklarına dair bir örneği ve açıklaması olan var mı?


1
Sadece meraktan, neden kullanmıyorsunuz workonbir şekilde prefix?
Daniel C. Sobral

Yanıtlar:


96

Şu anda, yaptığım şeyi yapabilirsin, ki bu kludgy ama mükemmel bir şekilde çalışıyor * (bu kullanım, virtualenvwrapper kullandığınızı varsayar - ki olmanız gerekir - ancak bahsettiğiniz daha uzun 'kaynak' çağrısında kolayca ikame edebilirsiniz , değilse):

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

1.0 sürümünden beri Fabric'in bu tekniği kullanan bir prefixbağlam yöneticisi vardır, böylece örneğin şunları yapabilirsiniz:

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

* Başarısız olduğunda ( asla çalışmayacağında) veya uygun şekilde kaçılmadığında ve özel kabuk karakterleri içerdiğinde , command1 && command2yaklaşımı kullanmanın üzerinize patlayabileceği durumlar olacaktır .command1command2command1


7
Ancak workonbilinmemektedir sh. Kumaşa bunun yerine bash kullanmasını nasıl söyleyebiliriz?
Pierre de LESPINAY

18
IMHO sadece kullanmalısınız source venv/bin/activate. Daha kolaydır ve kutudan çıkar çıkmaz çalışır. workonek bir bağımlılıktır ve kurulu olsa bile eklemeniz gerekir .bashrc- yapı dağıtımları için çok karmaşıktır.
Dave Halter

@PierredeLESPINAY , probleminizin çözümü için stackoverflow.com/questions/11272372/… adresine bakın .
dükebody

137

Bitprophet'in tahminine güncelleme olarak: Fabric 1.0 ile prefix () ve kendi bağlam yöneticilerinizden yararlanabilirsiniz.

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'yi çağıran ve hem öneki hem de komutu bash için -c argümanına saran kendi önek yönteminizi yazarak. Aşağıya bakın
Dave

5
Ancak sourcebilinmemektedir sh. Kumaşa bunun yerine bash kullanmasını nasıl söyleyebiliriz?
Pierre de LESPINAY

2
@PierredeLESPINAY .yerine kullanabilirsinizsource
katy

Neden kullanıyorsun cd()tam yolunu belirterek yaparken activatede prefix()?
Nick T

@NickT Çünkü prefix()orada cd yok gibi - aynı şeyi yapan bu belgelere bakın . İçin İstiyoruz cdbiz ne zaman bu kadar oradaki yield(diğer komutları yürütmek için pip freezebizim örneğimizde), bu komutlar bu dizine göreli olabilir.
nh2

18

Ben sadece run () yerine çağrılabilen basit bir sarmalayıcı işlevi virtualenv () kullanıyorum. CD içerik yöneticisini kullanmaz, bu nedenle göreceli yollar kullanılabilir.

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 bunu biraz daha basitleştirebilir

  1. @ Nh2'nin yaklaşımını kullanma (bu yaklaşım aynı zamanda kullanılırken de işe yarar local, ancak yalnızca workoniçinde olduğu , $PATHbaşka bir deyişle Windows'da bulunan sanal yazıcı kurulumları için )

    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. Veya fab dosyanızı dağıtın ve bunu yerel olarak çalıştırın. Bu kurulum, yerel veya uzak komutlar için virtualenv'i etkinleştirmenizi sağlar. Bu yaklaşım güçlüdür, çünkü local.bashrc dosyasını çalıştırma konusundaki yetersizliği etrafında çalışır 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'nin cevabını özetlediğiniz için teşekkürler, virtualenv contextmanager bildirimi Python 2.6+ üzerinde 5 satırda yapılabilir, ancak 'workon' takma adının her zaman doğru bir şekilde içe aktarılacağı asla garanti edilmez ve `` kaynak ... / etkinleştirme '' kullanmak çok daha güvenilirdir komut
Alex Volkov

8

Bu, virtualenvyerel dağıtımlarla kullanma yaklaşımımdır .

Fabric'in yol () bağlam yöneticisini kullanarak virtualenv'den ikili dosyalar ile pipveya çalıştırabilirsiniz 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')

Bunu çok beğendim - bu yaklaşımın bariz dezavantajlarını görmüyorum ve çok temiz. Teşekkürler :)
simon

hala en iyi ve en temiz cevap burada
n1_

4

Gönderilen tüm cevaplara teşekkürler ve bunun için bir alternatif daha eklemek istiyorum. Aynı kod olarak işlevi sağlayabilen bir modül, fabric-virtualenv vardır:

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

fabric-virtualenv kullanır fabric.context_managers.prefix, bu da iyi bir yol olabilir :)


İlginç ama SCM / sorun izleyiciye bağlantı olmaması hoşuma gitmiyor. Kaynak koduna ve sorun izleyiciye bir bağlantı olmadan yalnızca PYPI'de yayınlanan bir paket çok güven vermez .... ancak düzeltmesi kolaydır.
sorin

2

Paketleri ortama kurmak istiyorsanız veya ortamdaki paketlere göre komutları çalıştırmak istiyorsanız, karmaşık yapı yöntemleri yazmak veya yeni işletim sistemi paketleri kurmak yerine, sorunumu çözmek için bu hack'i buldum:

/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

Bu şekilde ortamı etkinleştirmeniz gerekmeyebilir, ancak ortamın altında komutları çalıştırabilirsiniz.


1

Herhangi bir çalıştırma / sudo çağrısı için Sanal Ortamın kullanılmasına neden olacak bir dekoratör kodu:

# 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

ve sonra dekoratörü kullanmak için dekoratörlerin sırasının önemli olduğuna dikkat edin:

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

1

Bu yaklaşım benim için çalıştı, bunu da uygulayabilirsiniz.

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

Varsayalım venvki sizin sanal env dizininiz ve bu yöntemi uygun olan yere ekleyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.