mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-12 21:13:49 -06:00
feat: end a check with files missing on code 3
This commit is contained in:
1 parent
286c2e8d29
commit
8477cda1ca
11 files changed
+57
-36
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 = "9d9768d0d0a9cd702d1eefb60146ae96fc343e1699ce8780afca57b4fb4dd5ac"
|
||||
$defaultInstallSha256 = "8a276fc96f3172fc0f447e57f8ff6aab53614982043197edcb435d54b1903411"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+5
-3
@@ -7712,7 +7712,7 @@ def _install_standalone_folders(
|
||||
if args.check:
|
||||
if pending:
|
||||
print("\n" + _check_fetch_line(pending, "its folder"))
|
||||
sys.exit(1)
|
||||
sys.exit(3)
|
||||
return True
|
||||
if args.dry_run:
|
||||
return True
|
||||
@@ -16320,9 +16320,11 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
skipped=_skipped(omitted_seen), left_out=_left_out_events(left_out_seen),
|
||||
kept=KEPT.summary(), interrupted=total_interrupted,
|
||||
)
|
||||
# A check scripted as `--check && launch` reads the exit code only.
|
||||
# A check scripted as `--check && launch` reads the exit code only. Its
|
||||
# own code, 3: with 1, a check that found files missing could not be
|
||||
# told from a check that never ran (a list refused, a --from missing).
|
||||
if args.check and check_pending:
|
||||
sys.exit(1)
|
||||
sys.exit(3)
|
||||
if not args.check and not listing and not args.dry_run:
|
||||
_report_outcome(
|
||||
installed_paths,
|
||||
|
||||
+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="9d9768d0d0a9cd702d1eefb60146ae96fc343e1699ce8780afca57b4fb4dd5ac"
|
||||
DEFAULT_INSTALL_SHA256="8a276fc96f3172fc0f447e57f8ff6aab53614982043197edcb435d54b1903411"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
{
|
||||
"dest": "roms/ports/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1120968,
|
||||
"sha256": "9d9768d0d0a9cd702d1eefb60146ae96fc343e1699ce8780afca57b4fb4dd5ac",
|
||||
"size": 1121120,
|
||||
"sha256": "8a276fc96f3172fc0f447e57f8ff6aab53614982043197edcb435d54b1903411",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -71,8 +71,8 @@
|
||||
"muos": {
|
||||
"archive": {
|
||||
"dest": "ARCHIVE/RetroBIOS.muxapp",
|
||||
"size": 1174595,
|
||||
"sha256": "0f65a01eaa506007e580d81d8687a91f32da4406ef7a95feb3dac992edf02c86"
|
||||
"size": 1174747,
|
||||
"sha256": "a92c48887550f3f68e2528f533c0acc49be77263f6da3e2cb50571d8d97a2d9a"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
@@ -92,8 +92,8 @@
|
||||
{
|
||||
"name": "RetroBIOS/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1120968,
|
||||
"sha256": "9d9768d0d0a9cd702d1eefb60146ae96fc343e1699ce8780afca57b4fb4dd5ac",
|
||||
"size": 1121120,
|
||||
"sha256": "8a276fc96f3172fc0f447e57f8ff6aab53614982043197edcb435d54b1903411",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -166,8 +166,8 @@
|
||||
{
|
||||
"dest": ".config/modules/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1120968,
|
||||
"sha256": "9d9768d0d0a9cd702d1eefb60146ae96fc343e1699ce8780afca57b4fb4dd5ac",
|
||||
"size": 1121120,
|
||||
"sha256": "8a276fc96f3172fc0f447e57f8ff6aab53614982043197edcb435d54b1903411",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
|
||||
@@ -443,9 +443,9 @@ class Sandbox:
|
||||
(system / "system" / "gba_bios.bin").write_bytes(data["gba_bios.bin"])
|
||||
with zipfile.ZipFile(system / "PSX BIOS.zip", "w") as archive:
|
||||
archive.writestr("extra.bin", data["pcsx/extra.bin"])
|
||||
# A check that flags a file ends on 1, as documented.
|
||||
# A check that flags a file ends on 3, as documented.
|
||||
return self.run("retroarch", "--check", "--manifest", str(listed), home=home,
|
||||
codes=(1,))
|
||||
codes=(3,))
|
||||
old = home / "old"
|
||||
old.mkdir()
|
||||
for dest in ("scph5500.bin", "scph5501.bin"):
|
||||
|
||||
+26
-8
@@ -1509,7 +1509,7 @@ class InstallerStaysOnPython38AndTheStdlib(unittest.TestCase):
|
||||
cwd=REPO_ROOT, env=env, capture_output=True, text=True, timeout=300,
|
||||
check=False,
|
||||
)
|
||||
self.assertEqual(proc.returncode, 1, proc.stdout + proc.stderr)
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
self.assertIn("to download:", proc.stdout)
|
||||
|
||||
def test_no_syntax_a_312_parser_lets_through(self):
|
||||
@@ -4533,6 +4533,24 @@ class AFullDriveIsSaidAsOne(unittest.TestCase):
|
||||
self.assertEqual(len(attempts), 1)
|
||||
|
||||
|
||||
class ACheckThatFindsFilesMissingIsNoFailure(unittest.TestCase):
|
||||
"""--check ended on 1 for files missing as for a list refused or a
|
||||
--from folder that does not exist: a scheduled check could not tell a
|
||||
BIOS folder to complete from a tool that never ran."""
|
||||
|
||||
def test_missing_is_3_and_a_failure_stays_1(self):
|
||||
from test_install_selection import FakeRepository # noqa: PLC0415
|
||||
|
||||
with FakeRepository() as repo:
|
||||
missing = repo.run("--no-input", "--check")
|
||||
nowhere = repo.run("--no-input", "--check", "--from", str(repo.root / "nope"))
|
||||
repo.run("--no-input")
|
||||
complete = repo.run("--no-input", "--check")
|
||||
self.assertEqual(missing.returncode, 3, missing.stdout + missing.stderr)
|
||||
self.assertEqual(nowhere.returncode, 1, nowhere.stdout + nowhere.stderr)
|
||||
self.assertEqual(complete.returncode, 0, complete.stdout + complete.stderr)
|
||||
|
||||
|
||||
class OneEmulatorsFilesInOneCommand(unittest.TestCase):
|
||||
"""An emulator page offers one command for that emulator's files.
|
||||
--core kept the platform's whole list, and narrowing to cores kept the
|
||||
@@ -4921,7 +4939,7 @@ class TheInstallerSaysWhatItFound(unittest.TestCase):
|
||||
self.assertEqual(self._run("--dest", str(dest), "--system", "atari-lynx", "--yes").returncode, 0)
|
||||
(dest / "lynxboot.img").write_bytes(b"corrupt")
|
||||
proc = self._run("--dest", str(dest), "--system", "atari-lynx", "--check")
|
||||
self.assertEqual(proc.returncode, 1)
|
||||
self.assertEqual(proc.returncode, 3)
|
||||
self.assertIn("wrong copy: lynxboot.img", proc.stdout)
|
||||
self.assertIn("without --check", proc.stdout)
|
||||
|
||||
@@ -5607,7 +5625,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun):
|
||||
(dest / "scph5501.bin").write_bytes(b"junk")
|
||||
proc = _install_run(self.env, "--platform", "retroarch", "--dest", str(dest),
|
||||
"--check", "--no-input")
|
||||
self.assertEqual(proc.returncode, 1, proc.stderr)
|
||||
self.assertEqual(proc.returncode, 3, proc.stderr)
|
||||
listing = proc.stdout.split("to download:\n", 1)[1].splitlines()
|
||||
self.assertEqual(listing[0].strip(), "wrong copy: scph5501.bin")
|
||||
|
||||
@@ -5639,7 +5657,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun):
|
||||
shutil.copy(REPO_ROOT / repo_path, dest / "PPSSPP")
|
||||
proc = _install_run(self.env, "--platform", "retroarch", "--dest", str(dest),
|
||||
"--system", "sony-psp", "--check", "--no-input")
|
||||
self.assertEqual(proc.returncode, 1, proc.stdout + proc.stderr)
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
self.assertNotIn("Everything is in place", proc.stdout)
|
||||
found = re.search(r"(\d+) in place, (\d+) missing", proc.stdout)
|
||||
self.assertIsNotNone(found, proc.stdout)
|
||||
@@ -5653,7 +5671,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun):
|
||||
proc = _install_run({**self.env, "RETROBIOS_INSTALL_OFFLINE": "1"}, "--platform",
|
||||
"retroarch", "--dest", str(dest), "--check", "--no-input",
|
||||
"--manifest", str(REPO_ROOT / "install" / "retroarch.json"))
|
||||
self.assertEqual(proc.returncode, 1, proc.stdout + proc.stderr)
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
missing = re.search(r"0 in place, (\d+) missing", proc.stdout).group(1)
|
||||
self.assertIn(f"\n {missing} files not in place:\n", proc.stdout)
|
||||
self.assertIn(f" {missing} files need the internet", proc.stdout)
|
||||
@@ -6764,13 +6782,13 @@ class EventsDescribeTheRun(unittest.TestCase, _SyntheticTree):
|
||||
|
||||
def test_a_check_run(self):
|
||||
proc, events = self._run("--check")
|
||||
self.assertEqual(proc.returncode, 1)
|
||||
self.assertEqual(proc.returncode, 3)
|
||||
installer = events[0]["installer"]
|
||||
self.assertEqual(events, self._head("check", installer) + [
|
||||
{"event": "summary", "mode": "check", "installed": 0, "up_to_date": 1,
|
||||
"pending": 3, "failed": [], "skipped": self.SKIPPED, "left_out": [], "kept": [],
|
||||
"interrupted": False},
|
||||
{"event": "end", "code": 1},
|
||||
{"event": "end", "code": 3},
|
||||
])
|
||||
self.assertIn("1 in place, 2 missing, 1 wrong copy", proc.stderr)
|
||||
self.assertFalse((self.bios / "c.bin").exists())
|
||||
@@ -6986,7 +7004,7 @@ class TheInstallerPageIsWrittenFromTheCode(unittest.TestCase):
|
||||
self.scratch.read_text(encoding="utf-8"))
|
||||
|
||||
def test_the_exit_codes_are_the_ones_install_py_exits_with(self):
|
||||
self.assertEqual(self.generator.exit_codes(), [0, 1, 2, 130, 141])
|
||||
self.assertEqual(self.generator.exit_codes(), [0, 1, 2, 3, 130, 141])
|
||||
|
||||
def test_a_missing_marker_stops_it(self):
|
||||
page = self.scratch.read_text(encoding="utf-8")
|
||||
|
||||
@@ -546,7 +546,7 @@ class AFolderThisUserCannotEnter(unittest.TestCase):
|
||||
finally:
|
||||
os.chmod(locked, 0o755)
|
||||
self.assertNotIn("Traceback", proc.stderr)
|
||||
self.assertEqual(proc.returncode, 1, proc.stdout + proc.stderr)
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
self.assertIn("wrong copy: pcsx/extra.bin", proc.stdout)
|
||||
self.assertIn("could not be read (Permission denied)", proc.stdout)
|
||||
self.assertIn("missing: scph5501.bin", proc.stdout)
|
||||
|
||||
@@ -219,7 +219,7 @@ class CopyFromAnOldCard(FromFolder):
|
||||
self.keep("gba_bios.bin", GBA)
|
||||
proc = self.run_installer("--check", "--manifest", str(self.list), "--from",
|
||||
str(self.old))
|
||||
self.assertEqual(proc.returncode, 1, proc.stdout + proc.stderr)
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
self.assertIn(f"{self.old} holds 2 of these files: a run without --check "
|
||||
"copies them.", proc.stdout)
|
||||
self.assertIn(f"in {self.old}: BIOS/SCPH5501.BIN", proc.stdout)
|
||||
@@ -605,7 +605,7 @@ class UnreadableCopies(FromFolder):
|
||||
for options in (("--check",), ("--dry-run",), ()):
|
||||
with self.subTest(options=options):
|
||||
proc = self.install(*options)
|
||||
self.assertEqual(proc.returncode, 1 if options != ("--dry-run",) else 0,
|
||||
self.assertEqual(proc.returncode, {("--check",): 3, ("--dry-run",): 0}.get(options, 1),
|
||||
proc.stdout + proc.stderr)
|
||||
self.assertIn(line, proc.stdout)
|
||||
self.assertNotIn("notes.txt", proc.stdout)
|
||||
|
||||
@@ -118,7 +118,7 @@ class Scratch(unittest.TestCase):
|
||||
|
||||
def check(self) -> str:
|
||||
proc = self.run_installer("--check", "--manifest", str(self.list), "--verbose")
|
||||
self.assertEqual(proc.returncode, 1, proc.stdout + proc.stderr)
|
||||
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
|
||||
return proc.stdout
|
||||
|
||||
def complete(self, *skip: str) -> None:
|
||||
@@ -1035,7 +1035,7 @@ class OneOfflineVocabulary(Scratch):
|
||||
""""Run the same command without --check to fetch them"."""
|
||||
proc = self.run_installer("--check", "--offline", "--manifest", str(self.list))
|
||||
out = proc.stdout + proc.stderr
|
||||
self.assertEqual(proc.returncode, 1, out)
|
||||
self.assertEqual(proc.returncode, 3, out)
|
||||
self.assertNotIn("to fetch them", out)
|
||||
self.assertIn("4 files need the internet, which --offline does not use.", out)
|
||||
self.assertIn("Copy them from your old card or a folder (--from)", out)
|
||||
|
||||
@@ -1726,7 +1726,7 @@ class SomethingElseAtADestination(unittest.TestCase):
|
||||
with FakeRepository() as repo:
|
||||
self.prepare(repo)
|
||||
proc = repo.run("--check")
|
||||
self.assertEqual(proc.returncode, 1, proc.stderr)
|
||||
self.assertEqual(proc.returncode, 3, proc.stderr)
|
||||
self.assertNotIn("Traceback", proc.stderr)
|
||||
self.assertIn(" wrong copy: scph5500.bin\n a folder sits where this "
|
||||
"file goes: move it away, then run again", proc.stdout)
|
||||
|
||||
+8
-7
@@ -577,7 +577,7 @@ Checking existing files...
|
||||
`Everything is in place.` is said only when the data folders are complete
|
||||
too. With the BIOS files in place and data files missing (PPSSPP's assets,
|
||||
Dolphin's `Sys`), the line counts those instead (`169 data files to fetch`),
|
||||
and `--check` exits with code 1. The files the collection does not hold are
|
||||
and `--check` exits with code 3. The files the collection does not hold are
|
||||
listed after it again, as long as they are absent from the folder. A number before `wrong copies` means a file is
|
||||
in place with contents the platform does not accept. Running the install again
|
||||
replaces it and keeps the old one, see
|
||||
@@ -1011,8 +1011,8 @@ what the options name, everything by default.
|
||||
|
||||
<!-- /generated: options -->
|
||||
|
||||
`--check` exits with code 1 when a file is missing or does not match, and 0
|
||||
when every one does. What it lists is under
|
||||
`--check` exits with code 3 when a file is missing or does not match, 0
|
||||
when every one does, and 1 when the check itself failed. What it lists is under
|
||||
[Why a file is refused](#why-a-file-is-refused). An install leaves a file with
|
||||
the expected hash untouched and replaces any other, the old one kept beside
|
||||
the BIOS folder. Files the list does not name are never read, moved or deleted.
|
||||
@@ -1768,8 +1768,9 @@ fields, the installer refuses to narrow rather than install everything.
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| `0` | everything asked for is installed or already in place |
|
||||
| `1` | a failure: the one-liner could not download or verify `install.py`, or found no Python 3.8 with its ssl, unicodedata and zlib modules (nothing was run), an unusable base URL, `--installed-cores` with no core found, a manifest that fails validation, a fetch that never succeeded, no platform to install for in a non-interactive run, some files failed or were left out by `--offline` while others installed, `--check` found files to fetch, a `--from-pack` pack that cannot be read, lacks a part or is for another platform, a `--from` folder that does not exist or cannot be read, a BIOS folder that is a file or lies under one, a `--dest` that is not the card of the system named (another system's card, a folder inside one, a drive with none of its files where its card always has them, or a folder that does not exist), `--restore` could not put a file back, or `--add-app` could not put every file of the app on the card |
|
||||
| `1` | a failure: the one-liner could not download or verify `install.py`, or found no Python 3.8 with its ssl, unicodedata and zlib modules (nothing was run), an unusable base URL, `--installed-cores` with no core found, a manifest that fails validation, a fetch that never succeeded, no platform to install for in a non-interactive run, some files failed or were left out by `--offline` while others installed, a `--from-pack` pack that cannot be read, lacks a part or is for another platform, a `--from` folder that does not exist or cannot be read, a BIOS folder that is a file or lies under one, a `--dest` that is not the card of the system named (another system's card, a folder inside one, a drive with none of its files where its card always has them, or a folder that does not exist), `--restore` could not put a file back, or `--add-app` could not put every file of the app on the card |
|
||||
| `2` | nothing was installed: every file the run tried failed (a BIOS folder that cannot be written, for one), or `--offline` left every file out, the drive has too little free space for the download (checked before any folder is created), or the question about a folder that does not exist, named with `--dest` or typed at the folder question, was answered no. Also an option the installer refused before any download: an unknown option, `--jobs` outside 1 to 32, `--target` with `--every-board`, `--target` with `--from-pack` or `--offline` (or `RETROBIOS_INSTALL_OFFLINE` set) when no core list per board is at hand (the pack carries none and none is beside `--manifest` as `targets/<platform>.json`), or for a platform that publishes none, which is said to have no hardware targets, `--list-targets` with `--offline` and neither, `--add-app` with `--check`, `--dry-run`, a listing, `--from-pack` or `--offline`. The message then starts with `install.py: error:`. Also an unknown platform, target, system, core or emulator, said in an `Error:` or `Unknown platform` line and an `error` event whose `stage` is `option`. Also `--add-app` for a folder on no card that takes the app, said in an `Error:` line and an `app` event before anything is written. With `--restore`, a folder that is not a dated folder inside `retrobios-backup`. Also a quit chosen before the install, as `gh` ends a cancelled prompt: `q` at a question, `q` or **Quit** on the full screen, which then keeps `RetroBIOS: quit. Nothing was installed.`, and the full screen closed with no button pressed (`RETROBIOS_IDLE_EXIT`). No code but `0` closes a Windows Terminal tab started on the installer itself, so such a tab stays open on a quit |
|
||||
| `3` | `--check` ran and found files to fetch or wrong copies, nothing having failed. A failure takes `1` as before: a manifest refused, a `--from` folder that does not exist. Until November 2026 this case also ended on `1`, so a script that reads any code but `0` as "not ready" needs no change |
|
||||
| `130` | stopped with Ctrl+C, or with Ctrl+C or Ctrl+D at a question, the terminal keeping `RetroBIOS: stopped. Nothing was installed.` before an install. Run the same command again to carry on |
|
||||
| `141` | the output was piped to a reader that closed early (`--list-platforms \| head`) |
|
||||
|
||||
@@ -1792,9 +1793,9 @@ in the session.
|
||||
Failures that are per-file, such as a download exhausting its three attempts,
|
||||
are counted and reported at the end.
|
||||
|
||||
To tell missing files from a failure, read the `check` event of
|
||||
[Machine-readable events](#machine-readable-events): `missing` and `wrong_hash`
|
||||
count what is left.
|
||||
`--check` tells missing files (`3`) from a failure (`1`) by its code. The
|
||||
`check` event of [Machine-readable events](#machine-readable-events) counts what
|
||||
is left in `missing` and `wrong_hash`.
|
||||
|
||||
## Machine-readable events
|
||||
|
||||
|
||||
Reference in new issue
Block a user