277 lines
7.4 KiB
Bash
Executable file
277 lines
7.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# A script to bootstrap dotfiles with a mapping of repo-file -> home-file:
|
|
# - Clones the repo if needed (when run outside ~/.dotfiles).
|
|
# - Installs packages (different for macOS vs. Ubuntu/Debian).
|
|
# - Changes shell to Fish if it's not already.
|
|
# - Symlinks dotfiles (with custom filename mapping), prompting to replace existing ones.
|
|
|
|
set -euo pipefail
|
|
|
|
################################################################################
|
|
# VARIABLES
|
|
################################################################################
|
|
|
|
DOTFILES_REPO="https://git.straybits.ca/jeff/dotfiles.git"
|
|
DOTFILES_DIR="$HOME/.dotfiles"
|
|
|
|
# Packages for macOS:
|
|
PACKAGES_MAC=(
|
|
fish
|
|
fzf
|
|
bat
|
|
ack
|
|
fd
|
|
age
|
|
minisign
|
|
macvim
|
|
mc
|
|
lazygit
|
|
)
|
|
|
|
# Packages for Linux (assuming Ubuntu/Debian):
|
|
PACKAGES_LINUX=(
|
|
git
|
|
fish
|
|
curl
|
|
fzf
|
|
bat
|
|
ack
|
|
fd-find
|
|
age
|
|
minisign
|
|
vim-tiny
|
|
mc
|
|
)
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Symlinking Dotfiles With Different Filenames
|
|
#
|
|
# In this associative array:
|
|
# - The key is the file/directory name as it appears in the dotfiles repo.
|
|
# - The value is the target path you want symlinked in your home directory.
|
|
#------------------------------------------------------------------------------
|
|
SYMLINKS=(
|
|
"vim/config.vim:$HOME/.vim_runtime/my_configs.vim"
|
|
"vim/plugins:$HOME/.vim_runtime/my_plugins"
|
|
"fish:$HOME/.config/fish"
|
|
)
|
|
|
|
TARGET_SHELL="fish"
|
|
|
|
################################################################################
|
|
# FUNCTIONS
|
|
################################################################################
|
|
|
|
detect_os() {
|
|
local os
|
|
os="$(uname -s)"
|
|
case "${os}" in
|
|
Linux*) echo "linux" ;;
|
|
Darwin*) echo "mac" ;;
|
|
*) echo "unsupported" ;;
|
|
esac
|
|
}
|
|
|
|
install_package_linux() {
|
|
local pkg="$1"
|
|
# Check if installed:
|
|
if ! dpkg -s "$pkg" >/dev/null 2>&1; then
|
|
echo "Installing ${pkg} via apt..."
|
|
sudo apt-get update -y
|
|
sudo apt-get install -y "${pkg}"
|
|
else
|
|
echo "[OK] ${pkg} is already installed (Linux)."
|
|
fi
|
|
}
|
|
|
|
install_package_mac() {
|
|
local pkg="$1"
|
|
# Check if installed:
|
|
if ! brew ls --versions "$pkg" >/dev/null; then
|
|
echo "Installing ${pkg} via Homebrew..."
|
|
brew install "${pkg}"
|
|
else
|
|
echo "[OK] ${pkg} is already installed (macOS)."
|
|
fi
|
|
}
|
|
|
|
install_packages() {
|
|
local os="$1"
|
|
|
|
if [ "${os}" = "mac" ]; then
|
|
# Make sure Homebrew is installed first
|
|
if ! command -v brew >/dev/null 2>&1; then
|
|
echo "Homebrew not found, installing..."
|
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
eval "$(/opt/homebrew/bin/brew shellenv)"
|
|
fi
|
|
|
|
# Install each macOS package if missing
|
|
for pkg in "${PACKAGES_MAC[@]}"; do
|
|
install_package_mac "${pkg}"
|
|
done
|
|
|
|
elif [ "${os}" = "linux" ]; then
|
|
if ! command -v apt-get >/dev/null 2>&1; then
|
|
echo "Error: This script currently only supports apt-based distros on Linux."
|
|
exit 1
|
|
fi
|
|
|
|
# Install each Linux package if missing
|
|
for pkg in "${PACKAGES_LINUX[@]}"; do
|
|
install_package_linux "${pkg}"
|
|
done
|
|
|
|
# No packages for lazygit on Linux :(
|
|
install_lazygit_linux
|
|
|
|
fi
|
|
}
|
|
|
|
install_lazygit_linux() {
|
|
LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | \grep -Po '"tag_name": *"v\K[^"]*')
|
|
arch="$(uname -m)"
|
|
case "$arch" in
|
|
x86_64)
|
|
LAZYGIT_ARCH="Linux_x86_64"
|
|
;;
|
|
aarch64)
|
|
LAZYGIT_ARCH="Linux_arm64"
|
|
;;
|
|
*)
|
|
echo "Unsupported architecture: $arch"
|
|
exit 1
|
|
;;
|
|
esac
|
|
echo "Downloading LazyGit v${LAZYGIT_VERSION} for ${LAZYGIT_ARCH}..."
|
|
curl -Lo lazygit.tar.gz \
|
|
"https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_${LAZYGIT_ARCH}.tar.gz"
|
|
tar xf lazygit.tar.gz lazygit
|
|
sudo install lazygit -D -t /usr/local/bin/
|
|
rm -f lazygit.tar.gz lazygit
|
|
}
|
|
|
|
install_awesome_vim() {
|
|
if [ ! -d "$HOME/.vim_runtime" ]; then
|
|
echo "Cloning Amix's vimrc..."
|
|
git clone --depth=1 https://github.com/amix/vimrc.git "$HOME/.vim_runtime"
|
|
echo "Installing Awesome Vimrc..."
|
|
sh "$HOME/.vim_runtime/install_awesome_vimrc.sh"
|
|
else
|
|
echo "~/.vim_runtime already exists, skipping clone."
|
|
fi
|
|
}
|
|
|
|
install_starship() {
|
|
if ! command -v starship >/dev/null 2>&1; then
|
|
echo "Installing Starship"
|
|
curl -sS https://starship.rs/install.sh | sh
|
|
else
|
|
echo "Starship already installed"
|
|
fi
|
|
}
|
|
|
|
change_shell_to_fish() {
|
|
local fish_path
|
|
fish_path="$(command -v fish)"
|
|
if ! grep -Fxq "${fish_path}" /etc/shells; then
|
|
echo "Adding ${fish_path} to /etc/shells..."
|
|
# Some systems might require sudo for writing to /etc/shells
|
|
echo "${fish_path}" | sudo tee -a /etc/shells
|
|
else
|
|
echo "Fish ${fish_path} already in /etc/shells..."
|
|
fi
|
|
|
|
if [[ $SHELL != *"${TARGET_SHELL}"* ]]; then
|
|
# Check if fish is actually installed
|
|
echo "Changing default shell to '${TARGET_SHELL}'..."
|
|
chsh -s "$(command -v fish)"
|
|
else
|
|
echo "[OK] Shell is already '${TARGET_SHELL}'."
|
|
fi
|
|
}
|
|
|
|
create_symlinks() {
|
|
# Iterate over the SYMLINKS associative array
|
|
for pair in "${SYMLINKS[@]}"; do
|
|
local src="${DOTFILES_DIR}/${pair%%:*}"
|
|
local dest="${pair#*:}"
|
|
|
|
# Ensure the parent directory of the destination exists
|
|
mkdir -p "$(dirname "${dest}")"
|
|
|
|
# Early exit if the link already exists
|
|
if [ -e "${dest}" ] && [ -L "${dest}" ]; then
|
|
echo " -> Link '${dest}' to '${src}' exists."
|
|
continue
|
|
fi
|
|
|
|
if [ -e "${dest}" ]; then
|
|
# A real file or directory is in the way
|
|
read -rp "File '${dest}' already exists. Overwrite? [y/N] " answer
|
|
if [[ "${answer}" =~ ^[Yy]$ ]]; then
|
|
rm -rf "${dest}"
|
|
ln -s "${src}" "${dest}"
|
|
echo " -> Overwrote '${dest}' with symlink to '${src}'."
|
|
else
|
|
echo " -> Skipped '${dest}'."
|
|
fi
|
|
else
|
|
ln -s "${src}" "${dest}"
|
|
echo " -> Linked '${dest}' to '${src}'."
|
|
fi
|
|
done
|
|
}
|
|
|
|
deploy_dotfiles() {
|
|
local os
|
|
os="$(detect_os)"
|
|
|
|
if [ "${os}" = "unsupported" ]; then
|
|
echo "Unsupported OS: $(uname -s). Exiting."
|
|
exit 1
|
|
fi
|
|
|
|
echo "1. Installing necessary packages..."
|
|
install_packages "${os}"
|
|
|
|
echo "2. Intalling awesome vim..."
|
|
install_awesome_vim
|
|
|
|
echo "3. Intalling Starship..."
|
|
install_starship
|
|
|
|
echo "4. Changing shell to '${TARGET_SHELL}' (if needed)..."
|
|
change_shell_to_fish
|
|
|
|
echo "5. Creating symlinks..."
|
|
create_symlinks
|
|
|
|
echo "Done!"
|
|
}
|
|
|
|
################################################################################
|
|
# MAIN SCRIPT
|
|
################################################################################
|
|
|
|
# If the script is not being run from ~/.dotfiles, we assume the user just curl'ed it.
|
|
if [ "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" != "${DOTFILES_DIR}" ]; then
|
|
echo "Script is not in ${DOTFILES_DIR}; assuming first-time setup..."
|
|
|
|
if [ ! -d "${DOTFILES_DIR}" ]; then
|
|
echo "Cloning dotfiles repo into ${DOTFILES_DIR}..."
|
|
git clone "${DOTFILES_REPO}" "${DOTFILES_DIR}"
|
|
else
|
|
echo "${DOTFILES_DIR} already exists. Pulling latest changes..."
|
|
git -C "${DOTFILES_DIR}" pull --rebase
|
|
fi
|
|
|
|
echo "Running deployment from cloned repo..."
|
|
cd "${DOTFILES_DIR}"
|
|
bash install.sh # re-invoke the script from within ~/.dotfiles
|
|
exit 0
|
|
else
|
|
echo "Script running from ${DOTFILES_DIR} - proceeding with deployment..."
|
|
deploy_dotfiles
|
|
fi
|