mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-12 04:53:52 -06:00
fix: keep each installer error to one sentence
Six messages on stderr ran 26 to 35 words before the option to give. Each now says the problem and the remedy in at most 25 words, and a test measures every stderr message against that budget.
This commit is contained in:
1 parent
07178f8c28
commit
63088b663f
5 files changed
+53
-27
No files matched your search
+1
-1
@@ -16,7 +16,7 @@
|
||||
# and Invoke-WebRequest throws on a cut transfer before the hash is read:
|
||||
# the site's build rewrites this line there (scripts/sitebootstrap.py).
|
||||
$mismatchAdvice = "The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
|
||||
$defaultInstallSha256 = "61176387d38c67e596c1669fee2bb3b981333ab0b808dd2e280a5a3870957738"
|
||||
$defaultInstallSha256 = "e9bfce57f1aab1123937498d7ed7913223762df755bb572b9a36f2d6a69b7a55"
|
||||
# The pin above refuses any changed byte: this cap only stops a body that
|
||||
# cannot be the installer (a sign-in portal's page) before it is hashed.
|
||||
$maximumInstallerBytes = 8MB
|
||||
|
||||
+14
-17
@@ -4423,9 +4423,9 @@ def fetch_manifest(plat: str) -> dict:
|
||||
# request, so the revision is what has no such list.
|
||||
print(f" No file list for {plat} at {RELEASE_REF}.", file=sys.stderr)
|
||||
if RELEASE_REF != DEFAULT_RELEASE_REF:
|
||||
print(f" RETROBIOS_REF={RELEASE_REF} names a tag that does not exist or "
|
||||
f"predates {plat}: unset RETROBIOS_REF, or pick a tag from "
|
||||
"https://github.com/Abdess/retrobios/releases.", file=sys.stderr)
|
||||
print(f" RETROBIOS_REF={RELEASE_REF} has no list for {plat}: unset it, or "
|
||||
"pick a newer tag from https://github.com/Abdess/retrobios/releases.",
|
||||
file=sys.stderr)
|
||||
else:
|
||||
print(" The repository may be moving its files: run the same command "
|
||||
"again in a few minutes.", file=sys.stderr)
|
||||
@@ -4441,9 +4441,9 @@ def fetch_manifest(plat: str) -> dict:
|
||||
message=words if code != "network"
|
||||
else f"the file list could not be fetched: {words}")
|
||||
if code == "offline":
|
||||
print(f" No file list for {plat}: {offline_words()}. Give it with "
|
||||
f"--manifest FILE (a copy of install/{plat}.json) or "
|
||||
f"--from-pack PACK, or run {offline_undo()}.", file=sys.stderr)
|
||||
print(f" No file list for {plat}: {offline_words()}. Give --manifest FILE "
|
||||
f"(a copy of install/{plat}.json) or --from-pack PACK, or run "
|
||||
f"{offline_undo()}.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
if code != "network":
|
||||
print(f" Could not fetch the file list for {plat}.", file=sys.stderr)
|
||||
@@ -4502,9 +4502,9 @@ def fetch_targets(plat: str) -> "dict | None":
|
||||
if LOCAL.offline:
|
||||
source = (f"{LOCAL.pack.name} carries none" if LOCAL.pack is not None
|
||||
else f"{offline_named()} makes no request")
|
||||
print(f"Error: --target reads the cores of each {display_name(plat)} board from a "
|
||||
f"list, and {source}. Put install/targets/{plat}.json beside the file list "
|
||||
"named with --manifest, or run with the network.", file=sys.stderr)
|
||||
print(f"Error: no {display_name(plat)} board list here ({source}). Put "
|
||||
f"install/targets/{plat}.json beside the --manifest file, or go online.",
|
||||
file=sys.stderr)
|
||||
sys.exit(2)
|
||||
url = TARGETS_URL.format(platform=plat)
|
||||
try:
|
||||
@@ -14011,9 +14011,8 @@ def main() -> None:
|
||||
and not (named and named not in TARGET_PLATFORMS)):
|
||||
# No list can be at hand: a pack carries one, and so can the folder
|
||||
# of a --manifest (targets/<platform>.json).
|
||||
parser.error("--target and --list-targets read a core list from the network, "
|
||||
f"which {offline_named()} does not use: name a pack with --from-pack, "
|
||||
"or a file list with --manifest and targets/<platform>.json beside it")
|
||||
parser.error(f"--target needs a core list, which {offline_named()} does not fetch: "
|
||||
"give --from-pack, or --manifest with targets/<platform>.json beside it")
|
||||
install_bounded_opener()
|
||||
if getattr(args, "from") and (
|
||||
args.list_platforms or args.list_targets or args.list_systems
|
||||
@@ -15207,8 +15206,7 @@ def card_install_dest(named: str, plat: str, interactive: bool, ask: bool = True
|
||||
message=f"{system} keeps its BIOS files on its SD card, and no "
|
||||
"card was named with --dest")
|
||||
print(f" {system} keeps its BIOS files on its SD card, not on this machine. "
|
||||
f"Mount the card and name its root with --dest, for example: {example}",
|
||||
file=sys.stderr)
|
||||
f"Mount it and give its root with --dest: {example}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
print(f" {system} keeps its BIOS files {card_where(system, setup.below)}, not on "
|
||||
"this machine. "
|
||||
@@ -15393,9 +15391,8 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
kind = _output_kind(real_stdout)
|
||||
where = f"Output goes to a {kind}" if kind else "Output is not a terminal"
|
||||
undo = "the pipe" if kind == "pipe" else "the redirection"
|
||||
print(f"{where}, so nothing is asked: the run goes on as with --no-input. "
|
||||
f"Add --no-input to say so, or run it without {undo} to answer.",
|
||||
file=sys.stderr)
|
||||
print(f"{where}, so nothing is asked. Add --no-input to say so, or run it "
|
||||
f"without {undo} to answer.", file=sys.stderr)
|
||||
OUTPUT.verbose = bool(getattr(args, "verbose", False))
|
||||
OUTPUT.where_said = False
|
||||
detail(f"{term.bold('RetroBIOS')} {term.dim(installer_id())}\n")
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/ins
|
||||
# curl or wget stop on a cut transfer before the hash is read: the site's
|
||||
# build rewrites this line there (scripts/sitebootstrap.py).
|
||||
MISMATCH_ADVICE="The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
|
||||
DEFAULT_INSTALL_SHA256="61176387d38c67e596c1669fee2bb3b981333ab0b808dd2e280a5a3870957738"
|
||||
DEFAULT_INSTALL_SHA256="e9bfce57f1aab1123937498d7ed7913223762df755bb572b9a36f2d6a69b7a55"
|
||||
# The pin above refuses any changed byte: this cap only stops a body that
|
||||
# cannot be the installer (a sign-in portal's page) before it is hashed.
|
||||
MAX_INSTALLER_BYTES=8388608
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
{
|
||||
"dest": "roms/ports/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1143258,
|
||||
"sha256": "61176387d38c67e596c1669fee2bb3b981333ab0b808dd2e280a5a3870957738",
|
||||
"size": 1142976,
|
||||
"sha256": "e9bfce57f1aab1123937498d7ed7913223762df755bb572b9a36f2d6a69b7a55",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -71,8 +71,8 @@
|
||||
"muos": {
|
||||
"archive": {
|
||||
"dest": "ARCHIVE/RetroBIOS.muxapp",
|
||||
"size": 1196883,
|
||||
"sha256": "2c84115b87ed4bcd4fdf4d64d56fc1221485cbd9822cfeb0770b07b9b4226e51"
|
||||
"size": 1196601,
|
||||
"sha256": "9305dd087110937f9c4c2d08cf4b52aa55dc0c8835109991f913e23ca30f3926"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
@@ -92,8 +92,8 @@
|
||||
{
|
||||
"name": "RetroBIOS/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1143258,
|
||||
"sha256": "61176387d38c67e596c1669fee2bb3b981333ab0b808dd2e280a5a3870957738",
|
||||
"size": 1142976,
|
||||
"sha256": "e9bfce57f1aab1123937498d7ed7913223762df755bb572b9a36f2d6a69b7a55",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -166,8 +166,8 @@
|
||||
{
|
||||
"dest": ".config/modules/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1143258,
|
||||
"sha256": "61176387d38c67e596c1669fee2bb3b981333ab0b808dd2e280a5a3870957738",
|
||||
"size": 1142976,
|
||||
"sha256": "e9bfce57f1aab1123937498d7ed7913223762df755bb572b9a36f2d6a69b7a55",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7677,5 +7677,34 @@ class APackageHintNamesThePackageCommand(unittest.TestCase):
|
||||
"uvx retrobios --platform retroarch --dest DIR"))
|
||||
|
||||
|
||||
class AnErrorIsOneShortSentence(unittest.TestCase):
|
||||
"""A message on stderr says what to do in a few words: one of 35 words
|
||||
asked a beginner to read a paragraph to find the option to give."""
|
||||
|
||||
BUDGET = 25
|
||||
|
||||
def test_every_stderr_message_is_short(self):
|
||||
import ast
|
||||
|
||||
tree = ast.parse((REPO_ROOT / "install.py").read_text(encoding="utf-8"))
|
||||
long = []
|
||||
for node in ast.walk(tree):
|
||||
if not isinstance(node, ast.Call):
|
||||
continue
|
||||
name = getattr(node.func, "id", getattr(node.func, "attr", ""))
|
||||
to_err = any(k.arg == "file" and "stderr" in ast.unparse(k.value)
|
||||
for k in node.keywords)
|
||||
if not (to_err or name == "error"):
|
||||
continue
|
||||
text = " ".join(ast.unparse(a) for a in node.args)
|
||||
if ".command(" in text:
|
||||
continue
|
||||
prose = re.sub(r"\{[^}]*\}", "X", text)
|
||||
words = len(re.findall(r"[A-Za-z']+", prose))
|
||||
if words > self.BUDGET:
|
||||
long.append((node.lineno, words))
|
||||
self.assertEqual(long, [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user