-
Notifications
You must be signed in to change notification settings - Fork 2.3k
new plugin: safe_autoenv #2354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
new plugin: safe_autoenv #2354
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| # shellcheck shell=bash | ||
| # BASH_IT_LOAD_PRIORITY: 200 | ||
|
|
||
| # Autoenv Plugin for Bash-it with automatic cleanup | ||
| # Automatically loads .env files when changing directories | ||
| # Automatically unsets variables when leaving directories | ||
|
|
||
| cite about-plugin | ||
| about-plugin 'Automatically loads .env files and cleans up when leaving directories' | ||
|
|
||
| # Global tracking for autoenv state | ||
| declare -A _AUTOENV_PROCESSED_DIRS # Track processed directories | ||
| declare -A _AUTOENV_DIR_VARS # Map directories to their variables | ||
| declare -A _AUTOENV_VAR_SOURCES # Map variables to their source directories | ||
| declare _AUTOENV_LAST_PWD="" # Track last working directory | ||
|
|
||
| _autoenv_init() { | ||
| typeset target home _file current_dir | ||
| typeset -a _files | ||
| target=$1 | ||
| home="${HOME%/*}" | ||
|
|
||
| _files=($( | ||
| current_dir="$target" | ||
| while [[ "$current_dir" != "/" && "$current_dir" != "$home" ]]; do | ||
| _file="$current_dir/.env" | ||
| if [[ -e "${_file}" ]]; then | ||
| echo "${_file}" | ||
| fi | ||
| # Move to parent directory | ||
| current_dir="$(dirname "$current_dir")" | ||
| done | ||
| )) | ||
|
|
||
| # Process files in reverse order (from root to current directory) | ||
| local _file_count=${#_files[@]} | ||
| local i | ||
| for ((i = _file_count - 1; i >= 0; i--)); do | ||
| local env_file="${_files[i]}" | ||
| local env_dir="$(dirname "$env_file")" | ||
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show fixed
Hide fixed
|
||
|
|
||
| # Only process if this directory hasn't been processed yet | ||
| # OR if it was processed but its variables were cleaned up | ||
| if [[ -z "${_AUTOENV_PROCESSED_DIRS[$env_dir]}" ]] || [[ -z "${_AUTOENV_DIR_VARS[$env_dir]}" ]]; then | ||
| echo "Processing $env_file" | ||
| _autoenv_process_file "$env_file" "$env_dir" | ||
| _AUTOENV_PROCESSED_DIRS[$env_dir]=1 | ||
| fi | ||
| done | ||
| } | ||
|
|
||
| _autoenv_process_file() { | ||
| local env_file="$1" | ||
| local env_dir="$2" | ||
| local line key value original_line line_number=0 | ||
| local -a dir_vars=() | ||
|
|
||
| # Check if file is readable | ||
| if [[ ! -r "$env_file" ]]; then | ||
| echo "Warning: Cannot read $env_file" >&2 | ||
| return 1 | ||
| fi | ||
|
|
||
| # Read the file line by line | ||
| while IFS= read -r line || [[ -n "$line" ]]; do | ||
| ((line_number++)) | ||
| original_line="$line" | ||
|
|
||
| # Skip empty lines and comments | ||
| [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue | ||
|
|
||
| # Remove leading whitespace | ||
| line="${line#"${line%%[![:space:]]*}"}" | ||
|
|
||
| # Check if line matches KEY=value pattern | ||
| if [[ "$line" =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then | ||
| key="${BASH_REMATCH[1]}" | ||
| value="${BASH_REMATCH[2]}" | ||
|
|
||
| # Validate key name (additional safety check) | ||
| if [[ ! "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then | ||
| echo "Warning: Invalid variable name '$key' at line $line_number in $env_file" >&2 | ||
| continue | ||
| fi | ||
|
|
||
| # Handle quoted values (remove outer quotes if present) | ||
| if [[ "$value" =~ ^\"(.*)\"$ ]]; then | ||
| value="${BASH_REMATCH[1]}" | ||
| elif [[ "$value" =~ ^\'(.*)\'$ ]]; then | ||
| value="${BASH_REMATCH[1]}" | ||
| fi | ||
|
|
||
| # Export the variable silently | ||
| export "$key=$value" | ||
|
|
||
| # Track the variable | ||
| dir_vars+=("$key") | ||
| _AUTOENV_VAR_SOURCES["$key"]="$env_dir" | ||
|
|
||
| else | ||
| echo "Warning: Skipping invalid line $line_number in $env_file: $original_line" >&2 | ||
| fi | ||
| done < "$env_file" | ||
|
|
||
| # Store variables for this directory | ||
| if [[ ${#dir_vars[@]} -gt 0 ]]; then | ||
| _AUTOENV_DIR_VARS["$env_dir"]="${dir_vars[*]}" | ||
| fi | ||
| } | ||
|
|
||
| # Check if a directory is an ancestor of the current directory | ||
| _autoenv_is_ancestor() { | ||
| local ancestor="$1" | ||
| local current="$PWD" | ||
|
|
||
| # Normalize paths (remove trailing slashes) | ||
| ancestor="${ancestor%/}" | ||
| current="${current%/}" | ||
|
|
||
| # Check if current path starts with ancestor path | ||
| [[ "$current" == "$ancestor"* ]] | ||
| } | ||
|
|
||
| # Clean up variables from directories we've left | ||
| _autoenv_cleanup() { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer if the function were prefixed with something like |
||
| local dir var_list var | ||
|
|
||
| # Check each directory we've processed | ||
| for dir in "${!_AUTOENV_DIR_VARS[@]}"; do | ||
| # If this directory is no longer an ancestor of current directory | ||
| if ! _autoenv_is_ancestor "$dir"; then | ||
| var_list="${_AUTOENV_DIR_VARS[$dir]}" | ||
|
|
||
| # Unset each variable from this directory | ||
| for var in $var_list; do | ||
| if [[ "${_AUTOENV_VAR_SOURCES[$var]}" == "$dir" ]]; then | ||
| echo "Unsetting $var (from $dir)" | ||
| unset "$var" | ||
| unset "_AUTOENV_VAR_SOURCES[$var]" | ||
| fi | ||
| done | ||
|
|
||
| # Remove directory from tracking AND clear its processed status | ||
| unset "_AUTOENV_DIR_VARS[$dir]" | ||
| unset "_AUTOENV_PROCESSED_DIRS[$dir]" | ||
| fi | ||
| done | ||
| } | ||
|
|
||
| # Main prompt command function | ||
| _autoenv_prompt_command() { | ||
| local current_dir="$PWD" | ||
|
|
||
| # If directory changed, perform cleanup first | ||
| if [[ "$current_dir" != "$_AUTOENV_LAST_PWD" ]]; then | ||
| _autoenv_cleanup | ||
| _AUTOENV_LAST_PWD="$current_dir" | ||
| fi | ||
|
|
||
| # Always try to initialize the current directory and its ancestors | ||
| # The _autoenv_init function will handle checking if processing is needed | ||
| _autoenv_init "$current_dir" | ||
| } | ||
|
|
||
| # Public function for manual use | ||
| autoenv() { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like to keep |
||
| case "$1" in | ||
| "reload"|"refresh") | ||
| # Clear all tracking and reload | ||
| _autoenv_clear_all | ||
| _autoenv_init "$PWD" | ||
| ;; | ||
| "status") | ||
| echo "Processed directories:" | ||
| for dir in "${!_AUTOENV_PROCESSED_DIRS[@]}"; do | ||
| echo " $dir" | ||
| done | ||
| echo | ||
| echo "Active variables by directory:" | ||
| for dir in "${!_AUTOENV_DIR_VARS[@]}"; do | ||
| echo " $dir: ${_AUTOENV_DIR_VARS[$dir]}" | ||
| done | ||
| echo | ||
| echo "Variable sources:" | ||
| for var in "${!_AUTOENV_VAR_SOURCES[@]}"; do | ||
| echo " $var -> ${_AUTOENV_VAR_SOURCES[$var]}" | ||
| done | ||
| ;; | ||
| "clean"|"cleanup") | ||
| _autoenv_cleanup | ||
| ;; | ||
| "clear") | ||
| _autoenv_clear_all | ||
| ;; | ||
| *) | ||
| _autoenv_init "${1:-$PWD}" | ||
| ;; | ||
| esac | ||
| } | ||
|
|
||
| # Clear all autoenv state and unset tracked variables | ||
| _autoenv_clear_all() { | ||
| local var | ||
|
|
||
| # Unset all tracked variables | ||
| for var in "${!_AUTOENV_VAR_SOURCES[@]}"; do | ||
| echo "Clearing $var" | ||
| unset "$var" | ||
| done | ||
|
|
||
| # Clear all tracking arrays | ||
| unset _AUTOENV_PROCESSED_DIRS | ||
| unset _AUTOENV_DIR_VARS | ||
| unset _AUTOENV_VAR_SOURCES | ||
|
|
||
| # Reinitialize arrays | ||
| declare -A _AUTOENV_PROCESSED_DIRS | ||
| declare -A _AUTOENV_DIR_VARS | ||
| declare -A _AUTOENV_VAR_SOURCES | ||
|
|
||
| _AUTOENV_LAST_PWD="" | ||
| } | ||
|
|
||
| # Hook into bash-it's prompt command system | ||
| safe_append_prompt_command '_autoenv_prompt_command' | ||
Uh oh!
There was an error while loading. Please reload this page.