diff --git a/bin/.local/bin/bootstrap.sh b/bin/.local/bin/bootstrap.sh index b4f3625..b076816 100755 --- a/bin/.local/bin/bootstrap.sh +++ b/bin/.local/bin/bootstrap.sh @@ -1,19 +1,156 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash +set -euo pipefail -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -case "$(uname -s)" in -Linux) - echo "Linux bootstrapping not implemented yet" - eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - ;; -Darwin) - eval "$(/opt/homebrew/bin/brew shellenv)" - ;; +log() { printf "\n==> %s\n" "$*"; } +have() { command -v "$1" >/dev/null 2>&1; } + +DOTFILES_REPO="https://code.unbl.ink/secstate/dotfiles" +DOTFILES_DIR="${DOTFILES_DIR:-$HOME/.dotfiles}" +OMZ_DIR="${ZSH:-$HOME/.oh-my-zsh}" +DOOM_DIR="${DOOM_DIR:-$HOME/.emacs.d}" + +OS="$(uname -s)" +PLATFORM="" + +# -------- Detect platform -------- +if [[ "$OS" == "Darwin" ]]; then + PLATFORM="macos" +elif [[ "$OS" == "FreeBSD" ]]; then + PLATFORM="freebsd" +elif [[ "$OS" == "Linux" ]]; then + if [[ -r /etc/os-release ]]; then + # shellcheck disable=SC1091 + . /etc/os-release + fi + + is_arch=0 + case "${ID:-}" in + arch | endeavouros) is_arch=1 ;; + esac + if [[ $is_arch -eq 0 && -n "${ID_LIKE:-}" ]] && echo "$ID_LIKE" | grep -qi arch; then + is_arch=1 + fi + + is_fedora=0 + case "${ID:-}" in + fedora) is_fedora=1 ;; + esac + if [[ $is_fedora -eq 0 && -n "${ID_LIKE:-}" ]] && echo "$ID_LIKE" | grep -qiE 'fedora|rhel'; then + is_fedora=1 + fi + + if [[ $is_arch -eq 1 ]]; then + PLATFORM="arch" + elif [[ $is_fedora -eq 1 ]]; then + PLATFORM="fedora" + else + echo "Unsupported Linux distro (ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-unknown})." + exit 1 + fi +else + echo "Unsupported OS: $OS" + exit 1 +fi + +# -------- Install basics (git, stow, zsh, curl, make) -------- +install_arch() { + log "Installing prerequisites (Arch/EndeavourOS)..." + sudo pacman -Sy --needed --noconfirm git stow zsh curl make openssh +} + +install_fedora() { + log "Installing prerequisites (Fedora)..." + sudo dnf install -y git stow zsh curl make openssh-clients +} + +install_macos() { + log "Ensuring Homebrew..." + if ! have brew; then + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + fi + + # shellenv for both Apple Silicon and Intel + if [[ -x /opt/homebrew/bin/brew ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" + elif [[ -x /usr/local/bin/brew ]]; then + eval "$(/usr/local/bin/brew shellenv)" + fi + + log "Installing prerequisites (macOS via brew)..." + brew update + brew install git stow zsh curl gnu-make +} + +install_freebsd() { + log "Installing prerequisites (FreeBSD)..." + sudo pkg update -f + # gmake is GNU make; stow is stow; git/curl/zsh are available + sudo pkg install -y git stow zsh curl gmake +} + +case "$PLATFORM" in +arch) install_arch ;; +fedora) install_fedora ;; +macos) install_macos ;; +freebsd) install_freebsd ;; esac -brew install stow pass just fzf direnv -git clone https://code.unbl.ink/secstate/dotfiles ~/.dotfiles -(cd ~/.dotfiles && make) -git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh ~/.oh-my-zsh -source ~/.zshrc -scp powellc@192.168.40.208:~/.gnupg ~/. +# -------- Clone/update dotfiles -------- +if [[ -d "$DOTFILES_DIR/.git" ]]; then + log "Updating dotfiles in $DOTFILES_DIR..." + git -C "$DOTFILES_DIR" pull --rebase +else + log "Cloning dotfiles to $DOTFILES_DIR..." + git clone "$DOTFILES_REPO" "$DOTFILES_DIR" +fi + +# -------- Build/apply dotfiles (make vs gmake) -------- +MAKE_CMD="make" +if [[ "$PLATFORM" == "freebsd" ]]; then + MAKE_CMD="gmake" +elif [[ "$PLATFORM" == "macos" ]]; then + # prefer GNU make if available (brew installs as gmake) + if have gmake; then MAKE_CMD="gmake"; fi +fi + +log "Running $MAKE_CMD in dotfiles repo..." +(cd "$DOTFILES_DIR" && "$MAKE_CMD") + +# -------- oh-my-zsh -------- +if [[ -d "$OMZ_DIR" ]]; then + log "oh-my-zsh already present at $OMZ_DIR" +else + log "Cloning oh-my-zsh..." + git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh "$OMZ_DIR" +fi + +# -------- Doom Emacs -------- +if [[ -d "$DOOM_DIR/.git" ]]; then + log "Doom Emacs already present at $DOOM_DIR (updating)..." + git -C "$DOOM_DIR" pull --rebase || true +elif [[ -e "$DOOM_DIR" ]]; then + log "Skipping Doom Emacs clone because $DOOM_DIR exists but is not a git repo." + log "Move it aside if you want to install Doom there." +else + log "Cloning Doom Emacs to $DOOM_DIR..." + git clone --depth=1 https://github.com/doomemacs/doomemacs "$DOOM_DIR" +fi + +# -------- Next steps -------- +log "Next steps" +cat <<'EOF' +1) Start a new shell (or open a new terminal) so shell config reloads. + +2) If you want zsh as default: + - Linux: chsh -s $(command -v zsh) + - macOS: chsh -s /bin/zsh (or $(command -v zsh) if preferred) + - FreeBSD: chsh -s $(command -v zsh) + +3) Doom Emacs: + ~/.emacs.d/bin/doom install + (And later, when you change config: ~/.emacs.d/bin/doom sync) + +Note: I didn't 'source ~/.zshrc' inside this script because non-interactive sourcing is unreliable. +EOF + +log "Done." diff --git a/bin/.local/bin/build_snapclient.sh b/bin/.local/bin/build_snapclient.sh new file mode 100644 index 0000000..73b4432 --- /dev/null +++ b/bin/.local/bin/build_snapclient.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env sh +set -eu + +REPO_URL="https://github.com/badaix/snapcast.git" +WORKDIR="${WORKDIR:-$HOME/tmp/snapcast}" +PREFIX="$HOME/.local" + +# Ensure ~/.local/bin exists +mkdir -p "$PREFIX/bin" + +# --- Detect distro --- +if [ -r /etc/os-release ]; then + . /etc/os-release +else + echo "Cannot read /etc/os-release; unsupported system." >&2 + exit 1 +fi + +# Normalize Arch-like (EndeavourOS is Arch-based) +IS_ARCH=0 +case "${ID:-}" in +arch | endeavouros) IS_ARCH=1 ;; +esac +if [ "$IS_ARCH" -eq 0 ] && [ -n "${ID_LIKE:-}" ]; then + echo "$ID_LIKE" | grep -qi arch && IS_ARCH=1 || true +fi + +# --- Install dependencies --- +if [ "$IS_ARCH" -eq 1 ]; then + echo "Detected Arch/EndeavourOS. Installing dependencies with pacman..." + sudo pacman -Sy --needed --noconfirm \ + base-devel cmake boost flac libvorbis opus alsa-lib libsoxr avahi +else + IS_FEDORA=0 + case "${ID:-}" in + fedora) IS_FEDORA=1 ;; + esac + if [ "$IS_FEDORA" -eq 0 ] && [ -n "${ID_LIKE:-}" ]; then + echo "$ID_LIKE" | grep -qi 'fedora\|rhel' && IS_FEDORA=1 || true + fi + + if [ "$IS_FEDORA" -eq 1 ]; then + echo "Detected Fedora. Installing dependencies with dnf..." + sudo dnf -y install \ + cmake gcc-c++ make git \ + boost-devel flac-devel libvorbis-devel opus-devel alsa-lib-devel libsoxr-devel avahi-devel + else + echo "Unsupported distro (ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-unknown})." >&2 + exit 1 + fi +fi + +# --- Fetch source --- +mkdir -p "$(dirname "$WORKDIR")" + +if [ -d "$WORKDIR/.git" ]; then + echo "Updating existing Snapcast repo..." + git -C "$WORKDIR" pull --rebase +else + echo "Cloning Snapcast..." + git clone "$REPO_URL" "$WORKDIR" +fi + +# --- Build snapclient only --- +cd "$WORKDIR" +mkdir -p build +cd build + +echo "Configuring with prefix=$PREFIX" +cmake .. \ + -DCMAKE_INSTALL_PREFIX="$PREFIX" \ + -DBUILD_SERVER=OFF \ + -DBUILD_CLIENT=ON + +echo "Building..." +make -j"$(nproc)" + +echo "Installing to $PREFIX/bin (no sudo)..." +make install + +echo +echo "Done 🎧" +echo "Make sure ~/.local/bin is on your PATH." +echo "Test with: snapclient --version" diff --git a/bin/.local/bin/setup.sh b/bin/.local/bin/setup.sh new file mode 100755 index 0000000..c81e95a --- /dev/null +++ b/bin/.local/bin/setup.sh @@ -0,0 +1,315 @@ +#!/usr/bin/env bash +set -euo pipefail + +log() { printf "\n==> %s\n" "$*"; } +have() { command -v "$1" >/dev/null 2>&1; } + +OS="$(uname -s)" +PLATFORM="" + +# -------- OS detection -------- +if [[ "$OS" == "Darwin" ]]; then + PLATFORM="macos" +elif [[ "$OS" == "FreeBSD" ]]; then + PLATFORM="freebsd" +elif [[ "$OS" == "Linux" ]]; then + if [[ -r /etc/os-release ]]; then + # shellcheck disable=SC1091 + . /etc/os-release + fi + + is_arch=0 + case "${ID:-}" in + arch|endeavouros) is_arch=1 ;; + esac + if [[ $is_arch -eq 0 && -n "${ID_LIKE:-}" ]] && echo "$ID_LIKE" | grep -qi arch; then + is_arch=1 + fi + + is_fedora=0 + case "${ID:-}" in + fedora) is_fedora=1 ;; + esac + if [[ $is_fedora -eq 0 && -n "${ID_LIKE:-}" ]] && echo "$ID_LIKE" | grep -qiE 'fedora|rhel'; then + is_fedora=1 + fi + + if [[ $is_arch -eq 1 ]]; then + PLATFORM="arch" + elif [[ $is_fedora -eq 1 ]]; then + PLATFORM="fedora" + else + echo "Unsupported Linux distro (ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-unknown})." + exit 1 + fi +else + echo "Unsupported OS: $OS" + exit 1 +fi + +# -------- Helpers -------- +install_pacman() { + local pkgs=("$@") + log "pacman install: ${pkgs[*]}" + sudo pacman -Sy --needed --noconfirm "${pkgs[@]}" +} + +install_dnf() { + local pkgs=("$@") + log "dnf install: ${pkgs[*]}" + sudo dnf install -y "${pkgs[@]}" +} + +brew_install() { + local pkgs=("$@") + log "brew install: ${pkgs[*]}" + brew install "${pkgs[@]}" +} + +brew_cask() { + local pkgs=("$@") + log "brew install --cask: ${pkgs[*]}" + brew install --cask "${pkgs[@]}" +} + +install_pkg() { + local pkgs=("$@") + log "pkg install: ${pkgs[*]}" + sudo pkg install -y "${pkgs[@]}" +} + +# Best-effort install loops (skip missing packages cleanly) +dnf_install_best_effort() { + local pkgs=("$@") + for p in "${pkgs[@]}"; do + if sudo dnf info "$p" >/dev/null 2>&1; then + install_dnf "$p" + else + log "Skipping (dnf not found): $p" + fi + done +} + +pacman_install_best_effort() { + local pkgs=("$@") + for p in "${pkgs[@]}"; do + if pacman -Si "$p" >/dev/null 2>&1; then + install_pacman "$p" + else + log "Skipping (pacman not found): $p" + fi + done +} + +pkg_install_best_effort() { + local pkgs=("$@") + for p in "${pkgs[@]}"; do + if pkg search -q "^${p}$" >/dev/null 2>&1; then + install_pkg "$p" + else + log "Skipping (pkg not found): $p" + fi + done +} + +aur_install_if_possible() { + local pkgs=("$@") + if have yay; then + log "AUR install via yay: ${pkgs[*]}" + yay -S --needed --noconfirm "${pkgs[@]}" + else + log "Skipping AUR packages (yay not found): ${pkgs[*]}" + fi +} + +ensure_brew() { + if have brew; then return 0; fi + log "Homebrew not found; installing Homebrew..." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + + if [[ -x /opt/homebrew/bin/brew ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" + elif [[ -x /usr/local/bin/brew ]]; then + eval "$(/usr/local/bin/brew shellenv)" + fi +} + +ensure_flathub() { + if ! have flatpak; then + log "flatpak not installed; skipping flathub apps." + return 0 + fi + log "Ensuring Flathub remote exists..." + sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo +} + +# -------- Package sets (portable intent) -------- +# Required by you: +CORE_CLI=(fzf direnv stow pass just) + +# Plus from your history / common tooling: +EXTRA_CLI=(fd editorconfig git) + +DEV_TOOLS_LINUX=(cmake libtool make gcc gcc-c++) +UTILS_LINUX=(gnuplot graphviz shfmt shellcheck pandoc) + +DESKTOP_LINUX=(kitty alacritty dino syncthing snapcast) + +FEDORA_EXTRAS=( + gnome-extensions-app + gnome-tweaks + spice-vdagent + kernel-modules-extra + pinentry-tty + NetworkManager-openvpn-gnome + openvpn + openvpn3-client + libpq-devel + postgresql + pass-otp + chromium + google-chrome-stable +) + +ARCH_EXTRAS=( + gnome-extensions-app + gnome-tweaks + spice-vdagent + linux-headers + pinentry + networkmanager-openvpn + openvpn + postgresql-libs + postgresql + pass-otp + chromium +) + +MAC_BREW_PKGS=( + fzf direnv stow pass just + fd editorconfig git + cmake libtool + gnuplot graphviz shfmt shellcheck pandoc + postgresql + syncthing + pinentry-mac +) + +MAC_CASKS=( + kitty + alacritty + slack + google-chrome + chromium +) + +# FreeBSD name mapping (best-effort) +# Notes: +# - "just" is typically "just" on FreeBSD pkg. +# - "stow" is "stow". +# - "pass" is often "password-store". +# - fd is "fd-find". +# - shellcheck/shfmt exist. +# - direnv exists. +FREEBSD_CORE=(fzf direnv stow just password-store) +FREEBSD_EXTRA=(fd-find editorconfig-core-c git) +FREEBSD_DEV=(cmake libtool gmake llvm) # gmake instead of make; llvm as a sane default toolchain +FREEBSD_UTILS=(gnuplot graphviz shfmt shellcheck pandoc) +FREEBSD_SECURITY=(gnupg pinentry) # helpful for pass +FREEBSD_MISC=(postgresql16-client syncthing) + +# -------- Install per-platform -------- +case "$PLATFORM" in + fedora) + log "Platform: Fedora. Refreshing + upgrading..." + sudo dnf -y upgrade --refresh || true + + install_dnf "${CORE_CLI[@]}" "${EXTRA_CLI[@]}" || true + dnf_install_best_effort "${DEV_TOOLS_LINUX[@]}" + dnf_install_best_effort "${UTILS_LINUX[@]}" + dnf_install_best_effort "${DESKTOP_LINUX[@]}" + dnf_install_best_effort "${FEDORA_EXTRAS[@]}" + + ensure_flathub + if have flatpak; then + log "Optional: Slack via Flatpak" + sudo flatpak install -y flathub com.slack.Slack || true + fi + ;; + + arch) + log "Platform: EndeavourOS/Arch. Updating package databases..." + sudo pacman -Sy --noconfirm + + install_pacman "${CORE_CLI[@]}" "${EXTRA_CLI[@]}" + pacman_install_best_effort "${DEV_TOOLS_LINUX[@]}" + pacman_install_best_effort "${UTILS_LINUX[@]}" + pacman_install_best_effort "${DESKTOP_LINUX[@]}" + pacman_install_best_effort "${ARCH_EXTRAS[@]}" + + aur_install_if_possible google-chrome slack-desktop || true + ;; + + macos) + log "Platform: macOS. Ensuring Homebrew..." + ensure_brew + + log "Updating Homebrew..." + brew update + + brew_install "${MAC_BREW_PKGS[@]}" + brew_cask "${MAC_CASKS[@]}" || true + + if [[ -f "$(brew --prefix)/opt/fzf/install" ]]; then + log "Tip: run fzf install helper if you want keybindings/completion:" + echo " $(brew --prefix)/opt/fzf/install" + fi + ;; + + freebsd) + log "Platform: FreeBSD. Updating pkg metadata..." + sudo pkg update -f + + # Ensure basic SSL certs exist for fetches/tools that need it + pkg_install_best_effort ca_root_nss || true + + # Core CLI tools you asked for + pkg_install_best_effort "${FREEBSD_CORE[@]}" + + # Extras + dev + utilities + pkg_install_best_effort "${FREEBSD_EXTRA[@]}" + pkg_install_best_effort "${FREEBSD_DEV[@]}" + pkg_install_best_effort "${FREEBSD_UTILS[@]}" + + # pass needs gpg + pinentry + pkg_install_best_effort "${FREEBSD_SECURITY[@]}" + + # Optional stuff from your history where it makes sense + pkg_install_best_effort "${FREEBSD_MISC[@]}" + + log "FreeBSD notes:" + cat <<'EOF' +- 'pass' is installed as 'password-store' on FreeBSD; command is still: pass +- Build tools often use gmake (GNU make). If you compile from source, try gmake. +- GUI apps (kitty/alacritty/slack/chrome) are not installed here by default. +EOF + ;; +esac + +# -------- Post-install notes -------- +log "Post-install reminders" +cat <<'EOF' +- direnv (bash): + eval "$(direnv hook bash)" + (zsh uses: eval "$(direnv hook zsh)") + +- pass needs a GPG key: + gpg --full-generate-key + pass init "" + +- stow for dotfiles: + mkdir -p ~/dotfiles + # stow +EOF + +log "Done."