From 048675577139de95cc16682b6cf4b5eb5a8a098d Mon Sep 17 00:00:00 2001 From: Aditya Gupta Date: Wed, 24 Jun 2026 19:57:38 +0530 Subject: [PATCH] refactor: use drop-ins for aliases and path management --- bootstrap.sh | 6 +++- installers/install_agy.sh | 17 +++--------- installers/install_bat.sh | 29 +++++-------------- installers/install_node.sh | 15 ++++------ installers/install_nvim.sh | 31 +++++++++++---------- installers/install_pnpm.sh | 14 ++++------ installers/install_rust.sh | 14 +++------- installers/install_starship.sh | 24 ++++++---------- installers/install_uv.sh | 22 ++++----------- installers/install_yazi.sh | 15 ++++------ installers/install_zoxide.sh | 15 ++++------ lib/shell_config.sh | 51 +++++++++++++++++++++++++++++++++- 12 files changed, 121 insertions(+), 132 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index 1ce7dd4..ede2687 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -67,6 +67,8 @@ install_bootstrap() { local routes_dir="$HOME/.config/bootstrap" mkdir -p "$routes_dir" + mkdir -p "$routes_dir/env.d" + mkdir -p "$routes_dir/aliases.d" # List of all files to download/copy local files=( @@ -126,13 +128,15 @@ install_bootstrap() { # 2. Clean up old loader block if it exists remove_block "$config_file" "bootstrap-cli setup" - # 3. Append the new lightweight loader block + # 3. Append the new lightweight loader block that sources modular configs log_info "Adding bootstrap loader to $config_file..." cat << 'EOF' >> "$config_file" # >>> bootstrap-cli setup >>> export BOOTSTRAP_DIR="$HOME/.config/bootstrap" [ -f "$BOOTSTRAP_DIR/b.sh" ] && . "$BOOTSTRAP_DIR/b.sh" +for f in "$BOOTSTRAP_DIR/env.d/"*.sh; do [ -r "$f" ] && . "$f"; done +for f in "$BOOTSTRAP_DIR/aliases.d/"*.sh; do [ -r "$f" ] && . "$f"; done # <<< bootstrap-cli setup <<< EOF diff --git a/installers/install_agy.sh b/installers/install_agy.sh index b505b3d..b880768 100644 --- a/installers/install_agy.sh +++ b/installers/install_agy.sh @@ -135,22 +135,13 @@ install_agy() { } configure_shell() { - # Ensure $TARGET_DIR is in PATH for shell configurations if not present + # Clean up legacy in-place configuration blocks IFS=' ' read -ra target_files <<< "$(get_shell_configs)" - - local path_content='export PATH="$HOME/.local/bin:$PATH"' - for config_file in "${target_files[@]}"; do - if [ -f "$config_file" ] && ! grep -q '\.local/bin' "$config_file" 2>/dev/null; then - log_info "Adding ~/.local/bin to PATH in $config_file..." - inject_block "$config_file" "local-bin path" "$path_content" - - # Source if modified (only for bashrc) - if [ "$config_file" = "$HOME/.bashrc" ]; then - . "$config_file" 2>/dev/null || true - fi - fi + remove_block "$config_file" "local-bin path" done + + write_env_snippet "local-bin" 'export PATH="$HOME/.local/bin:$PATH"' } run_handoff() { diff --git a/installers/install_bat.sh b/installers/install_bat.sh index 51458f3..5d65076 100644 --- a/installers/install_bat.sh +++ b/installers/install_bat.sh @@ -75,31 +75,16 @@ install_bat() { } configure_shell() { + # Clean up legacy in-place configuration blocks IFS=' ' read -ra target_files <<< "$(get_shell_configs)" - - local content="alias cat='bat --paging=never -p'" - for config_file in "${target_files[@]}"; do - local target_file="$config_file" - if [ "$config_file" = "$HOME/.bashrc" ]; then - # Clean up old block from ~/.bashrc if present to avoid duplication - remove_block "$config_file" "bat alias" - target_file="$HOME/.bash_aliases" - # Ensure the file exists - if [ ! -f "$target_file" ]; then - touch "$target_file" - fi - fi - - log_info "Adding bat alias to $target_file..." - inject_block "$target_file" "bat alias" "$content" - - # Source if modified (only for bashrc) - if [ "$config_file" = "$HOME/.bashrc" ]; then - log_info "Sourcing $config_file..." - . "$config_file" 2>/dev/null || true - fi + remove_block "$config_file" "bat alias" done + if [ -f "$HOME/.bash_aliases" ]; then + remove_block "$HOME/.bash_aliases" "bat alias" + fi + + write_alias_snippet "bat" "alias cat='bat --paging=never -p'" } main() { diff --git a/installers/install_node.sh b/installers/install_node.sh index 7c029c5..c3f1883 100644 --- a/installers/install_node.sh +++ b/installers/install_node.sh @@ -56,7 +56,11 @@ install_nvm() { } configure_shell() { + # Clean up legacy in-place configuration blocks IFS=' ' read -ra target_files <<< "$(get_shell_configs)" + for config_file in "${target_files[@]}"; do + remove_block "$config_file" "nvm setup" + done local content content=$(cat << 'EOF' @@ -66,16 +70,7 @@ export NVM_DIR="$HOME/.nvm" EOF ) - for config_file in "${target_files[@]}"; do - log_info "Adding NVM configuration block to $config_file..." - inject_block "$config_file" "nvm setup" "$content" - - # Source if modified (only for bashrc) - if [ "$config_file" = "$HOME/.bashrc" ]; then - log_info "Sourcing $config_file..." - . "$config_file" 2>/dev/null || true - fi - done + write_env_snippet "node" "$content" } install_node() { diff --git a/installers/install_nvim.sh b/installers/install_nvim.sh index d754356..abbc3c7 100644 --- a/installers/install_nvim.sh +++ b/installers/install_nvim.sh @@ -106,24 +106,27 @@ install_config() { } configure_shell() { + # Clean up legacy inline edits from bashrc and bash_aliases IFS=' ' read -ra target_files <<< "$(get_shell_configs)" - for config_file in "${target_files[@]}"; do - local modified=false - - if add_alias_if_missing "$config_file" "vim" "nvim"; then - modified=true - fi - - if add_env_if_missing "$config_file" "EDITOR" "nvim"; then - modified=true - fi - - # Source if modified (only for bashrc, and not when sourced to prevent recursion) - if [ "$modified" = true ] && [ "$config_file" = "$HOME/.bashrc" ]; then - . "$config_file" 2>/dev/null || true + if [ -f "$config_file" ]; then + local tmp_file + tmp_file=$(mktemp) + sed '/^export EDITOR="nvim"/d' "$config_file" > "$tmp_file" + cat "$tmp_file" > "$config_file" + rm -f "$tmp_file" fi done + if [ -f "$HOME/.bash_aliases" ]; then + local tmp_file + tmp_file=$(mktemp) + sed '/^alias vim="nvim"/d' "$HOME/.bash_aliases" > "$tmp_file" + cat "$tmp_file" > "$HOME/.bash_aliases" + rm -f "$tmp_file" + fi + + write_alias_snippet "nvim" 'alias vim="nvim"' + write_env_snippet "nvim" 'export EDITOR="nvim"' } main() { diff --git a/installers/install_pnpm.sh b/installers/install_pnpm.sh index e7ec949..9c2ebbf 100644 --- a/installers/install_pnpm.sh +++ b/installers/install_pnpm.sh @@ -179,7 +179,11 @@ install_pnpm() { # ─── Shell Configuration ───────────────────────────────────────────── configure_shell() { + # Clean up legacy in-place configuration blocks IFS=' ' read -ra target_files <<< "$(get_shell_configs)" + for config_file in "${target_files[@]}"; do + remove_block "$config_file" "pnpm setup" + done # pnpm's `setup --force` configures PNPM_HOME and PATH automatically, # but we also add an env block to ensure PNPM_HOME is set consistently. @@ -194,15 +198,7 @@ esac EOF ) - for config_file in "${target_files[@]}"; do - log_info "Configuring pnpm in $config_file..." - inject_block "$config_file" "pnpm setup" "$content" - - # Source if modified (only for bashrc) - if [ "$config_file" = "$HOME/.bashrc" ]; then - . "$config_file" 2>/dev/null || true - fi - done + write_env_snippet "pnpm" "$content" } # ─── Main ───────────────────────────────────────────────────────────── diff --git a/installers/install_rust.sh b/installers/install_rust.sh index 44a3665..dac02bd 100644 --- a/installers/install_rust.sh +++ b/installers/install_rust.sh @@ -91,19 +91,13 @@ configure_shell() { # Add ~/.cargo/bin to PATH for the current process export PATH="$HOME/.cargo/bin:$PATH" + # Clean up legacy in-place configuration blocks IFS=' ' read -ra target_files <<< "$(get_shell_configs)" - for config_file in "${target_files[@]}"; do - log_info "Configuring Rust environment in $config_file..." - local content='. "$HOME/.cargo/env"' - - inject_block "$config_file" "rust init" "$content" - - # Source if modified (only for bashrc) - if [ "$config_file" = "$HOME/.bashrc" ]; then - . "$config_file" 2>/dev/null || true - fi + remove_block "$config_file" "rust init" done + + write_env_snippet "rust" '. "$HOME/.cargo/env"' } main() { diff --git a/installers/install_starship.sh b/installers/install_starship.sh index fecefea..dba8b3e 100644 --- a/installers/install_starship.sh +++ b/installers/install_starship.sh @@ -77,23 +77,15 @@ configure_shell() { # Add ~/.local/bin to PATH for the current process export PATH="$HOME/.local/bin:$PATH" - local config_file="$HOME/.bashrc" - if [ -f "$config_file" ]; then - # Ensure ~/.local/bin is in PATH for this file if not already present - if ! grep -q '\.local/bin' "$config_file" 2>/dev/null; then - log_info "Adding ~/.local/bin to PATH in $config_file..." - local path_content='export PATH="$HOME/.local/bin:$PATH"' - inject_block "$config_file" "local-bin path" "$path_content" - fi + # Clean up legacy in-place configuration blocks + IFS=' ' read -ra target_files <<< "$(get_shell_configs)" + for config_file in "${target_files[@]}"; do + remove_block "$config_file" "local-bin path" + remove_block "$config_file" "starship init" + done - log_info "Adding starship initialization to $config_file..." - local content='eval "$(starship init bash)"' - - inject_block "$config_file" "starship init" "$content" - - # Source to apply changes in the current context - . "$config_file" 2>/dev/null || true - fi + write_env_snippet "local-bin" 'export PATH="$HOME/.local/bin:$PATH"' + write_env_snippet "starship" 'eval "$(starship init bash)"' } main() { diff --git a/installers/install_uv.sh b/installers/install_uv.sh index 2f9f063..ccf6fc6 100644 --- a/installers/install_uv.sh +++ b/installers/install_uv.sh @@ -87,25 +87,15 @@ configure_shell() { # Add ~/.local/bin to PATH for the current process export PATH="$HOME/.local/bin:$PATH" + # Clean up legacy in-place configuration blocks IFS=' ' read -ra target_files <<< "$(get_shell_configs)" - for config_file in "${target_files[@]}"; do - # Ensure ~/.local/bin is in PATH for this file if not already present - if ! grep -q '\.local/bin' "$config_file" 2>/dev/null; then - log_info "Adding ~/.local/bin to PATH in $config_file..." - local path_content='export PATH="$HOME/.local/bin:$PATH"' - inject_block "$config_file" "local-bin path" "$path_content" - fi - - log_info "Adding uv completion to $config_file..." - local content='eval "$(uv generate-shell-completion bash)"' - inject_block "$config_file" "uv completion" "$content" - - # Source to apply changes in the current context - if [ "$config_file" = "$HOME/.bashrc" ]; then - . "$config_file" 2>/dev/null || true - fi + remove_block "$config_file" "local-bin path" + remove_block "$config_file" "uv completion" done + + write_env_snippet "local-bin" 'export PATH="$HOME/.local/bin:$PATH"' + write_env_snippet "uv" 'eval "$(uv generate-shell-completion bash)"' } main() { diff --git a/installers/install_yazi.sh b/installers/install_yazi.sh index 7090ee2..0121919 100755 --- a/installers/install_yazi.sh +++ b/installers/install_yazi.sh @@ -21,7 +21,11 @@ cleanup() { trap cleanup EXIT add_y_wrapper() { + # Clean up legacy in-place configuration blocks IFS=' ' read -ra target_files <<< "$(get_shell_configs)" + for config_file in "${target_files[@]}"; do + remove_block "$config_file" "yazi wrapper" + done local wrapper_content wrapper_content=$(cat << 'EOF' @@ -37,16 +41,7 @@ y() { EOF ) - for config_file in "${target_files[@]}"; do - log_info "Adding yazi wrapper function 'y' to $config_file..." - inject_block "$config_file" "yazi wrapper" "$wrapper_content" - done - - # Source ~/.bashrc to make the alias immediately available in the current shell context (if sourced) - if [ -f "$HOME/.bashrc" ]; then - log_info "Sourcing ~/.bashrc..." - . "$HOME/.bashrc" 2>/dev/null || true - fi + write_alias_snippet "yazi" "$wrapper_content" } install_yazi() { diff --git a/installers/install_zoxide.sh b/installers/install_zoxide.sh index d9efac0..0c059db 100755 --- a/installers/install_zoxide.sh +++ b/installers/install_zoxide.sh @@ -46,19 +46,14 @@ configure_shell() { # Add ~/.local/bin to PATH for the current process export PATH="$HOME/.local/bin:$PATH" + # Clean up legacy in-place configuration blocks IFS=' ' read -ra target_files <<< "$(get_shell_configs)" - for config_file in "${target_files[@]}"; do - log_info "Adding zoxide initialization to $config_file..." - local content="eval \"\$(zoxide init --cmd cd bash)\"" - - inject_block "$config_file" "zoxide init" "$content" - - # Source if modified (only for bashrc) - if [ "$config_file" = "$HOME/.bashrc" ]; then - . "$config_file" 2>/dev/null || true - fi + remove_block "$config_file" "zoxide init" done + + write_env_snippet "local-bin" 'export PATH="$HOME/.local/bin:$PATH"' + write_env_snippet "zoxide" 'eval "$(zoxide init --cmd cd bash)"' } main() { diff --git a/lib/shell_config.sh b/lib/shell_config.sh index 50005f3..b810984 100644 --- a/lib/shell_config.sh +++ b/lib/shell_config.sh @@ -102,6 +102,54 @@ add_env_if_missing() { return 1 # Not added } +# Write environment snippet to env.d/ +# Usage: write_env_snippet +write_env_snippet() { + local name="$1" + local content="$2" + local dir="${BOOTSTRAP_DIR:-$HOME/.config/bootstrap}/env.d" + + mkdir -p "$dir" + log_info "Writing environment snippet '$name' to $dir/${name}.sh" + echo "$content" > "$dir/${name}.sh" +} + +# Write alias snippet to aliases.d/ +# Usage: write_alias_snippet +write_alias_snippet() { + local name="$1" + local content="$2" + local dir="${BOOTSTRAP_DIR:-$HOME/.config/bootstrap}/aliases.d" + + mkdir -p "$dir" + log_info "Writing alias snippet '$name' to $dir/${name}.sh" + echo "$content" > "$dir/${name}.sh" +} + +# Remove environment snippet from env.d/ +# Usage: remove_env_snippet +remove_env_snippet() { + local name="$1" + local dir="${BOOTSTRAP_DIR:-$HOME/.config/bootstrap}/env.d" + + if [ -f "$dir/${name}.sh" ]; then + log_info "Removing environment snippet '$name'" + rm -f "$dir/${name}.sh" + fi +} + +# Remove alias snippet from aliases.d/ +# Usage: remove_alias_snippet +remove_alias_snippet() { + local name="$1" + local dir="${BOOTSTRAP_DIR:-$HOME/.config/bootstrap}/aliases.d" + + if [ -f "$dir/${name}.sh" ]; then + log_info "Removing alias snippet '$name'" + rm -f "$dir/${name}.sh" + fi +} + # Setup fd symlink for Debian/Ubuntu (fdfind -> fd) create_fd_symlink() { if ! has_command fd && has_command fdfind; then @@ -112,5 +160,6 @@ create_fd_symlink() { # Export functions and variables for subshells export _LIB_SHELL_CONFIG_SOURCED=1 -export -f get_shell_configs remove_block inject_block add_alias_if_missing add_env_if_missing create_fd_symlink +export -f get_shell_configs remove_block inject_block add_alias_if_missing add_env_if_missing create_fd_symlink write_env_snippet write_alias_snippet remove_env_snippet remove_alias_snippet +