diff --git a/platforms/_core_info.json b/platforms/_core_info.json new file mode 100644 index 00000000..5bfe1431 --- /dev/null +++ b/platforms/_core_info.json @@ -0,0 +1,331 @@ +{ + "repository": "https://github.com/libretro/libretro-core-info", + "blobs": { + "00_example": "68a87f20d197cfb075dc744b911c354f4ee9c7e3", + "2048": "df66c7f6b23da5b6d7df6ec38ecdded2ea785225", + "3dengine": "f93e2625d5445c4e0319088f4fbacd693a9bf5a6", + "81": "4e0c43e15f0bdc299b2d706a1d496505a8c95ba1", + "DoubleCherryGB": "aedcc6d5a2fbd4df97ce391daab8019134b51384", + "FreeIntvTSOverlay": "469592af9ebe2239b3665218abde6e39d1a9424d", + "a5200": "89680e62646b7a9e1ba04135063cd6e6033d13f9", + "advanced_tests": "a13ebba9e3d4b1f70f882d824268152026ff184a", + "amiarcadia": "73e48e85824950f30df26673219cd5ca4548496a", + "amiberry": "e5d1f0f9a143594d893031caed9aa760ff34ce0a", + "anarch": "f06701967498ab0a5dfc0c7ca50c3aeea6c9e6e6", + "applewin": "c999c4b73ff48409acecb0239214c74f3464bcd1", + "ardens": "938877e6a867441fbab2edfd19acc3d85f4b0277", + "arduous": "cb6f0917fa4454126fdb93714eadb6d6cfab1a9f", + "armsx2": "c8a763b3d75e84997218323350a22cc79fe8e39a", + "atari800": "07b87e91cf4577db7791188399f1cc1f320932f0", + "azahar": "1173e2e8a919d578cc589545cb3c0c71dc4e1188", + "b2": "140b31e2d829f094fbf81856f63acd8f3c97f9e8", + "bbkemu": "ee36e46bfcff3ec6f66da3e35bc249d398d962ca", + "beetle_saturn": "d0364ee2ba9f0ba1e676dcf397cc66aad5204f8d", + "bennugd": "620191828ed5ac08426aa132a7e15dabfe78b702", + "bk": "7025d150c3265eaaabf8c1863a7fe367402f2dc1", + "blastem": "0850a1ce3c92ed115ea42d7df89741c26e46907a", + "bluemsx": "8ea8ac764e50f2618e4936dcf7d8dc43952488c1", + "bnes": "fcd6e352d4949a876014c516d9afc86fd25ae92c", + "boom3": "f7c3290aa476e2fa724b97974713bdfb9d9594d9", + "boytacean": "88da1bdd694a20ed1e3065cab07fe40205cedd9a", + "bsnes": "e414e247241ad1578c7c500b6009d0d9f3793900", + "bsnes-jg": "ea6966241dede9af48e3719478e41f0f8e3af565", + "bsnes2014_accuracy": "f4eb380fb2d70883b6bac33a7f8d6a8fb5a14ef2", + "bsnes2014_balanced": "ac390a8a0c6e6f095f55ce5806f55f02cd599937", + "bsnes2014_performance": "c733738d8b87b75def115381b066271df424affd", + "bsnes_cplusplus98": "f41a72cbba0287cd2d77d0f6d3344fc388b0f4eb", + "bsnes_hd_beta": "587c7282de1309894e49d7e90a6ea646cebf859f", + "bsnes_mercury_accuracy": "ac0794b5c57ab507326f9024ee2a1fd8b4d7667c", + "bsnes_mercury_balanced": "311b1630f18ab748901c5ee1a5a78b1424ba76e9", + "bsnes_mercury_performance": "82478bc1d89f8c09192461ef63119e3c7de33644", + "cannonball": "63d5881e7b6f64c4e320d937d90aec90783325f6", + "cap32": "6c814e8a1bfe4ec17ab4d36a24e6bbc919accf2e", + "cdi2015": "383f3b1388d2181e9af2f147e8c42e156b1ef3ae", + "cemu": "ab3e19d6975762f03a17e6602f504915622e7416", + "chailove": "79e1ee7b89725e4cba1334101b7cd1cae5d3f4f0", + "chimerasnes": "c038f874a3fc5ba64313063a7354f79438edbf61", + "citra": "e5d3b56989a82db718ee1d840571be9f1cc50b37", + "citra2018": "d306c4e2cb65cf83930ba4b5f131a61077a17a78", + "citra_canary": "0b1fd85442193d317370fb5410293366b1595c6c", + "clownmdemu": "00482d6fe4127fcd9fc59df68a0c9b5475c06c9e", + "craft": "e6fa30b75f892dfce039765b1b842e1f970ab038", + "crocods": "e3510a13cf2b285745a467c28ed3bb521f7fe936", + "cruzes": "d5bea3f63b4ad964fc5dc98bca37ce083f9732c1", + "daphne": "2d9268f2857ffbb826faba53a8dab973a2d8e2ff", + "desmume": "b176acacbbbec9d1924cd452fbf749e2515d61d9", + "desmume2015": "c3c14e4185b97115f9fe36ba2efa4f62f8742fec", + "dice": "2f1a4407867e03bb4f1e3a4590b318037ef6b709", + "dingooemu": "cd176c4ababe6feb9f27124a323564e4a13b3950", + "dinothawr": "ec1748f05742ce35cbd084b78785214e7d6a7cc8", + "directxbox": "a22c5e753b66a08aa98529c8145d1a4ccd328a21", + "dirksimple": "9754af3cff83a269fb29d17659bb6770e3b3f536", + "dolphin": "8ab1934d2c309f738f69ef603be9bebacd5fa545", + "dolphin_launcher": "6af4403328719b1af674e34fcb3aabfee1d6dd29", + "dosbox": "b9979165292ec0a4aa9fc0bece5887aeb195112e", + "dosbox_core": "5634e336ccefa587960bf6099ecb247abb879db1", + "dosbox_pure": "2afbf74996a013507f6fcb76a2ed40ca82eddb80", + "dosbox_svn": "e21a8e0ec4912ae4efb203a68231dceaf82b73b5", + "dosbox_svn_ce": "8f06959e2c24f023174e9eeeef7b5818a5cf0045", + "doukutsu_rs": "6e40973b911b81ce799156cec69af0f716e8b0e8", + "duckstation": "7113d3c62a314cc6da7ef3bc12efec29f415ed6b", + "easyrpg": "d057e86ecc3482bc41dd88e5af75a59dea3360c6", + "ecwolf": "514cca6aa6df9f5552e9119d6173d3ff0d4e1a4a", + "eka2l1": "b6a0192caf919ef988bef44653153eb4815b3852", + "emucv": "1cf170a6eea802ed5f58d51482b06098f20ee7d6", + "emuscv": "37ca60ffca2affc6e2a264184cf16b64a5a9d1d1", + "emux_chip8": "76b0e06041b05ebbf723b101c04e0016729919cc", + "emux_gb": "ea951760e5ade5fb20dc4ca56f12e36bfd0a65fd", + "emux_nes": "043810ea5c9b3dcd4e82df1427c504331d3fc297", + "emux_sms": "8492133ac9cfdc6b765c506b9e549d83368b42da", + "ep128emu_core": "c6689eeb5b484e2e420073376f7956b01f4f9be0", + "eternal": "85267764b219d487ccb1ea77818bd535cde84911", + "fake08": "4e47454003da665a00094ed49e824aa902875a04", + "fbalpha2012": "593194b6f89ace127a52961a7a9c0cc251478d07", + "fbalpha2012_cps1": "1dd842a35fec91794f2ced1abc3fb5444c81c4cb", + "fbalpha2012_cps2": "676a6acae6f1c0f93b402b2cd22bfc7ef4132e12", + "fbalpha2012_cps3": "acf3699e74516c40ebb353ce7b73a78b2ba0c241", + "fbalpha2012_neogeo": "8002b6464d1ec6937ed57ba23191bb0b18272c3c", + "fbneo": "b34cff43b57cab0db469b2fa9c919ef43a48272c", + "fbneo_cps12": "b21e20af0b0d8d0c37945189a953b3a3791701ac", + "fbneo_neogeo": "c1ce3daa0c022a1c63eb3470a95f08c10eb2ae3d", + "fceumm": "84881bc01ed03bdcb2d47f89ab88c09296feb0d4", + "ffmpeg": "653c039661e9c564bce6b6325e5cc956296cf096", + "fixgb": "3335f3fee37e1843fc8060a7d58317a7fb61efef", + "fixnes": "1b1e191debbda3b45f51b20a2819a477fc7407cb", + "flycast": "47894ac43adc8876a630a69848e755cc34b7ad68", + "flycast_gles2": "7699704ac889ac17c6d0953b5518d3f0bfa4a6c5", + "fmsx": "2ba0cdc82c92a1625723e818b14fdf450ae532e1", + "freechaf": "43b80752c21ca2c26b610e5890a5d8edf08d8c45", + "freeintv": "40d3bc28c03ea0c83ebe8c907aa6f61d9547f063", + "freej2me": "690600ece3290683db35eef9c753f368e3ad6c2e", + "freej2me_plus": "1437a0bc7f9aa6fcb5a1e7b07aafe046eb3d76bd", + "frodo": "00b434e120ef8488ed82a30c01c488cc697ba091", + "fsuae": "ccbbfc85cedc9b7ab0f30702584d8b8114437f39", + "fuse": "2c53a6834974fe1d7c3e3467f57f3c7b9347eb8e", + "galaksija": "f27a232f8ae2ac12bae8436ed8fd220b745e8264", + "gam4980": "3d757498a3c9fa728c9df1ee18dd88faf73432fa", + "gambatte": "fc1e4e3b8f0ae047fab73ab516c5a0276370303d", + "gearboy": "670b1b90974ab6487b792fbeeddf5736afa4318f", + "gearcoleco": "2126bdabe8d1d8bb7d6dbcf3d1956502777bbc49", + "geargrafx": "79fe02a2840a276d1c834e31910ec91b3d9aa8b0", + "gearlynx": "624951f9e137ad27af7eabbf02550bc615a78dd2", + "gearsystem": "90d34a245aa2b6ac69a23a9af7952043f5d34425", + "genesis_plus_gx": "ae18384f5f4ba3e8417d430419d5fb4c1da02349", + "genesis_plus_gx_wide": "7a0deff1895e84f7475928814cdcdc9795471405", + "geolith": "e130b2796ea18dcce8cb8dcc6e35361d7c4c1682", + "gme": "285c70e52192a80a36b8bcb2f50538a8b8df3a5c", + "gong": "299c72ad78ab8c2498640c6eead875651e7072df", + "gpsp": "df4023b3909c82118427cac75699529f18904068", + "gw": "de42ed9ebe4ffe4f55d25e8523880f2c7c517ca0", + "handy": "e9f0c36320a31642202201bce0031f8a73c5a49e", + "hatari": "7641a27200948c97d046b7e0d559401894cc24ae", + "hatari2014": "54fde5cfffa09ec45d7a27a9b37978b7742677c2", + "hatarib": "9b2901327080b1c81406ba053dc1887fece953f3", + "hbmame": "54c043535e2635e936a8ac20912ab125394adf89", + "higan_sfc": "9bdcf2d0e92f0e9509b0bd91872c84c3562b9040", + "holani": "ec099eecd2d31c2c9355ca0f2b057c877d75e58a", + "imageviewer": "5eeb8e208aed6bec71427f6d6ac6bc9c93bb3365", + "irogb": "fd57733234d7219ff1758464406d5c67201b8c4e", + "ishiiruka": "d8c8c6c016451cb7c0d340eb51f150bf6f0983b3", + "jaxe": "5bb4cd5077edf0fce90a51116130894612460d2e", + "jollycv": "598b90e899a7d7d46f555c77c89c3a888d8eafb9", + "jumpnbump": "ed1a11061c6c53045f3b0d8c10128f719d5ea113", + "kronos": "e9711a1019be483c0d994ad1f3109e5ab06d0f2d", + "lowresnx": "93b3bc6c1d6204449a63b5c3d665c1cf230f0158", + "lutro": "7a5e1ba0d29c909b24f4da77296e0b794323fddd", + "m2000": "5a93b6679ed203a68db5cd8478a2fdfd03c86bf0", + "mame": "ae3a33aec0981c37c8caa63a7d8c86cbccbbc11c", + "mame2000": "326d7666692086df51e77f6ec89438872604ed18", + "mame2003": "f3ed8c023d555151e4d2cfce389ffdd2e50dab6e", + "mame2003_midway": "aa36dcb2e9295ff7d39a1c44fd641ab127c8d5d0", + "mame2003_plus": "07d5ae3f3857d574a19a67a4feb5e382bd419f79", + "mame2009": "1b673833aca392291e9643b24cda35539e2f7273", + "mame2010": "8f6b8d900859ce2f7f01bff1be5c60946076b829", + "mame2015": "8abad707dd5c0206eb6f0889adb9b46128ea0975", + "mame2016": "6231bcc43590a3adc36fa4c14ddefe4d373fa440", + "mamearcade": "86f27948d45ed51bf9c6d523ebc1d63d5d92e840", + "mamemess": "77add36a71f40fd7bfb2cd3ba5664520346805fe", + "mcsoftserve": "3afd94c19a09208f3871b1045dc72d552627d11c", + "mednafen_gba": "786e4c6b87cab0b1307d42eae3eb622b23af9e38", + "mednafen_lynx": "37bb123616c246a94947778a8657eca319681f0b", + "mednafen_ngp": "bed26ff8cd9af0808d002ad5cd5e7fd54f88cf68", + "mednafen_pce": "857686ae3294ca1a963631a666261f4b8d085f2b", + "mednafen_pce_fast": "5ad7408d4a1b695f5f1c3a45a84484d3217c758d", + "mednafen_pcfx": "3b8f3cbd6d4f08459b4678b9cadc1f8ddc6b4d9a", + "mednafen_psx": "be7cbe483f0aa3b5dffafec0834e6295e7c4b594", + "mednafen_psx_hw": "865be67008dbe11c2d42f61297ca1e73fb305383", + "mednafen_saturn": "ecc7bcf61bc670aacc964a70a7e7d60c5c931424", + "mednafen_snes": "388cb94ba0e16c6306abd092f82494c72e6c2696", + "mednafen_supafaust": "7eec8261629ac0ac438f1cf6a5109db993aa132f", + "mednafen_supergrafx": "decbd8567766a7b39d7ceed042e46bb2d5180916", + "mednafen_vb": "0d3399122790f3e72d25abaab995622474e720e2", + "mednafen_wswan": "24cf8e85a0d027d464afd71612bbdc2a1aa86c65", + "melonds": "ba1e3762404c290082ca202183704e3c711bb49c", + "melondsds": "82c511d23dfa7b8a3f3bb43b38c6598cd835740b", + "mesen": "82871f69374e2e9a4e8ac52009bed1a9c26a3c94", + "mesen-s": "e9d19eb873e5d1dc8c65f409c7603413f5c99a32", + "mesen2": "cb556adf4cca53da9d7bad80fc63cc92fb37bf34", + "mess2015": "b9260d933fae4b78c34c45ed1b3e6f12cddae7d5", + "meteor": "871d3b256cff96544ee8866e860c5f5afb293ef1", + "mgba": "90e1425af4bf9b1cfcef189d51b596e19c793ffd", + "minivmac": "224fc445e6ffaa2b1ec2805fd5a8bf54daadc273", + "mkxp-z": "a5a54cb7c2001afe6fcdd9a782584a3ee8f020df", + "mojozork": "131fd6fe964349afd49b77a3d1b7e3712ad7aca9", + "moonlight": "c85e0fd4e9a9296840b3a8005b94fd80a289ba37", + "mpv": "a611b24c7b920d70d3512cc9080d1edeec92f31e", + "mrboom": "00144a62ac4606bf3fb5c8f81a01459b25a57471", + "mu": "399f56a82a4810c9779b788771d349b4853e9d42", + "mupen64plus_next": "e1fb9671b409bb51eda8a149862629a0b9b3dc35", + "mupen64plus_next_develop": "3e39838b6f2893f515ea5ffbea13c6c481400cd3", + "mupen64plus_next_gles2": "7244f0c0eae4b58fa4614f6e821bd1ff76d9ae8c", + "mupen64plus_next_gles3": "888e3863516ae1ad7795b3c8615aa635551dd7fc", + "native32emu": "c8b84e368952bea94f0710fbf9f6b5559bd6b5ba", + "nekop2": "53b91335b9daf398a84757a2b777c5de87cac906", + "neocd": "0aae4e07e8ed9b02fbe8a60abe29c1e3484171c1", + "nes": "0fbb75c08c902ca7b92d43504caf428235861138", + "nestopia": "26fd40b1b9aa3403df5cf6761e4f3759235d2c55", + "nicaiemu": "73472736288c7fb9ca98a711faabdfaa4f28153b", + "noods": "14e06a6c4a191fbfaf34b1770bff9ed6588c5ada", + "np2kai": "c23d1e3b202102da7102e5f693a309079102d64b", + "nside_sfc_balanced": "999c0e4741eef4b2791b8415f7d8cd39de926c33", + "nuance": "da298e6f6f087ba3121489556970118ea6056522", + "numero": "ccdad6bca3a9f6698372db09cadbf36fe4eb4ed1", + "nxengine": "e49b16e3ec843757de41d32a070f0b89fd15cdab", + "o2em": "46784954fb8b851ea6a6a6257200682d62686947", + "oberon": "ceabfa3830324b751b965be51e527bcd2bbeb471", + "omicron": "6737820370170e5602f1b932bb9ffdc7fbca86ed", + "onscripter": "96105396ccb990a5d0ca2d7fcbe832701a58f3f2", + "onsyuri": "45f2acc5c2060ad23904a0bc2ccda43918391f3e", + "openlara": "7c4a8cacd891a65038c46da00e110d951de95f71", + "opentyrian": "5f3bae87cddae1c5cb5f51cef3ea43e3a45c0a2b", + "opera": "d8447c579efd7425edc06b6e03697abfeebee062", + "panda3ds": "f95daaa5e6e68dabe71e825655f09a7e3c7b17fd", + "parallel_n64": "320b88d1032d3caa5ae3b39469dacc005ccae59b", + "parallel_n64_debug": "96611a7235f47b06075d237ef8e5d33207d195a2", + "pascal_pong": "a1810d465843e18701c208c9ec2a92d783195fe3", + "pcee2": "d2d27eff25a2135155dce50aa4cd75255887aec1", + "pcem": "66a67eb4428d34d796fa1d2f6a6546ed8d4fa26a", + "pcsx1": "0726d1eebfb99cdf672c1424d1a8a0690bf6dfe2", + "pcsx2": "a00056b019ba696ee75fcd11d4fec0a9085c4b89", + "pcsx_rearmed": "33df7832b10c5253967ca18c63149d6c7dfc743b", + "pcsx_rearmed_interpreter": "14cc4bb82765c2c5c96074d5b117922178590499", + "pcsx_rearmed_neon": "6d374259a34c88735a502d1d2de18e7fc95e990f", + "pd777": "d7ab7e6e9c9755a62d4cde072fc4b8460da64594", + "picodrive": "9e539d30e23a7ee469a6780500fb1400de00c976", + "piece": "0fbc5df982831b9ac3b2e327c41f4d68d42c3620", + "play": "b91e6d04d33a86694d1e14ed8f3cddd962805f33", + "pocketcdg": "9a7a9606dfc265ced4e6b8d0356b245bff076fc2", + "pokemini": "07cabab917a3b8040d80538b843de778f006820e", + "pokketstation": "90f40d6c9c3dc0dd347db21afa07d47c1407f032", + "potator": "8a05b453d812a73f016b868340e4463890d60b95", + "ppsspp": "5037b12f2cb253a439532c99e30f8df36afe394c", + "prboom": "0566bbfddd39bd187fbbacdc82bedc2e2744e471", + "prosystem": "040018e58b3fbbff26aaa45476212ffdc4e13668", + "puae": "59fa936dff0fe1329c6f71925bddadb99b15c9fa", + "puae2021": "97c86e42fe956830e1a3e4539ed4b2ada04f6908", + "puzzlescript": "f53511e49d7e193c99de1293893f2c29c178400c", + "px68k": "9421920a2234919334a160ae57548adac0c83065", + "qemu": "7928c363b7a7d5a7c865d5daac7d088980be3ab7", + "quasi88": "431e0b3da4b4930b7eb16d139202934357867cf8", + "quicknes": "8fcfcf350a9122d30c51c096f3fd13457fa3b517", + "race": "048634385705b2bf33b299abd2c43a7db45a0abe", + "radio": "878d659f05691ceaddeb7bf60054cb8018416ba7", + "redbook": "e095305bd14d068068d93db1d056e01dd72e946b", + "reminiscence": "535c6a79c5639d80039eb5519cfa37a08b81e88b", + "remotejoy": "fc0d8dfd3d4a21e675cdde0de25e2b6db962aebd", + "retro8": "87cc2d79300807ba11f259e27f9101133f8079d6", + "retrodream": "0544849053aa85007b3a4a4162501fa8ad259d9a", + "romcleaner": "6c9181472df165dab7449100f01cf6def1d9d707", + "rp6502": "128440e0c79671b0bdd13bad6b04f05ccd12492f", + "rustation": "01fdab0903e30a19a0ca299fc15b8aa241843417", + "rustynes": "c231a5836ff48970ada68f39cb002ebba190dbb8", + "rvvm": "5fe5334df5112ff14bee0009f2de55656fb815a4", + "same_cdi": "2bc8421aef357ccb70d320a113045b1bc2f8aff1", + "sameboy": "900d258764ec864fdae7b33d26ccb1f261023193", + "sameduck": "7625ddea334c4f1747b10e3ab92459ee2a3b05d7", + "scummvm": "17d120c360629463b535c6c872ec7d4faf94fd1c", + "sdlpal": "66b1f82a9de6ebc8d924ff82d4b37951d6fcc5f9", + "simcp": "7bf05971cd0545aa22e9145547d30c2cbda19b08", + "skyemu": "1d82dca4afeab74bed4be85445b1538b9bf28a70", + "smsplus": "ea86bf40b6ce50c84dd9dc0905972f1c2a6e2222", + "snes9x": "aad2e41f7a6f9663bf93e080f9b75068c204dcb3", + "snes9x2002": "1535b62e6098a7c8f3890f2687bae215a4268900", + "snes9x2005": "93ec3600e80213fcaf26168c8837d264c6a64267", + "snes9x2005_plus": "b7436a7e01fa83ddd57c8c5d7fa573b5a45af597", + "snes9x2010": "a6eecb552435a0dc6a54883f7bb41263268111fc", + "spmp8000emu": "a7f2dd6a74ef2c3c511e7127ebc5c3e95c9a130a", + "squirreljme": "7f276aa61baab33b72452f6a693168be5ecf1285", + "stella": "5cdf4139790033096241f62d56cb2c53da32715e", + "stella2014": "508af340a5913b19b0e645d81bef2870364db91c", + "stella2023": "abf54de5705fdb4df7d12f7db7952edb63c24e27", + "stonesoup": "b624f68bc05611fac7e646b63dbe335fc83062ec", + "superbroswar": "8a4f806684cba1237a398e3a65ce297656aed642", + "supermodel": "1aafc1cc70d192108835666be46a7e1eb8974352", + "swanstation": "ab8a9d1a14ae6d7ce33a38ab0294b8ac55018745", + "syobonaction": "4c632b15e8931e8c3cea5b760e971f67a33cac57", + "tamalibretro": "acb163b7c45456fd0e880bd32ce9d75690299000", + "tempgba": "3cdeb907e9a14694cf74b4611395d9dd478cb3b5", + "test": "f85524c6b3b569b5acc16980e3df5246b6748043", + "test_netplay": "2e7efd155452a5d3c45fc947b0d8eddcba4a1b0b", + "testaudio_callback": "10be60661a53052d41bef0316b302b6439b8ab90", + "testaudio_no_callback": "8e4b54a4570c6c960200235391854b608234596f", + "testaudio_playback_wav": "42d6ccc92c644a79f25ac1c09c6fdaaffa382aef", + "testgl": "1d10d7a086c26abb669b6cc3d2d3a19334ddda02", + "testgl_compute_shaders": "2b90f8841c367ab9c38bb841ea82942d30dd8cf9", + "testgl_ff": "59f2bb4c129aca7dc26a28e4fd0ce90b4a892371", + "testinput_buttontest": "eb08c91990fa1af920d357aa01a735f1e597757b", + "testretroluxury": "029dae162931a067d8340dfa62f8ae5fe48dc1ae", + "testsw": "f17e8892effda5f94b44cc3be49063279d4727bf", + "testsw_vram": "07258f7b36225cc23bec5c248d6de327fd38a7dc", + "testvulkan": "7b6e9a630201cc3303223f8f907e54546e75a93b", + "testvulkan_async_compute": "5bab2d38b89555ef0dd2659b6fcc57208f1c2f30", + "tgbdual": "db1f5af20a973dd2ad28ac3a4e235ee5073be46b", + "theodore": "7829b8f95b223baa5fde439a40105143636183f5", + "thepowdertoy": "e54f44c6c8bd8507932fa05714c1691cebbea9e1", + "tia": "e9604c40852f8a02b0ea3ed487810d0071ccc6b9", + "tic80": "4c07f9a66921648a01e492580e6415a241c4a277", + "trident": "d3ca42ffb218faf3e96c231f13abd4f42926ec7d", + "tyrquake": "2b492b43b6bdcce3f62b7ccb06f81b68e5802e0d", + "uae4arm": "4609b8172db67dbc9b2c5a6e9c10287f4b07e867", + "ume2015": "cc668cd200e31492ac09f6b7f3e77e338f8f10aa", + "uw8": "c920638e44627f5ea9fb5a66cd05b925d3fa7744", + "uxn": "ae7f7069dd14125875d1474c97eba70c916e3b99", + "uzem": "e3cec8c8a0ccee9fba3884a80c8a3c909d513355", + "vaporspec": "390f79a6b346d6aa32afb5f5e6356b079a05578b", + "vba_next": "edbdb88f64a85755f2085f2cb80d232429f4848b", + "vbam": "a6a4751eb8e9048595a161ffeb78106334c9b18b", + "vecx": "c1126410f4d0d9abbb8b2b879eed9195613b19e3", + "vemulator": "4a16b56827e312a454c488129a96a55760956a8c", + "vice_x128": "ed36f29cea1b2f078b5a395e8ea3c8385f8c4156", + "vice_x64": "5f6626bd3a5f4960d6cc5b3ad7639e62ff3f2065", + "vice_x64dtv": "f51980a6b237b549d69bec751c4e3abe248b006f", + "vice_x64sc": "09c7aea1cb6740ba7e57993bd0fcf27f99a8eaf3", + "vice_xcbm2": "c8eb7f84bf9e377c75831b903990b8af18662391", + "vice_xcbm5x0": "8a1e1a78ef2546c58d8545eff2d3f41a2ec5b27c", + "vice_xpet": "2251efb6f5b029e0112dd255e2d691046a903363", + "vice_xplus4": "4b46c2f951c2f402cf0ff8c56160b7bfb4460d54", + "vice_xscpu64": "4dcef239dd83be5a33ede64a2070adf9a211ef72", + "vice_xvic": "33f3689b881367a2400cdead1d7b542a311b4dc2", + "video_processor": "5bdc74ff749976a560a534af0d06277153a5c206", + "vidtest": "4d8fe9a3f3033d06b5ec8ac28327965dcf951f0b", + "vircon32": "66d770352a9a1da119e8f766df17b0bfcbf7d757", + "virtualjaguar": "fc434223e248d32c38e46fcd84eae40116d1bbb6", + "virtualxt": "0f078c4357c3f6196faea56951930491455b47b8", + "vitaquake2": "18ae56936e0857d726df6b1805bcaf39f649e1c8", + "vitaquake2-rogue": "5740238c8c868c1bd77278565deb4d0380bff1f9", + "vitaquake2-xatrix": "9457b624a2ef954d8a956a9dbb1cade98a4f8535", + "vitaquake2-zaero": "b6544d6d13255bdc9811277bf301bf5b764e1912", + "vitaquake3": "0fa5379c56f04a121e8026a3694fa45e01a50514", + "vitavoyager": "0e17542eeeb904e6bbfedb34db8d628b58b4c09b", + "wasm4": "448263d66739c91a3d53c992253b49742416871c", + "wqxemu": "75b6fd2d3726386ebf3e2839ab1facbe87df3f7a", + "x1": "81e99f41eb8a048defc206383fbabdf281e53b6f", + "x64sdl": "4171f40c8a70256a2c5cb70db6a2b8fa733d9b3d", + "xemu": "e6033c0002a3311d6f0ba2bd6c1f399324d65e96", + "xrick": "2bb032e72b1432fa2c428d186db4ce55dfec8e2f", + "yabasanshiro": "bc1d40f813591ab89fb3c69af143976b636a6d89", + "yabause": "3b4247a760bff675b05f8436ce0b648cf4ea9e21", + "yaps2": "809a88a9100d3021461aba03ffdae5d09a7036f9", + "ymir": "13f216fa1b836ac742e907d65fb5f5d462307d95" + } +} diff --git a/scripts/check_freshness.py b/scripts/check_freshness.py index 32d3d54e..1037b55f 100644 --- a/scripts/check_freshness.py +++ b/scripts/check_freshness.py @@ -56,6 +56,7 @@ from common import ( # noqa: E402 list_registered_platforms, load_emulator_profiles, upstream_profile_index, + write_text_atomic, yaml_load, ) from exporter import discover_exporters # noqa: E402 @@ -65,6 +66,8 @@ from scripts.scraper.targets import discover_target_scrapers # noqa: E402 REPO_ROOT = Path(__file__).resolve().parents[1] CORE_INFO_REPO = "https://github.com/libretro/libretro-core-info" +# The git blob of every .info as last reviewed: `--record-coreinfo` writes it. +CORE_INFO_RECORD = REPO_ROOT / "platforms" / "_core_info.json" NO_INTRO_MIRROR = "https://github.com/hugo19941994/auto-datfile-generator" NO_INTRO_RELEASE = "Daily_Rebuild" NO_INTRO_ASSET = "no-intro.zip" @@ -697,8 +700,9 @@ def _age_days(stamp: str, now: datetime) -> int | None: # --- core-info -------------------------------------------------------------- -def core_info_names(cache_dir: str, offline: bool) -> list[str] | None: - """Every core the libretro core-info repository describes.""" +def core_info_blobs(cache_dir: str, offline: bool) -> dict[str, str] | None: + """Every core the libretro core-info repository describes, with the git + blob of its .info.""" repo = upstream.parse_repo(CORE_INFO_REPO) if repo is None: return None @@ -710,12 +714,54 @@ def core_info_names(cache_dir: str, offline: bool) -> list[str] | None: ) if not isinstance(payload, list): return None - names = [] + blobs = {} for entry in payload: name = entry.get("name", "") if isinstance(entry, dict) else "" if name.endswith("_libretro.info"): - names.append(name[: -len("_libretro.info")]) - return sorted(names) + blobs[name[: -len("_libretro.info")]] = str(entry.get("sha") or "") + return dict(sorted(blobs.items())) + + +def core_info_names(cache_dir: str, offline: bool) -> list[str] | None: + """Every core the libretro core-info repository describes.""" + blobs = core_info_blobs(cache_dir, offline) + return None if blobs is None else list(blobs) + + +def load_core_info_record(path: Path = CORE_INFO_RECORD) -> dict[str, str] | None: + if not path.is_file(): + return None + return dict((json.loads(path.read_text(encoding="utf-8")) or {}).get("blobs") or {}) + + +def record_core_info( + blobs: dict[str, str], names: list[str], path: Path = CORE_INFO_RECORD +) -> list[str]: + """Record the current blob of *names* (every .info when empty) as reviewed. + + Naming the cores keeps a change nobody read out of the record. + """ + unknown = sorted(set(names) - set(blobs)) + if unknown: + raise ValueError(f"no such .info in core-info: {', '.join(unknown)}") + recorded = load_core_info_record(path) or {} + recorded.update({n: blobs[n] for n in (names or blobs)}) + payload = {"repository": CORE_INFO_REPO, "blobs": dict(sorted(recorded.items()))} + write_text_atomic(str(path), json.dumps(payload, indent=2) + "\n") + return sorted(names or blobs) + + +def coreinfo_drift( + blobs: dict[str, str], recorded: dict[str, str], profiles: dict[str, dict] +) -> list[str]: + """Profiled cores whose .info is not the one recorded as reviewed. + + The .info is no authority, but a new firmwareN_path in it is the + cheapest sign that a profile needs reading again. + """ + index = {key.casefold() for key in profile_name_index(profiles)} + return [n for n, sha in blobs.items() + if n.casefold() in index and recorded.get(n) != sha] def coreinfo_gaps( @@ -745,10 +791,14 @@ def coreinfo_gaps( return unprofiled, standalone -def check_coreinfo(profiles: dict[str, dict], cache_dir: str, offline: bool) -> list[Finding]: - names = core_info_names(cache_dir, offline) - if names is None: +def check_coreinfo( + profiles: dict[str, dict], cache_dir: str, offline: bool, + record_path: Path = CORE_INFO_RECORD, +) -> list[Finding]: + blobs = core_info_blobs(cache_dir, offline) + if blobs is None: return [Finding("coreinfo", "libretro-core-info", UNKNOWN, detail="listing unavailable")] + names = list(blobs) unprofiled, standalone = coreinfo_gaps(names, profiles) findings = [ Finding( @@ -773,6 +823,22 @@ def check_coreinfo(profiles: dict[str, dict], cache_dir: str, offline: bool) -> ) for name, key in standalone ) + recorded = load_core_info_record(record_path) + if recorded is None: + findings.append(Finding( + "coreinfo", "reviewed .info", UNKNOWN, + detail=f"no {record_path.name}: run check_freshness.py --record-coreinfo", + )) + return findings + findings.extend( + Finding( + "coreinfo", name, STALE, + local=(recorded.get(name) or "not recorded")[:12], remote=blobs[name][:12], + detail=(".info changed since reviewed: read its firmware, then " + f"check_freshness.py --record-coreinfo {name}"), + ) + for name in coreinfo_drift(blobs, recorded, profiles) + ) return findings @@ -1310,8 +1376,21 @@ def main() -> int: "--emulators-dir", default="emulators", help="emulator profile directory (default: %(default)s)", ) + parser.add_argument( + "--record-coreinfo", nargs="*", metavar="CORE", + help="record the current .info of CORE (every core when none is named) " + f"as reviewed in {CORE_INFO_RECORD.relative_to(REPO_ROOT)}, then exit", + ) args = parser.parse_args() + if args.record_coreinfo is not None: + blobs = core_info_blobs(args.cache_dir, args.offline) + if not blobs: + raise RuntimeError("core-info listing unavailable: nothing recorded") + done = record_core_info(blobs, args.record_coreinfo) + print(f"recorded {len(done)} .info file(s) as reviewed") + return 0 + areas = tuple(a.strip() for a in args.only.split(",")) if args.only else AREAS unknown = sorted(set(areas) - set(AREAS)) if unknown: diff --git a/tests/test_check_freshness.py b/tests/test_check_freshness.py index 99166b8f..12a96beb 100644 --- a/tests/test_check_freshness.py +++ b/tests/test_check_freshness.py @@ -266,6 +266,36 @@ class CoreResolutionTests(unittest.TestCase): self.assertEqual(unprofiled, ["wqxemu"]) self.assertEqual(standalone, [("eka2l1", "eka2l1")]) + def test_a_changed_info_of_a_profiled_core_is_stale(self): + """A firmwareN_path added to a profiled core's .info changes its blob: + the names alone said OK.""" + blobs = {"mednafen_psx": "new", "eka2l1": "same", "wqxemu": "other"} + recorded = {"mednafen_psx": "old", "eka2l1": "same"} + with tempfile.TemporaryDirectory() as tmp: + record = Path(tmp) / "_core_info.json" + record.write_text(cf.json.dumps({"blobs": recorded})) + with mock.patch.object(cf, "core_info_blobs", return_value=blobs): + rows = cf.check_coreinfo(self.PROFILES, "", True, record) + stale = {r.subject: r for r in rows if r.status == cf.STALE} + self.assertIn("mednafen_psx", stale) + self.assertIn("--record-coreinfo mednafen_psx", stale["mednafen_psx"].detail) + self.assertNotIn(".info changed", stale["eka2l1"].detail) + self.assertEqual(cf.coreinfo_drift(blobs, recorded, self.PROFILES), ["mednafen_psx"]) + + def test_recording_a_core_leaves_the_others_unread(self): + with tempfile.TemporaryDirectory() as tmp: + record = Path(tmp) / "_core_info.json" + record.write_text(cf.json.dumps({"blobs": {"a": "1", "b": "1"}})) + cf.record_core_info({"a": "2", "b": "2"}, ["a"], record) + self.assertEqual(cf.load_core_info_record(record), {"a": "2", "b": "1"}) + with self.assertRaises(ValueError): + cf.record_core_info({"a": "2"}, ["ghost"], record) + + def test_the_committed_record_holds_git_blobs(self): + recorded = cf.load_core_info_record() + self.assertIsNotNone(recorded) + self.assertTrue(all(len(sha) == 40 for sha in recorded.values())) + class PinParsingTests(unittest.TestCase): WORKFLOW = """ diff --git a/wiki/tools.md b/wiki/tools.md index 8164c5d4..0990c51a 100644 --- a/wiki/tools.md +++ b/wiki/tools.md @@ -553,7 +553,10 @@ today, and answer with one row per subject. Platform and target files are re-scraped through the scrapers' own write path into a throwaway copy and diffed against the committed file, so the diff decides rather than a version string. Core-info is listed and compared with the profiles (a core with no -profile, a profile that calls standalone a core libretro now builds). Data +profile, a profile that calls standalone a core libretro now builds, a +profiled core whose `.info` git blob differs from the one recorded in +`platforms/_core_info.json`). Once the changed `.info` is read against the +profile, `--record-coreinfo ` records its blob as reviewed. Data directories are checked against their upstream, dump catalogs and romset snapshots against the catalog they were read from (Redump DAT versions, the No-Intro daily rebuild, the newest TOSEC pack, the newest MAME release, the @@ -571,6 +574,7 @@ python scripts/check_freshness.py --only platforms,targets python scripts/check_freshness.py --json python scripts/check_freshness.py --profiles # also runs profile_sync (slow) python scripts/check_freshness.py --offline # local ages only +python scripts/check_freshness.py --record-coreinfo virtualjaguar # .info read, record it ``` The exit code is non-zero when anything is stale. Emulator profiles are the