Skip to content

Instantly share code, notes, and snippets.

@jakirkham
Last active June 14, 2016 22:35
Show Gist options
  • Save jakirkham/4d7830b3a7be1077168c45b1a7ecdc6b to your computer and use it in GitHub Desktop.
Save jakirkham/4d7830b3a7be1077168c45b1a7ecdc6b to your computer and use it in GitHub Desktop.
conda / conda_env activate / deactivate scripts
#!/bin/bash
# Determine the directory containing this script
if [[ -n $BASH_VERSION ]]; then
_SCRIPT_LOCATION=${BASH_SOURCE[0]}
SHELL="bash"
elif [[ -n $ZSH_VERSION ]]; then
_SCRIPT_LOCATION=${funcstack[1]}
SHELL="zsh"
else
echo "Only bash and zsh are supported"
return 1
fi
_CONDA_DIR=$(dirname "$_SCRIPT_LOCATION")
if [ $# -gt 1 ]; then
(>&2 echo "Error: did not expect more than one argument.")
(>&2 echo " (Got $@)")
return 1
fi
case "$(uname -s)" in
CYGWIN*|MINGW32*|MSYS*)
EXT=".exe"
;;
*)
EXT=""
;;
esac
# Export whatever PS setting we have, so it is available to Python subprocesses
export PS1
# Ensure that this script is sourced, not executed
# Also note that errors are ignored as `activate foo` doesn't generate a bad
# value for $0 which would cause errors.
if [[ -n $BASH_VERSION ]] && [[ "$(basename "$0" 2> /dev/null)" == "activate" ]]; then
(>&2 echo "Error: activate must be sourced. Run 'source activate envname'
instead of 'activate envname'.
")
"$_CONDA_DIR/conda" ..activate $SHELL$EXT -h
exit 1
fi
"$_CONDA_DIR/conda" ..checkenv $SHELL$EXT "$@"
if (( $? != 0 )); then
return 1
fi
# Ensure we deactivate any scripts from the old env
# Note: this empties $@. Preserve a copy.
args=$@
source "$_CONDA_DIR/deactivate"
_NEW_PATH=$("$_CONDA_DIR/conda" ..activate $SHELL$EXT "$args")
if (( $? == 0 )); then
export CONDA_PATH_BACKUP="$PATH"
# export this to restore it upon deactivation
export CONDA_OLD_PS1=$PS1
export PATH="$_NEW_PATH"
# Get first path (should be full path prefix of our env)
# inner string extraction pulls off first path
# outer string removes /bin if present (on Unix)
firstpath=${PATH%%:*}
export CONDA_DEFAULT_ENV="$(echo ${firstpath} | sed "s|/bin$||")" &>/dev/null
# Legacy support: CONDA_DEFAULT_ENV used to be either env name or full path if given as path.
# CONDA_DEFAULT_ENV is now always full path.
# Keep CONDA_ENV_PATH around, and have it mirror CONDA_DEFAULT_ENV.
# Last date of change: 2016-04-18
export CONDA_ENV_PATH=$CONDA_DEFAULT_ENV
export PS1="$( "$_CONDA_DIR/conda" ..setps1 $SHELL$EXT "$args" )"
# Load any of the scripts found $PREFIX/etc/conda/activate.d AFTER activation
_CONDA_D="${CONDA_DEFAULT_ENV}/etc/conda/activate.d"
if [[ -d "$_CONDA_D" ]]; then
IFS=$(echo -en "\n\b")&>/dev/null && for f in $(find "$_CONDA_D" -iname "*.sh"); do source "$f"; done
fi
else
return $?
fi
if [[ -n $BASH_VERSION ]]; then
hash -r
elif [[ -n $ZSH_VERSION ]]; then
rehash
else
echo "Only bash and zsh are supported"
return 1
fi
from __future__ import print_function, division, absolute_import
import errno
import os
from os.path import isdir, abspath
import re
import sys
from conda.cli.common import find_prefix_name
from conda.utils import (shells, run_in)
on_win = sys.platform == "win32"
def help(command, shell):
# sys.argv[1] will be ..checkenv in activate if an environment is already
# activated
# get grandparent process name to see which shell we're using
if command in ('..activate', '..checkenv'):
if shell in ["cmd.exe", "powershell.exe"]:
sys.exit("""Usage: activate ENV
Adds the 'Scripts' and 'Library\\bin' directory of the environment ENV to the front of PATH.
ENV may either refer to just the name of the environment, or the full
prefix path.""")
else:
sys.exit("""Usage: source activate ENV
Adds the 'bin' directory of the environment ENV to the front of PATH.
ENV may either refer to just the name of the environment, or the full
prefix path.""")
elif command == '..deactivate':
if shell in ["cmd.exe", "powershell.exe"]:
sys.exit("""Usage: deactivate
Removes the environment prefix, 'Scripts' and 'Library\\bin' directory
of the environment ENV from the front of PATH.""")
else:
sys.exit("""Usage: source deactivate
Removes the 'bin' directory of the environment activated with 'source
activate' from PATH. """)
else:
sys.exit("No help available for command %s" % sys.argv[1])
def prefix_from_arg(arg, shelldict):
'Returns a platform-native path'
# MSYS2 converts Unix paths to Windows paths with unix seps
# so we must check for the drive identifier too.
if shelldict['sep'] in arg and not re.match('[a-zA-Z]:', arg):
# strip is removing " marks, not \ - look carefully
native_path = shelldict['path_from'](arg)
if isdir(abspath(native_path.strip("\""))):
prefix = abspath(native_path.strip("\""))
else:
raise ValueError('could not find environment: %s' % native_path)
else:
prefix = find_prefix_name(arg.replace('/', os.path.sep))
if prefix is None:
raise ValueError('could not find environment: %s' % arg)
return prefix
def binpath_from_arg(arg, shelldict):
# prefix comes back as platform-native path
prefix = prefix_from_arg(arg, shelldict=shelldict)
if sys.platform == 'win32':
paths = [
prefix.rstrip("\\"),
os.path.join(prefix, 'Library', 'mingw-w64', 'bin'),
os.path.join(prefix, 'Library', 'usr', 'bin'),
os.path.join(prefix, 'Library', 'bin'),
os.path.join(prefix, 'Scripts'),
]
else:
paths = [
os.path.join(prefix, 'bin'),
]
# convert paths to shell-native paths
return [shelldict['path_to'](path) for path in paths]
def pathlist_to_str(paths, escape_backslashes=True):
"""
Format a path list, e.g., of bin paths to be added or removed,
for user-friendly output.
"""
path = ' and '.join(paths)
if on_win and escape_backslashes:
# escape for printing to console - ends up as single \
path = re.sub(r'(?<!\\)\\(?!\\)', r'\\\\', path)
else:
path = path.replace("\\\\", "\\")
return path
def get_path(shelldict):
"""Get path using a subprocess call.
os.getenv path isn't good for us, since bash on windows has a wildly different
path from Windows.
This returns PATH in the native representation of the shell - not necessarily
the native representation of the platform
"""
return run_in(shelldict["printpath"], shelldict)[0]
def main():
from conda.config import root_env_name, root_dir, changeps1
import conda.install
if '-h' in sys.argv or '--help' in sys.argv:
# all execution paths sys.exit at end.
help(sys.argv[1], sys.argv[2])
shell = sys.argv[2]
shelldict = shells[shell]
if sys.argv[1] == '..activate':
path = get_path(shelldict)
if len(sys.argv) == 3 or sys.argv[3].lower() == root_env_name.lower():
binpath = binpath_from_arg(root_env_name, shelldict=shelldict)
rootpath = None
elif len(sys.argv) == 4:
binpath = binpath_from_arg(sys.argv[3], shelldict=shelldict)
rootpath = binpath_from_arg(root_env_name, shelldict=shelldict)
else:
sys.exit("Error: did not expect more than one argument")
pathlist_str = pathlist_to_str(binpath)
sys.stderr.write("prepending %s to PATH\n" % shelldict['path_to'](pathlist_str))
# Clear the root path if it is present
if rootpath:
path = path.replace(shelldict['pathsep'].join(rootpath), "")
# prepend our new entries onto the existing path and make sure that the separator is native
path = shelldict['pathsep'].join(binpath + [path, ])
# deactivation is handled completely in shell scripts - it restores backups of env variables.
# It is done in shell scripts because they handle state much better than we can here.
elif sys.argv[1] == '..checkenv':
if len(sys.argv) < 4:
sys.argv.append(root_env_name)
if len(sys.argv) > 4:
sys.exit("Error: did not expect more than one argument.")
if sys.argv[3].lower() == root_env_name.lower():
# no need to check root env and try to install a symlink there
sys.exit(0)
# this should throw an error and exit if the env or path can't be found.
try:
prefix = prefix_from_arg(sys.argv[3], shelldict=shelldict)
except ValueError as e:
sys.exit(getattr(e, 'message', e))
# Make sure an env always has the conda symlink
try:
conda.install.symlink_conda(prefix, root_dir, shell)
except (IOError, OSError) as e:
if e.errno == errno.EPERM or e.errno == errno.EACCES:
msg = ("Cannot activate environment {0}, not have write access to conda symlink"
.format(sys.argv[2]))
sys.exit(msg)
raise
sys.exit(0)
elif sys.argv[1] == '..setps1':
# path is a bit of a misnomer here. It is the prompt setting. However, it is returned
# below by printing. That is why it is named "path"
# DO NOT use os.getenv for this. One Windows especially, it shows cmd.exe settings
# for bash shells. This method uses the shell directly.
path = os.getenv(shelldict['promptvar'], '')
# failsafes
if not path:
if shelldict['exe'] == 'cmd.exe':
path = '$P$G'
# strip off previous prefix, if any:
path = re.sub(".*\(\(.*\)\)\ ", "", path, count=1)
env_path = sys.argv[3]
if changeps1 and env_path:
path = "(({0})) {1}".format(os.path.split(env_path)[-1], path)
else:
# This means there is a bug in main.py
raise ValueError("unexpected command")
# This print is actually what sets the PATH or PROMPT variable. The shell
# script gets this value, and finishes the job.
print(path)
if __name__ == '__main__':
main()
#!/bin/bash
# Determine the directory containing this script
if [[ -n $BASH_VERSION ]]; then
_SCRIPT_LOCATION=${BASH_SOURCE[0]}
export PROMPT_VAR="PS1"
SHELL="bash"
elif [[ -n $ZSH_VERSION ]]; then
_SCRIPT_LOCATION=${funcstack[1]}
export PROMPT_VAR="PROMPT"
SHELL="zsh"
else
echo "Only bash and zsh are supported"
return 1
fi
_CONDA_DIR=$(dirname "$_SCRIPT_LOCATION")
case "$(uname -s)" in
CYGWIN*|MINGW32*|MSYS*)
EXT=".exe"
;;
*)
EXT=""
;;
esac
# shift over all args. We don't accept any, so it's OK that we ignore them all here.
while [[ $# > 0 ]]
do
key="$1"
case $key in
-h|--help)
"$_CONDA_DIR/conda" ..deactivate $SHELL$EXT -h
if [[ -n $BASH_VERSION ]] && [[ "$(basename "$0" 2> /dev/null)" == "deactivate" ]]; then
exit 0
else
return 0
fi
;;
esac
shift # past argument or value
done
# Ensure that this script is sourced, not executed
# Note that if the script was executed, we're running inside bash!
# Also note that errors are ignored as `activate foo` doesn't generate a bad
# value for $0 which would cause errors.
if [[ -n $BASH_VERSION ]] && [[ "$(basename "$0" 2> /dev/null)" == "deactivate" ]]; then
(>&2 echo "Error: deactivate must be sourced. Run 'source deactivate'
instead of 'deactivate'.
")
"$_CONDA_DIR/conda" ..deactivate -h $SHELL$EXT
exit 1
fi
if [[ -z "$CONDA_PATH_BACKUP" ]]; then
if [[ -n $BASH_VERSION ]] && [[ "$(basename "$0" 2> /dev/null)" == "deactivate" ]]; then
exit 0
else
return 0
fi
fi
if (( $? == 0 )); then
# Inverse of activation: run deactivate scripts prior to deactivating env
_CONDA_D="${CONDA_DEFAULT_ENV}/etc/conda/deactivate.d"
if [[ -d $_CONDA_D ]]; then
IFS=$(echo -en "\n\b") && for f in $(find "$_CONDA_D" -iname "*.sh"); do source "$f"; done
fi
unset CONDA_DEFAULT_ENV
unset CONDA_ENV_PATH
export PATH="$CONDA_PATH_BACKUP"
unset CONDA_PATH_BACKUP
export PS1="$CONDA_OLD_PS1"
unset CONDA_OLD_PS1
else
return $?
fi
if [[ -n $BASH_VERSION ]]; then
hash -r
elif [[ -n $ZSH_VERSION ]]; then
rehash
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment