fix: disk picker fd0 (#112), menu Back guard (#106), offline theme (#113)
Some checks failed
Check / eval (push) Has been cancelled
Some checks failed
Check / eval (push) Has been cancelled
- #112: list_installable_disks drops fd/loop/sr/zram/<8GiB, largest-first so OVMF no longer offers /dev/fd0 as the default wipe target - #106: tools/check-menu-back.py + checks.menu-back (proved to fail) - #113: offline theme-switch contract documented (default/pinned only); theme-sync run_switch adds offline-oriented hint when no network Verified: V0 flake check; installer-safety; menu-back; py_compile.
This commit is contained in:
@@ -72,6 +72,25 @@ check(
|
||||
"missing online-only compose-lock fallback warn",
|
||||
)
|
||||
|
||||
# ── 1b. Disk picker: exclude floppy/pseudo/tiny (#112) ─────────────────
|
||||
check(
|
||||
"list_installable_disks" in script,
|
||||
"missing list_installable_disks helper (#112)",
|
||||
)
|
||||
check(
|
||||
"/dev/fd*" in script or r"/dev/fd*" in script,
|
||||
"disk filter must exclude /dev/fd* (floppy — OVMF lists fd0 first)",
|
||||
)
|
||||
check(
|
||||
"MIN_DISK_BYTES" in script,
|
||||
"disk filter must enforce a minimum size floor",
|
||||
)
|
||||
check(
|
||||
"8 * 1024 * 1024 * 1024" in script or "8 * 1024**3" in script
|
||||
or "$((8 * 1024 * 1024 * 1024))" in script,
|
||||
"default min disk size should be 8 GiB (catches fd0 and crumbs)",
|
||||
)
|
||||
|
||||
# ── 2. Disk signature warn ──────────────────────────────────────────────
|
||||
sig_re = re.search(
|
||||
r"grep -qiE '([^']+)'\s*<<<\s*\"\$existing_sig\"",
|
||||
|
||||
94
tools/check-menu-back.py
Normal file
94
tools/check-menu-back.py
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Guard the nomarchy-menu Back/Left contract (BACKLOG #106).
|
||||
|
||||
Every *internal* list picker built with `rofi_menu` must emit the shared
|
||||
`↩ Back` row (via `back`, `printf … "$BACK"`, or a literal). External
|
||||
modi/tools and free-text prompts are listed as exceptions — Esc is their
|
||||
back path.
|
||||
|
||||
Usage: check-menu-back.py <modules/home/rofi.nix>
|
||||
Pure — no rofi runtime. Fails on a list menu that can strand the user.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit(f"usage: {sys.argv[0]} <rofi.nix>")
|
||||
|
||||
text = Path(sys.argv[1]).read_text(encoding="utf-8")
|
||||
|
||||
# Strip Nix multi-line comments lightly? Keep simple — work on the whole file.
|
||||
# Find `| rofi_menu` call sites (possibly with line breaks before `|`).
|
||||
# Look at a window of lines before each call for BACK emission.
|
||||
|
||||
lines = text.splitlines()
|
||||
|
||||
# Exception markers: if the window mentions these, allow no BACK row.
|
||||
EXCEPTION_MARKERS = (
|
||||
"External tool:",
|
||||
"external modi",
|
||||
"Esc closes",
|
||||
"Esc is their back",
|
||||
"free-text",
|
||||
"Free-text",
|
||||
"no list to",
|
||||
"rofi_menu -p search", # web: empty stdin free-text
|
||||
"rofi_menu -p ask",
|
||||
# calc/emoji/network are exec-only without rofi_menu list construction
|
||||
)
|
||||
|
||||
def window_has_back(chunk: str) -> bool:
|
||||
# Shared helpers emit ↩ Back: bare `back`, printf of $BACK, or a literal.
|
||||
if re.search(r"(?m)^\s*back\s*$", chunk):
|
||||
return True
|
||||
if re.search(r"\bback\b", chunk) and "back()" not in chunk.split("rofi_menu")[0][-20:]:
|
||||
# `back` as a command (not only the word in comments). Prefer line-start.
|
||||
if re.search(r"(?m)^\s*back\b", chunk):
|
||||
return True
|
||||
if "$BACK" in chunk or r"\$BACK" in chunk or "↩ Back" in chunk:
|
||||
return True
|
||||
if re.search(r'printf[^\n]*BACK', chunk):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def window_is_exception(chunk: str) -> bool:
|
||||
return any(m in chunk for m in EXCEPTION_MARKERS)
|
||||
|
||||
|
||||
# Match lines that invoke rofi_menu as a picker (not the function definition).
|
||||
invoke_re = re.compile(r"\brofi_menu\b")
|
||||
bad: list[str] = []
|
||||
for i, line in enumerate(lines):
|
||||
if "rofi_menu()" in line or "rofi_menu ()" in line:
|
||||
continue
|
||||
if not invoke_re.search(line):
|
||||
continue
|
||||
# Skip comments and the definition of the helper's docs.
|
||||
stripped = line.lstrip()
|
||||
if stripped.startswith("#"):
|
||||
continue
|
||||
# Window: up to 40 lines before this call (menu construction).
|
||||
start = max(0, i - 40)
|
||||
chunk = "\n".join(lines[start : i + 1])
|
||||
if window_is_exception(chunk):
|
||||
continue
|
||||
# Free-text: empty stdin piped in
|
||||
if re.search(r"rofi_menu[^\n]*<\s*/dev/null", chunk) or re.search(
|
||||
r"rofi_menu[^\n]*\n[^\n]*<\s*/dev/null", chunk
|
||||
):
|
||||
continue
|
||||
if not window_has_back(chunk):
|
||||
bad.append(f"line {i + 1}: rofi_menu without ↩ Back in preceding construction:\n {line.strip()}")
|
||||
|
||||
if bad:
|
||||
print("check-menu-back: FAIL — internal list menus must end with ↩ Back:\n", file=sys.stderr)
|
||||
for b in bad:
|
||||
print(b, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"check-menu-back: ok — {sum(1 for l in lines if invoke_re.search(l) and 'rofi_menu()' not in l)} rofi_menu sites scanned")
|
||||
Reference in New Issue
Block a user