Files
dotfiles/install.sh
ForeverPyrite f33e6a77a3 bro can't stop committing
1. Added `tree-sitter-cli` as a Rust package/dependancy
2. Updated README accordingly
3. Changed the default vault paths in obsidian.lua to my actual paths.
(Imagine copy and pasting the default, what a loser)
2025-09-17 22:30:26 -04:00

244 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#
# Dotfiles Bootstrap Script
#
# This script automates the setup of a high-performance, Rust-powered
# command-line environment. It uses a hybrid sequential/parallel approach.
#
# Flags:
# --extended: Performs a "desktop" setup: installs GUI fonts and changes the default shell.
# --docker: Installs Docker Engine.
set -e # Exit immediately if a command exits with a non-zero status.
# --- Helper Functions for Logging ---
info() { echo -e "\033[1;34m==> $1\033[0m"; }
success() { echo -e "\033[1;32m✅ $1\033[0m"; }
warn() { echo -e "\033[1;33m⚠ $1\033[0m"; }
# --- Argument Parsing & Environment Setup ---
EXTENDED_INSTALL=false
DOCKER_INSTALL=false
[[ " $* " =~ " --extended " ]] && EXTENDED_INSTALL=true
[[ " $* " =~ " --docker " ]] && DOCKER_INSTALL=true
# Phased installation package lists
PREREQ_PACKAGES=(git stow) # Git to clone my dotfiles repo, stow to symlink my conf from the cloned repo.
SYSTEM_PACKAGES=(curl tmux btop fish)
# Okay yes this may seem complete over-the-top oxidization, however:
RUST_PACKAGES=(
eza # Drop in `ls` replacement, more modern formatting, and even has a built in tree command! (The amount of times I've had to install tree...)
bat # Drop in `cat` replacement, more modern formatting, uhh "cat with wings" is what they said. I agree.
ripgrep # Drop in `grep` replacement, and it's FASTTTTTTTTTTTTTT. Has unironically saved me trying to find a file I misplaced so many times. FASTTTTTTTTTTTTTT.
fd-find # Drop in `find` replacement, and it's also FASTTTTTTTTTTTTTT. Very similar to `ripgrep`, but for file(path)s instead of file contents.
zoxide # Drop in `cd` replacement, can use `fzf` to...well...fuzzy find, and it also just knows where to go
starship # Super customizable cross-shell prompt. Very informative, yet very brief (at least, by default).
bob-nvim # Probably something I'll drop since installing up-to-date neovim seems like an impossible task. I'll figure out something...
tree-sitter-cli # Dependancy for some neovim stuff.
atuin # This is kinda like zoxide, but for your shell commands. Pressing the up arrow now shows your entire command history, and you can fuzzy find through them. I imagine it's more secure than .bash_history too.
dua-cli # Disk-usage-analyzer. Plain and simple. For some reason I can't figure out how to find folder sizes (you probably can with `eza`), so this'll do. Useful for my limited storage cloud VPS and stuff.
cargo-cache # Actually just used for this script so far. It'll clean up all the, likely useless, sizable compiled dependancies used to build all of this.
)
# Global variables for system context
SUDO_CMD=""
PM=""
OS_ID=""
# --- Prerequisite Functions (Unchanged) ---
detect_os_and_pm() {
info "Detecting OS and Package Manager..."
if [ -f /etc/os-release ]; then
. /etc/os-release
OS_ID=$ID
fi
if [[ "$(uname)" == "Darwin" ]]; then
PM="brew"
elif command -v apt-get &>/dev/null; then
PM="apt-get"
elif command -v dnf &>/dev/null; then
PM="dnf"
elif command -v pacman &>/dev/null; then
PM="pacman"
else
warn "Could not detect a supported package manager (apt-get, dnf, pacman, brew)."
exit 1
fi
info "Detected OS: ${OS_ID:-macOS}, Package Manager: $PM"
}
check_and_setup_sudo() {
info "Checking for root privileges and sudo..."
if [[ "$(id -u)" -eq 0 ]]; then
info "Running as root. 'sudo' is not required."
SUDO_CMD=""
if ! command -v sudo &>/dev/null; then
info "Sudo not found. Installing it for future convenience..."
case "$PM" in
apt-get) apt-get update && apt-get install -y sudo ;;
dnf) dnf install -y sudo ;;
pacman) pacman -S --noconfirm sudo ;;
esac
fi
else
if ! command -v sudo &>/dev/null; then
warn "This script requires 'sudo' to be installed for non-root users."
exit 1
fi
SUDO_CMD="sudo"
info "Running as non-root user. Using 'sudo' for privileged operations."
fi
}
install_build_tools() {
info "Installing essential build tools for Rust..."
case "$PM" in
apt-get) $SUDO_CMD apt-get install -y build-essential ;;
dnf) $SUDO_CMD dnf groupinstall -y "Development Tools" ;;
pacman) $SUDO_CMD pacman -S --noconfirm --needed base-devel ;;
esac
}
# lowk the best function tho
install_rust_toolchain() {
if command -v cargo &>/dev/null; then info "Rust toolchain is already installed."; else
info "Installing Rust and Cargo via rustup..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
fi
export PATH="$HOME/.cargo/bin:$PATH"
}
deploy_dotfiles() {
info "Cloning and deploying dotfiles..."
local dotfiles_repo="https://github.com/ForeverPyrite/dotfiles.git"
local dotfiles_dir="$HOME/dotfiles"
if [ ! -d "$dotfiles_dir" ]; then git clone "$dotfiles_repo" "$dotfiles_dir"; else info "Dotfiles directory already exists. Skipping clone."; fi
info "Backing up any conflicting default config files..."
local conflict_files=("$HOME/.bashrc" "$HOME/.profile" "$HOME/.bash_logout")
for file in "${conflict_files[@]}"; do
if [ -f "$file" ] && [ ! -L "$file" ]; then
mv "$file" "$file.bak"
info " -> Moved $file to $file.bak"
fi
done
info "Running 'stow' to link configurations..."
cd "$dotfiles_dir"
for dir in */; do [ -d "$dir" ] && stow "${dir%/}"; done
cd - >/dev/null
success "Dotfiles have been deployed."
}
# --- Parallel Installation Function ---
run_parallel_installs() {
info "Handing off to Tmux for parallel tool installation..."
local session_name="dotfiles"
# --- Command Definitions ---
# Note: if fish is set up in the .bashrc/.profile at this point, tmux sessions will start in fish, which messes up these commands (since they for bash).
# Solution: bash -c 'command'
local cargo_cmd="export PATH='$HOME/.cargo/bin:$PATH'; for pkg in ${RUST_PACKAGES[@]}; do cargo install --locked \$pkg; done && bob use stable && \
sudo ln -s ~/.local/share/bob/nvim-bob/nvim /usr/bin/nvim && \
cargo cache -a -y && \
echo '✅ Cargo packages installed, Neovim set up, and cache cleaned.'"
local fzf_cmd="git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && ~/.fzf/install --all && echo '✅ fzf installed.'"
local tpm_cmd="git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm && echo '✅ Tmux Plugin Manager installed.'"
# --- Create Layout & Send Commands ---
# This robust method creates the entire layout first, then sends commands to the numbered panes.
tmux start-server
# Pane 0
tmux new-session -d -s "$session_name"
# Pane 1
tmux split-window -h -t "$session_name:1.1"
# Pane 2
tmux split-window -v -t "$session_name:1.2"
# Send commands to their respective panes
# Yeah, I talked about `bash -c 'command'`, but I don't wanna test all that right now
tmux send-keys -t "$session_name:1.1" "$cargo_cmd" C-m
tmux send-keys -t "$session_name:1.2" "$tpm_cmd" C-m
tmux send-keys -t "$session_name:1.3" "$fzf_cmd" C-m
# Handle optional installs in new windows
if [ "$DOCKER_INSTALL" = true ]; then
tmux new-window -t "$session_name" -n "Docker"
local docker_cmd="curl -fsSL https://get.docker.com | $SUDO_CMD sh && echo '✅ Docker installed.'"
tmux send-keys -t "$session_name:Docker" "$docker_cmd" C-m
fi
if [ "$EXTENDED_INSTALL" = true ]; then
tmux new-window -t "$session_name" -n "Desktop"
# Pane 1: Font Installation
local font_cmd="mkdir -p ~/.local/share/fonts && curl -fLo f.tar.xz https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/Hack.tar.xz && tar -xf f.tar.xz -C ~/.local/share/fonts && rm f.tar.xz && fc-cache -fv && echo '✅ Fonts installed.'"
tmux send-keys -t "$session_name:Desktop.1" "$font_cmd" C-m
# Split the window for the next commands
tmux split-window -h -t "$session_name:Desktop.1"
tmux split-window -v -t "$session_name:Desktop.2"
# Pane 2: Change Shell
local shell_cmd="FISH_PATH=\$(which fish); if ! grep -q \"\$FISH_PATH\" /etc/shells; then echo \"\$FISH_PATH\" | $SUDO_CMD tee -a /etc/shells; fi; $SUDO_CMD chsh -s \"\$FISH_PATH\" \"$USER\" && echo '✅ Shell changed.'"
tmux send-keys -t "$session_name:Desktop.2" "$shell_cmd" C-m
warn "The 'chsh' command inside tmux may require your password to complete."
# Pane 3: Install Alacritty
# Oh the unfortunate life of this command.
# See, you can build alacritty from source via cargo, however, to do that I would need to install all the build dependancies...and like...there's a certain point where it's just not worth it.
local alacritty_install_cmd
case "$PM" in
# wait where is GUI_PACKAGES defined? is it even defined? oh god.
brew) alacritty_install_cmd="brew install --cask ${GUI_PACKAGES[*]}" ;;
apt-get) alacritty_install_cmd="$SUDO_CMD apt-get install -y ${GUI_PACKAGES[*]}" ;;
dnf) alacritty_install_cmd="$SUDO_CMD dnf install -y ${GUI_PACKAGES[*]}" ;;
pacman) alacritty_install_cmd="$SUDO_CMD pacman -S --noconfirm ${GUI_PACKAGES[*]}" ;;
esac
alacritty_install_cmd+=" && echo '✅ Alacritty installed.'"
tmux send-keys -t "$session_name:Desktop.3" "$alacritty_install_cmd" C-m
fi
success "Tmux session '$session_name' created. Attach with: tmux a -t $session_name"
}
# --- Main Execution ---
# Phase 0: System Detection & Prerequisite Installation
detect_os_and_pm
check_and_setup_sudo
info "Phase 0: Installing prerequisites (git, stow)..."
case "$PM" in
brew) brew install "${PREREQ_PACKAGES[@]}" ;;
apt-get) $SUDO_CMD apt-get update && $SUDO_CMD apt-get install -y "${PREREQ_PACKAGES[@]}" ;;
dnf)
if [[ "$OS_ID" == "ol" || "$OS_ID" == "almalinux" || "$OS_ID" == "rockylinux" || "$OS_ID" == "centos" ]]; then $SUDO_CMD dnf install -y epel-release --nogpgcheck; fi
$SUDO_CMD dnf install -y "${PREREQ_PACKAGES[@]}"
;;
pacman) $SUDO_CMD pacman -Syu --noconfirm "${PREREQ_PACKAGES[@]}" ;;
esac
success "Prerequisites installed."
# Phase 1: Deploy Configurations
deploy_dotfiles
# Phase 2: Core System Installation
info "Phase 2: Installing core system tools..."
case "$PM" in
brew) brew install "${SYSTEM_PACKAGES[@]}" ;; apt-get) $SUDO_CMD apt-get install -y "${SYSTEM_PACKAGES[@]}" ;;
dnf) $SUDO_CMD dnf install -y "${SYSTEM_PACKAGES[@]}" ;; pacman) $SUDO_CMD pacman -S --noconfirm "${SYSTEM_PACKAGES[@]}" ;;
esac
install_build_tools
install_rust_toolchain
success "Core system tools installed."
# Phase 3: Parallel Tool Installation
run_parallel_installs # unfortunate part of this is that it'll require your password/sudo auth quite a bit.
# I think it would be cool to be able to run this script without root, given prerequisites are installed, since cargo installed binaries are stored in `~/.cargo/bin`
# All the system needs is "git", "stow", and a few build tools. rustup is installed without sudo just fine too.
# I'm not sure why I'm acting like I'd use this script on a multi-user system: I'd just ssh into my own machines.
# --- Final Message ---
echo ""
info "--------------------------------------------------------"
success "Bootstrap script finished!"
info "Monitor the rest of the installation inside tmux: tmux a -t dotfiles_setup"
info "Log out and log back in to apply all changes, especially the new shell."
info "--------------------------------------------------------"