field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

app_dependency_graph.py (4524B)


      1 """Validate the real locked application graph after the proxy crate is retired."""
      2 
      3 from __future__ import annotations
      4 
      5 from typing import Any
      6 
      7 OWNED = {"tera_core", "tera_ffi", "tera_bindgen", "tera_wasm"}
      8 MOBILE = OWNED - {"tera_wasm"}
      9 RETIRED = {
     10     "radroots_ios_source_lock",
     11     "radroots_mobile_core",
     12     "radroots_mobile_ffi",
     13     "radroots_mobile_bindgen",
     14     "radroots_mobile_wasm",
     15 }
     16 
     17 
     18 class GraphError(ValueError):
     19     """A stable rejection without dependency source paths or command output."""
     20 
     21 
     22 def require(condition: bool, reason: str) -> None:
     23     if not condition:
     24         raise GraphError(reason)
     25 
     26 
     27 def indexed(rows: Any, label: str) -> dict[str, dict[str, Any]]:
     28     require(isinstance(rows, list) and bool(rows), f"{label} inventory is absent")
     29     result = {}
     30     for row in rows:
     31         require(isinstance(row, dict), f"{label} entry is malformed")
     32         identifier = row.get("id")
     33         require(
     34             isinstance(identifier, str) and bool(identifier),
     35             f"{label} identity is absent",
     36         )
     37         require(identifier not in result, f"{label} identity is duplicated")
     38         result[identifier] = row
     39     return result
     40 
     41 
     42 def owned_packages(
     43     document: dict[str, Any], packages: dict[str, Any]
     44 ) -> dict[str, Any]:
     45     members = document.get("workspace_members")
     46     require(isinstance(members, list), "owned workspace members are absent")
     47     require(len(members) == len(OWNED), "owned workspace inventory differs")
     48     require(
     49         all(identifier in packages for identifier in members), "owned package is absent"
     50     )
     51     owned = {
     52         packages[identifier]["name"]: packages[identifier] for identifier in members
     53     }
     54     require(set(owned) == OWNED, "owned workspace inventory differs")
     55     defaults = document.get("workspace_default_members")
     56     require(isinstance(defaults, list), "mobile defaults are absent")
     57     require(
     58         sorted(defaults) == sorted(owned[name]["id"] for name in MOBILE),
     59         "mobile defaults must select the real native packages only",
     60     )
     61     return owned
     62 
     63 
     64 def foundation_sources(packages: dict[str, Any], foundation: dict[str, Any]) -> None:
     65     revision = foundation["revision"]
     66     expected = f"git+{foundation['repository']}?rev={revision}#{revision}"
     67     shared = []
     68     for package in packages.values():
     69         name = package.get("name")
     70         require(isinstance(name, str), "resolved package name is absent")
     71         require(
     72             name not in RETIRED,
     73             "retired mobile producer or source-lock shim is present",
     74         )
     75         if name.startswith("radroots_"):
     76             shared.append(package)
     77             require(
     78                 package.get("source") == expected, "resolved foundation source differs"
     79             )
     80             require(
     81                 package.get("version") == foundation["version"],
     82                 "resolved foundation version differs",
     83             )
     84         elif package.get("source") is None:
     85             require(
     86                 name in OWNED, "unowned local package entered the application graph"
     87             )
     88     require(bool(shared), "resolved foundation inventory is empty")
     89 
     90 
     91 def mobile_profile(owned: dict[str, Any], nodes: dict[str, Any]) -> None:
     92     ffi = owned["tera_ffi"]
     93     edges = ffi.get("dependencies")
     94     require(isinstance(edges, list), "owned FFI dependency inventory is absent")
     95     core_edges = [edge for edge in edges if edge.get("name") == "tera_core"]
     96     require(len(core_edges) == 1, "owned FFI must select one application core")
     97     edge = core_edges[0]
     98     require(
     99         edge.get("source") is None and edge.get("kind") is None,
    100         "FFI core must be an owned runtime dependency",
    101     )
    102     require(
    103         "mobile-social" in edge.get("features", []),
    104         "owned FFI mobile-social profile is absent",
    105     )
    106     core_node = nodes.get(owned["tera_core"]["id"], {})
    107     require(
    108         "mobile-social" in core_node.get("features", []),
    109         "resolved mobile-social feature is absent",
    110     )
    111 
    112 
    113 def validate(document: dict[str, Any], foundation: dict[str, Any]) -> None:
    114     packages = indexed(document.get("packages"), "resolved package")
    115     owned = owned_packages(document, packages)
    116     foundation_sources(packages, foundation)
    117     resolution = document.get("resolve")
    118     require(isinstance(resolution, dict), "resolved dependency graph is absent")
    119     nodes = indexed(resolution.get("nodes"), "resolved node")
    120     require(set(nodes) == set(packages), "resolved node inventory differs")
    121     mobile_profile(owned, nodes)