diff options
Diffstat (limited to 'python/vyos/xml/definition.py')
-rw-r--r-- | python/vyos/xml/definition.py | 360 |
1 files changed, 0 insertions, 360 deletions
diff --git a/python/vyos/xml/definition.py b/python/vyos/xml/definition.py deleted file mode 100644 index bc3892b42..000000000 --- a/python/vyos/xml/definition.py +++ /dev/null @@ -1,360 +0,0 @@ -# Copyright (C) 2020 VyOS maintainers and contributors -# -# This library is free software; you can redistribute it and/or modify it under the terms of -# the GNU Lesser General Public License as published by the Free Software Foundation; -# either version 2.1 of the License, or (at your option) any later version. -# -# This library 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 Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License along with this library; -# if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from vyos.xml import kw - -# As we index by key, the name is first and then the data: -# {'dummy': { -# '[node]': '[tagNode]', -# 'address': { ... } -# } } - -# so when we encounter a tagNode, we are really encountering -# the tagNode data. - - -class XML(dict): - def __init__(self): - self[kw.tree] = {} - self[kw.priorities] = {} - self[kw.owners] = {} - self[kw.default] = {} - self[kw.tags] = [] - self[kw.component_version] = {} - - dict.__init__(self) - - self.tree = self[kw.tree] - # the options which matched the last incomplete world we had - # or the last word in a list - self.options = [] - # store all the part of the command we processed - self.inside = [] - # should we check the data pass with the constraints - self.check = False - # are we still typing a word - self.filling = False - # do what have the tagNode value ? - self.filled = False - # last word seen - self.word = '' - # do we have all the data we want ? - self.final = False - # do we have too much data ? - self.extra = False - # what kind of node are we in plain vs data not - self.plain = True - - def reset(self): - self.tree = self[kw.tree] - self.options = [] - self.inside = [] - self.check = False - self.filling = False - self.filled = False - self.word = '' - self.final = False - self.extra = False - self.plain = True - - # from functools import lru_cache - # @lru_cache(maxsize=100) - # XXX: need to use cachetool instead - for later - - def traverse(self, cmd): - self.reset() - - # using split() intead of split(' ') eats the final ' ' - words = cmd.split(' ') - passed = [] - word = '' - data_node = False - space = False - - while words: - word = words.pop(0) - space = word == '' - perfect = False - if word in self.tree: - passed = [] - perfect = True - self.tree = self.tree[word] - data_node = self.tree[kw.node] - self.inside.append(word) - word = '' - continue - if word and data_node: - passed.append(word) - - is_valueless = self.tree.get(kw.valueless, False) - is_leafNode = data_node == kw.leafNode - is_dataNode = data_node in (kw.leafNode, kw.tagNode) - named_options = [_ for _ in self.tree if not kw.found(_)] - - if is_leafNode: - self.final = is_valueless or len(passed) > 0 - self.extra = is_valueless and len(passed) > 0 - self.check = len(passed) >= 1 - else: - self.final = False - self.extra = False - self.check = len(passed) == 1 and not space - - if self.final: - self.word = ' '.join(passed) - else: - self.word = word - - if self.final: - self.filling = True - else: - self.filling = not perfect and bool(cmd and word != '') - - self.filled = self.final or (is_dataNode and len(passed) > 0 and word == '') - - if is_dataNode and len(passed) == 0: - self.options = [] - elif word: - if data_node != kw.plainNode or len(passed) == 1: - self.options = [_ for _ in self.tree if _.startswith(word)] - self.options.sort() - else: - self.options = [] - else: - self.options = named_options - self.options.sort() - - self.plain = not is_dataNode - - # self.debug() - - return self.word - - def speculate(self): - if len(self.options) == 1: - self.tree = self.tree[self.options[0]] - self.word = '' - if self.tree.get(kw.node,'') not in (kw.tagNode, kw.leafNode): - self.options = [_ for _ in self.tree if not kw.found(_)] - self.options.sort() - - def checks(self, cmd): - # as we move thought the named node twice - # the first time we get the data with the node - # and the second with the pass parameters - xml = self[kw.tree] - - words = cmd.split(' ') - send = True - last = [] - while words: - word = words.pop(0) - if word in xml: - xml = xml[word] - send = True - last = [] - continue - if xml[kw.node] in (kw.tagNode, kw.leafNode): - if kw.constraint in xml: - if send: - yield (word, xml[kw.constraint]) - send = False - else: - last.append((word, None)) - if len(last) >= 2: - yield last[0] - - def summary(self): - yield ('enter', '[ summary ]', str(self.inside)) - - if kw.help not in self.tree: - yield ('skip', '[ summary ]', str(self.inside)) - return - - if self.filled: - return - - yield('', '', '\nHelp:') - - if kw.help in self.tree: - summary = self.tree[kw.help].get(kw.summary) - values = self.tree[kw.help].get(kw.valuehelp, []) - if summary: - yield(summary, '', '') - for value in values: - yield(value[kw.format], value[kw.description], '') - - def constraint(self): - yield ('enter', '[ constraint ]', str(self.inside)) - - if kw.help in self.tree: - yield ('skip', '[ constraint ]', str(self.inside)) - return - if kw.error not in self.tree: - yield ('skip', '[ constraint ]', str(self.inside)) - return - if not self.word or self.filling: - yield ('skip', '[ constraint ]', str(self.inside)) - return - - yield('', '', '\nData Constraint:') - - yield('', 'constraint', str(self.tree[kw.error])) - - def listing(self): - yield ('enter', '[ listing ]', str(self.inside)) - - # only show the details when we passed the tagNode data - if not self.plain and not self.filled: - yield ('skip', '[ listing ]', str(self.inside)) - return - - yield('', '', '\nPossible completions:') - - options = list(self.tree.keys()) - options.sort() - for option in options: - if kw.found(option): - continue - if not option.startswith(self.word): - continue - inner = self.tree[option] - prefix = '+> ' if inner.get(kw.node, '') != kw.leafNode else ' ' - if kw.help in inner: - yield (prefix + option, inner[kw.help].get(kw.summary), '') - else: - yield (prefix + option, '(no help available)', '') - - def debug(self): - print('------') - print("word '%s'" % self.word) - print("filling " + str(self.filling)) - print("filled " + str(self.filled)) - print("final " + str(self.final)) - print("extra " + str(self.extra)) - print("plain " + str(self.plain)) - print("options " + str(self.options)) - - # from functools import lru_cache - # @lru_cache(maxsize=100) - # XXX: need to use cachetool instead - for later - - def component_version(self) -> dict: - d = {} - for k in sorted(self[kw.component_version]): - d[k] = int(self[kw.component_version][k]) - return d - - def defaults(self, lpath, flat): - d = self[kw.default] - for k in lpath: - d = d.get(k, {}) - - if not flat: - # _flatten will make this conversion - d = self.multi_to_list(lpath, d, defaults=True) - - r = {} - for k in d: - under = k.replace('-','_') - if isinstance(d[k],dict): - r[under] = self.defaults(lpath + [k], flat) - continue - r[under] = d[k] - return r - - def _flatten(inside, index, d): - r = {} - local = inside[index:] - prefix = '_'.join(_.replace('-','_') for _ in local) + '_' if local else '' - for k in d: - under = prefix + k.replace('-','_') - level = inside + [k] - if isinstance(d[k],dict): - r.update(_flatten(level, index, d[k])) - continue - if self.is_multi(level, with_tag=False): - r[under] = [_.strip() for _ in d[k].split(',')] - continue - r[under] = d[k] - return r - - return _flatten(lpath, len(lpath), d) - - def multi_to_list(self, lpath, conf, defaults=False): - r = {} - for k in conf: - # key mangling could also be done here - # it would prevent two parsing of the config tree - # under = k.replace('-','_') - under = k - fpath = lpath + [k] - if isinstance(conf[k],dict): - r[under] = self.multi_to_list(fpath, conf[k], defaults) - continue - value = conf[k] - if self.is_multi(fpath) and not isinstance(value, list): - if not defaults: - value = [value] - else: - value = value.split(' ') - r[under] = value - return r - - # from functools import lru_cache - # @lru_cache(maxsize=100) - # XXX: need to use cachetool instead - for later - - def _tree(self, lpath, with_tag=True): - """ - returns the part of the tree searched or None if it does not exists - if with_tag is set, this is a configuration path (with tagNode names) - and tag name will be removed from the path when traversing the tree - """ - tree = self[kw.tree] - spath = lpath.copy() - while spath: - p = spath.pop(0) - if p not in tree: - return None - tree = tree[p] - if with_tag and spath and tree[kw.node] == kw.tagNode: - spath.pop(0) - return tree - - def _get(self, lpath, tag, with_tag=True): - tree = self._tree(lpath, with_tag) - if tree is None: - return None - return tree.get(tag, None) - - def is_multi(self, lpath, with_tag=True): - tree = self._get(lpath, kw.multi, with_tag) - if tree is None: - return None - return tree is True - - def is_tag(self, lpath, with_tag=True): - tree = self._get(lpath, kw.node, with_tag) - if tree is None: - return None - return tree == kw.tagNode - - def is_leaf(self, lpath, with_tag=True): - tree = self._get(lpath, kw.node, with_tag) - if tree is None: - return None - return tree == kw.leafNode - - def exists(self, lpath, with_tag=True): - return self._get(lpath, kw.node, with_tag) is not None |