One command from fresh Fedora to the front door
`boot` is the script the README now leads with: curl it, and it installs git if the machine lacks it, clones the repository to PANAMA_PATH, and hands off to ./install -- reattaching the terminal first, because a piped stdin would strand the interview. Deliberately dumb: a curled copy leaves the repository the moment it runs, so nothing that can drift lives in it. Re-running is the recovery path: an existing clone is fast-forwarded, never re-cloned, and a refused fast-forward installs from what is there rather than stopping mid-repair. All of it pinned by the boot contract, against stub git and a throwaway clone.
This commit is contained in:
@@ -3,11 +3,23 @@
|
|||||||
Formerly Sunhat. A personal config for Fedora, with the intention of helping a
|
Formerly Sunhat. A personal config for Fedora, with the intention of helping a
|
||||||
user set up their Fedora system with one command.
|
user set up their Fedora system with one command.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot)
|
||||||
|
```
|
||||||
|
|
||||||
|
`boot` installs git if the machine lacks it, clones this repository to
|
||||||
|
`~/.local/share/Panama` (or `$PANAMA_PATH`), and hands off to `install`. It is
|
||||||
|
deliberately small enough to read first, and the same two steps by hand work
|
||||||
|
identically:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://git.gbrown.org/gib/Panama.git ~/.local/share/Panama
|
git clone https://git.gbrown.org/gib/Panama.git ~/.local/share/Panama
|
||||||
~/.local/share/Panama/install
|
~/.local/share/Panama/install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Both are safe to run again: an existing clone is fast-forwarded rather than
|
||||||
|
replaced, and `install` is the upgrade path.
|
||||||
|
|
||||||
`install` asks its questions first and then runs the stages in `setup/scripts/`
|
`install` asks its questions first and then runs the stages in `setup/scripts/`
|
||||||
in order, without stopping again:
|
in order, without stopping again:
|
||||||
|
|
||||||
@@ -101,7 +113,7 @@ docs/ Settings reference, and the design specs behind the work
|
|||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
131 of them, under `tests/`. Run the lot, or a subset by pattern:
|
132 of them, under `tests/`. Run the lot, or a subset by pattern:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
panama test # everything
|
panama test # everything
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Panama's front door: the one command a fresh Fedora machine needs.
|
||||||
|
#
|
||||||
|
# bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot)
|
||||||
|
#
|
||||||
|
# Deliberately dumb, because a copy of this script leaves the repository the
|
||||||
|
# moment somebody curls it -- nothing here can be fixed by re-running
|
||||||
|
# ./install, so there is as little here as possible: get git, get the clone,
|
||||||
|
# hand off. Everything with judgment in it lives in `install`, which is also
|
||||||
|
# where re-runs and upgrades already work.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_URL="https://git.gbrown.org/gib/Panama.git"
|
||||||
|
PANAMA_PATH="${PANAMA_PATH:-$HOME/.local/share/Panama}"
|
||||||
|
export PANAMA_PATH
|
||||||
|
|
||||||
|
# Root would put the clone and every dotfile in root's home and run the
|
||||||
|
# desktop setup for the wrong user. sudo is used inside where it is needed.
|
||||||
|
if [[ "$(id -u)" -eq 0 ]]; then
|
||||||
|
echo "Run this as your own user, not root: the install configures YOUR desktop." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Panama assumes Fedora's repositories, package names, and GNOME base install.
|
||||||
|
if ! grep -qi '^ID=fedora' /etc/os-release 2>/dev/null; then
|
||||||
|
echo "This looks like something other than Fedora; Panama only supports Fedora Workstation." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# git is the one dependency the clone itself needs. Everything else -- gum
|
||||||
|
# included -- is bootstrapped by `install`.
|
||||||
|
if ! command -v git >/dev/null 2>&1; then
|
||||||
|
echo "Installing git, which the clone needs"
|
||||||
|
sudo dnf install -y git
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d "$PANAMA_PATH/.git" ]]; then
|
||||||
|
# An existing clone makes this the recovery command too. Only a fast-forward:
|
||||||
|
# local work is never rewritten, and a diverged clone still installs from
|
||||||
|
# what it has rather than stopping someone mid-repair.
|
||||||
|
echo "Panama is already cloned at $PANAMA_PATH; updating"
|
||||||
|
git -C "$PANAMA_PATH" pull --ff-only \
|
||||||
|
|| echo "Could not fast-forward; installing from the clone as it is" >&2
|
||||||
|
else
|
||||||
|
git clone "$REPO_URL" "$PANAMA_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# `curl | bash` and `bash <(curl ...)` can leave stdin as the pipe, and the
|
||||||
|
# first thing install runs is the interview, which has to be able to ask.
|
||||||
|
# Reattach the terminal when there is one; without one the interview will say
|
||||||
|
# so itself.
|
||||||
|
# The probe actually opens /dev/tty rather than testing -r: a process with no
|
||||||
|
# controlling terminal passes -r and then fails the redirect.
|
||||||
|
if [[ ! -t 0 ]] && (exec </dev/tty) 2>/dev/null; then
|
||||||
|
exec "$PANAMA_PATH/install" </dev/tty
|
||||||
|
fi
|
||||||
|
exec "$PANAMA_PATH/install"
|
||||||
Executable
+104
@@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# The front door: `boot` is the script the README tells a fresh machine to
|
||||||
|
# curl, so it runs before anything else Panama ships -- including its own
|
||||||
|
# tests. What it must get right is small and worth pinning:
|
||||||
|
#
|
||||||
|
# * a machine without the clone gets one, from the documented URL, at
|
||||||
|
# PANAMA_PATH, and the install runs
|
||||||
|
# * a machine with the clone is not re-cloned -- the same command is the
|
||||||
|
# recovery command -- and a fast-forward failure does not stop the install
|
||||||
|
# * boot hands off to the clone's own install, with PANAMA_PATH exported,
|
||||||
|
# so a clone at a chosen location installs from that location
|
||||||
|
#
|
||||||
|
# Run against stub git and install in a throwaway PANAMA_PATH; nothing here
|
||||||
|
# touches the real clone or the network.
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
boot="$repo_dir/boot"
|
||||||
|
|
||||||
|
findings=()
|
||||||
|
note() { findings+=("$1"); }
|
||||||
|
|
||||||
|
[[ -x "$boot" ]] || { printf 'boot contract: %s is not executable\n' "$boot" >&2; exit 1; }
|
||||||
|
|
||||||
|
work="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$work"' EXIT
|
||||||
|
|
||||||
|
calls="$work/calls"
|
||||||
|
stub_dir="$work/bin"
|
||||||
|
clone_dir="$work/Panama"
|
||||||
|
mkdir -p "$stub_dir"
|
||||||
|
|
||||||
|
# The stub install records that it ran and what PANAMA_PATH it saw. The stub
|
||||||
|
# git records its arguments, and materializes a clone the way the real one
|
||||||
|
# would -- boot execs the clone's install, so the clone has to contain one.
|
||||||
|
cat >"$work/fake-install" <<STUB
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
printf 'install PANAMA_PATH=%s\n' "\${PANAMA_PATH:-unset}" >>"$calls"
|
||||||
|
STUB
|
||||||
|
chmod +x "$work/fake-install"
|
||||||
|
|
||||||
|
cat >"$stub_dir/git" <<STUB
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
printf 'git %s\n' "\$*" >>"$calls"
|
||||||
|
if [[ "\$1" == "clone" ]]; then
|
||||||
|
mkdir -p "\$3/.git"
|
||||||
|
cp "$work/fake-install" "\$3/install"
|
||||||
|
fi
|
||||||
|
STUB
|
||||||
|
chmod +x "$stub_dir/git"
|
||||||
|
|
||||||
|
run_boot() {
|
||||||
|
: >"$calls"
|
||||||
|
PATH="$stub_dir:$PATH" PANAMA_PATH="$clone_dir" bash "$boot" </dev/null >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── A machine without the clone ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
run_boot || note 'boot failed on a machine without the clone'
|
||||||
|
|
||||||
|
grep -q "git clone https://git.gbrown.org/gib/Panama.git $clone_dir" "$calls" \
|
||||||
|
|| note 'boot does not clone the documented repository to PANAMA_PATH'
|
||||||
|
grep -q "install PANAMA_PATH=$clone_dir" "$calls" \
|
||||||
|
|| note 'boot does not hand off to the clone'\''s install with PANAMA_PATH exported'
|
||||||
|
|
||||||
|
# ── A machine that already has it ────────────────────────────────────────────
|
||||||
|
|
||||||
|
run_boot || note 'boot failed on a machine that already has the clone'
|
||||||
|
|
||||||
|
grep -q 'git clone' "$calls" \
|
||||||
|
&& note 'boot re-clones over an existing checkout'
|
||||||
|
grep -q 'git -C .* pull --ff-only' "$calls" \
|
||||||
|
|| note 'boot does not fast-forward an existing clone'
|
||||||
|
grep -q "install PANAMA_PATH=$clone_dir" "$calls" \
|
||||||
|
|| note 'boot does not run the install from an existing clone'
|
||||||
|
|
||||||
|
# ── A diverged clone still installs ──────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# pull --ff-only refusing is normal life -- local commits, a rebase upstream.
|
||||||
|
# The command doubles as the repair path, so a refusal must be stepped over.
|
||||||
|
|
||||||
|
cat >"$stub_dir/git" <<'STUB'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
[[ "$*" == *pull* ]] && exit 1
|
||||||
|
exit 0
|
||||||
|
STUB
|
||||||
|
chmod +x "$stub_dir/git"
|
||||||
|
|
||||||
|
: >"$calls"
|
||||||
|
if ! PATH="$stub_dir:$PATH" PANAMA_PATH="$clone_dir" bash "$boot" </dev/null >/dev/null 2>&1; then
|
||||||
|
note 'a clone that cannot fast-forward stops the install instead of proceeding'
|
||||||
|
fi
|
||||||
|
grep -q "install PANAMA_PATH=$clone_dir" "$calls" \
|
||||||
|
|| note 'the install does not run when the fast-forward is refused'
|
||||||
|
|
||||||
|
if (( ${#findings[@]} > 0 )); then
|
||||||
|
printf 'boot contract: %d finding(s)\n' "${#findings[@]}" >&2
|
||||||
|
printf ' - %s\n' "${findings[@]}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'boot contract: PASS\n'
|
||||||
Reference in New Issue
Block a user