Skip to content

Feature/ifconfig helpers #383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
rootdir = os.environ.get('ROOTDIR')
sys.path.insert(0, os.path.abspath(rootdir))

from scripts import interpretvalues, sectinc, replacevars
from scripts import interpretvalues, sectinc, replacevars, ifconfig_helpers

# -- General configuration ------------------------------------------------

Expand Down
64 changes: 64 additions & 0 deletions scripts/ifconfig_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""Helper functions to guard against incorrect ifconfig usage

SPDX-License-Identifier: MIT
Copyright (C) 2025 Texas Instruments Incorporated - https://www.ti.com
"""

import re
import sys
from pathlib import Path

# This is not a full regular expression for config values, as '\' is valid, but it's good enough for
# the processing below
_CONFIG_REGEX = re.compile(r"'(CONFIG_.*)'\s*:\s*'(.*)'")


def _load_internal_set(path):
"""Populate the internal set we use to check that the expected values are sane

:param path: Pathlib path to config directory
"""
internal_set_dict = {}
if not path.is_dir():
return internal_set_dict

for config_path in path.glob("**/*_config.txt"):
with config_path.open("r", encoding="utf-8") as file:
for line in file:
match = _CONFIG_REGEX.match(line)
if match:
key = match.group(1)
key_set = internal_set_dict.get(key, set())
key_set.add(match.group(2))
internal_set_dict[key] = key_set

return internal_set_dict


_INTERNAL_SET_DICT = _load_internal_set(
Path(__file__).parent.parent.joinpath("configs/")
)


def key_within(config, expected):
"""Check if the values specified are all valid and return if the value of the config option is
in that set

:param config: Config value in current scope
:param expected: Any iterable set of values expected to be in the key
"""
real_set = set(expected)
if not real_set.issubset(_INTERNAL_SET_DICT[config]):
raise ValueError(f"Given expectations are unreasonable for '{config}'")

return locals()[config] in expected


class CollisionException(Exception):
"""Exception class to indicate when a function definition collision occurs"""


if __builtins__.get("key_within") is not None:
raise CollisionException("Function collides with an existing definition")

__builtins__["key_within"] = key_within
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ CPWSxG CPTS GENF0 output to HW4_TS_PUSH input.
The following block shows the Time Sync Router device-tree node with the mapping from CPSWxG CPTS
GENF0 to HW4_TS_PUSH added.

.. ifconfig:: CONFIG_part_variant in ('AM62AX','AM62X')
.. ifconfig:: key_within('CONFIG_part_variant', ('AM62AX','AM62X','A'))

::

Expand Down