-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC — DtSh, shell-like interface with Devicetree #59863
base: main
Are you sure you want to change the base?
Conversation
7057216
to
66b9925
Compare
7f86207
to
b170331
Compare
I think VS Code extension: nRF DeviceTree is a good graphical tool. But it's not open source. Not particularly friendly to non-nRF devices |
b1c9d74
to
b5d6d2c
Compare
Thanks for this. I think it's a great idea and I especially appreciate the attention to detail you put into the RFC as well as volunteering maintenance. Consider me onboard with this idea. I'll give it some testing and review. |
Some unboxing comments:
I can't get tab completion working as I expect using the homebrew python 3.11. From the prompt:
I press TAB and expect commands to be completed. But instead I see a tab character is inserted. Is that expected? Here is my python info (using a virtual environment):
I can The command parser also doesn't seem to be stripping leading whitespace:
this isn't like what you'd expect from a shell in my opinion -- I would expect both of those to quit. |
Stateless view factories for base Devicetree model elements. Signed-off-by: Christophe Dufaza <[email protected]>
Provides a model layer between the rich library Console.export_html() API and DTSh command outputs redirection to HTML files. Although the primary rationale for this module is to support appending a command output to an existing HTML file (>>), it should also help in the long term to maintain and evolve our HTML format. Signed-off-by: Christophe Dufaza <[email protected]>
Provides a model layer between the rich library Console.export_svg() API and DTSh command outputs redirection to SVG files. Although the primary rationale for this module is to support appending a command output to an existing SVG file (and to get rid of the macOS-like title bar generated by the rich library), it should also help in the long term to maintain and evolve our SVG format. Signed-off-by: Christophe Dufaza <[email protected]>
- VT (colors and styles) - VT with batch commands support - SVG/HTML output streams for command outputs redirection Signed-off-by: Christophe Dufaza <[email protected]>
Rich display callback for GNU readline integration Style candidates based on completion context. Signed-off-by: Christophe Dufaza <[email protected]>
Command options to configure formatted outputs. Base command with boilerplate code to support formatted outputs. Signed-off-by: Christophe Dufaza <[email protected]>
PoC command. Signed-off-by: Christophe Dufaza <[email protected]>
The essential companion of 'pwd'. Signed-off-by: Christophe Dufaza <[email protected]>
Think of a POSIX-like 'ls' where the filesystem is a devicetree. Signed-off-by: Christophe Dufaza <[email protected]>
Think of a POSIX-like 'tree' where the filesystem is a devicetree. Signed-off-by: Christophe Dufaza <[email protected]>
Think of a POSIX-like 'find' where the filesystem is a devicetree. Signed-off-by: Christophe Dufaza <[email protected]>
Access special node '/aliases'. Signed-off-by: Christophe Dufaza <[email protected]>
Access special node '/chosen'. Signed-off-by: Christophe Dufaza <[email protected]>
Think of something like using 'cat' to retrieve information from the /proc filesystem on Linux. Signed-off-by: Christophe Dufaza <[email protected]>
Print system hardware and firmware information (kernel, board, SoC). Signed-off-by: Christophe Dufaza <[email protected]>
A session binds a devicetree shell and I/O streams to: - execute batch commands - and/or run an interactive loop Signed-off-by: Christophe Dufaza <[email protected]>
Extends the base session with rich TUI elements and support for SVG and HTML command output redirection formats. Signed-off-by: Christophe Dufaza <[email protected]>
- Factorize command line parser initialization (options and arguments definitions) - Factorize the boilerplate code needed to bootstrap a DTSh session (CLI or batch, loading additional theme and preferences files, etc) - Provide an API suitable for both standalone installations (raw CLI) or integration as a West extension Signed-off-by: Christophe Dufaza <[email protected]>
Tests are based on pytest. Run with 'hatch test'. Signed-off-by: Christophe Dufaza <[email protected]>
- West command: class DTShell in scripts/west_commands/dtsh.py - dtsh extension to West in west-commands.yml. - support for completion west-completion.{bash,zsh} Signed-off-by: Christophe Dufaza <[email protected]>
Document "west dtsh" in "Additional Zephyr extension commands". Document DTSh itself in the Handbook. Signed-off-by: Christophe Dufaza <[email protected]>
I'm looking forward to seeing this happen 💯 |
Hi @dottspina - would you be available to present this work at an upcoming Zephyr Architecture Working Group meeting? Given this adds quite a bit of functionality (in a positive way!) this is worth raising broader awareness about. Group meets every Tuesday at 5pm CET, and I think there would be room on the agenda on the 28th. In the meantime, I wonder if @pdgendt or @mbolivar have feedback. One piece of feedback from my side is that this might need to be split across several PRs. |
I didn't dive much in the code yet, mostly because of the sheer size TBH. |
Hi @kartben, Yes, great, that might be helpful.
I agree that the size of this PR is a concern (@pdgendt also seemed a little discouraged). I tried to soften the effort required by organizing the changes into successive commits, each dedicated to a single task, and depending only on the previous ones. But, in the end, 36 commits proved no less overwhelming than 115 files ;-) What kind of division into multiple PRs were you thinking of ? I'm willing to dig deeper, but it seems to me that we should first agree on the type of integration (Zephyr main tree or external module/project), as it means different PRs anyway (and may be a different review process).
Hi @pdgendt, @decsny suggested a somewhat similar approach a few months ago, adding DTSh to Zephyr as an optional module [1]. I welcomed the idea, my only real concern was not figuring out how to install the missing Python requirements ( Before answering you, I reconsidered this type of approach, and I am still undecided. An optional module integrates with the Zephyr build system, which could give us some hook to install the missing Python requirements: it seems a ugly hack to me, and I'm not even sure DTSh would qualify (make sense) as a module. Besides, users having to go through the External tooling, "software that assists the compilation, testing or simulation processes but in no case ends up being part of the code compiled and linked into the final image" [2] sounds interesting. IIUC, we then have three options:
The second option seems to me a good compromise to have DTSh both available OOTB, and maintained separate from zephyr itself. If we choose this approach, my only remaining concerns will be:
To summarize my thoughts:
If we choose this option, we must make it clear as soon as possible: this will lead to different PRs and may imply some infrastructure/organizational setup. I will also really appreciate any help in working through the above concerns. As I understand it, feature freeze for zephyr 4.1 is planned for mid-February: I'll do my best to respond to any feedback promptly. Thanks. [1] https://docs.zephyrproject.org/latest/contribute/external.html#integration-as-optional-modules |
There's already a |
RFC: DTSh: DTS file viewer with a shell-like command line interface
Introduction
Problem description
Prior to Zephyr, I've only approached Devicetree while looking through LKML or The Linux Kernel documentation.
And, quoting @mbolivar-nordic (October 2020):
I can agree that, when learning Zephyr use of Devicetree, I've personally felt the lack of a quick, simple tool to:
References:
Proposed change
The proposed change is a new West command that opens Devicetree Source files (DTS) in a shell-like command line interface:
where:
west dtsh
: called without argument, the command will open the DTS filebuild/zephyr/zephyr.dts
, and retrieve the bindings that Zephyr used at build-time from the CMake cache filebuild/CMakeCache.txt
cd &flash_controller
changes the current working branch from the devicetree's root to the node at/soc/flash-controller@4001e000
, using its DTS labelflash_controller
find
is with no surprise a shell command that will search for devices, bindings, buses, interrupts, etc-E --also-known-as (image|storage).*
will match nodes with a label or alias starting withimage
orstorage
; predicates like--with-reg-size >4k
are also supported--format NKd
: set the node output format to the columns "nodeN
ame,", "AlsoK
nown As" (all labels and aliases), and "d
escription" (D
is the "Depends-on" column)-T
: list found nodes in tree-like format> doc/partitions.svg
to the last command line would save the partitions tree to the filedoc/partitions.svg
, in SVG formatThe considered use cases include:
This proposal is based on DTSh - A Devicetree Shell: please also refer to the Handbook (also included in this PR) to find out more about its features and how it works.
Detailed RFC
This RFC includes:
Proposed change (Detailed)
This PR comes with 36 commits:
[1]
: Python building and packaging, includingruff
configuration and DTSh requirements[2..33]
: DTSh implementation[34]
: DTSh unit tests[35]
: West command implementation and integration[36]
: DocumentationThey can of course be rearranged.
DTSh
DTSh is implemented in Python and is a Devicetree tool: it seems its natural location is
zephyr/scripts/dts/dtsh
, sibling to the python-devicetree library with which it's tightly coupled.Source files are located in
dtsh/src
, anddtsh
is the root Python package.Bellow is a summary of the software architecture.
Devicetree model
DTSh introduces its own model layer above
edtlib.EDT
:edtlib
APIdtsh.hwm
test_dtsh_hwm
dtsh.dts
test_dtsh_dts
dtsh.model
test_dtsh_model
dtsh.modelutils
test_dtsh_modelutils
GNU Readline integration
Responsibilities:
dtsh.rl
dtsh.autocomp
test_dtsh_autocomp
Devicetree shell
Responsibilities:
dtsh.io
test_dtsh_io
dtsh.config
test_dtsh_config
dtsh.shell
test_dtsh_shell
dtsh.shellutils
test_dtsh_shellutils
dtsh.session
Rich CLI
DTSh's Command Line Interface is built on top of the Textualize's rich API.
dtsh.rich.theme
test_dtsh_theme
dtsh.rich.text
dtsh.rich.tui
dtsh.rich.modelview
dtsh.rich.html
test_dtsh_rich_html
dtsh.rich.svg
test_dtsh_rich_svg
dtsh.rich.io
dtsh.rich.autocomp
dtsh.rich.shellutils
test_dtsh_rich_shellutils
dtsh.rich.session
Built-in Commands
dtsh.builtins.pwd
pwd
: print path of current working branch.test_dtsh_builtin_pwd
dtsh.builtins.cd
cd
: change the current working branchtest_dtsh_builtin_cd
dtsh.builtins.ls
ls
: list information about nodestest_dtsh_builtin_ls
dtsh.builtins.tree
tree
: list nodes in tree-like formattest_dtsh_builtin_tree
dtsh.builtins.find
find
: search branches for nodestest_dtsh_builtin_find
dtsh.builtins.alias
alias
: list aliased nodestest_dtsh_builtin_alias
dtsh.builtins.chosen
chosen
: list chosen nodestest_dtsh_builtin_chosen
dtsh.builtins.cat
cat
: concat and output informationtest_dtsh_builtin_cat
dtsh.builtins.uname
uname
: print system informationPlease refer to Built-in Commands in the DTSh handbook for detailed command descriptions.
Unit tests
Unit tests are implemented with pytest, and located in
dtsh/tests
.The
res
sub-directory contains test resource files.The easiest way to run the tests is simply
hatch test
.West extension
West command implementation:
DTShell
inzephyr/scripts/west_commands/dtshell.py
dtsh
anddevicetree
made available withsys.path.append()
statementsThe West
dtsh
extension is added tozephyr/scripts/west-commands.yml
.Support for West completion is added to
west-completion.bash
andwest-completion.zsh
.Documentation
The proposed change:
zephyr-cmds.rst
to document the West commandhandbook.rst
), located in a dedicated directory along with some imagesDependencies
Beside a couple of extra Python requirements, DTSh does not affect other Zephyr components or needs changes in other areas.
It is however tightly coupled with Zephyr’s devicetree tooling, in particular the
edtlib
library.Extra requirements
These requirements are added to
zephyr/scripts/requirements-extra.txt
.Textualize's rich
DTSh's Command Line Interface is built on top of Textualize's rich library.
It's a mature and actively maintained project, upon which Textual, the company's flagship framework, is based.
rich
itself installs a few dependencies:pygments
: Pygments Python syntax highlightermarkdown-it-py
: Markdown parser done rightGNU Readline (macOS)
For auto-completion, command history and key bindings, DTSh relies on the
readline
module of the Python standard library.On POSIX-like systems, the underlying Readline facilities are implemented by either:
libreadline
, the GNU Readline library, on GNU/Linux systemslibedit
, the Command Line Editor Library, typically used on BSD-like systemsThese libraries are not fully compatible, and DTSh currently supports only the GNU Readline implementation of the Python
readline
module.On macOS, where
libedit
will likely be the default for most Python distributions, DTSh substitutes the shippedreadline
module with gnureadline, "bundling the standard Python readline module with the GNU Readline source code, which is compiled and statically linked to it".Although
gnureadline
is added only to the macOS requirements, DTSh will prefer this stand-alone module wherever it is installed, assuming it's on purpose: this allows users of other POSIX-like systems to fix their Readline support with justpip install gnureadline
.On Windows, Readline support will very likely be disabled: see Readline on MS Windows.
Zephyr’s devicetree tooling
DTSh naturally relies on Zephyr’s python-devicetree for loading DTS and binding files into Devicetree models: API changes in
edtlib
may require changes in DTSh, and, conversely, DTSh may welcome API changes inedtlib
.This adds some maintenance, but may also help
edtlib
mature as an independent library: DTSh seems like a good eat your own dog food context for evaluating the use ofedtlib
outside of the Zephyr build-system.This was more or less part of the initial goals:
Note
DTSh also relies on the contents of the CMake cache populated when the DTS was generated, if found.
Changes in the available (cached, external) variables or their semantic may therefore also affect DTSh.
For example, in the absence of more conclusive evidence, DTSh may consider the availability of
SOC_FULL_DIR
to be an indication of a version 2 hardware model (HWMv2).This heuristic is actually based on the contents of
soc_v1.cmake
andsoc_v2.cmake
: only the latter will saveSOC_FULL_DIR
to the CMake cache.I thought of this example because I don't believe this difference in cache files is due to a difference between hardware models: nothing actually prevents the relevant maintainers from changing their mind and deciding to cache
SOC_FULL_DIR
also when building an HWMv1 target. DTSh would then have to adapt (drop the broken rule, without regret).Concerns and Unresolved Questions
Known Issues
Just linking to the DTSh project's known issues.
If you find any bugs while reviewing this RFC, please (also) report them here.
Maintenance
This is probably the main concern with this RFC:
edtlib
, and adapt when necessaryOnce the initial review is complete, day-to-day maintenance should be low, though:
dtsh.model
encapsulates all DTSh uses of theedtlib
API: if breaking changes are introduced, DTSh will fail thereMore significant changes, like "Hardware model v2" or transitioning from YAML to JSON bindings (unlikely to happen anytime soon), can however involve a little more work to either fix DTSh or add support for the new concepts or resources.
Fortunately:
Finally, I'll gladly continue myself contributing support, features and bug fixing in the long run.
Testing
DTSh use cases include an educational tool for newcomers to Zephyr Devicetree: incorrect, erroneous results (command outputs) would do more harm than good.
Existing unit tests should provide a minimum level of correctness, but:
I expect we will improve this when reviewing this RFC, may be:
Ideally, this should be automated.
Note
DTSh unit tests are currently not integrated with Zephyr CI.
Should I already try adding:
tox.ini
file to DTSh Python building and packaging (for now tests are setup only for Hatch)zephyr/.github/workflows/devicetree_checks.yml
Or is it just as well to wait until we have thought a bit more about what to test and how ?
Readline on MS Windows
The
readline
module of the Python standard library has a rather eventful history:libedit
instead oflibreadline
to avoid the GPL license, and some users had to fix their configuration or workflows due to incompatibility issuesreadline
API, and users complained they lostTAB
-completion in REPLlibedit
andlibreadline
backends on POSIX-like systems, and the need for somereadline
support on MS Windows, are gradually being addressed by the Python communityIn a nutshell, although the situation is improving, for now
readline
integration will very likely be disabled on MS Windows, resulting in a degraded user experience (neither auto-completion nor command history).To get a fully cross-platform implementation, I've also considered the pure Python Prompt Toolkit:
My approach here is to follow changes in Python and incorporate any improvements into DTSh as they come.
Meanwhile, I'm quite optimistic that this will not be considered a merge blocker: Zephyr seems to admit this kind of little (though very unfortunate here) difference between POSIX and non POSIX systems, e.g.
west
itself also supports auto-completion only with POSIX shells.Note
IIUC, Python 3.13 for MS Windows includes an almost complete
readline
module.It seems the only relevant missing API is
set_completion_display_matches_hook()
, which DTSh uses for plugging in its own display of the completion candidates.On MS windows, it could however fallback to the default display implementation provided by the
readline
module.I can draft a patch if there is demand from Windows users with Python 3.13.
References:
Security
The proposed change is not that hazardous:
dtsh
does not evaluate (eval()
) any part of the user inputdtsh
does not pipe any part of the user input to the system interpreter (e.g.os.system()
)dtsh
will not override user files, excepted when appending a redirected command output to an existing file$XDG_CONFIG_HOME
or%LOCALAPPDATA%
)Handbook
The DTSh Handbook (
handbook.rst
) is quite long, and contains sections, subsections, sub-subsections, etc.Its integration with Zephyr's documentation is almost fine in HTML.
Its integration when generating PDF is more debatable:
The final PDF document is still legible, but not optimal: I will gladly try any ideas for improvement.
Personal biases
Why a command line application ? Well, when you've done
west build
, you're already at the command line, and I think continuing from there withwest dtsh
, getting a different prompt but the same user interface paradigms and even key bindings (the base ones used by Zsh, GNU Bash, Emacs, GDB), is more ditrsaction-free than opening a GUI.Beyond this personal biases, things like PyGObject or Qt for Python have nonetheless been considered, but:
Alternatives
There doesn't seem to be many DTS file viewers, and even fewer that support Zephyr's bindings.
Nordic Semiconductor's distributes the nRF DeviceTree extension for VS Code, which looks interesting but does not address the initial problem (as @hongshui3000 also pointed out):