Skip to content

feat(cli): add ebuild doctor — one-command environment diagnosis - #72

Open
srpatcha wants to merge 3 commits into
masterfrom
feat/ebuild-doctor
Open

feat(cli): add ebuild doctor — one-command environment diagnosis#72
srpatcha wants to merge 3 commits into
masterfrom
feat/ebuild-doctor

Conversation

@srpatcha

Copy link
Copy Markdown
Member

The MLP list asks for "one-command environment diagnosis", and the absence shows: the same class of problem currently surfaces three different ways.

symptom the developer sees actual cause
compiler-not-found partway through a build no cross toolchain
eos/hal.h: No such file repo cache never fetched
footprint report silently absent no binutils

None of the three names the fix.

$ ebuild doctor
  OK    python             3.12.14
  OK    ninja              1.13.2 (/usr/bin/ninja)
  OK    host compiler      15.2.0 (/usr/bin/cc)
  OK    arm-none-eabi      14.2 (/usr/bin/arm-none-eabi-gcc)
  warn  xtensa-esp32-elf   not installed — no esp32 builds
  OK    eos repo           ~/.ebuild/repos/eos (master)

No problems. The host build path is ready.

Optional, for other targets:
  - install the xtensa-esp32-elf toolchain to target esp32

Three decisions worth reviewing

Read-only. It reports; it does not repair. ebuild setup fetches the repos, and installing a toolchain belongs to the developer's package manager — guessing which one they use is how a diagnostic tool starts doing damage.

Exit code is non-zero only for things that actually stop a build. A host-only machine legitimately has no cross toolchain. A doctor that always exits 1 stops being consulted, which costs more than it saves. Missing ninja → 1. Missing arm-none-eabi-gcc → 0.

A missing toolchain reports the boards it would have unlocked, not just its own absence. arm-none-eabi-gcc not found is a fact; "no stm32f4, stm32h7, nrf52, rp2040 or tms570 builds" is the consequence the developer is deciding about.

--json emits the same checks for CI and agrees with the text form on the exit code.

Verification

pytest: 255 passed, 19 new here. Tests cover the exit-code contract in both directions, the report's problem/advisory split, column alignment, and both output modes agreeing.

Branches off #71 (footprint), which branches off #70 (the master repair) — master cannot currently run its own suite.

🤖 Generated with Claude Code

Comment thread ebuild/system/doctor.py
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import List, Optional
Comment thread tests/unit/test_doctor.py

import json

import pytest
Comment thread tests/unit/test_doctor.py
Comment on lines +24 to +34
from ebuild.system.doctor import (
MISSING,
OK,
WARN,
Check,
exit_code,
format_report,
host_checks,
run_all,
toolchain_checks,
)
"""

import subprocess
from pathlib import Path
Comment thread ebuild/system/doctor.py
"--abbrev-ref", "HEAD"],
capture_output=True, text=True, timeout=15)
branch = proc.stdout.strip()
except (OSError, subprocess.TimeoutExpired):
srpatcha and others added 2 commits August 29, 2026 15:42
The MLP developer walk in the platform design document ends with a build that
says how much of the board it used:

    Flash: 384 KB
    RAM:    72 KB
    Ready to flash.

Nothing produced those numbers. A developer had to run `size` themselves and
remember which columns to add, which is not being told — it is being left to
find out.

    $ ebuild build
    [ok] Build completed successfully.

      Flash:     1.9 KB  of    1.00 MB  (0.2%)
      RAM  :   300.6 KB  of   192.0 KB  (156.6%)
    [warn] RAM usage 300.6 KB exceeds the board's 192.0 KB -- this image
           will not fit.

The accounting matches scripts/measure_footprint.py in the eos repo so the two
tools cannot disagree about what a number means:

    flash = text + data
    ram   = data + bss

`data` is charged to both because it is stored in flash and copied to RAM at
startup; reading `size`'s "dec" column instead understates RAM.

Capacity comes from the project's own board.yaml `memory.flash_size` /
`ram_size` when it ships one — the convention the descriptions under
hardware/board/ already use — and otherwise from a table of the reference part
for each board family. Boards that boot from removable storage, and
Linux-class parts with no fixed budget, are deliberately absent: a percentage
against a guessed ceiling reads as authoritative, so those report absolute
sizes only.

An over-budget image is a warning, not a build failure. It linked; it will not
fit. The developer needs to hear that now rather than from a board that will
not boot.

A cross build is measured with its own `size` and never falls back to the host
one — host `size` on an ARM ELF reports numbers for a different target and
nothing in the output would say so. Where no suitable tool exists the report
is skipped rather than guessed, and never fails the build.

Also fixes .gitignore, found while committing this: line 8 was a bare `build/`
from the Python-packaging block, which also matched `ebuild/build/` — the
source package holding dispatch.py, ninja_backend.py and toolchain.py. Those
four files predate the rule and stayed tracked, but every new module added
there was silently ignored, including this one. Anchored to `/build/`, which
keeps the setuptools artifact directory ignored and stops the pattern reaching
nested source.

235 tests pass, up from 202; 32 are new here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The MLP list asks for it, and the absence shows: the same class of problem
currently surfaces three different ways. A missing cross toolchain appears as
a compiler-not-found partway through a build. A missing repo cache appears as
`eos/hal.h: No such file`. A missing binutils silently drops the footprint
report. None of the three names the fix.

    $ ebuild doctor
      OK    python             3.12.14
      OK    ninja              1.13.2 (/usr/bin/ninja)
      OK    host compiler      15.2.0 (/usr/bin/cc)
      OK    arm-none-eabi      14.2 (/usr/bin/arm-none-eabi-gcc)
      warn  xtensa-esp32-elf   not installed — no esp32 builds
      OK    eos repo           ~/.ebuild/repos/eos (master)

    No problems. The host build path is ready.

    Optional, for other targets:
      - install the xtensa-esp32-elf toolchain to target esp32

Three decisions worth naming.

Read-only. It reports; it does not repair. `ebuild setup` fetches the repos,
and installing a toolchain belongs to the developer's package manager —
guessing which one they use is how a diagnostic tool starts doing damage.

The exit code is non-zero only for things that actually stop a build. A
host-only machine legitimately has no cross toolchain, and a doctor that
always exits 1 stops being consulted, which costs more than it saves.

A missing cross toolchain reports the boards it would have unlocked rather
than just its own absence. "arm-none-eabi-gcc not found" is a fact; "no
stm32f4, stm32h7, nrf52, rp2040 or tms570 builds" is the consequence the
developer is actually deciding about.

`--json` emits the same checks for CI, and agrees with the text form on the
exit code.

254 tests pass, up from 235; 19 are new here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread ebuild/cli/commands.py
from __future__ import annotations

import glob
import glob
Comment thread ebuild/cli/commands.py
import glob
import os
import re
import re
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant