#!/usr/bin/env bash # ------------------------------------------------------------------------------ # Description # "Modular" bash_profile. # - First executes every script in header/active to output a custom terminal # header or welcome screen. # - Then sources the configs in configs/ # * configs/active/: sources every file found recursively. # * configs/prompt/: prompts the user to source every file # found recursively. # # Usage # The directory structure must be as follows: # ├─ header # │ ├─ active # │ └─ inactive # ├─ configs # │ ├─ active # │ ├─ inactive # │ └─ prompt # └─ bash_profile # # Then make sure bash_profile is sourced at bash startup, for example by # setting a symbolic link this way: # ln -s /path/to/this/file $HOME/.bash_profile # # Dependencies # * Commands: awk, tput, read, source, test, readlink. # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Constants # ------------------------------------------------------------------------------ # Formatting constants export BOLD=`tput bold` export UNDERLINE_ON=`tput smul` export UNDERLINE_OFF=`tput rmul` export TEXT_BLACK=`tput setaf 0` export TEXT_RED=`tput setaf 1` export TEXT_GREEN=`tput setaf 2` export TEXT_YELLOW=`tput setaf 3` export TEXT_BLUE=`tput setaf 4` export TEXT_MAGENTA=`tput setaf 5` export TEXT_CYAN=`tput setaf 6` export TEXT_WHITE=`tput setaf 7` export BACKGROUND_BLACK=`tput setab 0` export BACKGROUND_RED=`tput setab 1` export BACKGROUND_GREEN=`tput setab 2` export BACKGROUND_YELLOW=`tput setab 3` export BACKGROUND_BLUE=`tput setab 4` export BACKGROUND_MAGENTA=`tput setab 5` export BACKGROUND_CYAN=`tput setab 6` export BACKGROUND_WHITE=`tput setab 7` export RESET_FORMATTING=`tput sgr0` # ------------------------------------------------------------------------------ # Functions # ------------------------------------------------------------------------------ # Print the header. bash-profile_print-header () { # Loop through files in the header folder for file in $BASH_PROFILE_LOCATION/header/active/*; do # If this is a file, execute it if [ -f "$file" ]; then "$file" fi done } # Ask the user a "yes/no" question. Defaults to "no". # # Arguments # 1 (optional) the question to ask. bash-profile_ask () { read -s -n1 -p "$@ [y/N] " ans case "$ans" in y*|Y*) return 0 ;; *) return 1 ;; esac } # Source the given file. # # Arguments # 1 (required) the file to source. # # Options # --ask Prompt the user before. # To be put before first argument. bash-profile_load-bash-config () { # Handle the --ask option if [ $1 = "--ask" ]; then shift ask=0 else ask=1 fi # Extract a readable name from the file name # Example: "/home/user/folder/010_Aliases and functions.sh" => "Aliases and functions" config_name=$(expr match "`echo $@`" '.*[/_]\([^\.]*\)') # Ask if needed if [ $ask -eq 0 ]; then if ! bash-profile_ask "Load $config_name ?"; then echo -e `tput rc; tput ed`$CONFIGS_LINE return 1 fi fi # Source the file source "`echo $@`" &> /tmp/bash_profile_config_out.log # Append the output to the report if needed if [ -s /tmp/bash_profile_config_out.log ]; then echo "${TEXT_BLUE}${BOLD}$config_name${RESET_FORMATTING}▸ " >> /tmp/bash_profile_configs_out (cat /tmp/bash_profile_config_out.log | sed -e "s/\(.*\)/\ \ \1/g"; echo) >> /tmp/bash_profile_configs_out fi # Update the configurations line if [ -z "${CONFIGS_LINE}" ]; then export CONFIGS_LINE="${TEXT_BLUE}${BOLD}Configs▸ ${RESET_FORMATTING} $config_name" else export CONFIGS_LINE=${CONFIGS_LINE}" ${TEXT_BLUE}|${RESET_FORMATTING} $config_name" fi # Print the line at the last saved position echo -e `tput rc; tput ed`$CONFIGS_LINE } # Source the files recursively in the given folder. # # Arguments # 1 (required) the folder to process. # # Options # --ask Prompt the user before loading each script. # To be put before first argument. bash-profile_load-folder-bash-configs () { # Handle the --ask option if [ $1 = "--ask" ]; then shift load_opts="--ask" else load_opts="" fi # Declare a boolean to determine the success of the operation success=true # Escape spaces in the folder name local folder=`echo $1 | sed -e "s/ /\\ /g"` # Check that a valid folder was given if [ -d "$folder" ]; then # Check the folder is not empty if [ `ls "$folder" | wc -l` -ne 0 ]; then # Loop through files in the folder # (Trick: replace spaces in filenames with '&' to enter the for loop) for file in `find $folder/* -xtype f | sort | sed -e "s/ /\\&/g"` do # Restore spaces file=`echo $file | sed -e "s/\\&/ /g"` # Try loading the config bash-profile_load-bash-config $load_opts $file done fi # If this is not a valid folder else echo "${TEXT_RED}${BOLD}'$1' is not a valid folder.${RESET_FORMATTING}" success=false fi # If something went wrong, exit if ! $success; then `exit 1` fi } # Load the configurations bash-profile_load-configs () { # Save the current cursor position tput sc # Source scripts in active/ bash-profile_load-folder-bash-configs "$BASH_PROFILE_LOCATION/configs/active" # Source scripts in prompt/ (ask first) bash-profile_load-folder-bash-configs --ask "$BASH_PROFILE_LOCATION/configs/prompt" } # Print the footer line. bash-profile_print-footer () { local _WINDOW_Y=`tput cols` local _FOOTER_LINE_CHARACTER="_" echo -e ${BOLD}`echo ""|awk ' { _SPACES = '${_WINDOW_Y}' while (_SPACES-- > 0) printf ("'${_FOOTER_LINE_CHARACTER}'") }'`${RESET_FORMATTING} } # Print the configurations output report. bash-profile_print-configs-output() { if [ -s /tmp/bash_profile_configs_out ]; then cat /tmp/bash_profile_configs_out | head --lines=-1 bash-profile_print-footer fi } # ------------------------------------------------------------------------------ # Main # ------------------------------------------------------------------------------ # Resolve the real location of this file export BASH_PROFILE_LOCATION="$(dirname "$(test -L "$BASH_SOURCE" && readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")" # Local variables declarations CONFIGS_LINE="" # Clear the terminal clear # Clean traces from a previous execution rm -f /tmp/bash_profile_configs_out # Print the header bash-profile_print-header # Load the configurations bash-profile_load-configs # Print the footer bash-profile_print-footer # Print the configurations output bash-profile_print-configs-output # Unset all variables and functions to ensure their visibility stay local unset CONFIGS_LINE unset -f bash-profile_print-header unset -f bash-profile_ask unset -f bash-profile_load-bash-config unset -f bash-profile_load-folder-bash-configs unset -f bash-profile_print-configs-line unset -f bash-profile_load-configs unset -f bash-profile_print-footer