diff --git a/tools/python/jwutils/Config.py b/tools/python/jwutils/Config.py index 89b01e0..e7dd364 100644 --- a/tools/python/jwutils/Config.py +++ b/tools/python/jwutils/Config.py @@ -158,3 +158,9 @@ class Config(): # export @property def name(self): return self.__conf.content + + def find(self, key: str|None, val: str|None, match:StringTree.Match=StringTree.Match.Equal) -> list[str]: + return self.__conf.find(key, val, match=match) + + #def __getattr__(self, name: str): + # return getattr(self.__conf, name) diff --git a/tools/python/jwutils/stree/StringTree.py b/tools/python/jwutils/stree/StringTree.py index 581fba9..d6f8a31 100644 --- a/tools/python/jwutils/stree/StringTree.py +++ b/tools/python/jwutils/stree/StringTree.py @@ -1,7 +1,11 @@ from __future__ import annotations -from collections import OrderedDict + from typing import Any, List, Optional, Union +import re, fnmatch +from collections import OrderedDict +from enum import Enum, auto + from jwutils.log import * def quote(s): @@ -227,3 +231,70 @@ class StringTree: # export slog(prio, ",------------" + msg + "----------- >", caller=caller) self.__dump(prio, indent=0, caller=caller) slog(prio, "`------------" + msg + "----------- <", caller=caller) + + class Match(Enum): + Equal = auto() + RegExArg = auto() + RegExConf = auto() + GlobArg = auto() + GlobConf = auto() + + def __find(self, key: str|None, val: str|None, match: Match, depth_first: bool): + + def __children(): + for name, child in self.children.items(): + ret.extend(child.__find(key, val, match, depth_first)) + + def __self(): + _val = self.value() + _content = self.content + try: + if ( + (key == _content and matcher(val, _val)) + or (key is None and matcher(val, _val)) + or (key == _content and val is None) + ): + ret.append(self) + except Exception as e: + if isinstance(e, re.PatternError): + pass + else: + raise + + def __debug_matcher(matcher, log_level=DEBUG): + def __matcher(x, y): + slog(log_level, f'Comparing "{x}" ~ "{y}"') + return matcher(x, y) + return __matcher + + if not self.children: + return [] + + matcher = lambda x, y: x == y + match match: + case self.Match.Equal: + pass + case self.Match.RegExArg: + matcher = lambda x, y: re.search(x, y) is not None + case self.Match.RegExConf: + matcher = lambda x, y: re.search(y, x) is not None + case self.Match.GlobArg: + matcher = lambda x, y: fnmatch.fnmatch(y, x) + case self.Match.GlobConf: + matcher = lambda x, y: fnmatch.fnmatch(x, y) + case _: + raise NotImplementedError(f'Matcher {match} is not yet implemented') + + ret = [] + + if depth_first: + __children() + __self() + else: + __self() + __children() + + return ret + + def find(self, key: str|None=None, val: str|None=None, match: Match=Match.Equal, depth_first: bool=False): + return [ node.parent.path for node in self.__find(key, val, match=match, depth_first=depth_first)]