Handle array properties

This commit is contained in:
dece 2020-09-27 18:13:03 +02:00
parent 8cf32a44c2
commit 099672e43c
2 changed files with 62 additions and 31 deletions

View file

@ -1,5 +1,6 @@
import re
import shutil
import string
import subprocess
from dataclasses import dataclass
@ -7,6 +8,15 @@ from dataclasses import dataclass
class Xfconf:
"""Interface around Xfconf, using xion-query behind the scene."""
# GTypes to xfconf-query types along with a value string parser.
TYPE_MAP = {
"gboolean": "bool",
"gint": "int",
"guint": "uint",
"gdouble": "double",
"gchararray": "string",
}
def __init__(self, xq=None):
self._xq = xq or self.find_xq()
@ -21,6 +31,7 @@ class Xfconf:
if not print_failures:
return None
print(f"xion-query command failed with code {exc.returncode}.")
print("command:", command)
if exc.stdout:
print("stdout:", exc.stdout.decode().strip())
if exc.stderr:
@ -58,28 +69,44 @@ class Xfconf:
return XfconfProperty.parse(output)
def set_property(self, channel, prop, prop_type, value):
"""Create or update this property."""
"""Create or update this property, return True on success."""
if not self.does_property_exist(channel, prop):
self.create_property(channel, prop, prop_type, value)
return self.create_property(channel, prop, prop_type, value)
else:
self.update_property(channel, prop, value)
return self.update_property(channel, prop, value)
def create_property(self, channel, prop, prop_type, value):
"""Create a new property with those params, return True on success."""
if " " in value:
value = f'"{value}"'
prop_type = Xfconf.convert_type(prop_type)
if not prop_type:
return False
value = Xfconf.sanitize_str(value)
output = self.xq(["-c", channel, "-p", prop, "-n",
"-t", prop_type, "-s", value])
if output is None:
return False
return output == ""
def update_property(self, channel, prop, value):
"""Update an existing property, return True on success."""
if " " in value:
value = f'"{value}"'
value = Xfconf.sanitize_str(value)
output = self.xq(["-c", channel, "-p", prop, "-s", value])
return output == ""
def set_property_array(self, channel, prop, values):
"""Set a property array, return True on success.
Due to limitations in the way xfconf-query work, whether the array
exists or not it is entirely replaced by values.
"""
command = ["-c", channel, "-p", prop, "-n", "-a"]
for value in values:
subtype = Xfconf.convert_type(value["type"])
if not subtype:
return False
subvalue = Xfconf.sanitize_str(value["value"])
command += ["-t", subtype, "-s", subvalue]
output = self.xq(command)
return output == ""
def reset_root(self, channel, root):
"""Reset all channel properties under root, return True on success."""
output = self.xqs(f"-c {channel} -p {root} -r -R")
@ -87,11 +114,29 @@ class Xfconf:
@staticmethod
def find_xq():
"""Find xion-query in the path and return it, or None on failure."""
xq = shutil.which("xion-query")
if not xq:
exit("Could not find xion-query in path.")
print("Could not find xion-query in path.")
return None
return xq
@staticmethod
def convert_type(gtype):
"""Get an xfconf-query type from a gtype."""
xq_type = Xfconf.TYPE_MAP.get(gtype)
if xq_type is None:
print(f"Unknown gtype {gtype}.")
return xq_type
@staticmethod
def sanitize_str(value):
"""Wrap value with doublequotes if it contains whitespaces."""
for char in string.whitespace:
if char in value:
return f'"{value}"'
return value
XION_PROP_RE = re.compile(r"t:(\S+) (.+)")

28
xion.py
View file

@ -57,15 +57,6 @@ def main():
class Xion:
"""Manipulate Xfconf settings trees."""
# GTypes to xfconf-query types along with a value string parser.
TYPE_MAP = {
"gboolean": "bool",
"gint": "int",
"guint": "uint",
"gdouble": "double",
"gchararray": "string",
}
def __init__(self, xq=None):
self.xfconf = Xfconf(xq=xq)
@ -95,6 +86,10 @@ class Xion:
tree[prop_name] = leaf
return tree
@staticmethod
def _build_prop_leaf(prop):
return {"type": prop.gtype, "value": str(prop.value)}
def export_tree(self, channel, root, tree, output_path):
"""Export a property tree as a sorted JSON file."""
tree["channel"] = channel
@ -139,20 +134,11 @@ class Xion:
def apply_property(self, channel, name, content):
"""Update one property in Xfconf, return True on success."""
# if isinstance(content, list):
# for subprop in content:
# if not self.apply_property(channel,
if isinstance(content, list):
return self.xfconf.set_property_array(channel, name, content)
prop_type = content["type"]
if not prop_type in Xion.TYPE_MAP:
print(f"Unknown property type {prop_type}!")
return False
xq_type = Xion.TYPE_MAP[prop_type]
value = content["value"]
self.xfconf.set_property(channel, name, xq_type, value)
@staticmethod
def _build_prop_leaf(prop):
return {"type": prop.gtype, "value": str(prop.value)}
return self.xfconf.set_property(channel, name, prop_type, value)
if __name__ == "__main__":