通过部署用户激活Virtualenv
-
19-09-2019 - |
题
我想在本地运行我的面料脚本,然后将其登录到我的服务器,切换用户部署,激活项目.virtualenv,这将更改为项目并发出GIT拉动。
def git_pull():
sudo('su deploy')
# here i need to switch to the virtualenv
run('git pull')
我通常使用virtualenvwrapper的workon命令,该命令来源,该命令来源,激活文件将使我将我放在项目文件夹中。在这种情况下,似乎由于织物从外壳内部运行,因此控件会覆盖到面料上,因此我无法将Bash的源内置到'$ source〜/.virtualenv/myvenv/myvenv/bin/activate'
有人有一个例子和解释他们如何做到这一点?
解决方案
现在,您可以做我所做的事情,这是kludgy但效果很好*(此用法假设您使用VirtualenvWrapper-您应该这样做 - 但是您可以轻松地替换为更长的“源”调用,您提到了, 如果不):
def task():
workon = 'workon myvenv && '
run(workon + 'git pull')
run(workon + 'do other stuff, etc')
自1.0版以来,面料具有 prefix
上下文管理器 哪个使用此技术,因此您可以:
def task():
with prefix('workon myvenv'):
run('git pull')
run('do other stuff, etc')
*有必要在某些情况下使用 command1 && command2
方法可能会炸毁您,例如 command1
失败(command2
永远不会运行)或 command1
没有适当逃脱并包含特殊的外壳角色,依此类推。
其他提示
作为对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')
我只是使用一个简单的包装器函数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)
virtualenvwrapper
可以使它变得更简单
使用 @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")
或部署工厂文件并在本地运行。此设置使您可以激活本地或远程命令的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")
这是我使用的方法 virtualenv
与本地部署。
使用面料 小路() 您可以运行的上下文管理器 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')
多亏了发布的所有答案,我想为此添加另一种选择。有一个模块, 织物 - 虚拟, ,可以将函数作为相同的代码提供:
>>> from fabvenv import virtualenv
>>> with virtualenv('/home/me/venv/'):
... run('python foo')
织物virtualenv使用 fabric.context_managers.prefix
, ,这可能是一个好方法:)
如果您想将软件包安装到环境中或想根据环境中的软件包运行命令,我发现了这个hack来解决我的问题,而不是编写复杂的面料或安装新的OS软件包:
/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
这样,您可能不需要激活环境,但是可以在环境下执行命令。
这是装饰器的代码,将导致使用虚拟环境进行任何运行/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")
这种方法对我有用,您也可以应用此方法。
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
是您的虚拟环境目录,并在适当的地方添加此方法。