#!/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 constantsexport 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 configurationsbash-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 fileexport BASH_PROFILE_LOCATION="$(dirname "$(test -L "$BASH_SOURCE" && readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"# Local variables declarationsCONFIGS_LINE=""# Clear the terminalclear# Clean traces from a previous executionrm -f /tmp/bash_profile_configs_out# Print the headerbash-profile_print-header# Load the configurationsbash-profile_load-configs# Print the footerbash-profile_print-footer# Print the configurations outputbash-profile_print-configs-output# Unset all variables and functions to ensure their visibility stay localunset CONFIGS_LINEunset -f bash-profile_print-headerunset -f bash-profile_askunset -f bash-profile_load-bash-configunset -f bash-profile_load-folder-bash-configsunset -f bash-profile_print-configs-lineunset -f bash-profile_load-configsunset -f bash-profile_print-footer