"""Build /etc/gconf/gconf.xml.defaults from Psion's .schemas files. On the device gconftool-2 --install-schemas runs at image build time; we do the same job here so the defaults source is populated before first boot. Without it every app that reads a schema default gets NULL -- which is why AisleRiot drew blank white cards (no /apps/aisleriot/card_options). """ import os, re, sys, html, xml.etree.ElementTree as ET MTIME = "1104537600" # 2005-01-01, matching the era of the tree def entries(path): """Yield (key, type, ltype, value) for every schema that carries a default.""" txt = open(path, encoding="utf-8", errors="replace").read() for m in re.finditer(r"(.*?)", txt, re.S): b = m.group(1) applyto = re.findall(r"(.*?)", b, re.S) typ = re.search(r"(.*?)", b, re.S) lty = re.search(r"(.*?)", b, re.S) dfl = re.search(r"(.*?)", b, re.S) if not (applyto and typ and dfl): continue for key in applyto: # .schemas files wrap long defaults across lines; the value itself # never contains a newline, so fold the wrapping back to one space. val = " ".join(html.unescape(dfl.group(1)).split()) yield (key.strip(), typ.group(1).strip(), lty.group(1).strip() if lty else None, val) def render(name, typ, ltype, val): if typ == "bool": return f'\t' if typ in ("int", "float"): return f'\t' if typ == "string": return (f'\t\n' f'\t\t{html.escape(val)}\n\t') if typ == "list": lt = ltype or "string" body = "" inner = val.strip() if inner.startswith("[") and inner.endswith("]"): inner = inner[1:-1].strip() if inner: for item in [i.strip() for i in inner.split(",") if i.strip()]: if lt == "string": body += f'\t\t
  • {html.escape(item)}
  • \n' else: body += f'\t\t
  • \n' return (f'\t\n' f'{body}\t') return None def main(root, schema_files): dirs = {} for f in schema_files: for key, typ, ltype, val in entries(f): d, _, name = key.rpartition("/") line = render(name, typ, ltype, val) if line: dirs.setdefault(d.lstrip("/"), []).append(line) for d, lines in sorted(dirs.items()): out = os.path.join(root, d) os.makedirs(out, exist_ok=True) with open(os.path.join(out, "%gconf.xml"), "w", encoding="utf-8") as fh: fh.write('\n\n' + "\n".join(lines) + "\n\n") print(f" /{d:44} {len(lines)} keys") # every intermediate directory needs a %gconf.xml for the XML backend to walk it for d in list(dirs): parts = d.split("/") for i in range(1, len(parts)): p = os.path.join(root, *parts[:i]) os.makedirs(p, exist_ok=True) f = os.path.join(p, "%gconf.xml") if not os.path.exists(f): open(f, "w").write('\n\n\n') f = os.path.join(root, "%gconf.xml") if not os.path.exists(f): open(f, "w").write('\n\n\n') if __name__ == "__main__": main(sys.argv[1], sys.argv[2:])