Pergunta

Quero executar meu script de tecido localmente, que, por sua vez, login no meu servidor, trocar o usuário para implantar, ativar os projetos .VirtualEnv, que mudará o dir para o projeto e emitirá uma tração git.

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

Normalmente, uso o comando Workon do VirtualEnvWrapper, que obtém o arquivo ativado e o arquivo Postative me colocará na pasta do projeto. Nesse caso, parece que, como o tecido corre de dentro do shell, o controle é entregue ao tecido, por isso não posso usar a fonte de Bash integrada para '$ fonte ~/.virtualenv/myvenv/bin/ativação'

Alguém tem um exemplo e explicação de como eles fizeram isso?

Foi útil?

Solução

No momento, você pode fazer o que eu faço, que é kludgy, mas funciona perfeitamente bem* (esse uso pressupõe que você esteja usando o VirtualEnvwrapper - o que você deve ser - mas você pode facilmente substituir na chamada 'fonte' bastante mais longa que você mencionou , se não):

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

Desde a versão 1.0, o tecido tem um prefix Gerente de contexto que usa essa técnica para que você possa, por exemplo,:

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

* É provável que haja casos em que o uso do command1 && command2 a abordagem pode explodir sobre você, como quando command1 falha (command2 nunca vai correr) ou se command1 Não é escape adequadamente e contém caracteres de concha especiais, e assim por diante.

Outras dicas

Como atualização da previsão do BitProphet: com o Fabric 1.0, você pode usar prefixo() e seus próprios gerentes de contexto.

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

Estou apenas usando uma função de wrapper simples virtualenv () que pode ser chamada em vez de run (). Ele não usa o gerenciador de contexto de CD, portanto, os caminhos relativos podem ser usados.

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)

virtualenvwrapper pode tornar isso um pouco mais simples

  1. Usando a abordagem do @NH2 (essa abordagem também funciona ao usar local, mas apenas para instalações do VirtualEnvwrapper onde workon é em $PATH, em outras palavras - 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. Ou implante seu arquivo FAB e execute isso localmente. Essa configuração permite ativar o VirtualEnv para comandos locais ou remotos. Essa abordagem é poderosa porque funciona locala incapacidade de executar .bashrc usando 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")
    

Esta é minha abordagem para usar virtualenv com implantações locais.

Usando o tecido caminho() Gerente de contexto que você pode executar pip ou python com binários da 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')

Obrigado a todas as respostas postadas e eu gostaria de adicionar mais uma alternativa para isso. Existe um módulo, Fabric-virtualenv, que pode fornecer a função como o mesmo código:

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

Fabric-virtualenv faz uso de fabric.context_managers.prefix, o que pode ser uma boa maneira :)

Se você deseja instalar os pacotes no ambiente ou executar comandos de acordo com os pacotes que você tem no ambiente, encontrei esse hack para resolver meu problema, em vez de escrever métodos complexos de tecido ou instalar novos pacotes do sistema operacional:

/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

Dessa forma, você pode não precisar ativar o ambiente, mas pode executar comandos no ambiente.

Aqui está o código para um decorador que resultará no uso do ambiente virtual para qualquer chamada de execução/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

E então, para usar o decorador, observe que a ordem dos decoradores é importante:

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

Essa abordagem funcionou para mim, você também pode aplicar isso.

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

Assumindo venv é o seu diretório Env virtual e adicione esse método sempre que apropriado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top