Appendix One

Installation Script

Way back in the Getting Started chapter when I had you first create the dotfiles project I also had you create a setup.sh file. I haven’t mentioned it again since then. This book is largely about setting up a terminal based development environment, not as much about shell scripting. There are other full books written about shell scripting.

I didn’t think this book would be complete without at least a simple attempt at creating this setup.sh script though. One of the other main points I make in this book is that this development environment should be easy to move to other machines, and this script is a big part of that. So lets get started.

High Level Design

We should plan out this script a bit before we start writing it. What do we want it to do? Ideally it will install all of the tools that we need, (Z Shell, tmux and Vim) and then make the symbolic links to our configuration files in the dotfiles directory. It should be able to tell the difference between macOS and Ubuntu so the correct install tool is used (Homebrew or Apt). When the script is complete it should inform the user of any additional steps needed to finalize the setup process.

It is possible to write the script in a way that doesn’t require Git to be installed and configured already, but that would require running the script via something like curl or wget and we would end up with a bare dotfiles directory rather than a dotfiles Git repository. That would make it harder to pick up any updates made to the dotfiles project.

I’ll keep it simple in this example. It will just install the three tools being used and make the symbolic links needed. The script won’t attempt to also install any dependencies. I will have it check for them and report an error if they are not available though.

If you want to take this script further and are looking for inspiration, Github hosts a page full of different user’s dotfiles projects. You can certainly find a lot of ideas for expansion there.

Building The Script

The package names and package managers are different between macOS and Ubuntu. We need a way to tell which OS the script is running on? For macOS it is fairly straightforward. Check the OSTYPE environment variable. If it starts with darwin we know it is macOS.

For Ubuntu it’s a little bit trickier. We can still check the OSTYPE, but on Ubuntu it just reports linux-gnu. If all Linux distributions used Apt that would be fine, but that isn’t the case. We need a way to further refine the OS detection when OSTYPE is linux-gnu.

Many newer Linux distributions are using a standardized file to report the distribution name, version and other important information. It is /etc/os-release. Since we are using a newer version of Ubuntu this should be sufficient. Here is the first part of the script.

~/dotfiles/scripts/setup.sh
  #!/usr/bin/env bash
  
  # Currently only macOS and Ubuntu are supported.
  if [[ "$OSTYPE" == "darwin"* ]]; then
    # macOS Setup
  elif [[ -f /etc/os-release ]]; then
    . /etc/os-release
    if [[ "$NAME" == "Ubuntu" ]]; then
      # Ubuntu Setup
    fi
  else
    echo "Unsupported OS detected."
    exit 1
  fi

We are using bash as the scripting environment because Z Shell is not installed yet. The script checks the OSTYPE environment variable first. If it contains “darwin” we know it is macOS, otherwise the script checks to see if a file named /etc/os-release exists. If it does it reads the file and checks that the NAME value is “Ubuntu”. If neither of those conditions are met the script displays a message and exits with a non-zero value denoting an error.

Inside the macOS branch of the script we can now make sure Homebrew is installed.

~/dotfiles/scripts/setup.sh
  # macOS Setup
  # Check for or install Homebrew.
  command -v brew >/dev/null 2>&1 || /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

The command -v brew part of that command checks to see if the brew command is available. If it is that section of the or clause will be true and the second part of the or clause will not be run. If it fails then the Homebrew install script is run.

Now the rest of the macOS section can be fleshed out. These are the same commands that were used in the other chapters to install the tools.

~/dotfiles/scripts/setup.sh
  #macOS Setup
  ...
  # Install Z Shell, Oh My Zsh and make Z Shell the default
  brew install zsh zsh-completions
  sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
  chsh -s $(which zsh)
  mv ~/.zshrc ~/dotfiles/zsh/.zshrc
  ln -s ~/dotfiles/zsh/.zshrc ~/.zshrc
  
  # Install tmux
  brew install tmux
  ln -s ~/dotfiles/tmux/.tmux.conf
  
  # Install Vim
  brew install vim
  mkdir ~/.vim
  ln -s ~/dotfiles/vim/.vimrc ~/.vim/.vimrc

Refer to the Install (Neo)Vim section and modify the script as necessary if you would rather install Neovim.

Finishing up the Ubuntu section is also straightforward. The only hiccup is that the Ubuntu commands all use sudo, which requires a password. You can actually get sudo to gather the password before you use it in the rest of the script. Using sudo -v will validate the password for sudo and allow the remaining sudo commands to run normally. I’ve also added the -y argument to the Apt install commands to automatically respond ‘yes’ to the ‘are you sure you want to install’ prompts.

~/dotfiles/scripts/setup.sh
  # Ubuntu Setup
  sudo -v
  
  # Make sure apt is updated
  sudo apt-get update
  
  # Install Z Shell, Oh My Zsh and make Z Shell the default
  sudo apt install -y zsh
  sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
  chsh -s $(which zsh)
  mv ~/.zshrc ~/dotfiles/zsh/.zshrc
  ln -s ~/dotfiles/zsh/.zshrc ~/.zshrc
  
  # Install tmux
  sudo apt install -y tmux
  ln -s ~/dotfiles/tmux/.tmux.conf
  
  # Install Vim
  sudo apt install -y vim
  mkdir ~/.vim
  ln -s ~/dotfiles/vim/.vimrc ~/.vim/.vimrc

There are some final setup steps in the script to install Minpac and add the Powerline fonts. The code is the same as what is shown in the Vim Plugins and Theme Wrap Up sections, so there should be no surprises there. You can find the complete script in the code download. Feel free to modify it to your own needs.