diff options
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/build-command-templates | 76 | ||||
-rwxr-xr-x | scripts/override-default | 38 | ||||
-rwxr-xr-x | scripts/transclude-template | 50 |
3 files changed, 128 insertions, 36 deletions
diff --git a/scripts/build-command-templates b/scripts/build-command-templates index 452c420eb..d8abb0a13 100755 --- a/scripts/build-command-templates +++ b/scripts/build-command-templates @@ -86,6 +86,37 @@ def make_path(l): print(path) return path +def collect_validators(ve): + regexes = [] + regex_elements = ve.findall("regex") + if regex_elements is not None: + regexes = list(map(lambda e: e.text.strip().replace('\\','\\\\'), regex_elements)) + if "" in regexes: + print("Warning: empty regex, node will be accepting any value") + + validator_elements = ve.findall("validator") + validators = [] + if validator_elements is not None: + for v in validator_elements: + v_name = os.path.join(validator_dir, v.get("name")) + + # XXX: lxml returns None for empty arguments + v_argument = None + try: + v_argument = v.get("argument") + except: + pass + if v_argument is None: + v_argument = "" + + validators.append("{0} {1}".format(v_name, v_argument)) + + + regex_args = " ".join(map(lambda s: "--regex \\\'{0}\\\'".format(s), regexes)) + validator_args = " ".join(map(lambda s: "--exec \\\"{0}\\\"".format(s), validators)) + + return regex_args + " " + validator_args + def get_properties(p): props = {} @@ -108,7 +139,8 @@ def get_properties(p): except: props["val_help"] = [] - # Get the constraint statements + # Get the constraint and constraintGroup statements + error_msg = default_constraint_err_msg # Get the error message if it's there try: @@ -117,40 +149,24 @@ def get_properties(p): pass vce = p.find("constraint") - vc = [] + + distinct_validator_string = "" if vce is not None: # The old backend doesn't support multiple validators in OR mode # so we emulate it - regexes = [] - regex_elements = vce.findall("regex") - if regex_elements is not None: - regexes = list(map(lambda e: e.text.strip().replace('\\','\\\\'), regex_elements)) - if "" in regexes: - print("Warning: empty regex, node will be accepting any value") - - validator_elements = vce.findall("validator") - validators = [] - if validator_elements is not None: - for v in validator_elements: - v_name = os.path.join(validator_dir, v.get("name")) - - # XXX: lxml returns None for empty arguments - v_argument = None - try: - v_argument = v.get("argument") - except: - pass - if v_argument is None: - v_argument = "" - - validators.append("{0} {1}".format(v_name, v_argument)) - - - regex_args = " ".join(map(lambda s: "--regex \\\'{0}\\\'".format(s), regexes)) - validator_args = " ".join(map(lambda s: "--exec \\\"{0}\\\"".format(s), validators)) + distinct_validator_string = collect_validators(vce) + + vcge = p.findall("constraintGroup") + + group_validator_string = "" + if len(vcge): + for vcg in vcge: + group_validator_string = group_validator_string + " --grp " + collect_validators(vcg) + + if vce is not None or len(vcge): validator_script = '${vyos_libexec_dir}/validate-value' - validator_string = "exec \"{0} {1} {2} --value \\\'$VAR(@)\\\'\"; \"{3}\"".format(validator_script, regex_args, validator_args, error_msg) + validator_string = "exec \"{0} {1} {2} --value \\\'$VAR(@)\\\'\"; \"{3}\"".format(validator_script, distinct_validator_string, group_validator_string, error_msg) props["constraint"] = validator_string diff --git a/scripts/override-default b/scripts/override-default index c8a0ff1da..0c49087c8 100755 --- a/scripts/override-default +++ b/scripts/override-default @@ -27,6 +27,7 @@ import sys import glob import logging +from copy import deepcopy from lxml import etree debug = False @@ -60,30 +61,55 @@ def override_element(l: list): for el in parents: el.getparent().remove(el) +def merge_remaining(l: list, elementtree): + """ + Merge (now) single leaf node containing 'defaultValue' with leaf nodes + of same path and no 'defaultValue'. + """ + for p in l: + p = p.split() + path_str = f'/interfaceDefinition/*' + path_list = [] + for i in range(len(p)): + path_list.append(f'[@name="{p[i]}"]') + path_str += '/children/*'.join(path_list) + rp = elementtree.xpath(path_str) + if len(rp) > 1: + for el in rp[1:]: + # in practice there will only be one child of the path, + # either defaultValue or Properties, since + # override_element() has already run + for child in el: + rp[0].append(deepcopy(child)) + el.getparent().remove(el) + def collect_and_override(dir_name): """ - Collect elements with defaultValue tag into dictionary indexed by tuple - of (name: str, ancestor path: str). + Collect elements with defaultValue tag into dictionary indexed by name + attributes of ancestor path. """ for fname in glob.glob(f'{dir_name}/*.xml'): tree = etree.parse(fname) root = tree.getroot() defv = {} - xpath_str = f'//defaultValue' + xpath_str = '//defaultValue' xp = tree.xpath(xpath_str) for element in xp: ap = element.xpath('ancestor::*[@name]') ap_name = [el.get("name") for el in ap] - ap_path_str = ' '.join(ap_name[:-1]) - defv.setdefault((ap_name[-1], ap_path_str), []).append(element) + ap_path_str = ' '.join(ap_name) + defv.setdefault(ap_path_str, []).append(element) for k, v in defv.items(): if len(v) > 1: - logger.info(f"overridding default in {k[0]}, path '{k[1]}'") + logger.info(f"overridding default in path '{k}'") override_element(v) + to_merge = list(defv) + merge_remaining(to_merge, tree) + revised_str = etree.tostring(root, encoding='unicode', pretty_print=True) with open(f'{fname}', 'w') as f: diff --git a/scripts/transclude-template b/scripts/transclude-template new file mode 100755 index 000000000..5c6668a84 --- /dev/null +++ b/scripts/transclude-template @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# transclude-template: preprocessor for XML interface definitions to +# interpret #include statements to include nested XML fragments and +# snippets in documents. +# +# Copyright (C) 2021 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# + +import os +import re +import sys + +regexp = re.compile(r'^ *#include <(.+)>$') + +def parse_file(filename): + lines = "" + with open(filename, 'r') as f: + while True: + line = f.readline() + if line: + result = regexp.match(line) + if result: + lines += parse_file(os.path.join(directory, result.group(1))) + else: + lines += line + else: + return lines + +if __name__ == '__main__': + if len(sys.argv) < 2: + print('Must specify XML file!', file=sys.stderr) + sys.exit(1) + filename = sys.argv[1] + directory = os.path.dirname(os.path.abspath(filename)) + print(parse_file(filename)) + |