#!/bin/bash # use as hashbang: # #!/usr/bin/env -S useve-runner [venv-name] export VENV_HOME=$HOME/.local/share/venvs/ function useve() { local USEVE_HELP='Wrapper to python3 venv, subcommands: - setup install global environment - [env] enters the env if exists - ls [-v] list envs - mk [env] [[pkgs../requirements.txt]] create virtualenv and install packages - rm [env] remove virtualenv - cd [env] to virtualenv - w [env] enter (same as [env] - add [env] [pkg/requirements.txt] add package(s) and add to requirements.txt - req [env] list the requirements.txt file - up [env] upgrade packages listed in requirements.txt - reinstall [env] reinstall env using requirements.txt - freeze [env] make a list of installed packages in freeze.txt Additional command: useve-runner [env] python_script.py or as hashbang: #!/usr/bin/env -S useve-runner [env] ' [[ -z "$1" ]] && { echo -e "$USEVE_HELP" if which smenu &>/dev/null; then local VE_CHOICE=$( ls "$VENV_HOME" \ | sort \ | smenu -t 1 -a c:2,bu i:8,b -n 25 -m "Virtual envs" -W $'\n' ) if [[ -z $VE_CHOICE ]]; then return 0 fi useve "$VE_CHOICE" else useve ls fi return } local CMD="$1" shift 1 case $CMD in -h|help) echo "$USEVE_HELP" ;; mk) if [[ -z "$1" ]]; then echo "Virtual env name required" return 1 fi if [[ -e "$VENV_HOME"/"$1" ]]; then echo "Virtual env already exists" useve ls -v "$1" return 1 fi # for p3.10.x python3 -m venv --copies --upgrade-deps "$VENV_HOME"/"$1" python3 -m venv --copies "$VENV_HOME"/"$1" . "$VENV_HOME"/"$1"/bin/activate pip install -U pip if [[ -n "$2" ]]; then useve add "$@" fi ;; rm) if [[ -z "$1" ]]; then echo "Virtual env name required" return 1 fi if [[ ! -e "$VENV_HOME"/"$1" ]]; then echo "No such virtual env '$1'" return 1 fi du -sh "$VENV_HOME"/"$1" if [[ -e "$VENV_HOME"/"$1"/freeze.txt ]]; then cp -v "$VENV_HOME"/"$1"/freeze.txt "$VENV_HOME"/.backups/"$1"-freeze.txt fi if [[ -e "$VENV_HOME"/"$1"/requirements.txt ]]; then cp -v "$VENV_HOME"/"$1"/requirements.txt "$VENV_HOME"/.backups/"$1"-requirements.txt fi find "$VENV_HOME"/"$1" > "$VENV_HOME"/.backups/"$1"-filelist.txt rm -r "$VENV_HOME"/"$1" ;; ls) local n local bn if [[ "$1" = "-v" ]]; then printf '# Virtual envs\n\n' for n in "$VENV_HOME"/*/; do bn=$( basename "$n" ) printf "\e[1;32m%15s \e[0m%4s %s %s\n" \ "$bn" \ "$( du -sh "$n" | awk '{ print $1}' )" \ "$( date -I -r "$n" )" \ "$( "$n"/bin/python -V ) " done else for n in "$VENV_HOME"/*/; do bn=$( basename "$n" ) echo "$bn" done fi return 0 ;; cd) if [[ -z "$1" ]]; then cd "$VENV_HOME" return fi cd "$VENV_HOME"/"$1" ;; w) . "$VENV_HOME"/"$1"/bin/activate ;; setup) mkdir -p "$VENV_HOME" mkdir -p "$VENV_HOME"/.backups alias p=python3 ;; add) if [[ -z "$1" ]]; then return; fi local ALREADY_ACTIVE=0 if [[ $( readlink -f "$VIRTUAL_ENV" ) = $( readlink -f "$VENV_HOME"/"$1" ) ]]; then ALREADY_ACTIVE=1 fi . "$VENV_HOME"/"$1"/bin/activate || return local VENV_ENV VENV_ENV="$1" shift 1 local VENV_PKG for VENV_PKG in "$@"; do if [[ -f "$VENV_PKG" ]]; then pip install -r "$VENV_PKG" && { cat "$VENV_PKG" >> "$VENV_HOME/$VENV_ENV/requirements.txt"; } || return else pip install "$VENV_PKG" && { echo "$VENV_PKG" >> "$VENV_HOME/$VENV_ENV/requirements.txt"; } || return fi done pip freeze > "$VENV_HOME/$VENV_ENV/freeze.txt" if [[ "$ALREADY_ACTIVE" -eq 0 ]]; then deactivate fi echo Current "$VENV_HOME/$VENV_ENV/requirements.txt" cat "$VENV_HOME/$VENV_ENV/requirements.txt" ;; up) if [[ -z "$1" ]]; then return; fi local ALREADY_ACTIVE=0 if [[ $( readlink -f "$VIRTUAL_ENV" ) = $( readlink -f "$VENV_HOME"/"$1" ) ]]; then ALREADY_ACTIVE=1 fi . "$VENV_HOME"/"$1"/bin/activate || return local pkg while read pkg; do if [[ "$pkg" = "#"* ]]; then continue; fi if [[ -z $pkg ]]; then continue; fi pip install --upgrade --upgrade-strategy eager "$pkg" done < "$VENV_HOME/$1/requirements.txt" pip freeze > "$VENV_HOME/$1/freeze.txt" if [[ "$ALREADY_ACTIVE" -eq 0 ]]; then deactivate fi echo Current "$VENV_HOME/$1/requirements.txt" cat "$VENV_HOME/$1/requirements.txt" ;; freeze) if [[ -z "$1" ]]; then return; fi . "$VENV_HOME"/"$1"/bin/activate || return pip freeze > "$VENV_HOME/$1/freeze.txt" cat "$VENV_HOME/$1/freeze.txt" deactivate ;; req) if [[ -z "$1" ]]; then return; fi if [[ -e "$VENV_HOME/$1/requirements.txt" ]]; then echo "# $VENV_HOME/$1/requirements.txt:" cat "$VENV_HOME/$1/requirements.txt" else echo '# No requirements file.' return 1 fi ;; reinstall) if [[ -z "$1" ]]; then return; fi if [[ ! -e "$VENV_HOME/$1/requirements.txt" ]]; then echo No requirements to base reinstall on. return 1 fi mkdir -p "$VENV_HOME/.reinstalls/" cp -v "$VENV_HOME/$1/requirements.txt" "$VENV_HOME/.reinstalls/$1-requirements.txt" useve rm "$1" useve mk "$1" cp -v "$VENV_HOME/.reinstalls/$1-requirements.txt" "$VENV_HOME/$1/requirements.txt" useve up "$1" ;; exists) if [[ -z "$1" ]]; then return 1; fi test -d "$VENV_HOME"/"$1" return $? ;; *) if [[ -d "$VENV_HOME"/"$CMD" ]]; then . "$VENV_HOME"/"$CMD"/bin/activate else echo No such environment, or recognized command echo Environments: useve ls echo -e "\n$USEVE_HELP" return 1 fi ;; esac } function localve () { [[ -z "$1" ]] && { local envs=( $( find . -maxdepth 3 -mindepth 2 -type f -wholename '*/bin/activate' -printf "%P\n" | sed 's,/bin/activate,,' ) ) if [[ ${#envs[@]} -eq 1 ]]; then localve ${envs[0]} return $? fi } [[ -z "$1" ]] && { { LOCAL_ENVS=( $( ) ) echo -e '# Virtual envs\n' find . -maxdepth 3 -mindepth 2 -type f -wholename '*/bin/activate' -printf "* %P\n" | sed 's,/bin/activate,,' } | HB_RULES='"\\*.*" "$G" "#.*" "$W"' highbeam return 0 } test -f "$1"/bin/activate || { echo "No such environment '$1', create and enter? y/n" | HB_RULES='"^.*" "$R"' highbeam local VE_ANSWER read -n 1 VE_ANSWER [[ "$VE_ANSWER" = "y" ]] && { python3 -m venv --copies --upgrade-deps "$1" } } source "$1"/bin/activate && { [[ $- == *i* ]] && { # Interactive echo -e "\nEntered [[ $1 ]]\n" | HB_RULES='"^.*" "$G"' highbeam echo "End with: deactivate" } || { true; } } } if ! (return 0 2>/dev/null); then # we are being executed set -e if [[ -z "$1" ]]; then echo Virtualenv name missing echo "Source this script to enable useve() function" exit 1 fi if [[ ! -f "$VENV_HOME/$1/bin/activate" ]]; then echo No such Virtualenv: "$1" exit 1 fi source "$VENV_HOME/$1/bin/activate" shift 1 if [ -t 0 ]; then exec python "$@" else cat - | python "$@" fi else useve setup fi