Attivare un virtualenv via di tessuto come distribuire utente
-
19-09-2019 - |
Domanda
Voglio correre il mio tessuto script in locale, che, a sua volta, ad accedere al mio server, switch utente di distribuire, di attivare progetti .virtualenv, che cambierà dir il progetto e il rilascio di un git pull.
def git_pull():
sudo('su deploy')
# here i need to switch to the virtualenv
run('git pull')
Io in genere uso il workon comando da virtualenvwrapper che fonti l'attivazione di file e il postactivate file mi mettono nella cartella del progetto.In questo caso, sembra che a causa di tessuto viene eseguito dall'interno della shell, il controllo è dare al tessuto, in modo che non posso usare bash fonte built-in '$source ~/.virtualenv/myvenv/bin/attivare'
Qualcuno ha un esempio e una spiegazione di come hanno fatto questo?
Soluzione
Adesso, si può fare quello che faccio, che è difettose, ma funziona perfettamente (con utilizzo presuppone che si sta utilizzando virtualenvwrapper, che dovrebbe essere-ma si può facilmente sostituire piuttosto più 'fonte' chiamata che hai citato, se non lo è):
def task():
workon = 'workon myvenv && '
run(workon + 'git pull')
run(workon + 'do other stuff, etc')
A partire dalla versione 1.0, Tessuto prefix
contesto il gestore di che utilizza questa tecnica, è possibile per esempio:
def task():
with prefix('workon myvenv'):
run('git pull')
run('do other stuff, etc')
* Ci sono tenuti ad essere dei casi in cui l'utilizzo dell' command1 && command2
approccio può saltare su di voi, come quando command1
non riesce (command2
non verrà mai eseguita) o se command1
non è propriamente sfuggito e contiene caratteri speciali della shell, e così via.
Altri suggerimenti
Come un aggiornamento per bitprophet previsione:Con Tessuto 1.0 è possibile utilizzare prefisso() e proprio contesto gestori.
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')
Sto solo utilizzando una semplice funzione wrapper virtualenv() che può essere chiamato al posto di run().Non utilizzare il cd contesto manager, in modo che i percorsi relativi possono essere utilizzati.
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
può fare questo un po ' più semplice
Con @nh2 approccio (questo approccio funziona anche quando si utilizza
local
, ma solo per virtualenvwrapper installazioni in cuiworkon
è in$PATH
, in altre parole, 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")
O distribuire il fab file ed eseguire questo locale.Questa impostazione consente di attivare la virtualenv locale o remoto comandi.Questo approccio è potente perché funziona tutto
local
's incapacità di eseguire .bashrc utilizzandobash -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")
Questo è il mio approccio utilizzando virtualenv
con locale distribuzioni.
Utilizzando tessuto path() contesto manager è possibile eseguire pip
o python
con i binari 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')
Grazie per tutte le risposte pubblicate e vorrei aggiungere una o più alternative per questo.C'è un modulo, tessuto-virtualenv, e in grado di fornire la funzione del codice stesso:
>>> from fabvenv import virtualenv
>>> with virtualenv('/home/me/venv/'):
... run('python foo')
tessuto-virtualenv fa uso di fabric.context_managers.prefix
, che potrebbe essere una buona soluzione :)
Se si desidera installare i pacchetti ambiente o desidera eseguire comandi in base ai pacchetti che si hanno nell'ambiente, ho trovato questo hack per risolvere il mio problema, invece di scrivere metodi complessi di tessuto o l'installazione di nuovi pacchetti sistema operativo:
/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
In questo modo potrebbe non essere necessario attivare l'ambiente, ma è possibile eseguire i comandi in ambiente.
Ecco il codice per un decoratore che comporterà l'utilizzo di un Ambiente Virtuale per qualsiasi corsa/sudo chiamate:
# 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 poi utilizzare il decoratore, nota l'ordine dei decoratori è importante:
@task
@with_venv
def which_python():
"Gets which python is being used"
run("which python")
Questo approccio ha funzionato per me, si può applicare anche a questo.
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'")
Supponendo venv
è virtuale env directory e aggiungere questo metodo, laddove opportuno.