|
|
@@ -12,6 +12,10 @@ import sys
|
|
|
import confgen
|
|
|
from confgen import FatalError, __version__
|
|
|
|
|
|
+# Min/Max supported protocol versions
|
|
|
+MIN_PROTOCOL_VERSION = 1
|
|
|
+MAX_PROTOCOL_VERSION = 2
|
|
|
+
|
|
|
|
|
|
def main():
|
|
|
parser = argparse.ArgumentParser(description='confserver.py v%s - Config Generation Tool' % __version__, prog=os.path.basename(sys.argv[0]))
|
|
|
@@ -27,8 +31,19 @@ def main():
|
|
|
parser.add_argument('--env', action='append', default=[],
|
|
|
help='Environment to set when evaluating the config file', metavar='NAME=VAL')
|
|
|
|
|
|
+ parser.add_argument('--version', help='Set protocol version to use on initial status',
|
|
|
+ type=int, default=MAX_PROTOCOL_VERSION)
|
|
|
+
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
+ if args.version < MIN_PROTOCOL_VERSION:
|
|
|
+ print("Version %d is older than minimum supported protocol version %d. Client is much older than ESP-IDF version?" %
|
|
|
+ (args.version, MIN_PROTOCOL_VERSION))
|
|
|
+
|
|
|
+ if args.version > MAX_PROTOCOL_VERSION:
|
|
|
+ print("Version %d is newer than maximum supported protocol version %d. Client is newer than ESP-IDF version?" %
|
|
|
+ (args.version, MAX_PROTOCOL_VERSION))
|
|
|
+
|
|
|
try:
|
|
|
args.env = [(name,value) for (name,value) in (e.split("=",1) for e in args.env)]
|
|
|
except ValueError:
|
|
|
@@ -38,17 +53,26 @@ def main():
|
|
|
for name, value in args.env:
|
|
|
os.environ[name] = value
|
|
|
|
|
|
- print("Server running, waiting for requests on stdin...", file=sys.stderr)
|
|
|
run_server(args.kconfig, args.config)
|
|
|
|
|
|
|
|
|
-def run_server(kconfig, sdkconfig):
|
|
|
+def run_server(kconfig, sdkconfig, default_version=MAX_PROTOCOL_VERSION):
|
|
|
config = kconfiglib.Kconfig(kconfig)
|
|
|
config.load_config(sdkconfig)
|
|
|
|
|
|
+ print("Server running, waiting for requests on stdin...", file=sys.stderr)
|
|
|
+
|
|
|
config_dict = confgen.get_json_values(config)
|
|
|
ranges_dict = get_ranges(config)
|
|
|
- json.dump({"version": 1, "values": config_dict, "ranges": ranges_dict}, sys.stdout)
|
|
|
+ visible_dict = get_visible(config)
|
|
|
+
|
|
|
+ if default_version == 1:
|
|
|
+ # V1: no 'visibility' key, send value None for any invisible item
|
|
|
+ values_dict = dict((k, v if visible_dict[k] else False) for (k,v) in config_dict.items())
|
|
|
+ json.dump({"version": 1, "values": values_dict, "ranges": ranges_dict}, sys.stdout)
|
|
|
+ else:
|
|
|
+ # V2 onwards: separate visibility from version
|
|
|
+ json.dump({"version": default_version, "values": config_dict, "ranges": ranges_dict, "visible": visible_dict}, sys.stdout)
|
|
|
print("\n")
|
|
|
|
|
|
while True:
|
|
|
@@ -58,10 +82,12 @@ def run_server(kconfig, sdkconfig):
|
|
|
req = json.loads(line)
|
|
|
before = confgen.get_json_values(config)
|
|
|
before_ranges = get_ranges(config)
|
|
|
+ before_visible = get_visible(config)
|
|
|
|
|
|
if "load" in req: # if we're loading a different sdkconfig, response should have all items in it
|
|
|
before = {}
|
|
|
before_ranges = {}
|
|
|
+ before_visible = {}
|
|
|
|
|
|
# if no new filename is supplied, use existing sdkconfig path, otherwise update the path
|
|
|
if req["load"] is None:
|
|
|
@@ -79,10 +105,19 @@ def run_server(kconfig, sdkconfig):
|
|
|
|
|
|
after = confgen.get_json_values(config)
|
|
|
after_ranges = get_ranges(config)
|
|
|
+ after_visible = get_visible(config)
|
|
|
|
|
|
values_diff = diff(before, after)
|
|
|
ranges_diff = diff(before_ranges, after_ranges)
|
|
|
- response = {"version": 1, "values": values_diff, "ranges": ranges_diff}
|
|
|
+ visible_diff = diff(before_visible, after_visible)
|
|
|
+ if req["version"] == 1:
|
|
|
+ # V1 response, invisible items have value None
|
|
|
+ for k in (k for (k,v) in visible_diff.items() if not v):
|
|
|
+ values_diff[k] = None
|
|
|
+ response = {"version": 1, "values": values_diff, "ranges": ranges_diff}
|
|
|
+ else:
|
|
|
+ # V2+ response, separate visibility values
|
|
|
+ response = {"version": req["version"], "values": values_diff, "ranges": ranges_diff, "visible": visible_diff}
|
|
|
if error:
|
|
|
for e in error:
|
|
|
print("Error: %s" % e, file=sys.stderr)
|
|
|
@@ -94,8 +129,12 @@ def run_server(kconfig, sdkconfig):
|
|
|
def handle_request(config, req):
|
|
|
if "version" not in req:
|
|
|
return ["All requests must have a 'version'"]
|
|
|
- if int(req["version"]) != 1:
|
|
|
- return ["Only version 1 requests supported"]
|
|
|
+
|
|
|
+ if req["version"] < MIN_PROTOCOL_VERSION or req["version"] > MAX_PROTOCOL_VERSION:
|
|
|
+ return ["Unsupported request version %d. Server supports versions %d-%d" % (
|
|
|
+ req["version"],
|
|
|
+ MIN_PROTOCOL_VERSION,
|
|
|
+ MAX_PROTOCOL_VERSION)]
|
|
|
|
|
|
error = []
|
|
|
|
|
|
@@ -154,12 +193,10 @@ def handle_set(config, error, to_set):
|
|
|
|
|
|
def diff(before, after):
|
|
|
"""
|
|
|
- Return a dictionary with the difference between 'before' and 'after' (either with the new value if changed,
|
|
|
- or None as the value if a key in 'before' is missing in 'after'
|
|
|
+ Return a dictionary with the difference between 'before' and 'after',
|
|
|
+ for items which are present in 'after' dictionary
|
|
|
"""
|
|
|
diff = dict((k,v) for (k,v) in after.items() if before.get(k, None) != v)
|
|
|
- hidden = dict((k,None) for k in before if k not in after)
|
|
|
- diff.update(hidden)
|
|
|
return diff
|
|
|
|
|
|
|
|
|
@@ -178,6 +215,35 @@ def get_ranges(config):
|
|
|
return ranges_dict
|
|
|
|
|
|
|
|
|
+def get_visible(config):
|
|
|
+ """
|
|
|
+ Return a dict mapping node IDs (config names or menu node IDs) to True/False for their visibility
|
|
|
+ """
|
|
|
+ result = {}
|
|
|
+ menus = []
|
|
|
+
|
|
|
+ # when walking the menu the first time, only
|
|
|
+ # record whether the config symbols are visible
|
|
|
+ # and make a list of menu nodes (that are not symbols)
|
|
|
+ def handle_node(node):
|
|
|
+ sym = node.item
|
|
|
+ try:
|
|
|
+ visible = (sym.visibility != 0)
|
|
|
+ result[node] = visible
|
|
|
+ except AttributeError:
|
|
|
+ menus.append(node)
|
|
|
+ config.walk_menu(handle_node)
|
|
|
+
|
|
|
+ # now, figure out visibility for each menu. A menu is visible if any of its children are visible
|
|
|
+ for m in reversed(menus): # reverse to start at leaf nodes
|
|
|
+ result[m] = any(v for (n,v) in result.items() if n.parent == m)
|
|
|
+
|
|
|
+ # return a dict mapping the node ID to its visibility.
|
|
|
+ result = dict((confgen.get_menu_node_id(n),v) for (n,v) in result.items())
|
|
|
+
|
|
|
+ return result
|
|
|
+
|
|
|
+
|
|
|
if __name__ == '__main__':
|
|
|
try:
|
|
|
main()
|