#!/usr/bin/env bash ############# # Variables # ############# # Define formatting variables fb="$(tput bold)" fr="$(tput sgr0)" name_regex='[^a-zA-Z0-9]' # Define name regular expression # Set virtual environments directory ves_dir="" # Set projects directory projs_dir="" # Create required modules array req_mods=('pip' 'venv') # Create required variables array required_vars=( 'projs_dir' 'ves_dir' ) ############# # Functions # ############# display_usage() { local help_msg # Define local variable help_msg="Usage: . '${0}' Purpose: Create a new Python virtual environment. Requires: pip3 pip is the package installer for Python. python3-venv (Debian) This package contains the venv module for the Python language (default python3 version). Variables to set: projs_dir Directory of projects. ves_dir Directory to create virtual environment in." echo "${help_msg}" } # Parse arguments parse_args() { local parsed_args inv_ents parsed_args="$(getopt \ -n "${0##*/}" \ -o h \ --long help \ -- "${@}")" # Check for invalid entries inv_ents="${?}" ; readonly inv_ents if [[ "${inv_ents}" -ne 0 ]]; then echo '' display_usage exit 1 fi # Set positional parameters using parsed argument string eval set -- "${parsed_args}" # Evaluate options while true; do case "${1}" in '-h' | '--help') display_usage exit 0 ;; '--') ## End of options shift break ;; esac done } # Run initialization checks run_init_cks() { local err_msg mis_mods req_mod # Verify script was loaded via . command if ! [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then echo -e "\nRerun script using the ${fb}.${fr} command." 1>&2 && exit 1 fi # Create missing modules array declare -a mis_mods # Verify that required modules are installed for req_mod in "${req_mods[@]}"; do if ! python3 -c "import ${req_mod}" > '/dev/null' 2>&1; then mis_mods+=("${req_mod}") fi done # Display error message if modules are missing if [[ "${mis_mods[*]}" ]]; then err_msg='\nInstall the following Python module(s) before ' err_msg+='running the script again:' echo -e "${err_msg}\n${fb}${mis_mods[*]}${fr}" 1>&2 fi } # Sanitize name clean_name() { local cleaned # Replace most non-alphanumeric characters with underscores cleaned="${1//${name_regex}/_}" # Squeeze underscores and lowercase name cleaned="$(echo -n "${cleaned}" | tr -s '_' | tr '[:upper:]' '[:lower:]')" echo "${cleaned}" } # Display projects menu proj_menu() { PS3='Select a project: ' select proj in "${projs[@]}"; do if ! [[ "${proj}" ]]; then echo -e '\nPlease enter a valid menu selection.\n' 1>&2 proj_menu break elif [[ "${proj}" == 'Quit' ]]; then break else cd "${projs_dir}/${proj}" || exit 1 break fi done } # Define starting point for execution of the program main() { parse_args "${@}" run_init_cks # Create unset variables array declare -a unset_vars # Verify that required variables are set for required_var in "${required_vars[@]}"; do if ! [[ "${!required_var}" ]]; then unset_vars+=("${required_var}") fi done # Display error message if variables are not set if [[ "${unset_vars[*]}" ]]; then err_msg='\nSet the following variable(s) before ' err_msg+='running the script again:' echo -e "${err_msg}\n${fb}${unset_vars[*]}${fr}" 1>&2 else # Capture virtual environment name echo '' read -p 'Enter virtual environment name: ' -r ve_name ve_name="$(clean_name "${ve_name}")" # Sanitize input # Set virtual environment directory path ve_dir="${ves_dir}/${ve_name}" # If specified directory does not already exist if ! [[ -d "${ve_dir}" ]]; then # Create virtual environment, upgrade its version of pip and setuptools python3 -m venv --upgrade-deps "${ve_dir}" # Activate virtual environment and install wheel . "${ve_dir}/bin/activate" && python3 -m pip install wheel msg="\nSuccessfully created ${fb}${ve_dir}${fr} " msg+="virtual environment." echo -e "${msg}\n" # Declare projects indexed array declare -a projs # Define projects array mapfile -t projs < \ <(find "${projs_dir}" -mindepth 1 -maxdepth 1 -type d -printf '%f\n') projs+=('Quit') # Add quit option to projects array proj_menu # Display projects menu else echo -e "\n${fb}${ve_dir}${fr} already exists." fi fi } ########### # Program # ########### main "${@}" # Start program