summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2023-05-05 14:41:18 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2023-05-08 14:34:56 +0200
commitacbac0174de3b8f18cdc549fa92cdf5957775086 (patch)
tree15c280818b39a53d706b483225250c662f190417
parentitems: Yield only links of enabled items (diff)
downloadrtems-central-acbac0174de3b8f18cdc549fa92cdf5957775086.tar.bz2
items: Add proxy item type
-rw-r--r--config.yml3
-rw-r--r--rtemsspec/interface.py5
-rw-r--r--rtemsspec/items.py43
-rw-r--r--rtemsspec/tests/spec-item-cache/d/c.yml3
-rw-r--r--rtemsspec/tests/spec-item-cache/p.yml5
-rw-r--r--rtemsspec/tests/spec-item-cache/proxy.yml3
-rw-r--r--rtemsspec/tests/spec-item-cache/proxy2.yml5
-rw-r--r--rtemsspec/tests/spec-item-cache/q.yml6
-rw-r--r--rtemsspec/tests/spec-item-cache/r.yml3
-rw-r--r--rtemsspec/tests/spec-item-cache/s.yml6
-rw-r--r--rtemsspec/tests/spec/proxy.yml28
-rw-r--r--rtemsspec/tests/test_items_itemcache.py20
-rw-r--r--spec-spec/spec/proxy-member.yml23
-rw-r--r--spec-spec/spec/proxy.yml28
-rwxr-xr-xspec2modules.py4
15 files changed, 174 insertions, 11 deletions
diff --git a/config.yml b/config.yml
index 16105bf1..1b96b7e7 100644
--- a/config.yml
+++ b/config.yml
@@ -60,12 +60,13 @@ build:
workspace-directory: workspace/rtems
spec:
cache-directory: cache
- spec-type-root-uid: /spec/root
paths:
- spec-spec
- spec
- spec-glossary
- modules/rtems/spec
+ resolve-proxies: true
+ spec-type-root-uid: /spec/root
glossary:
project-groups:
- /glossary-general
diff --git a/rtemsspec/interface.py b/rtemsspec/interface.py
index 85a6781a..d31bcb0e 100644
--- a/rtemsspec/interface.py
+++ b/rtemsspec/interface.py
@@ -871,6 +871,5 @@ def generate(config: dict, item_cache: ItemCache) -> None:
enabled = config["enabled"]
enabled_by_defined = _gather_enabled_by_defined(
config["item-level-interfaces"], item_cache)
- for item in item_cache.all.values():
- if item.type == "interface/header-file":
- _generate_header_file(item, domains, enabled_by_defined, enabled)
+ for item in item_cache.items_by_type.get("interface/header-file", []):
+ _generate_header_file(item, domains, enabled_by_defined, enabled)
diff --git a/rtemsspec/items.py b/rtemsspec/items.py
index d9cf8801..1adbcdc7 100644
--- a/rtemsspec/items.py
+++ b/rtemsspec/items.py
@@ -203,6 +203,7 @@ class Item:
self._data = data
self._links_to_parents: List[Link] = []
self._links_to_children: List[Link] = []
+ self._resolved_proxy = False
def __eq__(self, other: Any) -> bool:
if not isinstance(other, Item):
@@ -421,6 +422,11 @@ class Item:
return self._data["_enabled"]
@property
+ def resolved_proxy(self) -> bool:
+ """ Is true if the item is a resolved proxy, otherwise false. """
+ return self._resolved_proxy
+
+ @property
def data(self) -> Any:
""" The item data. """
return self._data
@@ -707,6 +713,33 @@ def item_is_enabled(_enabled: List[str], _item: Item) -> bool:
return True
+def _resolve_proxy(proxy: Item, is_link_enabled: Callable[[Link],
+ bool]) -> None:
+
+ # pylint: disable=protected-access
+ try:
+ member = proxy.child("proxy-member", is_link_enabled=is_link_enabled)
+ except IndexError:
+ pass
+ else:
+ member._links_to_parents.extend(proxy._links_to_parents)
+ member._links_to_children.extend(proxy._links_to_children)
+ proxy._data = member._data
+ proxy._ident = member._ident
+ proxy._resolved_proxy = True
+ proxy._uid = member._uid
+ for link in proxy._links_to_parents:
+ for link_2 in link.item._links_to_children:
+ if link_2.item == proxy:
+ link_2._item = member
+ for link in proxy._links_to_children:
+ for link_2 in link.item._links_to_parents:
+ if link_2.item == proxy:
+ link_2._item = member
+ proxy._links_to_children = member._links_to_children
+ proxy._links_to_parents = member._links_to_parents
+
+
class ItemCache:
""" This class provides a cache of specification items. """
@@ -734,6 +767,8 @@ class ItemCache:
for item in self._items.values():
self._set_type(item)
item["_enabled"] = is_item_enabled(self._enabled, item)
+ if config.get("resolve-proxies", False):
+ self.resolve_proxies()
def __getitem__(self, uid: str) -> Item:
return self._items[uid]
@@ -774,6 +809,14 @@ class ItemCache:
for item in self._items.values():
item["_enabled"] = is_item_enabled(enabled, item)
+ def resolve_proxies(
+ self,
+ is_link_enabled: Callable[[Link],
+ bool] = _is_link_enabled) -> None:
+ """ Resolves each proxy item to the its first enabled member. """
+ for item in self.items_by_type.get("proxy", []):
+ _resolve_proxy(item, is_link_enabled)
+
def add_volatile_item(self, uid: str, data: Any) -> Item:
"""
Adds an item with the specified data to the cache and returns it.
diff --git a/rtemsspec/tests/spec-item-cache/d/c.yml b/rtemsspec/tests/spec-item-cache/d/c.yml
index b31a8978..786b66cd 100644
--- a/rtemsspec/tests/spec-item-cache/d/c.yml
+++ b/rtemsspec/tests/spec-item-cache/d/c.yml
@@ -12,5 +12,8 @@ enabled-by: true
links:
- role: null
uid: ../p
+- role: null
+ uid: ../r
+type: other
v: c
r6: ${../p:/r7}
diff --git a/rtemsspec/tests/spec-item-cache/p.yml b/rtemsspec/tests/spec-item-cache/p.yml
index d2d69d33..ca1545e7 100644
--- a/rtemsspec/tests/spec-item-cache/p.yml
+++ b/rtemsspec/tests/spec-item-cache/p.yml
@@ -1,6 +1,9 @@
enabled-by:
not: foobar
-links: []
+links:
+- role: proxy-member
+ uid: proxy
+type: other
v: p
x:
y: z
diff --git a/rtemsspec/tests/spec-item-cache/proxy.yml b/rtemsspec/tests/spec-item-cache/proxy.yml
new file mode 100644
index 00000000..5c068b28
--- /dev/null
+++ b/rtemsspec/tests/spec-item-cache/proxy.yml
@@ -0,0 +1,3 @@
+enabled-by: true
+links: []
+type: proxy
diff --git a/rtemsspec/tests/spec-item-cache/proxy2.yml b/rtemsspec/tests/spec-item-cache/proxy2.yml
new file mode 100644
index 00000000..7507739d
--- /dev/null
+++ b/rtemsspec/tests/spec-item-cache/proxy2.yml
@@ -0,0 +1,5 @@
+enabled-by: true
+links:
+- role: xyz
+ uid: r
+type: proxy
diff --git a/rtemsspec/tests/spec-item-cache/q.yml b/rtemsspec/tests/spec-item-cache/q.yml
new file mode 100644
index 00000000..c33c3a6b
--- /dev/null
+++ b/rtemsspec/tests/spec-item-cache/q.yml
@@ -0,0 +1,6 @@
+enabled-by: blub
+links:
+- role: proxy-member
+ uid: proxy
+type: other
+v: q
diff --git a/rtemsspec/tests/spec-item-cache/r.yml b/rtemsspec/tests/spec-item-cache/r.yml
new file mode 100644
index 00000000..2678ce82
--- /dev/null
+++ b/rtemsspec/tests/spec-item-cache/r.yml
@@ -0,0 +1,3 @@
+enabled-by: true
+links: []
+type: other
diff --git a/rtemsspec/tests/spec-item-cache/s.yml b/rtemsspec/tests/spec-item-cache/s.yml
new file mode 100644
index 00000000..cc19b614
--- /dev/null
+++ b/rtemsspec/tests/spec-item-cache/s.yml
@@ -0,0 +1,6 @@
+enabled-by: foobar
+links:
+- role: proxy-member
+ uid: proxy2
+type: other
+v: s
diff --git a/rtemsspec/tests/spec/proxy.yml b/rtemsspec/tests/spec/proxy.yml
new file mode 100644
index 00000000..f5cbbfb3
--- /dev/null
+++ b/rtemsspec/tests/spec/proxy.yml
@@ -0,0 +1,28 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: type
+ spec-value: proxy
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes: {}
+ description: |
+ Items of similar characteristics may link to a proxy item through links
+ with the ${proxy-member:/spec-name}. A proxy item resolves to the first
+ member item which is enabled. Proxies may be used to provide an
+ interface with a common name and implementations which depend on
+ configuration options. For example, in one configuration a constant
+ could be a compile time constant and in another configuration it could be
+ a read-only object.
+ mandatory-attributes: all
+spec-name: Proxy Item Types
+spec-type: proxy
+type: spec
diff --git a/rtemsspec/tests/test_items_itemcache.py b/rtemsspec/tests/test_items_itemcache.py
index 07cec0bf..ff75db12 100644
--- a/rtemsspec/tests/test_items_itemcache.py
+++ b/rtemsspec/tests/test_items_itemcache.py
@@ -64,7 +64,7 @@ def test_load(tmpdir):
assert p.map("/p") == p
assert p.map("p") == p
a = item_cache.all
- assert len(a) == 2
+ assert len(a) == 7
assert a["/p"]["v"] == "p"
assert a["/d/c"]["v"] == "c"
item_cache.set_enabled([])
@@ -125,7 +125,11 @@ def get_value_dict(ctx):
def test_item_mapper(tmpdir):
- config = create_item_cache_config_and_copy_spec(tmpdir, "spec-item-cache")
+ config = create_item_cache_config_and_copy_spec(tmpdir,
+ "spec-item-cache",
+ with_spec_types=True)
+ config["enabled"] = ["foobar"]
+ config["resolve-proxies"] = True
item_cache = ItemCache(config)
item = item_cache["/p"]
base_mapper = ItemMapper(item)
@@ -146,10 +150,18 @@ def test_item_mapper(tmpdir):
with mapper.prefix("y"):
assert mapper[".:."] == "z"
assert mapper["."] == "/p"
+ match = r"cannot get value for '/v' of spec:/proxy specified by 'proxy:/v"
+ with pytest.raises(ValueError, match=match):
+ mapper["proxy:/v"]
+ assert not item_cache["/proxy"].resolved_proxy
+ assert item_cache["/proxy2"].resolved_proxy
+ assert not item_cache["/r"].resolved_proxy
+ assert mapper["proxy2:/v"] == "s"
+ assert item_cache["/r"].child("xyz").uid == "/s"
assert mapper["d/c"] == "/d/c"
assert mapper["d/c:v"] == "c"
assert mapper["d/c:a/b"] == "e"
- mapper.add_get_value(":/a/x-to-b", get_x_to_b_value)
+ mapper.add_get_value("other:/a/x-to-b", get_x_to_b_value)
assert mapper["d/c:a/x-to-b:args:0:%"] == "eargs:0:%"
assert mapper["d/c:a/f[1]"] == 2
assert mapper["d/c:a/../a/f[3]/g[0]"] == 4
@@ -157,7 +169,7 @@ def test_item_mapper(tmpdir):
assert item_3 == item
assert key_path_3 == "/v"
assert value_3 == "p"
- mapper.add_get_value_dictionary(":/dict", get_value_dict)
+ mapper.add_get_value_dictionary("other:/dict", get_value_dict)
assert mapper["d/c:/dict/some-arbitrary-key"] == "some-arbitrary-key"
recursive_mapper = ItemMapper(item, recursive=True)
assert recursive_mapper.substitute("${.:/r1/r2/r3}") == "foobar"
diff --git a/spec-spec/spec/proxy-member.yml b/spec-spec/spec/proxy-member.yml
new file mode 100644
index 00000000..5265c07c
--- /dev/null
+++ b/spec-spec/spec/proxy-member.yml
@@ -0,0 +1,23 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: role
+ spec-value: proxy-member
+ uid: link
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes: {}
+ description: |
+ It defines the proxy member role of links. Items may use this role to
+ link to ${proxy:/spec-name} items.
+ mandatory-attributes: all
+spec-name: Proxy Member Link Role
+spec-type: proxy-member
+type: spec
diff --git a/spec-spec/spec/proxy.yml b/spec-spec/spec/proxy.yml
new file mode 100644
index 00000000..f5cbbfb3
--- /dev/null
+++ b/spec-spec/spec/proxy.yml
@@ -0,0 +1,28 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: type
+ spec-value: proxy
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes: {}
+ description: |
+ Items of similar characteristics may link to a proxy item through links
+ with the ${proxy-member:/spec-name}. A proxy item resolves to the first
+ member item which is enabled. Proxies may be used to provide an
+ interface with a common name and implementations which depend on
+ configuration options. For example, in one configuration a constant
+ could be a compile time constant and in another configuration it could be
+ a read-only object.
+ mandatory-attributes: all
+spec-name: Proxy Item Types
+spec-type: proxy
+type: spec
diff --git a/spec2modules.py b/spec2modules.py
index 16df8cf8..8c86d396 100755
--- a/spec2modules.py
+++ b/spec2modules.py
@@ -68,8 +68,8 @@ def main() -> None:
if args.diff:
rtemsspec.content.Content.write = _diff # type: ignore
config = rtemsspec.util.load_config("config.yml")
- item_cache = rtemsspec.items.ItemCache(
- config["spec"], is_item_enabled=rtemsspec.items.item_is_enabled)
+ item_cache = rtemsspec.items.ItemCache(config["spec"])
+ item_cache.set_enabled([], rtemsspec.items.item_is_enabled)
rtemsspec.validation.generate(config["validation"], item_cache,
args.targets)