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

Adding pre/post hooks #202

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,67 @@ By default `mkvenv` will install setup.py via pip in `editable (i.e. development
<https://pip.pypa.io/en/stable/cli/pip_install/#editable-installs>`__.
To change this set ``AUTOSWITCH_PIPINSTALL`` to ``FULL``.

**Set pre and post hooks to run before and after virtual environment activation**

Autoswitch Virtualenv allows you to define custom actions to be executed
before and after a virtual environment is activated. This feature is useful
for running setup scripts, updating environment variables, or performing any
other tasks that should occur around the activation process.

Usage:

To set pre and post hooks, use the `autoswitch_add_pre_hook` and
`autoswitch_add_post_hook` functions. These functions accept a string containing
the commands you want to execute.

::

autoswitch_add_pre_hook '
echo "Starting pre-hook"
for i in {1..3}; do
echo "Pre-hook step $i"
done
'

autoswitch_add_post_hook '
echo "Starting post-hook"
for i in {1..3}; do
echo "Post-hook step $i"
done
'

In the example above:
- The pre-hook will run before the virtual environment is activated.
- The post-hook will run after the virtual environment has been successfully activated.

You can add multiple pre and post hooks. They will be executed in the order they were added.

Additional Information:

1. Hooks are executed in a subshell, so they cannot modify the parent shell's environment directly.
2. If you need to modify environment variables or perform actions that affect the current shell,
consider using the `eval` command within your hook.
3. Hooks should be added after the Autoswitch Virtualenv plugin is loaded in your Zsh configuration.
4. Pre-hooks run regardless of whether the activation is successful, while post-hooks only run if
the activation succeeds.
5. Be cautious with the commands you include in hooks, especially if they modify the system or
project state.

Example of a more practical post-hook:

::

autoswitch_add_post_hook '
if [ -n "$VIRTUAL_ENV" ]; then
echo "Activated virtualenv: $VIRTUAL_ENV"
pip list
fi
'

This post-hook will display the path of the activated virtual environment and list all installed packages whenever a virtualenv is activated.

Remember to test your hooks thoroughly to ensure they don't introduce unexpected behavior in your development workflow.

Security Warnings
-----------------

Expand Down
102 changes: 94 additions & 8 deletions autoswitch_virtualenv.plugin.zsh
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
export AUTOSWITCH_VERSION="3.7.1"
export AUTOSWITCH_FILE=".venv"

# Arrays to store hook functions
typeset -a AUTOSWITCH_PRE_HOOKS_ON_ACTIVATE
typeset -a AUTOSWITCH_POST_HOOKS_ON_ACTIVATE
typeset -a AUTOSWITCH_PRE_HOOKS_ON_DEACTIVATE
typeset -a AUTOSWITCH_POST_HOOKS_ON_DEACTIVATE


AUTOSWITCH_RED="\e[31m"
AUTOSWITCH_GREEN="\e[32m"
AUTOSWITCH_PURPLE="\e[35m"
Expand All @@ -9,6 +16,66 @@ AUTOSWITCH_NORMAL="\e[0m"

VIRTUAL_ENV_DIR="${AUTOSWITCH_VIRTUAL_ENV_DIR:-$HOME/.virtualenvs}"

# Function to add pre-hook for activation
autoswitch_add_pre_hook_on_activate() {
local hook_name="AUTOSWITCH_PRE_HOOK_ON_ACTIVATE_${#AUTOSWITCH_PRE_HOOKS_ON_ACTIVATE[@]}"
eval "$hook_name() { $@ }"
AUTOSWITCH_PRE_HOOKS_ON_ACTIVATE+=("$hook_name")
}

# Function to add post-hook for activation
autoswitch_add_post_hook_on_activate() {
local hook_name="AUTOSWITCH_POST_HOOK_ON_ACTIVATE_${#AUTOSWITCH_POST_HOOKS_ON_ACTIVATE[@]}"
eval "$hook_name() { $@ }"
AUTOSWITCH_POST_HOOKS_ON_ACTIVATE+=("$hook_name")
}

