Kit Manager: detect unsupported kits via platform database
Scan sedona/platforms/db/ to find which native kits are compiled for the SAX's platform. Kits with native code for other platforms, kits providing a PlatformService for a different device, and their transitive dependents are placed in a "Not supported" section with a red-cross checkbox that cannot be toggled. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+153
@@ -246,9 +246,162 @@ def list_component_types(kit_name):
|
||||
return sorted(entries)
|
||||
|
||||
|
||||
_unsupported_cache = {} # frozenset(sax kit names) -> set of unsupported kit names
|
||||
|
||||
|
||||
def _platforms_db():
|
||||
return os.path.join(app_state.SEDONA_HOME, "platforms", "db")
|
||||
|
||||
|
||||
def _platform_native_kits():
|
||||
"""Return (matching, all_platforms) — two sets of kit names.
|
||||
|
||||
*matching* is the union of nativeKit names from platform builds that include
|
||||
every PlatformService-providing kit the SAX declares. *all_platforms* is the
|
||||
union across every build in the database regardless of match.
|
||||
|
||||
A kit that appears in *all_platforms* but not in *matching* has native code
|
||||
compiled for a different device and cannot work with this SAX.
|
||||
"""
|
||||
sax_names = set(app_state.active_schema_kits.keys())
|
||||
db = _platforms_db()
|
||||
if not os.path.isdir(db):
|
||||
return None, None
|
||||
|
||||
sax_platform_kits = set()
|
||||
for name in sax_names:
|
||||
kit_dir = os.path.join(_manifests_dir(), name)
|
||||
if not os.path.isdir(kit_dir):
|
||||
continue
|
||||
for entry in os.listdir(kit_dir):
|
||||
if not (entry.startswith(f"{name}-") and entry.endswith(".xml")):
|
||||
continue
|
||||
try:
|
||||
tree = ET.parse(os.path.join(kit_dir, entry))
|
||||
except ET.ParseError:
|
||||
continue
|
||||
for t in tree.getroot().findall(".//type"):
|
||||
text = t.get("name", "") + " " + t.get("base", "")
|
||||
if "PlatformService" in text:
|
||||
sax_platform_kits.add(name)
|
||||
break
|
||||
|
||||
if not sax_platform_kits:
|
||||
return None, None
|
||||
|
||||
matching = set()
|
||||
all_platforms = set()
|
||||
found = False
|
||||
for vendor in os.listdir(db):
|
||||
vd = os.path.join(db, vendor)
|
||||
if not os.path.isdir(vd):
|
||||
continue
|
||||
for device in os.listdir(vd):
|
||||
dd = os.path.join(vd, device)
|
||||
if not os.path.isdir(dd):
|
||||
continue
|
||||
for build in os.listdir(dd):
|
||||
mf = os.path.join(dd, build, ".par", "platformManifest.xml")
|
||||
if not os.path.isfile(mf):
|
||||
continue
|
||||
try:
|
||||
tree = ET.parse(mf)
|
||||
except ET.ParseError:
|
||||
continue
|
||||
nk_names = set()
|
||||
for nk in tree.getroot().findall(".//nativeKit"):
|
||||
nk_names.add(nk.get("depend", "").split()[0])
|
||||
all_platforms.update(nk_names)
|
||||
if sax_platform_kits <= nk_names:
|
||||
matching.update(nk_names)
|
||||
found = True
|
||||
|
||||
return (matching if found else None), all_platforms
|
||||
|
||||
|
||||
def unsupported_kits():
|
||||
"""Kit names that cannot work with the open file's platform.
|
||||
|
||||
A kit is unsupported when:
|
||||
- it has native code (hasNatives or listed as nativeKit on some platform)
|
||||
but is not compiled into any build matching the SAX's device, or
|
||||
- it provides a PlatformService type for a different device.
|
||||
|
||||
Kits that depend on an unsupported kit are also flagged.
|
||||
"""
|
||||
sax_names = frozenset(app_state.active_schema_kits.keys())
|
||||
if sax_names in _unsupported_cache:
|
||||
return _unsupported_cache[sax_names]
|
||||
|
||||
matching_natives, all_natives = _platform_native_kits()
|
||||
if matching_natives is None:
|
||||
_unsupported_cache[sax_names] = set()
|
||||
return set()
|
||||
|
||||
unsupported = set()
|
||||
all_kits = list_kits()
|
||||
|
||||
for name in all_kits:
|
||||
if name in sax_names:
|
||||
continue
|
||||
|
||||
# Native on another platform but not on the matching one.
|
||||
if name in all_natives and name not in matching_natives:
|
||||
unsupported.add(name)
|
||||
continue
|
||||
|
||||
kit_dir = os.path.join(_manifests_dir(), name)
|
||||
if not os.path.isdir(kit_dir):
|
||||
continue
|
||||
for entry in os.listdir(kit_dir):
|
||||
if not (entry.startswith(f"{name}-") and entry.endswith(".xml")):
|
||||
continue
|
||||
try:
|
||||
tree = ET.parse(os.path.join(kit_dir, entry))
|
||||
except ET.ParseError:
|
||||
continue
|
||||
root = tree.getroot()
|
||||
has_natives = root.get("hasNatives") == "true"
|
||||
has_platform_type = any(
|
||||
"PlatformService" in (t.get("name", "") + " " + t.get("base", ""))
|
||||
for t in root.findall(".//type")
|
||||
)
|
||||
if (has_natives or has_platform_type) and name not in matching_natives:
|
||||
unsupported.add(name)
|
||||
break
|
||||
|
||||
# Transitive: kits that depend on an unsupported kit
|
||||
changed = True
|
||||
while changed:
|
||||
changed = False
|
||||
for name in all_kits:
|
||||
if name in unsupported or name in sax_names:
|
||||
continue
|
||||
kit_dir = os.path.join(_manifests_dir(), name)
|
||||
if not os.path.isdir(kit_dir):
|
||||
continue
|
||||
for entry in os.listdir(kit_dir):
|
||||
if not (entry.startswith(f"{name}-") and entry.endswith(".xml")):
|
||||
continue
|
||||
try:
|
||||
tree = ET.parse(os.path.join(kit_dir, entry))
|
||||
except ET.ParseError:
|
||||
continue
|
||||
for dep in tree.getroot().findall(".//depend"):
|
||||
dep_name = dep.get("on", "").split()[0]
|
||||
if dep_name in unsupported:
|
||||
unsupported.add(name)
|
||||
changed = True
|
||||
break
|
||||
|
||||
_unsupported_cache[sax_names] = unsupported
|
||||
return unsupported
|
||||
|
||||
|
||||
def invalidate():
|
||||
"""Clears every cache, for when Sedona home changes or a kit is repinned."""
|
||||
_versions_cache.clear()
|
||||
_manifest_cache.clear()
|
||||
_component_cache.clear()
|
||||
_builds_cache.clear()
|
||||
_unsupported_cache.clear()
|
||||
|
||||
Reference in New Issue
Block a user