diff options
| author | Daniil Baturin <daniil@vyos.io> | 2026-05-12 12:43:31 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-05-12 12:43:31 +0100 |
| commit | a360670bce2e8996ea8e4da5176e695c51cbf01f (patch) | |
| tree | 425505d73d2eb8c57299efeb32e61f7dfd285775 | |
| parent | e959c1da15180a4a4b8399d6cd9a2057a1749e4d (diff) | |
| parent | e514f728cd48478e88543f6e9e5c6c9423b8e0df (diff) | |
| download | vyos-1x-a360670bce2e8996ea8e4da5176e695c51cbf01f.tar.gz vyos-1x-a360670bce2e8996ea8e4da5176e695c51cbf01f.zip | |
Merge pull request #5180 from jestabro/override-help-text
T8360: add XML preprocessor to allow overriding help element
| -rw-r--r-- | Makefile | 1 | ||||
| -rwxr-xr-x | scripts/override-help | 115 |
2 files changed, 116 insertions, 0 deletions
@@ -32,6 +32,7 @@ interface_definitions: libvyosconfig $(config_xml_obj) rm -rf $(TMPL_DIR); mkdir -p $(TMPL_DIR) $(CURDIR)/scripts/override-default $(BUILD_DIR)/interface-definitions + $(CURDIR)/scripts/override-help $(BUILD_DIR)/interface-definitions find $(BUILD_DIR)/interface-definitions -type f -name "*.xml" | xargs -I {} $(CURDIR)/scripts/build-command-templates {} $(CURDIR)/schema/interface_definition.rng $(TMPL_DIR) || exit 1 diff --git a/scripts/override-help b/scripts/override-help new file mode 100755 index 000000000..16c74bbed --- /dev/null +++ b/scripts/override-help @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# +# Copyright (C) VyOS Inc. +# +# 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/>. +# +# + +# Use lxml xpath capability to find multiple elements with tag help +# relative to path; copy and replace to override the initial value. + +import sys +import glob +import logging +from copy import deepcopy +from lxml import etree + +debug = False + +logger = logging.getLogger(__name__) +logs_handler = logging.StreamHandler() +logger.addHandler(logs_handler) + +if debug: + logger.setLevel(logging.DEBUG) +else: + logger.setLevel(logging.INFO) + + +def override_element(lst: list): + """ + Allow multiple override elements; use the final one (in document order). + """ + if len(lst) < 2: + logger.debug('passing list of single element to override_element') + return + + # replace element with final override + first_element = lst[0] + # lxml will remove on replace, hence make a copy to avoid cleaning up + # empty elements + final_element = deepcopy(lst[-1]) + parent = first_element.getparent() + parent.replace(first_element, final_element) + + +def collect_and_override(dir_name): + # pylint: disable=too-many-locals,c-extension-no-member + """ + Collect elements with help 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 = '//help' + 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) + defv.setdefault(ap_path_str, []).append(element) + + trivial = [] + for k, v in defv.items(): + if len(v) < 2: + trivial.append(k) + for i in trivial: + del defv[i] + + for k, v in defv.items(): + text_set = set() + for e in v: + text_set.add(e.text) + if len(text_set) > 1: + logger.debug(f'Inconsistent help elements in file {fname}:') + for e in v: + logger.debug( + f'Element is {e.tag} with content {e.text} at {e.sourceline}' + ) + + logger.info(f"overriding help in path '{k}'") + override_element(v) + + revised_str = etree.tostring(root, encoding='unicode', pretty_print=True) + + with open(f'{fname}', 'w') as f: + f.write(revised_str) + + +def main(): + if len(sys.argv) < 2: + logger.critical('Must specify XML directory!') + sys.exit(1) + + dir_name = sys.argv[1] + + collect_and_override(dir_name) + + +if __name__ == '__main__': + main() |
