Automation is iteration. First you'll find a way to make it work, and share your learnings - feedback and best practices help make it even better. When I first published my dotfiles - Document and automate your Macbook setup blog post, Nate suggested to use Homebrew bundle for a more clean management approach.
Homebrew bundle follows the same idea as known from Ruby bundle, has a Brewfile
and specific keywords for packages to install.
First Steps with Homebrew Bundle
- tap: Add more brew third-party repos
- cask: Install application casks (Gimp, etc.)
- brew: Install packages
- mas: Install App store items (requires
brew install mas
)
You can also override the default cask installation path:
$ vim Brewfile
cask_args appdir: "/Applications"
tap "homebrew/cask"
cask "gimp"
brew "git"
mas "Slack", id: 803453959
Run it to see how it works.
$ brew bundle
Using homebrew/cask
Using gimp
Using git
Using Slack
Homebrew Bundle complete! 4 Brewfile dependencies now installed.
git
from Homebrew is newer than the macOS Git binary.
$ git --version
git version 2.29.2
$ /usr/bin/git --version
git version 2.24.3 (Apple Git-128)
Homebrew's Git is installed into /usr/local/bin
which has a priority in the PATH
environment variable.
$ which git
/usr/local/bin/git
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
Existing Homebrew Setup? No Problem
bundle
provides the dump
sub command which writes a new Brewfile
with your current setup.
brew bundle dump
Homebrew automatically installs the bundle
tap the first time the command is invoked, no extra preparations needed.
You can either use this file to continue working, or start fresh in your own Brewfile
. You can also manually install software first and then analyse how a dump looks like.
Caveats with GNU tools (sed, tar, ...)
You can install GNU tools to avoid different parameters and behaviour with the native UNIX representation of sed, tar, etc. Homebrew provides binaries prefixed with the g
character, so even an updated PATH variable won't help, requiring you to call gsed
instead of sed
. To keep compatibility with existing Linux scripts, I used symlinks created inside a brew setup script:
BREW_PREFIX=$(brew --prefix)
ln -s "${BREW_PREFIX}/bin/gsed" "${BREW_PREFIX}/bin/sed"
This isn't possible inside a Brewfile. Luckily this can be automated in your PATH, as the Homebrew formulas provide these symlink overrides on their own:
$ brew info gnu-sed
GNU "sed" has been installed as "gsed".
If you need to use it as "sed", you can add a "gnubin" directory
to your PATH from your bashrc like:
PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
$ ls -la /usr/local/opt/gnu-sed/libexec/gnubin
total 0
drwxr-xr-x 3 mfriedrich staff 96 Jan 15 2020 .
drwxr-xr-x 5 mfriedrich staff 160 Jan 15 2020 ..
lrwxr-xr-x 1 mfriedrich staff 14 Jan 15 2020 sed -> ../../bin/gsed
Collect the inventory from all GNU tools and render an update for your environment file. You can automate this task with this inventory snippet added to .oh-my-zsh/custom/path.zsh or .zshrc
:
# GNU utils path overrides as default CLI tools
if type brew &>/dev/null; then
HOMEBREW_PREFIX=$(brew --prefix)
for d in ${HOMEBREW_PREFIX}/opt/*/libexec/gnubin; do export PATH=$d:$PATH; done
fi
If you prefer to use symlinks, you can do so too instead of the export. Keep in mind that the PATH environment is generated on each new terminal, while symlinks can run stale.
A complete example
Follow the iteration in this merge request and open the dotfiles repository to learn more.
My Brewfile focusses on my work as Developer Evangelist at GitLab with a local Linux-ified CLI environment and Docker. Heavier workloads are shifted into cloud environments. Image manipulation tools help with automating tasks for blog posts and workshops.
I'm also not pinning specific versions for packages, this is not supported by Homebrew bundle either.
cask_args appdir: "/Applications"
# Tap Homebrew
tap "homebrew/bundle"
tap "homebrew/cask"
tap "homebrew/cask-fonts"
tap "homebrew/cask-versions"
tap "homebrew/core"
tap "homebrew/services"
cask "java"
cask "visual-studio-code"
cask "firefox"
cask "vlc"
cask "wireshark"
cask "gimp"
cask "inkscape"
cask "jitsi-meet"
cask "handbrake"
cask "vagrant"
cask "spotify"
# System
brew "mas"
brew "curl"
brew "wget"
brew "git"
brew "vim"
brew "openssl"
brew "coreutils"
brew "moreutils"
brew "findutils"
brew "binutils"
brew "rename"
brew "gnu-sed"
brew "gnu-tar"
brew "gawk"
brew "gnutls"
brew "gnu-indent"
brew "gnu-getopt"
brew "tree"
brew "htop"
brew "pidof"
brew "pstree"
brew "grep"
brew "openssh"
brew "rsync"
brew "ssh-copy-id"
brew "screen"
brew "gmp"
brew "nmap"
brew "socat"
brew "rlwrap"
brew "dnstracer"
# Images, Audio, Video
brew "imagemagick"
brew "gifsicle"
brew "gifify"
brew "ffmpeg"
# Archive & Git
brew "xz"
brew "p7zip"
brew "git"
brew "git-lfs"
brew "tig"
brew "hub"
# Extract rpm file content with rpm2cpio *.rpm | cpio -ivd
brew "rpm2cpio"
# JSON
brew "jq"
brew "jo"
# Dev
brew "ruby"
brew "yarn"
brew "rbenv"
brew "python"
brew "go"
brew "cmake"
brew "openjdk"
brew "kind"
# GitLab Pages
brew "hugo"
# App Store
mas "1Password 7", id: 1333542190
mas "Slack", id: 803453959
mas "Telegram", id: 747648890
mas "uBlock", id: 1385985095
Top comments (0)