diff --git a/platforms/retropie.yml b/platforms/retropie.yml index 6f670b3a..6e69cfdb 100644 --- a/platforms/retropie.yml +++ b/platforms/retropie.yml @@ -186,3 +186,2502 @@ cores: - yabause - yquake2 - zesarux +launchers: +- emulator: advmame-0.94 + package: advmame-0.94 + repo: file $__archive_url/advancemame-0.94.0.tar.gz + systems: + - arcade + - mame-advmame + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/advmame-0.94.sh:12, 16, scriptmodules/emulators/advmame.sh:147-148" +- emulator: advmame-1.4 + package: advmame-1.4 + repo: file $__archive_url/advancemame-1.4.tar.gz + systems: + - arcade + - mame-advmame + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/advmame-1.4.sh:12, 16, scriptmodules/emulators/advmame.sh:147-148" +- emulator: advmame + package: advmame + repo: "git https://github.com/amadvance/advancemame" + systems: + - arcade + - mame-advmame + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/advmame.sh:12, 16, 147-148" +- emulator: ags + package: ags + repo: "git https://github.com/adventuregamestudio/ags.git release-3.6.0" + systems: + - ags + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/ags.sh:12, 16, 55" +- emulator: amiberry + package: amiberry + repo: "git https://github.com/BlitterStudio/amiberry :_get_branch_amiberry" + systems: + - amiga + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/amiberry.sh:12, 16, 118" +- emulator: amiberry + package: amiberry + build: standalone + kind: moves + names: + - kick13.rom + - kick20.rom + - kick31.rom + case_insensitive: false + search_dir: $biosdir + passes_to: $biosdir/amiga + fails_when_missing: false + depends_on_option: "[[ -f \"$biosdir/$rom\" && ! -h \"$biosdir/$rom\" ]]" + source_ref: "scriptmodules/emulators/amiberry.sh:26" +- emulator: amiberry + package: amiberry + build: standalone + kind: passes_path + names: [] + search_dir: $biosdir/amiga + passes_to: rom_path in $md_inst/conf/amiberry.conf + fails_when_missing: false + source_ref: "scriptmodules/emulators/amiberry.sh:135" +- emulator: amiberry + package: amiberry + build: standalone + kind: links + names: [] + search_dir: $biosdir/amiga + passes_to: $md_inst/kickstarts is a symlink to it + fails_when_missing: false + source_ref: "scriptmodules/emulators/amiberry.sh:147" +- emulator: atari800 + package: atari800 + repo: "git https://github.com/atari800/atari800.git ATARI800_5_2_0" + systems: + - atari800 + - atari5200 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/atari800.sh:12, 16, 102-103" +- emulator: basilisk + package: basilisk + repo: "git https://github.com/cebix/macemu.git master" + systems: + - macintosh + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/basilisk.sh:12, 16, 57" +- emulator: basilisk + package: basilisk + build: standalone + kind: fixed_name + names: + - mac.rom + case_insensitive: false + search_dir: $romdir/macintosh + passes_to: command line --rom + fails_when_missing: false + source_ref: "scriptmodules/emulators/basilisk.sh:56" +- emulator: capricerpi + package: capricerpi + repo: "git https://github.com/KaosOverride/CapriceRPI.git master" + systems: + - amstradcpc + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/capricerpi.sh:12, 16, 46" +- emulator: coolcv + package: coolcv + repo: file $__archive_url/coolcv.tar.gz + systems: + - coleco + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/coolcv.sh:12, 16, 35" +- emulator: daphne + package: daphne + repo: "git https://github.com/RetroPie/daphne-emu.git retropie" + systems: + - daphne + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/daphne.sh:12, 16, 54" +- emulator: dgen + package: dgen + repo: file $__archive_url/dgen-sdl-1.33.tar.gz + systems: + - megadrive + - segacd + - sega32x + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/dgen.sh:12, 16, 53" +- emulator: dolphin + package: dolphin + repo: "git https://github.com/dolphin-emu/dolphin.git master :_get_commit_dolphin" + systems: + - gc + - wii + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/dolphin.sh:12, 16, 87-88" +- emulator: dosbox-sdl2 + package: dosbox-sdl2 + repo: "git https://github.com/duganchen/dosbox.git master" + systems: + - pc + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/dosbox-sdl2.sh:12, 16, scriptmodules/emulators/dosbox.sh:94" +- emulator: dosbox-staging + package: dosbox-staging + repo: "git https://github.com/dosbox-staging/dosbox-staging.git :_get_branch_dosbox-staging" + systems: + - pc + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/dosbox-staging.sh:12, 16, scriptmodules/emulators/dosbox.sh:94" +- emulator: dosbox + package: dosbox + repo: "svn https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk - 4252" + systems: + - pc + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/dosbox.sh:12, 16, 94" +- emulator: drastic + package: drastic + systems: + - nds + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/drastic.sh:12, 40" +- emulator: fbzx + package: fbzx + repo: "git https://github.com/rastersoft/fbzx :_get_branch_fbzx" + systems: + - zxspectrum + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/fbzx.sh:12, 16, 57" +- emulator: flycast + package: flycast + repo: "git https://github.com/flyinghead/flycast.git master" + systems: + - arcade + - dreamcast + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/flycast.sh:12, 16, 66" +- emulator: flycast + package: flycast + build: standalone + kind: links + names: [] + search_dir: $biosdir/dc + passes_to: $home/.local/share/flycast is a symlink to it + fails_when_missing: false + source_ref: "scriptmodules/emulators/flycast.sh:77" +- emulator: flycast + package: flycast + build: standalone + kind: passes_path + names: [] + search_dir: $biosdir/dc + passes_to: Dreamcast.BiosPath in $md_conf_root/dreamcast/emu.cfg + fails_when_missing: false + source_ref: "scriptmodules/emulators/flycast.sh:144" +- emulator: frotz + package: frotz + systems: + - zmachine + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/frotz.sh:12, 53" +- emulator: fs-uae + package: fs-uae + systems: + - amiga + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/fs-uae.sh:12, 80" +- emulator: fuse + package: fuse + repo: file $__archive_url/fuse-1.5.7.tar.gz + systems: + - zxspectrum + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/fuse.sh:12, 16, 56" +- emulator: gngeopi + package: gngeopi + repo: "git https://github.com/ymartel06/GnGeo-Pi.git master" + systems: + - arcade + - neogeo + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/gngeopi.sh:12, 16, 62-63" +- emulator: gngeopi + package: gngeopi + build: standalone + kind: passes_path + names: [] + search_dir: $md_inst/neogeobios + passes_to: command line -B + fails_when_missing: false + source_ref: "scriptmodules/emulators/gngeopi.sh:60-61" +- emulator: gpsp + package: gpsp + repo: "git https://github.com/gizmo98/gpsp.git master" + systems: + - gba + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/gpsp.sh:12, 16, 59" +- emulator: gpsp + package: gpsp + build: standalone + kind: links + names: + - gba_bios.bin + case_insensitive: false + search_dir: $biosdir + passes_to: $md_inst/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/gpsp.sh:53" +- emulator: hatari + package: hatari + repo: "git https://github.com/hatari/hatari v2.4.1" + systems: + - atarist + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/hatari.sh:12, 16, 92" +- emulator: hatari + package: hatari + build: standalone + kind: links + names: + - tos.img + case_insensitive: false + search_dir: $biosdir + passes_to: $md_inst/share/hatari/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/hatari.sh:99" +- emulator: hypseus + package: hypseus + repo: "git https://github.com/DirtBagXon/hypseus-singe.git RetroPie" + systems: + - daphne + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/hypseus.sh:12, 16, 56" +- emulator: jzintv + package: jzintv + repo: file $__archive_url/jzintv-20200712-src.zip + systems: + - intellivision + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/jzintv.sh:12, 16, 125" +- emulator: jzintv + package: jzintv + build: standalone + kind: passes_path + names: [] + search_dir: $biosdir + passes_to: --rom-path in $md_inst/jzintv_launcher.sh + fails_when_missing: false + source_ref: "scriptmodules/emulators/jzintv.sh:113" +- emulator: linapple + package: linapple + repo: "git https://github.com/dabonetn/linapple-pie.git master" + systems: + - apple2 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/linapple.sh:12, 16, 52" +- emulator: mame + package: mame + repo: "git https://github.com/mamedev/mame.git :_get_branch_mame" + systems: + - arcade + - mame + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/mame.sh:12, 16, 187-188" +- emulator: mame + package: mame + build: standalone + kind: passes_path + names: [] + search_dir: $romdir/mame;$romdir/arcade;$biosdir/mame + passes_to: rompath in $md_conf_root/mame/mame.ini + fails_when_missing: false + source_ref: "scriptmodules/emulators/mame.sh:133" +- emulator: mame4all + package: mame4all + repo: "git https://github.com/RetroPie/mame4all-pi.git master" + systems: + - arcade + - mame-mame4all + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/mame4all.sh:12, 16, 91-92" +- emulator: minivmac + package: minivmac + repo: "git https://github.com/minivmac/minivmac.git master" + systems: + - macintosh + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/minivmac.sh:12, 16, 90" +- emulator: minivmac + package: minivmac + build: standalone + kind: links + names: + - vMac.ROM + case_insensitive: false + search_dir: $biosdir + passes_to: $md_inst/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/minivmac.sh:87" +- emulator: mupen64plus + package: mupen64plus + repo: ":_pkg_info_mupen64plus" + systems: + - n64 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/mupen64plus.sh:12, 16, 314" +- emulator: np2pi + package: np2pi + repo: "git https://github.com/eagle0wl/np2pi.git master" + systems: + - pc98 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/np2pi.sh:12, 15, 60" +- emulator: np2pi + package: np2pi + build: standalone + kind: links + names: + - 2608_bd.wav + - 2608_hh.wav + - 2608_rim.wav + - 2608_sd.wav + - 2608_tom.wav + - 2608_top.wav + - bios.rom + - FONT.ROM + - sound.rom + case_insensitive: false + search_dir: $biosdir/pc98 + passes_to: $md_conf_root/pc98/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/np2pi.sh:53" +- emulator: openmsx + package: openmsx + repo: "git https://github.com/openMSX/openMSX.git RELEASE_19_1 :_get_commit_openmsx" + systems: + - msx + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/openmsx.sh:12, 16, 66" +- emulator: openmsx + package: openmsx + build: standalone + kind: links + names: [] + search_dir: $home/RetroPie/BIOS/openmsx + passes_to: $configdir/msx/openmsx/share/systemroms is a symlink to it + fails_when_missing: false + source_ref: "scriptmodules/emulators/openmsx.sh:77" +- emulator: oricutron + package: oricutron + repo: "git https://github.com/HerbFargus/oricutron.git extras" + systems: + - oric + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/oricutron.sh:12, 16, 67" +- emulator: osmose + package: osmose + repo: "git https://github.com/RetroPie/osmose-rpi.git master" + systems: + - gamegear + - mastersystem + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/osmose.sh:12, 16, 49-50" +- emulator: pcsx-rearmed + package: pcsx-rearmed + repo: "git https://github.com/notaz/pcsx_rearmed.git master" + systems: + - psx + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/pcsx-rearmed.sh:12, 16, 70" +- emulator: pcsx-rearmed + package: pcsx-rearmed + build: standalone + kind: links + names: + - SCPH1001.BIN + case_insensitive: false + search_dir: $biosdir + passes_to: $md_inst/bios/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/pcsx-rearmed.sh:62" +- emulator: pcsx2 + package: pcsx2 + systems: + - ps2 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/pcsx2.sh:12, 86" +- emulator: pifba + package: pifba + repo: "git https://github.com/RetroPie/pifba.git master" + systems: + - arcade + - neogeo + - fba + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/pifba.sh:12, 16, 69-71" +- emulator: pisnes + package: pisnes + repo: "git https://github.com/RetroPie/pisnes.git master" + systems: + - snes + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/pisnes.sh:12, 16, 53" +- emulator: ppsspp-1.5.4 + package: ppsspp-1.5.4 + repo: "git https://github.com/hrydgard/ppsspp.git v1.5.4" + systems: + - psp + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/ppsspp-1.5.4.sh:12, 16, scriptmodules/emulators/ppsspp.sh:211" +- emulator: ppsspp + package: ppsspp + repo: "git https://github.com/hrydgard/ppsspp.git :_get_release_ppsspp" + systems: + - psp + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/ppsspp.sh:12, 16, 211" +- emulator: px68k + package: px68k + repo: "git https://github.com/TurtleBazooka/px68k.git master" + systems: + - x68000 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/px68k.sh:12, 15, 62" +- emulator: px68k + package: px68k + build: standalone + kind: moves + names: + - cgrom.dat + - iplrom30.dat + - iplromco.dat + - iplrom.dat + - iplromxv.dat + case_insensitive: false + search_dir: $biosdir + passes_to: $biosdir/keropi + fails_when_missing: false + depends_on_option: "[[ -f \"$biosdir/$bios\" ]]" + source_ref: "scriptmodules/emulators/px68k.sh:56" +- emulator: px68k + package: px68k + build: standalone + kind: links + names: + - cgrom.dat + - iplrom30.dat + - iplromco.dat + - iplrom.dat + - iplromxv.dat + case_insensitive: false + search_dir: $biosdir/keropi + passes_to: $md_conf_root/x68000/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/px68k.sh:58" +- emulator: quasi88 + package: quasi88 + repo: "git https://github.com/winterheart/quasi88.git master" + systems: + - pc88 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/quasi88.sh:12, 15, 53" +- emulator: quasi88 + package: quasi88 + build: standalone + kind: passes_path + names: [] + search_dir: $biosdir/pc88 + passes_to: build option -DROMDIR + fails_when_missing: false + source_ref: "scriptmodules/emulators/quasi88.sh:32" +- emulator: quasi88 + package: quasi88 + build: standalone + kind: passes_path + names: [] + search_dir: $biosdir/pc88 + passes_to: -romdir in $md_conf_root/pc88/quasi88.ini + fails_when_missing: false + depends_on_option: "[[ ! -f \"$md_conf_root/pc88/quasi88.ini\" ]]" + source_ref: "scriptmodules/emulators/quasi88.sh:67" +- emulator: redream + package: redream + systems: + - dreamcast + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/redream.sh:12, 35" +- emulator: redream + package: redream + build: standalone + kind: links + names: + - dc_boot.bin + - dc_flash.bin + case_insensitive: false + search_dir: $biosdir/dc + passes_to: $md_inst/boot.bin, $md_inst/flash.bin + fails_when_missing: false + source_ref: "scriptmodules/emulators/redream.sh:58-59" +- emulator: reicast + package: reicast + repo: "git https://github.com/reicast/reicast-emulator.git master" + systems: + - dreamcast + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/reicast.sh:12, 16, 145" +- emulator: reicast + package: reicast + build: standalone + kind: links + names: + - dc_boot.bin + - dc_flash.bin + case_insensitive: false + search_dir: $biosdir/dc + passes_to: $md_conf_root/dreamcast/data/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/reicast.sh:114" +- emulator: retroarch + package: retroarch + repo: "git https://github.com/retropie/RetroArch.git retropie-v1.19.0" + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/emulators/retroarch.sh:12, 15" +- emulator: retroarch + package: retroarch + build: libretro + kind: passes_path + names: [] + search_dir: $biosdir + passes_to: system_directory in $configdir/all/retroarch.cfg + fails_when_missing: false + source_ref: "scriptmodules/emulators/retroarch.sh:177" +- emulator: rpix86 + package: rpix86 + systems: + - pc + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/rpix86.sh:12, 46" +- emulator: scummvm-sdl1 + package: scummvm-sdl1 + repo: "git https://github.com/scummvm/scummvm.git v2026.3.0" + systems: + - scummvm + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/scummvm-sdl1.sh:12, 16, scriptmodules/emulators/scummvm.sh:98" +- emulator: scummvm + package: scummvm + repo: "git https://github.com/scummvm/scummvm.git v2026.3.0" + systems: + - scummvm + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/scummvm.sh:12, 16, 98" +- emulator: sdltrs + package: sdltrs + repo: "git https://gitlab.com/jengun/sdltrs.git sdl2" + systems: + - trs-80 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/sdltrs.sh:12, 17, 53" +- emulator: sdltrs-model1 + package: sdltrs + build: standalone + kind: fixed_name + names: + - level2.rom + case_insensitive: false + search_dir: $biosdir + passes_to: command line -romfile + fails_when_missing: false + source_ref: "scriptmodules/emulators/sdltrs.sh:49" +- emulator: sdltrs-model3 + package: sdltrs + build: standalone + kind: fixed_name + names: + - level3.rom + case_insensitive: false + search_dir: $biosdir + passes_to: command line -romfile3 + fails_when_missing: false + source_ref: "scriptmodules/emulators/sdltrs.sh:50" +- emulator: sdltrs-model4 + package: sdltrs + build: standalone + kind: fixed_name + names: + - level4.rom + case_insensitive: false + search_dir: $biosdir + passes_to: command line -romfile3 + fails_when_missing: false + source_ref: "scriptmodules/emulators/sdltrs.sh:51" +- emulator: sdltrs-model4p + package: sdltrs + build: standalone + kind: fixed_name + names: + - level4p.rom + case_insensitive: false + search_dir: $biosdir + passes_to: command line -romfile4p + fails_when_missing: false + source_ref: "scriptmodules/emulators/sdltrs.sh:52" +- emulator: simcoupe + package: simcoupe + repo: "git https://github.com/simonowen/simcoupe.git :_get_branch_simcoupe" + systems: + - samcoupe + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/simcoupe.sh:12, 16, 65" +- emulator: snes9x + package: snes9x + repo: "git https://github.com/RetroPie/snes9x-rpi.git retropie" + systems: + - snes + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/snes9x.sh:12, 16, 51" +- emulator: stella + package: stella + repo: "git https://github.com/stella-emu/stella.git :_get_version_stella" + systems: + - atari2600 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/stella.sh:12, 16, 54" +- emulator: stratagus + package: stratagus + repo: "git https://github.com/Wargus/stratagus.git v2.4.3" + systems: + - stratagus + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/stratagus.sh:12, 16, 47" +- emulator: supermodel3 + package: supermodel3 + repo: "git https://github.com/DirtBagXon/model3emu-code-sinden.git :_get_branch_supermodel3\ + \ :_get_commit_supermodel3" + systems: + - arcade + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/supermodel3.sh:12, 16, 69" +- emulator: ti99sim-sdl1 + package: ti99sim-sdl1 + repo: file $__archive_url/ti99sim-0.15.0.src.tar.gz + systems: + - ti99 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/ti99sim-sdl1.sh:12, 16, 42" +- emulator: ti99sim-sdl1 + package: ti99sim-sdl1 + build: standalone + kind: links + names: + - TI-994A.ctg + case_insensitive: false + search_dir: $biosdir + passes_to: $md_inst/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/ti99sim-sdl1.sh:49" +- emulator: ti99sim + package: ti99sim + repo: file $__archive_url/ti99sim-0.16.0.src.tar.gz + systems: + - ti99 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/ti99sim.sh:12, 16, 54" +- emulator: ti99sim + package: ti99sim + build: standalone + kind: links + names: + - TI-994A.ctg + case_insensitive: false + search_dir: $biosdir + passes_to: $md_inst/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/ti99sim.sh:59" +- emulator: uae4all + package: uae4all + repo: "git https://github.com/RetroPie/uae4all2.git retropie" + systems: + - amiga + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/uae4all.sh:12, 16, 103" +- emulator: uae4all + package: uae4all + build: standalone + kind: links + names: [] + search_dir: $biosdir/amiga + passes_to: $md_inst/kickstarts is a symlink to it + fails_when_missing: false + source_ref: "scriptmodules/emulators/uae4all.sh:79" +- emulator: uae4all + package: uae4all + build: standalone + kind: copies + names: [] + search_dir: aros20140110.zip + passes_to: $biosdir/amiga + fails_when_missing: false + depends_on_option: "[[ ! -f \"$biosdir/aros-amiga-m68k-ext.bin\" ]]" + source_ref: "scriptmodules/emulators/uae4all.sh:85" +- emulator: uae4arm + package: uae4arm + repo: "git https://github.com/Chips-fr/uae4arm-rpi.git master" + systems: + - amiga + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/uae4arm.sh:12, 16, 49" +- emulator: uae4arm + package: uae4arm + build: standalone + kind: links + names: [] + search_dir: $biosdir/amiga + passes_to: $md_inst/kickstarts is a symlink to it + fails_when_missing: false + source_ref: "scriptmodules/emulators/uae4arm.sh:64" +- emulator: vice + package: vice + repo: "svn svn://svn.code.sf.net/p/vice-emu/code/tags/v3.7.1/vice - HEAD" + systems: + - c64 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/vice.sh:12, 16, 84" +- emulator: xm7 + package: xm7 + repo: "git https://github.com/nakatamaho/XM7-for-SDL.git master" + systems: + - fm7 + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/xm7.sh:12, 16, 67" +- emulator: xm7 + package: xm7 + build: standalone + kind: links + names: + - DICROM.ROM + - EXTSUB.ROM + - FBASIC30.ROM + - INITIATE.ROM + - KANJI1.ROM + - KANJI2.ROM + - SUBSYS_A.ROM + - SUBSYS_B.ROM + - SUBSYSCG.ROM + - SUBSYS_C.ROM + - fddseek.wav + - relayoff.wav + - relay_on.wav + case_insensitive: false + search_dir: $biosdir/fm7 + passes_to: $md_conf_root/fm7/ + fails_when_missing: false + source_ref: "scriptmodules/emulators/xm7.sh:77" +- emulator: xroar + package: xroar + repo: "git http://www.6809.org.uk/git/xroar.git 1.11" + systems: + - dragon32 + - coco + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/xroar.sh:12, 16, 64-65" +- emulator: xroar + package: xroar + build: standalone + kind: links + names: [] + case_insensitive: false + search_dir: $biosdir + passes_to: $md_inst/share/xroar/roms is a symlink to it + fails_when_missing: false + source_ref: "scriptmodules/emulators/xroar.sh:52" +- emulator: yabasanshiro + package: yabasanshiro + repo: "git https://github.com/retropie/yabause.git pi4-1-9-0" + systems: + - saturn + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/yabasanshiro.sh:12, 16, 58" +- emulator: zesarux + package: zesarux + repo: "git https://github.com/chernandezba/zesarux.git ZEsarUX-12.1" + systems: + - zxspectrum + - samcoupe + - amstradcpc + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/emulators/zesarux.sh:12, 16, 107-109" +- emulator: lr-81 + package: lr-81 + repo: "git https://github.com/libretro/81-libretro.git master" + systems: + - zx81 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-81.sh:12, 16, 41" +- emulator: lr-atari800 + package: lr-atari800 + repo: "git https://github.com/libretro/libretro-atari800.git master" + systems: + - atari800 + - atari5200 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-atari800.sh:12, 16, 48-49" +- emulator: lr-beetle-lynx + package: lr-beetle-lynx + repo: "git https://github.com/libretro/beetle-lynx-libretro.git master" + systems: + - atarilynx + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-lynx.sh:12, 16, 40" +- emulator: lr-beetle-ngp + package: lr-beetle-ngp + repo: "git https://github.com/libretro/beetle-ngp-libretro.git master" + systems: + - ngp + - ngpc + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-ngp.sh:12, 16, 46" +- emulator: lr-beetle-pce-fast + package: lr-beetle-pce-fast + repo: "git https://github.com/libretro/beetle-pce-fast-libretro.git master" + systems: + - pcengine + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-pce-fast.sh:12, 16, 47" +- emulator: lr-beetle-pce + package: lr-beetle-pce + repo: "git https://github.com/libretro/beetle-pce-libretro.git master" + systems: + - pcengine + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-pce.sh:12, 16, 43" +- emulator: lr-beetle-pcfx + package: lr-beetle-pcfx + repo: "git https://github.com/libretro/beetle-pcfx-libretro master" + systems: + - pcfx + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-pcfx.sh:12, 16, 40" +- emulator: lr-beetle-psx + package: lr-beetle-psx + repo: "git https://github.com/libretro/beetle-psx-libretro.git master" + systems: + - psx + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-psx.sh:12, 16, 48" +- emulator: lr-beetle-saturn + package: lr-beetle-saturn + repo: "git https://github.com/libretro/beetle-saturn-libretro.git master" + systems: + - saturn + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-saturn.sh:12, 16, 41" +- emulator: lr-beetle-supergrafx + package: lr-beetle-supergrafx + repo: "git https://github.com/libretro/beetle-supergrafx-libretro.git master" + systems: + - pcengine + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-supergrafx.sh:12, 16, 41" +- emulator: lr-beetle-vb + package: lr-beetle-vb + repo: "git https://github.com/libretro/beetle-vb-libretro.git master" + systems: + - virtualboy + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-vb.sh:12, 16, 43" +- emulator: lr-beetle-wswan + package: lr-beetle-wswan + repo: "git https://github.com/libretro/beetle-wswan-libretro.git master" + systems: + - wonderswan + - wonderswancolor + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-beetle-wswan.sh:12, 16, 48-49" +- emulator: lr-bennugd + package: lr-bennugd + repo: "git https://github.com/diekleinekuh/BennuGD_libretro.git master" + systems: + - bennugd + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-bennugd.sh:12, 16, 49" +- emulator: lr-bluemsx + package: lr-bluemsx + repo: "git https://github.com/libretro/blueMSX-libretro.git master" + systems: + - msx + - coleco + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-bluemsx.sh:12, 16, 40, 43" +- emulator: lr-bluemsx + package: lr-bluemsx + build: libretro + kind: copies + names: + - Databases + - Machines + search_dir: $md_inst + passes_to: $biosdir + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-bluemsx.sh:59" +- emulator: lr-bsnes + package: lr-bsnes + repo: "git https://github.com/libretro/bsnes.git master" + systems: + - snes + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-bsnes.sh:12, 16, 46" +- emulator: lr-caprice32 + package: lr-caprice32 + repo: "git https://github.com/libretro/libretro-cap32.git master" + systems: + - amstradcpc + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-caprice32.sh:12, 16, 45" +- emulator: lr-desmume + package: lr-desmume + repo: "git https://github.com/libretro/desmume.git master" + systems: + - nds + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-desmume.sh:12, 16, 52" +- emulator: lr-desmume2015 + package: lr-desmume2015 + repo: "git https://github.com/libretro/desmume2015.git master" + systems: + - nds + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-desmume2015.sh:12, 16, 45" +- emulator: lr-dinothawr + package: lr-dinothawr + repo: "git https://github.com/libretro/Dinothawr.git master" + systems: + - ports + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-dinothawr.sh:12, 16, 45" +- emulator: lr-dirksimple + package: lr-dirksimple + repo: "git https://github.com/icculus/DirkSimple.git main" + systems: + - daphne + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-dirksimple.sh:12, 16, 53" +- emulator: lr-dirksimple + package: lr-dirksimple + build: libretro + kind: copies + names: + - data + search_dir: $md_inst + passes_to: $biosdir/DirkSimple + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-dirksimple.sh:49" +- emulator: lr-dolphin + package: lr-dolphin + repo: "git https://github.com/libretro/dolphin master" + systems: + - gc + - wii + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-dolphin.sh:12, 16, 53-54" +- emulator: lr-dosbox-pure + package: lr-dosbox-pure + repo: "git https://github.com/libretro/dosbox-pure.git main" + systems: + - pc + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-dosbox-pure.sh:12, 16, 49" +- emulator: lr-dosbox + package: lr-dosbox + repo: "git https://github.com/libretro/dosbox-libretro.git master" + systems: + - pc + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-dosbox.sh:12, 16, 52" +- emulator: lr-ep128emu + package: lr-ep128emu + repo: "git https://github.com/libretro/ep128emu-core.git core" + systems: + - enterprise + - tvc + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-ep128emu.sh:12, 16, 38" +- emulator: lr-fbalpha2012 + package: lr-fbalpha2012 + repo: "git https://github.com/libretro/fbalpha2012.git master" + systems: + - arcade + - fba + - neogeo + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-fbalpha2012.sh:12, 16, 54" +- emulator: lr-fbneo + package: lr-fbneo + repo: "git https://github.com/libretro/FBNeo.git master" + systems: + - arcade + - neogeo + - fba + - pcengine + - gamegear + - mastersystem + - megadrive + - sg-1000 + - coleco + - msx + - zxspectrum + - fds + - nes + - ngp + - ngpc + - channelf + - snes + - gba + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-fbneo.sh:12, 16, 103" +- emulator: lr-fbneo + package: lr-fbneo + build: libretro + kind: copies + names: + - hiscore.dat + search_dir: $md_inst/metadata + passes_to: $biosdir/fbneo + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-fbneo.sh:124" +- emulator: lr-fceumm + package: lr-fceumm + repo: "git https://github.com/libretro/libretro-fceumm.git master" + systems: + - nes + - fds + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-fceumm.sh:12, 16, 51-52" +- emulator: lr-flycast-dev + package: lr-flycast-dev + repo: "git https://github.com/flyinghead/flycast.git master" + systems: + - arcade + - dreamcast + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-flycast-dev.sh:12, 16, 63" +- emulator: lr-flycast + package: lr-flycast + repo: "git https://github.com/libretro/flycast.git master" + systems: + - dreamcast + - arcade + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-flycast.sh:12, 16, 87" +- emulator: lr-fmsx + package: lr-fmsx + repo: "git https://github.com/libretro/fmsx-libretro.git master" + systems: + - msx + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-fmsx.sh:12, 16, 45" +- emulator: lr-fmsx + package: lr-fmsx + build: libretro + kind: copies + names: + - CARTS.SHA + search_dir: $md_inst + passes_to: $biosdir + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-fmsx.sh:50" +- emulator: lr-freechaf + package: lr-freechaf + repo: "git https://github.com/libretro/FreeChaF.git master" + systems: + - channelf + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-freechaf.sh:12, 16, 42" +- emulator: lr-freeintv + package: lr-freeintv + repo: "git https://github.com/libretro/FreeIntv.git master" + systems: + - intellivision + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-freeintv.sh:12, 16, 42" +- emulator: lr-fuse + package: lr-fuse + repo: "git https://github.com/libretro/fuse-libretro.git master" + systems: + - zxspectrum + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-fuse.sh:12, 16, 45" +- emulator: lr-gambatte + package: lr-gambatte + repo: "git https://github.com/libretro/gambatte-libretro.git master" + systems: + - gb + - gbc + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-gambatte.sh:12, 16, 51-52" +- emulator: lr-gambatte + package: lr-gambatte + build: libretro + kind: copies + names: + - default.pal + search_dir: $md_data + passes_to: $biosdir/palettes + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-gambatte.sh:41" +- emulator: lr-geargrafx + package: lr-geargrafx + repo: "git https://github.com/drhelius/Geargrafx.git main" + systems: + - pcengine + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-geargrafx.sh:12, 16, 42" +- emulator: lr-gearsystem + package: lr-gearsystem + repo: "git https://github.com/drhelius/Gearsystem.git master" + systems: + - gamegear + - mastersystem + - sg-1000 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-gearsystem.sh:12, 16, 44" +- emulator: lr-genesis-plus-gx + package: lr-genesis-plus-gx + repo: "git https://github.com/libretro/Genesis-Plus-GX.git master" + systems: + - gamegear + - mastersystem + - megadrive + - sg-1000 + - segacd + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-genesis-plus-gx.sh:12, 16, 49" +- emulator: lr-gpsp + package: lr-gpsp + repo: "git https://github.com/libretro/gpsp.git master" + systems: + - gba + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-gpsp.sh:12, 16, 50" +- emulator: lr-gw + package: lr-gw + repo: "git https://github.com/libretro/gw-libretro.git master" + systems: + - gameandwatch + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-gw.sh:12, 16, 42" +- emulator: lr-handy + package: lr-handy + repo: "git https://github.com/libretro/libretro-handy.git master" + systems: + - atarilynx + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-handy.sh:12, 16, 41" +- emulator: lr-hatari + package: lr-hatari + repo: "git https://github.com/libretro/hatari.git hitari2014-mercurial" + systems: + - atarist + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-hatari.sh:12, 16, 56" +- emulator: lr-kronos + package: lr-kronos + repo: "git https://github.com/libretro/yabause.git kronos" + systems: + - saturn + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-kronos.sh:12, 16, 48" +- emulator: lr-mame + package: lr-mame + repo: "git https://github.com/libretro/mame.git :_get_version_lr-mame" + systems: + - arcade + - mame-libretro + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mame.sh:12, 16, 74" +- emulator: lr-mame + package: lr-mame + build: libretro + kind: passes_path + names: [] + search_dir: $biosdir/mame/plugins + passes_to: pluginspath in $biosdir/mame/ini/mame.ini + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-mame.sh:87" +- emulator: lr-mame + package: lr-mame + build: libretro + kind: copies + names: + - mame.ini + passes_to: $biosdir/mame/ini + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-mame.sh:88" +- emulator: lr-mame + package: lr-mame + build: libretro + kind: copies + names: + - plugin.ini + passes_to: $biosdir/mame/ini + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-mame.sh:94" +- emulator: lr-mame + package: lr-mame + build: libretro + kind: copies + names: + - plugins + search_dir: $md_inst + passes_to: $biosdir/mame + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-mame.sh:97" +- emulator: lr-mame2000 + package: lr-mame2000 + repo: "git https://github.com/libretro/mame2000-libretro.git master" + systems: + - arcade + - mame-mame4all + - mame-libretro + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mame2000.sh:12, 16, 52" +- emulator: lr-mame2003-plus + package: lr-mame2003-plus + repo: "git https://github.com/libretro/mame2003-plus-libretro.git master" + systems: + - arcade + - mame-libretro + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mame2003-plus.sh:12, 16, scriptmodules/libretrocores/lr-mame2003.sh:54-55" +- emulator: lr-mame2003-plus + package: lr-mame2003-plus + build: libretro + kind: copies + names: + - hiscore.dat + - cheat.dat + search_dir: $md_inst/metadata + passes_to: $biosdir/mame2003-plus + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-mame2003.sh:77" +- emulator: lr-mame2003-plus + package: lr-mame2003-plus + build: libretro + kind: copies + names: + - '*' + search_dir: $md_inst/metadata/artwork + passes_to: $biosdir/mame2003-plus/artwork + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-mame2003.sh:83" +- emulator: lr-mame2003 + package: lr-mame2003 + repo: "git https://github.com/libretro/mame2003-libretro.git master" + systems: + - arcade + - mame-libretro + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mame2003.sh:12, 16, 54-55" +- emulator: lr-mame2003 + package: lr-mame2003 + build: libretro + kind: copies + names: + - hiscore.dat + - cheat.dat + search_dir: $md_inst/metadata + passes_to: $biosdir/mame2003 + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-mame2003.sh:77" +- emulator: lr-mame2010 + package: lr-mame2010 + repo: "git https://github.com/libretro/mame2010-libretro.git master" + systems: + - arcade + - mame-libretro + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mame2010.sh:12, 16, 58" +- emulator: lr-mame2015 + package: lr-mame2015 + repo: "git https://github.com/libretro/mame2015-libretro.git master" + systems: + - arcade + - mame-libretro + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mame2015.sh:12, 16, 50" +- emulator: lr-mame2016 + package: lr-mame2016 + repo: "git https://github.com/libretro/mame2016-libretro.git master" + systems: + - arcade + - mame-libretro + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mame2016.sh:12, 16, 49" +- emulator: lr-mesen + package: lr-mesen + repo: "git https://github.com/libretro/Mesen.git master" + systems: + - nes + - fds + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mesen.sh:12, 16, 44" +- emulator: lr-mess + package: lr-mess + repo: "git https://github.com/libretro/mame.git :_get_version_lr-mame" + systems: + - nes + - gb + - coleco + - arcadia + - crvision + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mess.sh:12, 16, 59" +- emulator: lr-mess + package: lr-mess + build: libretro + kind: copies + names: + - hash + search_dir: $md_inst + passes_to: $biosdir/mame + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-mess.sh:69" +- emulator: lr-mess2016 + package: lr-mess2016 + repo: "git https://github.com/libretro/mame2016-libretro.git master" + systems: + - nes + - gb + - coleco + - arcadia + - crvision + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mess2016.sh:12, 16, scriptmodules/libretrocores/lr-mess.sh:59" +- emulator: lr-mess2016 + package: lr-mess2016 + build: libretro + kind: copies + names: + - hash + search_dir: $md_inst + passes_to: $biosdir/mame + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-mess.sh:69" +- emulator: lr-mgba + package: lr-mgba + repo: "git https://github.com/libretro/mgba.git master" + systems: + - gb + - gbc + - gba + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mgba.sh:12, 16, 54" +- emulator: lr-mrboom + package: lr-mrboom + repo: "git https://github.com/libretro/mrboom-libretro.git master" + systems: + - ports + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mrboom.sh:12, 16, 46" +- emulator: lr-mupen64plus-next + package: lr-mupen64plus-next + repo: "git https://github.com/libretro/mupen64plus-libretro-nx.git develop" + systems: + - n64 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mupen64plus-next.sh:12, 16, 103" +- emulator: lr-mupen64plus + package: lr-mupen64plus + repo: "git https://github.com/RetroPie/mupen64plus-libretro.git master" + systems: + - n64 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-mupen64plus.sh:12, 16, 99" +- emulator: lr-neocd + package: lr-neocd + repo: "git https://github.com/libretro/neocd_libretro.git master" + systems: + - neogeo + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-neocd.sh:12, 16, 42" +- emulator: lr-nestopia + package: lr-nestopia + repo: "git https://github.com/libretro/nestopia.git master" + systems: + - nes + - fds + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-nestopia.sh:12, 16, 47-48" +- emulator: lr-np2kai + package: lr-np2kai + repo: "git https://github.com/AZO234/NP2kai.git master" + systems: + - pc98 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-np2kai.sh:12, 16, 41" +- emulator: lr-nxengine + package: lr-nxengine + repo: "git https://github.com/libretro/nxengine-libretro.git master" + systems: + - ports + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-nxengine.sh:12, 16, 39" +- emulator: lr-o2em + package: lr-o2em + repo: "git https://github.com/libretro/libretro-o2em master" + systems: + - videopac + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-o2em.sh:12, 16, 41" +- emulator: lr-opera + package: lr-opera + repo: "git https://github.com/libretro/opera-libretro.git master" + systems: + - 3do + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-opera.sh:12, 16, 44" +- emulator: lr-parallel-n64 + package: lr-parallel-n64 + repo: "git https://github.com/RetroPie/parallel-n64.git retropie" + systems: + - n64 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-parallel-n64.sh:12, 16, 177" +- emulator: lr-parallel-n64 + package: lr-parallel-n64 + build: libretro + kind: copies + names: + - gles2n64rom.conf + passes_to: $home/RetroPie/BIOS + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-parallel-n64.sh:72" +- emulator: lr-pcsx-rearmed + package: lr-pcsx-rearmed + repo: "git https://github.com/libretro/pcsx_rearmed.git master" + systems: + - psx + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-pcsx-rearmed.sh:12, 16, 64" +- emulator: lr-picodrive + package: lr-picodrive + repo: "git https://github.com/libretro/picodrive.git master" + systems: + - megadrive + - mastersystem + - segacd + - sega32x + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-picodrive.sh:12, 16, 61" +- emulator: lr-pokemini + package: lr-pokemini + repo: "git https://github.com/libretro/pokemini.git master" + systems: + - pokemini + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-pokemini.sh:12, 16, 40" +- emulator: lr-ppsspp + package: lr-ppsspp + repo: "git https://github.com/hrydgard/ppsspp.git :_get_release_ppsspp" + systems: + - psp + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-ppsspp.sh:12, 16, 66" +- emulator: lr-ppsspp + package: lr-ppsspp + build: libretro + kind: copies + names: + - '*' + search_dir: $md_inst/assets + passes_to: $biosdir/PPSSPP + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-ppsspp.sh:56" +- emulator: lr-prboom + package: lr-prboom + repo: "git https://github.com/libretro/libretro-prboom.git master" + systems: + - ports + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-prboom.sh:12, 15, 86, 88" +- emulator: lr-prosystem + package: lr-prosystem + repo: "git https://github.com/libretro/prosystem-libretro.git master" + systems: + - atari7800 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-prosystem.sh:12, 16, 42" +- emulator: lr-puae + package: lr-puae + repo: "git https://github.com/libretro/libretro-uae.git master" + systems: + - amiga + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-puae.sh:12, 16, 39" +- emulator: lr-puae2021 + package: lr-puae2021 + repo: "git https://github.com/libretro/libretro-uae.git 2.6.1" + systems: + - amiga + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-puae2021.sh:12, 16, 39" +- emulator: lr-px68k + package: lr-px68k + repo: "git https://github.com/libretro/px68k-libretro.git master" + systems: + - x68000 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-px68k.sh:12, 15, 44" +- emulator: lr-quasi88 + package: lr-quasi88 + repo: "git https://github.com/libretro/quasi88-libretro.git master" + systems: + - pc88 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-quasi88.sh:12, 16, 40" +- emulator: lr-quicknes + package: lr-quicknes + repo: "git https://github.com/libretro/QuickNES_Core.git master" + systems: + - nes + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-quicknes.sh:12, 16, 43" +- emulator: lr-retro8 + package: lr-retro8 + repo: "git https://github.com/libretro/retro8.git master" + systems: + - pico8 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-retro8.sh:12, 16, 41" +- emulator: lr-scummvm + package: lr-scummvm + repo: "git https://github.com/libretro/scummvm.git master" + systems: + - scummvm + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-scummvm.sh:12, 16, 47" +- emulator: lr-scummvm + package: lr-scummvm + build: libretro + kind: copies + names: [] + search_dir: $md_inst/scummvm.zip + passes_to: $biosdir + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-scummvm.sh:55" +- emulator: lr-scummvm + package: lr-scummvm + build: libretro + kind: copies + names: + - scummvm.ini + passes_to: $biosdir + fails_when_missing: false + depends_on_option: "[[ ! -f \"$biosdir/scummvm.ini\" ]]" + source_ref: "scriptmodules/libretrocores/lr-scummvm.sh:60" +- emulator: lr-scummvm + package: lr-scummvm + build: libretro + kind: passes_path + names: [] + search_dir: $biosdir/scummvm/extra + passes_to: extrapath in $biosdir/scummvm.ini + fails_when_missing: false + depends_on_option: "[[ ! -f \"$biosdir/scummvm.ini\" ]]" + source_ref: "scriptmodules/libretrocores/lr-scummvm.sh:62" +- emulator: lr-scummvm + package: lr-scummvm + build: libretro + kind: passes_path + names: [] + search_dir: $biosdir/scummvm/theme + passes_to: themepath in $biosdir/scummvm.ini + fails_when_missing: false + depends_on_option: "[[ ! -f \"$biosdir/scummvm.ini\" ]]" + source_ref: "scriptmodules/libretrocores/lr-scummvm.sh:63" +- emulator: lr-scummvm + package: lr-scummvm + build: libretro + kind: fixed_name + names: + - Roland_SC-55.sf2 + case_insensitive: false + search_dir: $biosdir/scummvm/extra + passes_to: soundfont in $biosdir/scummvm.ini + fails_when_missing: false + depends_on_option: "[[ ! -f \"$biosdir/scummvm.ini\" ]]" + source_ref: "scriptmodules/libretrocores/lr-scummvm.sh:64" +- emulator: lr-smsplus-gx + package: lr-smsplus-gx + repo: "git https://github.com/libretro/smsplus-gx.git master" + systems: + - gamegear + - mastersystem + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-smsplus-gx.sh:12, 16, 43" +- emulator: lr-snes9x + package: lr-snes9x + repo: "git https://github.com/libretro/snes9x.git master" + systems: + - snes + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-snes9x.sh:12, 16, 48" +- emulator: lr-snes9x2002 + package: lr-snes9x2002 + repo: "git https://github.com/libretro/snes9x2002.git master" + systems: + - snes + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-snes9x2002.sh:12, 16, 49" +- emulator: lr-snes9x2005 + package: lr-snes9x2005 + repo: "git https://github.com/libretro/snes9x2005.git master" + systems: + - snes + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-snes9x2005.sh:12, 16, 45" +- emulator: lr-snes9x2010 + package: lr-snes9x2010 + repo: "git https://github.com/libretro/snes9x2010.git master" + systems: + - snes + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-snes9x2010.sh:12, 16, 55" +- emulator: lr-stella + package: lr-stella + repo: "git https://github.com/stella-emu/stella.git master :_get_commit_lr-stella" + systems: + - atari2600 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-stella.sh:12, 16, 53" +- emulator: lr-stella2014 + package: lr-stella2014 + repo: "git https://github.com/libretro/stella2014-libretro.git master" + systems: + - atari2600 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-stella2014.sh:12, 16, 42" +- emulator: lr-superflappybirds + package: lr-superflappybirds + repo: "git https://github.com/IgniparousTempest/libretro-superflappybirds.git master" + systems: + - ports + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-superflappybirds.sh:12, 16, 45" +- emulator: lr-tgbdual + package: lr-tgbdual + repo: "git https://github.com/libretro/tgbdual-libretro.git master" + systems: + - gb + - gbc + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-tgbdual.sh:12, 16, 46-47" +- emulator: lr-theodore + package: lr-theodore + repo: "git https://github.com/Zlika/theodore master" + systems: + - moto + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-theodore.sh:12, 16, 44" +- emulator: lr-tic80 + package: lr-tic80 + repo: "git https://github.com/libretro/TIC-80.git master" + systems: + - tic80 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-tic80.sh:12, 16, 49" +- emulator: lr-tyrquake + package: lr-tyrquake + repo: "git https://github.com/libretro/tyrquake.git master" + systems: + - ports + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-tyrquake.sh:12, 15, 68" +- emulator: lr-uae4arm + package: lr-uae4arm + repo: "git https://github.com/Chips-fr/uae4arm-rpi.git master" + systems: + - amiga + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-uae4arm.sh:12, 16, 48" +- emulator: lr-vba-next + package: lr-vba-next + repo: "git https://github.com/libretro/vba-next.git master" + systems: + - gba + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-vba-next.sh:12, 16, 45" +- emulator: lr-vecx + package: lr-vecx + repo: "git https://github.com/libretro/libretro-vecx.git master" + systems: + - vectrex + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-vecx.sh:12, 16, 62" +- emulator: lr-vecx + package: lr-vecx + build: libretro + kind: copies + names: + - fast.bin + - skip.bin + - system.bin + search_dir: $md_inst + passes_to: $biosdir + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-vecx.sh:55" +- emulator: lr-vice + package: lr-vice + repo: "git https://github.com/libretro/vice-libretro.git master" + systems: + - c64 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-vice.sh:12, 16, 67" +- emulator: lr-vice + package: lr-vice + build: libretro + kind: copies + names: + - data + search_dir: $md_inst + passes_to: $biosdir + fails_when_missing: false + source_ref: "scriptmodules/libretrocores/lr-vice.sh:76" +- emulator: lr-virtualjaguar + package: lr-virtualjaguar + repo: "git https://github.com/libretro/virtualjaguar-libretro.git master" + systems: + - atarijaguar + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-virtualjaguar.sh:12, 16, 44" +- emulator: lr-x1 + package: lr-x1 + repo: "git https://github.com/libretro/xmil-libretro.git master" + systems: + - x1 + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-x1.sh:12, 15, 41" +- emulator: lr-xrick + package: lr-xrick + repo: "git https://github.com/libretro/xrick-libretro.git master" + systems: + - ports + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-xrick.sh:12, 16, 40" +- emulator: lr-yabause + package: lr-yabause + repo: "git https://github.com/libretro/yabause.git master" + systems: + - saturn + build: libretro + kind: package + names: [] + source_ref: "scriptmodules/libretrocores/lr-yabause.sh:12, 16, 49" +- emulator: alephone + package: alephone + repo: "git https://github.com/Aleph-One-Marathon/alephone.git :_get_branch_alephone" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/alephone.sh:12, 16, 78-80" +- emulator: cannonball + package: cannonball + repo: "git https://github.com/djyt/cannonball.git master 2b3839dd34c1b4263ec5006fdeeb1ae2689cd401" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/cannonball.sh:12, 16, 60" +- emulator: cdogs-sdl + package: cdogs-sdl + repo: "git https://github.com/cxong/cdogs-sdl.git 1.4.1" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/cdogs-sdl.sh:12, 15, 48" +- emulator: cgenius + package: cgenius + repo: "git https://gitlab.com/Dringgstein/Commander-Genius.git v3.6.1" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/cgenius.sh:12, 15, 44" +- emulator: darkplaces-quake + package: darkplaces-quake + repo: "git https://github.com/xonotic/darkplaces.git div0-stable" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/darkplaces-quake.sh:12, 15, scriptmodules/libretrocores/lr-tyrquake.sh:68" +- emulator: dsda-doom + package: dsda-doom + repo: "git https://github.com/kraflab/dsda-doom :_get_branch_dsda-doom" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/dsda-doom.sh:12, 15, scriptmodules/libretrocores/lr-prboom.sh:86,\ + \ 88" +- emulator: dxx-rebirth + package: dxx-rebirth + repo: "git https://github.com/dxx-rebirth/dxx-rebirth master :_get_commit_dxx-rebirth" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/dxx-rebirth.sh:12, 15, 156" +- emulator: eduke32 + package: eduke32 + repo: "git https://voidpoint.io/terminx/eduke32.git master dfc16b08" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/eduke32.sh:12, 15, 153" +- emulator: gemrb + package: gemrb + repo: "git https://github.com/gemrb/gemrb.git v0.8.6" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/gemrb.sh:12, 15, 49-53" +- emulator: giana + package: giana + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/giana.sh:12, 30" +- emulator: gzdoom + package: gzdoom + repo: "git https://github.com/ZDoom/gzdoom :_get_version_gzdoom" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/gzdoom.sh:12, 15, scriptmodules/libretrocores/lr-prboom.sh:86,\ + \ 88" +- emulator: ionfury + package: ionfury + repo: "git https://voidpoint.io/terminx/eduke32.git master dfc16b08" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/ionfury.sh:12, 15, scriptmodules/ports/eduke32.sh:153" +- emulator: ioquake3 + package: ioquake3 + repo: "git https://github.com/ioquake/ioq3 main :_get_commit_ioquake3" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/ioquake3.sh:12, 15, 71" +- emulator: jumpnbump + package: jumpnbump + repo: "git https://gitlab.com/LibreGames/jumpnbump.git master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/jumpnbump.sh:12, 16, 58" +- emulator: kodi + package: kodi + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/kodi.sh:12, 91" +- emulator: lincity-ng + package: lincity-ng + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/lincity-ng.sh:12, 38" +- emulator: love-0.10.2 + package: love-0.10.2 + repo: "git https://github.com/love2d/love 0.10.2" + systems: + - love + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/love-0.10.2.sh:12, 16, scriptmodules/ports/love.sh:67" +- emulator: love + package: love + repo: "git https://github.com/love2d/love 11.5" + systems: + - love + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/love.sh:12, 16, 67" +- emulator: lzdoom + package: lzdoom + repo: "git https://github.com/drfrag666/gzdoom 3.88b" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/lzdoom.sh:12, 15, scriptmodules/libretrocores/lr-prboom.sh:86,\ + \ 88" +- emulator: micropolis + package: micropolis + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/micropolis.sh:12, 34" +- emulator: minecraft + package: minecraft + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/minecraft.sh:12, 32" +- emulator: mysticmine + package: mysticmine + repo: "git https://github.com/dewitters/MysticMine.git master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/mysticmine.sh:12, 15, 36" +- emulator: openblok + package: openblok + repo: "git https://github.com/mmatyas/openblok.git v0.8.7" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/openblok.sh:12, 15, 39" +- emulator: openbor + package: openbor + repo: "git https://github.com/rofl0r/openbor.git master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/openbor.sh:12, 16, 47" +- emulator: openpht + package: openpht + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/openpht.sh:12, 45" +- emulator: openttd + package: openttd + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/openttd.sh:12, 32" +- emulator: opentyrian + package: opentyrian + repo: "git https://github.com/opentyrian/opentyrian.git master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/opentyrian.sh:12, 15, 51" +- emulator: quake3 + package: quake3 + repo: "git https://github.com/raspberrypi/quake3.git master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/quake3.sh:12, 15, 49" +- emulator: sdlpop + package: sdlpop + repo: "git https://github.com/NagyD/SDLPoP.git master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/sdlpop.sh:12, 15, 44" +- emulator: smw + package: smw + repo: "git https://github.com/mmatyas/supermariowar master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/smw.sh:12, 15, 48" +- emulator: solarus + package: solarus + repo: "git https://gitlab.com/solarus-games/solarus.git :_get_branch_solarus" + systems: + - solarus + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/solarus.sh:12, 16, 78" +- emulator: splitwolf + package: splitwolf + repo: "git https://bitbucket.org/linuxwolf6/splitwolf.git scrubbed" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/splitwolf.sh:12, 16, scriptmodules/ports/wolf4sdl.sh:57" +- emulator: srb2 + package: srb2 + repo: "git https://git.do.srb2.org/STJr/SRB2 :_get_branch_srb2" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/srb2.sh:12, 15, 63" +- emulator: steamlink + package: steamlink + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/steamlink.sh:12, 47" +- emulator: supertux + package: supertux + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/supertux.sh:12, 32" +- emulator: tyrquake + package: tyrquake + repo: "git https://github.com/RetroPie/tyrquake.git master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/tyrquake.sh:12, 15, scriptmodules/libretrocores/lr-tyrquake.sh:68" +- emulator: uqm + package: uqm + repo: "file :_get_archive_uqm" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/uqm.sh:12, 15, 59" +- emulator: vvvvvv + package: vvvvvv + repo: "git https://github.com/TerryCavanagh/VVVVVV master 39abcfa8" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/vvvvvv.sh:12, 15, 47" +- emulator: wolf4sdl + package: wolf4sdl + repo: "git https://github.com/AryanWolf3D/Wolf4SDL.git master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/wolf4sdl.sh:12, 15, 57" +- emulator: xrick + package: xrick + repo: "git https://github.com/RetroPie/xrick.git master" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/xrick.sh:12, 16, 42" +- emulator: yquake2 + package: yquake2 + repo: "git https://github.com/yquake2/yquake2.git QUAKE2_8_70" + systems: + - ports + build: standalone + kind: package + names: [] + source_ref: "scriptmodules/ports/yquake2.sh:12, 15, 86" +- emulator: fs-uae + package: fs-uae + build: standalone + kind: fixed_name + names: + - kick13.rom + case_insensitive: false + search_dir: $HOME/RetroPie/BIOS + passes_to: command line --kickstart_file + fails_when_missing: "You need to copy the Amiga kickstart file (kick13.rom) to the\ + \ folder $biosdir to boot the Amiga emulator." + source_ref: "scriptmodules/emulators/fs-uae/fs-uae.sh:23-26, 41" +- emulator: reicast + package: reicast + build: standalone + kind: fixed_name + names: + - dc_boot.bin + case_insensitive: false + search_dir: $HOME/RetroPie/BIOS/dc + fails_when_missing: "You need to copy the Dreamcast BIOS files (dc_boot.bin and\ + \ dc_flash.bin) to the folder $biosdir to boot the Dreamcast emulator." + source_ref: "scriptmodules/emulators/reicast/reicast.sh:22-25" diff --git a/schemas/platform.schema.json b/schemas/platform.schema.json index a2ab7805..8a5dda57 100644 --- a/schemas/platform.schema.json +++ b/schemas/platform.schema.json @@ -153,9 +153,26 @@ "passes_path", "links", "copies", - "scans_dir" + "moves", + "scans_dir", + "package" ], - "description": "names_searched: tries the names in order, first found wins. fixed_name: writes or opens one path per name. core_option: sets a core option whose value names the file. passes_path: hands over a directory. links, copies: links or copies a file to where the emulator reads it. scans_dir: the emulator picks from a directory" + "description": "names_searched: tries the names in order, first found wins. fixed_name: writes or opens one path per name. core_option: sets a core option whose value names the file. passes_path: hands over a directory. links, copies: links or copies a file to where the emulator reads it. moves: moves a file the user left in one folder to the folder the launcher links from. scans_dir: the emulator picks from a directory. package: names no file, records what a package builds (`repo`) and the systems it registers (`systems`)" + }, + "package": { + "type": "string", + "description": "The platform package whose script this record comes from, when the platform installs emulators as packages" + }, + "repo": { + "type": "string", + "description": "What the package fetches and builds, as its script declares it: method, URL, then branch or commit" + }, + "systems": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Systems the package registers, under the platform's own names, in the order the script adds them" }, "slot": { "type": "string", diff --git a/scripts/scraper/retropie_launchers.py b/scripts/scraper/retropie_launchers.py new file mode 100644 index 00000000..1d9e1df0 --- /dev/null +++ b/scripts/scraper/retropie_launchers.py @@ -0,0 +1,995 @@ +"""RetroPie's launcher layer, read from the scriptmodules. + +RetroPie publishes no BIOS list, but its package scripts decide where a file +dropped in ~/RetroPie/BIOS ends up: px68k links five names into ~/.keropi, +redream links dc_boot.bin under another name, sdltrs passes one ROM per +machine on its command line, the fs-uae launch script refuses to start +without kick13.rom. Each package also says which project it builds +(`rp_module_repo`) and which systems it registers (`addSystem`), which is +what ties a package to the emulator profile describing that build. + +The bash is read as text, never run. A small evaluator follows what the +scripts do between a function's braces: local assignments, arrays, `for` +loops, brace expansion, `$md_id` and calls into other packages' functions, +the way RetroPie runs them in one shell. Every line of a package function +that names the BIOS directory must match a known construct, else the scrape +stops with LauncherPatternMissing: a use nobody classified would otherwise +drop out of the platform file without a word. +""" + +from __future__ import annotations + +import re +import shlex +from collections.abc import Iterator +from dataclasses import dataclass, field +from itertools import product +from pathlib import PurePosixPath +from typing import Any + +SCRIPTMODULES = "scriptmodules" +SECTIONS = ("emulators", "libretrocores", "ports") +PACKAGES_SCRIPT = "retropie_packages.sh" + +BIOSDIR = "$biosdir" +# The package whose config every lr- core runs under. +LIBRETRO_FRONTEND = "retroarch" +# The launch scripts copied next to an emulator spell the directory out. +BIOS_SPELLED = "RetroPie/BIOS" + +# Commands whose $biosdir argument creates, owns or deletes a path and hands +# nothing to an emulator. +HOUSEKEEPING = frozenset({"mkUserDir", "chown", "chmod", "rm", "mkdir", "iniConfig"}) + +# Arguments that name a BIOS file or directory outside $biosdir, per package, +# as the emulator documents the flag. Each must still be in the scriptmodule. +OUTSIDE_BIOS: dict[str, tuple[str, ...]] = { + "basilisk": ("--rom",), # BasiliskII --rom + "gngeopi": ("-B",), # gngeo -B/--biospath +} + +_FUNCTION = re.compile(r"^function\s+([\w.+-]+)\s*\(\)\s*\{\s*$") +_ASSIGN = re.compile(r"^(?:local\s+)?([A-Za-z_]\w*)=(.*)$") +_DECLARE = re.compile(r"^local\s+([A-Za-z_]\w*(?:\s+[A-Za-z_]\w*)*)\s*$") +_FOR = re.compile(r"^for\s+([A-Za-z_]\w*)\s+in\s+(.*?)\s*(?:;\s*do)?\s*$") +_HEREDOC = re.compile(r"(? None: + super().__init__(f"{path}: {what}") + + +@dataclass +class Launcher: + """One thing a package hands an emulator, or the package itself.""" + + emulator: str + build: str + kind: str + names: list[str] + source_ref: str + package: str | None = None + repo: str | None = None + systems: list[str] | None = None + slot: str | None = None + case_insensitive: bool | None = None + search_dir: str | None = None + passes_to: str | None = None + fails_when_missing: bool | str | None = None + depends_on_option: str | None = None + lines: list[tuple[str, int]] = field(default_factory=list, repr=False) + + def entry(self) -> dict[str, Any]: + """The platform YAML form, in a fixed key order, unset keys left out.""" + order = ( + "emulator", "package", "repo", "systems", "build", "kind", "slot", + "names", "case_insensitive", "search_dir", "passes_to", + "fails_when_missing", "depends_on_option", "source_ref", + ) + return {key: getattr(self, key) for key in order if getattr(self, key) is not None} + + +@dataclass +class Module: + """One package script: its id, section, lines and functions.""" + + path: str + section: str + lines: list[str] + id: str + id_line: int + repo: str | None + repo_line: int | None + functions: dict[str, tuple[int, int]] = field(default_factory=dict) + + @property + def build(self) -> str: + libretro = self.section == "libretrocores" or self.id == LIBRETRO_FRONTEND + return "libretro" if libretro else "standalone" + + +@dataclass +class Event: + """A statement reached while walking a package's functions.""" + + path: str + line: int + words: list[list[str]] + raw: str + conditions: list[str] + heredoc: bool + opener: list[list[str]] = field(default_factory=list) + + +def _logical_lines( + lines: list[str], start: int, end: int +) -> Iterator[tuple[int, str, str | None]]: + """(line number, text, heredoc opener or None) for lines start..end, continuations joined.""" + tag: str | None = None + opener = "" + number = start + while number <= end: + text = lines[number - 1] + first = number + if tag is not None: + if text.strip() == tag: + tag = None + else: + yield first, text, opener + number += 1 + continue + while text.rstrip().endswith("\\") and number < end: + number += 1 + text = text.rstrip()[:-1] + " " + lines[number - 1].strip() + opened = _HEREDOC.search(text) + if opened is not None: + tag = opened.group(1) + opener = text.strip() + yield first, text, None + number += 1 + + +def _brace(word: str) -> list[str]: + """Bash brace expansion of comma lists, outside variable references.""" + found = re.search(r"(? list[str]: + """Shell words with quotes removed, a line bash itself would accept.""" + try: + return shlex.split(text, comments=True) + except ValueError: + return text.split() + + +class Scripts: + """Every package script, with the functions RetroPie loads into one shell.""" + + def __init__(self, files: dict[str, str]) -> None: + self.files = files + self.modules: dict[str, Module] = {} + self.owner: dict[str, Module] = {} + self._walked: dict[str, list[Event]] = {} + for path in sorted(files): + parts = PurePosixPath(path).parts + is_package = ( + len(parts) == 3 + and parts[0] == SCRIPTMODULES + and parts[1] in SECTIONS + and parts[2].endswith(".sh") + ) + if is_package: + module = self._parse(path, parts[1], files[path]) + if module is not None: + self.modules[module.id] = module + if not self.modules: + raise LauncherPatternMissing(SCRIPTMODULES, "no package script declares rp_module_id") + for module in self.modules.values(): + for name in module.functions: + self.owner[name] = module + + @staticmethod + def _parse(path: str, section: str, text: str) -> Module | None: + lines = text.splitlines() + fields: dict[str, tuple[str, int]] = {} + for found in _MODULE_FIELD.finditer(text): + line = text.count("\n", 0, found.start()) + 1 + fields.setdefault(found.group(1), (found.group(2), line)) + if "id" not in fields: + return None + repo = fields.get("repo") + module = Module( + path=path, section=section, lines=lines, + id=fields["id"][0], id_line=fields["id"][1], + repo=repo[0] if repo else None, repo_line=repo[1] if repo else None, + ) + opened: tuple[str, int] | None = None + tag: str | None = None + for number, line in enumerate(lines, 1): + # A generated script may define functions of its own. + if tag is not None: + if line.strip() == tag: + tag = None + continue + heredoc = _HEREDOC.search(line) + if heredoc is not None: + tag = heredoc.group(1) + header = _FUNCTION.match(line) + if header is not None: + opened = (header.group(1), number) + elif opened is not None and line.rstrip() == "}": + module.functions[opened[0]] = (opened[1], number) + opened = None + if opened is not None: + raise LauncherPatternMissing(path, f"function {opened[0]} has no closing brace") + return module + + def echo_value(self, name: str) -> str | None: + """What a function whose whole body is one `echo "X"` prints.""" + module = self.owner.get(name) + if module is None: + return None + start, end = module.functions[name] + body = [line.strip() for line in module.lines[start:end - 1] if line.strip()] + if len(body) == 1: + words = _split(body[0]) + if len(words) == 2 and words[0] == "echo": + return words[1] + return None + + def walk(self, package: Module) -> list[Event]: + """Every statement of a package's functions, as RetroPie runs them for it.""" + if package.id not in self._walked: + events: dict[tuple[str, int], Event] = {} + for name in package.functions: + self._walk(package, name, {}, [], set(), events) + self._walked[package.id] = sorted( + events.values(), key=lambda e: (e.path != package.path, e.path, e.line) + ) + return self._walked[package.id] + + def _walk( + self, + package: Module, + name: str, + args: dict[str, list[str]], + conditions: list[str], + stack: set[str], + events: dict[tuple[str, int], Event], + ) -> None: + if name in stack: + return + module = self.owner[name] + start, end = module.functions[name] + env: dict[str, list[str]] = dict(args) + loops: list[tuple[str | None, list[str] | None]] = [] + branches: list[tuple[str, bool | None]] = [] + array: tuple[str, list[str]] | None = None + for number, text, opener in _logical_lines(module.lines, start + 1, end - 1): + stripped = text.strip() + if array is not None: + body = re.sub(r"\s+#.*$", "", stripped) + closed = body.endswith(")") + array[1].append(body[:-1] if closed else body) + if closed: + words = _split(" ".join(array[1])) + env[array[0]] = [v for w in words for v in self.expand(w, package, env)] + array = None + continue + if opener is not None: + if self._live(branches): + words = [self.expand(w, package, env) for w in stripped.split()] + events.setdefault((module.path, number), Event( + module.path, number, words, stripped, + conditions + self._shown(branches, package, env), True, + [self.expand(w, package, env) for w in _split(opener)], + )) + continue + if not stripped or stripped.startswith("#"): + continue + if self._branch(stripped, package, env, branches): + continue + if not self._live(branches): + continue + loop = _FOR.match(stripped) + if loop is not None: + values = [v for w in _split(loop.group(2)) for v in self.expand(w, package, env)] + loops.append((loop.group(1), env.get(loop.group(1)))) + env[loop.group(1)] = values + continue + if re.match(r"^(while|until)\b|^for\s*\(\(", stripped): + loops.append((None, None)) + continue + if stripped == "done" or stripped.startswith("done ") or stripped.startswith("done;"): + if loops: + var, previous = loops.pop() + if var is not None: + if previous is None: + env.pop(var, None) + else: + env[var] = previous + continue + if stripped in ("do", "then", "else", "fi", "esac", "{", "}"): + continue + guard = re.match(r"^\[\[\s*(.*?)\s*\]\]\s*&&\s*(.*)$", stripped) + shown = conditions + self._shown(branches, package, env) + if guard is not None: + verdict = self._md_id_test(f"[[ {guard.group(1)} ]]", package) + if verdict is False or "$md_mode" in guard.group(1) or "$mode" in guard.group(1): + continue + if verdict is None: + shown = shown + [self._render(guard.group(1), package, env)] + stripped = guard.group(2) + opens = re.match(r"^(?:local\s+)?([A-Za-z_]\w*)=\(([^)]*)$", stripped) + if opens is not None: + array = (opens.group(1), [opens.group(2)]) + continue + if self._bind(stripped, package, env): + continue + words = [self.expand(w, package, env) for w in _split(stripped)] + # The first walk to reach a line is the one with its caller's arguments. + events.setdefault( + (module.path, number), Event(module.path, number, words, stripped, shown, False) + ) + callee = words[0][0] if words and words[0] else None + if callee in self.owner and callee != name: + call_args = {str(i): w for i, w in enumerate(words[1:], 1)} + self._walk(package, callee, call_args, shown, stack | {name}, events) + + def _branch( + self, stripped: str, package: Module, env: dict[str, list[str]], + branches: list[tuple[str, bool | None]], + ) -> bool: + """Track if/elif/else/fi, and say whether the line was one of them.""" + opened = re.match(r"^(if|elif)\s+(.*?)\s*(?:;\s*then)?\s*$", stripped) + if opened is not None: + condition = opened.group(2) + verdict = self._md_id_test(condition, package) + if "$md_mode" in condition or "$mode" in condition: + verdict = True if "install" in condition else None + if opened.group(1) == "if": + branches.append((condition, verdict)) + elif branches: + previous, previous_verdict = branches[-1] + if previous_verdict is True: + verdict = False + branches[-1] = (condition, verdict) + return True + if stripped == "else" and branches: + condition, verdict = branches[-1] + branches[-1] = (f"not ({condition})", None if verdict is None else not verdict) + return True + if stripped == "fi" or stripped.startswith("fi "): + if branches: + branches.pop() + return True + return False + + @staticmethod + def _live(branches: list[tuple[str, bool | None]]) -> bool: + return all(verdict is not False for _c, verdict in branches) + + def _shown( + self, branches: list[tuple[str, bool | None]], package: Module, env: dict[str, list[str]] + ) -> list[str]: + return [ + self._render(condition, package, env) + for condition, verdict in branches if verdict is None + ] + + def _render(self, condition: str, package: Module, env: dict[str, list[str]]) -> str: + """A condition with its variables filled in when each takes one value.""" + values = self.expand(condition, package, env) + return values[0] if len(values) == 1 else condition + + @staticmethod + def _md_id_test(condition: str, package: Module) -> bool | None: + test = _MD_ID_TEST.match(condition.strip()) + if test is None: + return None + equal = package.id == test.group(2) + return equal if test.group(1) == "==" else not equal + + def _bind(self, stripped: str, package: Module, env: dict[str, list[str]]) -> bool: + """Record a variable assignment, and say whether the line was one.""" + if _DECLARE.match(stripped): + return True + assign = _ASSIGN.match(stripped) + if assign is None: + return False + name, value = assign.group(1), assign.group(2).strip() + if value.startswith("("): + closing = value.rfind(")") + inner = value[1:closing] if closing > 0 else value[1:] + env[name] = [v for w in _split(inner) for v in self.expand(w, package, env)] + return True + words = _split(value) or [""] + if "$(" in words[0] and _SUBST.fullmatch(words[0]) is None: + # A command's output: the variable stays a reference. + env.pop(name, None) + return True + expanded = self.expand(words[0], package, env) + if any("$(" in v for v in expanded): + env.pop(name, None) + else: + env[name] = expanded + return True + + def expand(self, word: str, package: Module, env: dict[str, list[str]]) -> list[str]: + """Every value a word takes: braces, $md_id, bound variables, $(echo functions).""" + word = re.sub(r"\$\{md_id\}|\$md_id\b", package.id, word) + + def substitute(found: re.Match[str]) -> str: + printed = self.echo_value(found.group(1)) + return printed if printed is not None else found.group(0) + + word = _SUBST.sub(substitute, word) + results: list[str] = [] + for braced in _brace(word): + names = [m.group(1) or m.group(3) for m in _VAR.finditer(braced)] + bound = [n for n in names if n in env] + if not bound: + results.append(braced) + continue + for values in product(*(env[n] for n in bound)): + chosen = dict(zip(bound, values)) + + def replace(found: re.Match[str]) -> str: + key = found.group(1) or found.group(3) + return chosen.get(key, found.group(0)) + + results.append(_VAR.sub(replace, braced)) + return results + + +def _mentions_bios(text: str) -> bool: + return BIOSDIR in text or "${biosdir}" in text or BIOS_SPELLED in text + + +def _is_file(path: str) -> bool: + return bool(_EXTENSION.search(PurePosixPath(path).name)) and "*" not in path + + +def _split_path(path: str) -> tuple[str, str]: + pure = PurePosixPath(path.rstrip("/")) + return str(pure.parent), pure.name + + +class PackageReader: + """Launcher records of one package, from the statements its functions run.""" + + def __init__(self, scripts: Scripts, package: Module) -> None: + self.scripts = scripts + self.package = package + self.records: list[Launcher] = [] + self.installed_as: dict[str, str] = {} + + def record( + self, kind: str, names: list[str], lines: list[tuple[str, int]], **fields: Any + ) -> None: + self.records.append(Launcher( + emulator=fields.pop("emulator", self.package.id), + package=self.package.id, + build=self.package.build, + kind=kind, + names=names, + source_ref=source_ref(lines), + lines=list(lines), + **fields, + )) + + def final(self, path: str) -> str: + """The file a scratch config ends up as, from the copyDefaultConfig that installs it.""" + return self.installed_as.get(path, path) + + def read(self) -> list[Launcher]: + events = self.scripts.walk(self.package) + for event in events: + if not event.heredoc and event.words and event.words[0] == ["copyDefaultConfig"]: + if len(event.words) >= 3 and len(event.words[1]) == 1 and len(event.words[2]) == 1: + self.installed_as.setdefault(event.words[1][0], event.words[2][0]) + links: list[Event] = [] + for event in events: + if not event.words or not event.words[0]: + continue + if links and not self._same_link_run(links[-1], event): + self._links(links) + links = [] + if self._is_bios_link(event): + links.append(event) + continue + self._classify(event) + if links: + self._links(links) + self._outside_bios(events) + return self.records + + @staticmethod + def _depends(event: Event) -> str | None: + return "; ".join(event.conditions) if event.conditions else None + + def _classify(self, event: Event) -> None: + command = event.words[0][0] + if event.heredoc: + if _mentions_bios(event.raw): + self._heredoc_setting(event) + return + if command == "addEmulator": + self._add_emulator(event) + return + if not _mentions_bios(event.raw): + return + if command in HOUSEKEEPING: + return + handlers = { + "cp": self._copy, + "runCmd": self._run_cmd, + "unzip": self._unzip, + "mv": self._move, + "moveConfigFile": self._move, + "moveConfigDir": self._move_dir, + "iniSet": self._ini_set, + "copyDefaultConfig": self._written, + "cat": self._written, + "echo": self._written, + "cmake": self._build_flag, + } + handler = handlers.get(command) + if handler is None: + raise LauncherPatternMissing( + f"{event.path}:{event.line}", f"unrecognised use of the BIOS directory: {event.raw}" + ) + handler(event) + + def _is_bios_link(self, event: Event) -> bool: + words = event.words + if words[0][0] != "ln" or not _mentions_bios(event.raw): + return False + paths = [w for w in words[1:] if not w[0].startswith("-")] + if len(paths) != 2 or not all(_mentions_bios(v) for v in paths[0]): + raise LauncherPatternMissing( + f"{event.path}:{event.line}", f"link without a BIOS source: {event.raw}" + ) + return True + + @staticmethod + def _same_link_run(previous: Event, event: Event) -> bool: + return ( + event.words[0][0] == "ln" + and previous.path == event.path + and event.line - previous.line <= 2 + ) + + def _links(self, events: list[Event]) -> None: + sources: list[str] = [] + targets: list[str] = [] + for event in events: + paths = [w for w in event.words[1:] if not w[0].startswith("-")] + source, target = paths + if len(target) == 1 and len(source) > 1: + target = [f"{target[0].rstrip('/')}/{_split_path(s)[1]}" for s in source] + sources += source + targets += target + folders = {_split_path(s)[0] for s in sources} + whole_dir = all( + not _is_file(s) and "/" not in s.replace(BIOSDIR, "", 1).strip("/") for s in sources + ) + if whole_dir: + names: list[str] = [] + search_dir = sources[0] + passes_to = f"{targets[0]} is a symlink to it" + else: + if len(folders) != 1: + raise LauncherPatternMissing( + f"{events[0].path}:{events[0].line}", + "links from several BIOS folders in one run", + ) + search_dir = folders.pop() + names = [_split_path(s)[1] for s in sources] + passes_to = _render_targets(names, targets) + self.record( + "links", names, [(e.path, e.line) for e in events], + case_insensitive=False, search_dir=search_dir, passes_to=passes_to, + fails_when_missing=False, depends_on_option=self._depends(events[0]), + ) + + def _copy(self, event: Event) -> None: + paths = [v for w in event.words[1:] if not w[0].startswith("-") for v in w] + *sources, target = paths + if not _mentions_bios(target): + raise LauncherPatternMissing( + f"{event.path}:{event.line}", f"copy out of the BIOS directory: {event.raw}" + ) + folders = {_split_path(s)[0] for s in sources} + if len(folders) != 1: + raise LauncherPatternMissing(f"{event.path}:{event.line}", "copy from several folders") + self.record( + "copies", [_split_path(s)[1] for s in sources], [(event.path, event.line)], + search_dir=folders.pop(), passes_to=target.rstrip("/"), + fails_when_missing=False, depends_on_option=self._depends(event), + ) + + def _run_cmd(self, event: Event) -> None: + inner = Event(event.path, event.line, event.words[1:], event.raw, event.conditions, False) + if not inner.words or inner.words[0][0] != "unzip": + raise LauncherPatternMissing(f"{event.path}:{event.line}", f"runCmd of {event.raw}") + self._unzip(inner) + + def _unzip(self, event: Event) -> None: + values = [v for w in event.words[1:] for v in w] + if "-d" not in values: + raise LauncherPatternMissing(f"{event.path}:{event.line}", "unzip without -d") + target = values[values.index("-d") + 1] + archives = [v for v in values if v.endswith(".zip")] + if len(archives) != 1 or not _mentions_bios(target): + raise LauncherPatternMissing(f"{event.path}:{event.line}", f"unzip of {event.raw}") + self.record( + "copies", [], [(event.path, event.line)], + search_dir=archives[0], passes_to=target, + fails_when_missing=False, depends_on_option=self._depends(event), + ) + + def _move(self, event: Event) -> None: + source, target = (w for w in event.words[1:] if not w[0].startswith("-")) + if not all(_mentions_bios(v) for v in source + target): + raise LauncherPatternMissing( + f"{event.path}:{event.line}", f"move across folders: {event.raw}" + ) + folders = {_split_path(s)[0] for s in source} + destinations = {_split_path(t)[0] for t in target} + if len(folders) != 1 or len(destinations) != 1: + raise LauncherPatternMissing( + f"{event.path}:{event.line}", "move between several folders" + ) + self.record( + "moves", [_split_path(s)[1] for s in source], [(event.path, event.line)], + case_insensitive=False, search_dir=folders.pop(), passes_to=destinations.pop(), + fails_when_missing=False, depends_on_option=self._depends(event), + ) + + def _move_dir(self, event: Event) -> None: + link, real = (w[0] for w in event.words[1:3]) + if not _mentions_bios(real) or _mentions_bios(link): + raise LauncherPatternMissing( + f"{event.path}:{event.line}", f"moveConfigDir into a non-BIOS folder: {event.raw}" + ) + self.record( + "links", [], [(event.path, event.line)], + search_dir=real, passes_to=f"{link} is a symlink to it", + fails_when_missing=False, depends_on_option=self._depends(event), + ) + + def _ini_set(self, event: Event) -> None: + key, value = event.words[1][0], event.words[2][0] + target = self._ini_file(event) + passes_to = f"{key} in {self.final(target)}" if target else key + if _is_file(value) and ";" not in value: + folder, name = _split_path(value) + self.record( + "fixed_name", [name], [(event.path, event.line)], + case_insensitive=False, search_dir=folder, passes_to=passes_to, + fails_when_missing=False, depends_on_option=self._depends(event), + ) + return + self.record( + "passes_path", [], [(event.path, event.line)], + search_dir=value, passes_to=passes_to, + fails_when_missing=False, depends_on_option=self._depends(event), + ) + + def _ini_file(self, event: Event) -> str | None: + """The file the closest iniConfig above this iniSet points at.""" + if len(event.words) > 3: + return event.words[3][0] + lines = self.scripts.files[event.path].splitlines() + for number in range(event.line - 1, 0, -1): + words = _split(lines[number - 1].strip()) + if words and words[0] == "iniConfig" and len(words) >= 4: + return words[3] + if _FUNCTION.match(lines[number - 1]): + break + return None + + def _written(self, event: Event) -> None: + """A file the package writes into the BIOS directory itself.""" + target = next( + (v for w in reversed(event.words[1:]) for v in w if _mentions_bios(v)), None + ) + if target is None or not _is_file(target): + raise LauncherPatternMissing(f"{event.path}:{event.line}", f"write of {event.raw}") + folder, name = _split_path(target) + self.record( + "copies", [name], [(event.path, event.line)], + search_dir=None, passes_to=folder, + fails_when_missing=False, depends_on_option=self._depends(event), + ) + + def _build_flag(self, event: Event) -> None: + flags = [ + v for w in event.words[1:] for v in w + if v.startswith("-D") and "=" in v and _mentions_bios(v) + ] + if not flags: + raise LauncherPatternMissing(f"{event.path}:{event.line}", f"cmake of {event.raw}") + for flag in flags: + option, value = flag.split("=", 1) + self.record( + "passes_path", [], [(event.path, event.line)], + search_dir=value, passes_to=f"build option {option}", + fails_when_missing=False, depends_on_option=self._depends(event), + ) + + def _heredoc_setting(self, event: Event) -> None: + """A `KEY = $biosdir/...` or `--flag="$biosdir"` line of a generated file.""" + text = event.raw + setting = re.match(r'^([\w.-]+)\s*=\s*"?([^"]*)"?$', text) + flag = re.match(r'^(--?[\w-]+)(?:=|\s+)"?([^"]*)"?$', text) + found = flag or setting + if found is None: + raise LauncherPatternMissing( + f"{event.path}:{event.line}", f"generated line names the BIOS directory: {text}" + ) + key, value = found.group(1), found.group(2) + kind, names, folder = "passes_path", [], value + if _is_file(value): + folder, name = _split_path(value) + kind, names = "fixed_name", [name] + written = _redirect_target(event.opener) + if written is None: + raise LauncherPatternMissing( + f"{event.path}:{event.line}", "generated file with no > or >> target" + ) + self.record( + kind, names, [(event.path, event.line)], + case_insensitive=False if kind == "fixed_name" else None, + search_dir=folder, passes_to=f"{key} in {self.final(written)}", + fails_when_missing=False, depends_on_option=self._depends(event), + ) + + def _add_emulator(self, event: Event) -> None: + if len(event.words) < 5: + return + command = event.words[4][0] + if not _mentions_bios(command): + return + names = event.words[2] + tokens = _split(command) + found = [ + (flag, value) for flag, value in zip(tokens, tokens[1:]) + if flag.startswith("-") and _mentions_bios(value) + ] + found += [ + tuple(token.split("=", 1)) for token in tokens + if token.startswith("-") and "=" in token and _mentions_bios(token.split("=", 1)[1]) + ] + if not found: + raise LauncherPatternMissing( + f"{event.path}:{event.line}", + f"addEmulator names the BIOS directory without a flag: {command}", + ) + for emulator in names: + for flag, value in found: + self._command_line(event, emulator, flag, value) + + def _command_line(self, event: Event, emulator: str, flag: str, value: str) -> None: + folder, name = _split_path(value) + if _is_file(value): + kind, names, search = "fixed_name", [name], folder + else: + kind, names, search = "passes_path", [], value + self.record( + kind, names, [(event.path, event.line)], emulator=emulator, + case_insensitive=False if kind == "fixed_name" else None, + search_dir=search, passes_to=f"command line {flag}", + fails_when_missing=False, depends_on_option=self._depends(event), + ) + + def _outside_bios(self, events: list[Event]) -> None: + flags = OUTSIDE_BIOS.get(self.package.id) + if not flags: + return + seen: set[str] = set() + for event in events: + if event.words[0][0] != "addEmulator" or len(event.words) < 5: + continue + tokens = _split(event.words[4][0]) + for flag, value in zip(tokens, tokens[1:]): + if flag in flags: + seen.add(flag) + for emulator in event.words[2]: + self._command_line(event, emulator, flag, value) + missing = sorted(set(flags) - seen) + if missing: + raise LauncherPatternMissing( + self.package.path, f"addEmulator no longer passes {missing}" + ) + + +def _redirect_target(words: list[list[str]]) -> str | None: + """The file a `cat > FILE << EOF` or `cat << EOF >> FILE` line writes.""" + flat = [w[0] for w in words if w] + for index, word in enumerate(flat[:-1]): + if word in (">", ">>"): + return flat[index + 1] + return None + + +def merge_records(records: list[Launcher]) -> list[Launcher]: + """Records equal but for their lines become one, citing every line.""" + merged: dict[tuple[Any, ...], Launcher] = {} + for record in records: + entry = record.entry() + entry.pop("source_ref") + key = tuple((k, repr(v)) for k, v in entry.items()) + if key in merged: + kept = merged[key] + kept.lines += record.lines + kept.source_ref = source_ref(kept.lines) + else: + merged[key] = record + return list(merged.values()) + + +def _render_targets(names: list[str], targets: list[str]) -> str: + """Where linked names land: one folder when the names are kept, each path when renamed.""" + folders = {_split_path(t)[0] for t in targets} + kept = [_split_path(t)[1] for t in targets] == names + if kept and len(folders) == 1: + return f"{folders.pop()}/" + return ", ".join(targets) + + +def source_ref(lines: list[tuple[str, int]]) -> str: + """`path:a-b, c` per file, in first-seen file order, adjacent lines joined.""" + by_path: dict[str, list[int]] = {} + for path, number in lines: + by_path.setdefault(path, []).append(number) + parts = [] + for path, numbers in by_path.items(): + ranges: list[list[int]] = [] + for number in sorted(set(numbers)): + if ranges and number == ranges[-1][1] + 1: + ranges[-1][1] = number + else: + ranges.append([number, number]) + spans = ", ".join(str(a) if a == b else f"{a}-{b}" for a, b in ranges) + parts.append(f"{path}:{spans}") + return ", ".join(parts) + + +def package_record(scripts: Scripts, package: Module) -> Launcher: + """What the package builds and the systems it registers.""" + systems: list[str] = [] + lines: list[tuple[str, int]] = [(package.path, package.id_line)] + if package.repo_line is not None: + lines.append((package.path, package.repo_line)) + for event in scripts.walk(package): + if event.heredoc or not event.words or not event.words[0]: + continue + command = event.words[0][0] + if command == "addSystem": + values = event.words[1] if len(event.words) > 1 else [] + elif command == "addPort": + values = ["ports"] + else: + continue + if not values: + raise LauncherPatternMissing(f"{event.path}:{event.line}", f"{command} takes no value") + for value in values: + if "$" in value or not value: + raise LauncherPatternMissing( + f"{event.path}:{event.line}", f"system name {value!r} not resolved" + ) + if value not in systems: + systems.append(value) + lines.append((event.path, event.line)) + return Launcher( + emulator=package.id, package=package.id, repo=package.repo, + systems=systems or None, build=package.build, kind="package", names=[], + source_ref=source_ref(lines), + ) + + +def launch_script_records(scripts: Scripts) -> list[Launcher]: + """The launch scripts installed next to an emulator that refuse to start without a file.""" + records = [] + for path, text in sorted(scripts.files.items()): + parts = PurePosixPath(path).parts + is_script = ( + len(parts) == 4 and parts[0] == SCRIPTMODULES and parts[1] in SECTIONS + and path.endswith(".sh") + ) + if not is_script or not _mentions_bios(text): + continue + package = scripts.modules.get(parts[2]) + if package is None: + raise LauncherPatternMissing(path, f"launch script of no package {parts[2]}") + records += _launch_script(path, text.splitlines(), package) + return records + + +def _launch_script(path: str, lines: list[str], package: Module) -> list[Launcher]: + env: dict[str, str] = {"HOME": "$HOME"} + records = [] + checks = 0 + number = 0 + while number < len(lines): + number += 1 + stripped = lines[number - 1].strip() + if not stripped or stripped.startswith("#"): + continue + assign = re.match(r'^([A-Za-z_]\w*)="([^"]*)"$', stripped) + if assign is not None: + env[assign.group(1)] = _VAR.sub( + lambda m: env.get(m.group(1) or m.group(3), m.group(0)), assign.group(2) + ) + continue + check = re.match(r'^if \[\[ ! -f "([^"]+)" \]\]; then$', stripped) + if check is None: + continue + tested = check.group(1) + resolved = _VAR.sub(lambda m: env.get(m.group(1) or m.group(3), m.group(0)), tested) + if not _mentions_bios(resolved): + continue + block_start = number + message: str | None = None + exits = False + while number < len(lines) and lines[number].strip() != "fi": + number += 1 + body = lines[number - 1].strip() + exits = exits or body == "exit 1" + pause = re.search(r'--pause "([^"]*)"', body) + if pause is not None: + message = pause.group(1) + number += 1 + if not exits: + continue + checks += 1 + variable = re.fullmatch(r"\$\{?(\w+)\}?", tested) + passes_to = None + cited = list(range(block_start, number + 1)) + if variable is not None: + for later, line in enumerate(lines[number:], number + 1): + flag = re.search(r'(--?[\w-]+)="\$' + variable.group(1) + r'"', line) + if flag is not None: + passes_to = f"command line {flag.group(1)}" + cited.append(later) + break + folder, name = _split_path(resolved) + records.append(Launcher( + emulator=package.id, package=package.id, build=package.build, + kind="fixed_name", names=[name], case_insensitive=False, + search_dir=folder, passes_to=passes_to, + fails_when_missing=message if message is not None else True, + source_ref=source_ref([(path, n) for n in cited]), + )) + if not checks: + raise LauncherPatternMissing(path, "names the BIOS directory but checks no file") + return records + + +def extract_launchers(files: dict[str, str]) -> list[dict[str, Any]]: + """Every launcher record, from the scriptmodules keyed by repo-relative path.""" + scripts = Scripts(files) + records: list[Launcher] = [] + for package in sorted(scripts.modules.values(), key=lambda m: m.path): + records.append(package_record(scripts, package)) + records += merge_records(PackageReader(scripts, package).read()) + records += launch_script_records(scripts) + return [record.entry() for record in records] diff --git a/scripts/scraper/retropie_scraper.py b/scripts/scraper/retropie_scraper.py index 07a3d77c..85b47460 100644 --- a/scripts/scraper/retropie_scraper.py +++ b/scripts/scraper/retropie_scraper.py @@ -15,6 +15,10 @@ RetroArch: RetroPie claimed every libretro core in existence while shipping 96 of them, and claimed none of the standalone emulators it also packages (openmsx, pcsx2, xroar, sdltrs, amiberry and the rest). Both halves were wrong, in opposite directions. + +The same scripts carry the launcher layer (retropie_launchers): where each +package links, copies or passes a BIOS file, what it builds and which +systems it registers. """ from __future__ import annotations @@ -27,8 +31,14 @@ import urllib.request try: from .base_scraper import BaseScraper, BiosRequirement, fetch_branch_head + from .retropie_launchers import SCRIPTMODULES + from .retropie_launchers import SECTIONS as _SCRIPT_SECTIONS + from .retropie_launchers import extract_launchers except ImportError: from base_scraper import BaseScraper, BiosRequirement, fetch_branch_head + from retropie_launchers import SCRIPTMODULES + from retropie_launchers import SECTIONS as _SCRIPT_SECTIONS + from retropie_launchers import extract_launchers PLATFORM_NAME = "retropie" @@ -43,7 +53,7 @@ _VERSION_FILE = "retropie_packages.sh" _VERSION = re.compile(r'^__version="([^"]+)"', re.MULTILINE) # Sections RetroPie does not build as emulators: setup helpers, themes, # drivers and the like carry no core. -_PACKAGE_DIRS = ("emulators", "libretrocores", "ports") +_PACKAGE_DIRS = _SCRIPT_SECTIONS class Scraper(BaseScraper): @@ -56,6 +66,8 @@ class Scraper(BaseScraper): super().__init__(url=url) self._modules: list[str] | None = None self._version = "" + # Package scripts and the launch scripts beside them, by repo path. + self._scripts: dict[str, str] = {} def _fetch_archive(self) -> bytes: request = urllib.request.Request( @@ -89,12 +101,19 @@ class Scraper(BaseScraper): and parts[0] == "scriptmodules" and parts[1] in _PACKAGE_DIRS ) - if not (is_version_file or is_package): + is_launch_script = ( + len(parts) == 4 and parts[0] == SCRIPTMODULES and parts[1] in _SCRIPT_SECTIONS + ) + if not (is_version_file or is_package or is_launch_script): continue handle = archive.extractfile(member) if handle is None: continue text = handle.read().decode("utf-8", errors="replace") + if is_package or is_launch_script: + self._scripts[relative] = text + if is_launch_script: + continue match = (_VERSION if is_version_file else _MODULE_ID).search(text) if not match: continue @@ -139,6 +158,7 @@ class Scraper(BaseScraper): "source": self.url, "base_destination": "BIOS", "cores": cores, + "launchers": extract_launchers(self._scripts), } diff --git a/tests/test_launchers.py b/tests/test_launchers.py index ec22f8df..515d242e 100644 --- a/tests/test_launchers.py +++ b/tests/test_launchers.py @@ -31,6 +31,7 @@ from scraper.batocera_launchers import ( # noqa: E402 extract_launchers, hatari, ) +from scraper.retropie_launchers import Launcher as PackageLauncher # noqa: E402 PATHS = """from pathlib import Path from typing import Final @@ -372,7 +373,10 @@ class PlatformRecords(unittest.TestCase): def test_the_schema_describes_what_the_scraper_writes(self): fields = {f.name for f in dataclasses.fields(Launcher)} described = set(self.schema["$defs"]["launcher"]["properties"]) - self.assertEqual(fields, described) + # package, repo and systems are written by package platforms (RetroPie). + package_fields = {f.name for f in dataclasses.fields(PackageLauncher)} - {"lines"} + self.assertEqual(sorted(fields - described), []) + self.assertEqual(fields | package_fields, described) def test_the_wiki_names_every_launcher_field(self): page = (REPO_ROOT / "wiki" / "adding-a-platform.md").read_text(encoding="utf-8") diff --git a/tests/test_launchers_retropie.py b/tests/test_launchers_retropie.py new file mode 100644 index 00000000..a4280c73 --- /dev/null +++ b/tests/test_launchers_retropie.py @@ -0,0 +1,364 @@ +"""RetroPie's launcher layer read from the scriptmodules. + +Each fixture copies the lines an extractor reads from RetroPie-Setup +46128cd252cdecae852a4d0bafa2aaf9d03ab563, placed at the line numbers they +have there, so the source_ref a record carries is the one platforms/retropie.yml +cites. A construct that is gone or unknown must stop the scrape. +""" + +from __future__ import annotations + +import dataclasses +import json +import sys +import textwrap +import unittest +from pathlib import Path + +import yaml + +REPO_ROOT = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(REPO_ROOT / "scripts")) + +from scraper import batocera_launchers # noqa: E402 +from scraper import retropie_launchers as rl # noqa: E402 + +EMULATORS = "scriptmodules/emulators" +LIBRETRO = "scriptmodules/libretrocores" + + +def at(first_line: int, text: str) -> str: + """Text placed so its first line is line `first_line` of the file.""" + return "\n" * (first_line - 1) + textwrap.dedent(text).lstrip("\n") + + +def header(package: str, repo: str | None = None, repo_line: int = 15) -> str: + lines = {12: f'rp_module_id="{package}"'} + if repo is not None: + lines[repo_line] = f'rp_module_repo="{repo}"' + return "\n".join(lines.get(n, "") for n in range(1, max(lines) + 1)) + "\n" + + +def module(package: str, body: str, first_line: int, repo: str | None = None, + repo_line: int = 15) -> str: + head = header(package, repo, repo_line) + padding = first_line - 1 - head.count("\n") + return head + "\n" * padding + textwrap.dedent(body).lstrip("\n") + + +def records(files: dict[str, str], package: str | None = None) -> list[dict]: + found = rl.extract_launchers(files) + return [r for r in found if package is None or r["package"] == package] + + +PX68K = module("px68k", """ + function configure_px68k() { + mkRomDir "x68000" + + moveConfigDir "$home/.keropi" "$md_conf_root/x68000" + mkUserDir "$biosdir/keropi" + + local bios + for bios in cgrom.dat iplrom30.dat iplromco.dat iplrom.dat iplromxv.dat; do + if [[ -f "$biosdir/$bios" ]]; then + mv "$biosdir/$bios" "$biosdir/keropi/$bios" + fi + ln -sf "$biosdir/keropi/$bios" "$md_conf_root/x68000/$bios" + done + + addEmulator 1 "$md_id" "x68000" "$md_inst/px68k.sdl2 %ROM%" + addSystem "x68000" + } +""", 47, repo="git https://github.com/TurtleBazooka/px68k.git master") + +REDREAM = module("redream", """ + function configure_redream() { + mkUserDir "$biosdir/dc" + ln -sf "$biosdir/dc/dc_boot.bin" "$md_inst/boot.bin" + ln -sf "$biosdir/dc/dc_flash.bin" "$md_inst/flash.bin" + } +""", 56) + +SDLTRS = module("sdltrs", """ + function configure_sdltrs() { + local common_args + mkRomDir "trs-80" + + common_args="-fullscreen -nomousepointer -showled" + addEmulator 1 "$md_id-model1" "trs-80" "$md_inst/sdl2trs $common_args -m1 -romfile $biosdir/level2.rom -disk0 %ROM%" + addEmulator 0 "$md_id-model3" "trs-80" "$md_inst/sdl2trs $common_args -m3 -romfile3 $biosdir/level3.rom -disk0 %ROM%" + addEmulator 0 "$md_id-model4" "trs-80" "$md_inst/sdl2trs $common_args -m4 -romfile3 $biosdir/level4.rom -disk0 %ROM%" + addEmulator 0 "$md_id-model4p" "trs-80" "$md_inst/sdl2trs $common_args -m4p -romfile4p $biosdir/level4p.rom -disk0 %ROM%" + addSystem "trs-80" + } +""", 44) + +BASILISK = module("basilisk", """ + function configure_basilisk() { + addEmulator 1 "$md_id" "macintosh" "$md_inst/bin/BasiliskII --rom $romdir/macintosh/mac.rom --disk $romdir/macintosh/disk.img" + addSystem "macintosh" + } +""", 55, repo="git https://github.com/cebix/macemu.git master", repo_line=16) + +GNGEOPI = module("gngeopi", """ + function configure_gngeopi() { + addEmulator 0 "$md_id" "arcade" "$md_inst/bin/gngeo -i $romdir/neogeo -B $md_inst/neogeobios %ROM%" + addEmulator 0 "$md_id" "neogeo" "$md_inst/bin/gngeo -i $romdir/neogeo -B $md_inst/neogeobios %ROM%" + addSystem "arcade" + addSystem "neogeo" + } +""", 59) + +FS_UAE = module("fs-uae", """ + function configure_fs-uae() { + mkRomDir "amiga" + + addEmulator 1 "$md_id" "amiga" "CON:bash $md_inst/bin/fs-uae.sh %ROM%" + addSystem "amiga" + } +""", 76) + +FS_UAE_LAUNCHER = at(15, """ + rootdir="/opt/retropie" + datadir="$HOME/RetroPie" + romdir="$datadir/roms/amiga" + biosdir="$datadir/BIOS" + kickfile="$biosdir/kick13.rom" + + source "$rootdir/lib/archivefuncs.sh" + + if [[ ! -f "$kickfile" ]]; then + dialog --no-cancel --pause "You need to copy the Amiga kickstart file (kick13.rom) to the folder $biosdir to boot the Amiga emulator." 22 76 15 + exit 1 + fi +""") + "\n" * 14 + 'fs-uae --floppy_drive_0="$rom" --kickstart_file="$kickfile" --floppies_dir="$romdir"\n' + +DOSBOX = module("dosbox", """ + function configure_dosbox() { + local def=0 + mkRomDir "pc" + addEmulator "$def" "$md_id" "pc" "bash $romdir/pc/launcher %ROM%" + addSystem "pc" + + cat > "$romdir/pc/launcher" << _EOF_ + function midi_synth() { + echo start + } + _EOF_ + } +""", 64) + +DOSBOX_SDL2 = module("dosbox-sdl2", """ + function configure_dosbox-sdl2() { + configure_dosbox + } +""", 42, repo="git https://github.com/duganchen/dosbox.git master", repo_line=16) + +FBNEO = module("lr-fbneo", """ + function configure_lr-fbneo() { + local systems=( + "arcade" + "neogeo" + "pcengine" + ) + + local system + for system in "${systems[@]}"; do + addSystem "$system" + done + } +""", 94) + +MAME2003 = module("lr-mame2003", """ + function _get_dir_name_lr-mame2003() { + echo "mame2003" + } + + function configure_lr-mame2003() { + addSystem "arcade" + local dir_name="$(_get_dir_name_${md_id})" + cp "$md_inst/metadata/"{hiscore.dat,cheat.dat} "$biosdir/$dir_name/" + if [[ "$md_id" == "lr-mame2003-plus" ]]; then + cp "$md_inst/metadata/artwork/"* "$biosdir/$dir_name/artwork/" + fi + } +""", 19) + +MAME2003_PLUS = module("lr-mame2003-plus", """ + function _get_dir_name_lr-mame2003-plus() { + echo "mame2003-plus" + } + + function configure_lr-mame2003-plus() { + configure_lr-mame2003 + } +""", 19) + + +class LinksAndCopies(unittest.TestCase): + def test_px68k_links_only_its_five_names(self): + found = records({f"{EMULATORS}/px68k.sh": PX68K}, "px68k") + links = next(r for r in found if r["kind"] == "links") + self.assertEqual( + links["names"], + ["cgrom.dat", "iplrom30.dat", "iplromco.dat", "iplrom.dat", "iplromxv.dat"], + ) + self.assertNotIn("cgrom30.dat", links["names"]) + self.assertEqual(links["search_dir"], "$biosdir/keropi") + self.assertEqual(links["passes_to"], "$md_conf_root/x68000/") + self.assertEqual(links["source_ref"], f"{EMULATORS}/px68k.sh:58") + + def test_px68k_moves_a_root_copy_first(self): + found = records({f"{EMULATORS}/px68k.sh": PX68K}, "px68k") + moves = next(r for r in found if r["kind"] == "moves") + self.assertEqual((moves["search_dir"], moves["passes_to"]), ("$biosdir", "$biosdir/keropi")) + self.assertEqual(moves["depends_on_option"], '[[ -f "$biosdir/$bios" ]]') + self.assertEqual(moves["source_ref"], f"{EMULATORS}/px68k.sh:56") + + def test_redream_renames_both_files(self): + found = records({f"{EMULATORS}/redream.sh": REDREAM}, "redream") + links = next(r for r in found if r["kind"] == "links") + self.assertEqual(links["names"], ["dc_boot.bin", "dc_flash.bin"]) + self.assertEqual(links["passes_to"], "$md_inst/boot.bin, $md_inst/flash.bin") + self.assertEqual(links["source_ref"], f"{EMULATORS}/redream.sh:58-59") + + def test_a_copy_kept_only_for_the_package_the_test_names(self): + files = { + f"{LIBRETRO}/lr-mame2003.sh": MAME2003, + f"{LIBRETRO}/lr-mame2003-plus.sh": MAME2003_PLUS, + } + base = [r for r in records(files, "lr-mame2003") if r["kind"] == "copies"] + plus = [r for r in records(files, "lr-mame2003-plus") if r["kind"] == "copies"] + self.assertEqual([r["passes_to"] for r in base], ["$biosdir/mame2003"]) + self.assertEqual( + [r["passes_to"] for r in plus], + ["$biosdir/mame2003-plus", "$biosdir/mame2003-plus/artwork"], + ) + self.assertEqual(base[0]["names"], ["hiscore.dat", "cheat.dat"]) + + +class CommandLines(unittest.TestCase): + def test_sdltrs_passes_one_rom_per_machine(self): + found = records({f"{EMULATORS}/sdltrs.sh": SDLTRS}, "sdltrs") + found = [r for r in found if r["kind"] == "fixed_name"] + self.assertEqual( + [(r["emulator"], r["names"], r["passes_to"]) for r in found], + [ + ("sdltrs-model1", ["level2.rom"], "command line -romfile"), + ("sdltrs-model3", ["level3.rom"], "command line -romfile3"), + ("sdltrs-model4", ["level4.rom"], "command line -romfile3"), + ("sdltrs-model4p", ["level4p.rom"], "command line -romfile4p"), + ], + ) + self.assertEqual(found[2]["source_ref"], f"{EMULATORS}/sdltrs.sh:51") + + def test_a_bios_read_outside_the_bios_folder(self): + files = {f"{EMULATORS}/basilisk.sh": BASILISK, f"{EMULATORS}/gngeopi.sh": GNGEOPI} + rom = next(r for r in records(files, "basilisk") if r["kind"] == "fixed_name") + self.assertEqual((rom["names"], rom["search_dir"]), (["mac.rom"], "$romdir/macintosh")) + bios = next(r for r in records(files, "gngeopi") if r["kind"] == "passes_path") + self.assertEqual(bios["search_dir"], "$md_inst/neogeobios") + self.assertEqual(bios["source_ref"], f"{EMULATORS}/gngeopi.sh:60-61") + + def test_a_flag_dropped_from_the_command_raises(self): + files = { + f"{EMULATORS}/basilisk.sh": BASILISK.replace("--rom ", "--romfile "), + f"{EMULATORS}/gngeopi.sh": GNGEOPI, + } + with self.assertRaises(rl.LauncherPatternMissing): + rl.extract_launchers(files) + + +class LaunchScripts(unittest.TestCase): + def test_fs_uae_refuses_to_start_without_kick13(self): + files = {f"{EMULATORS}/fs-uae.sh": FS_UAE, f"{EMULATORS}/fs-uae/fs-uae.sh": FS_UAE_LAUNCHER} + check = next(r for r in records(files, "fs-uae") if r["kind"] == "fixed_name") + self.assertEqual(check["names"], ["kick13.rom"]) + self.assertEqual(check["search_dir"], "$HOME/RetroPie/BIOS") + self.assertEqual(check["passes_to"], "command line --kickstart_file") + message = check["fails_when_missing"] + self.assertTrue(message.startswith("You need to copy the Amiga kickstart")) + self.assertEqual(check["source_ref"], f"{EMULATORS}/fs-uae/fs-uae.sh:23-26, 41") + + def test_a_launch_script_without_a_check_raises(self): + script = FS_UAE_LAUNCHER.replace("exit 1", "true") + files = {f"{EMULATORS}/fs-uae.sh": FS_UAE, f"{EMULATORS}/fs-uae/fs-uae.sh": script} + with self.assertRaises(rl.LauncherPatternMissing): + records(files) + + +class Packages(unittest.TestCase): + def test_the_package_names_what_it_builds_and_registers(self): + found = records({f"{EMULATORS}/px68k.sh": PX68K}, "px68k") + package = next(r for r in found if r["kind"] == "package") + self.assertEqual(package["repo"], "git https://github.com/TurtleBazooka/px68k.git master") + self.assertEqual(package["systems"], ["x68000"]) + self.assertEqual(package["source_ref"], f"{EMULATORS}/px68k.sh:12, 15, 62") + + def test_a_package_inherits_the_systems_of_the_function_it_runs(self): + files = {f"{EMULATORS}/dosbox.sh": DOSBOX, f"{EMULATORS}/dosbox-sdl2.sh": DOSBOX_SDL2} + package = next(r for r in records(files, "dosbox-sdl2") if r["kind"] == "package") + self.assertEqual(package["systems"], ["pc"]) + self.assertIn(f"{EMULATORS}/dosbox.sh:68", package["source_ref"]) + + def test_systems_from_a_multi_line_array(self): + found = records({f"{LIBRETRO}/lr-fbneo.sh": FBNEO}, "lr-fbneo") + package = next(r for r in found if r["kind"] == "package") + self.assertEqual(package["systems"], ["arcade", "neogeo", "pcengine"]) + self.assertEqual(package["build"], "libretro") + + def test_a_system_name_left_unresolved_raises(self): + broken = FBNEO.replace('"${systems[@]}"', '"${others[@]}"') + with self.assertRaises(rl.LauncherPatternMissing): + records({f"{LIBRETRO}/lr-fbneo.sh": broken}) + + +class UnknownConstructs(unittest.TestCase): + def test_an_unclassified_use_of_the_bios_folder_raises(self): + broken = REDREAM.replace('mkUserDir "$biosdir/dc"', 'rsync -a "$biosdir/dc" "$md_inst"') + with self.assertRaises(rl.LauncherPatternMissing): + records({f"{EMULATORS}/redream.sh": broken}) + + def test_scripts_without_a_package_raise(self): + with self.assertRaises(rl.LauncherPatternMissing): + rl.Scripts({f"{EMULATORS}/redream.sh": "function x() {\n}\n"}) + + +class PlatformRecords(unittest.TestCase): + """The launchers platforms/retropie.yml carries, as the scraper wrote them.""" + + @classmethod + def setUpClass(cls) -> None: + cls.config = yaml.safe_load((REPO_ROOT / "platforms" / "retropie.yml").read_text()) + cls.schema = json.loads((REPO_ROOT / "schemas" / "platform.schema.json").read_text()) + + def test_one_package_record_per_core(self): + packages = [r["package"] for r in self.config["launchers"] if r["kind"] == "package"] + self.assertEqual(len(packages), len(set(packages))) + stripped = {p.removeprefix("lr-") for p in packages} + self.assertEqual(stripped, set(self.config["cores"])) + + def test_every_record_belongs_to_a_package(self): + packages = {r["package"] for r in self.config["launchers"] if r["kind"] == "package"} + for record in self.config["launchers"]: + self.assertIn(record["package"], packages, record) + self.assertTrue(record["source_ref"].startswith("scriptmodules/"), record) + + def test_the_standalone_builds_name_their_own_project(self): + repos = { + r["package"]: r.get("repo") for r in self.config["launchers"] if r["kind"] == "package" + } + self.assertEqual(repos["minivmac"], "git https://github.com/minivmac/minivmac.git master") + self.assertEqual(repos["quasi88"], "git https://github.com/winterheart/quasi88.git master") + self.assertEqual(repos["px68k"], "git https://github.com/TurtleBazooka/px68k.git master") + + def test_the_schema_describes_every_scraper_field(self): + fields = { + f.name for cls in (batocera_launchers.Launcher, rl.Launcher) + for f in dataclasses.fields(cls) + } - {"lines"} + self.assertEqual(fields, set(self.schema["$defs"]["launcher"]["properties"])) + + +if __name__ == "__main__": + unittest.main() diff --git a/wiki/adding-a-platform.md b/wiki/adding-a-platform.md index 13ee2c3a..c7b79e20 100644 --- a/wiki/adding-a-platform.md +++ b/wiki/adding-a-platform.md @@ -224,7 +224,10 @@ launchers: |-------|---------| | `emulator` | Emulator or core as the platform names it | | `build` | `standalone` or `libretro` | -| `kind` | `names_searched` (tried in order, first found wins), `fixed_name` (one path per name), `core_option` (an option value names the file), `passes_path`, `links`, `copies`, `scans_dir` | +| `kind` | `names_searched` (tried in order, first found wins), `fixed_name` (one path per name), `core_option` (an option value names the file), `passes_path`, `links`, `copies`, `moves` (a file left in one folder is moved to the one the launcher links from), `scans_dir`, `package` (no file: what a package builds and registers) | +| `package` | The platform package whose script the record comes from (RetroPie's `rp_module_id`) | +| `repo` | What the package fetches and builds, as the script writes it (`rp_module_repo`: method, URL, branch or commit) | +| `systems` | Systems the package registers, under the platform's names (`addSystem`, `addPort` for ports) | | `slot` | The key the code files the list under: a region, a machine | | `names` | In the order the code tries or writes them, relative to `search_dir` | | `expands` | Values a `{X}` placeholder in `names` takes, in the order tried (Hatari tries each TOS in ten languages) | @@ -265,6 +268,21 @@ reads it from there. `emulator: libretro` stands for every core Recalbox runs, for the default directory and for the per-system overrides applied after the per-core choice, and `` in `search_dir` is the system's own name. +Shell platforms are read as text. RetroPie's scriptmodules are walked the way +RetroPie runs them, one shell for every package: local assignments, arrays, +`for` loops, brace expansion, `$md_id` and calls into another package's +functions (`dosbox-sdl2` runs `configure_dosbox`). Paths keep the variables +the scripts write, `$biosdir` being `~/RetroPie/BIOS` (`retropie_packages.sh:48-49`). +Each package also gets one `kind: package` record, and that record is what +maps a package to the profile of the build it compiles: `repo` names the +project (`minivmac` builds github.com/minivmac/minivmac, Mini vMac 37, not the +libretro port), so the mapping never rests on stripping `lr-` from a name. +RetroDECK's records come from each component's `component_prepare.sh`, +`component_launcher.sh` and `component_functions.sh`, and from the presets +they copy, with `$bios_path` as the framework names it. In both, every line +that names the BIOS directory must match a known construct, else the scrape +stops with `LauncherPatternMissing`. + ### Inheritance If the new platform inherits from an existing one (e.g. Lakka inherits RetroArch),