我想在本地运行我的结构脚本,然后登录我的服务器,切换用户进行部署,激活项目.virtualenv,这会将dir更改为项目并发出git pull。
def git_pull():
sudo('su deploy')
# here i need to switch to the virtualenv
run('git pull')
我通常使用virtualenvwrapper中的workon命令来源激活文件,而postactivate文件将把我放在项目文件夹中。在这种情况下,似乎因为结构从shell内部运行,控制权交给了结构,所以我不能使用bash的内置源代码来'$ source~ / .virtualenv / myvenv / bin / activate'
任何人都有他们如何做到这一点的例子和解释?
答案 0 :(得分:137)
作为对bitprophet预测的更新:使用Fabric 1.0,您可以使用prefix()和您自己的上下文管理器。
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')
答案 1 :(得分:95)
现在,你可以做我做的事情,这是kludgy,但效果非常好*(这种用法假设你正在使用virtualenvwrapper - 你应该 - 但你可以轻松替换相当长的'源'打电话给你,如果没有):
def task():
workon = 'workon myvenv && '
run(workon + 'git pull')
run(workon + 'do other stuff, etc')
从1.0版开始,Fabric有prefix
context manager使用这种技术,所以你可以举例如:
def task():
with prefix('workon myvenv'):
run('git pull')
run('do other stuff, etc')
*必然会出现使用command1 && command2
方法的情况,例如command1
失败(command2
永不运行)或{{1} }没有正确转义并包含特殊的shell字符,等等。
答案 2 :(得分:17)
我只是使用一个简单的包装函数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)
答案 3 :(得分:8)
virtualenvwrapper
可以让这更简单
使用@ nh2的方法(这种方法在使用local
时也有效,但仅适用于workon
位于$PATH
的virtualenvwrapper安装,换句话说 - Windows)< / p>
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")
或部署您的fab文件并在本地运行。此设置允许您激活本地或远程命令的virtualenv。这种方法很有用,因为它可以解决local
使用bash -l
无法运行.bashrc的问题:
@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")
答案 4 :(得分:7)
这是我使用virtualenv
进行本地部署的方法。
使用fabric的path()上下文管理器,您可以使用virtualenv中的二进制文件运行pip
或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')
答案 5 :(得分:4)
感谢发布的所有答案,我想为此添加一个替代方案。有一个模块fabric-virtualenv,它可以提供相同代码的功能:
>>> from fabvenv import virtualenv
>>> with virtualenv('/home/me/venv/'):
... run('python foo')
fabric-virtualenv使用fabric.context_managers.prefix
,这可能是一个好方法:)
答案 6 :(得分:2)
如果你想将软件包安装到环境中或想要根据环境中的软件包运行命令,我发现这个hack来解决我的问题,而不是编写复杂的结构方法或安装新的OS软件包: / p>
/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
这样您可能不需要激活环境,但可以在环境下执行命令。
答案 7 :(得分:1)
以下是装饰器的代码,它将导致任何run / sudo调用使用Virtual Environment:
# 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")
答案 8 :(得分: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
是您的虚拟环境目录,并在适当的地方添加此方法。
答案 9 :(得分:0)
我将 pyenv 与插件 pyenv-virtualenvwrapper 一起使用。我在 workon 上没有成功,而是使用了这个(fabric 2.5):
with c.prefix('source /home/mirek/.virtualenvs/%s/bin/activate' % PROJECT):
with c.prefix('cd /home/mirek/%s/%s' % (PROJECT, PROJECT)):
c.run('python manage.py ....')
对于 git pull
代理转发是好的,即。 ssh -A ..
或更好的 ~/.ssh/config
类似这样的:
Host forpsi
HostName xx.xx.xx.xx
IdentityFile /home/mirek/.ssh/id_ed25519_xxx
ForwardAgent yes
现在在开发机器上,如果您在代理中有一个私钥(在 ssh-add
之后,或者如果您在 AddKeysToAgent yes
之后在 ~/.ssh/config
中有 git push
)然后git pull
不应询问密钥的密码。