ui: toast per-type durations, Details modal for long errors, concise acme.sh failure summary

This commit is contained in:
2026-09-03 03:29:50 +00:00
parent 7e6fd71bdc
commit d78b90db00
5 changed files with 146 additions and 16 deletions
+27 -5
View File
@@ -98,11 +98,15 @@ def _run_acme(args: list[str]) -> str:
*args,
# Append the full transcript to $ACME_HOME/acme.sh.log so manual
# runs (whose stdout is captured below) leave a persistent record
# of the raw CA exchange. Last on purpose: acme.sh treats the next
# token after --log as its optional file argument, so a trailing
# --log defaults the log to $LE_CONFIG_HOME/acme.sh.log and can
# never swallow a real argument.
# of the raw CA exchange. The log file is passed explicitly (never
# as a bare trailing --log): a valueless trailing --log makes
# acme.sh's arg loop double-shift under dash (the --log branch
# shifts once, then the loop's trailing `shift 1` runs with zero
# positional params) and fails with "shift: can't shift that many"
# (exit 2). The explicit path keeps the same default destination
# ($LE_CONFIG_HOME/acme.sh.log) and can never swallow a real arg.
"--log",
str(Path(acme_home_env) / "acme.sh.log"),
]
try:
@@ -125,12 +129,30 @@ def _run_acme(args: list[str]) -> str:
if result.returncode != 0:
logger.error("acme.sh failed (rc=%d): %s", result.returncode, output.strip())
raise RuntimeError(
f"acme.sh failed with exit code {result.returncode}: {output.strip()}"
f"acme.sh failed with exit code {result.returncode}: "
f"{_summarize_acme_output(output)}"
)
return output
def _summarize_acme_output(output: str) -> str:
"""Reduce raw acme.sh output to a concise, human-readable summary.
acme.sh prints timestamped transcript lines; the failure reason is
in the final lines (e.g. "The retryafter=86400 value is too large
(> 600), will not retry anymore."). Strips per-line timestamps and
the "Please check log file" pointer so the summary stays toast-
sized. The full transcript remains in the log and acme.sh.log.
"""
lines = [line.strip() for line in output.strip().splitlines() if line.strip()]
lines = [re.sub(r"^\[[^\]]*\] ", "", line) for line in lines]
lines = [line for line in lines if not line.startswith("Please check log file")]
if not lines:
return "(no output)"
return "; ".join(lines[-2:])
def set_email(email: str) -> None:
"""Configure the default ACME contact email.