Skip to content

Instantly share code, notes, and snippets.

@maxwellb
Last active August 29, 2019 18:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxwellb/002d06664b522798c2352fe395af397d to your computer and use it in GitHub Desktop.
Save maxwellb/002d06664b522798c2352fe395af397d to your computer and use it in GitHub Desktop.
Universal Python venv wrapper
$ ln -s /opt/work/my-env/../../../usr/local/bin/within-venv.sh /opt/within-my-venv && ln -s /opt/within-my-venv /usr/local/bin/mytool
$ mytool     # runs in /opt/work/my-venv

Usage

  1. Create a virtual env in a directory. Example: python3 -m venv /opt/work/my-venv
  2. Create a symbolic link to this script on your PATH, in a special way:
  • The source of the link must be this script, as a relative path to the virtual environment to run within.
  • The name of the link should be an executable file within the bin/ directory of the virtual environment. Example: ln -s /opt/work/my-env/../../../usr/local/bin/within-venv.sh /usr/local/bin/mytool
  • Alternatively, create a "wrapper link" from the relative path to this script from the virtual environment. Then, create a link named after your target executable to this link. Example: ln -s /opt/work/my-env/../../../usr/local/bin/within-venv.sh /opt/within-my-venv && ln -s /opt/within-my-venv /usr/local/bin/mytool

What's Happening

You are running this script. The script then runs mytool (or your link name) after adding your virtual environment's bin/ directory to the PATH. It determines the correct PATH by inspecting the special way you created the link.

#!/bin/bash
# Copyright Maxwell Bloch 2019
# Licensed GPL version 2 or later
unwind() {
path=${1}
path=$(dirname ${path})
while [ "$(basename ${path})" != ".." ]; do
path=$(dirname ${path})
done
while [ "$(basename ${path})" = ".." ]; do
path=$(dirname ${path})
done
echo ${path}
}
if [ -L ${0} -a -f ${0} ]; then
script="$(basename ${0})"
wrapper=${0}
dirname=$(readlink -f $(dirname ${wrapper}))
while [ -L ${wrapper} ]; do
wrapper=$(readlink ${wrapper})
if [ "$(echo ${wrapper} | cut -c1)" != "/" ]; then
wrapper="${dirname}/${wrapper}"
fi
done
path="$(unwind ${wrapper})"
fi
if [ -x ${path}/bin/${script} ]; then
PATH="${path}/bin:$PATH" ${path}/bin/${script} "$@"
else
echo "Script or program '${script}' not found in path ${path}/bin"
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment