Skip to content

Fix: support newer conda #290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 23, 2018
Merged

Fix: support newer conda #290

merged 2 commits into from
Nov 23, 2018

Conversation

lmmarsano
Copy link
Contributor

pyenv-virtualenv had issues listing conda environments, activating conda environments, and cleaning up pyenv virtualenv runs on error.
The issue is primarily explained in #178: conda and activate files no longer exist under derived conda environment bin directories, so pyenv-virtualenv can't use them to detect conda.
To resolve this, I add criteria to detect a conda-meta subdirectory.
Obtaining VIRTUALENV_PREFIX_PATH uses an implementation of realpath that would normalize paths across multiple scripts (though this might also be achieved with cd in a subshell).
(Moreover, I'm puzzled that substitutes for readlink and related commands are redefined throughout several scripts instead of defined in a single file for inclusion via sourceing. Is there a reason for this?)
A pyenv-which hook redirects conda invocations to its new location in the base environment.
Is this the best way to go about it?

I'd like to include functional tests, though I'm not sure how to best do that.
I welcome suggestions/solutions.

closes pyenv/pyenv#1230
closes #178
and probably others

Copy link
Collaborator

@yyuu yyuu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patch! Looks good in general 👍


if ! {
enable -f "${BASH_SOURCE%/*}"/../libexec/pyenv-realpath.dylib realpath ||
type realpath
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to have this condition? At least this is something new and I'd like to know your intention of this new condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose is to skip defining unneeded substitutes.
realpath is commonly available: coreutils & busybox have it, so it's basically standard in Linux systems.
BSD systems commonly have it, too.
Is there something wrong with the native commands?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine to use GNU coreutils feature as long as we have fallback code for where the platform without it. My point was that there was no such condition before you split the code into library condition and would like to know your intention for the change.


realpath() {
local cwd="$PWD"
local path="$(normalize "$1")"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this normalization something nice to have, or a requirement to make ot working...? To be honest, the normalization code looks little complicated and took me awhile to understand the bahaviour. Plus, I think the realpath.dynlib won't behave equally.

Copy link
Contributor Author

@lmmarsano lmmarsano Nov 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realpath "$(realpath "${PYENV_PREFIX_PATH}")"/../.. didn't work with that standard behavior missing.
(The previous realpath definition breaks down at the resolve_link .. step.)
There might be better alternatives.
I'll try to simplify it if possible.

How do you get realpath.dynlib?
If it doesn't follow standards, then it needs to be brought into compliance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realpath() {
local f="$*" \
name dir
[[ $f ]] || {
>&2 echo ${FUNCNAME[0]}: missing operand
return
}
while [[ -L $f ]]; do
f="$(resolve_link "$f")"
done
if [[ ! -d $f ]]; then
name="/${f##*/}"
# parent?
dir="${f%/*}"
if [[ $dir == $f ]]; then
#lacks /: parent is current directory
f="$PWD"
else
f="$dir"
fi
fi
#absolute directory
dir="$(cd "$f"
pwd)"
echo "$dir$name"
}

Simplified it: normalize is now gone.
(My previous version was wrong: normalize should happen after link resolution, not before.)
Simply realpath "${PYENV_PREFIX_PATH}"../.. should work (as it does with standard realpath).
Is this better?

#!/usr/bin/env bash
# Summary: Substitute realpath if unavailable as a builtin or file
# Usage: . pyenv-virtualenv-realpath

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to have "set -e" in all scripts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do that.
However, are you aware this is an inline shell file and not a proper script?
It's never run on it's own.
It's always run inline/sourced inside another script already doing set -e.
It's really like a reusable, incomplete section of larger script, like the files under pyenv.d.
Should I rename it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. I was overlooking that this script was placed umder libexec dir. It's fine without -e.

pyenv-virtualenvs could not list conda environments & pyenv shell would only activate the base conda environment
the conda detection criteria of testing the presence of `conda` or `activate` files under `$(pyenv root)/versions/$version/bin` appears to be the culprit, since newer environments no longer include these files: those files reside in the base conda environment
- add detection criteria of `$(pyenv root)/versions/$version/conda-meta`
- compute the real prefix to the base environment from `realpath $(realpath $(pyenv root)/versions/$version)/../..`
- to allow that, enhance substitute `realpath` in `pyenv-virtualenvs` to reduce relative paths `.` & `..`, and factor that code out to a file under `libexec` for reuse
- hook `which` to locate conda from the real prefix
also cleanup compatibility paths
#!/usr/bin/env bash
# Summary: Substitute realpath if unavailable as a builtin or file
# Usage: . pyenv-virtualenv-realpath

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. I was overlooking that this script was placed umder libexec dir. It's fine without -e.


if ! {
enable -f "${BASH_SOURCE%/*}"/../libexec/pyenv-realpath.dylib realpath ||
type realpath
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine to use GNU coreutils feature as long as we have fallback code for where the platform without it. My point was that there was no such condition before you split the code into library condition and would like to know your intention for the change.

@yyuu yyuu merged commit 6d90f61 into pyenv:master Nov 23, 2018
lmmarsano added a commit to lmmarsano/pyenv-virtualenv that referenced this pull request Oct 9, 2019
non-base conda environments lack bin/conda
apply same solution as pyenv#290
@guesswh0
Copy link

guesswh0 commented Mar 3, 2020

For macOS users don't forget to install:

brew install coreutils

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

pyenv seems to break conda environments Can not access Anaconda/Miniconda environment as virtualenv
3 participants