Managing preference plists under Chezmoi
Chezmoi handles my dotfiles, and it allows me to painlessly go to great levels of configuration management across machines. There’s one difficult type of configuration to deal with on Mac, though: binary .plist
files.
Take Soulver, for example, which stores its font settings in UserDefaults. This results in a binary plist in ~/Library/Preferences
which contains information changed on each run of the app. It is a great example of what not to check into source control.
My solution is using a modify
script, which Chezmoi calls with the current version of the file looking for a modified version in response. The script for Soulver is stored in modify_private_app.soulver.mac.plist
:
source "$(chezmoi source-path)/path/to/plist.sh"
pl SV_CUSTOM_FONT_NAME -string CUSTOM_FONT
pl SV_CUSTOM_FONT_POST_SCRIPT_NAME -string "Input-Regular"
pl SV_FONT_SIZE -integer 16
This is relatively stable, but more prone to breaking than a concretely-defined settings file format, of course. This uses a helper script named plist.sh
which acts as a thin wrapper around plutil
while minimizing the amount of boilerplate:
set -e
TMPFILE=$(mktemp)
trap "cat $TMPFILE; rm $TMPFILE" EXIT
function pl() {
# test before setting because plutil _will_ mutate the file
# macOS 12.+, you can use plutil like:
# CURRENT=$(plutil -extract $1 raw $TMPFILE 2>/dev/null || :)
CURRENT=$(/usr/libexec/PlistBuddy -c "Print :$1" $TMPFILE 2>/dev/null || :)
if [ "$CURRENT" != "$3" ]; then
plutil -replace $* "$TMPFILE"
fi
}
cat <&0 >$TMPFILE
if [ ! -s $TMPFILE ]; then
# plutil will error if it encounters an empty file
# macOS 12.+ you can use plutil like:
# plutil -create binary1 $TMPFILE
echo "{}" | plutil -convert binary1 -o $TMPFILE -
fi
Now my Soulver settings are synced and updated using Chezmoi, and I don’t have to keep track of which apps I need to visit if I decide I want to play with a different font.
I recently looked at every programming font I could find; here are my favorites in order: