mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-26 21:57:24 -05:00
fix: settle the interface audit findings
A stop by SIGTERM (Start+Select under gptokeyb) reads the summary like Ctrl-C and prints the count on disk. The systems filter keeps the ticks and the focus. The bar names what A does on the focused row. Options check the folder again, a missing network fails in 15 s with plain words, an unwritable folder offers another one, a folder inside a card offers its root, and only a failure keeps its log. New event kind: checking, with files_done and files_total, while the files in place are hashed. The exact event lists of the check and install runs now carry two of them, for the two files in place.
This commit is contained in:
1 parent
48086b9966
commit
588a8d3350
68 files changed
+1012
-271
No files matched your search
+1
-1
@@ -11,7 +11,7 @@
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
$defaultInstallSha256 = "d0a92cac2d09da791fe3dbacdad37ec7e40b5a3685a39e3cc02f0dcbd5a556e6"
|
||||
$defaultInstallSha256 = "84ba56c9498a8bf89db4c4af8bd3413871f467771b36aea36158458aa4644ef8"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+479
-137
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="d0a92cac2d09da791fe3dbacdad37ec7e40b5a3685a39e3cc02f0dcbd5a556e6"
|
||||
DEFAULT_INSTALL_SHA256="84ba56c9498a8bf89db4c4af8bd3413871f467771b36aea36158458aa4644ef8"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
Vendored
+1
-1
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Open B/Esc Back ? Help
|
||||
A/Enter Use this folder B/Esc Back ? Help
|
||||
Vendored
+1
-1
@@ -9,4 +9,4 @@
|
||||
system/
|
||||
|
||||
|
||||
A/Enter Open B/Esc Back ? Help
|
||||
A Use this folder B Back ? Help
|
||||
Vendored
+1
-1
@@ -12,4 +12,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Open B/Esc Back ? Help
|
||||
A Use this folder B Back ? Help
|
||||
Vendored
+1
-1
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Open B/Esc Back ? Help
|
||||
A/Enter Use this folder B/Esc Back ? Help
|
||||
Vendored
+1
-1
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Done B/Esc Back X/Space Tick ? Help
|
||||
A/Enter Filter B/Esc Back X/Space Tick ? Help
|
||||
Vendored
+1
-1
@@ -9,4 +9,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Done B/Esc Back X/Space Tick
|
||||
A Filter B Back X Tick ? Help
|
||||
Vendored
+1
-1
@@ -12,4 +12,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Done B/Esc Back X/Space Tick
|
||||
A Filter B Back X Tick ? Help
|
||||
Vendored
+1
-1
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Done B/Esc Back X/Space Tick ? Help
|
||||
A/Enter Filter B/Esc Back X/Space Tick ? Help
|
||||
Vendored
+1
-1
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back
|
||||
A/Enter Create B/Esc Back
|
||||
Vendored
+1
-1
@@ -9,4 +9,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back
|
||||
A/Enter Create B/Esc Back
|
||||
Vendored
+1
-1
@@ -12,4 +12,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back
|
||||
A/Enter Create B/Esc Back
|
||||
Vendored
+1
-1
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back
|
||||
A/Enter Create B/Esc Back
|
||||
Vendored
+3
-3
@@ -4,8 +4,7 @@
|
||||
known
|
||||
Address: https://raw.githubusercontent.com/Abdess/retrobios/main/install/retroarch.json
|
||||
|
||||
> Try again
|
||||
Choose another setup or folder
|
||||
> Choose another setup or folder
|
||||
Quit
|
||||
|
||||
|
||||
@@ -37,4 +36,5 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back
|
||||
|
||||
A/Enter Back B/Esc Back
|
||||
Vendored
+6
-6
@@ -3,10 +3,10 @@
|
||||
Could not fetch the file list for
|
||||
retroarch after 3 attempts: [Errno
|
||||
-2] Name or service not known
|
||||
|
||||
> Try again
|
||||
Choose another setup or folder
|
||||
Address:
|
||||
https://raw.githubusercontent.com/
|
||||
Abdess/retrobios/main/install/
|
||||
retroarch.json
|
||||
> Choose another setup or folder
|
||||
Quit
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back
|
||||
A/Enter Back B/Esc Back
|
||||
Vendored
+3
-3
@@ -8,8 +8,8 @@
|
||||
Abdess/retrobios/main/install/
|
||||
retroarch.json
|
||||
|
||||
> Try again
|
||||
Choose another setup or folder
|
||||
> Choose another setup or folder
|
||||
Quit
|
||||
|
||||
A/Enter Choose B/Esc Back
|
||||
|
||||
A/Enter Back B/Esc Back
|
||||
Vendored
+3
-3
@@ -5,8 +5,7 @@
|
||||
Address: https://raw.githubusercontent.com/Abdess/retrobios/main/install/
|
||||
retroarch.json
|
||||
|
||||
> Try again
|
||||
Choose another setup or folder
|
||||
> Choose another setup or folder
|
||||
Quit
|
||||
|
||||
|
||||
@@ -21,4 +20,5 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back
|
||||
|
||||
A/Enter Back B/Esc Back
|
||||
Vendored
+1
-1
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back ? Help
|
||||
A/Enter Use this folder B/Esc Back ? Help
|
||||
Vendored
+1
-1
@@ -9,4 +9,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back ? Help
|
||||
A Use this folder B Back ? Help
|
||||
Vendored
+1
-1
@@ -12,4 +12,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back ? Help
|
||||
A Use this folder B Back ? Help
|
||||
Vendored
+1
-1
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back ? Help
|
||||
A/Enter Use this folder B/Esc Back ? Help
|
||||
+1
-1
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back ? Help
|
||||
A/Enter Browse B/Esc Back ? Help
|
||||
+1
-1
@@ -9,4 +9,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back ? Help
|
||||
A/Enter Browse B/Esc Back ? Help
|
||||
+1
-1
@@ -12,4 +12,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back ? Help
|
||||
A/Enter Browse B/Esc Back ? Help
|
||||
+1
-1
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Back ? Help
|
||||
A/Enter Browse B/Esc Back ? Help
|
||||
Vendored
+2
-2
@@ -1,8 +1,6 @@
|
||||
RetroBIOS: Keys
|
||||
|
||||
Up/Down, k/j Move
|
||||
PgUp/PgDn, L1/R1 Page
|
||||
Home/End, g/G First, last
|
||||
A/Enter, Start Install
|
||||
Y, o, Tab Options
|
||||
B/Esc, Backspace Back
|
||||
@@ -34,6 +32,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -1,12 +1,12 @@
|
||||
RetroBIOS: Keys
|
||||
|
||||
Up/Down, k/j Move
|
||||
PgUp/PgDn, L1/R1 Page
|
||||
Home/End, g/G First, last
|
||||
A/Enter, Start Install
|
||||
Y, o, Tab Options
|
||||
B/Esc, Backspace Back
|
||||
q, Ctrl-C Quit
|
||||
?, F1 This help
|
||||
|
||||
BIOS folder:
|
||||
/home/user/.config/retroarch/system
|
||||
Any key closes this help
|
||||
Vendored
+2
-2
@@ -1,8 +1,6 @@
|
||||
RetroBIOS: Keys
|
||||
|
||||
Up/Down, k/j Move
|
||||
PgUp/PgDn, L1/R1 Page
|
||||
Home/End, g/G First, last
|
||||
A/Enter, Start Install
|
||||
Y, o, Tab Options
|
||||
B/Esc, Backspace Back
|
||||
@@ -12,4 +10,6 @@
|
||||
BIOS folder:
|
||||
/home/user/.config/retroarch/system
|
||||
|
||||
|
||||
|
||||
Any key closes this help
|
||||
Vendored
+2
-2
@@ -1,8 +1,6 @@
|
||||
RetroBIOS: Keys
|
||||
|
||||
Up/Down, k/j Move
|
||||
PgUp/PgDn, L1/R1 Page
|
||||
Home/End, g/G First, last
|
||||
A/Enter, Start Install
|
||||
Y, o, Tab Options
|
||||
B/Esc, Backspace Back
|
||||
@@ -21,4 +19,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Any key closes this help
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
528.0 KB of 1.0 MB
|
||||
128.9 KB/s, 0:04 left
|
||||
2 of 4 files
|
||||
What is done stays done if you stop.
|
||||
B, Ctrl-C or Start+Select stops. What is done stays done.
|
||||
|
||||
FAILED scph5500.bin (HTTP 404)
|
||||
ok gba_bios.bin
|
||||
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
Ctrl-C / Start+Select stops
|
||||
B/Esc Stop ? Help
|
||||
+3
-3
@@ -4,9 +4,9 @@
|
||||
528.0 KB of 1.0 MB
|
||||
128.9 KB/s, 0:04 left
|
||||
2 of 4 files
|
||||
What is done stays done if you stop.
|
||||
B, Ctrl-C or Start+Select stops. What
|
||||
is done stays done.
|
||||
|
||||
FAILED scph5500.bin (HTTP 404)
|
||||
ok gba_bios.bin
|
||||
|
||||
Ctrl-C / Start+Select stops
|
||||
B/Esc Stop ? Help
|
||||
+3
-3
@@ -4,12 +4,12 @@
|
||||
528.0 KB of 1.0 MB
|
||||
128.9 KB/s, 0:04 left
|
||||
2 of 4 files
|
||||
What is done stays done if you stop.
|
||||
B, Ctrl-C or Start+Select stops. What
|
||||
is done stays done.
|
||||
|
||||
FAILED scph5500.bin (HTTP 404)
|
||||
ok gba_bios.bin
|
||||
|
||||
|
||||
|
||||
|
||||
Ctrl-C / Start+Select stops
|
||||
B/Esc Stop ? Help
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
528.0 KB of 1.0 MB
|
||||
128.9 KB/s, 0:04 left
|
||||
2 of 4 files
|
||||
What is done stays done if you stop.
|
||||
B, Ctrl-C or Start+Select stops. What is done stays done.
|
||||
|
||||
FAILED scph5500.bin (HTTP 404)
|
||||
ok gba_bios.bin
|
||||
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
Ctrl-C / Start+Select stops
|
||||
B/Esc Stop ? Help
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
Each row is an option of the command line, named on the right.
|
||||
|
||||
> Preferred regions: north-america, japan --region
|
||||
> Preferred regions: North America, Japan --region
|
||||
Leave out game data: no --no-game-data
|
||||
Installed cores only: no (1 found) --installed-cores
|
||||
Cores: all --core
|
||||
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Change B/Esc Back Left/Right Set ? Help
|
||||
A/Enter Open B/Esc Back Left/Right Set ? Help
|
||||
Vendored
+3
-3
@@ -1,12 +1,12 @@
|
||||
RetroBIOS: Options
|
||||
|
||||
> Preferred regions: north-america, ja
|
||||
> Preferred regions: North America, Ja
|
||||
Leave out game data: no
|
||||
Installed cores only: no (1 found)
|
||||
Cores: all
|
||||
Parallel downloads: 8
|
||||
BIOS folder: ~/.config/retroarch/sys
|
||||
BIOS folder: ~/.config...ch/system
|
||||
Preview the file list
|
||||
Show the command line
|
||||
|
||||
A/Enter Change B/Esc Back
|
||||
A Open B Back <> Set ? Help
|
||||
Vendored
+3
-3
@@ -1,15 +1,15 @@
|
||||
RetroBIOS: Options
|
||||
|
||||
> Preferred regions: north-america, ja
|
||||
> Preferred regions: North America, Ja
|
||||
Leave out game data: no
|
||||
Installed cores only: no (1 found)
|
||||
Cores: all
|
||||
Parallel downloads: 8
|
||||
BIOS folder: ~/.config/retroarch/sys
|
||||
BIOS folder: ~/.config...ch/system
|
||||
Preview the file list
|
||||
Show the command line
|
||||
|
||||
Sets --region
|
||||
|
||||
|
||||
A/Enter Change B/Esc Back
|
||||
A Open B Back <> Set ? Help
|
||||
Vendored
+2
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
Each row is an option of the command line, named on the right.
|
||||
|
||||
> Preferred regions: north-america, japan --region
|
||||
> Preferred regions: North America, Japan --region
|
||||
Leave out game data: no --no-game-data
|
||||
Installed cores only: no (1 found) --installed-cores
|
||||
Cores: all --core
|
||||
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Change B/Esc Back Left/Right Set ? Help
|
||||
A/Enter Open B/Esc Back Left/Right Set ? Help
|
||||
Vendored
+2
-2
@@ -3,7 +3,7 @@
|
||||
The folder for RetroArch:
|
||||
> ~/bios_
|
||||
|
||||
Quotes are removed, ~ and variables are expanded.
|
||||
Ctrl-U clears. Quotes are removed, ~ and variables are expanded.
|
||||
|
||||
|
||||
|
||||
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
Enter Use this folder Esc Back
|
||||
Enter Use this folder Esc Back Ctrl-U Clear
|
||||
Vendored
+2
-2
@@ -3,8 +3,8 @@
|
||||
The folder for RetroArch:
|
||||
> ~/bios_
|
||||
|
||||
Quotes are removed, ~ and variables
|
||||
are expanded.
|
||||
Ctrl-U clears. Quotes are removed, ~
|
||||
and variables are expanded.
|
||||
|
||||
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -3,8 +3,8 @@
|
||||
The folder for RetroArch:
|
||||
> ~/bios_
|
||||
|
||||
Quotes are removed, ~ and variables
|
||||
are expanded.
|
||||
Ctrl-U clears. Quotes are removed, ~
|
||||
and variables are expanded.
|
||||
|
||||
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -3,7 +3,7 @@
|
||||
The folder for RetroArch:
|
||||
> ~/bios_
|
||||
|
||||
Quotes are removed, ~ and variables are expanded.
|
||||
Ctrl-U clears. Quotes are removed, ~ and variables are expanded.
|
||||
|
||||
|
||||
|
||||
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
Enter Use this folder Esc Back
|
||||
Enter Use this folder Esc Back Ctrl-U Clear
|
||||
Vendored
+1
-1
@@ -9,4 +9,4 @@
|
||||
Choose systems
|
||||
Options
|
||||
Quit
|
||||
A/Enter Install B/Esc Back
|
||||
A Install B Back Y Options ? Help
|
||||
Vendored
+1
-1
@@ -12,4 +12,4 @@
|
||||
Choose systems
|
||||
Options
|
||||
Quit
|
||||
A/Enter Install B/Esc Back
|
||||
A Install B Back Y Options ? Help
|
||||
+1
-1
@@ -9,4 +9,4 @@
|
||||
> Close
|
||||
Options
|
||||
|
||||
A/Enter Close B/Esc Back Y/o Options
|
||||
A Close B Back Y Options ? Help
|
||||
+1
-1
@@ -12,4 +12,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Close B/Esc Back Y/o Options
|
||||
A Close B Back Y Options ? Help
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
Choose the setup that will use the BIOS files.
|
||||
|
||||
Filter (/ to type)
|
||||
> RetroArch
|
||||
> RetroArch muOS, JELOS, KOLOS, Uno...Anbernic stock firmware
|
||||
Batocera
|
||||
Recalbox
|
||||
RetroBat
|
||||
@@ -15,7 +15,7 @@
|
||||
BizHawk
|
||||
MiSTer FPGA
|
||||
RetroPie
|
||||
AmberELEC
|
||||
AmberELEC PAN4ELEC
|
||||
EmuELEC
|
||||
KNULLI
|
||||
MinUI
|
||||
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
RetroBIOS: Which setup?
|
||||
|
||||
Filter (/ to type)
|
||||
> RetroArch
|
||||
> RetroArch muOS, JE...firmware
|
||||
Batocera
|
||||
Recalbox
|
||||
RetroBat
|
||||
EmuDeck
|
||||
Lakka
|
||||
RetroDECK
|
||||
1-8 of 19
|
||||
A/Enter Choose B/Esc Back / Filter
|
||||
1-7 of 18
|
||||
A Choose B Back / Filter ? Help
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
RetroBIOS: Which setup?
|
||||
|
||||
Filter (/ to type)
|
||||
> RetroArch
|
||||
> RetroArch muOS, JE...firmware
|
||||
Batocera
|
||||
Recalbox
|
||||
RetroBat
|
||||
@@ -11,5 +11,5 @@
|
||||
ROCKNIX
|
||||
RomM
|
||||
BizHawk
|
||||
1-11 of 19
|
||||
A/Enter Choose B/Esc Back / Filter
|
||||
1-10 of 18
|
||||
A Choose B Back / Filter ? Help
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
Choose the setup that will use the BIOS files.
|
||||
|
||||
Filter (/ to type)
|
||||
> RetroArch
|
||||
> RetroArch muOS, JELOS, KOLOS...nic stock firmware
|
||||
Batocera
|
||||
Recalbox
|
||||
RetroBat
|
||||
@@ -15,7 +15,7 @@
|
||||
BizHawk
|
||||
MiSTer FPGA
|
||||
RetroPie
|
||||
AmberELEC
|
||||
AmberELEC PAN4ELEC
|
||||
EmuELEC
|
||||
KNULLI
|
||||
MinUI
|
||||
|
||||
Vendored
+1
-1
@@ -37,4 +37,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Stay
|
||||
A/Enter Quit B/Esc Stay
|
||||
Vendored
+1
-1
@@ -9,4 +9,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Stay
|
||||
A/Enter Quit B/Esc Stay
|
||||
Vendored
+1
-1
@@ -12,4 +12,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Stay
|
||||
A/Enter Quit B/Esc Stay
|
||||
Vendored
+1
-1
@@ -21,4 +21,4 @@
|
||||
|
||||
|
||||
|
||||
A/Enter Choose B/Esc Stay
|
||||
A/Enter Quit B/Esc Stay
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
Tick the regions to keep, best first. Where a system has one BIOS per region, the best one found
|
||||
is installed.
|
||||
|
||||
> [1] north-america
|
||||
[ ] japan
|
||||
> [1] North America
|
||||
[ ] Japan
|
||||
|
||||
|
||||
|
||||
|
||||
Vendored
+3
-3
@@ -5,8 +5,8 @@
|
||||
region, the best one found is
|
||||
installed.
|
||||
|
||||
> [1] north-america
|
||||
[ ] japan
|
||||
> [1] North America
|
||||
[ ] Japan
|
||||
|
||||
|
||||
A/Enter Tick B/Esc Done
|
||||
A Tick B Done <> Order ? Help
|
||||
Vendored
+3
-3
@@ -5,11 +5,11 @@
|
||||
region, the best one found is
|
||||
installed.
|
||||
|
||||
> [1] north-america
|
||||
[ ] japan
|
||||
> [1] North America
|
||||
[ ] Japan
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
A/Enter Tick B/Esc Done
|
||||
A Tick B Done <> Order ? Help
|
||||
Vendored
+2
-2
@@ -3,8 +3,8 @@
|
||||
Tick the regions to keep, best first. Where a system has one BIOS per region,
|
||||
the best one found is installed.
|
||||
|
||||
> [1] north-america
|
||||
[ ] japan
|
||||
> [1] North America
|
||||
[ ] Japan
|
||||
|
||||
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -8,5 +8,5 @@
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
To put them back: python3 install.py
|
||||
1-8 of 20
|
||||
1-4 of 9
|
||||
A/Enter Exit Up/Down Scroll
|
||||
Vendored
+1
-1
@@ -11,5 +11,5 @@
|
||||
--restore
|
||||
/home/user/.config/retroarch/
|
||||
retrobios-backup/2026-10-23_1200
|
||||
1-11 of 20
|
||||
1-5 of 9
|
||||
A/Enter Exit Up/Down Scroll
|
||||
Vendored
+2
-2
@@ -2,8 +2,8 @@
|
||||
|
||||
Found on this machine:
|
||||
|
||||
> RetroArch ~/.config/retroarch/system
|
||||
KNULLI (Batocera files) /userdata/bios
|
||||
> RetroArch
|
||||
KNULLI (Batocera files)
|
||||
Another setup or folder
|
||||
|
||||
BIOS folder: /home/user/.config/retroarch/system
|
||||
|
||||
Vendored
+2
-2
@@ -2,8 +2,8 @@
|
||||
|
||||
Found on this machine:
|
||||
|
||||
> RetroArch ~/.config/retroarch/system
|
||||
KNULLI (Batocera files) /userdata/bios
|
||||
> RetroArch
|
||||
KNULLI (Batocera files)
|
||||
Another setup or folder
|
||||
|
||||
BIOS folder: /home/user/.config/retroarch/system
|
||||
|
||||
Vendored
+1
-1
@@ -9,4 +9,4 @@
|
||||
|
||||
|
||||
2 of 3 systems: 4 files, 1.0 MB
|
||||
A/Enter Continue B/Esc Back
|
||||
A Continue B Back X Tick ? Help
|
||||
Vendored
+1
-1
@@ -12,4 +12,4 @@
|
||||
|
||||
|
||||
2 of 3 systems: 4 files, 1.0 MB
|
||||
A/Enter Continue B/Esc Back
|
||||
A Continue B Back X Tick ? Help
|
||||
@@ -5049,6 +5049,9 @@ class EventsDescribeTheRun(unittest.TestCase, _SyntheticTree):
|
||||
{"event": "detect", "os": "linux", "os_name": install._os_name(),
|
||||
"platforms": [{"platform": "retroarch", "name": "RetroArch",
|
||||
"bios_dir": str(self.bios)}]},
|
||||
# a.bin and b.bin are in place: the first read and the last.
|
||||
{"event": "checking", "files_done": 1, "files_total": 2},
|
||||
{"event": "checking", "files_done": 2, "files_total": 2},
|
||||
{"event": "file", "platform": "retroarch", "dest": "a.bin",
|
||||
"systems": ["sys-a"], "size": 100, "state": "present"},
|
||||
{"event": "file", "platform": "retroarch", "dest": "b.bin",
|
||||
|
||||
+405
-17
@@ -484,7 +484,8 @@ class Flow(unittest.TestCase):
|
||||
self.assertEqual(state.screen, "cores")
|
||||
self.assertEqual([row.value for row in install.tui_rows(state)][1:],
|
||||
["mesen", "pcsx_rearmed"])
|
||||
press(state, "down", " ")
|
||||
self.assertEqual(install.tui_rows(state)[state.focus["cores"]].value, "mesen")
|
||||
press(state, " ")
|
||||
self.assertEqual(state.cores, ["mesen"])
|
||||
press(state, "left")
|
||||
self.assertEqual(state.cores, [])
|
||||
@@ -644,13 +645,14 @@ class Flow(unittest.TestCase):
|
||||
state = fresh_state()
|
||||
with mock.patch.object(install.Path, "exists", return_value=True):
|
||||
press(state, "enter")
|
||||
install.tui_receive(state, ("manifest_failed", "retroarch",
|
||||
install.tui_receive(state, ("manifest_failed", "retroarch", "No connection",
|
||||
[" Could not fetch the file list for retroarch", ""], 1))
|
||||
self.assertIn("RetroBIOS: No connection", install.tui_view(state, 80, 24)[0])
|
||||
self.assertEqual(state.screen, "error")
|
||||
self.assertEqual([row.action for row in install.tui_rows(state)],
|
||||
["retry", "back", "quit"])
|
||||
self.assertEqual(press(state, "enter"), [("fetch", "retroarch")])
|
||||
install.tui_receive(state, ("manifest_failed", "retroarch", ["no"], 1))
|
||||
install.tui_receive(state, ("manifest_failed", "retroarch", "No connection", ["no"], 1))
|
||||
press(state, "down", "down", "enter")
|
||||
self.assertEqual(state.exit_code, 1)
|
||||
|
||||
@@ -697,7 +699,13 @@ class PlanWarnings(unittest.TestCase):
|
||||
state = checked_state({"free": 1024, "writable": False, "cores": []})
|
||||
text = " ".join(install.tui_view(state, 120, 40))
|
||||
self.assertIn("Not enough free space for this download", text)
|
||||
self.assertIn("This folder cannot be written", text)
|
||||
self.assertIn("You cannot write to this folder: choose another one, or run the "
|
||||
"installer with sudo.", text)
|
||||
rows = install.tui_rows(state)
|
||||
self.assertEqual([row.action for row in rows[:2]], ["folder", "install"])
|
||||
self.assertEqual(state.focus.get("plan", 0), 0)
|
||||
self.assertEqual(press(state, "enter"), [])
|
||||
self.assertEqual(state.screen, "folder")
|
||||
self.assertNotIn("--installed-cores", [row.right for row in install._option_rows(state)])
|
||||
|
||||
|
||||
@@ -716,7 +724,8 @@ class Widgets(unittest.TestCase):
|
||||
press(state, "end")
|
||||
lines = install.tui_view(state, 40, 15)
|
||||
self.assertIn("> [x] system-111", "\n".join(lines))
|
||||
self.assertTrue(any(re.fullmatch(r" \d+-115 of 115", line) for line in lines), lines)
|
||||
# The All, None and Filter rows are not counted among the systems.
|
||||
self.assertTrue(any(re.fullmatch(r" \d+-112 of 112", line) for line in lines), lines)
|
||||
press(state, "pgup")
|
||||
self.assertLess(state.focus["systems"], 114)
|
||||
press(state, "home")
|
||||
@@ -755,7 +764,10 @@ class Widgets(unittest.TestCase):
|
||||
press(state, "a")
|
||||
self.assertEqual(len(state.ticked), 5)
|
||||
state.focus["systems"] = 1
|
||||
# X on None does nothing: only A, an explicit choice, unticks all.
|
||||
press(state, " ")
|
||||
self.assertEqual(len(state.ticked), 5)
|
||||
press(state, "enter")
|
||||
self.assertEqual(state.ticked, set())
|
||||
|
||||
def test_running_total_counts_each_file_once(self):
|
||||
@@ -909,8 +921,8 @@ 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()
|
||||
self.assertTrue(hint.startswith(("A/Enter", "Enter", "Ctrl-C", "Any key")),
|
||||
hint)
|
||||
self.assertTrue(hint.startswith(("A/Enter", "A ", "Enter", "Ctrl-C", "Any key",
|
||||
"B/Esc Stop")), hint)
|
||||
|
||||
def test_focus_is_marked_without_colour(self):
|
||||
lines = install.tui_view(fresh_state(), 80, 24)
|
||||
@@ -1092,6 +1104,19 @@ class SmallFixes(unittest.TestCase):
|
||||
self.assertTrue(state.installed_only)
|
||||
self.assertNotIn("--installed-cores", [f for f, _v in install.tui_flags(state)])
|
||||
|
||||
def test_the_end_of_a_wrapped_pager_is_reachable(self):
|
||||
state = checked_state()
|
||||
state.stack.append("result")
|
||||
state.code, state.summary = 0, {"installed": 3}
|
||||
state.dest = Path("/media/" + "long-folder-name/" * 8)
|
||||
state.cols, state.rows = 40, 12
|
||||
press(state, "end")
|
||||
lines = install.tui_view(state, 40, 12)
|
||||
self.assertIn("python3 install.py", "\n".join(lines))
|
||||
top = state.focus["result"]
|
||||
press(state, "up")
|
||||
self.assertEqual(state.focus["result"], top - 1)
|
||||
|
||||
def test_end_then_up_in_a_pager(self):
|
||||
state = checked_state()
|
||||
state.stack += ["options", "preview"]
|
||||
@@ -1127,7 +1152,7 @@ class SmallFixes(unittest.TestCase):
|
||||
"event": "downloaded", "dest": "a.bin", "ok": True, "reason": "", "size": 1,
|
||||
"files_done": 1, "files_total": 4, "bytes_done": 1, "bytes_total": 100}))
|
||||
press(state, "ctrl-c")
|
||||
self.assertIn("Press Ctrl-C again to quit now.",
|
||||
self.assertIn("Press B or Ctrl-C again to stop now.",
|
||||
" ".join(install.tui_view(state, 120, 40)))
|
||||
self.assertEqual(press(state, "ctrl-c"), [("kill",)])
|
||||
install.tui_receive(state, ("ended", state.run_id, -9, []))
|
||||
@@ -1206,6 +1231,346 @@ class CleanupSurvivesABrokenTerminal(unittest.TestCase):
|
||||
self.assertEqual(signal.getsignal(number), handler)
|
||||
|
||||
|
||||
class AuditRoundTwo(unittest.TestCase):
|
||||
"""tui_audit_1.md, each finding held where it was found."""
|
||||
|
||||
def systems(self) -> install.TuiState:
|
||||
state = checked_state()
|
||||
press(state, "down", "enter")
|
||||
self.assertEqual(state.screen, "systems")
|
||||
return state
|
||||
|
||||
def focused(self, state: install.TuiState) -> install.TuiRow:
|
||||
rows = install.tui_rows(state)
|
||||
return rows[state.focus[state.screen]]
|
||||
|
||||
def test_p1_3_the_filter_never_changes_the_ticks(self):
|
||||
state = self.systems()
|
||||
press(state, "n")
|
||||
state.focus["systems"] = next(i for i, row in enumerate(install.tui_rows(state))
|
||||
if row.value == "nintendo-gba")
|
||||
press(state, "right")
|
||||
self.assertEqual(state.ticked, {"nintendo-gba"})
|
||||
press(state, "/", "p", "l", "a", "y")
|
||||
self.assertEqual(self.focused(state).action, "filter")
|
||||
press(state, "enter")
|
||||
# Enter lands on the first match, never on All or None.
|
||||
self.assertEqual(self.focused(state).value, "sony-playstation")
|
||||
press(state, " ")
|
||||
self.assertEqual(state.ticked, {"nintendo-gba", "sony-playstation"})
|
||||
press(state, " ")
|
||||
press(state, "esc")
|
||||
# The filter is cleared, the row in focus stays in focus, and A there
|
||||
# continues instead of ticking everything.
|
||||
self.assertEqual(state.filters["systems"], "")
|
||||
self.assertEqual(self.focused(state).value, "sony-playstation")
|
||||
self.assertEqual(state.ticked, {"nintendo-gba"})
|
||||
self.assertIn("A/Enter Continue", install.tui_view(state, 80, 24)[-1])
|
||||
state.focus["systems"] = 2
|
||||
press(state, " ")
|
||||
self.assertEqual(state.editing, "")
|
||||
self.assertEqual(state.ticked, {"nintendo-gba"})
|
||||
|
||||
def test_p2_2_the_bar_names_what_a_does_on_the_focused_row(self):
|
||||
state = checked_state()
|
||||
self.assertTrue(install.tui_view(state, 80, 24)[-1].strip().startswith("A/Enter Install"))
|
||||
press(state, "down")
|
||||
self.assertTrue(install.tui_view(state, 80, 24)[-1].strip().startswith("A/Enter Open"))
|
||||
state = self.systems()
|
||||
state.focus["systems"] = 0
|
||||
self.assertIn("A/Enter Tick all", install.tui_view(state, 80, 24)[-1])
|
||||
|
||||
def test_p2_2_b_esc_and_q_stop_an_install(self):
|
||||
for key in ("esc", "backspace", "q"):
|
||||
with self.subTest(key=key):
|
||||
state = checked_state()
|
||||
press(state, "enter")
|
||||
self.assertEqual(press(state, key), [("stop",)])
|
||||
self.assertTrue(state.stopping)
|
||||
self.assertEqual(press(state, key), [("kill",)])
|
||||
|
||||
def test_p2_3_options_read_the_plan_again(self):
|
||||
state = self.systems()
|
||||
press(state, "n")
|
||||
state.focus["systems"] = 3
|
||||
press(state, "right")
|
||||
ticked = set(state.ticked)
|
||||
press(state, "esc", "o")
|
||||
self.assertEqual(state.screen, "options")
|
||||
state.focus["options"] = 1
|
||||
press(state, "enter")
|
||||
self.assertTrue(state.no_game_data)
|
||||
effects = press(state, "esc")
|
||||
self.assertEqual(effects, [("run", "check")])
|
||||
self.assertIn("--no-game-data", [f for f, _v in state.checked_flags])
|
||||
self.assertNotIn("--system", [f for f, _v in state.checked_flags])
|
||||
for event in [*FILES, *SYSTEMS, {**CHECK, "missing": 2, "bytes_needed": 600}]:
|
||||
install.tui_receive(state, ("event", state.run_id, event))
|
||||
with mock.patch.object(install, "_tui_folder_facts", return_value={}):
|
||||
install.tui_receive(state, ("ended", state.run_id, 1, []))
|
||||
self.assertEqual(state.screen, "plan")
|
||||
self.assertEqual(state.ticked, ticked)
|
||||
for cols, rows in ((80, 24), (40, 15)):
|
||||
text = "\n".join(install.tui_view(state, cols, rows))
|
||||
self.assertIn("3 files to download, 600 B", text)
|
||||
self.assertIn("For your 1 of 3 systems", text)
|
||||
|
||||
def test_p2_4_no_network_is_said_at_once(self):
|
||||
import socket
|
||||
|
||||
with socket.socket() as probe:
|
||||
probe.bind(("127.0.0.1", 0))
|
||||
port = probe.getsockname()[1]
|
||||
inbox = __import__("queue").Queue()
|
||||
started = time.monotonic()
|
||||
with mock.patch.object(install, "MANIFEST_URL",
|
||||
f"http://127.0.0.1:{port}/install/{{platform}}.json"):
|
||||
install._tui_fetch("retroarch", inbox, io.StringIO())
|
||||
self.assertLess(time.monotonic() - started, 5)
|
||||
kind, plat, title, lines, code = inbox.get_nowait()
|
||||
self.assertEqual((kind, title, code), ("manifest_failed", "No connection", 1))
|
||||
self.assertIn("could not be downloaded: the server refused the connection", lines[0])
|
||||
self.assertNotIn("--", " ".join(lines))
|
||||
state = fresh_state()
|
||||
with mock.patch.object(install.Path, "exists", return_value=True):
|
||||
press(state, "enter")
|
||||
install.tui_receive(state, (kind, plat, title, lines, code))
|
||||
self.assertEqual([row.action for row in install.tui_rows(state)],
|
||||
["retry", "back", "quit"])
|
||||
|
||||
def test_p2_4_the_clock_says_so(self):
|
||||
import ssl
|
||||
|
||||
inbox = __import__("queue").Queue()
|
||||
error = urllib_error(ssl.SSLCertVerificationError("certificate is not yet valid"))
|
||||
words = install.network_words(error, today=install.datetime.date(1980, 1, 1))
|
||||
with mock.patch.object(install, "_fetch_json", side_effect=error), \
|
||||
mock.patch.object(install, "network_words", return_value=words):
|
||||
install._tui_fetch("retroarch", inbox, io.StringIO())
|
||||
_kind, _plat, title, lines, _code = inbox.get_nowait()
|
||||
self.assertEqual(title, "The clock is wrong")
|
||||
self.assertIn("The clock reads 1980-01-01", lines[0])
|
||||
|
||||
def test_p2_5_one_line_per_cause(self):
|
||||
state = checked_state()
|
||||
state.stack.append("result")
|
||||
state.code = 2
|
||||
state.summary = {"installed": 0, "up_to_date": 0, "failed": [
|
||||
{"dest": f"f{n}.bin", "reason": "folder not writable"} for n in range(50)]}
|
||||
_title, lines = install.tui_outcome(state)
|
||||
self.assertEqual([line for line in lines if "failed" in line],
|
||||
["Nothing was installed: 50 files failed.",
|
||||
" 50 files failed (folder not writable), the first f0.bin"])
|
||||
|
||||
def test_p2_6_a_folder_inside_a_card_offers_its_root(self):
|
||||
card = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp"))
|
||||
self.addCleanup(shutil.rmtree, card, True)
|
||||
(card / ".system").mkdir()
|
||||
(card / ".system" / "version.txt").write_text("MinUI-20250101\n")
|
||||
(card / "Bios").mkdir()
|
||||
state = fresh_state()
|
||||
state.stack = ["folder"]
|
||||
self.assertEqual(install._choose(state, "minui", card / "Bios"), [])
|
||||
self.assertEqual(state.screen, "cardroot")
|
||||
text = " ".join(line.strip() for line in install.tui_view(state, 120, 40))
|
||||
self.assertIn(f"under the card's root: {card}", text)
|
||||
self.assertEqual(press(state, "enter"), [("fetch", "minui")])
|
||||
self.assertEqual(state.dest, card)
|
||||
|
||||
def test_p2_6_the_banner_is_not_an_error_line(self):
|
||||
state = fresh_state()
|
||||
state.platform, state.dest = "retroarch", SYSTEM_DIR
|
||||
state.manifest, state.manifest_for = MANIFEST, "retroarch"
|
||||
install._start_check(state)
|
||||
install.tui_receive(state, ("ended", state.run_id, 1,
|
||||
["RetroBIOS 532f0b8d96e0", "Error: refused."]))
|
||||
self.assertEqual(state.error, ["Error: refused."])
|
||||
self.assertNotIn("retry", [row.action for row in install.tui_rows(state)])
|
||||
|
||||
def test_p2_7_a_typed_path_replaces_the_one_offered(self):
|
||||
state = fresh_state()
|
||||
state.platform, state.stack = "retroarch", ["folder"]
|
||||
state.folder_default = SYSTEM_DIR
|
||||
state.focus["folder"] = 2
|
||||
press(state, "enter")
|
||||
self.assertEqual((state.screen, state.path_selected), ("path", True))
|
||||
install.tui_update(state, Key("paste", '"/media/sd card/bios"'))
|
||||
self.assertEqual(state.path_text, '"/media/sd card/bios"')
|
||||
install.tui_update(state, Key("ctrl-u"))
|
||||
self.assertEqual(state.path_text, "")
|
||||
install.tui_update(state, Key("paste", '/media/x"'))
|
||||
self.assertEqual(install.typed_path(state.path_text), Path("/media/x"))
|
||||
|
||||
def test_p2_7_a_path_from_the_root_is_not_created_on_a(self):
|
||||
state = fresh_state()
|
||||
state.stack = ["folder"]
|
||||
install._choose(state, "retroarch", Path("/no/such/deep/folder"))
|
||||
self.assertEqual(state.screen, "create")
|
||||
self.assertEqual(self.focused(state).action, "other")
|
||||
self.assertIn("Every folder of this path would be made",
|
||||
" ".join(install.tui_view(state, 120, 40)))
|
||||
near = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp"))
|
||||
self.addCleanup(shutil.rmtree, near, True)
|
||||
install._choose(state, "retroarch", near / "bios")
|
||||
self.assertEqual(self.focused(state).action, "create")
|
||||
|
||||
def test_p2_9_two_setups_of_one_name(self):
|
||||
flatpak = HOME / ".var/app/org.libretro.RetroArch/config/retroarch/system"
|
||||
setups = install.tell_apart([("retroarch", flatpak, "RetroArch"),
|
||||
("retroarch", SYSTEM_DIR, "RetroArch"),
|
||||
("emudeck", HOME / "Emulation/bios", "EmuDeck")])
|
||||
self.assertEqual([label for _p, _f, label in setups],
|
||||
["RetroArch (Flatpak)", "RetroArch (retroarch/system)", "EmuDeck"])
|
||||
state = fresh_state()
|
||||
state.setups = setups
|
||||
self.assertIn("RetroArch (Flatpak)", "\n".join(install.tui_view(state, 40, 15)))
|
||||
# A Flatpak whose config names a system folder outside its sandbox.
|
||||
elsewhere = HOME / "bios"
|
||||
config = HOME / ".var/app/org.libretro.RetroArch/config/retroarch/retroarch.cfg"
|
||||
with mock.patch.dict(install._RETROARCH_CONFIGS, {elsewhere: (config, config.parent)}):
|
||||
setups = install.tell_apart([("retroarch", elsewhere, "RetroArch"),
|
||||
("retroarch", SYSTEM_DIR, "RetroArch")])
|
||||
self.assertEqual(setups[0][2], "RetroArch (Flatpak)")
|
||||
|
||||
def test_p2_10_the_check_counts_while_it_reads(self):
|
||||
state = fresh_state()
|
||||
state.platform, state.dest = "retroarch", SYSTEM_DIR
|
||||
state.manifest, state.manifest_for = MANIFEST, "retroarch"
|
||||
install._start_check(state)
|
||||
install.tui_receive(state, ("event", state.run_id,
|
||||
{"event": "checking", "files_done": 120, "files_total": 400}))
|
||||
self.assertIn("Reading the files already in the folder: 120 of 400",
|
||||
"\n".join(install.tui_view(state, 80, 24)))
|
||||
|
||||
def test_p2_11_a_narrow_bar_keeps_the_keys_to_finish(self):
|
||||
state = self.systems()
|
||||
self.assertEqual(install.tui_view(state, 40, 15)[-1].strip(),
|
||||
"A Continue B Back X Tick ? Help")
|
||||
|
||||
def test_p2_12_a_device_name_finds_its_setup(self):
|
||||
state = fresh_state()
|
||||
state.stack = ["platforms"]
|
||||
press(state, "/", "m", "u", "o", "s")
|
||||
self.assertEqual([row.value for row in install.tui_rows(state)][1:], ["retroarch"])
|
||||
|
||||
def test_p2_13_a_long_preview_wraps_only_what_is_in_view(self):
|
||||
state = checked_state()
|
||||
state.stack += ["options", "preview"]
|
||||
state.dry = dict(CHECK)
|
||||
state.dry_files = [{**FILES[0], "dest": f"file{n:05d}.bin"} for n in range(8000)]
|
||||
state.cols, state.rows = 40, 15
|
||||
real = install._text_lines
|
||||
calls = []
|
||||
|
||||
def counted(items, width):
|
||||
calls.append(len(items))
|
||||
return real(items, width)
|
||||
|
||||
with mock.patch.object(install, "_text_lines", counted):
|
||||
press(state, "end")
|
||||
lines = install.tui_view(state, 40, 15)
|
||||
self.assertLess(sum(calls), 40)
|
||||
self.assertIn("file07999.bin", "\n".join(lines))
|
||||
|
||||
def test_p2_1_titles_and_regions(self):
|
||||
state = checked_state()
|
||||
state.manifest = {**MANIFEST, "system_titles": {"nintendo-gba": "Game Boy Advance"}}
|
||||
state.stack.append("systems")
|
||||
text = "\n".join(install.tui_view(state, 40, 15))
|
||||
self.assertIn("[x] Game Boy Advance", text)
|
||||
self.assertEqual(install.region_title("asia-ntsc"), "Asia (NTSC)")
|
||||
self.assertEqual(install.region_title("north-america"), "North America")
|
||||
|
||||
def test_p3_jobs_stop_at_the_ends_and_q_keeps_the_error_code(self):
|
||||
state = checked_state()
|
||||
state.jobs = 1
|
||||
install._option(state, "jobs", -1)
|
||||
self.assertEqual(state.jobs, 1)
|
||||
state.jobs = 32
|
||||
install._option(state, "jobs", 1)
|
||||
self.assertEqual(state.jobs, 32)
|
||||
state = fresh_state()
|
||||
state.stack, state.error_code = ["setup", "error"], 2
|
||||
press(state, "q")
|
||||
self.assertEqual(state.exit_code, 2)
|
||||
|
||||
def test_p3_ascii_keeps_the_columns(self):
|
||||
self.assertEqual(install.ascii_text("Édition ファミ"), "Edition ??????")
|
||||
|
||||
def test_p3_a_refused_tui_says_why_without_the_usage(self):
|
||||
proc = install_run("--tui")
|
||||
self.assertEqual(proc.returncode, 2)
|
||||
self.assertEqual(proc.stderr.strip().splitlines(),
|
||||
["install.py: error: --tui cannot open the full-screen interface "
|
||||
"here: the input is not a terminal"])
|
||||
|
||||
|
||||
def urllib_error(reason: BaseException):
|
||||
import urllib.error
|
||||
|
||||
return urllib.error.URLError(reason)
|
||||
|
||||
|
||||
class WorkFolders(unittest.TestCase):
|
||||
"""Every run's folder of logs goes, but the one a failure names."""
|
||||
|
||||
class Terminal:
|
||||
state_to = None
|
||||
|
||||
def __init__(self, *_streams) -> None:
|
||||
self.frame = []
|
||||
|
||||
def enter(self) -> None:
|
||||
pass
|
||||
|
||||
def leave(self) -> None:
|
||||
pass
|
||||
|
||||
def size(self) -> tuple:
|
||||
return 80, 24
|
||||
|
||||
def draw(self, lines, cols) -> None:
|
||||
pass
|
||||
|
||||
def keys(self, timeout):
|
||||
WorkFolders.Terminal.state_to(self)
|
||||
return [Key("enter")]
|
||||
|
||||
def run_to(self, code: int) -> tuple:
|
||||
work = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp"))
|
||||
self.addCleanup(shutil.rmtree, work, True)
|
||||
state = checked_state()
|
||||
state.stack.append("result")
|
||||
state.code = code
|
||||
state.log = str(work / "install.log")
|
||||
state.summary = {"installed": 1, "failed": [] if code == 0 else [
|
||||
{"dest": "a.bin", "reason": "HTTP 404"}]}
|
||||
WorkFolders.Terminal.state_to = lambda _t: None
|
||||
out = io.StringIO()
|
||||
with mock.patch.object(install, "_TuiTerminal", self.Terminal), \
|
||||
mock.patch.object(install, "tui_start", return_value=(state, [])), \
|
||||
mock.patch.object(install, "_open_local_sources"), \
|
||||
mock.patch.object(install, "detect_os", return_value="linux"), \
|
||||
mock.patch.object(install.tempfile, "mkdtemp", return_value=str(work)), \
|
||||
mock.patch.object(sys, "stdout", out), mock.patch.object(sys, "stderr", out):
|
||||
self.assertEqual(install.run_tui(_args()), code)
|
||||
return work, out.getvalue()
|
||||
|
||||
def test_a_success_leaves_nothing(self):
|
||||
work, out = self.run_to(0)
|
||||
self.assertFalse(work.exists())
|
||||
self.assertNotIn("Details:", out)
|
||||
|
||||
def test_a_failure_keeps_the_log_it_names(self):
|
||||
work, out = self.run_to(1)
|
||||
self.assertTrue(work.exists())
|
||||
self.assertIn(f"Details: {work / 'install.log'}", out)
|
||||
|
||||
def test_a_stop_leaves_nothing(self):
|
||||
work, out = self.run_to(130)
|
||||
self.assertFalse(work.exists())
|
||||
|
||||
|
||||
class Crash(unittest.TestCase):
|
||||
"""An unexpected error ends on one sentence and a log, never a traceback."""
|
||||
|
||||
@@ -1441,13 +1806,11 @@ class EndToEnd(unittest.TestCase):
|
||||
term.send("\r")
|
||||
term.wait("Preferred regions")
|
||||
term.send(DOWN, "\r", "\x1b")
|
||||
screen = term.wait("Preferred regions: north-america")
|
||||
screen = term.wait("Preferred regions: North America")
|
||||
term.send(DOWN, RIGHT, "\x1b")
|
||||
screen = term.wait("> Install")
|
||||
self.assertIn("Your choices: --region north-america --no-game-data", screen)
|
||||
term.send("\r")
|
||||
# Back on the plan, the check runs again under the new options.
|
||||
screen = term.wait("4 files to download")
|
||||
self.assertIn("RetroBIOS: Confirm", screen)
|
||||
self.assertIn("> Install", screen)
|
||||
term.send("\r")
|
||||
screen = term.wait("installed.")
|
||||
self.assertIn("Left out as game data: 1 file.", screen)
|
||||
@@ -1477,11 +1840,36 @@ class EndToEnd(unittest.TestCase):
|
||||
term.wait("1 of 6 files")
|
||||
term.send("\x03")
|
||||
screen = term.wait("Stopped:")
|
||||
self.assertRegex(screen, r"Stopped: \d of 6 installed, run again to finish\.")
|
||||
term.send("\r")
|
||||
self.assertEqual(term.close(), 130)
|
||||
self.assertLess(len(repo.installed()), 6)
|
||||
self.assertIn("RetroBIOS: Stopped", term.after())
|
||||
# The count said is the count on disk: "6 of 6" after a stop at 1
|
||||
# passed a regex and was false.
|
||||
on_disk = len(repo.installed())
|
||||
self.assertLess(on_disk, 6)
|
||||
self.assertIn(f"Stopped: {on_disk} of 6 installed, run again to finish.", screen)
|
||||
self.assertIn(f"Stopped: {on_disk} of 6 installed", term.after())
|
||||
|
||||
def test_sigterm_during_the_download_is_a_stop(self):
|
||||
"""Start+Select on a handheld is gptokeyb's pkill: SIGTERM, SIGKILL 3 s on."""
|
||||
import signal
|
||||
|
||||
repo = self.repo(GameDataRepository, slow=True)
|
||||
term = self.start("--platform", "retroarch", "--dest", str(repo.dest), "--jobs", "1")
|
||||
term.wait("> Install")
|
||||
term.send("\r")
|
||||
term.wait("1 of 6 files")
|
||||
started = time.monotonic()
|
||||
os.kill(term.pid, signal.SIGTERM)
|
||||
code = term.close()
|
||||
self.assertLess(time.monotonic() - started, 3)
|
||||
self.assertEqual(code, 130)
|
||||
on_disk = len(repo.installed())
|
||||
self.assertGreaterEqual(on_disk, 1)
|
||||
after = term.after()
|
||||
self.assertIn(f"Stopped: {on_disk} of 6 installed, run again to finish.", after)
|
||||
self.assertNotIn("Nothing was installed", after)
|
||||
time.sleep(1)
|
||||
self.assertEqual(len(repo.installed()), on_disk)
|
||||
|
||||
def test_ctrl_c_on_the_first_screen(self):
|
||||
self.repo()
|
||||
@@ -1524,7 +1912,7 @@ class EndToEnd(unittest.TestCase):
|
||||
term.resize(100, 30)
|
||||
term.send(DOWN)
|
||||
screen = term.wait("> Another setup or folder")
|
||||
self.assertIn("A/Enter Continue", screen.splitlines()[29])
|
||||
self.assertIn("B/Esc Quit", screen.splitlines()[29])
|
||||
term.resize(30, 10)
|
||||
term.wait("Make the window larger")
|
||||
term.resize(40, 12)
|
||||
|
||||
+16
-8
@@ -92,8 +92,10 @@ play, with the total to download under the list. **Options** sets the
|
||||
preferred regions, game data, the installed cores only, the cores, the parallel
|
||||
downloads and the folder. Each row names the option it sets, and **Show the
|
||||
command line** gives the same choice as one command for a script. **Preview the
|
||||
file list** shows what would be downloaded and writes nothing. When a choice
|
||||
changes the plan, the exact count appears before the install starts.
|
||||
file list** shows what would be downloaded and writes nothing. Back on the plan
|
||||
after a change of options, the folder is checked again, so its numbers are the
|
||||
exact ones for the new choice. Ticked systems get their exact count before the
|
||||
install starts.
|
||||
|
||||
| Action | Keyboard | Controller |
|
||||
|--------|----------|------------|
|
||||
@@ -106,14 +108,19 @@ changes the plan, the exact count appears before the install starts.
|
||||
| Options | `o`, Tab | Y |
|
||||
| Filter a long list | `/` then type | the Filter row |
|
||||
| Keys of the screen | `?`, F1 | |
|
||||
| Stop an install | Esc, `q`, Ctrl+C | B, Start+Select |
|
||||
| Quit | `q`, Ctrl+C | B on the first screen |
|
||||
|
||||
The bottom line of each screen names its keys, with both spellings (`A/Enter`,
|
||||
`B/Esc`), since A and B swap places between controller layouts. On the regions
|
||||
screen, Left and Right move the region under the cursor up and down the order of
|
||||
preference. During the download, Ctrl+C stops after the files in progress, a
|
||||
second Ctrl+C stops at once, and the result says how many were installed. The result stays printed in the
|
||||
terminal once the screen closes, with the command that repeats the run.
|
||||
The bottom line of each screen names what A does on the row under the cursor,
|
||||
with both spellings (`A/Enter`, `B/Esc`), since A and B swap places between
|
||||
controller layouts. A narrow screen shortens them to `A`, `B` and `X`. On the
|
||||
regions screen, Left and Right move the region under the cursor up and down the
|
||||
order of preference. During the download, a stop waits for the files in
|
||||
progress, and a second one stops at once. Start+Select on a handheld ends the
|
||||
installer with a signal (SIGTERM), which stops it the same way. Either way the
|
||||
result says how many files were installed, and it stays printed in the terminal
|
||||
once the screen closes, with the command that repeats the run. A run that failed
|
||||
keeps its log and names it, and every other run leaves nothing behind.
|
||||
|
||||
It opens only for an install, at a terminal of at least 40 columns and 12 rows
|
||||
that is not `TERM=dumb`. A listing, `--check`, `--dry-run`, `--events`,
|
||||
@@ -1099,6 +1106,7 @@ kind, and each kind has exactly the keys below, in this order. The schema is
|
||||
| `start` | `schema`, `installer`, `mode` | First line. `schema` is 1, `installer` the identity `--version` prints, `mode` one of `install`, `check`, `dry-run`, `list` |
|
||||
| `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, or `no_ca` when the machine holds no list of trusted certificates (`SSL_CERT_FILE` names one). `message` says it in words |
|
||||
| `checking` | `files_done`, `files_total` | While the files already in the folder are read and hashed, at most every half second and once at the end. `files_total` counts the files found in place |
|
||||
| `file` | `platform`, `dest`, `systems`, `size`, `state` | Each file of the list after the check. `state` is `present` (hash verified), `wrong_hash` or `missing` |
|
||||
| `system` | `platform`, `system`, `name`, `files`, `present`, `missing`, `wrong_hash`, `bytes_needed` | Each system, sorted by id, and with `--system` only the systems named. Files with no system count under `other`. `name` is the platform's own name for it |
|
||||
| `check` | `platform`, `name`, `bios_dir`, `files`, `present`, `missing`, `wrong_hash`, `bytes_needed`, `data_missing`, `not_installable` | The platform's totals. `data_missing` counts data-tree files to fetch, `not_installable` the files the collection cannot supply |
|
||||
|
||||
Reference in new issue
Block a user