mirror of
https://github.com/Klipper4FlashForge/firmware.git
synced 2026-10-22 13:22:16 -05:00
A sweep for comments and messages that describe machinery this tree no longer
has. Each one read as current and was not.
* bin/verify.sh, retired two commits before this branch, was still named as
the thing `make release` and docs/building.md were explaining the absence
of. The absence needs no explaining -- `make qa-replica` is the gate.
* `make test-recovery` does not exist. docs/hardware-testing.md told owners
it "used to" prove the stock rollback; the useful half of that -- nothing
tests the rollback today, treat it as unverified -- is kept and the dead
target name is not. runFirmwareExe.sh pointed at it too.
* run-append.sh in bin/build-payload.py, case-install.sh in
docs/printer-replica.md: both files are gone.
* `make test`/`make test-py` over test/, and the note that both suites run
in CI "until a case-*.sh has a green replacement" -- test/ was deleted and
there are no case scripts left to replace.
* docs/building.md still said a package carries the software component.
CI's shellcheck globs are the one real defect this turned up. Two of the four
-- pkgs/*/payload/init.d/S* and pkgs/*/prog/*.sh -- match nothing: the recipes
stopped using both paths, and payload/prog/ is where those scripts live now.
shellcheck given a pattern that expands to nothing writes usage to stderr and
exits 1, so that step has been failing for its globs rather than for the code.
Fixed to the paths that exist, with a pointer to
qa/static/test_shell_syntax.py, which addresses the same files and refuses a
glob that matches nothing -- the guard this step did not have.
Verified: the corrected invocation runs clean over the 21 files it now
matches, and 112 static tests pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CH7Yb4wuPhnppHAB25UX7e
112 lines
4.2 KiB
Python
Executable File
112 lines
4.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Build $MODDIR by installing the feed inside the printer replica.
|
|
|
|
./bin/build-payload.py <root-package> [<root-package> ...]
|
|
|
|
Writes the installed tree to $PAYLOAD_DIR, replacing whatever was there.
|
|
|
|
The printer's OWN opkg installs onto the printer's own filesystem, under
|
|
qemu-mipsel, and the tree is tarred back out -- so maintainer scripts run
|
|
where they will run on a machine, and the install that ships is the install
|
|
that was tested.
|
|
|
|
WHAT IT COSTS. A privileged container and the printer image, which is why
|
|
`make build` has its own docker lane. The feed itself
|
|
(bin/build-packages.sh) still needs nothing but a checkout.
|
|
"""
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
for _p in Path(__file__).resolve().parents:
|
|
if (_p / "bin" / "common.sh").is_file():
|
|
ROOT = _p
|
|
sys.path.insert(0, str(_p / "tools" / "replica"))
|
|
break
|
|
|
|
from ffsim import cli # noqa: E402
|
|
from ffsim.config import Config # noqa: E402
|
|
from ffsim.replica import Replica # noqa: E402
|
|
|
|
CASE = "tools/replica/printer/case-build-payload.sh"
|
|
|
|
|
|
def _sh(var, default=""):
|
|
"""One value out of bin/common.sh, asked of the shell that defines it.
|
|
|
|
Re-deriving IPK_ARCH or PKG_FEED here would be a second place for them to
|
|
be wrong, and the two would agree until somebody edited one.
|
|
"""
|
|
out = subprocess.run(
|
|
["bash", "-c", '. "%s/bin/common.sh" >/dev/null 2>&1; printf "%%s" "${%s:-%s}"'
|
|
% (ROOT, var, default)],
|
|
capture_output=True, text=True, cwd=str(ROOT))
|
|
return out.stdout.strip()
|
|
|
|
|
|
def run():
|
|
roots = sys.argv[1:]
|
|
if not roots:
|
|
raise SystemExit("usage: build-payload.py <root-package> ...")
|
|
|
|
feed = Path(_sh("PKG_FEED", str(ROOT / "work" / "packages")))
|
|
payload_dir = Path(_sh("PAYLOAD_DIR"))
|
|
if not payload_dir.is_absolute() and not str(payload_dir).startswith(str(ROOT)):
|
|
payload_dir = ROOT / payload_dir
|
|
|
|
ipks = sorted(feed.glob("*.ipk"))
|
|
if not ipks:
|
|
raise SystemExit("no feed at %s -- run ./bin/build-packages.sh" % feed)
|
|
index = feed / "Packages"
|
|
if not index.is_file():
|
|
raise SystemExit("no Packages index at %s" % index)
|
|
|
|
# Everything the printer's opkg needs, on the simulated stick at /mnt: the
|
|
# archives and the index that names them. `packages` is the replica's own
|
|
# mechanism for this and copies each to /mnt/<name>.
|
|
packages = {p.name: str(p) for p in ipks}
|
|
packages[index.name] = str(index)
|
|
|
|
config = Config.load()
|
|
replica = Replica.start(config)
|
|
out = ROOT / "work" / ".payload-out"
|
|
replica.run_case(
|
|
ROOT / CASE, packages=packages, out_dir=out, on_output=_echo,
|
|
env={
|
|
"MOD_ROOTS": " ".join(roots),
|
|
"IPK_ARCH": _sh("IPK_ARCH", "mipsel_xburst2"),
|
|
"SOURCE_DATE_EPOCH": os.environ.get("SOURCE_DATE_EPOCH", "1"),
|
|
# The case compiles the s6-rc database and stamps it db-$MOD_VER.
|
|
# Asked of common.sh like every other value here, so the database
|
|
# name and the package versions cannot come from two clocks.
|
|
"MOD_VER": _sh("MOD_VER"),
|
|
})
|
|
|
|
tar = out / "payload.tar"
|
|
if not tar.is_file():
|
|
raise SystemExit("the replica produced no payload.tar")
|
|
|
|
# Replace, never merge: a surviving file from a previous build is one no
|
|
# package accounts for, and the manifest would ship it as though it did.
|
|
if payload_dir.exists():
|
|
subprocess.run(["rm", "-rf", str(payload_dir)], check=True)
|
|
payload_dir.mkdir(parents=True)
|
|
# --strip-components=1 drops the leading anvil/ the case tarred with.
|
|
# No -p and no --same-owner: the archive carries the printer's root, this
|
|
# runs as the build user, and runFirmwareExe.sh extracts as root on the
|
|
# machine -- ownership in the payload means nothing.
|
|
subprocess.run(["tar", "-xf", str(tar), "-C", str(payload_dir),
|
|
"--strip-components=1"], check=True)
|
|
subprocess.run(["rm", "-rf", str(out)], check=True)
|
|
_echo("payload: %s" % payload_dir)
|
|
|
|
|
|
def _echo(text):
|
|
sys.stdout.write(str(text).rstrip("\n") + "\n")
|
|
sys.stdout.flush()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(cli.main(run))
|