mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-07 21:33:54 +00:00
fix(cot-dt2c): fix various breakages
This change fixes several breakages that were introduced in some build configurations by the introduction of the cot-dt2c tool. Some Python environments cannot be managed directly via `pip`, and invocations of `make`, including `make distclean`, would cause errors along the lines of: error: externally-managed-environment × This environment is externally managed ╰─> To install Python packages system-wide, try apt install python3-xyz, where xyz is the package you are trying to install. This change has been resolved by ensuring that calls to the cot-dt2c tool from the build system happen exclusively through Poetry, which automatically sets up a virtual environment that *can* be modified. Some environments saw the following error when building platforms where the cot-dt2c tool was used: make: *** No rule to make target '<..>/debug/bl2_cot.c', needed by '<..>/debug/bl2/bl2_cot.o'. Stop. Additionally, environments with a more recent version of Python saw the following error: File "<...>/lib/python3.12/site-packages/cot_dt2c/cot_parser.py", line 637, in img_to_c if ifdef: ^^^^^ NameError: name 'ifdef' is not defined Both of these errors have now been resolved by modifications to the build system and the cot-dt2c tool to enable preprocessing of the device tree source file before it is processed by the tool. As a consequence of this change, the `pydevicetree` library is no longer vendored into the repository tree, and we instead pull it in via a dependency in Poetry. This change also resolves several MyPy warnings and errors related to missing type hints. Change-Id: I72b2d01caca3fcb789d3fe2549f318a9c92d77d1 Signed-off-by: Chris Kay <chris.kay@arm.com>
This commit is contained in:
parent
e19977d664
commit
73f7b7ddbe
22 changed files with 751 additions and 1823 deletions
5
Makefile
5
Makefile
|
@ -121,9 +121,6 @@ SPTOOL ?= ${SPTOOLPATH}/sptool.py
|
|||
SP_MK_GEN ?= ${SPTOOLPATH}/sp_mk_generator.py
|
||||
SP_DTS_LIST_FRAGMENT ?= ${BUILD_PLAT}/sp_list_fragment.dts
|
||||
|
||||
# Variables for use with Certificate Conversion (cot-dt2c) Tool
|
||||
CERTCONVPATH ?= tools/cot_dt2c
|
||||
|
||||
# Variables for use with ROMLIB
|
||||
ROMLIBPATH ?= lib/romlib
|
||||
|
||||
|
@ -1619,7 +1616,6 @@ endif #(CHECKPATCH)
|
|||
clean:
|
||||
$(s)echo " CLEAN"
|
||||
$(call SHELL_REMOVE_DIR,${BUILD_PLAT})
|
||||
$(q)${MAKE} -C ${CERTCONVPATH} clean
|
||||
ifdef UNIX_MK
|
||||
$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
|
||||
else
|
||||
|
@ -1635,7 +1631,6 @@ realclean distclean:
|
|||
$(s)echo " REALCLEAN"
|
||||
$(call SHELL_REMOVE_DIR,${BUILD_BASE})
|
||||
$(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*)
|
||||
$(q)${MAKE} -C ${CERTCONVPATH} clean
|
||||
ifdef UNIX_MK
|
||||
$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
|
||||
else
|
||||
|
|
|
@ -406,7 +406,6 @@ ifneq (${TRUSTED_BOARD_BOOT},0)
|
|||
COTDTPATH := fdts/tbbr_cot_descriptors.dtsi
|
||||
endif
|
||||
endif
|
||||
bl2: cot-dt2c
|
||||
endif
|
||||
|
||||
BL1_SOURCES += ${AUTH_SOURCES} \
|
||||
|
@ -481,16 +480,23 @@ ifeq (${TRANSFER_LIST}, 1)
|
|||
endif
|
||||
endif
|
||||
|
||||
cot-dt2c:
|
||||
ifneq ($(COTDTPATH),)
|
||||
$(info COT CONVERSION FOR ${COTDTPATH})
|
||||
toolpath := $(shell which cot-dt2c)
|
||||
ifeq (${toolpath},)
|
||||
output := $(shell make -C ./${CERTCONVPATH} install)
|
||||
$(info install output ${output})
|
||||
toolpath := $(shell which cot-dt2c)
|
||||
endif
|
||||
output := $(shell ${toolpath} convert-to-c ${COTDTPATH} ${BUILD_PLAT}/bl2_cot.c)
|
||||
$(info ${output})
|
||||
BL2_SOURCES += ${BUILD_PLAT}/bl2_cot.c
|
||||
cot-dt-defines = IMAGE_BL2 $(BL2_DEFINES) $(PLAT_BL_COMMON_DEFINES)
|
||||
cot-dt-include-dirs = $(BL2_INCLUDE_DIRS) $(PLAT_BL_COMMON_INCLUDE_DIRS)
|
||||
|
||||
cot-dt-cpp-flags = $(cot-dt-defines:%=-D%)
|
||||
cot-dt-cpp-flags += $(cot-dt-include-dirs:%=-I%)
|
||||
|
||||
cot-dt-cpp-flags += $(BL2_CPPFLAGS) $(PLAT_BL_COMMON_CPPFLAGS)
|
||||
cot-dt-cpp-flags += $(CPPFLAGS) $(BL_CPPFLAGS) $(TF_CFLAGS_$(ARCH))
|
||||
cot-dt-cpp-flags += -c -x assembler-with-cpp -E -P -o $@ $<
|
||||
|
||||
$(BUILD_PLAT)/$(COTDTPATH:.dtsi=.dts): $(COTDTPATH) | $$(@D)/
|
||||
$(q)$($(ARCH)-cpp) $(cot-dt-cpp-flags)
|
||||
|
||||
$(BUILD_PLAT)/$(COTDTPATH:.dtsi=.c): $(BUILD_PLAT)/$(COTDTPATH:.dtsi=.dts) | $$(@D)/
|
||||
$(q)poetry -q install
|
||||
$(q)poetry run cot-dt2c convert-to-c $< $@
|
||||
|
||||
BL2_SOURCES += $(BUILD_PLAT)/$(COTDTPATH:.dtsi=.c)
|
||||
endif
|
||||
|
|
151
poetry.lock
generated
151
poetry.lock
generated
|
@ -216,6 +216,26 @@ files = [
|
|||
[package.extras]
|
||||
test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "cot-dt2c"
|
||||
version = "0.1.0"
|
||||
description = "CoT-dt2c Tool is a python script to convert CoT DT file into corresponding C file"
|
||||
optional = false
|
||||
python-versions = "^3.8"
|
||||
files = []
|
||||
develop = true
|
||||
|
||||
[package.dependencies]
|
||||
click = "^8.1.7"
|
||||
igraph = "^0.11.6"
|
||||
plotly = "^5.23.0"
|
||||
pydevicetree = "0.0.13"
|
||||
pyparsing = "^3.1.2"
|
||||
|
||||
[package.source]
|
||||
type = "directory"
|
||||
url = "tools/cot_dt2c"
|
||||
|
||||
[[package]]
|
||||
name = "docutils"
|
||||
version = "0.18.1"
|
||||
|
@ -238,6 +258,66 @@ files = [
|
|||
{file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "igraph"
|
||||
version = "0.11.6"
|
||||
description = "High performance graph data structures and algorithms"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "igraph-0.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3f8b837181e8e87676be3873ce87cc92cc234efd58a2da2f6b4e050db150fcf4"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:245c4b7d7657849eff80416f5df4525c8fc44c74a981ee4d44f0ef2612c3bada"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdb7be3d165073c0136295c0808e9edc57ba096cdb26e94086abb04561f7a292"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58974e20df2986a1ae52a16e51ecb387cc0cbeb41c5c0ddff4d373a1bbf1d9c5"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bef14de5e8ab70724a43808b1ed14aaa6fe1002f87e592289027a3827a8f44a"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:86c1e98de2e32d074df8510bf18abfa1f4c5fda4cb28a009985a5d746b0c0125"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ebc5b3d702158abeb2e4d2414374586a2b932e1a07e48352b470600e1733d528"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0efe6d0fb22d3987a800eb3857ed04df9eb4c5dddd0998be05232cb646f1c337"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-win32.whl", hash = "sha256:f4e68b27497b1c8ada2fb2bc35ef3fa7b0d72e84306b3d648d3de240fc618c32"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:5665b33dfbfca5f54ce9b4fea6b97903bd0e99fb1b02acf5e57e600bdfa5a355"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8aabef03d787b519d1075dfc0da4a1109fb113b941334883e3e7947ac30a459e"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1f2cc4a518d99cdf6cae514f85e93e56852bc8c325b3abb96037d1d690b5975f"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e859238be52ab8ccc614d18f9362942bc88ce543afc12548f81ae99b10801d"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d61fbe5e85eb4ae9efe08c461f9bdeedb02a2b5739fbc223d324a71f40a28be2"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6620ba39df29fd42151becf82309b54e57148233c9c3ef890eed62e25eed8a5"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59666589bb3d07f310cda2c5106a8adeeb77c2ef27fecf1c6438b6091f4ca69d"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:8750b6d6caebf199cf7dc41c931f58e330153779707391e30f0a29f02666fb6e"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:967d6f2c30fe94317da15e459374d0fb8ca3e56020412f201ecd07dd5b5352f2"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-win32.whl", hash = "sha256:9744f95a67319eb6cb487ceabf30f5d7940de34bada51f0ba63adbd23e0f94ad"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-win_amd64.whl", hash = "sha256:b80e69eb11faa9c57330a9ffebdde5808966efe1c1f638d4d4827ea04df7aca8"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0329c16092e2ea7930d5f8368666ce7cb704900cc0ea04e4afe9ea1dd46e44af"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21752313f449bd8688e5688e95ea7231cea5e9199c7162535029be0d9af848ac"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea25e136c6c4161f53ff58868b23ff6c845193050ab0e502236d68e5d4174e32"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac84433a03aef15e4b810010b08882b09854a3669450ccf31e392dbe295d2a66"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac697a44e3573169fa2b28c9c37dcf9cf01e0f558b845dd7123860d4c7c8fb89"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bdeae8bf35316eb1fb27bf667dcf5ecf5fcfb0b8f51831bc1b00c39c09c2d73b"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ad7e4aa442935de72554b96733bf6d7f09eac5cee97988a2562bdd3ca173cfa3"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:8d2818780358a686178866d01568b9df1f29678581734ad7a78882bab54df004"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2352276a20d979f1dea360af4202bb9f0c9a7d2c77f51815c0e625165e82013d"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:687fdab543b507d622fa3043f4227e5b26dc61dcf8ff8c0919fccddcc655f8b8"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57f7f8214cd48c9a4d97f7346a4152ba2d4ac95fb5ee0df4ecf224fce4ba3d14"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2b9cc69ede53f76ffae03b066609aa90184dd68ef15da8c104a97cebb9210838"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:591e1e447c3f0092daf7613a3eaedab83f9a0b0adbaf7702724c5117ded038a5"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ca558eb331bc687bc33e5cd23717e22676e9412f8cda3a31d30c996a0487610d"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf43c30e08debb087c9e3da69aa5cf1b6732968da34d55a614e3421b9a452146"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d38e8d7db72b187d9d2211d0d06b3271fa9f32b04d49d789e2859b5480db0d0"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a318b059051ff78144a1c3cb880f4d933c812bcdb3d833a49cd7168d0427672"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c54027add809b3c5b6685b8deca4ea4763fd000b9ea45c7ee46b7c9d61ff15e"},
|
||||
{file = "igraph-0.11.6.tar.gz", hash = "sha256:837f233256c3319f2a35a6a80d94eafe47b43791ef4c6f9e9871061341ac8e28"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
texttable = ">=1.6.2"
|
||||
|
||||
[package.extras]
|
||||
cairo = ["cairocffi (>=1.2.0)"]
|
||||
doc = ["Sphinx (>=7.0.0)", "pydoctor (>=23.4.0)", "sphinx-gallery (>=0.14.0)", "sphinx-rtd-theme (>=1.3.0)"]
|
||||
matplotlib = ["matplotlib (>=3.6.0)"]
|
||||
plotly = ["plotly (>=5.3.0)"]
|
||||
plotting = ["cairocffi (>=1.2.0)"]
|
||||
test = ["Pillow (>=9)", "cairocffi (>=1.2.0)", "matplotlib (>=3.6.0)", "networkx (>=2.5)", "numpy (>=1.19.0)", "pandas (>=1.1.0)", "plotly (>=5.3.0)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)", "scipy (>=1.5.0)"]
|
||||
test-musl = ["cairocffi (>=1.2.0)", "networkx (>=2.5)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "imagesize"
|
||||
version = "1.4.1"
|
||||
|
@ -479,6 +559,21 @@ wheel = "*"
|
|||
coverage = ["covdefaults", "pytest-cov"]
|
||||
testing = ["flit-core (>=2,<4)", "poetry-core (>=1.0.0)", "pytest (>=7.2.0)", "pytest-rerunfailures", "pytest-xdist", "tomli-w"]
|
||||
|
||||
[[package]]
|
||||
name = "plotly"
|
||||
version = "5.23.0"
|
||||
description = "An open-source, interactive data visualization library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "plotly-5.23.0-py3-none-any.whl", hash = "sha256:76cbe78f75eddc10c56f5a4ee3e7ccaade7c0a57465546f02098c0caed6c2d1a"},
|
||||
{file = "plotly-5.23.0.tar.gz", hash = "sha256:89e57d003a116303a34de6700862391367dd564222ab71f8531df70279fc0193"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = "*"
|
||||
tenacity = ">=6.2.0"
|
||||
|
||||
[[package]]
|
||||
name = "prettytable"
|
||||
version = "3.10.2"
|
||||
|
@ -496,6 +591,20 @@ wcwidth = "*"
|
|||
[package.extras]
|
||||
tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"]
|
||||
|
||||
[[package]]
|
||||
name = "pydevicetree"
|
||||
version = "0.0.13"
|
||||
description = "A library for parsing Devicetree Source v1"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "pydevicetree-0.0.13-py3-none-any.whl", hash = "sha256:d61c695cec925b90a8b5740053f4b604e51154a9b36e62a2f12ed9ceaf2f8c38"},
|
||||
{file = "pydevicetree-0.0.13.tar.gz", hash = "sha256:5700c05df89bad8fd729c11aa6f764a3323bcb3796f13b32481ae34445cfc1b7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pyelftools"
|
||||
version = "0.29"
|
||||
|
@ -521,6 +630,20 @@ files = [
|
|||
[package.extras]
|
||||
windows-terminal = ["colorama (>=0.4.6)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.1.2"
|
||||
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||
optional = false
|
||||
python-versions = ">=3.6.8"
|
||||
files = [
|
||||
{file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"},
|
||||
{file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pyproject-hooks"
|
||||
version = "1.1.0"
|
||||
|
@ -882,6 +1005,32 @@ Sphinx = ">=1.6.3"
|
|||
[package.extras]
|
||||
cairosvg = ["cairosvg (>=1.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "tenacity"
|
||||
version = "9.0.0"
|
||||
description = "Retry code until it succeeds"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"},
|
||||
{file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
doc = ["reno", "sphinx"]
|
||||
test = ["pytest", "tornado (>=4.5)", "typeguard"]
|
||||
|
||||
[[package]]
|
||||
name = "texttable"
|
||||
version = "1.7.0"
|
||||
description = "module to create simple ASCII tables"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "texttable-1.7.0-py2.py3-none-any.whl", hash = "sha256:72227d592c82b3d7f672731ae73e4d1f88cd8e2ef5b075a7a7f01a23a3743917"},
|
||||
{file = "texttable-1.7.0.tar.gz", hash = "sha256:2d2068fb55115807d3ac77a4ca68fa48803e84ebb0ee2340f858107a36522638"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tlc"
|
||||
version = "0.9.0"
|
||||
|
@ -1005,4 +1154,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools",
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "8798a2d1efd456c3b68ae464a216f015afaa1bbb653a905148bef17ab8ce278e"
|
||||
content-hash = "d893034cad02533bc86fb98c7d93a0eac6a755fea5efd553924e4762ed3f1fdb"
|
||||
|
|
|
@ -14,6 +14,7 @@ memory = "memory.memmap:main"
|
|||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
cot-dt2c = {path = "tools/cot_dt2c", develop = true}
|
||||
tlc = {path = "tools/tlc"}
|
||||
|
||||
[tool.poetry.group.docs]
|
||||
|
|
176
tools/cot_dt2c/.gitignore
vendored
Normal file
176
tools/cot_dt2c/.gitignore
vendored
Normal file
|
@ -0,0 +1,176 @@
|
|||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
### Python Patch ###
|
||||
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
||||
poetry.toml
|
||||
|
||||
# ruff
|
||||
.ruff_cache/
|
||||
|
||||
# LSP config files
|
||||
pyrightconfig.json
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
|
@ -1,68 +0,0 @@
|
|||
#
|
||||
# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
##* Variables
|
||||
SHELL := /usr/bin/env bash
|
||||
PYTHON := python
|
||||
PYTHONPATH := `pwd`
|
||||
|
||||
.PHONY: dist
|
||||
dist: clean
|
||||
poetry build
|
||||
|
||||
#* Installation
|
||||
.PHONY: dev-install
|
||||
dev-install:
|
||||
pip3 install mypy
|
||||
pip3 install pytest
|
||||
pip install -r requirements.txt
|
||||
poetry lock -n && poetry export --without-hashes > requirements.txt
|
||||
poetry install -n
|
||||
-poetry run mypy --install-types --non-interactive ./
|
||||
|
||||
.PHONY: install
|
||||
install: dist
|
||||
pip install mypy
|
||||
pip install pytest
|
||||
pip install -r requirements.txt
|
||||
pip install dist/*.whl
|
||||
|
||||
clean-test: ## remove test and coverage artifacts
|
||||
rm -fr .tox/
|
||||
rm -f .coverage
|
||||
rm -fr htmlcov/
|
||||
|
||||
clean-pyc: ## remove Python file artifacts
|
||||
find . -name '*.pyc' -exec rm -f {} +
|
||||
find . -name '*.pyo' -exec rm -f {} +
|
||||
find . -name '*~' -exec rm -f {} +
|
||||
find . -name '__pycache__' -exec rm -fr {} +
|
||||
find . | grep -E ".pytest_cache" | xargs rm -rf
|
||||
find . | grep -E ".mypy_cache" | xargs rm -rf
|
||||
|
||||
|
||||
clean-build: ## remove build artifacts
|
||||
rm -fr build/
|
||||
rm -fr dist/
|
||||
rm -fr .eggs/
|
||||
find . -name '*.egg-info' -exec rm -fr {} +
|
||||
find . -name '*.egg' -exec rm -f {} +
|
||||
|
||||
clean-tmp:
|
||||
rm -rf ./tmp
|
||||
|
||||
#* Cleaning
|
||||
.PHONY: clean clean-build clean-pyc clean-test
|
||||
clean: uninstall clean-build clean-pyc clean-test clean-tmp ## remove all build, test, coverage and Python artifacts
|
||||
|
||||
uninstall:
|
||||
pip uninstall -y cot-dt2c
|
||||
|
||||
.PHONY: reinstall
|
||||
reinstall: clean install
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
PYTHONPATH=$(PYTHONPATH) poetry run pytest -c pyproject.toml tests/
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -6,35 +6,15 @@
|
|||
|
||||
import sys
|
||||
import re
|
||||
from cot_dt2c.pydevicetree.source.parser import ifdef_stack
|
||||
from cot_dt2c.pydevicetree.ast import CellArray, LabelReference
|
||||
from cot_dt2c.pydevicetree import *
|
||||
from pydevicetree.ast import CellArray, LabelReference
|
||||
from pydevicetree import Devicetree, Property, Node
|
||||
from pathlib import Path
|
||||
|
||||
def extractNumber(s):
|
||||
for i in s:
|
||||
if i.isdigit():
|
||||
return (int)(i)
|
||||
|
||||
return -1
|
||||
|
||||
def removeNumber(s):
|
||||
result = ''.join([i for i in s if not i.isdigit()])
|
||||
return result
|
||||
from typing import List, Optional
|
||||
|
||||
class COT:
|
||||
def __init__(self, inputfile: str, outputfile=None):
|
||||
with open(inputfile, 'r') as f:
|
||||
contents = f.read()
|
||||
pos = contents.find("cot")
|
||||
if pos == -1:
|
||||
print("not a valid CoT DT file")
|
||||
exit(1)
|
||||
|
||||
contents = contents[pos:]
|
||||
|
||||
try:
|
||||
self.tree = Devicetree.parseStr(contents)
|
||||
self.tree = Devicetree.parseFile(inputfile)
|
||||
except:
|
||||
print("not a valid CoT DT file")
|
||||
exit(1)
|
||||
|
@ -336,13 +316,10 @@ class COT:
|
|||
|
||||
def format_auth_data_val(self, node:Node, cert:Node):
|
||||
type_desc = node.name
|
||||
if "sp_pkg" in type_desc:
|
||||
ptr = removeNumber(type_desc) + "_buf"
|
||||
else:
|
||||
ptr = type_desc + "_buf"
|
||||
len = "(unsigned int)HASH_DER_LEN"
|
||||
if "pk" in type_desc:
|
||||
len = "(unsigned int)PK_DER_LEN"
|
||||
ptr = type_desc + "_buf"
|
||||
len = "HASH_DER_LEN"
|
||||
if re.search("_pk$", type_desc):
|
||||
len = "PK_DER_LEN"
|
||||
|
||||
# edge case
|
||||
if not self.if_root(cert) and "key_cert" in cert.name:
|
||||
|
@ -351,7 +328,7 @@ class COT:
|
|||
|
||||
return type_desc, ptr, len
|
||||
|
||||
def get_node(self, nodes: list[Node], name: str) -> Node:
|
||||
def get_node(self, nodes: List[Node], name: str) -> Node:
|
||||
for i in nodes:
|
||||
if i.name == name:
|
||||
return i
|
||||
|
@ -458,10 +435,6 @@ class COT:
|
|||
def validate_nodes(self) -> bool:
|
||||
valid = True
|
||||
|
||||
if ifdef_stack:
|
||||
print("invalid ifdef macro")
|
||||
valid = False
|
||||
|
||||
certs = self.get_all_certificates()
|
||||
images = self.get_all_images()
|
||||
|
||||
|
@ -478,71 +451,16 @@ class COT:
|
|||
|
||||
return valid
|
||||
|
||||
def extract_licence(self, f):
|
||||
licence = []
|
||||
|
||||
licencereg = re.compile(r'/\*')
|
||||
licenceendReg = re.compile(r'\*/')
|
||||
|
||||
licencePre = False
|
||||
|
||||
for line in f:
|
||||
match = licencereg.search(line)
|
||||
if match != None:
|
||||
licence.append(line)
|
||||
licencePre = True
|
||||
continue
|
||||
|
||||
match = licenceendReg.search(line)
|
||||
if match != None:
|
||||
licence.append(line)
|
||||
licencePre = False
|
||||
return licence
|
||||
|
||||
if licencePre:
|
||||
licence.append(line)
|
||||
else:
|
||||
return licence
|
||||
|
||||
return licence
|
||||
|
||||
def licence_to_c(self, licence, f):
|
||||
if len(licence) != 0:
|
||||
for i in licence:
|
||||
f.write(i)
|
||||
|
||||
f.write("\n")
|
||||
return
|
||||
|
||||
def extract_include(self, f):
|
||||
include = []
|
||||
|
||||
for line in f:
|
||||
if "cot" in line:
|
||||
return include
|
||||
|
||||
if line != "" and "common" not in line and line != "\n":
|
||||
include.append(line)
|
||||
|
||||
return include
|
||||
|
||||
def include_to_c(self, include, f):
|
||||
def include_to_c(self, f):
|
||||
f.write("#include <stddef.h>\n")
|
||||
f.write("#include <mbedtls/version.h>\n")
|
||||
f.write("#include <common/tbbr/cot_def.h>\n")
|
||||
f.write("#include <drivers/auth/auth_mod.h>\n")
|
||||
f.write("\n")
|
||||
for i in include:
|
||||
f.write(i)
|
||||
f.write("\n")
|
||||
f.write("#include <platform_def.h>\n\n")
|
||||
return
|
||||
|
||||
def generate_header(self, input, output):
|
||||
licence = self.extract_licence(input)
|
||||
include = self.extract_include(input)
|
||||
self.licence_to_c(licence, output)
|
||||
self.include_to_c(include, output)
|
||||
def generate_header(self, output):
|
||||
self.include_to_c(output)
|
||||
|
||||
def all_cert_to_c(self, f):
|
||||
certs = self.get_all_certificates()
|
||||
|
@ -552,17 +470,16 @@ class COT:
|
|||
f.write("\n")
|
||||
|
||||
def cert_to_c(self, node: Node, f):
|
||||
ifdef = node.get_fields("ifdef")
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("{}\n".format(i))
|
||||
node_image_id: int = node.get_field("image-id")
|
||||
|
||||
f.write("static const auth_img_desc_t {} = {{\n".format(node.name))
|
||||
f.write("\t.img_id = {},\n".format(node.get_field("image-id").values[0].replace('"', "")))
|
||||
f.write(f"static const auth_img_desc_t {node.name} = {{\n")
|
||||
f.write(f"\t.img_id = {node_image_id},\n")
|
||||
f.write("\t.img_type = IMG_CERT,\n")
|
||||
|
||||
if not self.if_root(node):
|
||||
f.write("\t.parent = &{},\n".format(node.get_field("parent").label.name))
|
||||
node_parent: Node = node.get_field("parent")
|
||||
|
||||
f.write(f"\t.parent = &{node_parent.label.name},\n")
|
||||
else:
|
||||
f.write("\t.parent = NULL,\n")
|
||||
|
||||
|
@ -608,13 +525,9 @@ class COT:
|
|||
f.write("\t\t\t.type_desc = &{},\n".format(type_desc))
|
||||
f.write("\t\t\t.data = {\n")
|
||||
|
||||
n = extractNumber(type_desc)
|
||||
if "pkg" not in type_desc or n == -1:
|
||||
f.write("\t\t\t\t.ptr = (void *){},\n".format(ptr))
|
||||
else:
|
||||
f.write("\t\t\t\t.ptr = (void *){}[{}],\n".format(ptr, n-1))
|
||||
f.write("\t\t\t\t.ptr = (void *){},\n".format(ptr))
|
||||
|
||||
f.write("\t\t\t\t.len = {}\n".format(data_len))
|
||||
f.write("\t\t\t\t.len = (unsigned int){}\n".format(data_len))
|
||||
f.write("\t\t\t}\n")
|
||||
|
||||
f.write("\t\t}}{}\n".format("," if i != len(auth_data) - 1 else ""))
|
||||
|
@ -623,42 +536,31 @@ class COT:
|
|||
|
||||
f.write("};\n\n")
|
||||
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("#endif\n")
|
||||
f.write("\n")
|
||||
|
||||
return
|
||||
|
||||
|
||||
def img_to_c(self, node:Node, f):
|
||||
ifdef = node.get_fields("ifdef")
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("{}\n".format(i))
|
||||
node_image_id: int = node.get_field("image-id")
|
||||
node_parent: Node = node.get_field("parent")
|
||||
node_hash: Node = node.get_field("hash")
|
||||
|
||||
f.write("static const auth_img_desc_t {} = {{\n".format(node.name))
|
||||
f.write("\t.img_id = {},\n".format(node.get_field("image-id").values[0].replace('"', "")))
|
||||
f.write(f"static const auth_img_desc_t {node.name} = {{\n")
|
||||
f.write(f"\t.img_id = {node_image_id},\n")
|
||||
f.write("\t.img_type = IMG_RAW,\n")
|
||||
f.write("\t.parent = &{},\n".format(node.get_field("parent").label.name))
|
||||
f.write(f"\t.parent = &{node_parent.label.name},\n")
|
||||
f.write("\t.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {\n")
|
||||
|
||||
f.write("\t\t[0] = {\n")
|
||||
f.write("\t\t\t.type = AUTH_METHOD_HASH,\n")
|
||||
f.write("\t\t\t.param.hash = {\n")
|
||||
f.write("\t\t\t\t.data = &raw_data,\n")
|
||||
f.write("\t\t\t\t.hash = &{}\n".format(node.get_field("hash").label.name))
|
||||
f.write(f"\t\t\t\t.hash = &{node_hash.label.name}\n")
|
||||
f.write("\t\t\t}\n")
|
||||
|
||||
f.write("\t\t}\n")
|
||||
f.write("\t}\n")
|
||||
f.write("};\n\n")
|
||||
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("#endif\n")
|
||||
f.write("\n")
|
||||
|
||||
return
|
||||
|
||||
def all_img_to_c(self, f):
|
||||
|
@ -672,7 +574,10 @@ class COT:
|
|||
nv_ctr = self.get_all_nv_counters()
|
||||
|
||||
for nv in nv_ctr:
|
||||
f.write("static auth_param_type_desc_t {} = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, {});\n".format(nv.name, nv.get_field("oid")))
|
||||
nv_oid: str = nv.get_field("oid")
|
||||
|
||||
f.write(f"static auth_param_type_desc_t {nv.name} = "\
|
||||
f"AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, \"{nv_oid}\");\n")
|
||||
|
||||
f.write("\n")
|
||||
|
||||
|
@ -682,7 +587,10 @@ class COT:
|
|||
pks = self.get_all_pks()
|
||||
|
||||
for p in pks:
|
||||
f.write("static auth_param_type_desc_t {} = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, {});\n".format(p.name, p.get_field("oid")))
|
||||
pk_oid: str = p.get_field("oid")
|
||||
|
||||
f.write(f"static auth_param_type_desc_t {p.name} = "\
|
||||
f"AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, \"{pk_oid}\");\n")
|
||||
|
||||
f.write("\n")
|
||||
return
|
||||
|
@ -690,30 +598,17 @@ class COT:
|
|||
def buf_to_c(self, f):
|
||||
certs = self.get_all_certificates()
|
||||
|
||||
buffers = {}
|
||||
buffers = set()
|
||||
|
||||
for c in certs:
|
||||
auth_data = self.get_auth_data(c)
|
||||
|
||||
for a in auth_data:
|
||||
type_desc, ptr, data_len = self.format_auth_data_val(a, c)
|
||||
if ptr not in buffers:
|
||||
buffers[ptr] = c.get_fields("ifdef")
|
||||
|
||||
for key, values in buffers.items():
|
||||
if values:
|
||||
for i in values:
|
||||
f.write("{}\n".format(i))
|
||||
|
||||
if "sp_pkg_hash_buf" in key:
|
||||
f.write("static unsigned char {}[MAX_SP_IDS][HASH_DER_LEN];\n".format(key))
|
||||
elif "pk" in key:
|
||||
f.write("static unsigned char {}[PK_DER_LEN];\n".format(key))
|
||||
else:
|
||||
f.write("static unsigned char {}[HASH_DER_LEN];\n".format(key))
|
||||
|
||||
if values:
|
||||
for i in values:
|
||||
f.write("#endif\n")
|
||||
if not ptr in buffers:
|
||||
f.write(f"static unsigned char {ptr}[{data_len}];\n")
|
||||
buffers.add(ptr)
|
||||
|
||||
f.write("\n")
|
||||
|
||||
|
@ -726,29 +621,18 @@ class COT:
|
|||
|
||||
certs = self.get_all_certificates()
|
||||
for c in certs:
|
||||
ifdef = c.get_fields("ifdef")
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("{}\n".format(i))
|
||||
|
||||
hash = c.children
|
||||
for h in hash:
|
||||
name = h.name
|
||||
oid = h.get_field("oid")
|
||||
|
||||
if "pk" in name and "pkg" not in name:
|
||||
f.write("static auth_param_type_desc_t {} = "\
|
||||
"AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, {});\n".format(name, oid))
|
||||
elif "hash" in name:
|
||||
f.write("static auth_param_type_desc_t {} = "\
|
||||
"AUTH_PARAM_TYPE_DESC(AUTH_PARAM_HASH, {});\n".format(name, oid))
|
||||
elif "ctr" in name:
|
||||
f.write("static auth_param_type_desc_t {} = "\
|
||||
"AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, {});\n".format(name, oid))
|
||||
if re.search("_pk$", name):
|
||||
ty = "AUTH_PARAM_PUB_KEY"
|
||||
elif re.search("_hash$", name):
|
||||
ty = "AUTH_PARAM_HASH"
|
||||
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("#endif\n")
|
||||
f.write(f"static auth_param_type_desc_t {name} = "\
|
||||
f"AUTH_PARAM_TYPE_DESC({ty}, \"{oid}\");\n")
|
||||
|
||||
f.write("\n")
|
||||
|
||||
|
@ -759,28 +643,14 @@ class COT:
|
|||
f.write("static const auth_img_desc_t * const cot_desc[] = {\n")
|
||||
|
||||
for i, c in enumerate(certs):
|
||||
ifdef = c.get_fields("ifdef")
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("{}\n".format(i))
|
||||
c_image_id: int = c.get_field("image-id")
|
||||
|
||||
f.write("\t[{}] = &{}{}\n".format(c.get_field("image-id").values[0], c.name, ","))
|
||||
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("#endif\n")
|
||||
f.write(f"\t[{c_image_id}] = &{c.name},\n")
|
||||
|
||||
for i, c in enumerate(images):
|
||||
ifdef = c.get_fields("ifdef")
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("{}\n".format(i))
|
||||
c_image_id: int = c.get_field("image-id")
|
||||
|
||||
f.write("\t[{}] = &{}{}\n".format(c.get_field("image-id").values[0], c.name, "," if i != len(images) - 1 else ""))
|
||||
|
||||
if ifdef:
|
||||
for i in ifdef:
|
||||
f.write("#endif\n")
|
||||
f.write(f"\t[{c_image_id}] = &{c.name},\n")
|
||||
|
||||
f.write("};\n\n")
|
||||
f.write("REGISTER_COT(cot_desc);\n")
|
||||
|
@ -789,16 +659,15 @@ class COT:
|
|||
def generate_c_file(self):
|
||||
filename = Path(self.output)
|
||||
filename.parent.mkdir(exist_ok=True, parents=True)
|
||||
output = open(self.output, 'w+')
|
||||
input = open(self.input, "r")
|
||||
|
||||
self.generate_header(input, output)
|
||||
self.buf_to_c(output)
|
||||
self.param_to_c(output)
|
||||
self.nv_to_c(output)
|
||||
self.pk_to_c(output)
|
||||
self.all_cert_to_c(output)
|
||||
self.all_img_to_c(output)
|
||||
self.cot_to_c(output)
|
||||
with open(self.output, 'w+') as output:
|
||||
self.generate_header(output)
|
||||
self.buf_to_c(output)
|
||||
self.param_to_c(output)
|
||||
self.nv_to_c(output)
|
||||
self.pk_to_c(output)
|
||||
self.all_cert_to_c(output)
|
||||
self.all_img_to_c(output)
|
||||
self.cot_to_c(output)
|
||||
|
||||
return
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import sys
|
||||
from os import path, walk, mkdir
|
||||
import subprocess
|
||||
from cot_dt2c.pydevicetree import *
|
||||
from pydevicetree import Devicetree
|
||||
|
||||
class bcolors:
|
||||
HEADER = '\033[95m'
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from cot_dt2c.pydevicetree.ast import Devicetree, Node, Property, Directive, CellArray, LabelReference
|
|
@ -1,9 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from cot_dt2c.pydevicetree.ast.directive import Directive
|
||||
from cot_dt2c.pydevicetree.ast.node import Node, NodeReference, Devicetree
|
||||
from cot_dt2c.pydevicetree.ast.property import PropertyValues, Bytestring, CellArray, StringList, Property, \
|
||||
RegArray, OneString
|
||||
from cot_dt2c.pydevicetree.ast.reference import Label, Path, Reference, LabelReference, PathReference
|
|
@ -1,46 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from typing import Any
|
||||
|
||||
from cot_dt2c.pydevicetree.ast.helpers import formatLevel, wrapStrings
|
||||
|
||||
class Directive:
|
||||
"""Represents a Devicetree directive
|
||||
|
||||
Directives in Devicetree source are statements of the form
|
||||
|
||||
/directive-name/ [option1 [option2 [...]]];
|
||||
|
||||
Common directive examples include:
|
||||
|
||||
/dts-v1/;
|
||||
/include/ "overlay.dtsi";
|
||||
/delete-node/ &uart0;
|
||||
/delete-property/ status;
|
||||
|
||||
Their semantic meaning depends on the directive name, their location in the Devicetree,
|
||||
and their options.
|
||||
"""
|
||||
def __init__(self, directive: str, option: Any = None):
|
||||
"""Create a directive object"""
|
||||
self.directive = directive
|
||||
self.option = option
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<Directive %s>" % self.directive
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.to_dts()
|
||||
|
||||
def to_dts(self, level: int = 0) -> str:
|
||||
"""Format the Directive in Devicetree Source format"""
|
||||
if isinstance(self.option, list):
|
||||
return formatLevel(level, "%s %s;\n" % (self.directive,
|
||||
wrapStrings(self.option)))
|
||||
if isinstance(self.option, str):
|
||||
if self.directive == "/include/":
|
||||
return formatLevel(level, "%s \"%s\"\n" % (self.directive, self.option))
|
||||
return formatLevel(level, "%s \"%s\";\n" % (self.directive, self.option))
|
||||
return formatLevel(level, "%s;\n" % self.directive)
|
|
@ -1,28 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from typing import List, Any
|
||||
|
||||
from cot_dt2c.pydevicetree.ast.reference import Reference
|
||||
|
||||
def formatLevel(level: int, s: str) -> str:
|
||||
"""Helper to indent a string with a number of tabs"""
|
||||
return "\t" * level + s
|
||||
|
||||
def wrapStrings(values: List[Any], formatHex: bool = False) -> List[Any]:
|
||||
"""Helper to wrap strings in quotes where appropriate"""
|
||||
wrapped = []
|
||||
for v in values:
|
||||
if isinstance(v, Reference):
|
||||
wrapped.append(v.to_dts())
|
||||
elif isinstance(v, str):
|
||||
wrapped.append("\"%s\"" % v)
|
||||
elif isinstance(v, int):
|
||||
if formatHex:
|
||||
wrapped.append("0x%x" % v)
|
||||
else:
|
||||
wrapped.append(str(v))
|
||||
else:
|
||||
wrapped.append(str(v))
|
||||
return wrapped
|
|
@ -1,514 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import re
|
||||
import os
|
||||
from typing import List, Union, Optional, Iterable, Callable, Any, cast, Pattern
|
||||
|
||||
from cot_dt2c.pydevicetree.ast.helpers import formatLevel
|
||||
from cot_dt2c.pydevicetree.ast.property import Property, PropertyValues, RegArray, RangeArray
|
||||
from cot_dt2c.pydevicetree.ast.directive import Directive
|
||||
from cot_dt2c.pydevicetree.ast.reference import Label, Path, Reference, LabelReference, PathReference
|
||||
|
||||
# Type signature for elements passed to Devicetree constructor
|
||||
ElementList = Iterable[Union['Node', Property, Directive]]
|
||||
|
||||
# Callback type signatures for Devicetree.match() and Devicetree.chosen()
|
||||
MatchFunc = Callable[['Node'], bool]
|
||||
MatchCallback = Optional[Callable[['Node'], None]]
|
||||
ChosenCallback = Optional[Callable[[PropertyValues], None]]
|
||||
|
||||
class Node:
|
||||
"""Represents a Devicetree Node
|
||||
|
||||
A Devicetree Node generally takes the form
|
||||
|
||||
[label:] node-name@unit-address {
|
||||
[directives]
|
||||
[properties]
|
||||
[child nodes]
|
||||
};
|
||||
|
||||
The structure formed by creating trees of Nodes is the bulk of any Devicetree. As the naming
|
||||
system implies, then, each node roughly corresponds to some conceptual device, subsystem of
|
||||
devices, bus, etc.
|
||||
|
||||
Devices can be referenced by label or by path, and are generally uniquely identified by a
|
||||
collection of string identifiers assigned to the "compatible" property.
|
||||
|
||||
For instance, a UART device might look like
|
||||
|
||||
uart0: uart@10013000 {
|
||||
compatible = "sifive,uart0";
|
||||
reg = <0x10013000 0x1000>;
|
||||
reg-names = "control";
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <3>;
|
||||
clocks = <&busclk>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
This node can be identified in the following ways:
|
||||
|
||||
- By label: uart0
|
||||
- By path: /path/to/uart@10013000
|
||||
- By name: uart@10013000 (for example when referenced in a /delete-node/ directive)
|
||||
"""
|
||||
# pylint: disable=too-many-arguments
|
||||
def __init__(self, name: str, label: Optional[str], address: Optional[int],
|
||||
properties: List[Property], directives: List[Directive],
|
||||
children: List['Node']):
|
||||
"""Initializes a Devicetree Node
|
||||
|
||||
Also evaluates the /delete-node/ and /delete-property/ directives found in the node
|
||||
and deletes the respective nodes and properties.
|
||||
"""
|
||||
self.name = name
|
||||
self.parent = None # type: Optional['Node']
|
||||
|
||||
self.label = label
|
||||
self.address = address
|
||||
self.properties = properties
|
||||
self.directives = directives
|
||||
self.children = children
|
||||
self.ifdef = []
|
||||
|
||||
for d in self.directives:
|
||||
if d.directive == "/delete-node/":
|
||||
if isinstance(d.option, LabelReference):
|
||||
node = self.get_by_reference(d.option)
|
||||
elif isinstance(d.option, str):
|
||||
node = self.__get_child_by_handle(d.option)
|
||||
if node:
|
||||
self.remove_child(node)
|
||||
elif d.directive == "/delete-property/":
|
||||
# pylint: disable=cell-var-from-loop
|
||||
properties = list(filter(lambda p: p.name == d.option, self.properties))
|
||||
if properties:
|
||||
del self.properties[self.properties.index(properties[0])]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
if self.address:
|
||||
return "<Node %s@%x>" % (self.name, self.address)
|
||||
return "<Node %s>" % self.name
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.to_dts()
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
return self.name == other.name and self.address == other.address
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.name, self.address))
|
||||
|
||||
@staticmethod
|
||||
def from_dts(source: str) -> 'Node':
|
||||
"""Create a node from Devicetree Source"""
|
||||
# pylint: disable=import-outside-toplevel,cyclic-import
|
||||
from pydevicetree.source import parseNode
|
||||
return parseNode(source)
|
||||
|
||||
def add_child(self, node: 'Node', merge: bool = True):
|
||||
"""Add a child node and merge it into the tree"""
|
||||
node.parent = self
|
||||
self.children.append(node)
|
||||
if merge:
|
||||
self.merge_tree()
|
||||
|
||||
def to_dts(self, level: int = 0) -> str:
|
||||
"""Format the subtree starting at the node as Devicetree Source"""
|
||||
out = ""
|
||||
if isinstance(self.address, int) and self.label:
|
||||
out += formatLevel(level,
|
||||
"%s: %s@%x {\n" % (self.label, self.name, self.address))
|
||||
elif isinstance(self.address, int):
|
||||
out += formatLevel(level, "%s@%x {\n" % (self.name, self.address))
|
||||
elif self.label:
|
||||
out += formatLevel(level, "%s: %s {\n" % (self.label, self.name))
|
||||
elif self.name != "":
|
||||
out += formatLevel(level, "%s {\n" % self.name)
|
||||
|
||||
for d in self.directives:
|
||||
out += d.to_dts(level + 1)
|
||||
for p in self.properties:
|
||||
out += p.to_dts(level + 1)
|
||||
for c in self.children:
|
||||
out += c.to_dts(level + 1)
|
||||
|
||||
if self.name != "":
|
||||
out += formatLevel(level, "};\n")
|
||||
|
||||
return out
|
||||
|
||||
def merge_tree(self):
|
||||
"""Recursively merge child nodes into a single tree
|
||||
|
||||
Parsed Devicetrees can describe the same tree multiple times, adding nodes and properties
|
||||
each time. After parsing, this method is called to recursively merge the tree.
|
||||
"""
|
||||
partitioned_children = []
|
||||
for n in self.children:
|
||||
partitioned_children.append([e for e in self.children if e == n])
|
||||
|
||||
new_children = []
|
||||
for part in partitioned_children:
|
||||
first = part[0]
|
||||
rest = part[1:]
|
||||
if first not in new_children:
|
||||
for n in rest:
|
||||
first.merge(n)
|
||||
new_children.append(first)
|
||||
|
||||
self.children = new_children
|
||||
|
||||
for n in self.children:
|
||||
n.parent = self
|
||||
n.merge_tree()
|
||||
|
||||
def merge(self, other: 'Node'):
|
||||
"""Merge the contents of a node into this node.
|
||||
|
||||
Used by Node.merge_trees()
|
||||
"""
|
||||
if not self.label and other.label:
|
||||
self.label = other.label
|
||||
self.properties += other.properties
|
||||
self.directives += other.directives
|
||||
self.children += other.children
|
||||
self.ifdef += other.ifdef
|
||||
|
||||
def get_path(self, includeAddress: bool = True) -> str:
|
||||
"""Get the path of a node (ex. /cpus/cpu@0)"""
|
||||
if self.name == "/":
|
||||
return ""
|
||||
if self.parent is None:
|
||||
return "/" + self.name
|
||||
if isinstance(self.address, int) and includeAddress:
|
||||
return self.parent.get_path() + "/" + self.name + "@" + ("%x" % self.address)
|
||||
return self.parent.get_path() + "/" + self.name
|
||||
|
||||
def get_by_reference(self, reference: Reference) -> Optional['Node']:
|
||||
"""Get a node from the subtree by reference (ex. &label, &{/path/to/node})"""
|
||||
if isinstance(reference, LabelReference):
|
||||
return self.get_by_label(reference.label)
|
||||
if isinstance(reference, PathReference):
|
||||
return self.get_by_path(reference.path)
|
||||
|
||||
return None
|
||||
|
||||
def get_by_label(self, label: Union[Label, str]) -> Optional['Node']:
|
||||
"""Get a node from the subtree by label"""
|
||||
matching_nodes = list(filter(lambda n: n.label == label, self.child_nodes()))
|
||||
if len(matching_nodes) != 0:
|
||||
return matching_nodes[0]
|
||||
return None
|
||||
|
||||
def __get_child_by_handle(self, handle: str) -> Optional['Node']:
|
||||
"""Get a child node by name or name and unit address"""
|
||||
if '@' in handle:
|
||||
name, addr_s = handle.split('@')
|
||||
address = int(addr_s, base=16)
|
||||
nodes = list(filter(lambda n: n.name == name and n.address == address, self.children))
|
||||
else:
|
||||
name = handle
|
||||
nodes = list(filter(lambda n: n.name == name, self.children))
|
||||
|
||||
if not nodes:
|
||||
return None
|
||||
if len(nodes) > 1:
|
||||
raise Exception("Handle %s is ambiguous!" % handle)
|
||||
return nodes[0]
|
||||
|
||||
def get_by_path(self, path: Union[Path, str]) -> Optional['Node']:
|
||||
"""Get a node in the subtree by path"""
|
||||
matching_nodes = list(filter(lambda n: path == n.get_path(includeAddress=True), \
|
||||
self.child_nodes()))
|
||||
if len(matching_nodes) != 0:
|
||||
return matching_nodes[0]
|
||||
|
||||
matching_nodes = list(filter(lambda n: path == n.get_path(includeAddress=False), \
|
||||
self.child_nodes()))
|
||||
if len(matching_nodes) != 0:
|
||||
return matching_nodes[0]
|
||||
return None
|
||||
|
||||
def filter(self, matchFunc: MatchFunc, cbFunc: MatchCallback = None) -> List['Node']:
|
||||
"""Filter all child nodes by matchFunc
|
||||
|
||||
If cbFunc is provided, this method will iterate over the Nodes selected by matchFunc
|
||||
and call cbFunc on each Node
|
||||
|
||||
Returns a list of all matching Nodes
|
||||
"""
|
||||
nodes = list(filter(matchFunc, self.child_nodes()))
|
||||
|
||||
if cbFunc is not None:
|
||||
for n in nodes:
|
||||
cbFunc(n)
|
||||
|
||||
return nodes
|
||||
|
||||
def match(self, compatible: Pattern, func: MatchCallback = None) -> List['Node']:
|
||||
"""Get a node from the subtree by compatible string
|
||||
|
||||
Accepts a regular expression to match one of the strings in the compatible property.
|
||||
"""
|
||||
regex = re.compile(compatible)
|
||||
|
||||
def match_compat(node: Node) -> bool:
|
||||
compatibles = node.get_fields("compatible")
|
||||
if compatibles is not None:
|
||||
return any(regex.match(c) for c in compatibles)
|
||||
return False
|
||||
|
||||
return self.filter(match_compat, func)
|
||||
|
||||
def child_nodes(self) -> Iterable['Node']:
|
||||
"""Get an iterable over all the nodes in the subtree"""
|
||||
for n in self.children:
|
||||
yield n
|
||||
for m in n.child_nodes():
|
||||
yield m
|
||||
|
||||
def remove_child(self, node):
|
||||
"""Remove a child node"""
|
||||
del self.children[self.children.index(node)]
|
||||
|
||||
def get_fields(self, field_name: str) -> Optional[PropertyValues]:
|
||||
"""Get all the values of a property"""
|
||||
for p in self.properties:
|
||||
if p.name == field_name:
|
||||
return p.values
|
||||
return None
|
||||
|
||||
def has_field(self, field_name: str) -> bool:
|
||||
for p in self.properties:
|
||||
if p.name == field_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_field(self, field_name: str) -> Any:
|
||||
"""Get the first value of a property"""
|
||||
fields = self.get_fields(field_name)
|
||||
if fields is not None:
|
||||
if len(cast(PropertyValues, fields)) != 0:
|
||||
return fields[0]
|
||||
return None
|
||||
|
||||
def get_reg(self) -> Optional[RegArray]:
|
||||
"""If the node defines a `reg` property, return a RegArray for easier querying"""
|
||||
reg = self.get_fields("reg")
|
||||
reg_names = self.get_fields("reg-names")
|
||||
if reg is not None:
|
||||
if reg_names is not None:
|
||||
return RegArray(reg.values, self.address_cells(), self.size_cells(),
|
||||
reg_names.values)
|
||||
return RegArray(reg.values, self.address_cells(), self.size_cells())
|
||||
return None
|
||||
|
||||
def get_ranges(self) -> Optional[RangeArray]:
|
||||
"""If the node defines a `ranges` property, return a RangeArray for easier querying"""
|
||||
ranges = self.get_fields("ranges")
|
||||
child_address_cells = self.get_field("#address-cells")
|
||||
parent_address_cells = self.address_cells()
|
||||
size_cells = self.get_field("#size-cells")
|
||||
if ranges is not None:
|
||||
return RangeArray(ranges.values, child_address_cells, parent_address_cells, size_cells)
|
||||
return None
|
||||
|
||||
def address_cells(self):
|
||||
"""Get the number of address cells
|
||||
|
||||
The #address-cells property is defined by the parent of a node and describes how addresses
|
||||
are encoded in cell arrays. If no property is defined, the default value is 2.
|
||||
"""
|
||||
if self.parent is not None:
|
||||
cells = self.parent.get_field("#address-cells")
|
||||
if cells is not None:
|
||||
return cells
|
||||
return 2
|
||||
return 2
|
||||
|
||||
def size_cells(self):
|
||||
"""Get the number of size cells
|
||||
|
||||
The #size-cells property is defined by the parent of a node and describes how addresses
|
||||
are encoded in cell arrays. If no property is defined, the default value is 1.
|
||||
"""
|
||||
if self.parent is not None:
|
||||
cells = self.parent.get_field("#size-cells")
|
||||
if cells is not None:
|
||||
return cells
|
||||
return 1
|
||||
return 1
|
||||
|
||||
class NodeReference(Node):
|
||||
"""A NodeReference is used to extend the definition of a previously-defined Node
|
||||
|
||||
NodeReferences are commonly used by Devicetree "overlays" to extend the properties of a node
|
||||
or add child devices, such as to a bus like I2C.
|
||||
"""
|
||||
def __init__(self, reference: Reference, properties: List[Property],
|
||||
directives: List[Directive], children: List[Node]):
|
||||
"""Instantiate a Node identified by reference to another node"""
|
||||
self.reference = reference
|
||||
Node.__init__(self, label=None, name="", address=None, properties=properties,
|
||||
directives=directives, children=children)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<NodeReference %s>" % self.reference.to_dts()
|
||||
|
||||
def resolve_reference(self, tree: 'Devicetree') -> Node:
|
||||
"""Given the full tree, get the node being referenced"""
|
||||
node = tree.get_by_reference(self.reference)
|
||||
if node is None:
|
||||
raise Exception("Node reference %s cannot be resolved" % self.reference.to_dts())
|
||||
return cast(Node, node)
|
||||
|
||||
def to_dts(self, level: int = 0) -> str:
|
||||
out = formatLevel(level, self.reference.to_dts() + " {\n")
|
||||
|
||||
for d in self.directives:
|
||||
out += d.to_dts(level + 1)
|
||||
for p in self.properties:
|
||||
out += p.to_dts(level + 1)
|
||||
for c in self.children:
|
||||
out += c.to_dts(level + 1)
|
||||
|
||||
out += formatLevel(level, "};\n")
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class Devicetree(Node):
|
||||
"""A Devicetree object describes the full Devicetree tree
|
||||
|
||||
This class encapsulates both the tree itself (starting at the root node /) and any Directives
|
||||
or nodes which exist at the top level of the Devicetree Source files.
|
||||
|
||||
Devicetree Source files can be parsed by calling Devicetree.parseFile().
|
||||
"""
|
||||
def __init__(self, elements: ElementList):
|
||||
"""Instantiate a Devicetree with the list of parsed elements
|
||||
|
||||
Resolves all reference nodes and merges the tree to combine all identical nodes.
|
||||
"""
|
||||
properties = [] # type: List[Property]
|
||||
directives = [] # type: List[Directive]
|
||||
children = [] # type: List[Node]
|
||||
|
||||
for e in elements:
|
||||
if isinstance(e, Node):
|
||||
children.append(cast(Node, e))
|
||||
elif isinstance(e, Property):
|
||||
properties.append(cast(Property, e))
|
||||
elif isinstance(e, Directive):
|
||||
directives.append(cast(Directive, e))
|
||||
|
||||
Node.__init__(self, label=None, name="", address=None,
|
||||
properties=properties, directives=directives, children=children)
|
||||
|
||||
for node in self.children:
|
||||
node.parent = self
|
||||
|
||||
reference_nodes = self.filter(lambda n: isinstance(n, NodeReference))
|
||||
for refnode in reference_nodes:
|
||||
refnode = cast(NodeReference, refnode)
|
||||
|
||||
node = refnode.resolve_reference(self)
|
||||
|
||||
if refnode.parent:
|
||||
cast(Node, refnode.parent).remove_child(refnode)
|
||||
|
||||
node.properties += refnode.properties
|
||||
node.directives += refnode.directives
|
||||
node.children += refnode.children
|
||||
|
||||
self.merge_tree()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
name = self.root().get_field("compatible")
|
||||
return "<Devicetree %s>" % name
|
||||
|
||||
def to_dts(self, level: int = 0) -> str:
|
||||
"""Convert the tree back to Devicetree Source"""
|
||||
out = ""
|
||||
|
||||
for d in self.directives:
|
||||
out += d.to_dts()
|
||||
for p in self.properties:
|
||||
out += p.to_dts()
|
||||
for c in self.children:
|
||||
out += c.to_dts()
|
||||
|
||||
return out
|
||||
|
||||
def get_by_path(self, path: Union[Path, str]) -> Optional[Node]:
|
||||
"""Get a node in the tree by path (ex. /cpus/cpu@0)"""
|
||||
|
||||
# Find and replace all aliases in the path
|
||||
aliases = self.aliases()
|
||||
if aliases:
|
||||
for prop in aliases.properties:
|
||||
if prop.name in path and len(prop.values) > 0:
|
||||
path = path.replace(prop.name, prop.values[0])
|
||||
|
||||
return self.root().get_by_path(path)
|
||||
|
||||
@staticmethod
|
||||
# pylint: disable=arguments-differ
|
||||
def from_dts(dts: str) -> 'Devicetree':
|
||||
"""Parse a string and return a Devicetree object"""
|
||||
# pylint: disable=import-outside-toplevel,cyclic-import
|
||||
from pydevicetree.source import parseTree
|
||||
return parseTree(dts)
|
||||
|
||||
@staticmethod
|
||||
def parseFile(filename: str, followIncludes: bool = False) -> 'Devicetree':
|
||||
"""Parse a file and return a Devicetree object"""
|
||||
# pylint: disable=import-outside-toplevel,cyclic-import
|
||||
from cot_dt2c.pydevicetree.source.parser import parseTree
|
||||
with open(filename, 'r') as f:
|
||||
contents = f.read()
|
||||
dirname = os.path.dirname(filename)
|
||||
if dirname != "":
|
||||
dirname += "/"
|
||||
return parseTree(contents, dirname, followIncludes)
|
||||
|
||||
@staticmethod
|
||||
def parseStr(input: str, followIncludes: bool = False) -> 'Devicetree':
|
||||
from cot_dt2c.pydevicetree.source.parser import parseTree
|
||||
return parseTree(input, "", followIncludes)
|
||||
|
||||
def all_nodes(self) -> Iterable[Node]:
|
||||
"""Get an iterable over all nodes in the tree"""
|
||||
return self.child_nodes()
|
||||
|
||||
def root(self) -> Node:
|
||||
"""Get the root node of the tree"""
|
||||
for n in self.all_nodes():
|
||||
if n.name == "/":
|
||||
return n
|
||||
raise Exception("Devicetree has no root node!")
|
||||
|
||||
def aliases(self) -> Optional[Node]:
|
||||
"""Get the aliases node of the tree if it exists"""
|
||||
for n in self.all_nodes():
|
||||
if n.name == "aliases":
|
||||
return n
|
||||
return None
|
||||
|
||||
def chosen(self, property_name: str, func: ChosenCallback = None) -> Optional[PropertyValues]:
|
||||
"""Get the values associated with one of the properties in the chosen node"""
|
||||
def match_chosen(node: Node) -> bool:
|
||||
return node.name == "chosen"
|
||||
|
||||
for n in filter(match_chosen, self.all_nodes()):
|
||||
for p in n.properties:
|
||||
if p.name == property_name:
|
||||
if func is not None:
|
||||
func(p.values)
|
||||
return p.values
|
||||
|
||||
return None
|
|
@ -1,278 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from typing import List, Any, cast, Tuple, Optional, Iterable
|
||||
from itertools import zip_longest
|
||||
|
||||
from cot_dt2c.pydevicetree.ast.helpers import wrapStrings, formatLevel
|
||||
|
||||
class PropertyValues:
|
||||
"""PropertyValues is the parent class of all values which can be assigned to a Property
|
||||
|
||||
Child classes include
|
||||
|
||||
Bytestring
|
||||
CellArray
|
||||
StringList
|
||||
"""
|
||||
def __init__(self, values: List[Any]):
|
||||
"""Create a PropertyValue"""
|
||||
self.values = values
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<PropertyValues " + self.values.__repr__() + ">"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.to_dts()
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.values)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.values)
|
||||
|
||||
def to_dts(self, formatHex: bool = False) -> str:
|
||||
"""Format the values in Devicetree Source format"""
|
||||
return ", ".join(wrapStrings(self.values, formatHex))
|
||||
|
||||
def __getitem__(self, key) -> Any:
|
||||
return self.values[key]
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if isinstance(other, PropertyValues):
|
||||
return self.values == other.values
|
||||
return self.values == other
|
||||
|
||||
class Bytestring(PropertyValues):
|
||||
"""A Bytestring is a sequence of bytes
|
||||
|
||||
In Devicetree, Bytestrings are represented as a sequence of two-digit hexadecimal integers,
|
||||
optionally space-separated, enclosed by square brackets:
|
||||
|
||||
[de ad be eef]
|
||||
"""
|
||||
def __init__(self, bytelist: List[int]):
|
||||
"""Create a Bytestring object"""
|
||||
PropertyValues.__init__(self, cast(List[Any], bytearray(bytelist)))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<Bytestring " + str(self.values) + ">"
|
||||
|
||||
def to_dts(self, formatHex: bool = False) -> str:
|
||||
"""Format the bytestring in Devicetree Source format"""
|
||||
return "[" + " ".join("%02x" % v for v in self.values) + "]"
|
||||
|
||||
class CellArray(PropertyValues):
|
||||
"""A CellArray is an array of integer values
|
||||
|
||||
CellArrays are commonly used as the value of Devicetree properties like `reg` and `interrupts`.
|
||||
The interpretation of each element of a CellArray is device-dependent. For example, the `reg`
|
||||
property encodes a CellArray as a list of tuples (base address, size), while the `interrupts`
|
||||
property encodes a CellArray as simply a list of interrupt line numbers.
|
||||
"""
|
||||
def __init__(self, cells: List[Any]):
|
||||
"""Create a CellArray object"""
|
||||
PropertyValues.__init__(self, cells)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<CellArray " + self.values.__repr__() + ">"
|
||||
|
||||
def to_dts(self, formatHex: bool = False) -> str:
|
||||
"""Format the cell array in Devicetree Source format"""
|
||||
dtsValues = []
|
||||
for i in self.values:
|
||||
if not isinstance(i, OneString) and not isinstance(i, str):
|
||||
dtsValues.append(i)
|
||||
return "<" + " ".join(wrapStrings(dtsValues, formatHex)) + ">"
|
||||
|
||||
class RegArray(CellArray):
|
||||
"""A RegArray is the CellArray assigned to the reg property"""
|
||||
def __init__(self, cells: List[int],
|
||||
address_cells: int, size_cells: int,
|
||||
names: Optional[List[str]] = None):
|
||||
"""Create a RegArray from a list of ints"""
|
||||
# pylint: disable=too-many-locals
|
||||
CellArray.__init__(self, cells)
|
||||
self.address_cells = address_cells
|
||||
self.size_cells = size_cells
|
||||
|
||||
self.tuples = [] # type: List[Tuple[int, int, Optional[str]]]
|
||||
|
||||
group_size = self.address_cells + self.size_cells
|
||||
|
||||
if len(cells) % group_size != 0:
|
||||
raise Exception("CellArray does not contain enough cells")
|
||||
|
||||
grouped_cells = [cells[i:i+group_size] for i in range(0, len(cells), group_size)]
|
||||
|
||||
if not names:
|
||||
names = []
|
||||
|
||||
for group, name in zip_longest(grouped_cells, cast(Iterable[Any], names)):
|
||||
address = 0
|
||||
a_cells = list(reversed(group[:self.address_cells]))
|
||||
for a, i in zip(a_cells, range(len(a_cells))):
|
||||
address += (1 << (32 * i)) * a
|
||||
|
||||
size = 0
|
||||
s_cells = list(reversed(group[self.address_cells:]))
|
||||
for s, i in zip(s_cells, range(len(s_cells))):
|
||||
size += (1 << (32 * i)) * s
|
||||
|
||||
self.tuples.append(cast(Tuple[int, int, Optional[str]], tuple([address, size, name])))
|
||||
|
||||
def get_by_name(self, name: str) -> Optional[Tuple[int, int]]:
|
||||
"""Returns the (address, size) tuple with a given name"""
|
||||
for t in self.tuples:
|
||||
if t[2] == name:
|
||||
return cast(Tuple[int, int], tuple(t[:2]))
|
||||
return None
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<RegArray " + self.values.__repr__() + ">"
|
||||
|
||||
def __iter__(self) -> Iterable[Tuple[int, int]]:
|
||||
return cast(Iterable[Tuple[int, int]], map(lambda t: tuple(t[:2]), self.tuples))
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.tuples)
|
||||
|
||||
def __getitem__(self, key) -> Optional[Tuple[int, int]]:
|
||||
return list(self.__iter__())[key]
|
||||
|
||||
class RangeArray(CellArray):
|
||||
"""A RangeArray is the CellArray assigned to the range property"""
|
||||
def __init__(self, cells: List[int], child_address_cells: int,
|
||||
parent_address_cells: int, size_cells: int):
|
||||
"""Create a RangeArray from a list of ints"""
|
||||
# pylint: disable=too-many-locals
|
||||
CellArray.__init__(self, cells)
|
||||
self.child_address_cells = child_address_cells
|
||||
self.parent_address_cells = parent_address_cells
|
||||
self.size_cells = size_cells
|
||||
|
||||
self.tuples = [] # type: List[Tuple[int, int, int]]
|
||||
|
||||
group_size = self.child_address_cells + self.parent_address_cells + self.size_cells
|
||||
|
||||
if len(cells) % group_size != 0:
|
||||
raise Exception("CellArray does not contain enough cells")
|
||||
|
||||
grouped_cells = [cells[i:i+group_size] for i in range(0, len(cells), group_size)]
|
||||
|
||||
def sum_cells(cells: List[int]):
|
||||
value = 0
|
||||
for cell, index in zip(list(reversed(cells)), range(len(cells))):
|
||||
value += (1 << (32 * index)) * cell
|
||||
return value
|
||||
|
||||
for group in grouped_cells:
|
||||
child_address = sum_cells(group[:self.child_address_cells])
|
||||
parent_address = sum_cells(group[self.child_address_cells: \
|
||||
self.child_address_cells + self.parent_address_cells])
|
||||
size = sum_cells(group[self.child_address_cells + self.parent_address_cells:])
|
||||
|
||||
self.tuples.append(cast(Tuple[int, int, int],
|
||||
tuple([child_address, parent_address, size])))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<RangeArray " + self.values.__repr__() + ">"
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.tuples)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.tuples)
|
||||
|
||||
def __getitem__(self, key) -> Any:
|
||||
return self.tuples[key]
|
||||
|
||||
class StringList(PropertyValues):
|
||||
"""A StringList is a list of null-terminated strings
|
||||
|
||||
The most common use of a StringList in Devicetree is to describe the `compatible` property.
|
||||
"""
|
||||
def __init__(self, strings: List[str]):
|
||||
"""Create a StringList object"""
|
||||
PropertyValues.__init__(self, strings)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<StringList " + self.values.__repr__() + ">"
|
||||
|
||||
def to_dts(self, formatHex: bool = False) -> str:
|
||||
"""Format the list of strings in Devicetree Source format"""
|
||||
return ", ".join(wrapStrings(self.values))
|
||||
|
||||
class OneString(PropertyValues):
|
||||
def __init__(self, string: str):
|
||||
PropertyValues.__init__(self, string)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.values.__repr__()
|
||||
|
||||
def to_dts(self, formatHex: bool = False) -> str:
|
||||
return super().to_dts(formatHex)
|
||||
|
||||
class Property:
|
||||
"""A Property is a key-value pair for a Devicetree Node
|
||||
|
||||
Properties are used to describe Nodes in the tree. There are many common properties, like
|
||||
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- ranges
|
||||
- interrupt-controller
|
||||
- interrupts
|
||||
- interrupt-parent
|
||||
- clocks
|
||||
- status
|
||||
|
||||
Which might commonly describe many or all nodes in a tree, and there are device, vendor,
|
||||
operating system, runtime-specific properties.
|
||||
|
||||
Properties can possess no value, conveing meaning solely by their presence:
|
||||
|
||||
interrupt-controller;
|
||||
|
||||
Properties can also possess values such as an array of cells, a list of strings, etc.
|
||||
|
||||
reg = <0x10013000 0x1000>;
|
||||
compatible = "sifive,rocket0", "riscv";
|
||||
|
||||
And properties can posses arbitrarily complex values, such as the following from the
|
||||
Devicetree specification:
|
||||
|
||||
example = <0xf00f0000 19>, "a strange property format";
|
||||
"""
|
||||
def __init__(self, name: str, values: PropertyValues):
|
||||
"""Create a Property object"""
|
||||
self.name = name
|
||||
self.values = values
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<Property %s>" % self.name
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.to_dts()
|
||||
|
||||
@staticmethod
|
||||
def from_dts(dts: str) -> 'Property':
|
||||
"""Parse a file and return a Devicetree object"""
|
||||
# pylint: disable=import-outside-toplevel,cyclic-import
|
||||
from pydevicetree.source import parseProperty
|
||||
return parseProperty(dts)
|
||||
|
||||
def to_dts(self, level: int = 0) -> str:
|
||||
"""Format the Property assignment in Devicetree Source format"""
|
||||
if self.name in ["reg", "ranges"]:
|
||||
value = self.values.to_dts(formatHex=True)
|
||||
else:
|
||||
value = self.values.to_dts(formatHex=False)
|
||||
|
||||
if value != "":
|
||||
return formatLevel(level, "%s = %s;\n" % (self.name, value))
|
||||
if self.name == "ifdef":
|
||||
return ""
|
||||
return formatLevel(level, "%s;\n" % self.name)
|
|
@ -1,111 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from typing import Union, Iterator
|
||||
|
||||
class Label:
|
||||
"""A Label is a unique identifier for a Node
|
||||
|
||||
For example, the following node has the label "uart0":
|
||||
|
||||
uart0: uart@10013000 {
|
||||
...
|
||||
};
|
||||
"""
|
||||
def __init__(self, name: str):
|
||||
"""Create a Label"""
|
||||
self.name = name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<Label " + self.name + ">"
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, Label):
|
||||
return self.name == other.name
|
||||
if isinstance(other, str):
|
||||
return self.name == other
|
||||
return False
|
||||
|
||||
def to_dts(self) -> str:
|
||||
"""Format the label in Devicetree Source format"""
|
||||
return self.name + ":"
|
||||
|
||||
class Path:
|
||||
"""A Path uniquely identifies a Node by its parents and (optionally) unit address"""
|
||||
def __init__(self, path: str):
|
||||
"""Create a path out of a string"""
|
||||
self.path = path
|
||||
|
||||
def to_dts(self) -> str:
|
||||
"""Format the Path in Devicetree Source format"""
|
||||
return self.path
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<Path " + self.to_dts() + ">"
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, Path):
|
||||
return self.to_dts() == other.to_dts()
|
||||
if isinstance(other, str):
|
||||
return self.to_dts() == other
|
||||
return False
|
||||
|
||||
def __iter__(self) -> Iterator[str]:
|
||||
return iter(self.path.split("/"))
|
||||
|
||||
def replace(self, old: str, new: str) -> 'Path':
|
||||
"""Replace any elements of the path which match 'old' with a new element 'new'"""
|
||||
return Path(self.path.replace(old, new))
|
||||
|
||||
class Reference:
|
||||
"""A Reference is a Devicetree construct which points to a Node in the tree
|
||||
|
||||
The following are types of references:
|
||||
|
||||
- A reference to a label:
|
||||
|
||||
&my-label;
|
||||
|
||||
- A reference to a node by path:
|
||||
|
||||
&{/path/to/node@deadbeef}
|
||||
|
||||
This is the parent class for both types of references, LabelReference and PathReference
|
||||
"""
|
||||
# pylint: disable=no-self-use
|
||||
def to_dts(self, formatHex: bool = False) -> str:
|
||||
"""Format the Reference in Devicetree Source format"""
|
||||
return ""
|
||||
|
||||
class LabelReference(Reference):
|
||||
"""A LabelReference is a reference to a Node by label"""
|
||||
def __init__(self, label: Union[Label, str]):
|
||||
"""Create a LabelReference from a Label or string"""
|
||||
if isinstance(label, Label):
|
||||
self.label = label
|
||||
elif isinstance(label, str):
|
||||
self.label = Label(label)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<LabelReference " + self.to_dts() + ">"
|
||||
|
||||
def to_dts(self, formatHex: bool = False) -> str:
|
||||
"""Format the LabelReference in Devicetree Source format"""
|
||||
return "&" + self.label.name
|
||||
|
||||
class PathReference(Reference):
|
||||
"""A PathReference is a reference to a Node by path"""
|
||||
def __init__(self, path: Union[Path, str]):
|
||||
"""Create a PathReference from a Path or string"""
|
||||
if isinstance(path, Path):
|
||||
self.path = path
|
||||
elif isinstance(path, str):
|
||||
self.path = Path(path)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<PathReference " + self.to_dts() + ">"
|
||||
|
||||
def to_dts(self, formatHex: bool = False) -> str:
|
||||
"""Format the PathReference in Devicetree Source format"""
|
||||
return "&{" + self.path.to_dts() + "}"
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from cot_dt2c.pydevicetree.source.parser import parseTree, parseNode, parseProperty
|
|
@ -1,95 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pyparsing as p # type: ignore
|
||||
|
||||
ENV_CACHE_OPTION = "PYDEVICETREE_CACHE_SIZE_BOUND"
|
||||
|
||||
cache_bound = None
|
||||
if ENV_CACHE_OPTION in os.environ:
|
||||
option = os.environ[ENV_CACHE_OPTION]
|
||||
if option != "None":
|
||||
try:
|
||||
cache_bound = int(option)
|
||||
except ValueError:
|
||||
print("%s requires a valid integer" % ENV_CACHE_OPTION, file=sys.stderr)
|
||||
p.ParserElement.enablePackrat(cache_bound)
|
||||
|
||||
node_name = p.Word(p.alphanums + ",.-+_") ^ p.Literal("/")
|
||||
integer = p.pyparsing_common.integer ^ (p.Literal("0x").suppress() + p.pyparsing_common.hex_integer)
|
||||
unit_address = p.pyparsing_common.hex_integer
|
||||
unit_addresses = p.delimitedList(unit_address("address"), delim=",")
|
||||
node_handle = node_name("node_name") + p.Optional(p.Literal("@") + unit_addresses)
|
||||
property_name = p.Word(p.alphanums + ",.-_+?#")
|
||||
label = p.Word(p.alphanums + "_").setResultsName("label")
|
||||
label_creation = p.Combine(label + p.Literal(":"))
|
||||
string = p.QuotedString(quoteChar='"')
|
||||
stringlist = p.delimitedList(string)
|
||||
node_path = p.Combine(p.Literal("/") + \
|
||||
p.delimitedList(node_handle, delim="/", combine=True)).setResultsName("path")
|
||||
path_reference = p.Literal("&{").suppress() + node_path + p.Literal("}").suppress()
|
||||
label_reference = p.Literal("&").suppress() + label
|
||||
label_raw = p.Word(p.alphanums + "_")
|
||||
reference = path_reference ^ label_reference ^ label_raw
|
||||
include_directive = p.Literal("/include/") + p.QuotedString(quoteChar='"')
|
||||
generic_directive = p.QuotedString(quoteChar="/", unquoteResults=False) + \
|
||||
p.Optional(string ^ property_name ^ node_name ^ reference ^ (integer * 2)) + \
|
||||
p.Literal(";").suppress()
|
||||
directive = include_directive ^ generic_directive
|
||||
|
||||
operator = p.oneOf("~ ! * / + - << >> < <= > >= == != & ^ | && ||")
|
||||
arith_expr = p.Forward()
|
||||
ternary_element = arith_expr ^ integer
|
||||
ternary_expr = ternary_element + p.Literal("?") + ternary_element + p.Literal(":") + ternary_element
|
||||
arith_expr = p.nestedExpr(content=(p.OneOrMore(operator ^ integer) ^ ternary_expr))
|
||||
arth_str = p.Forward()
|
||||
arith_str_expr = p.nestedExpr(content=(p.OneOrMore(operator ^ integer ^ label_raw ^ p.Literal(",")) ^ ternary_expr))
|
||||
|
||||
label_list = p.OneOrMore(p.Combine(label + p.Literal("\n")))
|
||||
|
||||
cell_array = p.Literal("<").suppress() + \
|
||||
p.ZeroOrMore(integer ^ arith_expr ^ arith_str_expr ^ label_list ^ string ^ reference ^ label_creation.suppress()) + \
|
||||
p.Literal(">").suppress()
|
||||
bytestring = p.Literal("[").suppress() + \
|
||||
(p.OneOrMore(p.Word(p.hexnums, exact=2) ^ label_creation.suppress())) + \
|
||||
p.Literal("]").suppress()
|
||||
property_values = p.Forward()
|
||||
property_values = p.delimitedList(property_values ^ cell_array ^ bytestring ^ stringlist ^ \
|
||||
reference ^ label_raw)
|
||||
property_assignment = property_name("property_name") + p.Optional(p.Literal("=").suppress() + \
|
||||
(property_values)).setResultsName("value") + p.Optional(p.Literal(";").suppress())
|
||||
|
||||
ifdef_label = p.ZeroOrMore(p.Word(p.alphanums + " _|//*=/(/)"))
|
||||
ifdef_define = p.Combine(p.Keyword("#if") + ifdef_label)
|
||||
ifdef_end = p.Combine(p.Keyword("#endif") + ifdef_label)
|
||||
ifdef_define_values = p.Forward()
|
||||
ifdef_define_values = p.ZeroOrMore(ifdef_define)
|
||||
ifdef_end_values = p.Forward()
|
||||
ifdef_end_values = p.ZeroOrMore(ifdef_end)
|
||||
|
||||
node_opener = ifdef_define_values + p.Optional(label_creation) + node_handle + p.Literal("{").suppress()
|
||||
node_reference_opener = reference + p.Literal("{").suppress()
|
||||
node_closer = p.Literal("}").suppress() + p.Literal(";").suppress() + ifdef_end_values
|
||||
node_definition = p.Forward()
|
||||
# pylint: disable=expression-not-assigned
|
||||
node_definition << (node_opener ^ node_reference_opener) + \
|
||||
p.ZeroOrMore(property_assignment ^ directive ^ node_definition ^ ifdef_define ^ ifdef_end) + \
|
||||
node_closer
|
||||
|
||||
devicetree = p.ZeroOrMore(directive ^ node_definition)
|
||||
|
||||
devicetree.ignore(p.cStyleComment)
|
||||
devicetree.ignore("//" + p.SkipTo(p.lineEnd))
|
||||
devicetree.ignore("#include" + p.SkipTo(p.lineEnd))
|
||||
devicetree.ignore("#define" + p.SkipTo(p.lineEnd))
|
||||
devicetree.ignore("#else" + p.SkipTo(p.lineEnd))
|
||||
devicetree.ignore("#error" + p.SkipTo(p.lineEnd))
|
||||
devicetree.ignore("#ifndef" + p.SkipTo(p.lineEnd))
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
devicetree.parseFile(sys.argv[1]).pprint()
|
|
@ -1,238 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2019 SiFive Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from itertools import chain
|
||||
|
||||
from cot_dt2c.pydevicetree.source import grammar
|
||||
from cot_dt2c.pydevicetree.ast import *
|
||||
|
||||
ifdef_stack = []
|
||||
|
||||
def transformNode(string, location, tokens):
|
||||
"""Transforms a ParseResult into a Node"""
|
||||
properties = [e for e in tokens.asList() if isinstance(e, Property)]
|
||||
directives = [e for e in tokens.asList() if isinstance(e, Directive)]
|
||||
children = [e for e in tokens.asList() if isinstance(e, Node)]
|
||||
|
||||
if isinstance(tokens[0], Reference):
|
||||
return NodeReference(tokens[0], properties=properties,
|
||||
directives=directives, children=children)
|
||||
return Node(tokens.node_name, tokens.label, tokens.address, properties=properties,
|
||||
directives=directives, children=children)
|
||||
|
||||
def transformPropertyAssignment(string, location, tokens):
|
||||
"""Transforms a ParseResult into a Property"""
|
||||
for v in tokens.value:
|
||||
if isinstance(v, PropertyValues):
|
||||
return Property(tokens.property_name, v)
|
||||
if isinstance(v, CellArray):
|
||||
return Property(tokens.property_name, v)
|
||||
if isinstance(v, StringList):
|
||||
return Property(tokens.property_name, v)
|
||||
if isinstance(v, Reference):
|
||||
return Property(tokens.property_name, v)
|
||||
|
||||
return Property(tokens.property_name, PropertyValues([]))
|
||||
|
||||
def transformDirective(string, location, tokens):
|
||||
"""Transforms a ParseResult into a Directive"""
|
||||
if len(tokens.asList()) > 1:
|
||||
return Directive(tokens[0], tokens[1])
|
||||
return Directive(tokens[0])
|
||||
|
||||
def evaluateArithExpr(string, location, tokens):
|
||||
"""Evaluates a ParseResult as a python expression"""
|
||||
flat_tokens = list(chain.from_iterable(tokens.asList()))
|
||||
expr = " ".join(str(t) for t in flat_tokens)
|
||||
# pylint: disable=eval-used
|
||||
return eval(expr)
|
||||
|
||||
def transformTernary(string, location, tokens):
|
||||
"""Evaluates a ParseResult as a ternary expression"""
|
||||
# pylint: disable=eval-used
|
||||
return eval(str(tokens[2]) +" if " + str(tokens[0]) + " else " + str(tokens[4]))
|
||||
|
||||
def transformPropertyValues(string, location, tokens):
|
||||
"""Transforms a ParseResult into a PropertyValues"""
|
||||
if len(tokens.asList()) == 1:
|
||||
return tokens.asList()[0]
|
||||
return PropertyValues(tokens.asList())
|
||||
|
||||
def transformStringList(string, location, tokens):
|
||||
"""Transforms a ParseResult into a StringList"""
|
||||
return StringList(tokens.asList())
|
||||
|
||||
def transformString(string, location, token):
|
||||
return OneString(token)
|
||||
|
||||
def transformIfdefMacro(string, location, tokens):
|
||||
tokenlist = tokens.asList()
|
||||
for t in tokenlist:
|
||||
ifdef_stack.append(t)
|
||||
return Property("ifdef", PropertyValues(ifdef_stack.copy()))
|
||||
|
||||
def transformIfdefEnd(string, location, tokens):
|
||||
tokenlist = tokens.asList()
|
||||
for t in tokenlist:
|
||||
ifdef_stack.pop()
|
||||
|
||||
def transformIfdef(string, location, tokens):
|
||||
return Property("ifdef", PropertyValues(tokens))
|
||||
|
||||
def evaluateStrArithExpr(string, location, tokens):
|
||||
"""Evaluates a ParseResult as a python expression"""
|
||||
flat_tokens = list(chain.from_iterable(tokens.asList()))
|
||||
for i, t in enumerate(flat_tokens):
|
||||
if isinstance(t, int):
|
||||
flat_tokens[i] = "(" + str(t) + ")"
|
||||
expr = " ".join(str(t) for t in flat_tokens)
|
||||
# pylint: disable=eval-used
|
||||
return expr
|
||||
|
||||
def transformBytestring(string, location, tokens):
|
||||
"""Transforms a ParseResult into a Bytestring"""
|
||||
inttokens = []
|
||||
for t in tokens.asList():
|
||||
if all(c in "0123456789abcdefABCDEF" for c in t):
|
||||
inttokens.append(int(t, base=16))
|
||||
return Bytestring(inttokens)
|
||||
|
||||
def transformCellArray(string, location, tokens):
|
||||
"""Transforms a ParseResult into a CellArray"""
|
||||
return CellArray(tokens.asList())
|
||||
|
||||
def transformLabel(string, location, tokens):
|
||||
"""Transforms a ParseResult into a Label"""
|
||||
return Label(tokens.label)
|
||||
|
||||
def transformPath(string, location, tokens):
|
||||
"""Transforms a ParseResult into a Path"""
|
||||
path = ""
|
||||
for handle in tokens.path[0].split("/"):
|
||||
if "@" in handle:
|
||||
node, address = handle.split("@")
|
||||
path += "/%s@%x" % (node, int(address))
|
||||
elif handle != "":
|
||||
path += "/" + handle
|
||||
return Path(path)
|
||||
|
||||
def transformPathReference(string, location, tokens):
|
||||
"""Transforms a ParseResult into a PathReference"""
|
||||
return PathReference(tokens[0])
|
||||
|
||||
def transformLabelReference(string, location, tokens):
|
||||
"""Transforms a ParseResult into a LabelReference"""
|
||||
return LabelReference(tokens[0])
|
||||
|
||||
def transformReference(string, location, tokens):
|
||||
"""Transforms a ParseResult into a Reference"""
|
||||
if isinstance(tokens[0], Reference):
|
||||
return tokens[0]
|
||||
return None
|
||||
|
||||
grammar.label.setParseAction(transformLabel)
|
||||
grammar.node_path.setParseAction(transformPath)
|
||||
grammar.path_reference.setParseAction(transformPathReference)
|
||||
grammar.label_reference.setParseAction(transformLabelReference)
|
||||
grammar.reference.setParseAction(transformReference)
|
||||
grammar.node_definition.setParseAction(transformNode)
|
||||
grammar.property_assignment.setParseAction(transformPropertyAssignment)
|
||||
grammar.directive.setParseAction(transformDirective)
|
||||
grammar.arith_expr.setParseAction(evaluateArithExpr)
|
||||
grammar.ternary_expr.setParseAction(transformTernary)
|
||||
grammar.stringlist.setParseAction(transformStringList)
|
||||
grammar.bytestring.setParseAction(transformBytestring)
|
||||
grammar.cell_array.setParseAction(transformCellArray)
|
||||
grammar.property_values.setParseAction(transformPropertyValues)
|
||||
grammar.label_raw.setParseAction(transformString)
|
||||
grammar.ifdef_define_values.setParseAction(transformIfdefMacro)
|
||||
grammar.ifdef_end_values.setParseAction(transformIfdefEnd)
|
||||
grammar.arith_str_expr.setParseAction(transformPropertyValues)
|
||||
|
||||
def printTree(tree, level=0):
|
||||
"""Helper function to print a bunch of elements as a tree"""
|
||||
def printlevel(level, s):
|
||||
print(" " * level + s)
|
||||
|
||||
for item in tree:
|
||||
if isinstance(item, Node):
|
||||
if item.address:
|
||||
printlevel(level, "Node %s@%x" % (item.name, item.address))
|
||||
else:
|
||||
printlevel(level, "Node %s" % item.name)
|
||||
|
||||
if item.label:
|
||||
printlevel(level, " Label: %s" % item.label)
|
||||
|
||||
if item.parent:
|
||||
printlevel(level, " Parent: %s" % item.parent)
|
||||
|
||||
printTree(item.properties, level=(level + 1))
|
||||
|
||||
printTree(item.children, level=(level + 1))
|
||||
elif isinstance(item, Property):
|
||||
if item.values:
|
||||
printlevel(level, "Property %s: %s" % (item.name, item.values))
|
||||
else:
|
||||
printlevel(level, "Property %s" % item.name)
|
||||
elif isinstance(item, Directive):
|
||||
if item.options:
|
||||
printlevel(level, "Directive %s: %s" % (item.directive, item.options))
|
||||
else:
|
||||
printlevel(level, "Directive %s" % item.directive)
|
||||
|
||||
def parentNodes(tree, parent=None):
|
||||
"""Walks a tree and sets Nodes' parent field to point at their parent"""
|
||||
for item in tree:
|
||||
if isinstance(item, Node):
|
||||
item.parent = parent
|
||||
parentNodes(item.children, item)
|
||||
|
||||
def recurseIncludeFiles(elements, pwd):
|
||||
"""Recursively follows and parses /include/ directives an a tree"""
|
||||
for e in elements:
|
||||
if isinstance(e, Directive):
|
||||
if e.directive == "/include/":
|
||||
# Prefix with current directory if path is not absolute
|
||||
if e.option[0] != '/':
|
||||
e.option = pwd + e.option
|
||||
|
||||
with open(e.option, 'r') as f:
|
||||
contents = f.read()
|
||||
|
||||
elements += parseElements(contents)
|
||||
|
||||
del elements[elements.asList().index(e)]
|
||||
|
||||
def parseElements(dts, pwd="", followIncludes=False):
|
||||
"""Parses a string into a list of elements"""
|
||||
elements = grammar.devicetree.parseString(dts, parseAll=True)
|
||||
parentNodes(elements)
|
||||
if followIncludes:
|
||||
recurseIncludeFiles(elements, pwd)
|
||||
return elements
|
||||
|
||||
def parseTree(dts, pwd="", followIncludes=False):
|
||||
"""Parses a string into a full Devicetree"""
|
||||
return Devicetree(parseElements(dts, pwd, followIncludes))
|
||||
|
||||
def parseNode(dts):
|
||||
"""Parses a string into a Devictreee Node"""
|
||||
return grammar.node_definition.parseString(dts, parseAll=True)[0]
|
||||
|
||||
def parseProperty(dts):
|
||||
"""Parses a string into a Devicetree Property"""
|
||||
return grammar.property_assignment.parseString(dts, parseAll=True)[0]
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) > 1:
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
dts = f.read()
|
||||
tree = parseTree(dts)
|
||||
printTree(tree)
|
||||
print(tree)
|
||||
else:
|
||||
print("Please pass the devicetree source file as an argument")
|
||||
sys.exit(1)
|
334
tools/cot_dt2c/poetry.lock
generated
Normal file
334
tools/cot_dt2c/poetry.lock
generated
Normal file
|
@ -0,0 +1,334 @@
|
|||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "atomicwrites"
|
||||
version = "1.4.1"
|
||||
description = "Atomic file writes."
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "24.2.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
|
||||
{file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
|
||||
tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.1.7"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "igraph"
|
||||
version = "0.11.6"
|
||||
description = "High performance graph data structures and algorithms"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "igraph-0.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3f8b837181e8e87676be3873ce87cc92cc234efd58a2da2f6b4e050db150fcf4"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:245c4b7d7657849eff80416f5df4525c8fc44c74a981ee4d44f0ef2612c3bada"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdb7be3d165073c0136295c0808e9edc57ba096cdb26e94086abb04561f7a292"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58974e20df2986a1ae52a16e51ecb387cc0cbeb41c5c0ddff4d373a1bbf1d9c5"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bef14de5e8ab70724a43808b1ed14aaa6fe1002f87e592289027a3827a8f44a"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:86c1e98de2e32d074df8510bf18abfa1f4c5fda4cb28a009985a5d746b0c0125"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ebc5b3d702158abeb2e4d2414374586a2b932e1a07e48352b470600e1733d528"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0efe6d0fb22d3987a800eb3857ed04df9eb4c5dddd0998be05232cb646f1c337"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-win32.whl", hash = "sha256:f4e68b27497b1c8ada2fb2bc35ef3fa7b0d72e84306b3d648d3de240fc618c32"},
|
||||
{file = "igraph-0.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:5665b33dfbfca5f54ce9b4fea6b97903bd0e99fb1b02acf5e57e600bdfa5a355"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8aabef03d787b519d1075dfc0da4a1109fb113b941334883e3e7947ac30a459e"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1f2cc4a518d99cdf6cae514f85e93e56852bc8c325b3abb96037d1d690b5975f"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e859238be52ab8ccc614d18f9362942bc88ce543afc12548f81ae99b10801d"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d61fbe5e85eb4ae9efe08c461f9bdeedb02a2b5739fbc223d324a71f40a28be2"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6620ba39df29fd42151becf82309b54e57148233c9c3ef890eed62e25eed8a5"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59666589bb3d07f310cda2c5106a8adeeb77c2ef27fecf1c6438b6091f4ca69d"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:8750b6d6caebf199cf7dc41c931f58e330153779707391e30f0a29f02666fb6e"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:967d6f2c30fe94317da15e459374d0fb8ca3e56020412f201ecd07dd5b5352f2"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-win32.whl", hash = "sha256:9744f95a67319eb6cb487ceabf30f5d7940de34bada51f0ba63adbd23e0f94ad"},
|
||||
{file = "igraph-0.11.6-cp39-abi3-win_amd64.whl", hash = "sha256:b80e69eb11faa9c57330a9ffebdde5808966efe1c1f638d4d4827ea04df7aca8"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0329c16092e2ea7930d5f8368666ce7cb704900cc0ea04e4afe9ea1dd46e44af"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21752313f449bd8688e5688e95ea7231cea5e9199c7162535029be0d9af848ac"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea25e136c6c4161f53ff58868b23ff6c845193050ab0e502236d68e5d4174e32"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac84433a03aef15e4b810010b08882b09854a3669450ccf31e392dbe295d2a66"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac697a44e3573169fa2b28c9c37dcf9cf01e0f558b845dd7123860d4c7c8fb89"},
|
||||
{file = "igraph-0.11.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bdeae8bf35316eb1fb27bf667dcf5ecf5fcfb0b8f51831bc1b00c39c09c2d73b"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ad7e4aa442935de72554b96733bf6d7f09eac5cee97988a2562bdd3ca173cfa3"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:8d2818780358a686178866d01568b9df1f29678581734ad7a78882bab54df004"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2352276a20d979f1dea360af4202bb9f0c9a7d2c77f51815c0e625165e82013d"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:687fdab543b507d622fa3043f4227e5b26dc61dcf8ff8c0919fccddcc655f8b8"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57f7f8214cd48c9a4d97f7346a4152ba2d4ac95fb5ee0df4ecf224fce4ba3d14"},
|
||||
{file = "igraph-0.11.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2b9cc69ede53f76ffae03b066609aa90184dd68ef15da8c104a97cebb9210838"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:591e1e447c3f0092daf7613a3eaedab83f9a0b0adbaf7702724c5117ded038a5"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ca558eb331bc687bc33e5cd23717e22676e9412f8cda3a31d30c996a0487610d"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf43c30e08debb087c9e3da69aa5cf1b6732968da34d55a614e3421b9a452146"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d38e8d7db72b187d9d2211d0d06b3271fa9f32b04d49d789e2859b5480db0d0"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a318b059051ff78144a1c3cb880f4d933c812bcdb3d833a49cd7168d0427672"},
|
||||
{file = "igraph-0.11.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c54027add809b3c5b6685b8deca4ea4763fd000b9ea45c7ee46b7c9d61ff15e"},
|
||||
{file = "igraph-0.11.6.tar.gz", hash = "sha256:837f233256c3319f2a35a6a80d94eafe47b43791ef4c6f9e9871061341ac8e28"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
texttable = ">=1.6.2"
|
||||
|
||||
[package.extras]
|
||||
cairo = ["cairocffi (>=1.2.0)"]
|
||||
doc = ["Sphinx (>=7.0.0)", "pydoctor (>=23.4.0)", "sphinx-gallery (>=0.14.0)", "sphinx-rtd-theme (>=1.3.0)"]
|
||||
matplotlib = ["matplotlib (>=3.6.0)"]
|
||||
plotly = ["plotly (>=5.3.0)"]
|
||||
plotting = ["cairocffi (>=1.2.0)"]
|
||||
test = ["Pillow (>=9)", "cairocffi (>=1.2.0)", "matplotlib (>=3.6.0)", "networkx (>=2.5)", "numpy (>=1.19.0)", "pandas (>=1.1.0)", "plotly (>=5.3.0)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)", "scipy (>=1.5.0)"]
|
||||
test-musl = ["cairocffi (>=1.2.0)", "networkx (>=2.5)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
description = "brain-dead simple config-ini parsing"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "0.910"
|
||||
description = "Optional static typing for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"},
|
||||
{file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"},
|
||||
{file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"},
|
||||
{file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"},
|
||||
{file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"},
|
||||
{file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"},
|
||||
{file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"},
|
||||
{file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"},
|
||||
{file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"},
|
||||
{file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"},
|
||||
{file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"},
|
||||
{file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"},
|
||||
{file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"},
|
||||
{file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"},
|
||||
{file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"},
|
||||
{file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"},
|
||||
{file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"},
|
||||
{file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"},
|
||||
{file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"},
|
||||
{file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"},
|
||||
{file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"},
|
||||
{file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"},
|
||||
{file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mypy-extensions = ">=0.4.3,<0.5.0"
|
||||
toml = "*"
|
||||
typing-extensions = ">=3.7.4"
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
python2 = ["typed-ast (>=1.4.0,<1.5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "0.4.4"
|
||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
||||
optional = false
|
||||
python-versions = ">=2.7"
|
||||
files = [
|
||||
{file = "mypy_extensions-0.4.4.tar.gz", hash = "sha256:c8b707883a96efe9b4bb3aaf0dcc07e7e217d7d8368eec4db4049ee9e142f4fd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "24.1"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
||||
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotly"
|
||||
version = "5.23.0"
|
||||
description = "An open-source, interactive data visualization library for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "plotly-5.23.0-py3-none-any.whl", hash = "sha256:76cbe78f75eddc10c56f5a4ee3e7ccaade7c0a57465546f02098c0caed6c2d1a"},
|
||||
{file = "plotly-5.23.0.tar.gz", hash = "sha256:89e57d003a116303a34de6700862391367dd564222ab71f8531df70279fc0193"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = "*"
|
||||
tenacity = ">=6.2.0"
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.5.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
|
||||
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "py"
|
||||
version = "1.11.0"
|
||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydevicetree"
|
||||
version = "0.0.13"
|
||||
description = "A library for parsing Devicetree Source v1"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "pydevicetree-0.0.13-py3-none-any.whl", hash = "sha256:d61c695cec925b90a8b5740053f4b604e51154a9b36e62a2f12ed9ceaf2f8c38"},
|
||||
{file = "pydevicetree-0.0.13.tar.gz", hash = "sha256:5700c05df89bad8fd729c11aa6f764a3323bcb3796f13b32481ae34445cfc1b7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.1.2"
|
||||
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||
optional = false
|
||||
python-versions = ">=3.6.8"
|
||||
files = [
|
||||
{file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"},
|
||||
{file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "6.2.5"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
|
||||
{file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
|
||||
attrs = ">=19.2.0"
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<2.0"
|
||||
py = ">=1.8.2"
|
||||
toml = "*"
|
||||
|
||||
[package.extras]
|
||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "tenacity"
|
||||
version = "9.0.0"
|
||||
description = "Retry code until it succeeds"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"},
|
||||
{file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
doc = ["reno", "sphinx"]
|
||||
test = ["pytest", "tornado (>=4.5)", "typeguard"]
|
||||
|
||||
[[package]]
|
||||
name = "texttable"
|
||||
version = "1.7.0"
|
||||
description = "module to create simple ASCII tables"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "texttable-1.7.0-py2.py3-none-any.whl", hash = "sha256:72227d592c82b3d7f672731ae73e4d1f88cd8e2ef5b075a7a7f01a23a3743917"},
|
||||
{file = "texttable-1.7.0.tar.gz", hash = "sha256:2d2068fb55115807d3ac77a4ca68fa48803e84ebb0ee2340f858107a36522638"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.10.2"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
files = [
|
||||
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
||||
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.12.2"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "afa5cb49be96467a848bab753a630c6f5ec42d6750d67d29920c3e3971774e36"
|
|
@ -28,30 +28,33 @@ classifiers = [
|
|||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
click = "^8.1.7"
|
||||
pyparsing = "^2.4.7"
|
||||
plotly = "^5.23.0"
|
||||
pandas = "^2.2.2"
|
||||
pydevicetree = "0.0.13"
|
||||
igraph = "^0.11.6"
|
||||
pyparsing = "^3.1.2"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
[tool.poetry.group.dev]
|
||||
optional = true
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
mypy = "^0.910"
|
||||
pytest = "^6.2.5"
|
||||
pyparsing = "^2.4.7"
|
||||
plotly = "^5.23.0"
|
||||
pandas = "^2.2.2"
|
||||
igraph = "^0.11.6"
|
||||
|
||||
[tool.mypy]
|
||||
# https://mypy.readthedocs.io/en/latest/config_file.html#using-a-pyproject-toml-file
|
||||
python_version = 3.8
|
||||
python_version = "3.8"
|
||||
pretty = true
|
||||
show_traceback = true
|
||||
color_output = true
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = ["igraph", "pydevicetree", "pydevicetree.ast", "plotly", "plotly.graph_objects"]
|
||||
ignore_missing_imports = true
|
||||
|
||||
[tool.coverage.run]
|
||||
source = ["tests"]
|
||||
|
||||
[coverage.paths]
|
||||
[tool.coverage.paths]
|
||||
source = "cot_dt2c"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
mypy
|
||||
pylint
|
||||
pyparsing
|
||||
igraph
|
||||
pandas
|
||||
plotly
|
Loading…
Add table
Reference in a new issue