mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-31 16:17:19 -05:00
chore: merge one choice per run and seen taps
# Conflicts: # install.ps1 # install.sh # install/launchers/index.json
This commit is contained in:
commit
7259dbc7c4
27 files changed
+1705
-323
No files matched your search
+1
-1
@@ -11,7 +11,7 @@
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
$defaultInstallSha256 = "6467b259f1fff162581df002d95f17a2af8b2484e4524dd094003e6ee62217c7"
|
||||
$defaultInstallSha256 = "d6d3483bdaf5c54fae595a6469525015323defb7a4f9f22adbda80029fa3ee54"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+687
-160
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -18,7 +18,7 @@ esac
|
||||
TEMP_INSTALLER=""
|
||||
TEMP_DIRECTORY=""
|
||||
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
DEFAULT_INSTALL_SHA256="6467b259f1fff162581df002d95f17a2af8b2484e4524dd094003e6ee62217c7"
|
||||
DEFAULT_INSTALL_SHA256="d6d3483bdaf5c54fae595a6469525015323defb7a4f9f22adbda80029fa3ee54"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
{
|
||||
"dest": "roms/ports/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 881512,
|
||||
"sha256": "6467b259f1fff162581df002d95f17a2af8b2484e4524dd094003e6ee62217c7",
|
||||
"size": 910839,
|
||||
"sha256": "d6d3483bdaf5c54fae595a6469525015323defb7a4f9f22adbda80029fa3ee54",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -71,8 +71,8 @@
|
||||
"muos": {
|
||||
"archive": {
|
||||
"dest": "ARCHIVE/RetroBIOS.muxapp",
|
||||
"size": 934304,
|
||||
"sha256": "2d94d307ff407a842f4a7c8bbd98bc4cfcee27713e6ee88c94339b689dd7dbe0"
|
||||
"size": 963631,
|
||||
"sha256": "e82035ecc39b3a62898ebf7273c717c04880d2011ade0c09488924209796ab2a"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
@@ -92,8 +92,8 @@
|
||||
{
|
||||
"name": "RetroBIOS/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 881512,
|
||||
"sha256": "6467b259f1fff162581df002d95f17a2af8b2484e4524dd094003e6ee62217c7",
|
||||
"size": 910839,
|
||||
"sha256": "d6d3483bdaf5c54fae595a6469525015323defb7a4f9f22adbda80029fa3ee54",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -166,8 +166,8 @@
|
||||
{
|
||||
"dest": ".config/modules/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 881512,
|
||||
"sha256": "6467b259f1fff162581df002d95f17a2af8b2484e4524dd094003e6ee62217c7",
|
||||
"size": 910839,
|
||||
"sha256": "d6d3483bdaf5c54fae595a6469525015323defb7a4f9f22adbda80029fa3ee54",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
|
||||
+1
-1
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
Ctrl-C Quit B/Esc Quit
|
||||
B/Esc Quit Ctrl-C Quit
|
||||
+1
-1
@@ -9,4 +9,4 @@
|
||||
|
||||
|
||||
|
||||
Ctrl-C Quit B Quit
|
||||
B Quit Ctrl-C Quit
|
||||
+1
-1
@@ -12,4 +12,4 @@
|
||||
|
||||
|
||||
|
||||
Ctrl-C Quit B Quit
|
||||
B Quit Ctrl-C Quit
|
||||
+1
-1
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
Ctrl-C Quit B/Esc Quit
|
||||
B/Esc Quit Ctrl-C Quit
|
||||
Vendored
+1
-1
@@ -325,7 +325,7 @@
|
||||
|
||||
|
||||
|
||||
^[[0;1;35mCtrl-C^[[0m Quit ^[[0;2mB/Esc^[[0m Quit
|
||||
^[[0;1;35mB/Esc^[[0m Quit ^[[0;2mCtrl-C^[[0m Quit
|
||||
=== plan
|
||||
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
|
||||
|
||||
|
||||
Vendored
+7
-7
@@ -101,13 +101,13 @@
|
||||
|
||||
|
||||
|
||||
^[[0;1;35mCtrl-C^[[0m Quit ^[[0;2mB^[[0m Quit
|
||||
^[[0;1;35mB^[[0m Quit ^[[0;2mCtrl-C^[[0m Quit
|
||||
=== plan
|
||||
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
|
||||
|
||||
^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m
|
||||
BIOS folder: ^[[0;1m~/.co.../retroarch/system^[[0m
|
||||
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
|
||||
BIOS folder:
|
||||
^[[0;1m~/.config/retroarch/system^[[0m
|
||||
^[[0;33m1 wrong copy^[[0m: backed up, replaced.
|
||||
^[[0;7;35m > Install^[[0m
|
||||
Choose systems
|
||||
@@ -119,14 +119,14 @@
|
||||
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
|
||||
|
||||
^[[0;1m ^[[0;1;32mEverything is in place^[[0m
|
||||
BIOS folder: ^[[0;1m~/.co.../retroarch/system^[[0m
|
||||
BIOS folder:
|
||||
^[[0;1m~/.config/retroarch/system^[[0m
|
||||
^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
^[[0;7;35m > Close^[[0m
|
||||
Options
|
||||
|
||||
|
||||
^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
|
||||
=== systems
|
||||
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m
|
||||
@@ -240,8 +240,8 @@
|
||||
^[[0;1m/home/user/.config/retroarch/system^[[0m
|
||||
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
To put them back: python3 install.py
|
||||
^[[0;2m 1-8 of 16^[[0m
|
||||
^[[0;1;35mA^[[0m Exit ^[[0;2m^v^[[0m Scroll
|
||||
|
||||
Vendored
+8
-8
@@ -125,14 +125,15 @@
|
||||
|
||||
|
||||
|
||||
^[[0;1;35mCtrl-C^[[0m Quit ^[[0;2mB^[[0m Quit
|
||||
^[[0;1;35mB^[[0m Quit ^[[0;2mCtrl-C^[[0m Quit
|
||||
=== plan
|
||||
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
|
||||
|
||||
^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m
|
||||
BIOS folder: ^[[0;1m~/.co.../retroarch/system^[[0m
|
||||
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
|
||||
BIOS folder:
|
||||
^[[0;1m~/.config/retroarch/system^[[0m
|
||||
^[[0;33m1 wrong copy^[[0m: backed up, replaced.
|
||||
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
|
||||
Free space: 50.0 GB
|
||||
|
||||
^[[0;7;35m > Install^[[0m
|
||||
@@ -140,13 +141,13 @@
|
||||
Copy from your old card or a folder
|
||||
Options
|
||||
Quit
|
||||
|
||||
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
|
||||
=== plan-in-place
|
||||
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
|
||||
|
||||
^[[0;1m ^[[0;1;32mEverything is in place^[[0m
|
||||
BIOS folder: ^[[0;1m~/.co.../retroarch/system^[[0m
|
||||
BIOS folder:
|
||||
^[[0;1m~/.config/retroarch/system^[[0m
|
||||
^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
@@ -156,7 +157,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
|
||||
=== systems
|
||||
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m
|
||||
@@ -294,8 +294,8 @@
|
||||
^[[0;1m/home/user/.config/retroarch/system^[[0m
|
||||
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
To put them back: python3 install.py
|
||||
--restore
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
Vendored
+1
-1
@@ -197,7 +197,7 @@
|
||||
|
||||
|
||||
|
||||
^[[0;1;35mCtrl-C^[[0m Quit ^[[0;2mB/Esc^[[0m Quit
|
||||
^[[0;1;35mB/Esc^[[0m Quit ^[[0;2mCtrl-C^[[0m Quit
|
||||
=== plan
|
||||
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -1,8 +1,8 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
> Install
|
||||
Choose systems
|
||||
|
||||
Vendored
+3
-3
@@ -1,9 +1,10 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Install
|
||||
@@ -11,5 +12,4 @@
|
||||
Copy from your old card or a folder
|
||||
Options
|
||||
Quit
|
||||
|
||||
A Install B Back Y Options ? Help
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Close
|
||||
Options
|
||||
|
||||
|
||||
A Close B Back Y Options ? Help
|
||||
+2
-2
@@ -1,7 +1,8 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
@@ -11,5 +12,4 @@
|
||||
|
||||
|
||||
|
||||
|
||||
A Close B Back Y Options ? Help
|
||||
Vendored
+2
-2
@@ -5,8 +5,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
To put them back: python3 install.py
|
||||
1-8 of 16
|
||||
A Exit ^v Scroll
|
||||
Vendored
+2
-2
@@ -5,8 +5,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
To put them back: python3 install.py
|
||||
--restore
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
Vendored
+13
-13
@@ -405,8 +405,8 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
> Install
|
||||
Choose systems
|
||||
@@ -418,9 +418,10 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Install
|
||||
@@ -428,7 +429,6 @@
|
||||
Copy from your old card or a folder
|
||||
Options
|
||||
Quit
|
||||
|
||||
A Install B Back Y Options
|
||||
=== plan 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -459,20 +459,21 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Close
|
||||
Options
|
||||
|
||||
|
||||
A Close B Back Y Options
|
||||
=== plan-in-place 40x15
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
@@ -482,7 +483,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
A Close B Back Y Options
|
||||
=== plan-in-place 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -891,8 +891,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
A Exit
|
||||
@@ -904,8 +904,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
|
||||
|
||||
+16
-16
@@ -359,7 +359,7 @@
|
||||
|
||||
|
||||
|
||||
Select+Start Quit B Quit
|
||||
B Quit Select+Start Quit
|
||||
=== checking 40x15
|
||||
RetroBIOS: Checking
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
|
||||
|
||||
|
||||
Select+Start Quit B Quit
|
||||
B Quit Select+Start Quit
|
||||
=== checking 80x24
|
||||
RetroBIOS: Checking
|
||||
|
||||
@@ -400,13 +400,13 @@
|
||||
|
||||
|
||||
|
||||
Select+Start Quit B Quit
|
||||
B Quit Select+Start Quit
|
||||
=== plan 40x12
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
> Install
|
||||
Choose systems
|
||||
@@ -418,9 +418,10 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Install
|
||||
@@ -428,7 +429,6 @@
|
||||
Copy from your old card or a folder
|
||||
Options
|
||||
Quit
|
||||
|
||||
A Install B Back Y Options
|
||||
=== plan 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -459,20 +459,21 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Close
|
||||
Options
|
||||
|
||||
|
||||
A Close B Back Y Options
|
||||
=== plan-in-place 40x15
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
@@ -482,7 +483,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
A Close B Back Y Options
|
||||
=== plan-in-place 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -891,8 +891,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
A Exit
|
||||
@@ -904,8 +904,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
|
||||
|
||||
+16
-16
@@ -359,7 +359,7 @@
|
||||
|
||||
|
||||
|
||||
Select+Start Quit B Quit
|
||||
B Quit Select+Start Quit
|
||||
=== checking 40x15
|
||||
RetroBIOS: Checking
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
|
||||
|
||||
|
||||
Select+Start Quit B Quit
|
||||
B Quit Select+Start Quit
|
||||
=== checking 80x24
|
||||
RetroBIOS: Checking
|
||||
|
||||
@@ -400,13 +400,13 @@
|
||||
|
||||
|
||||
|
||||
Select+Start Quit B Quit
|
||||
B Quit Select+Start Quit
|
||||
=== plan 40x12
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
> Install
|
||||
Choose systems
|
||||
@@ -418,9 +418,10 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Install
|
||||
@@ -428,7 +429,6 @@
|
||||
Copy from your old card or a folder
|
||||
Options
|
||||
Quit
|
||||
|
||||
A Install B Back Y Options
|
||||
=== plan 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -459,20 +459,21 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Close
|
||||
Options
|
||||
|
||||
|
||||
A Close B Back Y Options
|
||||
=== plan-in-place 40x15
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
@@ -482,7 +483,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
A Close B Back Y Options
|
||||
=== plan-in-place 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -891,8 +891,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
A Exit
|
||||
@@ -904,8 +904,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
|
||||
|
||||
Vendored
+16
-16
@@ -334,7 +334,7 @@
|
||||
|
||||
|
||||
|
||||
Ctrl-C Quit Esc Quit
|
||||
Esc Quit Ctrl-C Quit
|
||||
=== checking 40x15
|
||||
RetroBIOS: Checking
|
||||
|
||||
@@ -350,7 +350,7 @@
|
||||
|
||||
|
||||
|
||||
Ctrl-C Quit Esc Quit
|
||||
Esc Quit Ctrl-C Quit
|
||||
=== checking 80x24
|
||||
RetroBIOS: Checking
|
||||
|
||||
@@ -375,13 +375,13 @@
|
||||
|
||||
|
||||
|
||||
Ctrl-C Quit Esc Quit
|
||||
Esc Quit Ctrl-C Quit
|
||||
=== plan 40x12
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
> Install
|
||||
Choose systems
|
||||
@@ -393,9 +393,10 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Install
|
||||
@@ -403,7 +404,6 @@
|
||||
Copy from your old card or a folder
|
||||
Options
|
||||
Quit
|
||||
|
||||
Enter Install Esc Back o Options
|
||||
=== plan 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -434,20 +434,21 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Close
|
||||
Options
|
||||
|
||||
|
||||
Enter Close Esc Back o Options
|
||||
=== plan-in-place 40x15
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
@@ -457,7 +458,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
Enter Close Esc Back o Options
|
||||
=== plan-in-place 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -924,8 +924,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
To put them back: python3 install.py
|
||||
1-8 of 16
|
||||
Enter Exit ^v Scroll
|
||||
@@ -937,8 +937,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
To put them back: python3 install.py
|
||||
--restore
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
Vendored
+13
-13
@@ -434,8 +434,8 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
> Install
|
||||
Choose systems
|
||||
@@ -447,9 +447,10 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Install
|
||||
@@ -457,7 +458,6 @@
|
||||
Copy from your old card or a folder
|
||||
Options
|
||||
Quit
|
||||
|
||||
A Install R2 Back L2 Options
|
||||
=== plan 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -488,20 +488,21 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Close
|
||||
Options
|
||||
|
||||
|
||||
A Close R2 Back L2 Options
|
||||
=== plan-in-place 40x15
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
@@ -511,7 +512,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
A Close R2 Back L2 Options
|
||||
=== plan-in-place 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -920,8 +920,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
A Exit
|
||||
@@ -933,8 +933,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
|
||||
|
||||
Vendored
+16
-16
@@ -388,7 +388,7 @@
|
||||
|
||||
|
||||
|
||||
Menu Quit B Quit
|
||||
B Quit Menu Quit
|
||||
=== checking 40x15
|
||||
RetroBIOS: Checking
|
||||
|
||||
@@ -404,7 +404,7 @@
|
||||
|
||||
|
||||
|
||||
Menu Quit B Quit
|
||||
B Quit Menu Quit
|
||||
=== checking 80x24
|
||||
RetroBIOS: Checking
|
||||
|
||||
@@ -429,13 +429,13 @@
|
||||
|
||||
|
||||
|
||||
Menu Quit B Quit
|
||||
B Quit Menu Quit
|
||||
=== plan 40x12
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
> Install
|
||||
Choose systems
|
||||
@@ -447,9 +447,10 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
4 files to download, 1.0 MB
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
1 wrong copy: backed up, replaced.
|
||||
1 in place, 3 missing, 1 wrong copy
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Install
|
||||
@@ -457,7 +458,6 @@
|
||||
Copy from your old card or a folder
|
||||
Options
|
||||
Quit
|
||||
|
||||
Start Install B Back
|
||||
=== plan 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -488,20 +488,21 @@
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
> Close
|
||||
Options
|
||||
|
||||
|
||||
Start Close B Back
|
||||
=== plan-in-place 40x15
|
||||
RetroBIOS: RetroArch
|
||||
|
||||
Everything is in place
|
||||
BIOS folder: ~/.co.../retroarch/system
|
||||
BIOS folder:
|
||||
~/.config/retroarch/system
|
||||
5 in place, 0 missing, 0 wrong copies
|
||||
Free space: 50.0 GB
|
||||
|
||||
@@ -511,7 +512,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
Start Close B Back
|
||||
=== plan-in-place 80x24
|
||||
RetroBIOS: RetroArch
|
||||
@@ -978,8 +978,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
Start Exit
|
||||
@@ -991,8 +991,8 @@
|
||||
/home/user/.config/retroarch/system
|
||||
failed: scph5500.bin (HTTP 404)
|
||||
The files it replaced are kept in
|
||||
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
|
||||
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
Details: /tmp/retrobios-x/install.log
|
||||
|
||||
|
||||
|
||||
@@ -1241,7 +1241,7 @@ class OfflineWithNothingFound(unittest.TestCase):
|
||||
said = proc.stdout + proc.stderr
|
||||
self.assertEqual(proc.returncode, 1, said)
|
||||
self.assertNotIn("emudeck", said.lower())
|
||||
self.assertIn("Use --platform and --dest", said)
|
||||
self.assertIn("Name the setup with --platform and its folder with --dest", said)
|
||||
|
||||
|
||||
class TheDryRunWords(unittest.TestCase):
|
||||
|
||||
+861
-15
@@ -381,6 +381,16 @@ def checked_state(facts: dict | None = None) -> install.TuiState:
|
||||
return state
|
||||
|
||||
|
||||
class HoldingPack:
|
||||
"""A pack given to the run that holds every file asked of it."""
|
||||
|
||||
name = "RetroArch_BIOS_Pack.zip"
|
||||
|
||||
@staticmethod
|
||||
def find(entry: dict) -> tuple:
|
||||
return (None, entry)
|
||||
|
||||
|
||||
def press(state: install.TuiState, *pressed) -> list:
|
||||
effects = []
|
||||
for key in pressed:
|
||||
@@ -496,7 +506,10 @@ class Flow(unittest.TestCase):
|
||||
self.assertEqual(state.regions, ["japan", "north-america"])
|
||||
press(state, "left")
|
||||
self.assertEqual(state.regions, ["north-america", "japan"])
|
||||
self.assertEqual(state.focus["regions"], 0)
|
||||
# The rank moves, the row stays where it is, under the focus.
|
||||
self.assertEqual(state.focus["regions"], 1)
|
||||
self.assertEqual([row.label for row in install.tui_rows(state)],
|
||||
["[2] Japan", "[1] North America"])
|
||||
press(state, "shift-down")
|
||||
self.assertEqual(state.regions, ["japan", "north-america"])
|
||||
press(state, "esc", "down", "enter", "down", "right", "down", "down", "right", "right")
|
||||
@@ -1113,8 +1126,12 @@ class Views(unittest.TestCase):
|
||||
for name, state in golden_states().items():
|
||||
with self.subTest(screen=name):
|
||||
hint = install.tui_view(state, 40, 15)[-1].strip()
|
||||
# Checking has no A: Back comes first, Quit never in the
|
||||
# cell the screen before had Continue in.
|
||||
self.assertTrue(hint.startswith(("A/Enter", "A ", "Enter", "Ctrl-C", "Any key",
|
||||
"B/Esc Stop", "B Stop")), hint)
|
||||
"B/Esc Stop", "B Stop")
|
||||
+ (("B ",) if name == "checking" else ())),
|
||||
hint)
|
||||
|
||||
def test_focus_is_marked_without_colour(self):
|
||||
lines = install.tui_view(fresh_state(), 80, 24)
|
||||
@@ -2416,7 +2433,7 @@ class AuditRoundThree(unittest.TestCase):
|
||||
"""With --from-pack and no Wi-Fi, the plan said "to download", which
|
||||
on a handheld with no network read as a failure on its way."""
|
||||
state = checked_state()
|
||||
with mock.patch.object(install.LOCAL, "pack", object()):
|
||||
with mock.patch.object(install.LOCAL, "pack", HoldingPack()):
|
||||
headline = str(install.tui_view(state, 80, 24)[0])
|
||||
plan = "\n".join(str(line) for line in install.tui_view(state, 80, 24))
|
||||
state.summary = {"installed": 3, "failed": [], "up_to_date": 0}
|
||||
@@ -2494,9 +2511,13 @@ class AuditRoundThree(unittest.TestCase):
|
||||
state.found = [found("scph5500.bin", zipped)]
|
||||
state.cols, state.rows = cols, rows
|
||||
lines = [line.strip() for line in install.tui_view(state, cols, rows)]
|
||||
folder = next(line for line in lines if line.startswith("BIOS folder: "))
|
||||
self.assertTrue(folder.endswith("retroarch/system"), folder)
|
||||
self.assertIn("...", folder)
|
||||
at = next(index for index, line in enumerate(lines)
|
||||
if line.startswith("BIOS folder: "))
|
||||
# Whole, broken after a separator: cut in its middle at 40
|
||||
# columns, it was spelled one way on the plan and another on
|
||||
# the result (tui_audit_13 P3-3).
|
||||
self.assertEqual(lines[at] + lines[at + 1], "BIOS folder: /home/someone/with/"
|
||||
"a/long/path/.config/retroarch/system")
|
||||
self.assertIn("1 found in PSX BIOS.zip,", " ".join(lines))
|
||||
self.assertNotIn("/home/me/a/long", " ".join(lines))
|
||||
|
||||
@@ -5635,8 +5656,11 @@ class GameDataIsNoFirmwareAlarm(unittest.TestCase):
|
||||
self.assertNotIn("Anims.j2a", lines[0])
|
||||
# The folder it goes in, and what game data is (the Android run of
|
||||
# 2026-10-27 said neither).
|
||||
self.assertIn("Not available here, game data: files a game or a game engine reads",
|
||||
lines[1])
|
||||
# The names first, the kind in a word, the definition on its own
|
||||
# line of the plan (tui_audit_13 P3-5).
|
||||
self.assertIn("Not available here: jazz2/Source/Anims.j2a (Jazz Jackrabbit 2), game "
|
||||
"data its game reads. Copy it", lines[1])
|
||||
self.assertNotIn("files a game or a game engine reads", lines[1])
|
||||
self.assertIn(f"into {SYSTEM_DIR / 'jazz2' / 'Source'}{os.sep}", lines[1])
|
||||
self.assertIn("Anims.j2a (Jazz Jackrabbit 2)", lines[1])
|
||||
|
||||
@@ -6191,8 +6215,10 @@ class AuditSix(unittest.TestCase):
|
||||
state.found = []
|
||||
state.check = dict(state.check, data_missing=2636, data_bytes=40 * 1024 * 1024)
|
||||
text = " ".join(" ".join(install.tui_view(state, 120, 40)).split())
|
||||
self.assertIn("4 files and 2636 data files (40.0 MB) need the internet, which "
|
||||
"--offline does not use", text)
|
||||
# One count of files, the kinds apart under the folder (tui_audit_13
|
||||
# P3-6): "4 files and 2636 data files" read as two kinds of one.
|
||||
self.assertIn("2640 files need the internet, which --offline does not use", text)
|
||||
self.assertIn("2636 data files (40.0 MB).", text)
|
||||
|
||||
def test_the_error_row_and_the_bar_agree(self):
|
||||
"""tui_audit_6 P3-9.3: "Choose another setup or folder" over
|
||||
@@ -7557,11 +7583,17 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings,
|
||||
self.assertIn("RetroArch: 1 file, 3 B, for 1 of 2 systems.", after)
|
||||
# No game data among the systems chosen: nothing for g to leave out.
|
||||
self.assertNotIn("g) Game data", after)
|
||||
text, _asked = self.line_run(_args(**args), ["c", "1", "g", ""])
|
||||
text, _asked = self.line_run(_args(**args), ["c", "1", "g", "", "g", ""])
|
||||
after = text[text.index("Counted again"):]
|
||||
self.assertIn("g) Game data: kept (3 files, 120 B): leave it out", after)
|
||||
last = after[after.rindex("Counted again"):]
|
||||
self.assertIn("g) Game data: left out (3 files, 120 B): keep it", last)
|
||||
# doom holds only game data: Enter is refused, as the screen offers
|
||||
# no Install for it (tui_audit_13 P3-11), and g puts it back.
|
||||
self.assertIn("g) Game data: left out (3 files, 120 B): keep it", after)
|
||||
self.assertIn("doom holds only game data: nothing is left to install.", after)
|
||||
self.assertNotIn("All files up to date", text)
|
||||
self.assertIn("RetroArch: 3 files, 120 B, for 1 of 2 systems.",
|
||||
after[after.rindex("Counted again"):])
|
||||
text, _asked = self.line_run(_args(**args), ["g", ""])
|
||||
self.assertIn("4 game data files left out (--no-game-data), 1 of them not "
|
||||
"installable", text)
|
||||
|
||||
@@ -9922,13 +9954,19 @@ class TheAndroidResultReadsWhole(unittest.TestCase):
|
||||
return install.tui_view(state, cols, 40)
|
||||
|
||||
def test_a_path_or_a_command_is_never_split_inside_a_word(self):
|
||||
full = "/sdcard/RetroArch/retrobios-backup/20261027-223524"
|
||||
for cols in (40, 50, 80):
|
||||
with self.subTest(cols=cols):
|
||||
lines = [str(line).strip() for line in self.result(cols)]
|
||||
self.assertIn("/sdcard/RetroArch/retrobios-backup/20261027-223524", lines)
|
||||
words = [word for line in lines for word in line.split()]
|
||||
self.assertIn("--restore", words)
|
||||
self.assertTrue(all(not word.endswith("/") for word in words), words)
|
||||
# The command keeps it whole, to be copied as one word.
|
||||
self.assertIn(full, words)
|
||||
# Prose breaks it after a separator only, never inside a name
|
||||
# (tui_audit_13 P3-3): glued again, it is whole.
|
||||
self.assertIn(full, re.sub(r"/ ", "/", " ".join(lines)))
|
||||
self.assertFalse(any(line.endswith(("retrobios-ba", "20261027-"))
|
||||
for line in lines), lines)
|
||||
state = _installed_state(Path("/sdcard/RetroArch/system"))
|
||||
command = install._styled(f"curl -fsSL {install.BOOTSTRAP_URL} | sh -s -- --restore "
|
||||
"'/storage/emulated/0/a b/20261027-223524'", "command")
|
||||
@@ -9956,7 +9994,12 @@ class TheAndroidResultReadsWhole(unittest.TestCase):
|
||||
lines = install._omission_lines(1, [entry], bios)
|
||||
said = " ".join(lines)
|
||||
self.assertIn(f"into {bios / 'jazz2' / 'Source'}{os.sep}", said)
|
||||
# Defined on its own line, never spliced into the sentence naming
|
||||
# the file (tui_audit_13 P3-5).
|
||||
self.assertIn("files a game or a game engine reads", said)
|
||||
self.assertEqual([line for line in lines if "game engine reads" in line],
|
||||
[" Game data: files a game or a game engine reads, of no use to "
|
||||
"the other cores."])
|
||||
self.assertNotIn("Needed to start an emulator", said)
|
||||
|
||||
|
||||
@@ -10182,6 +10225,17 @@ class MouseOnEveryScreen(unittest.TestCase):
|
||||
label = str(lines[line])[first:end].split(" ", 1)[0]
|
||||
self.assertIn(label, install._BAR_CLICKS)
|
||||
effects = tap(state, first, line)
|
||||
if install._bar_commits(base, target[1]):
|
||||
# Install, Quit and Continue into Confirm: the
|
||||
# first tap arms the entry, drawn so, the
|
||||
# second on the same entry presses it.
|
||||
self.assertEqual(effects, [])
|
||||
self.assertEqual(state.stack, base.stack)
|
||||
again = drawn(state, cols, rows)
|
||||
self.assertIn("tap again", str(again[-1]))
|
||||
at = next(first for row, first, _end, mark in state.hits.targets
|
||||
if mark == target)
|
||||
effects = tap(state, at, line)
|
||||
self.assertEqual(effects, install.tui_update(keyed, target[1]))
|
||||
self.assertEqual((state.stack, state.help),
|
||||
(keyed.stack, keyed.help))
|
||||
@@ -10643,6 +10697,7 @@ class AuditNineteenAndTwelve(_CardFixtures, unittest.TestCase):
|
||||
"systems": ["sony-playstation"], "cores": None} for index in range(50)]
|
||||
for left in (False, True):
|
||||
state.no_game_data = left
|
||||
state.checked_dests |= {f"game/{index}.dat" for index in range(50)}
|
||||
row = next(row for row in install.tui_rows(state) if row.action == "gamedata")
|
||||
line = str(install._row_line(row, False, 38))
|
||||
word = "left out" if left else "kept"
|
||||
@@ -11065,5 +11120,796 @@ class TapsOnAPty(unittest.TestCase):
|
||||
self.assertGreater(term.raw.rfind(b"\x1b[?1000l"), mark)
|
||||
|
||||
|
||||
class AuditTwentyAndThirteen(unittest.TestCase):
|
||||
"""code_audit_20 and tui_audit_13: one choice for the run, taps that
|
||||
never commit what was not seen, and the words that fit."""
|
||||
|
||||
setUp = LineModeAndScreenDecideAlike.setUp
|
||||
line_run = LineModeAndScreenDecideAlike.line_run
|
||||
listing = LineModeAndScreenDecideAlike.listing
|
||||
entry = staticmethod(LineModeAndScreenDecideAlike.entry)
|
||||
|
||||
@staticmethod
|
||||
def receive(state: install.TuiState, events: list, facts: dict | None = None) -> None:
|
||||
"""A check's events, then its end."""
|
||||
for event in events:
|
||||
install.tui_receive(state, ("event", state.run_id, event))
|
||||
with mock.patch.object(install, "_tui_folder_facts", return_value=facts or {
|
||||
"free": 50 * 1024 ** 3, "writable": True, "cores": []}):
|
||||
install.tui_receive(state, ("ended", state.run_id, 1, []))
|
||||
|
||||
def game_manifest(self) -> dict:
|
||||
"""Three systems, each with one BIOS file and one game data file."""
|
||||
files = []
|
||||
for system in ("nintendo-ds", "sega-dreamcast", "sony-playstation"):
|
||||
files += [{"dest": f"{system}.bin", "size": 100, "systems": [system],
|
||||
"cores": None},
|
||||
{"dest": f"{system}/game.dat", "size": 1000, "systems": [system],
|
||||
"cores": None, "category": install.GAME_DATA}]
|
||||
# Dreamcast holds only game data.
|
||||
files = [entry for entry in files if entry["dest"] != "sega-dreamcast.bin"]
|
||||
return {"manifest_version": 2, "platform": "retroarch", "categorized": True,
|
||||
"files": files}
|
||||
|
||||
def game_events(self, manifest: dict, left_out: bool = False,
|
||||
only: tuple = ()) -> list:
|
||||
"""The events of a check over manifest, game data left out or not,
|
||||
the files of only those systems when given (--emulator)."""
|
||||
kept = [entry for entry in manifest["files"]
|
||||
if not only or entry["systems"][0] in only]
|
||||
files = [entry for entry in kept
|
||||
if not (left_out and entry.get("category") == install.GAME_DATA)]
|
||||
events = [{"event": "file", "platform": "retroarch", "dest": entry["dest"],
|
||||
"systems": entry["systems"], "size": entry["size"], "state": "missing"}
|
||||
for entry in files]
|
||||
systems = sorted({entry["systems"][0] for entry in files})
|
||||
events += [{"event": "system", "platform": "retroarch", "system": system,
|
||||
"name": system, "files": 1, "present": 0, "missing": 1, "wrong_hash": 0,
|
||||
"bytes_needed": 100} for system in systems]
|
||||
games = [entry["dest"] for entry in kept if entry.get("category") == install.GAME_DATA]
|
||||
events.append({"event": "summary", "mode": "check", "installed": 0, "up_to_date": 0,
|
||||
"pending": len(files), "failed": [], "skipped": [],
|
||||
"left_out": [{"category": install.GAME_DATA, "label": "game data",
|
||||
"files": len(games), "dests": games}]
|
||||
if left_out else [], "kept": [], "interrupted": False})
|
||||
events.append({"event": "check", "platform": "retroarch", "name": "RetroArch",
|
||||
"bios_dir": str(SYSTEM_DIR), "files": len(files), "present": 0,
|
||||
"missing": len(files), "wrong_hash": 0,
|
||||
"bytes_needed": sum(entry["size"] for entry in files),
|
||||
"data_missing": 0, "not_installable": 0})
|
||||
return events
|
||||
|
||||
def game_plan(self, only: tuple = ()) -> install.TuiState:
|
||||
state = fresh_state()
|
||||
state.stack = ["setup"]
|
||||
manifest = self.game_manifest()
|
||||
with mock.patch.object(install.Path, "exists", return_value=True):
|
||||
install.tui_update(state, Key("enter"))
|
||||
install.tui_receive(state, ("manifest", "retroarch", manifest))
|
||||
self.receive(state, self.game_events(manifest, only=only))
|
||||
return state
|
||||
|
||||
# Root cause 2: one choice for the whole run.
|
||||
|
||||
def test_the_game_data_row_keeps_the_systems_ticked(self):
|
||||
"""tui_audit_13 P1-1: the plan's game data row set the ticks back to
|
||||
every system, and the install wrote all of them."""
|
||||
state = self.game_plan()
|
||||
state.ticked = {"nintendo-ds"}
|
||||
rows = install.tui_rows(state)
|
||||
state.focus["plan"] = next(index for index, row in enumerate(rows)
|
||||
if row.action == "gamedata")
|
||||
self.assertEqual(install.tui_update(state, Key("enter")), [("run", "check")])
|
||||
self.receive(state, self.game_events(self.game_manifest(), left_out=True))
|
||||
self.assertEqual(state.ticked, {"nintendo-ds"})
|
||||
self.assertIn(("--system", "nintendo-ds"), install.tui_flags(state))
|
||||
self.assertIn(("--no-game-data", None), install.tui_flags(state))
|
||||
|
||||
def test_every_check_of_the_same_list_keeps_the_choice(self):
|
||||
"""Root cause of tui_audit_13 P1-1: a folder to copy from added, the
|
||||
save folder chosen or Check again set the ticks back to every system
|
||||
too, as the game data row did."""
|
||||
for how in ("from", "savedir", "recheck"):
|
||||
with self.subTest(how=how):
|
||||
state = self.game_plan()
|
||||
state.ticked = {"nintendo-ds"}
|
||||
if how == "from":
|
||||
state.browse_for, state.browse_dir = "from", self.root
|
||||
state.stack.append("browse")
|
||||
install._activate(state, install.TuiRow("use", "Use this folder"))
|
||||
elif how == "savedir":
|
||||
state.browse_for, state.browse_dir = "save", self.root
|
||||
state.stack.append("browse")
|
||||
install._activate(state, install.TuiRow("use", "Use this folder"))
|
||||
else:
|
||||
install._activate(state, install.TuiRow("recheck", "Check again"))
|
||||
self.assertEqual(state.screen, "checking")
|
||||
self.receive(state, self.game_events(self.game_manifest()))
|
||||
self.assertEqual(state.ticked, {"nintendo-ds"})
|
||||
|
||||
def test_a_choice_the_toggle_empties_says_so_and_offers_choose_systems(self):
|
||||
"""tui_audit_13 P1-1: Dreamcast alone, game data left out: the plan
|
||||
promised the whole list and Install refused."""
|
||||
state = self.game_plan()
|
||||
state.ticked = {"sega-dreamcast"}
|
||||
rows = install.tui_rows(state)
|
||||
state.focus["plan"] = next(index for index, row in enumerate(rows)
|
||||
if row.action == "gamedata")
|
||||
install.tui_update(state, Key("enter"))
|
||||
self.receive(state, self.game_events(self.game_manifest(), left_out=True))
|
||||
text = " ".join(" ".join(install.tui_view(state, 80, 24)).split())
|
||||
self.assertIn("sega-dreamcast holds only game data: nothing is left to install.", text)
|
||||
actions = [row.action for row in install.tui_rows(state)]
|
||||
self.assertNotIn("install", actions)
|
||||
self.assertEqual(actions[0], "systems")
|
||||
# Kept again, the same system comes back.
|
||||
state.focus["plan"] = actions.index("gamedata")
|
||||
install.tui_update(state, Key("enter"))
|
||||
self.receive(state, self.game_events(self.game_manifest()))
|
||||
self.assertEqual(state.ticked, {"sega-dreamcast"})
|
||||
|
||||
def test_the_row_counts_the_list_the_check_read(self):
|
||||
"""code_audit_20 P2-1: under --emulator the row counted the game
|
||||
data of every system, line mode's g the emulator's alone."""
|
||||
state = self.game_plan(only=("nintendo-ds",))
|
||||
row = next(row for row in install.tui_rows(state) if row.action == "gamedata")
|
||||
self.assertEqual(row.right, "1 file, 1000 B")
|
||||
# Line mode, the same list narrowed as --emulator narrows it.
|
||||
manifest = self.game_manifest()
|
||||
listing = self.listing("retroarch", [
|
||||
self.entry(entry["dest"], b"x" * entry["size"], entry["systems"],
|
||||
**({"category": entry["category"]} if "category" in entry else {}))
|
||||
for entry in manifest["files"] if entry["systems"] == ["nintendo-ds"]],
|
||||
categorized=True)
|
||||
text, _asked = self.line_run(_args(manifest=listing, dest=self.here,
|
||||
declared_only=False, dry_run=True), [""])
|
||||
self.assertIn("g) Game data: kept (1 file, 1000 B)", text)
|
||||
|
||||
def test_line_mode_names_the_game_data_of_the_systems_chosen(self):
|
||||
"""tui_audit_13 P2-3: --system with --no-game-data named the game
|
||||
data of the whole list."""
|
||||
files = [self.entry("gba_bios.bin", b"gba", ["nintendo-gba"]),
|
||||
self.entry("doom/doom1.wad", b"wad" * 10, ["doom"], category="game_data")]
|
||||
listing = self.listing("retroarch", files, categorized=True)
|
||||
text, _asked = self.line_run(_args(manifest=listing, dest=self.here,
|
||||
declared_only=False, dry_run=True, no_input=True,
|
||||
system=["nintendo-gba"], no_game_data=True), [])
|
||||
self.assertNotIn("doom1.wad", text)
|
||||
self.assertNotIn("game data file left out", text)
|
||||
text, _asked = self.line_run(_args(manifest=listing, dest=self.here,
|
||||
declared_only=False, dry_run=True, no_input=True,
|
||||
system=["doom"], no_game_data=True), [])
|
||||
# The choice holds no file: said, never "All files up to date", nor
|
||||
# "unknown system" for a system the list names.
|
||||
self.assertIn("doom holds only game data: nothing is left to install.", text)
|
||||
self.assertNotIn("All files up to date", text)
|
||||
self.assertNotIn("unknown system", text)
|
||||
|
||||
def test_the_run_head_counts_three_kinds_and_defines_them(self):
|
||||
"""code_audit_20 P3-5: a run without the menu split two kinds beside
|
||||
the plan's three, from a second counting function."""
|
||||
self.assertFalse(hasattr(install, "split_words"))
|
||||
files = [self.entry("gba_bios.bin", b"gba", ["nintendo-gba"]),
|
||||
self.entry("doom/doom1.wad", b"wad" * 10, ["doom"], category="game_data")]
|
||||
listing = self.listing("retroarch", files, categorized=True)
|
||||
text, _asked = self.line_run(_args(manifest=listing, dest=self.here,
|
||||
declared_only=False, dry_run=True, no_input=True),
|
||||
[])
|
||||
head = text[:text.index("Checking existing files")]
|
||||
self.assertIn("1 BIOS file (3 B) and 1 game data file (30 B).", head)
|
||||
self.assertIn("Game data: files a game or a game engine reads", head)
|
||||
|
||||
def test_the_cores_of_the_systems_chosen_come_first(self):
|
||||
"""tui_audit_13 P3-12: with --system sony-playstation, Cores opened
|
||||
on every core of the list."""
|
||||
state = checked_state()
|
||||
state.cli_systems = ["sony-playstation"]
|
||||
state.stack.append("cores")
|
||||
values = [row.value for row in install.tui_rows(state) if row.action == "core"]
|
||||
self.assertEqual(values, ["pcsx_rearmed"])
|
||||
rows = install.tui_rows(state)
|
||||
self.assertEqual(rows[-1].label, "Cores of the other systems: 1")
|
||||
state.focus["cores"] = len(rows) - 1
|
||||
install.tui_update(state, Key("enter"))
|
||||
self.assertEqual([row.value for row in install.tui_rows(state)
|
||||
if row.action == "core"], ["mesen", "pcsx_rearmed"])
|
||||
|
||||
def test_line_mode_counts_the_systems_that_hold_a_file(self):
|
||||
"""tui_audit_13 P3-11: "2 of 8" in line mode, "1 of 8" on the screen."""
|
||||
files = [self.entry("ds.bin", b"ds", ["nintendo-ds"]),
|
||||
self.entry("dc/game.dat", b"dc", ["sega-dreamcast"], category="game_data"),
|
||||
self.entry("psx.bin", b"psx", ["sony-playstation"])]
|
||||
listing = self.listing("retroarch", files, categorized=True,
|
||||
system_titles={"nintendo-ds": "Nintendo DS",
|
||||
"sega-dreamcast": "Sega Dreamcast",
|
||||
"sony-playstation": "Sony PlayStation"})
|
||||
text, _asked = self.line_run(_args(manifest=listing, dest=self.here,
|
||||
declared_only=False, dry_run=True),
|
||||
["c", "1,2", "g"])
|
||||
last = text[text.rindex("Counted again"):]
|
||||
self.assertIn("for 1 of 2 systems.", last)
|
||||
# The screen, the same choice: DS and Dreamcast ticked, game data
|
||||
# left out on the plan.
|
||||
state = self.game_plan()
|
||||
state.ticked = {"nintendo-ds", "sega-dreamcast"}
|
||||
rows = install.tui_rows(state)
|
||||
state.focus["plan"] = next(index for index, row in enumerate(rows)
|
||||
if row.action == "gamedata")
|
||||
install.tui_update(state, Key("enter"))
|
||||
self.receive(state, self.game_events(self.game_manifest(), left_out=True))
|
||||
self.assertIn("for 1 of 2 systems", str(install.tui_view(state, 80, 24)[2]))
|
||||
|
||||
# Root cause 3: copies and packs.
|
||||
|
||||
def test_confirm_counts_the_copies_a_folder_holds(self):
|
||||
"""code_audit_20 P2-2: Confirm called the files packx holds
|
||||
downloads, offline and online."""
|
||||
state = checked_state()
|
||||
state.found = [found(event["dest"], "/media/old") for event in FILES]
|
||||
state.stack.append("confirm")
|
||||
state.dry, state.dry_files = dict(CHECK), list(FILES)
|
||||
for env in ({install.OFFLINE_VARIABLE: install.OFFLINE_FLAG_VALUE}, {}):
|
||||
with self.subTest(offline=bool(env)), mock.patch.dict(os.environ, env):
|
||||
text = " ".join(" ".join(install.tui_view(state, 80, 24)).split())
|
||||
self.assertIn("4 found in old, nothing to download", text)
|
||||
self.assertNotIn("need the internet", text)
|
||||
self.assertNotIn("to download,", text)
|
||||
|
||||
def test_an_old_card_holding_every_file_in_place_is_not_called_empty(self):
|
||||
"""tui_audit_13 P3-4: "packx holds none of these files" when all 22
|
||||
were in place."""
|
||||
state = checked_state()
|
||||
state.check = {**CHECK, "present": 5, "missing": 0, "wrong_hash": 0,
|
||||
"bytes_needed": 0}
|
||||
state.files = []
|
||||
state.from_folders = [Path("/media/packx")]
|
||||
text = " ".join(" ".join(install.tui_view(state, 80, 24)).split())
|
||||
self.assertIn("Nothing to copy from packx: every file is in place.", text)
|
||||
self.assertNotIn("holds none of these files", text)
|
||||
|
||||
def test_the_plan_says_what_the_pack_lacks_before_a_size(self):
|
||||
"""tui_audit_13 P3-8: "8358 files to install from the pack, 6.6 GB"
|
||||
from a pack that held none of them."""
|
||||
state = checked_state()
|
||||
|
||||
class Lacking:
|
||||
name = "RetroArch_BIOS_Pack.zip"
|
||||
|
||||
@staticmethod
|
||||
def find(entry: dict) -> tuple | None:
|
||||
return (None, entry) if entry["dest"] == "gba_bios.bin" else None
|
||||
|
||||
with mock.patch.object(install.LOCAL, "pack", Lacking()):
|
||||
text = " ".join(" ".join(install.tui_view(state, 80, 24)).split())
|
||||
self.assertIn("1 file to install from the pack, 16.0 KB", text)
|
||||
self.assertIn("3 of these 4 files are not in RetroArch_BIOS_Pack.zip", text)
|
||||
Lacking.find = staticmethod(lambda entry: None)
|
||||
text = " ".join(" ".join(install.tui_view(state, 80, 24)).split())
|
||||
self.assertIn("RetroArch_BIOS_Pack.zip holds none of these 4 files", text)
|
||||
self.assertNotIn("install", [row.action for row in install.tui_rows(state)])
|
||||
|
||||
def test_a_failed_pack_install_leaves_no_folder_behind(self):
|
||||
"""tui_audit_13 P3-8: 405 empty folders and a saves folder."""
|
||||
pack_dir = self.root / "downloads"
|
||||
pack_dir.mkdir()
|
||||
pack = pack_dir / "RetroArch_BIOS_Pack.zip"
|
||||
with zipfile.ZipFile(pack, "w") as archive:
|
||||
archive.writestr("manifest.json", json.dumps({"files": []}))
|
||||
files = [self.entry(f"deep/folder{n}/file.bin", b"x", ["nintendo-gba"])
|
||||
for n in range(3)]
|
||||
listing = self.listing("retroarch", files)
|
||||
dest = self.root / "new" / "system"
|
||||
dest.parent.mkdir()
|
||||
text, _asked = self.line_run(_args(manifest=listing, from_pack=[pack], dest=dest,
|
||||
declared_only=False, yes=True, no_input=True), [])
|
||||
self.assertIn("RetroArch_BIOS_Pack.zip holds none of these 3 files", text)
|
||||
self.assertFalse(dest.exists(), list(dest.rglob("*")) if dest.exists() else [])
|
||||
|
||||
# Root cause 4: Choose another folder.
|
||||
|
||||
def test_choose_another_folder_opens_the_folder_screen(self):
|
||||
"""code_audit_20 P2-3: with --dest the create screen is alone on the
|
||||
stack, and Choose another folder asked Quit?."""
|
||||
state = fresh_state()
|
||||
state.platform, state.dest = "retroarch", self.root / "missing" / "bios"
|
||||
state.stack = ["create"]
|
||||
state.facts = {"nearest": self.root, "risky": False}
|
||||
state.focus["create"] = 1
|
||||
install.tui_update(state, Key("enter"))
|
||||
self.assertEqual(state.screen, "folder")
|
||||
self.assertEqual(install.tui_view(state, 80, 24)[0].strip(),
|
||||
"RetroBIOS: Which folder?")
|
||||
|
||||
# Root cause 5: text that fits.
|
||||
|
||||
def test_the_version_note_stays_on_the_40x12_plan_and_in_every_farewell(self):
|
||||
"""tui_audit_13 P3-1."""
|
||||
note = "This list was built for RetroBat 8.3.1, this machine runs 8.2.0.1."
|
||||
state = checked_state()
|
||||
state.version = note
|
||||
state.files = []
|
||||
state.check = {**CHECK, "present": 5, "missing": 0, "wrong_hash": 0,
|
||||
"bytes_needed": 0}
|
||||
text = " ".join(" ".join(install.tui_view(state, 40, 12)).split())
|
||||
self.assertIn(note, text)
|
||||
state.exit_code = 0
|
||||
self.assertIn(note, install.tui_farewell(state))
|
||||
state.exit_code, state.quit_asked = install.QUIT_CODE, True
|
||||
self.assertIn(note, install.tui_farewell(state))
|
||||
|
||||
def test_the_help_defines_game_data_at_40_columns(self):
|
||||
"""tui_audit_13 P3-2: the row was a choice nothing explained on the
|
||||
Miyoo's screen."""
|
||||
state = _game_state()
|
||||
state.mouse = True
|
||||
state.help = True
|
||||
for rows in (12, 15):
|
||||
with self.subTest(rows=rows):
|
||||
text = " ".join(" ".join(install.tui_view(state, 40, rows)).split())
|
||||
self.assertIn("Game data: files a game or a game engine reads", text)
|
||||
# Data files too, each said whole: in a few words at 40x12.
|
||||
state.check = {**state.check, "data_missing": 7, "data_bytes": 2048}
|
||||
text = " ".join(" ".join(install.tui_view(state, 40, 12)).split())
|
||||
self.assertIn("Game data: what a game reads, of no use to other cores. Data files: "
|
||||
"what an emulator reads from its own data folder.", text)
|
||||
text = " ".join(" ".join(install.tui_view(state, 40, 15)).split())
|
||||
self.assertIn("such as Dolphin's Sys and PPSSPP's assets.", text)
|
||||
|
||||
def test_the_40_column_bar_keeps_help_and_the_help_its_tap_line(self):
|
||||
"""code_audit_20 P3-1."""
|
||||
state = checked_state()
|
||||
state.mouse = True
|
||||
state.stack.append("systems")
|
||||
state.focus["systems"] = 1
|
||||
bar = str(install.tui_view(state, 40, 12)[-1])
|
||||
self.assertIn("? Help", bar)
|
||||
state.help = True
|
||||
text = " ".join(" ".join(install.tui_view(state, 40, 12)).split())
|
||||
self.assertIn("Tap Tick or untick a row, as Space", text)
|
||||
|
||||
def test_one_spelling_of_a_folder_on_the_plan_and_the_result(self):
|
||||
"""tui_audit_13 P3-3: "/home...i_audit13/rb/bios" on the plan, the
|
||||
same folder whole and folded inside a name on the result."""
|
||||
dest = Path("/home/moi/retroarch_system/tmp/tui_audit13/rb/bios")
|
||||
for cols in (40, 80):
|
||||
with self.subTest(cols=cols):
|
||||
plan = checked_state()
|
||||
plan.dest = dest
|
||||
result = _installed_state(dest)
|
||||
spelled = []
|
||||
for state in (plan, result):
|
||||
lines = [str(line).strip() for line in install.tui_view(state, cols, 24)]
|
||||
at = next(i for i, line in enumerate(lines)
|
||||
if line.startswith("BIOS folder:"))
|
||||
pieces = [lines[at]]
|
||||
while pieces[-1].endswith("/") and lines[at + len(pieces)]:
|
||||
pieces.append(lines[at + len(pieces)])
|
||||
spelled.append(pieces)
|
||||
self.assertNotIn("...", " ".join(lines))
|
||||
self.assertTrue(all(len(piece) <= cols - 2 for piece in pieces), pieces)
|
||||
self.assertEqual(spelled[0], spelled[1])
|
||||
self.assertEqual("".join(spelled[0]), f"BIOS folder: {dest}")
|
||||
|
||||
def test_a_long_path_fits_without_its_indent(self):
|
||||
"""tui_audit_13 P3-3: a pack path of 75 cells folded at 80 columns
|
||||
under an indent of 6."""
|
||||
path = "/home/moi/retroarch_system/tmp/tui_audit13/pack/MinUI_2025-11_BIOS_Pack.zip"
|
||||
self.assertEqual(len(path), 75)
|
||||
lines = install._wrap(f" python3 install.py --from-pack {path}", 78,
|
||||
whole="command")
|
||||
self.assertIn(path, lines)
|
||||
|
||||
def test_the_definition_is_said_once_and_never_spliced(self):
|
||||
"""tui_audit_13 P3-5."""
|
||||
state = checked_state()
|
||||
state.systems = []
|
||||
state.manifest = {**MANIFEST, "categorized": True, "omitted_files": [
|
||||
{"dest": "jazz2/Source/Anims.j2a", "system": "jazz-jackrabbit-2",
|
||||
"required": True, "category": "game_data"}]}
|
||||
state.check = {**CHECK, "not_installable": 1}
|
||||
text = " ".join(" ".join(install.tui_view(state, 120, 40)).split())
|
||||
self.assertEqual(text.count("files a game or a game engine reads"), 1, text)
|
||||
self.assertIn("Not available here: jazz2/Source/Anims.j2a (Jazz Jackrabbit 2), game "
|
||||
"data its game reads.", text)
|
||||
|
||||
def test_the_headline_counts_every_file_once(self):
|
||||
"""tui_audit_13 P3-6: "8358 files and 2636 data files", and the
|
||||
definition dropped at 80 columns."""
|
||||
state = _game_state()
|
||||
state.check = {**state.check, "data_missing": 7, "data_bytes": 2048}
|
||||
lines = [str(line).strip() for line in install.tui_view(state, 80, 24)]
|
||||
text = " ".join(" ".join(lines).split())
|
||||
self.assertIn("11 files to download, 1.0 MB", text)
|
||||
self.assertNotIn("and 7 data files", lines[2])
|
||||
self.assertIn("Data files: the files an emulator reads", text)
|
||||
|
||||
def test_the_save_line_never_ends_on_its_colon(self):
|
||||
"""tui_audit_13 P3-7: "...goes to a folder per core under:" with no
|
||||
folder at 60x20."""
|
||||
state = _game_state()
|
||||
state.saves = {"event": "saves", "files": 1,
|
||||
"folder": "/home/user/.config/retroarch/saves/<core>"}
|
||||
shown = 0
|
||||
for rows in range(12, 30):
|
||||
with self.subTest(rows=rows):
|
||||
lines = [str(line).strip() for line in install.tui_view(state, 60, rows)]
|
||||
for index, line in enumerate(lines):
|
||||
if line.endswith("under:"):
|
||||
shown += 1
|
||||
self.assertTrue(lines[index + 1].startswith("~/"), lines)
|
||||
self.assertGreater(shown, 0)
|
||||
|
||||
def test_the_result_says_how_to_copy_and_counts_one_kind_once(self):
|
||||
"""tui_audit_13 P3-10 and P3-14."""
|
||||
state = _installed_state(SYSTEM_DIR)
|
||||
state.manifest = {**MANIFEST, "categorized": True}
|
||||
state.mouse = True
|
||||
state.finished = [(event["dest"], True, "") for event in FILES]
|
||||
state.summary = {**state.summary, "installed": 4}
|
||||
_title, lines = install.tui_outcome(state)
|
||||
self.assertEqual(lines[0], "4 BIOS files installed.")
|
||||
self.assertFalse(any(line.startswith("Installed:") for line in lines), lines)
|
||||
self.assertEqual(lines[-1], install.TUI_RESULT_COPY)
|
||||
self.assertNotIn(install.TUI_RESULT_COPY, install.tui_farewell(state))
|
||||
state.help = True
|
||||
self.assertIn("Shift+drag", " ".join(install.tui_view(state, 80, 24)))
|
||||
|
||||
def test_the_old_card_result_splits_what_is_missing(self):
|
||||
"""tui_audit_13 P3-14: "16 still missing" where 6 were game data."""
|
||||
state = _game_state()
|
||||
state.from_folders = [Path("/media/OLD")]
|
||||
state.local_dests = {"gba_bios.bin": ("/media/OLD", "")}
|
||||
state.finished = [("gba_bios.bin", True, "")]
|
||||
state.download = {"files": 4}
|
||||
state.stack, state.run = ["result"], "install"
|
||||
state.summary = {"event": "summary", "mode": "install", "installed": 1,
|
||||
"up_to_date": 0, "pending": 3, "failed": [], "skipped": [],
|
||||
"left_out": [], "kept": [], "interrupted": False}
|
||||
with mock.patch.dict(os.environ, {install.OFFLINE_VARIABLE:
|
||||
install.OFFLINE_FLAG_VALUE}):
|
||||
_title, lines = install.tui_outcome(state)
|
||||
self.assertIn("Still missing: 2 BIOS files and 1 game data file.", lines)
|
||||
|
||||
# Root cause 6: every other word.
|
||||
|
||||
def test_drives_are_named_once_under_wsl_and_windows(self):
|
||||
"""code_audit_20 P3-3: "D:: bios" and "D:\\: bios"."""
|
||||
with mock.patch.dict(install._WSL, {"active": True}):
|
||||
mount = Path(install._WSL["root"]) / "d"
|
||||
self.assertEqual(install._drive_folder(mount, "bios"), "D:\\bios")
|
||||
windows = PureWindowsPath("D:\\")
|
||||
with mock.patch.object(install, "_mount_name", return_value="D:\\"), \
|
||||
mock.patch.object(install, "shown_path", side_effect=str):
|
||||
self.assertEqual(install._drive_folder(windows, "bios"), "D:\\bios")
|
||||
stick = Path("/media/moi/USBSTICK")
|
||||
self.assertEqual(install._drive_folder(stick, "bios"), "USBSTICK: bios")
|
||||
|
||||
def test_the_linux_side_is_named_by_its_side(self):
|
||||
"""code_audit_20 P3-3, tui_audit_13 P3-9."""
|
||||
self.assertEqual(install.side_name("wsl", "retroarch"), "Linux RetroArch")
|
||||
self.assertEqual(install.side_name("linux", "retroarch"), "RetroArch")
|
||||
state = fresh_state()
|
||||
state.os_type, state.platform = "wsl", "retroarch"
|
||||
state.stack = ["setup", "folder"]
|
||||
state.folder_default, state.folder_kind = SYSTEM_DIR, "usual"
|
||||
with mock.patch.object(install, "_mounted_cards", return_value=[]), \
|
||||
mock.patch.object(install, "_is_dir", return_value=False):
|
||||
text = "\n".join(install.tui_view(state, 100, 30))
|
||||
self.assertIn("Linux RetroArch usually reads its BIOS files from:", text)
|
||||
self.assertIn("(does not exist yet)", text)
|
||||
|
||||
def test_a_folder_created_where_no_setup_is_says_so(self):
|
||||
"""tui_audit_13 P3-9: "system is created in C:\\RetroArch-Win64, where
|
||||
RetroArch reads it" with no RetroArch there."""
|
||||
state = fresh_state()
|
||||
missing = self.root / "RetroArch-Win64" / "system"
|
||||
with mock.patch.object(install, "_start_check", return_value=[]):
|
||||
install._choose(state, "retroarch", missing, proposed=True)
|
||||
self.assertIn("a folder that does not exist yet", state.card_note)
|
||||
self.assertNotIn("reads it", state.card_note)
|
||||
here = self.root / "pc" / "bios"
|
||||
with mock.patch.object(install, "_start_check", return_value=[]):
|
||||
install._choose(state, "retroarch", here, proposed=True)
|
||||
self.assertIn("where RetroArch reads it", state.card_note)
|
||||
|
||||
def test_the_needed_list_counts_one_more_system_in_words(self):
|
||||
"""tui_audit_13 P3-13, on the list of files an emulator needs too."""
|
||||
entries = [{"dest": f"s{n}.bin", "system": f"system-{n}", "required": True}
|
||||
for n in range(9)]
|
||||
said = " ".join(install._needed_lines(entries, "Needed"))
|
||||
self.assertIn("... and 1 more system (--check --verbose lists them all)", said)
|
||||
|
||||
def test_the_farewell_names_the_option_not_the_screen(self):
|
||||
"""code_audit_20 P3-4."""
|
||||
state = _installed_state(SYSTEM_DIR)
|
||||
state.summary = {**state.summary, "skipped": [
|
||||
{"reason": "no_save_directory", "label": "", "files": 1, "required": False}]}
|
||||
farewell = " ".join(install.tui_farewell(state))
|
||||
self.assertIn("Name it with --save-dir next time.", farewell)
|
||||
self.assertNotIn("Options", farewell)
|
||||
|
||||
def test_more_systems_is_counted_in_words(self):
|
||||
"""tui_audit_13 P3-13: "... and 1 more systems"."""
|
||||
entries = [{"dest": f"s{n}.bin", "size": 10, "systems": [f"system-{n:02d}"]}
|
||||
for n in range(install.PLAN_LARGEST_SYSTEMS + 1)]
|
||||
out = io.StringIO()
|
||||
with contextlib.redirect_stdout(out):
|
||||
install._print_plan(entries, SYSTEM_DIR, install.Terminal(io.StringIO()))
|
||||
self.assertIn("... and 1 more system:", out.getvalue())
|
||||
|
||||
def test_the_systems_question_aligns_and_explains_after_the_list(self):
|
||||
"""tui_audit_13 P3-13."""
|
||||
rows = [("mattel-intellivision", []), ("nec-pc-engine", []),
|
||||
(install.OTHER_SYSTEMS, [])]
|
||||
labels = {"mattel-intellivision": "Mattel Intellivision mattel-intellivision",
|
||||
"nec-pc-engine": "NEC PC Engine nec-pc-engine",
|
||||
install.OTHER_SYSTEMS: install.OTHER_TITLE + " " + "x" * 10}
|
||||
out = io.StringIO()
|
||||
with contextlib.redirect_stdout(out), \
|
||||
mock.patch.object(install, "_ask", return_value=""):
|
||||
install._pick("Systems:", rows, labels=labels, note="A note.",
|
||||
sizer=lambda files: "1 file")
|
||||
lines = out.getvalue().splitlines()
|
||||
listed = [line for line in lines if line.endswith("1 file")]
|
||||
self.assertEqual(len({line.index("1 file") for line in listed}), 1, listed)
|
||||
self.assertGreater(lines.index("A note."), lines.index(listed[-1]))
|
||||
|
||||
def test_the_yes_stop_says_one_thing_with_a_list_or_without(self):
|
||||
"""tui_audit_13 P3-13, code_audit_20 P3-6: "the file list" said of a
|
||||
pack, and two wordings for one stop."""
|
||||
pack = self.root / "RetroArch_BIOS_Pack.zip"
|
||||
with zipfile.ZipFile(pack, "w") as archive:
|
||||
archive.writestr("manifest.json", json.dumps({"files": []}))
|
||||
env = {"HOME": str(self.root / "home"), "XDG_CONFIG_HOME": str(self.root / "cfg"),
|
||||
"RETROBIOS_OS": "linux"}
|
||||
said = install_run("--from-pack", str(pack), "--yes", env=env)
|
||||
self.assertEqual(said.returncode, 1, said.stdout + said.stderr)
|
||||
self.assertIn("No supported platform detected: RetroArch was not found here, and "
|
||||
"the pack does not say where it goes.", said.stderr)
|
||||
alone = install_run("--yes", env=env)
|
||||
self.assertIn("No supported platform detected", alone.stdout + alone.stderr)
|
||||
hint = install._manual_usage_hint("linux")
|
||||
self.assertTrue(hint[0].startswith(" Name the setup with --platform and its folder "
|
||||
"with --dest"), hint)
|
||||
page = (REPO_ROOT / "wiki" / "installer.md").read_text(encoding="utf-8")
|
||||
self.assertIn("every run without questions stops before reading it", page)
|
||||
self.assertIn("none stops it too, with `reason` `not_found`", page)
|
||||
self.assertIn("So is a platform named by a file list or a pack", page)
|
||||
|
||||
|
||||
class TheUsageNamesTheInstaller(unittest.TestCase):
|
||||
"""The Windows one-liner's --help said "usage: retrobios-install-<guid>.py",
|
||||
the name install.ps1 gives its copy."""
|
||||
|
||||
def test_a_copy_under_a_temporary_name_says_install_py(self):
|
||||
scratch = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp"))
|
||||
self.addCleanup(shutil.rmtree, scratch, True)
|
||||
copy = scratch / "retrobios-install-33826e0b-37cc-4ad3-a6c4-6ed168e3fe9e.py"
|
||||
shutil.copyfile(REPO_ROOT / "install.py", copy)
|
||||
env = {**os.environ, "RETROBIOS_BOOTSTRAP": "ps1"}
|
||||
for option in ("--help", "--no-such-option"):
|
||||
with self.subTest(option=option):
|
||||
proc = subprocess.run([sys.executable, str(copy), option], env=env,
|
||||
capture_output=True, text=True, timeout=60,
|
||||
stdin=subprocess.DEVNULL, check=False)
|
||||
said = proc.stdout + proc.stderr
|
||||
self.assertIn("usage: install.py", said)
|
||||
self.assertNotIn("retrobios-install-", said)
|
||||
with mock.patch.object(sys, "argv", [str(copy), "--help"]):
|
||||
self.assertEqual(install.build_parser().prog, "install.py")
|
||||
|
||||
|
||||
class TapsSeenBeforeTheyAct(unittest.TestCase):
|
||||
"""code_audit_20 P3-2 and tui_audit_13 P2-1, P2-2: a tap acts on the
|
||||
frame it was made on, and never commits on one tap."""
|
||||
|
||||
def test_a_release_on_a_later_frame_does_nothing(self):
|
||||
state = checked_state()
|
||||
state.mouse = True
|
||||
lines = drawn(state, 80, 24)
|
||||
row = next(i for i, line in enumerate(lines)
|
||||
if getattr(line, "mark", None) and line.mark[0] == "row"
|
||||
and line.mark[2][0] == "systems")
|
||||
install.tui_update(state, install.TuiMouse(0, 5, row + 1))
|
||||
# The screen changes under the finger before it comes up.
|
||||
state.stack.append("options")
|
||||
drawn(state, 80, 24)
|
||||
state.stack.pop()
|
||||
drawn(state, 80, 24)
|
||||
effects = install.tui_update(state, install.TuiMouse(0, 5, row + 1, True))
|
||||
self.assertEqual(effects, [])
|
||||
self.assertIsNone(state.tapped)
|
||||
|
||||
def test_the_bar_install_arms_then_presses(self):
|
||||
state = checked_state()
|
||||
state.mouse = True
|
||||
lines = drawn(state, 80, 24)
|
||||
bar = len(lines) - 1
|
||||
self.assertEqual(tap(state, 3, bar), [])
|
||||
self.assertEqual(state.screen, "plan")
|
||||
armed = drawn(state, 80, 24)
|
||||
self.assertIn("A/Enter Install: tap again", str(armed[-1]))
|
||||
self.assertEqual(tap(state, 3, bar), [("run", "install")])
|
||||
|
||||
def test_a_tapped_quit_quits_with_the_quit_code(self):
|
||||
state = checked_state()
|
||||
state.mouse = True
|
||||
state.stack.append("checking")
|
||||
state.running, state.run = True, "check"
|
||||
lines = drawn(state, 80, 24)
|
||||
self.assertFalse(str(lines[-1]).strip().startswith("Ctrl-C"))
|
||||
at = str(lines[-1]).index("Ctrl-C")
|
||||
tap(state, at, len(lines) - 1)
|
||||
self.assertIsNone(state.exit_code)
|
||||
drawn(state, 80, 24)
|
||||
at = str(install.tui_view(state, 80, 24)[-1]).index("Ctrl-C")
|
||||
tap(state, at, len(lines) - 1)
|
||||
self.assertEqual(state.exit_code, install.QUIT_CODE)
|
||||
|
||||
def test_two_taps_on_a_region_leave_it_unticked_where_it_was(self):
|
||||
state = checked_state()
|
||||
state.mouse = True
|
||||
install.tui_update(state, Key("char", "o"))
|
||||
install.tui_update(state, Key("enter"))
|
||||
self.assertEqual(state.screen, "regions")
|
||||
lines = drawn(state, 80, 24)
|
||||
before = [row.value for row in install.tui_rows(state)]
|
||||
row = next(i for i, line in enumerate(lines)
|
||||
if getattr(line, "mark", None) and line.mark[0] == "row"
|
||||
and line.mark[2][1] == "north-america")
|
||||
tap(state, 5, row)
|
||||
drawn(state, 80, 24)
|
||||
self.assertEqual(state.regions, ["north-america"])
|
||||
self.assertEqual([row.value for row in install.tui_rows(state)], before)
|
||||
tap(state, 5, row)
|
||||
self.assertEqual(state.regions, [])
|
||||
bar = str(drawn(state, 80, 24)[-1])
|
||||
self.assertIn("A/Enter/tap Tick", bar)
|
||||
state.help = True
|
||||
self.assertIn("as A", " ".join(install.tui_view(state, 80, 24)))
|
||||
|
||||
|
||||
@unittest.skipUnless(pyte and pty and hasattr(pty, "fork"),
|
||||
"screen tests need pyte (pip install pyte==0.8.2) and a pty")
|
||||
class TapsOnAPtySeeFirst(unittest.TestCase):
|
||||
"""tui_audit_13 P1-1, P2-1, P2-2 on the real install.py --tui."""
|
||||
|
||||
repo = EndToEnd.repo
|
||||
start = EndToEnd.start
|
||||
line_of = staticmethod(MouseOnAPty.line_of)
|
||||
click = MouseOnAPty.click
|
||||
|
||||
def bar_entry(self, term: Pty, word: str) -> tuple[int, int]:
|
||||
line = len(term.screen.display) - 1
|
||||
return term.screen.display[line].index(word), line
|
||||
|
||||
def test_one_tap_on_the_bar_install_installs_nothing(self):
|
||||
repo = self.repo()
|
||||
term = self.start()
|
||||
term.wait("Where do you play?")
|
||||
term.send("\r")
|
||||
term.wait("> Install")
|
||||
term.settle()
|
||||
self.click(term, *self.bar_entry(term, "Install"))
|
||||
self.assertIn("tap again", term.settle().splitlines()[-1])
|
||||
self.assertEqual(repo.installed(), [])
|
||||
self.click(term, *self.bar_entry(term, "Install"))
|
||||
term.wait("files installed")
|
||||
term.send("q")
|
||||
term.close()
|
||||
|
||||
def test_a_double_tap_on_continue_neither_quits_nor_installs(self):
|
||||
repo = self.repo()
|
||||
term = self.start()
|
||||
term.wait("Where do you play?")
|
||||
term.settle()
|
||||
col, line = self.bar_entry(term, "Continue")
|
||||
report = sgr(col + 1, line + 1) + sgr(col + 1, line + 1, release=True)
|
||||
term.send(report + report)
|
||||
term.settle()
|
||||
term.send(report)
|
||||
term.settle(0.6)
|
||||
self.assertIsNone(os.waitpid(term.pid, os.WNOHANG)[0] or None)
|
||||
self.assertEqual(repo.installed(), [])
|
||||
term.send("q")
|
||||
if "Quit?" in term.settle():
|
||||
term.send("\r")
|
||||
self.assertIn(term.close(), (install.QUIT_CODE, 0))
|
||||
|
||||
def test_continue_then_install_in_one_cell_stops_on_confirm(self):
|
||||
repo = self.repo()
|
||||
term = self.start()
|
||||
term.wait("Where do you play?")
|
||||
term.send("\r")
|
||||
term.wait("> Install")
|
||||
row = self.line_of(term, "Choose systems")
|
||||
self.click(term, 20, row)
|
||||
term.settle()
|
||||
self.click(term, 20, row)
|
||||
term.wait("RetroBIOS: Choose systems")
|
||||
row = self.line_of(term, "sony-playstation")
|
||||
self.click(term, 20, row)
|
||||
term.settle()
|
||||
col, line = self.bar_entry(term, "Continue")
|
||||
report = sgr(col + 1, line + 1) + sgr(col + 1, line + 1, release=True)
|
||||
# A double tap: the first arms Continue, the second opens Confirm.
|
||||
term.send(report + report)
|
||||
term.wait("Counted again for your choices")
|
||||
term.settle()
|
||||
self.assertEqual(repo.installed(), [])
|
||||
# Install in the same cell: one tap arms it, nothing is written.
|
||||
term.send(report)
|
||||
screen = term.settle(0.6)
|
||||
self.assertIn("RetroBIOS: Confirm", screen)
|
||||
self.assertIn("Install: tap again", screen.splitlines()[-1])
|
||||
self.assertEqual(repo.installed(), [])
|
||||
term.send("q")
|
||||
term.close()
|
||||
|
||||
def test_the_game_data_row_keeps_the_ticks_to_the_install(self):
|
||||
from test_install_tui import GameDataRepository # noqa: PLC0415
|
||||
|
||||
repo = self.repo(GameDataRepository)
|
||||
term = self.start()
|
||||
term.wait("Where do you play?")
|
||||
term.send("\r")
|
||||
term.wait("> Install")
|
||||
for _step in range(8):
|
||||
if "> Choose systems" in term.settle():
|
||||
break
|
||||
term.send("\x1b[B")
|
||||
term.send("\r")
|
||||
term.wait("RetroBIOS: Choose systems")
|
||||
term.send("n")
|
||||
for _step in range(8):
|
||||
if "> [ ] nintendo-gba" in term.settle():
|
||||
break
|
||||
term.send("\x1b[B")
|
||||
term.send(" ")
|
||||
term.settle()
|
||||
term.send("\x1b")
|
||||
term.wait("> Install")
|
||||
for _step in range(8):
|
||||
if "> Game data: kept" in term.settle():
|
||||
break
|
||||
term.send("\x1b[B")
|
||||
term.send("\r")
|
||||
term.wait("Game data: left out")
|
||||
for _step in range(8):
|
||||
if "> Install" in term.settle():
|
||||
break
|
||||
term.send("\x1b[A")
|
||||
term.send("\r")
|
||||
screen = term.wait("RetroBIOS:")
|
||||
if "Confirm" in term.settle():
|
||||
term.send("\r")
|
||||
term.wait("files installed")
|
||||
self.assertEqual(repo.installed(), ["gba_bios.bin", "mgba/extra.bin"])
|
||||
del screen
|
||||
term.send("q")
|
||||
term.close()
|
||||
|
||||
def test_two_taps_on_a_region_untick_it_where_it_was(self):
|
||||
self.repo()
|
||||
term = self.start()
|
||||
term.wait("Where do you play?")
|
||||
term.send("\r")
|
||||
term.wait("> Install")
|
||||
term.send("o")
|
||||
term.wait("Preferred regions")
|
||||
term.send("\r")
|
||||
term.wait("RetroBIOS: Preferred regions")
|
||||
row = self.line_of(term, "North America")
|
||||
self.click(term, 20, row)
|
||||
screen = term.settle()
|
||||
self.assertIn("[1] North America", screen.splitlines()[row])
|
||||
self.click(term, 20, row)
|
||||
screen = term.settle()
|
||||
self.assertIn("[ ] North America", screen.splitlines()[row])
|
||||
self.assertNotIn("[1]", screen)
|
||||
term.send("q")
|
||||
term.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+22
-13
@@ -138,9 +138,12 @@ they do online, and a file of the list the pack does not hold fails as
|
||||
`not in the pack`. The list's platform has to be the one installed for.
|
||||
|
||||
`--offline` forbids every request, for a device with no Wi-Fi: `--check`
|
||||
still names the platform and its folder, then stops at the file list unless
|
||||
`--manifest` or `--from-pack` gives it, and counts the files that need the
|
||||
internet instead of offering to fetch them. The run installs the copies found
|
||||
still names the platform and its folder where it finds them, then stops at the
|
||||
file list unless `--manifest` or `--from-pack` gives it, and counts the files
|
||||
that need the internet instead of offering to fetch them. A file list or a pack
|
||||
names its platform, not where that platform is: when it is found nowhere here,
|
||||
every run without questions stops before reading it, `--check`, `--dry-run`
|
||||
and `--no-input` included, and names the `--dest` to give. The run installs the copies found
|
||||
on this machine and downloads nothing. The files left out are missing, not
|
||||
failed: it ends `Finished with files missing` (code 1), or `Nothing installed`
|
||||
(code 2) when nothing was installed, at a terminal, without questions and on
|
||||
@@ -262,11 +265,16 @@ does. On any other row it moves the cursor there, and a second one on that
|
||||
row does what Enter does: one row of a terminal is far smaller than a finger,
|
||||
and the row a screen opens on (**Install** on Confirm) is never chosen by one
|
||||
tap. The entries of the bottom line press their key, **Exit** on the result
|
||||
too, the line that says which rows are in view shows the next page, and the
|
||||
wheel scrolls a list or a text without moving the cursor unless it would leave
|
||||
the screen. Nothing happens until the button or the finger comes up, and only
|
||||
where it went down. The right and middle buttons do nothing. The help and the
|
||||
bottom line of a list of boxes say how a tap acts.
|
||||
too. One that installs, quits or goes on to Confirm takes two taps as a row
|
||||
does: the first adds `tap again` to it, the second presses it. A row of
|
||||
Preferred regions stays where it is when it is ticked, its number giving the
|
||||
order, which the list shows sorted the next time it opens. The line that says
|
||||
which rows are in view shows the next page, and the wheel scrolls a list or a
|
||||
text without moving the cursor unless it would leave the screen. Nothing
|
||||
happens until the button or the finger comes up, and only where it went down,
|
||||
on the screen drawn when it went down: the second tap of a double tap that
|
||||
changes the screen does nothing on the new one. The right and middle buttons
|
||||
do nothing. The help and the bottom line of a list of boxes say how a tap acts.
|
||||
|
||||
Clicks are off in the Windows console the PowerShell command runs in, which
|
||||
reports no click as a key, with `TERM` unset or set to `dumb`, `unknown`,
|
||||
@@ -276,9 +284,10 @@ them back on every way out, a stop with Ctrl+Z included. On the command line
|
||||
screen, any screen showing a command and the screen where a path is typed,
|
||||
the terminal keeps the mouse, so text is selected, copied and pasted as usual.
|
||||
The result takes taps, so a touch screen can leave it: it is printed again in
|
||||
the terminal once the screen closes, its commands with it. Elsewhere, hold
|
||||
Shift while selecting. `--plain` never asks for clicks. Clicks and taps were checked on
|
||||
2026-10-27 in xterm, tmux, GNU screen 4.09, Windows Terminal (WSL) and Termux
|
||||
the terminal once the screen closes, its commands with it, and its last line
|
||||
says so. Elsewhere, and on the result, hold Shift while selecting. `--plain`
|
||||
never asks for clicks. Clicks and taps were checked on 2026-10-27 in xterm,
|
||||
tmux, GNU screen 4.09, Windows Terminal (WSL) and Termux
|
||||
on Android 17. macOS Terminal and iTerm2 are not checked yet, nor the key
|
||||
they use to select over the installer.
|
||||
|
||||
@@ -862,7 +871,7 @@ what the options name, everything by default.
|
||||
| <span id="option-list-cores"></span>`--list-cores` | Print the cores whose extra files a platform installs |
|
||||
| <span id="option-list-emulators"></span>`--list-emulators` | Print every name `--emulator` accepts, each buildbot name beside the emulator it stands for |
|
||||
| <span id="option-romm-firmware"></span>`--romm-firmware TEMPLATE` | RomM: where each platform's firmware goes in the library, as `filesystem.structure.firmware` in RomM's `config.yml` says (`{platform}/bios` for a library laid out as `{platform}/roms`). Read from `config.yml` beside the library when it is there. See [RomM firmware layout](#romm-firmware-layout) |
|
||||
| <span id="option-no-input"></span>`--no-input` | Never ask a question, even at a terminal. A run whose output goes to a file or a pipe asks nothing either, and says so on stderr. It finds the setups and the mounted cards the screen finds: one is taken, as Enter takes it, and two stop the run with an `error` event (`stage` `detect`, `reason` `conflict`) naming each with its `--platform` and `--dest` |
|
||||
| <span id="option-no-input"></span>`--no-input` | Never ask a question, even at a terminal. A run whose output goes to a file or a pipe asks nothing either, and says so on stderr. It finds the setups and the mounted cards the screen finds: one is taken, as Enter takes it, two stop the run with an `error` event (`stage` `detect`, `reason` `conflict`) naming each with its `--platform` and `--dest`, and none stops it too, with `reason` `not_found` when a file list or a pack names the platform |
|
||||
| <span id="option-check"></span>`--check` | Report and exit without writing |
|
||||
| <span id="option-dry-run"></span>`--dry-run` | Show what would be downloaded, the totals first, then by system and with sizes, without writing anything. A plan taller than the screen names the ten largest systems, and `--verbose` lists every system and file |
|
||||
| <span id="option-yes"></span>`--yes`, `-y` | Do not ask before a download of 1 GB or more, nor anything else. Implies `--no-input`, so a run that needs an answer (nothing found here, a file list or a pack naming its platform included, or two setups found) stops on what to name instead. `--platform` names a setup, whose usual folder is then taken |
|
||||
@@ -1623,7 +1632,7 @@ other schemas under `api/v1/schemas/`.
|
||||
| `start` | `schema`, `installer`, `mode` | First line. `schema` is 1, `installer` the identity `--version` prints, `mode` one of `install`, `check`, `dry-run`, `list` |
|
||||
| `unsearched` | `folder`, `reason`, `message` | Before `detect`, once for each folder the search for setups could not look in, this user being refused it. What it would hold counts as absent, and the other places are still searched: `detect` then lists what they hold, and an empty `platforms` after an `unsearched` line means nothing was found where the installer could look. `reason` says why in words (`Permission denied`), `message` says it in a sentence |
|
||||
| `detect` | `os`, `os_name`, `platforms` | Once the platforms are known. `os_name` comes from `/etc/os-release`. `platforms` lists `{platform, name, bios_dir}`, and is empty when nothing supported was found |
|
||||
| `error` | `stage`, `reason`, `platform`, `message` | The file list could not be read (`stage` is `manifest`): `reason` is `network`, `not_found` or `invalid`, `clock` when the server's certificate was refused and the system clock reads a date before the installer was written, `no_ca` when the machine holds no list of trusted certificates (`SSL_CERT_FILE` names one), or `offline` when `--offline` forbids the request. A folder named with `--from` cannot be read (`stage` is `from`, `reason` `not_found`, `not_a_folder` for a file that is no ZIP, `unreadable`, or `system` for the root of the system, `/proc`, `/sys` or `/dev`). The BIOS folder sits under a folder this user cannot open (`stage` is `dest`, `reason` `unreadable`), and the run ends with code 1 before anything is written. The BIOS folder cannot be created (`stage` is `dest`, `reason` `not_writable`): a `summary` follows with what the run installed before it. Two systems are detected on one machine and no `--dest` names the folder (`stage` is `detect`, `reason` `conflict`). The platform named with `--platform` is found nowhere and no folder can be assumed for it: a card system with no card named, a portable emulator, Batocera or Recalbox named on a computer (their folder is the `bios` folder of their SHARE drive), or no usual folder on this system or one set aside behind a folder this user cannot open (`stage` is `detect`, `reason` `not_found`). A `--dest` refused as the card of the system named carries the same `stage` and `reason`: another system's card, a folder inside a card, a drive with none of the files its card always has, or a folder that does not exist. `message` says it in words, and is the only thing that tells these cases apart |
|
||||
| `error` | `stage`, `reason`, `platform`, `message` | The file list could not be read (`stage` is `manifest`): `reason` is `network`, `not_found` or `invalid`, `clock` when the server's certificate was refused and the system clock reads a date before the installer was written, `no_ca` when the machine holds no list of trusted certificates (`SSL_CERT_FILE` names one), or `offline` when `--offline` forbids the request. A folder named with `--from` cannot be read (`stage` is `from`, `reason` `not_found`, `not_a_folder` for a file that is no ZIP, `unreadable`, or `system` for the root of the system, `/proc`, `/sys` or `/dev`). The BIOS folder sits under a folder this user cannot open (`stage` is `dest`, `reason` `unreadable`), and the run ends with code 1 before anything is written. The BIOS folder cannot be created (`stage` is `dest`, `reason` `not_writable`): a `summary` follows with what the run installed before it. Two systems are detected on one machine and no `--dest` names the folder (`stage` is `detect`, `reason` `conflict`). The platform named with `--platform` is found nowhere and no folder can be assumed for it: a card system with no card named, a portable emulator, Batocera or Recalbox named on a computer (their folder is the `bios` folder of their SHARE drive), or no usual folder on this system or one set aside behind a folder this user cannot open (`stage` is `detect`, `reason` `not_found`). So is a platform named by a file list or a pack, in a run without questions where it is found nowhere here. A `--dest` refused as the card of the system named carries the same `stage` and `reason`: another system's card, a folder inside a card, a drive with none of the files its card always has, or a folder that does not exist. `message` says it in words, and is the only thing that tells these cases apart |
|
||||
| `scanned` | `folder`, `files`, `truncated`, `other_drives` | Each folder named with `--from`, once read and before `detect`. `files` counts the files found, `truncated` is true when the search stopped at 200,000 of them, and `other_drives` lists the folders below it on another drive, which were not entered |
|
||||
| `version` | `platform`, `list_version`, `installed_version`, `message` | Before `choices`, when the system here runs another version than the one the list was built for: `list_version` is the list's, `installed_version` the one the system's version file states, and `message` says it and what it means. Not written when either version is unknown. The run goes on |
|
||||
| `choices` | `platform`, `systems` | Before `checking`: the systems the run's list lets one choose among, sorted by id, `other` last for the files no system names. The run's other options apply (`--core`, `--region`, `--no-game-data`, the files left out for an unknown save directory), `--system` does not: these are the systems a screen lists to choose from, and the count a `--system` is out of |
|
||||
|
||||
Reference in new issue
Block a user