libretro-super/comptable.py
2023-10-30 18:05:46 +01:00

301 lines
10 KiB
Python
Executable File

#!/usr/bin/env python3
# License: MIT
# Copyright (C) Google
# Author: Vladimit 'phcoder' Serbinenko
import os
import csv
import requests
hostname = 'git.libretro.com'
namespace = 'libretro'
MISSING = 'missing'
OK = 'OK'
BROKEN = 'broken'
coremap = {}
allcores = set()
allplatformset = set()
corestatus = {}
corereason = {}
SUBCORE_SUFFIXES = [
"plus",
# bsnes
"accuracy", "balanced",
# Beetle PSX
"hw",
# Quake
"rogue", "xatrix", "zaero",
# VICE
"xpet", "xplus4", "xscpu64", "xvic", "x128", "x64sc", "xcbm2", "xcbm5x0",
# Boom3
"xp",
# MAME
"cdi2015"
]
GFX_FEATS = ['gfxaccel', 'gl1', 'gl2', 'gl3', 'gles2', 'gles3']
CPU_FEATS = ['x86_any', 'libco', 'cpu64', 'threads', 'thread-local', 'jit', 'little_endian']
PERIPHERAL_FEATS = ['cdrom', 'usb']
LANG_FEATS = ['c++14', 'c++11']
MISC_FEATS = ['physfs', 'jvm']
ALL_FEATS = GFX_FEATS + CPU_FEATS + PERIPHERAL_FEATS + MISC_FEATS + LANG_FEATS
DESKTOP_COMMON = list(set(ALL_FEATS) - set(['gles2', 'gles3', 'cpu64', 'x86_any', 'little_endian']))
DESKTOP_X64 = DESKTOP_COMMON + ['x86_any', 'cpu64', 'little_endian']
DESKTOP_X86 = DESKTOP_COMMON + ['x86_any', 'little_endian']
DESKTOP_X64_NO_CXX11 = list(set(DESKTOP_X64) - set(['c++14', 'c++11']))
DESKTOP_X86_NO_CXX11 = list(set(DESKTOP_X86) - set(['c++14', 'c++11']))
DESKTOP_ARM32LE = DESKTOP_COMMON + ['little_endian']
DESKTOP_PPC = DESKTOP_COMMON
UWP = ['gfxaccel', 'gles2', 'threads', 'thread-local', 'libco'] + ['cdrom', 'usb', 'physfs', 'c++14', 'c++11', 'jvm'] # unsure about second part
MOBILE_LE = ['gfxaccel', 'gles2', 'gles3', 'threads', 'libco', 'little_endian']
ANDROID = MOBILE_LE + ['jit', 'physfs', 'thread-local', 'c++14', 'c++11', 'jvm']
features_platforms = {
# Misc
'emscripten': ['gfxaccel', 'gles2', 'little_endian', 'physfs', 'c++14', 'c++11'],
# consoles
'ctr': ['threads', 'thread-local', 'libco', 'jit', 'little_endian', 'c++14', 'c++11'],
'psl1ght': ['cpu64'] + ['libco', 'cdrom', 'usb', 'jit', 'c++14', 'c++11'], # unsure about second part
'ngc': ['threads', 'thread-local', 'libco'] + ['cdrom', 'jit', 'c++14', 'c++11'], # unsure about second part
'wii': ['threads', 'thread-local', 'libco'] + ['cdrom', 'usb', 'jit', 'c++14', 'c++11'], # unsure about second part
'ps2': ['little_endian'] + ['libco', 'cpu64', 'threads', 'thread-local', 'cdrom', 'usb', 'jit', 'c++14', 'c++11'], # unsure about second part
'ps3': ['threads', 'thread-local', 'cpu64'] + ['libco', 'cdrom', 'usb', 'jit', 'c++14', 'c++11'], # unsure about second part
'psp': ['libco', 'threads', 'thread-local', 'little_endian'] + ['jit', 'c++14', 'c++11'], # unsure about second part
'libnx-aarch64': ['gfxaccel', 'gl1', 'gl2', 'gl3', 'libco', 'cpu64', 'threads', 'thread-local', 'jit', 'little_endian'] + ['usb', 'c++14', 'c++11'], # unsure about second part
'wiiu': ['libco'] + ['cdrom', 'usb', 'jit', 'c++14', 'c++11'] + ['threads'], # unsure about second part. Threads are present in OS but not in rthreads yet
'vita': ['gfxaccel', 'gl1', 'gl2', 'threads', 'thread-local', 'libco', 'jit', 'little_endian', 'c++14', 'c++11'], # 'gl3', 'gles2', 'gles3'?
# UWP
'windows-uwp-arm': UWP + ['little_endian'],
'windows-uwp-x64': UWP + ['x86_any', 'cpu64', 'little_endian'],
'windows-uwp-x86': UWP + ['x86_any', 'little_endian'],
# Mobile
'android-arm64-v8a': ANDROID + ['cpu64'],
'android-armeabi-v7a': ANDROID,
'android-x86': ANDROID + ['x86_any'],
'android-x86_64': ANDROID + ['x86_any', 'cpu64'],
'ios': MOBILE_LE + ['physfs', 'c++14', 'c++11'],
'ios9': MOBILE_LE + ['physfs', 'c++14', 'c++11'],
'ios-arm64': MOBILE_LE + ['cpu64', 'physfs', 'thread-local', 'c++14', 'c++11'],
'tvos-arm64': MOBILE_LE + ['cpu64', 'physfs', 'thread-local', 'c++14', 'c++11'],
'qnx': MOBILE_LE + ['physfs', 'thread-local', 'c++14', 'c++11', 'jvm'], # Unsure about usb and thread-local
# Desktop
'linux-x64': DESKTOP_X64,
'windows-x64': DESKTOP_X64,
'osx-x64': DESKTOP_X64,
'linux-i686': DESKTOP_X86,
'windows-i686': DESKTOP_X86,
'linux-arm7neonhf': DESKTOP_ARM32LE,
'linux-armhf': DESKTOP_ARM32LE,
'xbox-x86': DESKTOP_X86,
'windows-msvc05-i686': DESKTOP_X86_NO_CXX11,
'windows-msvc10-i686': DESKTOP_X86_NO_CXX11,
'windows-msvc10-x64': DESKTOP_X64_NO_CXX11,
'osx-ppc': [x for x in DESKTOP_PPC if x != 'c++14' and x != 'c++11']
}
features_cores = {
'3dengine': ['gl2'], # Should be gl2 or gles2 but current bugs prevent operating with gles2
'atari800': ['libco'],
'blastem': ['x86_any'],
'boom3': ['gl1'],
'boom3-xp': ['gl1'],
'bsnes': ['libco'],
'bsnes2014': ['libco'],
'bsnes-libretro-cplusplus98': ['libco'],
'bsnes-hd': ['libco'],
'bsnes-mercury': ['libco'],
'chailove': ['physfs', 'thread-local', 'threads'],
'citra': ['gfxaccel'],
'citra2018': ['gfxaccel'],
'Craft': ['gfxaccel'],
'chailove': ['c++14'],
'dolphin': ['cpu64', 'jit'],
'dosbox-svn': ['libco'],
'dosbox-core': ['threads'],
'dosbox-pure': ['c++11', 'threads'],
'ffmpeg': ['threads'],
'flycast': ['gfxaccel'],
'flycast-upstream': ['gfxaccel'],
'frodo': ['libco'],
'hatari': ['libco'],
'gpsp': ['libco'],
'ishiiruka': ['cpu64'],
'kronos': ['gl3'],
'mupen64plus': ['gfxaccel', 'libco'],
'neocd': ['c++11'],
'Omicron': ['gfxaccel', 'jvm'],
'OpenLara': ['gfxaccel'],
'parallel-n64': ['gfxaccel', 'libco'],
'pcem': ['threads'],
'play': ['gfxaccel'],
'redbook': ['cdrom'],
'remotejoy': ['usb'],
'retro8': ['c++11'],
'REminiscence': ['libco'],
'scummvm': ['libco'],
'ThePowderToy': ['threads'],
'tic80': ['little_endian'],
'uae': ['threads'],
'vitaquake3': ['gl1'],
'vitavoyager': ['gl1'],
'yabasanshiro': ['gfxaccel']
}
def strip_suffix(s, suffix):
if s.endswith(suffix):
return s[:-len(suffix)]
return s
def strip_suffixes(s, suffixes):
r = s
for suffix in suffixes + suffixes + suffixes:
r = strip_suffix(r, suffix)
return r
def strip_prefix(s, prefix):
if s.startswith(prefix):
return s[len(prefix):]
return s
def strip_prefixes(s, prefixes):
r = s
for prefix in prefixes:
r = strip_prefix(r, prefix)
return r
def file_to_platform(fname):
s = strip_suffixes(fname, [
"-legacy", "-mingw",
# Mupen64
"-gles2", "-gles3",
] + ["-" + x for x in SUBCORE_SUFFIXES])
s = strip_prefixes(s, ["libretro-", "build-", "static-",
"retroarch-", "dummy-", "deps:", "test:"])
# for infix in ["msvc05", "msvc10"]:
# s = s.replace("-" + infix + "-", "-")
mp = {
'code_quality': None,
'ios-9': 'ios9',
'trigger_static-cores': None,
"android": None,
'osx': None,
'switch': None
}
if s in mp:
s = mp[s]
subcore = list(filter(lambda x: "-" + x + "-" in fname
or fname.endswith("-" + x), SUBCORE_SUFFIXES))
return (s, "-".join(subcore))
def repo_to_core(repname):
s = strip_suffixes(repname, ["-nx", "-libretro", "_libretro"])
s = strip_prefixes(s, ["libretro-"])
return s
def page_get(base):
per_page = 20
res = []
for page in range(1, 30):
add = requests.get(base + ('per_page=%d&page=%d' % (per_page, page))).json()
res += add
if len(add) != per_page:
return res
return res
def parse_pipelines(projectid, sha):
pipelines = requests.get('https://%s/api/v4/projects/%d/pipelines?sha=%s&per_page=20' % (hostname, projectid, sha)).json()
for pipeline in pipelines:
if pipeline['status'] == 'success':
# print(pipeline)
return page_get('https://%s/api/v4/projects/%d/pipelines/%d/jobs?' % (hostname, projectid, pipeline['id']))
return None
projects_all = page_get('https://%s/api/v4/projects?simple=true&' % hostname)
projects = list(filter(lambda x: x['namespace']['path'] == namespace, projects_all))
for project in projects:
print(project['path_with_namespace'])
projectid = project['id']
core_base = repo_to_core(project['path'])
if core_base == 'RetroArch':
continue
commits = requests.get('https://%s/api/v4/projects/%d/repository/commits?ref_name=%s' % (hostname, projectid, project['default_branch'])).json()
# print(commits[0])
jobs = None
for commit in commits:
jobs = parse_pipelines(projectid, commit['id'])
if jobs is not None:
break
if jobs is None:
jobs = []
if not jobs:
allcores.add(core_base)
for job in jobs:
# print(job)
(platform, subcore) = file_to_platform(job['name'])
if platform is None:
continue
if subcore:
core = core_base + "-" + subcore
else:
core = core_base
allplatformset.add(platform)
allcores.add(core)
k = (platform, core)
if k not in coremap:
coremap[k] = []
coremap[k].append({'status': job['status']})
allplatforms = sorted(allplatformset)
cf = open ("comptable.csv", "w")
c = csv.writer(cf)
c.writerow([""] + allplatforms)
for core in allcores:
row = [core]
for platform in allplatforms:
k = (platform, core)
if k not in coremap:
status = MISSING
else:
status = OK if any(map(lambda x: x['status'], coremap[k])) else BROKEN
corestatus[k] = status
if core in features_cores and platform in features_platforms:
missing = set(features_cores[core]) - set(features_platforms[platform])
if missing:
corereason[k] = ','.join(missing)
for core in sorted (allcores):
if core in ('dosbox-libretro',):
continue
row = [core]
for platform in allplatforms:
k = (platform, core)
st = corestatus[k]
s = st
if st != OK and k in corereason:
s += " (" + corereason[k] + ")"
if st == OK and k in corereason:
print("%s is enabled on %s despite %s" % (core, platform, corereason[k]))
row += [s]
c.writerow(row)
cf.close()