Handle array properties
This commit is contained in:
parent
8cf32a44c2
commit
099672e43c
65
xfconf.py
65
xfconf.py
|
@ -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
28
xion.py
|
@ -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__":
|
||||
|
|
Loading…
Reference in a new issue