Skip to content
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

Anaconda Integration #378

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

Anaconda Integration #378

wants to merge 4 commits into from

Conversation

leycec
Copy link
Contributor

@leycec leycec commented Jun 26, 2015

This pull request improves integration with both Anaconda and its anorexic sibling Miniconda, fixing #377 and making Babun Python users squeal with kiddish glee. (You're out there. I know you are.)

What's the Problem, Bro?

Read issue #377 first, bro. High-level synopsis + fuzzy details = eureka moment.

No, Really. What's the Problem?

pact-installed packages take precedence over conda-installed packages under Babun's default bash and oh-my-zsh environments. That's a problem, effectively nullifying Anaconda and Miniconda out of the box.

So. Like, What's Your Solution?

First, a real-world example. The pact-managed path /usr/bin precedes the conda-managed path /cygdrive/c/Miniconda3 under default installations of both Babun and Miniconda3:

{ ~ }  » print -l $path
/home/Administrator/bin
/usr/local/bin
/usr/local/bin
/usr/bin
/cygdrive/c/WINDOWS/system32
/cygdrive/c/WINDOWS
/cygdrive/c/WINDOWS/System32/Wbem
/cygdrive/c/Miniconda3
/cygdrive/c/Miniconda3/Scripts
/cygdrive/c/babun/.babun
/cygdrive/c/Documents and Settings/Administrator/.babun

Ideally, Miniconda3 users want that to instead resemble:

{ ~ }  » print -l $path
/cygdrive/c/Miniconda3
/cygdrive/c/Miniconda3/Scripts
/home/Administrator/bin
/usr/local/bin
/usr/local/bin
/usr/bin
/cygdrive/c/WINDOWS/system32
/cygdrive/c/WINDOWS
/cygdrive/c/WINDOWS/System32/Wbem
/cygdrive/c/babun/.babun
/cygdrive/c/Documents and Settings/Administrator/.babun

To effect that, this pull request adds a new user-configurable ${PRIORITIZE_CONDA_PACKAGES} boolean. When manually uncommented in ~/.babunrc, this boolean instructs Babun startup to juggle the ${PATH} such that conda-installed packages take precedence over pact-installed packages. For end user sanity, this boolean is disabled by default in /usr/local/etc/babun.rc. For portability, this boolean has been implemented at the plugin level and exhaustively tested as working under both bash and oh-my-zsh.

What Could Possibly Go Wrong?

Plenty:

  1. bash has no analogue to zsh's standard ${path} list. zsh implicitly splits the colon-delimited ${PATH} string into the ${path} list, each item of which is a directory in ${PATH} (in the same order). Changes to one are immediately reflected in the other, trivializing ${PATH} juggling. bash has nothing like that. In bash, ${PATH} juggling requires:
    1. Manually splitting ${PATH} on colons into a ${path}-like list. (Hint: it sucks.)
    2. Juggling that list.
    3. Manually joining that list on colons back into ${PATH}. (Yup! This sucks, too.)
  2. oh-my-zsh's default ~/.zshrc prepends ${PATH} with /usr/local/bin after all Babun startup scripts and plugins have been run. Like /usr/bin, /usr/local/bin is a pact-managed path containing copies of pact-installed packages – including python. Since this happens after Babun has had its say, the default ~/.zshrc overrides any attempt by Babun to prepend ${PATH} with a conda-managed path containing conda-installed packages – again, including python. (This is me ineffectually shaking my broken keyboard at the sky.)
  3. Babun prohibits plugins from modifying the current shell environment. For safety, each Babun plugin is isolated to a separate bash process forked specifically for that plugin. That's usually what we want. We don't want plugins of dubious reliability taking down the entire Babun startup (e.g., due to some external command returning non-zero exit status under set -e strictness). That would be terrible, right? On occasion, however, we do actually need to source a plugin in the current shell process – and we swear we'll be careful about it! This is that occasion.

We've already addressed how we perform ${PATH} juggling in bash. It's not pretty, but it works. Let's address the latter two.

Default .zshrc

It's critical that Babun be able to safely modify ${PATH}, both for this pull request and any future plugins requiring such modification. Babun shouldn't have to worry about the default ~/.zshrc maliciously undo-ing its hard work.

Here's what the default ~/.zshrc does:

export PATH=$HOME/bin:/usr/local/bin:$PATH

