Managing Dotfiles with a Makefile
Assumed Knowledge: make, GPG, git.
Makefiles are great for managing dotfiles. They can do anything:
- Copy standard configs.
- Track changes.
- Keep separate versions for each computer.
- Securely handle secret files with passwords.
- Handle crontab.
The Setup
Mine looks like this:
1config/:
2 aerc cava khard rofi tut picom.conf
3 alacritty cmus lf s vdirsyncer powerbash.sh
4 amfora dunst ncmpcpp sc-im waybar powerbashrc
5 bat gtk-3.0 newsraft sway zathura redshift.conf
6 bottom himalaya procps systemd compton.conf
7 bugwarrior i3 profanity task mpd.conf
8 calcurse i3blocks qutebrowser tspreed mpv.conf
9
10home/:
11 gnupg mozilla vim bash_profile gitconfig inputrc xinitrc
12 local unison w3m bashrc gitignore_global tmux.conf Xresources
Hard Links
Standard configs are made with hard links, rather than soft. No need to destroy files, replace them with soft links, then remove the soft links and replace them with copies, then back again.
Just make hard links, and every change to that file will be tracked in your dot-files repo.
Command-Based Files
Some files are usually created through commands, like ~/.gitconfig.
These can change on different computers, as you add git lfs on one, or a credential helper on another.
So if you don't want to keep them in sync, you can just put the universal commands into a Makefile.
If your name ever changes, then all computers receive that change, but nothing will touch the strange git helpers installed on that old laptop.
1$(HOME)/.gitconfig: git.mk
2 git config --global user.name "$yerName"
3 [ ... ]
The same approach lets you manage secrets.
For example, you can set the secret token value in glab (the Gitlab CLI tool):
1git_token != pass gitlab-token
2glab config set token "$(git_token)" --host gitlab.com
Secrets Management
You can use pass to manage secrets with make.
For example, to keep ~/.config/aerc/accounts.conf as a secret file, just throw it into pass:
1cat ~/.config/aerc/accounts.conf | pass insert --echo config/aerc/accounts.conf
Add this file as a secret, and make a rule to create these secrets from all the files in ~/.password-store/:
1secrets += ${HOME}/.config/aerc/accounts.conf
2
3$(secrets): ${HOME}/.% : ${HOME}/.password-store/%.gpg
4 mkdir -p $(@D)
5 chmod 700 $(@D)
6 gpg --quiet --decrypt $< > $@
7 chmod 600 $@
Handling Crontab
Changes in different computers' crontab files can inflict a lot of merges.
Avoid this by just making each set of tasks its own file:
1echo '@daily import_events.sh "https://dmz.rs/events.ical"' > extra/cron/calendar
2echo '@hourly mbsync -a' > extra/cron/email
Combine the lot with cat, then import this into cron:
1cron.txt: $(wildcard extra/cron/*)
2 cat $^ > $@
3 crontab $@
Example Repo
You can find my basic setup here:
1ssh -p 2222 soft.dmz.rs -t mkdots
Or just clone the repo and see how it works:
1git clone ssh://soft.dmz.rs:2222/mkdots .dots
2cd .dots
3make -n