#!/bin/bash python_path="" module_to_import="" skip_import=False pip_package="" function usage { retval="$1" case "$retval" in 0) ;; *) exec 1>&2 ;; esac echo "Usage: $0" echo " --python-path /where/python/lives/python" echo " --module-to-import module_name" echo " --skip-import" echo " --pip-package pip-package-name" echo echo "This program installs a package from pypi, but only if module_name" echo "is not yet importable (or --skip-import is specified)." echo echo "This cuts down on unnecessary sudoing." exit "$retval" } while [ "$#" -ge 1 ] do case "$1" in --python-path) python_path="$2" shift ;; --skip-import) skip_import=True ;; --module-to-import) module_to_import="$2" shift ;; --pip-package) pip_package="$2" shift ;; -h|--help) usage 0 ;; *) echo "$0: Unrecognized option: $1" 1>&2 usage 1 ;; esac shift done case "$python_path" in "") echo --python-path is a required option 1>&2 usage 1 ;; esac function count_trues { sum=0 for cmd in "$@" do if eval "$cmd" > /dev/null 2>&1 then sum=$((sum+1)) fi done echo "$sum" } all_good=True if [[ $(count_trues "[[ $module_to_import != '' ]]" "[[ $skip_import = True ]]") != 1 ]] then echo "$0: You must specify exactly one of --module-to-import and --skip-import" 1>&2 all_good=False fi case "$pip_package" in "") echo --pip-package is a required option 1>&2 all_good=False ;; esac case "$all_good" in True) ;; False) echo "$0: One or more items in preflight check failed" 1>&2 usage 1 ;; *) echo "$0: internal error: \$all_good is neither True nor False: $all_good" 1>&2 ;; esac function import_test { "$python_path" -c "import $module_to_import" > /dev/null 2>&1 } function pip_test { "$python_path" -m pip list | grep -q "^$pip_package\$" > /dev/null 2>&1 } if import_test || pip_test then : else "$python_path" -m pip install --break-system-packages "$pip_package" \ || sudo "$python_path" -m pip install --break-system-packages "$pip_package" \ || "$python_path" -m pip install "$pip_package" \ || sudo "$python_path" -m pip install "$pip_package" fi