docs: README matches the shipped installer

Documents what the code now does: git is installed by the bootstrap rather than
assumed; the full path to dotup is what to type in the session that installed
it, and why; brew is a script row that lazygit, omp and herdr @needs, so
channel order is script-before-brew; apt resolution probes for an installation
candidate, not mere existence; ^o toggles and ^t clears the query; and the
header line carries ^o.
This commit is contained in:
bcherb2
2026-08-21 22:34:53 -04:00
parent 286c3281b5
commit 805c407764
+42 -7
View File
@@ -26,6 +26,22 @@ Two commands. The first lays down the files and clones the six externals; the
second picks and installs the software. There is no third step, and nothing second picks and installs the software. There is no third step, and nothing
here prompts for anything. here prompts for anything.
**Type the second path in full.** Bare `dotup` will not be found in the shell
that ran the install, and that is not a bug in either command: Ubuntu's own
`~/.profile` adds `~/.local/bin` to `PATH` only if the directory already exists
*when you log in*. On a fresh box it does not, the install then creates it, and
the shell you are sitting in never re-reads `.profile`. A new login shell finds
it. Nothing a child process can do changes the `PATH` of its parent, so the
install prints the working path rather than pretending otherwise.
**git does not have to be installed first.** It used to: chezmoi is a static
download and installs fine, but all six `git-repo` externals need git, and
Ubuntu cloud images, WSL and the docker image all ship curl and no git — so the
documented first command failed on the most ordinary kind of fresh box there
is. `.chezmoiscripts/run_before_00-require-git.sh` installs it across
apt/dnf/yum/pacman/zypper/apk/brew, and explains itself where it cannot (no
sudo, or macOS, where `git` is a stub that opens a GUI installer).
For a machine with nobody at the keyboard: For a machine with nobody at the keyboard:
```sh ```sh
@@ -86,7 +102,7 @@ tri-state summary of their children, never an independent switch.
▸ [ ] gpu 0/3 invasive kernel modules; a bad driver can bre… ▸ [ ] gpu 0/3 invasive kernel modules; a bad driver can bre…
▸ [ ] private 0/2 private one password, typed after the install… ▸ [ ] private 0/2 private one password, typed after the install…
space tick tab open ^t tick all shown ^a defaults ^x none enter install space tick tab open ^t tick all shown ^a defaults ^x none ^o open all enter install
``` ```
**One toggle rule, everywhere.** Expand the row to the packages it covers; if **One toggle rule, everywhere.** Expand the row to the packages it covers; if
@@ -102,8 +118,16 @@ safer than something inside it.
**Dependencies tick themselves.** `@needs` closure runs in both directions: **Dependencies tick themselves.** `@needs` closure runs in both directions:
ticking `xrdp` ticks the `desktop` group it is useless without, and unticking ticking `xrdp` ticks the `desktop` group it is useless without, and unticking
`core/node` drops `codex`, `pi`, `mermaid-cli` and then `neovim`. The closure is `core/node` drops `codex`, `pi`, `pi-plugins`, `mermaid-cli` and then `neovim`
shown, not described — the counts move on the same keystroke. — six rows including `node` itself. The closure is shown, not described: the
counts move on the same keystroke, and `^t` clears the filter so the rows it
just pulled in are on screen rather than hidden behind your query.
`^o` is a toggle, not "open all": press it again and everything closes. And on
the default collapsed screen every group row counts as "shown", so a single
`^t` there reaches all 69 packages — including the invasive and private ones.
That is the documented rule working as specified, but it is worth knowing
before you press it.
### The manifest ### The manifest
@@ -114,6 +138,7 @@ sixth column is an `@` directive instead:
@needs core/neovim core/imagemagick core/mermaid-cli @needs core/neovim core/imagemagick core/mermaid-cli
@spec agents/codex @openai/codex @spec agents/codex @openai/codex
core neovim safe -tarball neovim apt ships 0.9.5 — tarball to /opt/nvim core neovim safe -tarball neovim apt ships 0.9.5 — tarball to /opt/nvim
core node safe -tarball node apt ships 18.19 and the npm rows need 20+
core fd safe fd-find fd binary is fdfind on ubuntu core fd safe fd-find fd binary is fdfind on ubuntu
``` ```
@@ -121,9 +146,19 @@ A leading `-` in the apt or brew column means "not from this package manager":
`-tarball -npm -script -snap -deb -flatpak -uv -builtin -xcode`. A bare `-` `-tarball -npm -script -snap -deb -flatpak -uv -builtin -xcode`. A bare `-`
means unavailable there — and **Linux resolves apt-then-brew, not means unavailable there — and **Linux resolves apt-then-brew, not
apt-instead-of-brew**, because `omp`, `herdr` and `lazygit` have no apt package apt-instead-of-brew**, because `omp`, `herdr` and `lazygit` have no apt package
at all. The installer goes further and probes `apt-cache` before it batches: a at all — and `core/brew` is itself a `script` row that those three `@needs`, so
name apt does not know moves to the brew column rather than failing the whole ticking `lazygit` brings Homebrew with it. On Linux that means linuxbrew, under
batch. `/home/linuxbrew/.linuxbrew`; `/usr/local` is not touched. Channel order is a
dependency graph and not a preference: `script` runs **before** `brew`, because
otherwise brew would still be missing when the rows needing it are attempted.
The installer probes `apt-cache policy` before it batches, and asks for the
installation *candidate* rather than merely whether the name is known: on stock
Ubuntu `apt-cache show docker-ce` prints nothing and **exits 0**, so an
existence test kept it in the batch, apt refused all thirty packages at once,
and the brew fallback was never reached. One unavailable name took thirty
installable ones down with it. A name with no candidate now moves to the brew
column instead.
`@spec` carries the argument a channel needs but the package name cannot supply `@spec` carries the argument a channel needs but the package name cannot supply
— the scoped npm name, the flatpak app id, the `.deb` source. It defaults to the — the scoped npm name, the flatpak app id, the `.deb` source. It defaults to the
@@ -190,7 +225,7 @@ DOTUP_TEST_IMAGE=ubuntu:22.04 sh .tests/test.sh --docker
DOTUP_TEST_IMAGE=debian:12 sh .tests/test.sh --docker DOTUP_TEST_IMAGE=debian:12 sh .tests/test.sh --docker
``` ```
101 assertions covering the toggle rule, the `@needs` closure both ways, the risk 202 assertions covering the toggle rule, the `@needs` closure both ways, the risk
model as invariants rather than prose, match confinement (two-sided: `--exact` model as invariants rather than prose, match confinement (two-sided: `--exact`
confines `nvidia` to three rows **and** fuzzy still over-matches, so removing confines `nvidia` to three rows **and** fuzzy still over-matches, so removing
`--exact` fails loudly), the fzf preflight, channel resolution on both `--exact` fails loudly), the fzf preflight, channel resolution on both