diff --git a/docs/api-documentation.md b/docs/api-documentation.md index cf49a2f..7a3aed6 100644 --- a/docs/api-documentation.md +++ b/docs/api-documentation.md @@ -445,6 +445,7 @@ finalize the dependencies within the stash #### GetRecipes ```python +@functools.cache def GetRecipes() -> None ``` @@ -459,6 +460,7 @@ Get bb files in stash #### GetLoneAppends ```python +@functools.cache def GetLoneAppends() -> List[str] ``` @@ -473,6 +475,7 @@ Get bbappend without a matching bb #### GetConfFiles ```python +@functools.cache def GetConfFiles() -> List[str] ``` @@ -487,6 +490,7 @@ Get configurations files #### GetLinksForFile ```python +@functools.cache def GetLinksForFile(filename: str) -> List[str] ``` @@ -506,7 +510,7 @@ Get file which this file is linked against #### Reduce ```python -def Reduce(in_list: List[Item], +def Reduce(in_list: Iterable[Item], filename: str = None, classifier: Union[Iterable[str], str] = None, attribute: Union[Iterable[str], str] = None, @@ -587,6 +591,7 @@ Expand variable to dictionary #### GetFiles ```python +@functools.cache def GetFiles(_file: str, pattern: str) -> List[str] ``` @@ -607,6 +612,7 @@ Get files matching SRC_URI entries #### GetLayerRoot ```python +@functools.cache def GetLayerRoot(name: str) -> str ``` @@ -626,6 +632,7 @@ Find the path to the layer root of a file #### FindLocalOrLayer ```python +@functools.cache def FindLocalOrLayer(name: str, localdir: str) -> str ``` @@ -646,6 +653,7 @@ Find file in local dir or in layer #### GetScrComponents ```python +@functools.cache def GetScrComponents(string: str) -> dict ``` @@ -665,6 +673,7 @@ Return SRC_URI components #### SafeLineSplit ```python +@functools.cache def SafeLineSplit(string: str) -> List[str] ``` @@ -684,6 +693,7 @@ Split line in a safe manner #### GuessRecipeName ```python +@functools.cache def GuessRecipeName(_file: str) -> str ``` @@ -703,6 +713,7 @@ Get the recipe name from filename #### GuessBaseRecipeName ```python +@functools.cache def GuessBaseRecipeName(_file: str) -> str ``` @@ -722,6 +733,7 @@ Get the base recipe name from filename (aka BPN) #### GuessRecipeVersion ```python +@functools.cache def GuessRecipeVersion(_file: str) -> str ``` @@ -766,6 +778,7 @@ Expand a variable (replacing all variables by known content) #### GetValidPackageNames ```python +@functools.cache def GetValidPackageNames(_file: str, strippn: bool = False) -> List[str] ``` @@ -786,6 +799,7 @@ Get known valid names for packages #### GetValidNamedResources ```python +@functools.cache def GetValidNamedResources(_file: str) -> List[str] ``` @@ -805,6 +819,7 @@ Get list of valid SRCREV resource names #### IsImage ```python +@functools.cache def IsImage(_file: str) -> bool ``` @@ -824,6 +839,7 @@ returns if the file is likely an image recipe or not #### IsPackageGroup ```python +@functools.cache def IsPackageGroup(_file: str) -> bool ``` diff --git a/oelint_parser/cls_stash.py b/oelint_parser/cls_stash.py index 6a61ea0..89a84ad 100644 --- a/oelint_parser/cls_stash.py +++ b/oelint_parser/cls_stash.py @@ -1,3 +1,4 @@ +import functools import glob import os from collections import UserList @@ -120,9 +121,23 @@ def __init__(self, quiet: bool = False, new_style_override_syntax: bool = False, self.__new_style_override_syntax = new_style_override_syntax self.__negative_inline = negative_inline - self.__getconffiles_cached_values = None - self.__getrecipes_cached_values = None - self.__getloneappends_cached_values = None + self._clear_cached() + + def _clear_cached(self): + """Clear cached values""" + self.GetConfFiles.cache_clear() + self.GetFiles.cache_clear() + self.GetLinksForFile.cache_clear() + self.GetLoneAppends.cache_clear() + self.GetRecipes.cache_clear() + self.GetValidNamedResources.cache_clear() + self.GetValidPackageNames.cache_clear() + self.IsImage.cache_clear() + self.IsPackageGroup.cache_clear() + self.__get_items_by_attribute.cache_clear() + self.__get_items_by_classifier.cache_clear() + self.__get_items_by_file.cache_clear() + self.__is_linked_to.cache_clear() def AddFile(self, _file: str, lineOffset: int = 0, forcedLink: str = None) -> List[Item]: """Adds a file to the stash @@ -173,9 +188,7 @@ def AddFile(self, _file: str, lineOffset: int = 0, forcedLink: str = None) -> Li self.__list += res # Reset caches - self.__getconffiles_cached_values = None - self.__getrecipes_cached_values = None - self.__getloneappends_cached_values = None + self._clear_cached() return res @@ -191,6 +204,9 @@ def Append(self, item: Union[Item, Iterable[Item]]) -> None: else: self.__list.append(item) + # Reset caches + self._clear_cached() + def Remove(self, item: Union[Item, Iterable[Item]]) -> None: """removes one or more items from the stash @@ -203,6 +219,9 @@ def Remove(self, item: Union[Item, Iterable[Item]]) -> None: else: self.__list.remove(item) + # Reset caches + self._clear_cached() + def AddDistroMachineFromLayer(self, path: str) -> None: """adds machine and distro configuration from the layer of the provided file @@ -226,55 +245,58 @@ def Finalize(self) -> None: for item in self.__map[k][:]: self.__map[k] += self.__map[item] self.__map[k] = list(set(self.__map[k])) + # Reset caches + self._clear_cached() + @functools.lru_cache def GetRecipes(self) -> None: """Get bb files in stash Returns: list -- List of bb files in stash """ - if self.__getrecipes_cached_values is None: - self.__getrecipes_cached_values = sorted({x.Origin for x in self.__list if x.Origin.endswith(".bb")}) - return self.__getrecipes_cached_values + return sorted({x.Origin for x in self.__list if x.Origin.endswith(".bb")}) + @functools.lru_cache def GetLoneAppends(self) -> List[str]: """Get bbappend without a matching bb Returns: list -- list of bbappend without a matching bb """ - if self.__getloneappends_cached_values is None: - __linked_appends = set() - __appends = {x.Origin for x in self.__list if x.Origin.endswith('.bbappend')} - for k, v in self.__map.items(): - if k.endswith('.bb'): - __linked_appends.update(x for x in v if x.endswith('.bbappend')) - self.__getloneappends_cached_values = sorted({x for x in __appends if x not in __linked_appends}) - return self.__getloneappends_cached_values - + __linked_appends = set() + __appends = {x.Origin for x in self.__list if x.Origin.endswith('.bbappend')} + for k, v in self.__map.items(): + if k.endswith('.bb'): + __linked_appends.update(x for x in v if x.endswith('.bbappend')) + return sorted({x for x in __appends if x not in __linked_appends}) + + @functools.lru_cache def GetConfFiles(self) -> List[str]: """Get configurations files Returns: List[str]: List of configuration files """ - if self.__getconffiles_cached_values is None: - self.__getconffiles_cached_values = list({x.Origin for x in self.__list if x.Origin.endswith(".conf")}) - return self.__getconffiles_cached_values + return list({x.Origin for x in self.__list if x.Origin.endswith(".conf")}) + @functools.lru_cache def __is_linked_to(self, item: Item, filename: str, nolink: bool = False) -> bool: return (item.Origin in self.__map.get(filename, {}) and not nolink) or filename == item.Origin + @functools.lru_cache def __get_items_by_file(self, items: Iterable[Item], filename: str, nolink: bool = False) -> List[Item]: if not filename: return items return [x for x in items if self.__is_linked_to(x, filename, nolink=nolink)] + @functools.lru_cache def __get_items_by_classifier(self, items: Iterable[Item], classifier: Iterable[str]) -> List[Item]: if not classifier: return items return [x for x in items if x.CLASSIFIER in classifier] + @functools.lru_cache def __get_items_by_attribute(self, items: Iterable[Item], attname: Iterable[str], attvalue: Iterable[str]) -> List[Item]: if not attname: return items @@ -288,6 +310,7 @@ def _filter(x: Item, attname: Iterable[str], attvalue: Iterable[str]) -> bool: return [x for x in items if _filter(x, attname, attvalue)] + @functools.lru_cache def GetLinksForFile(self, filename: str) -> List[str]: """Get file which this file is linked against @@ -302,7 +325,7 @@ def GetLinksForFile(self, filename: str) -> List[str]: return [x.Origin for x in self.__get_items_by_file(self.__list, filename) if x.Origin != filename] def Reduce(self, - in_list: List[Item], + in_list: Iterable[Item], filename: str = None, classifier: Union[Iterable[str], str] = None, attribute: Union[Iterable[str], str] = None, @@ -328,11 +351,11 @@ def Reduce(self, if not isinstance(attributeValue, (list, set, tuple)): attributeValue = [attributeValue] if attributeValue else [] if filename: - in_list = self.__get_items_by_file(in_list, filename, nolink=nolink) + in_list = self.__get_items_by_file(tuple(in_list), filename, nolink=nolink) if classifier: - in_list = self.__get_items_by_classifier(in_list, classifier) + in_list = self.__get_items_by_classifier(tuple(in_list), tuple(classifier)) if attribute: - in_list = self.__get_items_by_attribute(in_list, attribute, attributeValue) + in_list = self.__get_items_by_attribute(tuple(in_list), tuple(attribute), tuple(attributeValue)) return sorted(set(in_list), key=lambda x: x.Line) def GetItemsFor(self, @@ -353,12 +376,12 @@ def GetItemsFor(self, Returns: Stash.StashList: Returns a list of items fitting the set filters """ - res = Stash.StashList(self, self.__list) - res.reduce(filename=filename, - classifier=classifier, - attribute=attribute, - attributeValue=attributeValue, - nolink=nolink) + res = Stash.StashList(self, self.Reduce(self.__list, + filename=filename, + classifier=classifier, + attribute=attribute, + attributeValue=attributeValue, + nolink=nolink)) return res def ExpandVar(self, @@ -474,6 +497,7 @@ def ExpandVar(self, self.ExpandTerm(filename, v or "")) return _finalexp + @functools.lru_cache def GetFiles(self, _file: str, pattern: str) -> List[str]: """Get files matching SRC_URI entries @@ -496,6 +520,7 @@ def GetFiles(self, _file: str, pattern: str) -> List[str]: res.update(glob.glob(item)) return sorted(res) + @functools.lru_cache def GetLayerRoot(self, name: str) -> str: """Find the path to the layer root of a file @@ -514,6 +539,7 @@ def GetLayerRoot(self, name: str) -> str: return _curdir return "" + @functools.lru_cache def FindLocalOrLayer(self, name: str, localdir: str) -> str: """Find file in local dir or in layer @@ -546,6 +572,7 @@ def _replace_with_known_mirrors(self, _in: dict) -> dict: _in = _in.replace(k, v) return _in + @functools.lru_cache def GetScrComponents(self, string: str) -> dict: """Return SRC_URI components @@ -567,6 +594,7 @@ def GetScrComponents(self, string: str) -> dict: for x in _options if "=" in x} return {"scheme": _scheme, "src": _path, "options": _parsed_opt} + @functools.lru_cache def SafeLineSplit(self, string: str) -> List[str]: """Split line in a safe manner @@ -578,6 +606,7 @@ def SafeLineSplit(self, string: str) -> List[str]: """ return RegexRpl.split(r"\s|\t|\x1b", string) + @functools.lru_cache def GuessRecipeName(self, _file: str) -> str: """Get the recipe name from filename @@ -590,6 +619,7 @@ def GuessRecipeName(self, _file: str) -> str: _name, _ = os.path.splitext(os.path.basename(_file)) return _name.split("_")[0] + @functools.lru_cache def GuessBaseRecipeName(self, _file: str) -> str: """Get the base recipe name from filename (aka BPN) @@ -604,6 +634,7 @@ def GuessBaseRecipeName(self, _file: str) -> str: tmp_ = RegexRpl.sub(r"^(.+)(-cross)$", r"\1", tmp_) return tmp_ + @functools.lru_cache def GuessRecipeVersion(self, _file: str) -> str: """Get recipe version from filename @@ -667,6 +698,7 @@ def ExpandTerm(self, _file: str, value: str, spare: List[str] = None, seen: List continue return res + @functools.lru_cache def GetValidPackageNames(self, _file: str, strippn: bool = False) -> List[str]: """Get known valid names for packages @@ -696,6 +728,7 @@ def GetValidPackageNames(self, _file: str, strippn: bool = False) -> List[str]: res.add(_pkg) return res + @functools.lru_cache def GetValidNamedResources(self, _file: str) -> List[str]: """Get list of valid SRCREV resource names @@ -717,6 +750,7 @@ def GetValidNamedResources(self, _file: str) -> List[str]: res.add(_url["options"]["name"].replace("${PN}", _recipe_name)) return res + @functools.lru_cache def IsImage(self, _file: str) -> bool: """returns if the file is likely an image recipe or not @@ -738,6 +772,7 @@ def IsImage(self, _file: str) -> bool: return res + @functools.lru_cache def IsPackageGroup(self, _file: str) -> bool: """returns if the file is likely a packagegroup recipe or not