#!/usr/bin/env bash set -euo pipefail # ============================================================ # Pinned versions — update manually # ============================================================ NVIM_VERSION="0.12.4" GO_VERSION="1.27.0" FZF_VERSION="0.61.1" JUST_VERSION="1.40.0" # ============================================================ # Global wget options # ============================================================ export WGET_OPTS="--quiet --timeout=30 --tries=3" # ============================================================ # Cleanup trap # ============================================================ TMP_DIRS=() cleanup() { for d in "${TMP_DIRS[@]}"; do rm -rf "$d" done } trap cleanup EXIT # ============================================================ # MSSQL Server setup # ============================================================ echo "=== MSSQL Server setup ===" if [[ -x /opt/mssql/bin/mssql-conf ]] && ! systemctl is-active mssql-server >/dev/null 2>&1; then echo 'export PATH=$PATH:/opt/mssql-tools18/bin' | sudo tee /etc/profile.d/mssql-tools.sh read -rp "MSSQL Server is installed but not configured. Run setup now? [Y/n] " CONFIRM if [[ "${CONFIRM:-Y}" =~ ^[Yy]$ ]]; then sudo /opt/mssql/bin/mssql-conf setup else echo "*** Skipped. Run manually: sudo /opt/mssql/bin/mssql-conf setup ***" fi elif [[ -x /opt/mssql/bin/mssql-conf ]]; then echo "mssql-server is already configured and running." echo 'export PATH=$PATH:/opt/mssql-tools18/bin' | sudo tee /etc/profile.d/mssql-tools.sh fi # ============================================================ # DBeaver repository # ============================================================ echo "=== DBeaver repository ===" if ! dpkg -s dbeaver-ce >/dev/null 2>&1; then sudo wget -q -O - https://dbeaver.io/debs/dbeaver.gpg.key | \ sudo gpg --dearmor -o /usr/share/keyrings/dbeaver.gpg.key echo "deb [signed-by=/usr/share/keyrings/dbeaver.gpg.key] https://dbeaver.io/debs/dbeaver-ce /" | \ sudo tee /etc/apt/sources.list.d/dbeaver.list fi # ============================================================ # apt packages # ============================================================ export DEBIAN_FRONTEND=noninteractive APT_PACKAGES=( build-essential clang curl fd-find findutils gawk git jq make ripgrep sqlite3 tmux unzip zip util-linux ncurses-base libheif-examples libheif1 libtiff-dev libwebp-dev libopenjp2-7 libopenjp2-7-dev ffmpeg libreoffice libgs-dev imagemagick libgl-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libxxf86vm-dev openjdk-21-jdk maven qemu-system libvirt-daemon-system libvirt-clients virt-manager bridge-utils apt-transport-https nodejs npm podman openssh-server mssql-server mssql-tools18 unixodbc-dev dbeaver-ce zsh patchelf ccache pkg-config libssl-dev libopenjp2-tools ) echo "=== apt packages ===" sudo apt-get update -y sudo apt-get upgrade -y ACCEPT_EULA=Y sudo apt-get install -y "${APT_PACKAGES[@]}" # ============================================================ # Set zsh as default shell # ============================================================ echo "=== zsh default shell ===" if [[ "$(getent passwd "$USER" | cut -d: -f7)" != *"zsh"* ]]; then chsh -s "$(which zsh)" echo "*** zsh set as default shell — log out/in required for full effect. ***" fi # ============================================================ # oh-my-zsh # ============================================================ echo "=== oh-my-zsh ===" ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" if [[ ! -d "$HOME/.oh-my-zsh" ]]; then sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended fi # ============================================================ # zsh plugins (syntax-highlighting + autosuggestions) # ============================================================ echo "=== zsh plugins ===" ZSH_HIGHLIGHT_REPO="https://github.com/zsh-users/zsh-syntax-highlighting.git" ZSH_AUTOSUGGEST_REPO="https://github.com/zsh-users/zsh-autosuggestions.git" if [[ ! -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ]]; then git clone --depth 1 "$ZSH_HIGHLIGHT_REPO" "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" fi if [[ ! -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ]]; then git clone --depth 1 "$ZSH_AUTOSUGGEST_REPO" "$ZSH_CUSTOM/plugins/zsh-autosuggestions" fi # ============================================================ # .zshrc # ============================================================ echo "=== .zshrc ===" ZSHRC="$HOME/.zshrc" cat > "$ZSHRC" << 'ZSHRC_EOF' export ZSH="$HOME/.oh-my-zsh" ZSH_THEME="robbyrussell" plugins=( git zsh-syntax-highlighting zsh-autosuggestions ) source $ZSH/oh-my-zsh.sh export PATH="$HOME/.cargo/bin:$PATH" export PATH="$HOME/.local/bin:$PATH" export PATH="$PATH:/usr/local/go/bin" export GOPATH="$HOME/go" export PATH="$PATH:$GOPATH/bin" export PATH="$PATH:/opt/mssql-tools18/bin" export PATH="$HOME/.atuin/bin:$PATH" . "$HOME/.local/bin/env" eval "$(atuin init zsh)" eval "$(zoxide init zsh)" alias gp='git push' alias gcm='git commit -m' alias gsw='git switch' alias gst='git status' alias gaa='git add .' alias ga='git add' alias gtree='git log --graph --oneline --decorate --all' alias cd='z' alias cdi='zi' ZSHRC_EOF # ============================================================ # tmux — default shell to zsh # ============================================================ echo "=== tmux default shell ===" TMUX_CONF="$HOME/.tmux.conf" TOUCH_TMUX=0 if [[ ! -f "$TMUX_CONF" ]]; then touch "$TMUX_CONF" TOUCH_TMUX=1 fi if ! grep -qF 'set-option -g default-shell' "$TMUX_CONF"; then printf 'set-option -g default-shell %s\n' "$(which zsh)" >> "$TMUX_CONF" fi # ============================================================ # Add user to libvirt groups # ============================================================ echo "=== Add user to libvirt groups ===" sudo usermod -aG libvirt,libvirt-qemu "$USER" || true echo "*** Added $USER to libvirt groups — log out/in required for effect. ***" # ============================================================ # MSSQL Server setup (post-install) # ============================================================ echo "=== MSSQL Server setup ===" if [[ -x /opt/mssql/bin/mssql-conf ]]; then echo "*** mssql-server installed. Run: sudo /opt/mssql/bin/mssql-conf setup ***" echo 'export PATH=$PATH:/opt/mssql-tools18/bin' | sudo tee /etc/profile.d/mssql-tools.sh sudo usermod -aG mssql "$USER" sudo install -d -m 2770 -o mssql -g mssql /var/opt/mssql/jsp fi # ============================================================ # Go # ============================================================ echo "=== Go ===" GO_NEEDS_INSTALL=1 if [[ -x /usr/local/go/bin/go ]]; then INSTALLED_GO=$(/usr/local/go/bin/go version | awk '{print $3}' | sed 's/^go//') if [[ "$INSTALLED_GO" == "$GO_VERSION" ]]; then GO_NEEDS_INSTALL=0 fi fi if [[ "$GO_NEEDS_INSTALL" -eq 1 ]]; then sudo rm -rf /usr/local/go wget ${WGET_OPTS} -O "/tmp/go${GO_VERSION}.linux-amd64.tar.gz" \ "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" sudo tar -C /usr/local -xzf "/tmp/go${GO_VERSION}.linux-amd64.tar.gz" rm -f "/tmp/go${GO_VERSION}.linux-amd64.tar.gz" if [[ ! -f /etc/profile.d/go.sh ]]; then printf '%s\n' \ 'export PATH=$PATH:/usr/local/go/bin' \ 'export GOPATH=$HOME/go' \ 'export PATH=$PATH:$GOPATH/bin' \ | sudo tee /etc/profile.d/go.sh fi fi # ============================================================ # Rust # ============================================================ echo "=== Rust ===" if [[ ! -x "$HOME/.cargo/bin/rustup" ]]; then curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path fi [[ -f "$HOME/.cargo/env" ]] && source "$HOME/.cargo/env" rustup default stable # ============================================================ # just # ============================================================ echo "=== just ===" JUST_NEEDS_INSTALL=1 if [[ -x "$HOME/.cargo/bin/just" ]]; then INSTALLED_JUST=$("$HOME/.cargo/bin/just" --version | awk '{print $2}') if [[ "$INSTALLED_JUST" == "$JUST_VERSION" ]]; then JUST_NEEDS_INSTALL=0 fi fi if [[ "$JUST_NEEDS_INSTALL" -eq 1 ]]; then "$HOME/.cargo/bin/cargo" install just --version "${JUST_VERSION}" --locked --force fi # ============================================================ # fzf # ============================================================ echo "=== fzf ===" FZF_NEEDS_INSTALL=1 if [[ -x /usr/local/bin/fzf ]]; then INSTALLED_FZF=$(/usr/local/bin/fzf --version | awk '{print $1}') if [[ "$INSTALLED_FZF" == "$FZF_VERSION" ]]; then FZF_NEEDS_INSTALL=0 fi fi if [[ "$FZF_NEEDS_INSTALL" -eq 1 ]]; then TMPDIR=$(mktemp -d) TMP_DIRS+=("$TMPDIR") wget ${WGET_OPTS} -O "$TMPDIR/fzf.tar.gz" \ "https://github.com/junegunn/fzf/releases/download/v${FZF_VERSION}/fzf-${FZF_VERSION}-linux_amd64.tar.gz" tar -xzf "$TMPDIR/fzf.tar.gz" -C "$TMPDIR" sudo cp "$TMPDIR/fzf" /usr/local/bin/fzf sudo chmod 0755 /usr/local/bin/fzf fi # ============================================================ # zoxide # ============================================================ echo "=== zoxide ===" if [[ ! -x "$HOME/.local/bin/zoxide" ]]; then curl -sSfL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh else echo "zoxide already installed, skipping." fi # ============================================================ # atuin # ============================================================ echo "=== atuin ===" if [[ ! -x "$HOME/.local/bin/atuin" ]]; then curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh else echo "atuin already installed, skipping." fi # ============================================================ # Neovim # ============================================================ echo "=== Neovim v${NVIM_VERSION} ===" NVIM_NEEDS_INSTALL=1 if [[ -x /usr/local/bin/nvim ]]; then INSTALLED_NVIM=$(/usr/local/bin/nvim --version | head -1 | awk '{print $2}' | sed 's/^v//') if [[ "$INSTALLED_NVIM" == "$NVIM_VERSION" ]]; then NVIM_NEEDS_INSTALL=0 fi fi if [[ "$NVIM_NEEDS_INSTALL" -eq 1 ]]; then wget ${WGET_OPTS} -O /tmp/nvim.tar.gz \ "https://github.com/neovim/neovim/releases/download/v${NVIM_VERSION}/nvim-linux-x86_64.tar.gz" sudo rm -rf /usr/local/nvim-linux-x86_64 sudo tar -C /usr/local -xzf /tmp/nvim.tar.gz sudo ln -sf /usr/local/nvim-linux-x86_64/bin/nvim /usr/local/bin/nvim rm -f /tmp/nvim.tar.gz fi echo "=== Neovim init.lua ===" mkdir -p "$HOME/.config/nvim" if [[ ! -f "$HOME/.config/nvim/init.lua" ]]; then wget ${WGET_OPTS} -O "$HOME/.config/nvim/init.lua" \ "https://git.flo.fo/FLO/dotfiles/raw/branch/main/nvim/.config/nvim/init.lua" fi # ============================================================ # Taskfile # ============================================================ echo "=== Taskfile ===" if ! command -v task >/dev/null 2>&1; then curl -1sLf 'https://dl.cloudsmith.io/public/task/task/setup.deb.sh' | sudo bash sudo apt-get install -y task fi # ============================================================ # Ensure cargo is in PATH (.bashrc kept for non-interactive bash) # ============================================================ if ! grep -q 'export PATH="$HOME/.cargo/bin:$PATH"' "$HOME/.bashrc"; then printf '\nexport PATH="$HOME/.cargo/bin:$PATH"\n' >> "$HOME/.bashrc" fi # ============================================================ # Services # ============================================================ echo "=== Services ===" sudo systemctl enable --now ssh.service 2>/dev/null \ || sudo systemctl enable --now sshd.service 2>/dev/null \ || true sudo systemctl enable --now libvirtd.service # ============================================================ echo "=== Done ===" echo "zsh is the default shell — log out and back in." echo "tmux is configured to use zsh as default-shell." echo "oh-my-zsh with syntax-highlighting + autosuggestions installed." echo "Rust and Cargo are at ~/.cargo/bin — added to .zshrc and .bashrc." echo "If mssql-server was installed, run: sudo /opt/mssql/bin/mssql-conf setup"