# Function to add pre-hook for deactivation
autoswitch_add_pre_hook_on_deactivate() {
local hook_name="AUTOSWITCH_PRE_HOOK_ON_DEACTIVATE_${#AUTOSWITCH_PRE_HOOKS_ON_DEACTIVATE[@]}"
eval "$hook_name() { $@ }"
AUTOSWITCH_PRE_HOOKS_ON_DEACTIVATE+=("$hook_name")
}

# Function to add post-hook for deactivation
autoswitch_add_post_hook_on_deactivate() {
local hook_name="AUTOSWITCH_POST_HOOK_ON_DEACTIVATE_${#AUTOSWITCH_POST_HOOKS_ON_DEACTIVATE[@]}"
eval "$hook_name() { $@ }"
AUTOSWITCH_POST_HOOKS_ON_DEACTIVATE+=("$hook_name")
}

# Function to execute pre-hooks on activation
_execute_pre_hooks_on_activate() {
local hook
for hook in "${AUTOSWITCH_PRE_HOOKS_ON_ACTIVATE[@]}"; do
$hook
done
}

# Function to execute post-hooks on activation
_execute_post_hooks_on_activate() {
local hook
for hook in "${AUTOSWITCH_POST_HOOKS_ON_ACTIVATE[@]}"; do
$hook
done
}

# Function to execute pre-hooks on deactivation
_execute_pre_hooks_on_deactivate() {
local hook
for hook in "${AUTOSWITCH_PRE_HOOKS_ON_DEACTIVATE[@]}"; do
$hook
done
}

# Function to execute post-hooks on deactivation
_execute_post_hooks_on_deactivate() {
local hook
for hook in "${AUTOSWITCH_POST_HOOKS_ON_DEACTIVATE[@]}"; do
$hook
done
}

function _validated_source() {
local target_path="$1"

Expand Down Expand Up @@ -190,22 +257,36 @@ function check_venv()
printf "Run the following command to fix this: ${AUTOSWITCH_PURPLE}\"chmod 600 $venv_path\"${AUTOSWITCH_NORMAL}\n"
else
if [[ "$venv_path" == *"/Pipfile" ]]; then
if type "pipenv" > /dev/null && _activate_pipenv; then
return
if type "pipenv" > /dev/null; then
_execute_pre_hooks_on_activate
if _activate_pipenv; then
_execute_post_hooks_on_activate
return
fi
fi
elif [[ "$venv_path" == *"/poetry.lock" ]]; then
if type "poetry" > /dev/null && _activate_poetry; then
return
if type "poetry" > /dev/null; then
_execute_pre_hooks_on_activate
if _activate_poetry; then
_execute_post_hooks_on_activate
return
fi
fi
# standard use case: $venv_path is a file containing a virtualenv name
elif [[ -f "$venv_path" ]]; then
local switch_to="$(<"$venv_path")"
_maybeworkon "$(_virtual_env_dir "$switch_to")" "virtualenv"
return
_execute_pre_hooks_on_activate
if _maybeworkon "$(_virtual_env_dir "$switch_to")" "virtualenv"; then
_execute_post_hooks_on_activate
return
fi
# $venv_path actually is itself a virtualenv
elif [[ -d "$venv_path" ]] && [[ -f "$venv_path/bin/activate" ]]; then
_maybeworkon "$venv_path" "virtualenv"
return
_execute_pre_hooks_on_activate
if _maybeworkon "$venv_path" "virtualenv"; then
_execute_post_hooks_on_activate
return
fi
fi
fi
fi
Expand All @@ -217,6 +298,7 @@ function check_venv()
printf "Python ${AUTOSWITCH_PURPLE}$venv_type${AUTOSWITCH_NORMAL} project detected. "
printf "Run ${AUTOSWITCH_PURPLE}mkvenv${AUTOSWITCH_NORMAL} to setup autoswitching\n"
fi

_default_venv
}

Expand All @@ -230,7 +312,11 @@ function _default_venv()
elif [[ -n "$VIRTUAL_ENV" ]]; then
local venv_name="$(_get_venv_name "$VIRTUAL_ENV" "$venv_type")"
_autoswitch_message "Deactivating: ${AUTOSWITCH_BOLD}${AUTOSWITCH_PURPLE}%s${AUTOSWITCH_NORMAL}\n" "$venv_name"

# Execute deactivation hooks
_execute_pre_hooks_on_deactivate
deactivate
_execute_post_hooks_on_deactivate
fi
}

Expand Down