#!/usr/bin/env bash set -euo pipefail usage() { cat <<'USAGE' Install ByteLyst shell aliases into your shell startup file. Usage: ./install.sh [--dry-run] [--shell bash|zsh] [--rc-file PATH] Options: --dry-run Show what would change without writing files. --shell SHELL Override detected shell. Supported: bash, zsh. --rc-file PATH Override the target startup file. --help Show this help. USAGE } die() { echo "Error: $*" >&2 exit 1 } detect_os() { case "$(uname -s)" in Darwin) echo "macos" ;; Linux) echo "linux" ;; *) echo "unknown" ;; esac } detect_shell() { local shell_name shell_name="$(basename "${SHELL:-}")" case "$shell_name" in bash | zsh) echo "$shell_name" ;; *) if command -v zsh >/dev/null 2>&1; then echo "zsh" elif command -v bash >/dev/null 2>&1; then echo "bash" else die "could not detect bash or zsh; pass --shell bash or --shell zsh" fi ;; esac } default_rc_file() { local shell_name="$1" local os_name="$2" case "$shell_name" in zsh) echo "$HOME/.zshrc" ;; bash) if [ "$os_name" = "macos" ]; then echo "$HOME/.bash_profile" else echo "$HOME/.bashrc" fi ;; *) die "unsupported shell: $shell_name" ;; esac } resolve_alias_dir() { local source_path="${BASH_SOURCE[0]}" cd -- "$(dirname -- "$source_path")" >/dev/null 2>&1 pwd -P } remove_existing_block() { local input_file="$1" local output_file="$2" awk ' /^# >>> bytelyst aliases >>>$/ { skip = 1; next } /^# <<< bytelyst aliases <<<$/{ skip = 0; next } !skip { lines[++count] = $0 } END { while (count > 0 && lines[count] == "") { count-- } for (i = 1; i <= count; i++) { print lines[i] } } ' "$input_file" > "$output_file" } write_block() { local alias_loader="$1" cat <>> bytelyst aliases >>> source "$alias_loader" # <<< bytelyst aliases <<< BLOCK } dry_run=false shell_override="" rc_file="" while [ "$#" -gt 0 ]; do case "$1" in --dry-run) dry_run=true shift ;; --shell) [ "$#" -ge 2 ] || die "--shell requires bash or zsh" shell_override="$2" shift 2 ;; --rc-file) [ "$#" -ge 2 ] || die "--rc-file requires a path" rc_file="$2" shift 2 ;; --help | -h) usage exit 0 ;; *) die "unknown option: $1" ;; esac done os_name="$(detect_os)" shell_name="${shell_override:-$(detect_shell)}" case "$shell_name" in bash | zsh) ;; *) die "unsupported shell: $shell_name" ;; esac alias_dir="$(resolve_alias_dir)" alias_loader="$alias_dir/_source_all.alias" [ -f "$alias_loader" ] || die "alias loader not found: $alias_loader" target_rc="${rc_file:-$(default_rc_file "$shell_name" "$os_name")}" echo "Detected OS: $os_name" echo "Target shell: $shell_name" echo "Target startup file: $target_rc" echo "Alias loader: $alias_loader" if [ "$dry_run" = true ]; then echo echo "Would add or replace this managed block:" write_block "$alias_loader" exit 0 fi mkdir -p "$(dirname -- "$target_rc")" touch "$target_rc" tmp_file="$(mktemp)" new_file="$(mktemp)" trap 'rm -f "$tmp_file" "$new_file"' EXIT remove_existing_block "$target_rc" "$tmp_file" { cat "$tmp_file" if [ -s "$tmp_file" ]; then echo fi write_block "$alias_loader" } > "$new_file" if cmp -s "$target_rc" "$new_file"; then echo echo "ByteLyst aliases are already installed." echo "They will be available in new shell sessions." echo "To use them in this shell now, run:" echo " source \"$target_rc\"" exit 0 fi backup_file="$target_rc.bytelyst-aliases.bak.$(date +%Y%m%d%H%M%S).$$" cp "$target_rc" "$backup_file" cat "$new_file" > "$target_rc" echo echo "Installed ByteLyst aliases." echo "Backup created: $backup_file" echo "They will be available in new shell sessions." echo "To use them in this shell now, run:" echo " source \"$target_rc\""