sashahart / vex

Run a command in the named virtualenv.
MIT License
372 stars 26 forks source link

PATH problem under zsh #44

Closed ariscn closed 8 years ago

ariscn commented 9 years ago
$ ~/.local/bin/vex test zsh -f -d
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/<me>/.virtualenvs/test/bin

I renamed all of my .z* files, and ran zsh -f -d, which ensures that zsh doesn't load RC files. In others words, this starts zsh as cleanly as I can, ignoring all of my personal and OS config. And yet, my virtualenv's bin still ends up at the end of my PATH instead of at the beginning.

sashahart commented 9 years ago

Keep looking at your shell environment. I use zsh, but there are too many degrees of freedom for me to immediately know what is going on. Maybe you will need to use something like strace to figure out more about what zsh is up to on your system. If you can replicate on a clean VM or something that would be more interesting.

vex --version 0.0.18

echo $PATH /home/sasha/bin:/home/sasha/.local/bin:/home/sasha/.npm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

vex --python python3.4 -m test echo done Already using interpreter /usr/bin/python3.4 Using base prefix '/usr' New python executable in /home/sasha/.virtualenvs/test/bin/python3.4 Also creating executable in /home/sasha/.virtualenvs/test/bin/python Installing setuptools, pip, wheel...done. done

vex test zsh -f -d rex% echo $PATH /home/sasha/.virtualenvs/test/bin:/home/sasha/bin:/home/sasha/.local/bin:/home/sasha/.npm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin rex%

I find that zsh -f -d actually does at least source /etc/zsh/zshenv:

vex test strace zsh -f -d -c "echo hi" 2>&1 | grep open open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 open("/lib/x86_64-linux-gnu/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3 open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 open("/lib/x86_64-linux-gnu/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = 3 open("/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3 open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 open("/dev/pts/12", O_RDWR|O_NOCTTY) = 3 open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 11 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 11 open("/lib/x86_64-linux-gnu/libnss_compat.so.2", O_RDONLY|O_CLOEXEC) = 11 open("/lib/x86_64-linux-gnu/libnsl.so.1", O_RDONLY|O_CLOEXEC) = 11 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 11 open("/lib/x86_64-linux-gnu/libnss_nis.so.2", O_RDONLY|O_CLOEXEC) = 11 open("/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 11 open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 11 open("/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 11 open("/proc/self/loginuid", O_RDONLY) = 11 open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 11 open("/var/run/utmp", O_RDONLY|O_CLOEXEC) = 11 open("/etc/zsh/zshenv", O_RDONLY|O_NOCTTY) = 3 open("/dev/null", O_RDONLY|O_NOCTTY) = 3

vex, by design, can only modify the shell environment of the process it is launching. vex does not know or care whether that process is a shell because it doesn't matter. Once the shell process starts, the shell can do whatever it wants to the environ it presents. If the shell is told to put certain things at the head of $PATH, it will do so. That could be any number of things, since shell is a messy environment. vex does not get any further opportunity to bicker with zsh and say "no, that's wrong, put the virtualenv path first." Once the process has started, that ship has sailed.

But if your ~/.bashrc says "SMASH PATH" then when you run bash under vex, vex will hand off a perfectly good virtualenv-activated environment for bash to use, and then after vex hands off bash will smash PATH as you instructed, and something else will have priority before your virtualenv stuff.

sashahart commented 9 years ago

there is also zsh -xv

ariscn commented 9 years ago

Thanks for the strace suggestion! Apparently zsh under OS X sources /etc/zshenv, which contains:

# system-wide environment settings for zsh(1)
if [ -x /usr/libexec/path_helper ]; then
    eval `/usr/libexec/path_helper -s`
fi

And /usr/libexec/path_helper outputs:

PATH="<stuff>"; export PATH;
MANPATH="<stuff>"; export MANPATH;

A quick sudo mv /etc/zshenv /etc/zshenv.bak and vex is working as expected, with the virtualenv at the front of $PATH.

path_helper is also run in /etc/profile. Given that OS X is very commonly used by developers, perhaps you could add a note to the README about this problem?

sashahart commented 8 years ago

This is a bug in the zsh package you got for OS X. I don't know where that comes from, but if they want to break your shell environment there is nothing I can do about that.

Despite the brokenness of your /etc/zshenv, simply disabling the system's zshenv isn't something I can recommend in good conscience.

ariscn commented 8 years ago

I still encourage you to add a note to the vex README. A very significant portion of the people using (or interested in using) vex will be on OS X, and vex will not work for them as intended unless they stumble across this issue or do a lot of troubleshooting.

brianbruggeman commented 8 years ago

I also use a Mac. I'm adding a comment here in case someone else ends up stumbling around. I found out a little late that all of my packages were actually being added to my host environment under /usr/local/lib/...

I had this same symptom, but my solution and actual problem was different.

Zsh honors /etc/paths where as bash does not immediately use that file. I had to remove /etc/paths.

sashahart commented 8 years ago

Thanks for your input. I would complain about removing system files in /etc as a solution, but it seems a lot of basic shell stuff is broken in natural OS X environments :(