mirror of
https://github.com/Klipper4FlashForge/firmware.git
synced 2026-10-21 12:52:16 -05:00
Ship the ff-*.cfg includes in printer.base.cfg
The package installed every file the mod needs and then relied on the user
to hand-edit printer.cfg with seven [include] lines. That was the one
install step nobody could automate, because printer.cfg is the user's file
and run-append.sh may not write it -- so a freshly flashed printer had all
seven configs sitting in /usr/data/config/ and not one of them loaded, and
came up as a plain printer with no toolchanger and nothing saying so.
printer.base.cfg is ours, and the stock run.sh force-copies it to
/usr/data/config/ on every flash -- the same directory as the ff-*.cfg, so
relative includes resolve. Putting them at its end wires the mod up at
flash time and makes the undo button complete: flashing the stock
FlashForge package restores its own printer.base.cfg and the includes go
with it, leaving the ff-*.cfg as inert files rather than as a config
referencing extras that are no longer in /usr/prog.
It also retires the trap in the old instructions. "Append to printer.cfg"
is wrong for any printer that has run SAVE_CONFIG: an [include] below the
"#*#" marker makes Klipper read the whole autosave block as corruption
("modifications after header") and discard every calibrated value -- PID,
mesh, shaper, nozzle and dock positions.
Most of the documented ordering rules turn out not to exist. Nothing needs
to follow [virtual_sdcard]: virtual_sdcard registers SDCARD_PRINT_FILE and
M23 in __init__, ff_print takes them over at klippy:connect, and by then
every section is loaded. That was true of the old gcode_macro wrapper and
stayed in the docs after the move to ff_print.py. gcode_macro's
rename_existing defers to klippy:connect too, so the G28 and
SHAPER_CALIBRATE wrappers do not need their targets declared first either,
and ff-print-macros.cfg reads _FF_FILAMENT through a runtime template
lookup rather than at parse time. What survives is override order:
ff-runout.cfg after printer.filament.cfg's sensors, ff-chamber.cfg after
printer.chamber.cfg. End-of-file satisfies both.
ff_print.py's error message said "must be loaded after [virtual_sdcard]",
which pointed at the wrong problem; it can only fire when there is no
[virtual_sdcard] at all.
Both halves are checked on the replica now: case-install.sh asserts the
includes and files are present after a flash, case-recovery.sh asserts a
stock flash takes the includes away again. test_includes.py covers the
wiring in the repo -- every shipped ff-*.cfg included, every include
resolving, and the block after everything it overrides.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
f10d002cf6
commit
9b1f944293
9 files changed
+274
-39
No files matched your search
+3
-2
@@ -62,8 +62,9 @@ STOCK_BASE=work/software/klipper/config/printer.base.cfg
|
||||
OURS=payload/klipper/config/printer.base.cfg
|
||||
if [ -f "$STOCK_BASE" ] && [ -f "$OURS" ]; then
|
||||
# Compare only the section/option lines: comments and blank lines differ by
|
||||
# design, and our chamber include replaces their heater block.
|
||||
strip() { grep -vE '^\s*(#|$)' "$1" | grep -vE '^\[(heater_generic|verify_heater) chamber_heater\]|^\[include printer\.chamber\.cfg\]'; }
|
||||
# design, our chamber include replaces their heater block, and the ff-*.cfg
|
||||
# includes at the end of the file are ours (see printer.base.cfg's tail).
|
||||
strip() { grep -vE '^\s*(#|$)' "$1" | grep -vE '^\[(heater_generic|verify_heater) chamber_heater\]|^\[include printer\.chamber\.cfg\]|^\[include ff-[a-z-]+\.cfg\]'; }
|
||||
if strip "$STOCK_BASE" | diff -q - <(strip "$OURS") >/dev/null 2>&1; then
|
||||
echo ">> printer.base.cfg matches the stock file"
|
||||
else
|
||||
|
||||
+46
-15
@@ -79,14 +79,28 @@ and stay next to the machine until you trust it.
|
||||
re-run step 1 after every firmware update. The `#*#` block in
|
||||
`printer.cfg` is on the data partition and survives.
|
||||
|
||||
## Install by hand
|
||||
## Install
|
||||
|
||||
A package built from this repo installs all of this for you — see
|
||||
[building.md](building.md). What follows is the manual route, for dropping a
|
||||
single edited file onto a printer that is already modded.
|
||||
A package built from this repo needs no config editing at all. It ships:
|
||||
|
||||
On the printer (ssh as `pwned` — this assumes a jailbroken printer; how to
|
||||
get root/ssh access is covered in the community
|
||||
* the `ff_*.py` extras, into the Klipper tree it flashes (`bin/patch.sh`)
|
||||
* the `ff-*.cfg`, to `/usr/data/config/` (`run-append.sh`, keeping any you
|
||||
edited and leaving the new one as `.mod-new`)
|
||||
* the `[include]` lines for all seven, at the end of `printer.base.cfg` —
|
||||
which the stock `run.sh` force-copies to `/usr/data/config/` on every flash
|
||||
|
||||
`printer.cfg` is never touched by any of that, by design: it is the user's
|
||||
file. That is also why the includes live in `printer.base.cfg` and not there
|
||||
— and it makes the undo button work, since flashing the stock FlashForge
|
||||
package restores its own `printer.base.cfg` and the includes go with it.
|
||||
|
||||
Flash, then jump to step 5 below to import your unit's calibration.
|
||||
|
||||
### By hand
|
||||
|
||||
For dropping a single edited file onto a printer that is already modded. On
|
||||
the printer (ssh as `pwned` — this assumes a jailbroken printer; how to get
|
||||
root/ssh access is covered in the community
|
||||
[Discord](https://discord.gg/tYs3eNEDq)):
|
||||
|
||||
```sh
|
||||
@@ -99,22 +113,37 @@ scp payload/klipper/config/ff-*.cfg \
|
||||
pwned@PRINTER:/usr/data/config/
|
||||
```
|
||||
|
||||
3. Append to `/usr/data/config/printer.cfg`. **All of these are required** —
|
||||
they are not optional drop-ins, and without them Klipper comes up as a
|
||||
plain printer with no toolchanger. Order matters: they must come AFTER
|
||||
`[virtual_sdcard]` is defined, and must **not** go in
|
||||
`printer.override.cfg`, which is included first:
|
||||
3. Make sure something includes them. A flashed printer already does, at the
|
||||
end of `printer.base.cfg`. **All seven are required** — they are not
|
||||
optional drop-ins, and without them Klipper comes up as a plain printer
|
||||
with no toolchanger:
|
||||
|
||||
```ini
|
||||
[include ff-toolchange.cfg]
|
||||
[include ff-tool-offset.cfg]
|
||||
[include ff-filament.cfg]
|
||||
[include ff-print-macros.cfg] ; after ff-filament.cfg (the nozzle clean uses it)
|
||||
[include ff-print-macros.cfg]
|
||||
[include ff-runout.cfg] ; after printer.base.cfg (overrides its sensor sections)
|
||||
[include ff-chamber.cfg] ; M141/M191; follows whatever printer.chamber.cfg declared
|
||||
[include ff-legacy.cfg] ; temporary — only for step 5
|
||||
[include ff-legacy.cfg] ; harmless to leave in — see step 8
|
||||
```
|
||||
|
||||
> **If you put these in `printer.cfg` instead, they must go ABOVE the
|
||||
> `#*# <---------------------- SAVE_CONFIG ---------------------->`
|
||||
> marker.** Klipper treats any non-`#*#` line below that marker as
|
||||
> corruption, discards the entire autosave block, and every calibrated
|
||||
> value — PID, mesh, shaper, nozzle and dock positions — stops being read.
|
||||
|
||||
Only two ordering rules are real, and both are about one file overriding
|
||||
another's values, which Klipper applies in include order: `ff-runout.cfg`
|
||||
after the sensor sections in `printer.base.cfg`, and `ff-chamber.cfg`
|
||||
after `printer.chamber.cfg`. Placement relative to `[virtual_sdcard]` does
|
||||
**not** matter — `ff_print` takes `SDCARD_PRINT_FILE`/`M23` over at
|
||||
`klippy:connect`, once every section is loaded — and neither does
|
||||
placement relative to the commands the `G28` and `SHAPER_CALIBRATE`
|
||||
wrappers rename, since `gcode_macro` defers its rename to `klippy:connect`
|
||||
as well.
|
||||
|
||||
4. `RESTART` (or reboot).
|
||||
|
||||
5. Import the factory/touchscreen calibration once:
|
||||
@@ -137,8 +166,10 @@ scp payload/klipper/config/ff-*.cfg \
|
||||
nothing should say `NOT CALIBRATED`, "no dock position" or "unsaved
|
||||
calibration pending".
|
||||
|
||||
8. Remove the `[include ff-legacy.cfg]` line and `RESTART`. The import is
|
||||
one-shot; the touchscreen's JSON is not consulted again.
|
||||
8. Optionally remove the `[include ff-legacy.cfg]` line and `RESTART`. Not
|
||||
required: the import is one-shot, and `ff_legacy`'s startup auto-import
|
||||
returns early as soon as any tool has a nozzle position, so the section is
|
||||
inert once step 6 has run. A flashed printer keeps it included.
|
||||
|
||||
## Verify
|
||||
|
||||
|
||||
@@ -9,16 +9,17 @@
|
||||
# Klipper fork ships no START/END/PAUSE/RESUME/CANCEL macros. These macros
|
||||
# reproduce the app's sequences for prints started from Mainsail.
|
||||
#
|
||||
# REQUIRED -- this is not an optional drop-in; the mod does not work
|
||||
# without it. Include from printer.cfg AFTER [pause_resume], [virtual_sdcard] and
|
||||
# ff-filament.cfg (the nozzle clean reuses its helpers and tunables):
|
||||
# [include /usr/data/config/ff-filament.cfg]
|
||||
# [include /usr/data/config/ff-print-macros.cfg]
|
||||
# REQUIRED -- this is not an optional drop-in; the mod does not work without
|
||||
# it. printer.base.cfg includes it, along with the rest of the ff-*.cfg set,
|
||||
# at its end. It needs [pause_resume], [virtual_sdcard] and ff-filament.cfg
|
||||
# (the nozzle clean reuses its helpers and tunables) to EXIST, but not to come
|
||||
# first: nothing here reads their config at parse time.
|
||||
#
|
||||
# [ff_print] (klippy-extras/ff_print.py) is declared at the end of this file:
|
||||
# it wraps SDCARD_PRINT_FILE and M23 so a print prepares the machine for
|
||||
# itself, with no slicer changes at all. Those are the commands it takes over,
|
||||
# which is why this file has to be included after [virtual_sdcard].
|
||||
# itself, with no slicer changes at all. It takes those commands over at
|
||||
# klippy:connect, once every section is loaded, so it does not care whether
|
||||
# [virtual_sdcard] was declared before or after this file.
|
||||
#
|
||||
# Deliberate divergences from firmwareExe (documented in OKF/61):
|
||||
# * resume reheats all tools in parallel, not e1+e2 then e3+e4 staged
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
# ff-toolchange.cfg -- configuration for the native Creator 5 Pro toolchanger.
|
||||
#
|
||||
# Implementation: klippy-extras/ff_tool.py + ff_toolchange.py (copy both to
|
||||
# /usr/prog/klipper/klippy/extras/).
|
||||
# Implementation: klippy-extras/ff_tool.py + ff_toolchange.py. A built package
|
||||
# installs them; see INSTALL below for the by-hand route.
|
||||
#
|
||||
# It is a Python extra rather than a set of gcode_macros because firmwareExe's
|
||||
# sequence is a polling state machine -- it waits for the grab sensor to read
|
||||
@@ -66,18 +66,30 @@
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
# INSTALL
|
||||
# 1. cp klippy-extras/ff_tool.py klippy-extras/ff_toolchange.py \
|
||||
# /usr/prog/klipper/klippy/extras/
|
||||
# A package built from this repo needs none of this: bin/patch.sh puts the
|
||||
# ff_*.py extras into the Klipper tree it flashes, the stock run.sh copies
|
||||
# the ff-*.cfg to /usr/data/config/, and printer.base.cfg ships the
|
||||
# [include] lines for all of them. Flashing is the whole install.
|
||||
#
|
||||
# By hand, onto a printer that is already modded:
|
||||
# 1. cp klippy-extras/ff_*.py /usr/prog/klipper/klippy/extras/
|
||||
# (Klipper lives on the firmware partition -- klipper_pri.sh runs
|
||||
# /usr/prog/klipper/klippy/klippy.py. It may be mounted read-only, and an
|
||||
# OTA will overwrite it, so keep a copy and a re-apply script.)
|
||||
# 2. append to /usr/data/config/printer.cfg: [include ff-toolchange.cfg]
|
||||
# REQUIRED -- the whole ff-*.cfg set is mandatory, not a menu of
|
||||
# optional drop-ins. Without them Klipper comes up as a plain
|
||||
# printer: no toolchanger, no tool offsets, no runout handling.
|
||||
# It MUST come after [virtual_sdcard] -- the SDCARD_PRINT_FILE wrapper
|
||||
# below uses rename_existing. Do NOT put it in printer.override.cfg, which
|
||||
# is included first, before virtual_sdcard exists.
|
||||
# 2. cp the ff-*.cfg to /usr/data/config/ and make sure something includes
|
||||
# them -- printer.base.cfg does, at its end. All of them: the set is
|
||||
# mandatory, not a menu of optional drop-ins. Without it Klipper comes up
|
||||
# as a plain printer: no toolchanger, no tool offsets, no runout handling.
|
||||
# If you add includes to printer.cfg instead, they MUST go ABOVE its
|
||||
# "#*# <--- SAVE_CONFIG --->" marker: Klipper reads anything below that
|
||||
# marker that is not a "#*#" line as corruption and drops the entire
|
||||
# autosave block, taking every calibrated value with it.
|
||||
# Section ORDER does not matter for [virtual_sdcard] or for the G28 /
|
||||
# SHAPER_CALIBRATE wrappers below -- ff_print and gcode_macro both do
|
||||
# their command takeover at klippy:connect, after all sections load.
|
||||
# It does matter where one file overrides another's values: ff-runout.cfg
|
||||
# after printer.base.cfg's sensor sections, ff-chamber.cfg after
|
||||
# printer.chamber.cfg.
|
||||
# 3. FF_IMPORT_FIRMWARE_CONFIG + SAVE_CONFIG (see README) fills in the
|
||||
# dock and nozzle data.
|
||||
# 4. Run TOOLCHANGE_STATUS and confirm the sensor names AND the geometry
|
||||
|
||||
@@ -361,5 +361,42 @@ z_hop: 10
|
||||
z_hop_speed: 3
|
||||
move_to_previous: False
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# The mod's Klipper config. Shipped here, at the END of this file, rather than
|
||||
# hand-appended to printer.cfg -- printer.cfg is the user's and nothing in the
|
||||
# package may write it (run-append.sh), so a manual edit was the one install
|
||||
# step nobody could automate and everybody could get wrong. There is a sharp
|
||||
# edge there too: an [include] below printer.cfg's "#*# SAVE_CONFIG" marker
|
||||
# makes Klipper discard the whole autosave block ("modifications after
|
||||
# header", configfile.py), silently losing every calibrated value.
|
||||
#
|
||||
# This file is force-copied to /usr/data/config/ by the stock run.sh on every
|
||||
# flash, into the same directory as the ff-*.cfg -- so the relative includes
|
||||
# below resolve, and flashing the stock FlashForge package removes them again
|
||||
# by simply restoring its own printer.base.cfg. That is the undo button.
|
||||
#
|
||||
# REQUIRED, all of them: the ff-*.cfg set is mandatory, not a menu of optional
|
||||
# drop-ins. Without it Klipper comes up as a plain printer -- no toolchanger,
|
||||
# no tool offsets, no runout handling.
|
||||
#
|
||||
# Why the END of the file. Only two ordering rules survive, and both are
|
||||
# about overriding a config VALUE, which Klipper applies in include order:
|
||||
# ff-runout.cfg overrides the filament-sensor sections above
|
||||
# ff-chamber.cfg follows whatever printer.chamber.cfg (line 132) declared
|
||||
# Rules that used to be here and are NOT real: nothing needs to follow
|
||||
# [virtual_sdcard] (ff_print.py hooks SDCARD_PRINT_FILE/M23 at klippy:connect,
|
||||
# by which point every section exists), and gcode_macro's rename_existing
|
||||
# defers to klippy:connect too, so the G28 and SHAPER_CALIBRATE wrappers do
|
||||
# not need their targets declared earlier either.
|
||||
#
|
||||
# ff-legacy.cfg stays included permanently: its auto-import returns early as
|
||||
# soon as any tool has a nozzle position, so it is inert after the first
|
||||
# SAVE_CONFIG and costs nothing to leave in.
|
||||
# ---------------------------------------------------------------------------
|
||||
[include ff-toolchange.cfg]
|
||||
[include ff-tool-offset.cfg]
|
||||
[include ff-filament.cfg]
|
||||
[include ff-print-macros.cfg]
|
||||
[include ff-runout.cfg]
|
||||
[include ff-chamber.cfg]
|
||||
[include ff-legacy.cfg]
|
||||
@@ -157,8 +157,10 @@ class FFPrint:
|
||||
prev = self.gcode.register_command(cmd, None)
|
||||
if prev is None:
|
||||
raise self.printer.config_error(
|
||||
"ff_print: command '%s' is not registered -- [ff_print]"
|
||||
" must be loaded after [virtual_sdcard]" % (cmd,))
|
||||
"ff_print: command '%s' is not registered -- is there a"
|
||||
" [virtual_sdcard] section in the config? (Section ORDER"
|
||||
" does not matter: this runs at klippy:connect, after"
|
||||
" every section is loaded.)" % (cmd,))
|
||||
self.prev_handlers[cmd] = prev
|
||||
self.gcode.register_command(
|
||||
cmd, self._make_handler(cmd),
|
||||
|
||||
@@ -189,6 +189,22 @@ fi
|
||||
grep -q 'USER-CONFIG-MUST-SURVIVE' /usr/data/config/printer.cfg 2>/dev/null \
|
||||
&& ok "user printer.cfg preserved" || bad "user printer.cfg was clobbered"
|
||||
|
||||
# The mod's Klipper config only does anything if something includes it, and
|
||||
# printer.cfg is the user's file that the package may not write. So the
|
||||
# includes ship in printer.base.cfg. Without them the printer boots as a plain
|
||||
# machine: no toolchanger, no tool offsets, no runout handling -- and nothing
|
||||
# says so out loud, which is why this is checked here.
|
||||
MISSING=""
|
||||
for c in ff-toolchange ff-tool-offset ff-filament ff-print-macros \
|
||||
ff-runout ff-chamber ff-legacy; do
|
||||
[ -f "/usr/data/config/$c.cfg" ] || MISSING="$MISSING $c.cfg(file)"
|
||||
grep -q "^\[include $c\.cfg\]" /usr/data/config/printer.base.cfg 2>/dev/null \
|
||||
|| MISSING="$MISSING $c.cfg(include)"
|
||||
done
|
||||
[ -z "$MISSING" ] \
|
||||
&& ok "printer.base.cfg includes the whole ff-*.cfg set, and all are present" \
|
||||
|| bad "the mod's Klipper config is not wired up:$MISSING"
|
||||
|
||||
if [ -d /usr/data/anvil/backup ]; then
|
||||
n=$(find /usr/data/anvil/backup -type f | wc -l)
|
||||
[ "$n" -gt 0 ] && ok "installer wrote $n backup file(s)" || bad "backup dir is empty"
|
||||
|
||||
@@ -88,6 +88,18 @@ grep -q 'USER-CONFIG-MUST-SURVIVE' /usr/data/config/printer.cfg 2>/dev/null \
|
||||
&& ok "user printer.cfg preserved through both flashes" \
|
||||
|| bad "user printer.cfg was clobbered"
|
||||
|
||||
# The mod's Klipper config is wired in by printer.base.cfg, which the stock
|
||||
# run.sh force-copies over on every flash. That is what makes the revert
|
||||
# complete: the ff-*.cfg are left on the data partition (inert, like the rest
|
||||
# of the payload) but nothing includes them any more. If a stock reflash left
|
||||
# the includes behind, klippy would come up referencing [ff_toolchange] with
|
||||
# the extras gone from /usr/prog -- a printer that will not start.
|
||||
if grep -q '^\[include ff-' /usr/data/config/printer.base.cfg 2>/dev/null; then
|
||||
bad "printer.base.cfg still includes the mod's ff-*.cfg after a stock flash"
|
||||
else
|
||||
ok "printer.base.cfg restored -- nothing includes the mod's config"
|
||||
fi
|
||||
|
||||
echo
|
||||
[ "$FAIL" = 0 ] && echo " recovery clean: a stock package fully reverts the mod" \
|
||||
|| echo " RECOVERY TEST FAILED"
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
"""printer.base.cfg must include the whole ff-*.cfg set, in a safe place.
|
||||
|
||||
The mod's config only takes effect if something includes it, and the one file
|
||||
that may not be written by the package is printer.cfg -- it is the user's.
|
||||
So printer.base.cfg carries the includes, and this checks the two things that
|
||||
silently break if it stops:
|
||||
|
||||
* every ff-*.cfg we ship is included, and every include resolves to a file
|
||||
we ship. A new config added to payload/klipper/config/ and not wired up
|
||||
would otherwise be dead weight nobody notices.
|
||||
* the includes sit after the sections they override. Klipper applies
|
||||
includes in parse order, so ff-chamber.cfg has to follow
|
||||
printer.chamber.cfg, and ff-runout.cfg the filament sensors that
|
||||
printer.filament.cfg (included at the top) declares. Putting the block at
|
||||
the end of the file satisfies both; this fails if someone moves it up.
|
||||
|
||||
Ordering rules that are NOT checked here because they are not real: nothing
|
||||
needs to follow [virtual_sdcard], and the G28 / SHAPER_CALIBRATE wrappers do
|
||||
not need their targets declared first. ff_print and gcode_macro both take
|
||||
their commands over at klippy:connect, once every section is loaded.
|
||||
|
||||
Needs nothing proprietary: the configs are all in the repo.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
INCLUDE = re.compile(r"^\[include\s+(\S+)\]\s*$")
|
||||
|
||||
# Everything the mod ships, in the order printer.base.cfg must list them.
|
||||
# ff-runout and ff-chamber are last because they override earlier sections.
|
||||
EXPECTED = [
|
||||
"ff-toolchange.cfg",
|
||||
"ff-tool-offset.cfg",
|
||||
"ff-filament.cfg",
|
||||
"ff-print-macros.cfg",
|
||||
"ff-runout.cfg",
|
||||
"ff-chamber.cfg",
|
||||
"ff-legacy.cfg",
|
||||
]
|
||||
|
||||
|
||||
def base_cfg(cfgdir):
|
||||
return os.path.join(cfgdir, "printer.base.cfg")
|
||||
|
||||
|
||||
def includes(cfgdir):
|
||||
"""[(lineno, spec)] for every [include] in printer.base.cfg, in order."""
|
||||
out = []
|
||||
with open(base_cfg(cfgdir), encoding="utf-8", errors="replace") as fh:
|
||||
for n, raw in enumerate(fh, 1):
|
||||
m = INCLUDE.match(raw.strip())
|
||||
if m:
|
||||
out.append((n, m.group(1)))
|
||||
return out
|
||||
|
||||
|
||||
def ff_includes(cfgdir):
|
||||
return [(n, s) for n, s in includes(cfgdir) if s.startswith("ff-")]
|
||||
|
||||
|
||||
def shipped(cfgdir):
|
||||
return sorted(f for f in os.listdir(cfgdir)
|
||||
if f.startswith("ff-") and f.endswith(".cfg"))
|
||||
|
||||
|
||||
def test_some_includes_are_found(cfgdir):
|
||||
"""Guard against the regex matching nothing and every test below passing."""
|
||||
assert includes(cfgdir), "no [include] parsed from printer.base.cfg"
|
||||
|
||||
|
||||
def test_every_shipped_ff_cfg_is_included(cfgdir):
|
||||
included = {s for _, s in ff_includes(cfgdir)}
|
||||
missing = [f for f in shipped(cfgdir) if f not in included]
|
||||
assert not missing, (
|
||||
"shipped but never included, so dead on the printer: %s" % missing)
|
||||
|
||||
|
||||
def test_every_ff_include_resolves(cfgdir):
|
||||
"""A typo'd include is not a warning -- klippy refuses to start."""
|
||||
for _, spec in ff_includes(cfgdir):
|
||||
assert os.path.isfile(os.path.join(cfgdir, spec)), (
|
||||
"printer.base.cfg includes '%s', which we do not ship" % spec)
|
||||
|
||||
|
||||
def test_ff_includes_are_the_expected_set(cfgdir):
|
||||
assert [s for _, s in ff_includes(cfgdir)] == EXPECTED
|
||||
|
||||
|
||||
def test_ff_includes_come_last(cfgdir):
|
||||
"""After every other include, so an override in ours actually wins."""
|
||||
ff_lines = [n for n, _ in ff_includes(cfgdir)]
|
||||
other = [n for n, s in includes(cfgdir) if not s.startswith("ff-")]
|
||||
assert other, "printer.base.cfg no longer includes any stock config"
|
||||
assert min(ff_lines) > max(other), (
|
||||
"an ff-*.cfg include at line %d precedes a stock include at line %d "
|
||||
"-- ours must be able to override theirs" % (min(ff_lines), max(other)))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ours,theirs", [
|
||||
# ff-chamber.cfg's macros build on whatever the model's chamber declared.
|
||||
("ff-chamber.cfg", "printer.chamber.cfg"),
|
||||
# ff-runout.cfg redeclares the fd_ex*/fm_ex* sensors that file sets up.
|
||||
("ff-runout.cfg", "printer.filament.cfg"),
|
||||
])
|
||||
def test_override_follows_what_it_overrides(cfgdir, ours, theirs):
|
||||
by_spec = {s: n for n, s in includes(cfgdir)}
|
||||
for spec in (ours, theirs):
|
||||
assert spec in by_spec, "printer.base.cfg no longer includes %s" % spec
|
||||
assert by_spec[ours] > by_spec[theirs], (
|
||||
"%s (line %d) is included before %s (line %d), so its overrides lose"
|
||||
% (ours, by_spec[ours], theirs, by_spec[theirs]))
|
||||
|
||||
|
||||
def test_nothing_follows_the_ff_block(cfgdir):
|
||||
"""The block is the tail of the file; a section added after it would
|
||||
parse after our overrides and quietly win."""
|
||||
text = open(base_cfg(cfgdir), encoding="utf-8", errors="replace").read()
|
||||
tail = text.split("[include %s]" % EXPECTED[-1], 1)[1]
|
||||
stray = [l for l in tail.splitlines()
|
||||
if l.strip() and not l.lstrip().startswith("#")]
|
||||
assert not stray, "config lines after the ff-*.cfg include block: %s" % stray
|
||||
Reference in new issue
Block a user