Prepending ${PATH} by /usr/local/bin here is pointless. As examples above illustrate, Babun already prepends ${PATH} by /usr/local/bin. Why do it twice? Don't! So, the prior statement is reducible without loss of generality to:

export PATH=$HOME/bin:$PATH

This pull request patches the latter statement into the default ~/.zshrc on installation. (O.K., technically /usr/local/etc/babun/home/.zshrc is patched on installation. But you know what we mean, man.) Since the default ~/.bashrc suffers no similar issue, we're done here.

Plugin Isolation

While Babun plugins cannot modify the current shell environment, Babun does provides two shell scripts commonly sourced on both bash and zsh startup:

  • /usr/local/etc/babun.rc, which is sourced before ~/.babunrc, which optionally redefines the ${PRIORITIZE_CONDA_PACKAGES} boolean upon which our ${PATH} juggling depends. It follows that /usr/local/etc/babun.rc cannot perform such juggling. (Q.E.D., and stuff.)
  • /usr/local/etc/babun.start, a high-level wrapper around the babun-core/plugins/start.sh and babun-core/tools/welcome.sh scripts. Technically, our ${PATH} juggling could be embedded directly into this wrapper. Doing so would probably establish a bad precedent, however. It's a high-level wrapper. It's not supposed to contain low-level logic specific to optional external commands. Plugins exist for a reason. This is it.

Since babun.rc is right out and babun.start should be, we're at an impasse. I'd hope we could all agree, though, that plugins should be able to modify the current shell environment when there absolutely exists no other way. (Let's just pretend we agree.) Under that assumption, this pull request adds support for a new type of plugin-specific script: start_sourced.sh.

Like start.sh scripts, start_sourced.sh scripts are run at Babun startup. Unlike start.sh scripts, start_sourced.sh scripts are sourced in the current shell process rather than run in a separate bash process. Simple, right?

The End, My Friend

Let's put it all together. Since plugins can now modify the current shell environment, we define a new conda plugin whose start_sourced.sh script tests whether the ${PRIORITIZE_CONDA_PACKAGES} boolean is true and, if so:

  1. Iteratively searches the ${PATH} for all Anaconda and Miniconda directories.
  2. Moves all such directories to the front of ${PATH} in an order-preserving manner (i.e., preserving the internal order of all such directories and all other directories in ${PATH}).

Yeah.

This plugin prioritizes Anaconda- and Miniconda-installed packages (e.g.,
"/cygdrive/c/Miniconda3/python") over pact-installed packages (e.g.,
"/usr/bin/python") when the user-configurable ${PRIORITIZE_CONDA_PACKAGES}
boolean is "true". By default, pact-installed packages still take priority over
Anaconda- and Miniconda-installed packages.
A user-configurable ${PRIORITIZE_CONDA_PACKAGES} boolean has been added.
When explicitly enabled by the user, the new "conda" plugin prioritizes
Anaconda- and Miniconda-installed packages over pact-installed packages.
For backwards compatibility, this setting defaults to "false".
Plugins may now (optionally) provide a "start_sourced.sh" script, which, if
explicitly referenced in the top-level "start_sourced.sh" script, will be
sourced on Babun startup by the current shell process rather than run in a
separate bash process. This functionality is required by plugins modifying
the current shell environment: namely the recent "conda" plugin, modifying
the current ${PATH}.
Previously, oh-my-zsh's default "~/.zshrc" prepended the $PATH with
"/usr/local/bin". Since doing so conflicts with plugins also prepending the
$PATH (e.g., "conda") and is redundant (as "/usr/local/bin" already heads the
$PATH by default), "~/.zshrc" is now patched on installation to prevent this.
@quapka
Copy link

quapka commented May 18, 2016

I've downloaded babun today and could not find any ${PRIORITIZE_CONDA_PACKAGES} variable in ~/.babunrc is this feature supported yet?

@delurker
Copy link

delurker commented Jun 13, 2016

You can fix this yourself with the following.

Find the alternative python location, which should already be in your path.

{ ~ }  » where python
/usr/bin/python
/cygdrive/c/Users/$USER/Miniconda3/python

Add a symlink to the python you wish to use in ~/bin.

{ ~ }  » ln -s /cygdrive/c/Users/$USER/Miniconda3/python ~/bin

~/bin (/home/$USER/bin) is first in the path so takes precedent.

{ ~ }  »  python -V
Python 3.5.1 :: Continuum Analytics, Inc.

Note: My libraries work but I have not tested conda environments.

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.

None yet

3 participants