"""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:])