Changeset 2c46d2d in rtems-central


Ignore:
Timestamp:
07/28/22 08:51:22 (17 months ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
bb633e2
Parents:
e0980df
git-author:
Sebastian Huber <sebastian.huber@…> (07/28/22 08:51:22)
git-committer:
Sebastian Huber <sebastian.huber@…> (07/28/22 09:26:30)
Message:

items: Add JSONItemCache

Location:
rtemsspec
Files:
2 added
2 edited

Legend:

Unmodified
Added
Removed
  • rtemsspec/items.py

    re0980df r2c46d2d  
    22""" This module provides specification items and an item cache. """
    33
    4 # Copyright (C) 2019, 2021 embedded brains GmbH (http://www.embedded-brains.de)
     4# Copyright (C) 2019, 2022 embedded brains GmbH (http://www.embedded-brains.de)
    55#
    66# Redistribution and use in source and binary forms, with or without
     
    3232import stat
    3333from typing import Any, Callable, Dict, Iterable, Iterator, List, NamedTuple, \
    34     Optional, Set, Tuple, Union
     34    Optional, Set, TextIO, Tuple, Union
     35import json
    3536import yaml
    3637
     
    417418    def save(self):
    418419        """ Saves the item to the corresponding file. """
    419         with open(self.file, "w") as dst:
    420             data = {}
    421             for key, value in self._data.items():
    422                 if not key.startswith("_"):
    423                     data[key] = value
    424             dst.write(
    425                 yaml.dump(data, default_flow_style=False, allow_unicode=True))
     420        self._cache.save_data(self.file, self._data)
    426421
    427422    def load(self):
    428423        """ Loads the item from the corresponding file. """
    429         filename = self.file
    430         with open(filename, "r") as src:
    431             self._data = yaml.safe_load(src.read())
    432             self._data["_file"] = filename
     424        self._data = self._cache.load_data(self.file, self._uid)
    433425
    434426
     
    620612
    621613
    622 def _load_item(path: str, uid: str) -> Any:
     614def _load_yaml_data(path: str, uid: str) -> Any:
    623615    with open(path, "r") as src:
    624616        try:
     
    633625
    634626
     627def _load_json_data(path: str, uid: str) -> Any:
     628    with open(path, "r") as src:
     629        try:
     630            data = json.load(src)
     631        except json.JSONDecodeError as err:
     632            msg = ("JSON error while loading specification item file "
     633                   f"'{path}': {str(err)}")
     634            raise IOError(msg) from err
     635        data["_file"] = os.path.abspath(path)
     636        data["_uid"] = uid
     637    return data
     638
     639
    635640class ItemCache:
    636641    """ This class provides a cache of specification items. """
     
    642647        self._types = set()  # type: Set[str]
    643648        self._updates = 0
    644         cache_dir = os.path.abspath(config["cache-directory"])
    645         for index, path in enumerate(config["paths"]):
    646             self._load_items_recursive(str(index), path, path, cache_dir)
     649        self._load_items(config)
    647650        if post_process_load:
    648651            post_process_load(self._items)
     
    696699        The item is not added to the persistent cache storage.
    697700        """
    698         return self.add_volatile_item(uid, _load_item(path, uid))
     701        return self.add_volatile_item(uid, self.load_data(path, uid))
    699702
    700703    def _add_item(self, uid: str, data: Any) -> Item:
     
    713716                    uid = "/" + os.path.relpath(path2, base).replace(
    714717                        ".yml", "")
    715                     data_by_uid[uid] = _load_item(path2, uid)
     718                    data_by_uid[uid] = _load_yaml_data(path2, uid)
    716719            os.makedirs(os.path.dirname(cache_file), exist_ok=True)
    717720            with open(cache_file, "wb") as out:
     
    745748        self._load_items_in_dir(base, path, cache_file, update_cache)
    746749
     750    def _load_items(self, config: Any):
     751        cache_dir = os.path.abspath(config["cache-directory"])
     752        for index, path in enumerate(config["paths"]):
     753            self._load_items_recursive(str(index), path, path, cache_dir)
     754
     755    def load_data(self, path: str, uid: str) -> Any:
     756        """ Loads the item data from the file specified by path. """
     757        # pylint: disable=no-self-use
     758        return _load_yaml_data(path, uid)
     759
     760    def _save_data(self, file: TextIO, data: Any) -> None:
     761        # pylint: disable=no-self-use
     762        file.write(
     763            yaml.dump(data, default_flow_style=False, allow_unicode=True))
     764
     765    def save_data(self, path: str, data: Any) -> None:
     766        """ Saves the item data to the file specified by path. """
     767        print('save-data', path, data)
     768        with open(path, "w") as file:
     769            data2 = {}
     770            for key, value in data.items():
     771                if not key.startswith("_"):
     772                    data2[key] = value
     773            self._save_data(file, data2)
     774
    747775    def _init_parents(self) -> None:
    748776        for item in self._items.values():
     
    776804
    777805
     806class JSONItemCache(ItemCache):
     807    """ This class provides a cache of specification items using JSON. """
     808    def _load_json_items(self, base: str, path: str) -> None:
     809        for name in os.listdir(path):
     810            path2 = os.path.join(path, name)
     811            if name.endswith(".json") and not name.startswith("."):
     812                uid = "/" + os.path.relpath(path2, base).replace(".json", "")
     813                self._add_item(uid, _load_json_data(path2, uid))
     814            else:
     815                if stat.S_ISDIR(os.lstat(path2).st_mode):
     816                    self._load_json_items(base, path2)
     817
     818    def _load_items(self, config: Any):
     819        for path in config["paths"]:
     820            self._load_json_items(path, path)
     821
     822    def load_data(self, path: str, uid: str) -> Any:
     823        # pylint: disable=no-self-use
     824        return _load_json_data(path, uid)
     825
     826    def _save_data(self, file: TextIO, data: Any) -> None:
     827        # pylint: disable=no-self-use
     828        json.dump(data, file, sort_keys=True, indent=2)
     829
     830
    778831class EmptyItem(Item):
    779832    """ Objects of this class represent empty items. """
  • rtemsspec/tests/test_items_item.py

    re0980df r2c46d2d  
    2828import pytest
    2929
    30 from rtemsspec.items import EmptyItemCache, Item, ItemCache, \
    31     ItemGetValueContext, Link
     30from rtemsspec.items import EmptyItemCache, Item, ItemGetValueContext, \
     31    JSONItemCache, Link
    3232
    3333
     
    267267
    268268
     269def test_save_and_load_json(tmpdir):
     270    spec_dir = os.path.join(os.path.dirname(__file__), "spec-json")
     271    config = {"paths": [spec_dir], "spec-type-root-uid": None}
     272    item_cache = JSONItemCache(config)
     273    item = item_cache["/d/b"].parent("b")
     274    file = os.path.join(tmpdir, "file")
     275    item.file = file
     276    assert item["enabled-by"]
     277    item["enabled-by"] = False
     278    item.save()
     279    with open(file, "r") as src:
     280        assert src.read() == """{
     281  "SPDX-License-Identifier": "CC-BY-SA-4.0 OR BSD-2-Clause",
     282  "copyrights": [
     283    "Copyright (C) 2022 embedded brains GmbH (http://www.embedded-brains.de)"
     284  ],
     285  "enabled-by": false,
     286  "links": [],
     287  "type": "a"
     288}"""
     289    item.load()
     290    with open(file, "w") as dst:
     291        dst.write("invalid")
     292    with pytest.raises(IOError):
     293        item.load()
     294
     295
    269296def test_item_get_value_arg():
    270297    item = Item(EmptyItemCache(), "i", {})
Note: See TracChangeset for help on using the changeset viewer.