I'd love to be able to control the path to virtualenv direnv creates/activates. This would allow you to:
From a usability perspective, I'm imagining something like:
use python 3.6.2
would continue to put it in the default path, i.e. ./.direnv/python-3.6.1, but an optional directive, e.g.
use python 3.6.2
virtualenvpath /var/venvs
virtualenvname my_project
would create a virtualenv my_project in /var/venvs if it didn't exist, and activate it there if it did. It would be nice if virtualenvpath could be set globally (and overided locally).
I'm happy to have a go at creating a PR for this, but right now the path seems pretty hard-coded in stdlib.sh. Has anyone tried? Would similar feature be useful for the other isolated environments dotenv manages (rbenv, etc.)?
What I recommend for experimentation is to create your own layout_python function in ~/.config/direnv/direnvrc. Copy and paste the original function and change what you want, that will override it everywhere.
Potentially we could define a layout_python_path='$PWD/.direnv/python-$python_version' and then eval it in export VIRTUAL_ENV=$(eval "$layout_python_path"). That would minimize the changes to the ~/.config/direnv/direnvrc to just setting the layout_python_path variable.
Thanks! The best I could come up with was
layout_python() {
local python=${1:-python}
[[ $# -gt 0 ]] && shift
local old_env=$PWD/.direnv/virtualenv
unset PYTHONHOME
if [[ -d $old_env && $python = python ]]; then
export VIRTUAL_ENV=$old_env
else
if [ -z ${layout_python_path+x} ] ; then
local python_version
python_version=$("$python" -c "import platform as p;print(p.python_version())")
if [[ -z $python_version ]]; then
log_error "Could not find python's version"
return 1
fi
export VIRTUAL_ENV=$PWD/.direnv/python-$python_version
else
export VIRTUAL_ENV=${layout_python_path}/${PWD##*/}
fi
if [[ ! -d $VIRTUAL_ENV ]]; then
"$python" -m virtualenv "$@" "$VIRTUAL_ENV"
fi
fi
PATH_add "$VIRTUAL_ENV/bin"
}
It's not pretty, but it works, at least for me.
If the user sets layout_python_path=~/.ves in the .envrc for a project /path/to/my_project (or in the global direnvrc) then the virtualenv is created in ~/.ves/my_project. If they don't set layout_python_path then the virtualenv is created in the current location, i.e. $PWD/.direnv/python-$python_version.
The reason this is kind of ugly is I need to name the virtualenv differently depending on whether layout_python_path is set, in order for it to do what I want _and_ preserve the default behaviour when layout_python_path is not set.
Any suggestions for improvements?
One thing I'm thinking is that if you want to move the .direnv/virtualenv out of the project's folder then this will also apply to the other layouts. So potentially we could introduce a direnv_layout_dir=${direnv_layout_dir:-$PWD/.direnv}. Then in layout_python, export VIRTUAL_ENV=${direnv_layout_dir}/python-$python_version.
Then as a user, you could set whatever logic in your direnvrc. For example direnv_layout_dir=$HOME/.direnv-layouts/$(echo -n $PWD | shasum | awk '{ print $1 }')
With that method the virtualenv will be "named" (i.e. in a path whose last directory is) python-$python_version whatever the user does.
That's not my preference, because (like many many people) I put the name of the virtualenv in $PS1, and I'm used to that name acting as confirmation that I've activated the right one. If they are all called the same thing, e.g. python-3.6.1, it doesn't help.
Hence my hacky if-then-else solution above.
But it's not the end of the world, and I'm happy to go with your approach, rather than have a local fork of direnv!
I'm at a bit of a loss for how to integrate it to the other layouts (my knowledge of those languages and their conventions is extremely limited), but I'll take a look.
That's not my preference, because (like many many people) I put the name of the virtualenv in $PS1, and I'm used to that name acting as confirmation that I've activated the right one. If they are all called the same thing, e.g. python-3.6.1, it doesn't help.
That's true, but direnv can give you a guarantee that the virtualenv loaded is the one for the project. In that case is it still necessary to display which venv has been loaded?
Fair point!
I can do a direnv_layout_dir PR for Python. Would that be useful or do you need one that works for other languages/systems too? If the latter, I'll have to bow out at this point as my knowledge of the equivalents of virtualenv in other languages is not enough.
@williamsmj I went ahead and implemented it in #290. Do you mind giving it a try and give me feedback on the feature?
Feature added in #290. Closing.
Most helpful comment
What I recommend for experimentation is to create your own
layout_pythonfunction in~/.config/direnv/direnvrc. Copy and paste the original function and change what you want, that will override it everywhere.Potentially we could define a
layout_python_path='$PWD/.direnv/python-$python_version'and then eval it inexport VIRTUAL_ENV=$(eval "$layout_python_path"). That would minimize the changes to the~/.config/direnv/direnvrcto just setting thelayout_python_pathvariable.