Automating Workstation Setup with Dotfiles

Cover Image for Automating Workstation Setup with Dotfiles

I recently bought a couple of new Raspberry Pi 5s to add to my home lab. I decided as I was setting them up that this would be a great time to finally work on my Dotfiles.

What Are Dotfiles?

Dotfiles are configuration files used to customize and automate the setup of a Unix environment. They typically include settings for shell environments, text editors, version control systems, and other tools that developers frequently use.

Why Dotfiles

By storing these configuration files in a version-controlled repository, developers can easily replicate their preferred setup across multiple machines. The time to configure each environment is significantly reduced, allowing for a more efficient workflow.

How I Use Dotfiles

My dotfiles repository can be found on GitHub. It includes configurations for:

  • Bash
  • Git
  • Vim
  • Tmux
  • VSCode settings
  • Zsh with Oh My Zsh

When setting up a new machine, all I need to is clone the repository and run the setup.sh script. Let's take a look.

#!/bin/bash

# Get the flavor of Unix we're working with
FLAVOR=$(uname -s)

if [ "$FLAVOR" = "Darwin" ]; then
  echo "Working on a Mac";
  mac/install-brew.sh;
  mac/omz.sh
  bash/install.sh
elif [ "$FLAVOR" = "Linux" ]; then
  echo "Working on Linux";
  bash/install.sh
else
  echo "This script only works on Linux or Mac, not $FLAVOR";
  exit 0;
fi

echo "symlinking gitconfig"
ln -sf $(pwd)/gitconfig "$HOME/.gitconfig"

The setup script detects the operating system using uname -s, and then runs various scripts for that target the speciffic OS. Finally, it symlinks the Git configuration file to the user's home directory.

Mac Setup

First the setup.sh script runs mac/install-brew.sh to install X-Tools for Mac, and Homebrew, the package manager for MacOS. Then the script reads from the list of packages in brew_packages.txt and installs each one using Homebrew.

#!/bin/bash

echo "🕵🏾‍♂️ Checking if x-tools is installed"
xcode-select --install 2>/dev/null || echo "✅X-Tools already installed"
echo "🕵🏾‍♂️ Checking if Homebrew is installed"
if command -v brew >/dev/null; then
  echo "✅ $$(brew --version) installed";
else \
  echo "👀 Homebrew not installed, installing now";
  /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)";
fi
if command -v brew >/dev/null; then
  echo "✅ Homebrew installed";
else
  echo "🤔 Something went wrong";
  exit 0;
fi

echo "🤖 Installing Homebrew packages"
pkgfile="$(pwd)/brew_packages.txt"
while IFS= read -r package || [ -n "$package" ]; do
  # strip comments and surrounding whitespace
  package="${package%%#*}"
  package="${package#"${package%%[![:space:]]*}"}"  # ltrim
  package="${package%"${package##*[![:space:]]}"}"  # rtrim
  [ -z "$package" ] && continue

  echo "🤖 Installing $package"
  brew install "$package"
done < "$pkgfile"

This is extremely convenient when setting up a new Mac, as it ensures that all of the packages that I commonly use are installed with a single command. No need to go brew list on the old machine and manually install each package on the new one. And when I want to add a new package, I just add it to the brew_packages.txt file and run the setup script again. Finally, the bash/install.sh script is run to set up the Bash environment.

Bash Setup

The bash/install.sh script which sets up the Bash environment is run on both Mac and Linux machines. It symlinks the various configuration files to the user's home directory. Let's take a look.

#!/bin/bash

# dotfiles directory
DOTFILES_DIR="$(pwd)"

# target dotfiles
DOTFILES="bash_aliases bash_config bashrc vimconfig"

echo "Installing dotfiles $DOTFILES_DIR"
for file in $DOTFILES; do
  file_name=$(echo "$file" | tr '/' '_')
  echo "$file_name"
  if [ -e "$HOME/.$file_name" ]; then
    echo "Backing up existing $HOME/.$file_name to $HOME/.$file_name.bak"
    mv "$HOME/.$file_name" "$HOME/.$file_name.bak"
  fi
  echo "Creating symlink for $file_name to $HOME/.$file_name"
  ln -sf "$DOTFILES_DIR/$file" "$HOME/.$file_name"
done
echo "Dotfiles installed"

This script iterates over a list of target dotfiles, backing up any existing files in my home directory by appending a .bak extension, and then creates symbolic links from the dotfiles in the repository to the home directory. This ensures that my environment is configured according to the settings defined in the dotfiles repository.

Conclusion

Setting up my dotfiles has greatly streamlined the process of configuring new workstations, as I experienced while setting up my new Raspberry Pi 5s. By automating the setup process, I can quickly get my development environment up and running with a mere git clone and a single script execution. This not only saves time but also ensures consistency across all my machines, allowing me to focus more on development and less on setup. If you haven't already, I highly recommend creating and using dotfiles for your own development workflow!