|
|
@@ -0,0 +1,147 @@
|
|
|
+# Dotfiles
|
|
|
+
|
|
|
+Manages dotfiles, packages, and system state across multiple machines, with
|
|
|
+per-host and per-group overrides.
|
|
|
+
|
|
|
+## Quick start
|
|
|
+
|
|
|
+ curl https://git.capella.pro/capella/dotfiles/raw/master/start | bash -s -- sync
|
|
|
+
|
|
|
+Or if already installed:
|
|
|
+
|
|
|
+ dotsync
|
|
|
+
|
|
|
+## Usage
|
|
|
+
|
|
|
+ start sync [--machine|--group <name>] [dot_file]
|
|
|
+ start list
|
|
|
+ start status
|
|
|
+ start packages [install|diff|save]
|
|
|
+
|
|
|
+`sync` also commits and pushes the repo. It is unprivileged and fast;
|
|
|
+`packages` needs sudo, so it is deliberately not run as part of `sync`.
|
|
|
+
|
|
|
+## Repository layout
|
|
|
+
|
|
|
+ dots/ # common dotfiles (all hosts)
|
|
|
+ dots.<hostname>/ # host-specific dotfiles
|
|
|
+ dots.@<group>/ # group-level dotfiles
|
|
|
+
|
|
|
+ to_sync[.<hostname>|.@<group>] # which dotfiles to deploy
|
|
|
+ pkglist[.<hostname>|.@<group>] # which packages to install
|
|
|
+ groups.<hostname> # group membership, one per line
|
|
|
+
|
|
|
+ start # this tool
|
|
|
+ bootstrap # system state that needs root (see below)
|
|
|
+
|
|
|
+## Multi-host
|
|
|
+
|
|
|
+Each host is identified by its hostname (`uname -n`).
|
|
|
+
|
|
|
+### File overrides
|
|
|
+
|
|
|
+Resolution order (**last wins**): common -> groups (alphabetical) -> host.
|
|
|
+
|
|
|
+A host copy of a file replaces the common one entirely, so host overrides
|
|
|
+must be complete files, not fragments.
|
|
|
+
|
|
|
+### Sync lists
|
|
|
+
|
|
|
+ to_sync # files synced to all hosts
|
|
|
+ to_sync.<hostname> # additional files for a specific host
|
|
|
+ to_sync.@<group> # additional files for a group
|
|
|
+
|
|
|
+### Groups
|
|
|
+
|
|
|
+ groups.<hostname> # one group name per line
|
|
|
+
|
|
|
+Example `groups.jellyfish`:
|
|
|
+
|
|
|
+ wayland
|
|
|
+
|
|
|
+Hosts in the same group share `to_sync.@<group>`, `dots.@<group>/` and
|
|
|
+`pkglist.@<group>`.
|
|
|
+
|
|
|
+### In-file markers
|
|
|
+
|
|
|
+For files that are mostly shared with a few per-host differences,
|
|
|
+use markers instead of duplicating the whole file:
|
|
|
+
|
|
|
+ # @host jellyfish
|
|
|
+ set $mod Mod4
|
|
|
+ # @end
|
|
|
+
|
|
|
+ # @host tompot
|
|
|
+ set $mod Mod1
|
|
|
+ # @end
|
|
|
+
|
|
|
+ # @group wayland
|
|
|
+ exec waybar
|
|
|
+ # @end
|
|
|
+
|
|
|
+- Lines between `@host <name>` and `@end` are included only on that host
|
|
|
+- Lines between `@group <name>` and `@end` are included for hosts in that group
|
|
|
+- Lines outside any markers are always included
|
|
|
+- The comment prefix (`#`, `//`, `;`, etc.) is auto-detected
|
|
|
+- Files with markers are processed and written (not symlinked)
|
|
|
+- Files without markers are symlinked as usual
|
|
|
+
|
|
|
+Generated files carry a `DO NOT EDIT` header naming their source. Edit the
|
|
|
+file under `dots/`, not the copy in `$HOME`.
|
|
|
+
|
|
|
+## Adding dotfiles
|
|
|
+
|
|
|
+ # Add to common (all hosts):
|
|
|
+ dotsync sync .config/foo
|
|
|
+
|
|
|
+ # Add for this host only:
|
|
|
+ dotsync sync --machine .config/bar
|
|
|
+
|
|
|
+ # Add for a group:
|
|
|
+ dotsync sync --group wayland .config/baz
|
|
|
+
|
|
|
+## Packages
|
|
|
+
|
|
|
+ dotsync packages # install tracked packages missing here
|
|
|
+ dotsync packages diff # show drift both ways, change nothing
|
|
|
+ dotsync packages save # write this host's packages to pkglist.<hostname>
|
|
|
+
|
|
|
+Package lists are **additive**, not last-wins: `pkglist`, `pkglist.@<group>`
|
|
|
+and `pkglist.<hostname>` are unioned. A host list adds to the common one and
|
|
|
+can never remove from it. This is the opposite of how dotfiles resolve --
|
|
|
+overriding makes sense for a config file, not for a package set.
|
|
|
+
|
|
|
+Put a package in `pkglist` when you want it everywhere, and in
|
|
|
+`pkglist.<hostname>` only when it is genuinely specific to that machine
|
|
|
+(hardware, or a role the other hosts do not have).
|
|
|
+
|
|
|
+Lists record **explicitly installed** packages only (`yay -Qqe`), so packages
|
|
|
+pulled in as dependencies stay out and get resolved automatically. Locally
|
|
|
+built `-debug` artifacts are filtered out: makepkg generates them on whichever
|
|
|
+machine did the build, and they are not installable elsewhere.
|
|
|
+
|
|
|
+`packages` never removes anything. Dropping an entry from a list makes it show
|
|
|
+up under "installed but NOT tracked" in `diff`; uninstall it yourself. A sync
|
|
|
+command that can silently uninstall is not worth the convenience.
|
|
|
+
|
|
|
+## System state
|
|
|
+
|
|
|
+`bootstrap` covers what dotsync cannot: things outside `$HOME` that need root.
|
|
|
+
|
|
|
+ ./bootstrap
|
|
|
+
|
|
|
+It is idempotent -- files are only written when their content differs, and
|
|
|
+units are skipped when already enabled, or when the package providing them is
|
|
|
+not installed on this host. Run it after `dotsync packages`.
|
|
|
+
|
|
|
+Currently it manages:
|
|
|
+
|
|
|
+- `KillUserProcesses=no`, as a logind drop-in so package upgrades cannot revert
|
|
|
+ it (the default kills `etterminal` and takes the whole `etserver` down)
|
|
|
+- `greetd` autologin into sway
|
|
|
+- `iwd` stop timeout
|
|
|
+- enabling the system and user units the desktop needs
|
|
|
+
|
|
|
+It needs a real terminal, since sudo has to prompt. Host differences use a
|
|
|
+plain `case $(uname -n)`, not `@host` markers -- those only apply to files
|
|
|
+deployed into `$HOME`.
|