summaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
blob: c4813dbd29ab5beb7c773c95623e402c47cc0e8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# sbo-dockerbuild

Docker-based toolchain for test-building [SlackBuilds.org (SBo)](https://slackbuilds.org)
packages on Slackware, on both `-current` and `15.0`, in throwaway containers.

Extracted from the `.extras/` dir of the **sbo-slackbuilds** package repo (danix's
SBo maintenance mirror) once it grew from a helper into a standalone tool. Git
history starts fresh here; the original 41-commit log is preserved in
[HISTORY.md](HISTORY.md) (those hashes refer to sbo-slackbuilds, not this repo).

## What this repo is (and is not)

This is the **tooling**, not packages. It builds and consumes docker images to
verify that a SlackBuild still builds; it does not itself contain SlackBuilds.
The packages live in the maintenance repo (sbo-slackbuilds) and other repos.

Two cooperating tools, one shared set of images:

- **`test-build`** — verify a single SlackBuild builds cleanly in a container.
- **`image-builder/`** — build the images `test-build` consumes.

## Layout

```
test-build                 the test-build tool (single bash script)
install.sh                 copy test-build into ~/bin (BINDIR= to override)
test-logic.sh              pure-logic self-check for test-build (no docker)
test-build-config.example  copy to ~/.config/sbo-testbuild/config and edit
overrides.example          current-vs-stable dep overrides (optional)
image-builder/             bootstrap.sh, build-full-image.sh,
                           build-sbo-testbuild.sh, lib.sh, config,
                           test-image-builder.sh, README
docs/specs, docs/plans     design specs and implementation plans
```

Everything is at the repo root (flat), not under `.extras/` — that nesting was a
sbo-slackbuilds convention and does not apply here.

## test-build

Resolves and builds a SlackBuild in a disposable Slackware container, then lints
it. The **target** is the local SlackBuild under edit; its **dependencies** come
from a configured SBo tree. These are two different sources — do not conflate
them (an earlier bug resolved the target from the tree, testing the published
version instead of the edit).

### Target resolution (`resolve_target_dir`)

Repo-agnostic, driven by where you are:

- a **path** (absolute, `./x`, or containing `/`): that directory
- a **bare name**: `./<name>/` under CWD, else CWD itself if it *is* `<name>/`

So `cd pkgdir && test-build <name>`, `test-build /path/to/pkg`, and
`test-build ./pkg` all work.

### Dependency resolution

Deps are resolved from the SBo tree in the config (`SBO_TREE_CURRENT` /
`SBO_TREE_STABLE`), topologically sorted, cycle-checked. A dep is satisfied by:

1. building it from the tree (recursively), or
2. `installed_in_base` — already present in the full-install image (queried once
   per run from the image's `/var/log/packages`), or
3. an override (see below).

Deps build first and are cached; the target always rebuilds (that is the test).

### current-vs-stable overrides

`~/.config/sbo-testbuild/overrides` (see `overrides.example`), applied **only on
-current** (15.0 is the SBo baseline). Verbs:

- `drop: <dep>` — a 15.0-only SBo dep whose payload the -current base already
  ships (e.g. `rust-opt`, `google-go-lang`, `cmake-opt`, `llvm-opt`,
  `python3-installer`, `python3-build`). Satisfied at resolution: not built, not
  UNMET.
- `rename: <old> -> <new>` — dep renamed on -current.
- `fetch: <prog>` — dep removed from the -current tree; built via `sbopkg` in
  the container.

### The build container

One `docker run --rm -i` per package (the `-i` is required — without it `bash -s`
gets no stdin and the heredoc is silently discarded). Inside, as root:
installs already-built deps, sources `/etc/profile.d/*.sh` (so dep-provided env
like google-go-lang's `GOROOT`/`PATH` is live in the non-login shell), builds the
SlackBuild, `installpkg`s it, and runs `sbopkglint` **in-container** (it shells
out to sudo, which only works as root here; never lint on the host). The host
reads a `LINT-CLEAN`/`LINT-FINDINGS` marker from the log.

### Dep cache

Host dir (`PKG_CACHE`), namespaced `<variant>-<image-digest>/`. An image rebuild
changes the digest and self-invalidates the cache. Each run prunes superseded
digests **of the same variant only**, so a `--current` run does not wipe the
`15.0` cache (both live caches survive; testing both trees back-to-back reuses
built deps). Only **deps** are cached, never the target.

### Flags

`--stable` (15.0), `--dry-run`, `--yes`, `--no-cache`, `--keep` (copy the built
target `.txz` to `<data>/kept/` so it can be installed on the host, e.g. to
regenerate post-install artifacts), `--no-color`.

## image-builder

Three chained scripts build the images, each self-gated so an unchanged night is
a cheap no-op:

- `bootstrap.sh``sbo-base:{ver}` FROM scratch (gated on the mirror's
  `ChangeLog.txt` hash)
- `build-full-image.sh``sbo-full:{ver}` all series (gated on base digest;
  `--force` prunes the build cache first)
- `build-sbo-testbuild.sh``sbo-testbuild:{ver}` + sbopkg + maintainer-tools
  (gated on full digest + tools `.txz` hash)

All settings in `image-builder/config`. Full setup (NFS mirror mounts, LAN
registry, prebuilt pkgs, cron) is in `image-builder/README`.

**Main-loop gotcha:** each script runs its `build_variant` in an `if ! (...)`
condition, which suppresses `set -e` inside the subshell. So `docker build` /
`docker push` failures are caught with **explicit** `if ! ...; return 1` checks,
not by relying on `set -e`. Keep that pattern when editing.

## Testing

Pure-logic self-checks, no docker, no network:

```bash
bash test-logic.sh                       # test-build resolver/overrides/cache
bash image-builder/test-image-builder.sh # image-builder lib.sh logic
```

Non-trivial logic changes get a check here. The docker build path itself is
verified by running `test-build` against a real image.

## Conventions

- Plain bash, single-file scripts where practical, minimal dependencies.
- `set -euo pipefail` in executables; guard `set -e` around subshell conditions
  (see the image-builder gotcha).
- GPLv2-only. Every source file carries a short GPL header notice.
- No em dashes in prose.

## Releases

SemVer, starting at `1.0.0`. The version is a baked `PROJECT_VERSION="X.Y.Z"`
const in every script (`test-build`, `install.sh`, and the three
`image-builder/*.sh`); there is no VERSION file. `test-build` and `install.sh`
expose `-V`/`--version`; the image-builder scripts already use `--version` for
the Slackware target, so their project-version flag is `-V` only.

To cut a release (bump `X.Y.Z`):

```bash
sed -i 's/^PROJECT_VERSION="[^"]*"/PROJECT_VERSION="X.Y.Z"/' \
    test-build install.sh image-builder/*.sh
git commit -aS -m "release X.Y.Z"
git tag -s vX.Y.Z -m "vX.Y.Z"
git push origin master --tags          # both remotes (danix_git + forge)
tea release create --repo danix/sbo-dockerbuild --tag vX.Y.Z --title vX.Y.Z
```

The `sed` anchors on `^PROJECT_VERSION="..."`, which never matches the SBo
package `VERSION=`/`OPT_VERSION=` vars, so it only touches the project const.

## Deployment

The image-builder scripts run on the docker host VM (`docker.noland.dnx`,
reached via the `docker` SSH host alias, root login), deployed under
`/opt/sbo-testbuild/image-builder/`. A nightly cron rebuilds both variants after
the repo syncs. Treat the VM as outward-facing: confirm before deploying, and
inspect a target before overwriting it. After editing a script here, sync it to
the VM so the cron runs the current version.