Compare commits
1 Commits
2abd8aba00
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 40d3b21e71 |
149
AGENTS.md
Normal file
149
AGENTS.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# AGENTS.md
|
||||
|
||||
Guidance for coding agents working in this repository.
|
||||
|
||||
## What this is
|
||||
|
||||
A set of Bash scripts that automate building OpenWrt from source: install the
|
||||
host dependencies, fetch the source tree, import a device's official
|
||||
configuration, and apply a per-device package list.
|
||||
|
||||
There is no build system, no test suite and no dependency manifest. The
|
||||
deliverable *is* the scripts. Everything is plain Bash plus `curl`/`wget`,
|
||||
`git`, `awk`, `sed` and `python3` (only for reading JSON — `jq` is deliberately
|
||||
not required).
|
||||
|
||||
The governing design rule: **a new OpenWrt release must not require editing any
|
||||
file here.** Anything version specific is fetched from `downloads.openwrt.org`
|
||||
at run time; only the user's own package choices are stored in git. Reject
|
||||
changes that would reintroduce a version-pinned file, a hardcoded device table
|
||||
or a copied-in package list.
|
||||
|
||||
## Repository layout
|
||||
|
||||
This repository is `helper/` *inside* an OpenWrt source tree. `prepare-openwrt.sh`
|
||||
puts it there on first run:
|
||||
|
||||
```
|
||||
<parent>/openwrt/ OpenWrt source root (not this repository)
|
||||
<parent>/openwrt/helper/ this repository
|
||||
<parent>/openwrt-build-helper symlink to openwrt/helper, for stale shells
|
||||
```
|
||||
|
||||
```
|
||||
helper/
|
||||
*.sh the scripts
|
||||
lib-openwrt-upstream.sh shared library, sourced not executed
|
||||
packages/<device-id>.txt tracked: the user's packages for one device
|
||||
.generated/ ignored: combined lists, saved buildinfo
|
||||
README.md user-facing documentation
|
||||
```
|
||||
|
||||
`<device-id>` is the official OpenWrt profile id (`linksys_mx8500`), so the
|
||||
filename, the `--device` argument and upstream's `profiles.json` key are always
|
||||
the same string.
|
||||
|
||||
## Where the scripts run from
|
||||
|
||||
Two groups, and mixing them up is the most common mistake:
|
||||
|
||||
- `prepare-openwrt-env.sh` and `prepare-openwrt.sh` run from **this directory**;
|
||||
they exist to create the OpenWrt tree, so they cannot assume one.
|
||||
- Everything else runs from the **OpenWrt root** (`./helper/<script>.sh`) because
|
||||
it reads or writes `.config`, `feeds/`, `tmp/` or `package/`. Each of those
|
||||
guards its entry point — `require_openwrt_root` from the library, or an
|
||||
equivalent inline test for `feeds.conf.default` + `Makefile`. Keep that guard
|
||||
when adding a script to this group. The exception is `gen-package-list.sh`,
|
||||
which only produces text: it needs the tree for version detection (or
|
||||
`--version`) and delegates the root check to `add-openwrt-packages.sh` on
|
||||
`--apply`.
|
||||
|
||||
Never derive the OpenWrt root from `$0`'s parent alone: the compat symlink means
|
||||
the script may be invoked through a path outside the tree. Resolve with
|
||||
`pwd -P`, and use `find_openwrt_root` when a version query must be anchored to
|
||||
the OpenWrt tree rather than to this repository's own git checkout.
|
||||
|
||||
## The scripts
|
||||
|
||||
| Script | Role |
|
||||
|---|---|
|
||||
| `prepare-openwrt-env.sh` | install host build dependencies; dispatches on the package manager (apt/dnf/yum/pacman/zypper/apk) |
|
||||
| `prepare-openwrt.sh` | clone or update the OpenWrt tree, relocate this repository into it |
|
||||
| `lib-openwrt-upstream.sh` | shared upstream access: URLs, caching, version detection, device lookup |
|
||||
| `download-config.sh` | install a device's official `config.buildinfo` as `.config` |
|
||||
| `gen-package-list.sh` | built-in packages from `profiles.json` + `packages/<id>.txt` |
|
||||
| `add-openwrt-packages.sh` | apply a package list to `.config` |
|
||||
| `update-go-path.sh` | point the build at an installed Go toolchain |
|
||||
| `add-external-repos.sh` | clone extra package repositories into `package/` |
|
||||
|
||||
Only `download-config.sh` and `gen-package-list.sh` source the library; it is
|
||||
guarded against double-sourcing by `_OWRT_LIB_LOADED`.
|
||||
|
||||
## Conventions
|
||||
|
||||
Match the existing style rather than introducing your own:
|
||||
|
||||
- `set -euo pipefail` and `umask 022` at the top of every executable script
|
||||
(`add-external-repos.sh` predates the convention and still uses bare
|
||||
`set -e`). The library sets nothing — the caller owns shell options.
|
||||
- The usage block is the file's own header comment, printed by
|
||||
`usage() { sed -n '<start>,<end>p' "$0" | sed 's/^# \{0,1\}//;s/^#$//'; }`.
|
||||
**Editing the header changes `--help`** — keep the line range correct, and
|
||||
update the header whenever you add an option.
|
||||
- All logging goes to **stderr** (`info`/`warn`/`err`). Functions return their
|
||||
value on stdout, so a stray `echo` to stdout corrupts `VAR="$(fn)"` at the
|
||||
call site. This has broken the code before.
|
||||
- Every destructive command goes through `run`, so `--dry-run` prints instead of
|
||||
acting; every prompt goes through `confirm`, so `-y` skips it. Both honour the
|
||||
`DRY_RUN` / `ASSUME_YES` globals.
|
||||
- Read-only discovery first, mutation after the confirmation prompt. Aborting at
|
||||
the prompt must leave the filesystem untouched.
|
||||
- Write to a temp file and validate before replacing something that matters;
|
||||
keep a `.bak`.
|
||||
- Tunables are `${VAR:-default}` so they can be overridden from the environment
|
||||
without editing the file.
|
||||
|
||||
Bash traps that have actually bitten this code:
|
||||
|
||||
- `local a="$1" b="$a"` — bash expands every word before assigning any, so `$a`
|
||||
is unset under `set -u`. Use one `local` per dependent variable.
|
||||
- `nullglob` only drops words that *contain* a wildcard; a literal path such as
|
||||
`/usr/local/go/` survives even when it does not exist. Check with `-d`.
|
||||
- `cmd | grep -q` under `pipefail` can fail on SIGPIPE. Prefer a pipe-free form.
|
||||
- In `awk -F'\t'`, `$2` is not whitespace-split. Extract with string operations
|
||||
when the field separator is not space.
|
||||
- `git checkout <ref>` is a no-op when HEAD is already at `<ref>`, so it does not
|
||||
restore deleted tracked files.
|
||||
|
||||
## Data files
|
||||
|
||||
`packages/<device-id>.txt` is hand written and holds **only** the user's extra
|
||||
packages — never the built-in set, which is always generated. Format:
|
||||
|
||||
```
|
||||
curl luci-app-ttyd whitespace separated, any number per line, applied as =y
|
||||
-luci-app-wol leading '-' removes a package (=n)
|
||||
##module following packages are set to =m
|
||||
##remove ... =n
|
||||
##built-in ... back to =y (the default)
|
||||
pkg # note text after a single '#' is a comment
|
||||
```
|
||||
|
||||
`.generated/` is git-ignored build output. Do not commit it, and do not make
|
||||
anything depend on a file in it existing.
|
||||
|
||||
## Checking your work
|
||||
|
||||
There is no test runner. Before committing:
|
||||
|
||||
- `bash -n <script>` on everything you touched.
|
||||
- `shellcheck` if available.
|
||||
- Run the script with `-n/--dry-run` and with `-h`; confirm `-h` still prints the
|
||||
full option list (the `sed` line range drifts silently).
|
||||
- Behaviour-changing edits to config handling deserve a real check against a
|
||||
concrete device: generate before and after, and diff the resulting sets of
|
||||
`=y` packages. Do not claim equivalence you have not diffed.
|
||||
|
||||
Assume the user's machine is not the only target: no absolute home paths, no
|
||||
assumption of a distro, an init system, or WSL. Platform-specific advice belongs
|
||||
in the README under an explicit conditional heading.
|
||||
32
README.md
32
README.md
@@ -89,6 +89,9 @@ make -j$(nproc) download world
|
||||
|
||||
## Scripts
|
||||
|
||||
Every script takes `-h/--help` and prints its full option list; the summaries
|
||||
below cover the options worth knowing about.
|
||||
|
||||
- **prepare-openwrt-env.sh** — installs the build dependencies from the official
|
||||
build system guide. Dispatches on the package manager rather than guessing from
|
||||
the distro version, and probes every package against the running release so a
|
||||
@@ -111,14 +114,21 @@ make -j$(nproc) download world
|
||||
the selected device and strips the buildbot flags (see below).
|
||||
`--device <id>`, `--target <t>`, `--version <ver>`, `--snapshot`,
|
||||
`--with-packages`, `--all-profiles`, `--keep-buildbot-flags`,
|
||||
`--save-buildinfo`, `--offline`, `--output <file>`, `-y`, `-n`.
|
||||
`--save-buildinfo`, `--offline`, `--output <file>`, `--refresh`,
|
||||
`--skip-defconfig`, `-y`, `-n`.
|
||||
|
||||
- **gen-package-list.sh** — builds the complete package list: the built-in part
|
||||
from the target's `profiles.json` (`default_packages` + `device_packages` plus
|
||||
the two packages the Firmware Selector adds), combined with your
|
||||
`packages/<device-id>.txt`.
|
||||
`--device <id>`, `--apply`, `--init-extras`, `--stdout`, `--full-stdout`,
|
||||
`--out <path>`, `--no-extras`, `-y`, `-n`.
|
||||
`--device <id>`, `--target <t>`, `--version <ver>`, `--snapshot`,
|
||||
`--apply`, `--init-extras`, `--extras-file <f>`, `--no-extras-file`,
|
||||
`--stdout`, `--full-stdout`, `--out <path>`, `--extras "<pkgs>"`,
|
||||
`--no-extras`, `--wrap <cols>`, `--refresh`, `-y`, `-n`.
|
||||
|
||||
`--extras`/`--no-extras` control the two packages the Firmware Selector adds
|
||||
on top of the target's own set; `--extras-file`/`--no-extras-file` control
|
||||
your `packages/<device-id>.txt`. They are different things.
|
||||
|
||||
- **add-openwrt-packages.sh** — applies a package list to `.config`. Rewrites
|
||||
existing `CONFIG_PACKAGE_` lines in place, so repeated runs do not grow the
|
||||
@@ -130,7 +140,7 @@ make -j$(nproc) download world
|
||||
`--external` clears `CONFIG_GOLANG_BUILD_BOOTSTRAP` so the installed toolchain
|
||||
builds host Go directly instead of OpenWrt building the whole bootstrap chain
|
||||
from source.
|
||||
`--external`, `--go-root <dir>`, `-n`.
|
||||
`--external`, `--go-root <dir>`, `--skip-defconfig`, `-n`.
|
||||
|
||||
- **add-external-repos.sh** — clones extra package repositories into `package/`.
|
||||
Edit the `REPOS` array to change the list.
|
||||
@@ -167,13 +177,17 @@ install an arbitrary kmod from your own build output.
|
||||
### Go packages
|
||||
Packages such as tailscale, adguardhome, easytier and cloudflared need a host Go.
|
||||
By default OpenWrt builds the entire bootstrap chain from source, which works but
|
||||
is slow. To skip it, install a Go matching the version the tree expects and run:
|
||||
is slow. To skip it, install a Go from your distribution (or from go.dev) at
|
||||
least as new as the version the tree expects, then run:
|
||||
|
||||
```bash
|
||||
sudo apt install golang-1.24-go
|
||||
./helper/update-go-path.sh --external
|
||||
```
|
||||
|
||||
The script searches `/usr/lib/go-*`, `/usr/local/go` and `/usr/lib/golang`,
|
||||
picks the newest, and warns if it is older than the bootstrap version the tree
|
||||
asks for. Point it elsewhere with `--go-root <dir>`.
|
||||
|
||||
### WSL: Windows PATH breaks Go package builds
|
||||
On WSL, `PATH` includes Windows directories containing spaces and parentheses
|
||||
(`/mnt/c/Program Files (x86)/...`). OpenWrt's Go build recipe interpolates `PATH`
|
||||
@@ -239,7 +253,9 @@ git clean -xdf -e /helper
|
||||
files unless you pass `--force`.
|
||||
- Scripts write under `package/` and `feeds/` inside your OpenWrt tree.
|
||||
|
||||
## License and authorship
|
||||
## Contributing and authorship
|
||||
|
||||
- Scripts authored by Zhe Yuan.
|
||||
- License: MIT (unless you choose a different license; update this line accordingly).
|
||||
- No `LICENSE` file is present yet; add one before redistributing.
|
||||
- [AGENTS.md](AGENTS.md) documents the layout, the shell conventions and the
|
||||
invariants to preserve — read it before changing a script.
|
||||
|
||||
Reference in New Issue
Block a user