* [PATCH] kunit: add bash completion
@ 2026-01-15 14:53 Ryota Sakamoto
2026-01-16 9:30 ` David Gow
2026-01-16 10:10 ` Jani Nikula
0 siblings, 2 replies; 5+ messages in thread
From: Ryota Sakamoto @ 2026-01-15 14:53 UTC (permalink / raw)
To: Brendan Higgins, David Gow, Rae Moar, Jonathan Corbet
Cc: linux-kernel, linux-kselftest, kunit-dev, workflows, linux-doc,
Ryota Sakamoto
Currently, kunit.py has many subcommands and options, making it difficult
to remember them without checking the help message.
Add --list-cmds and --list-opts to kunit.py to get available commands and
options, use those outputs in kunit-completion.sh to show completion.
This implementation is similar to perf and tools/perf/perf-completion.sh.
Example output:
$ source tools/testing/kunit/kunit-completion.sh
$ ./tools/testing/kunit/kunit.py [TAB][TAB]
build config exec parse run
$ ./tools/testing/kunit/kunit.py run --k[TAB][TAB]
--kconfig_add --kernel_args --kunitconfig
Signed-off-by: Ryota Sakamoto <sakamo.ryota@gmail.com>
---
Documentation/dev-tools/kunit/run_wrapper.rst | 9 ++++++++
tools/testing/kunit/kunit-completion.sh | 33 +++++++++++++++++++++++++++
tools/testing/kunit/kunit.py | 30 ++++++++++++++++++++++++
tools/testing/kunit/kunit_tool_test.py | 21 +++++++++++++++++
4 files changed, 93 insertions(+)
diff --git a/Documentation/dev-tools/kunit/run_wrapper.rst b/Documentation/dev-tools/kunit/run_wrapper.rst
index 6697c71ee8ca020b8ac7e91b46e29ab082d9dea0..3c0b585dcfffbd3929d0eef1ab9376fa4f380872 100644
--- a/Documentation/dev-tools/kunit/run_wrapper.rst
+++ b/Documentation/dev-tools/kunit/run_wrapper.rst
@@ -335,3 +335,12 @@ command line arguments:
- ``--list_tests_attr``: If set, lists all tests that will be run and all of their
attributes.
+
+Command-line completion
+==============================
+
+The kunit_tool comes with a bash completion script:
+
+.. code-block:: bash
+
+ source tools/testing/kunit/kunit-completion.sh
diff --git a/tools/testing/kunit/kunit-completion.sh b/tools/testing/kunit/kunit-completion.sh
new file mode 100644
index 0000000000000000000000000000000000000000..3b9b68e3bc384c026f10f74b8a1df2129cb2cd50
--- /dev/null
+++ b/tools/testing/kunit/kunit-completion.sh
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: GPL-2.0
+# bash completion support for KUnit
+
+_kunit_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+
+_kunit()
+{
+ local cur prev words cword
+ _init_completion || return
+
+ local script="${_kunit_dir}/kunit.py"
+
+ if [[ $cword -eq 1 && "$cur" != -* ]]; then
+ local cmds=$(${script} --list-cmds 2>/dev/null)
+ COMPREPLY=($(compgen -W "${cmds}" -- "$cur"))
+ return 0
+ fi
+
+ if [[ "$cur" == -* ]]; then
+ if [[ -n "${words[1]}" && "${words[1]}" != -* ]]; then
+ local opts=$(${script} ${words[1]} --list-opts 2>/dev/null)
+ COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
+ return 0
+ else
+ local opts=$(${script} --list-opts 2>/dev/null)
+ COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
+ return 0
+ fi
+ fi
+}
+
+complete -o default -F _kunit kunit.py
+complete -o default -F _kunit kunit
diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index cd99c1956331dbbfb06cf4ddf130db3dcf2a7c31..a5aee1eb88e65fa2387b2623642d2ee9a66db600 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -323,6 +323,17 @@ def get_default_jobs() -> int:
return ncpu
raise RuntimeError("os.cpu_count() returned None")
+def add_completion_opts(parser: argparse.ArgumentParser) -> None:
+ parser.add_argument('--list-opts',
+ help=argparse.SUPPRESS,
+ action='store_true')
+
+def add_root_opts(parser: argparse.ArgumentParser) -> None:
+ parser.add_argument('--list-cmds',
+ help=argparse.SUPPRESS,
+ action='store_true')
+ add_completion_opts(parser)
+
def add_common_opts(parser: argparse.ArgumentParser) -> None:
parser.add_argument('--build_dir',
help='As in the make command, it specifies the build '
@@ -374,6 +385,8 @@ def add_common_opts(parser: argparse.ArgumentParser) -> None:
help='Additional QEMU arguments, e.g. "-smp 8"',
action='append', metavar='')
+ add_completion_opts(parser)
+
def add_build_opts(parser: argparse.ArgumentParser) -> None:
parser.add_argument('--jobs',
help='As in the make command, "Specifies the number of '
@@ -569,6 +582,7 @@ subcommand_handlers_map = {
def main(argv: Sequence[str]) -> None:
parser = argparse.ArgumentParser(
description='Helps writing and running KUnit tests.')
+ add_root_opts(parser)
subparser = parser.add_subparsers(dest='subcommand')
# The 'run' command will config, build, exec, and parse in one go.
@@ -603,12 +617,28 @@ def main(argv: Sequence[str]) -> None:
parse_parser.add_argument('file',
help='Specifies the file to read results from.',
type=str, nargs='?', metavar='input_file')
+ add_completion_opts(parse_parser)
cli_args = parser.parse_args(massage_argv(argv))
if get_kernel_root_path():
os.chdir(get_kernel_root_path())
+ if cli_args.list_cmds:
+ print(" ".join(subparser.choices.keys()))
+ return
+
+ if cli_args.list_opts:
+ target_parser = subparser.choices.get(cli_args.subcommand)
+ if not target_parser:
+ target_parser = parser
+
+ # Accessing private attribute _option_string_actions to get
+ # the list of options. This is not a public API, but argparse
+ # does not provide a way to inspect options programmatically.
+ print(' '.join(target_parser._option_string_actions.keys()))
+ return
+
subcomand_handler = subcommand_handlers_map.get(cli_args.subcommand, None)
if subcomand_handler is None:
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index bbba921e0eacb18663abfcabb2bccf330d8666f5..a7f09a6c97a473ff85e087d17c2f5faf7755b994 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -11,11 +11,13 @@ from unittest import mock
import tempfile, shutil # Handling test_tmpdir
+import io
import itertools
import json
import os
import signal
import subprocess
+import sys
from typing import Iterable
import kunit_config
@@ -855,5 +857,24 @@ class KUnitMainTest(unittest.TestCase):
mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', filter='', filter_action=None, timeout=300),
])
+ @mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
+ def test_list_cmds(self, mock_stdout):
+ kunit.main(['--list-cmds'])
+ output = mock_stdout.getvalue()
+ output_cmds = sorted(output.split())
+ expected_cmds = sorted(['build', 'config', 'exec', 'parse', 'run'])
+ self.assertEqual(output_cmds, expected_cmds)
+
+ @mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
+ def test_run_list_opts(self, mock_stdout):
+ kunit.main(['run', '--list-opts'])
+ output = mock_stdout.getvalue()
+ output_cmds = set(output.split())
+ self.assertIn('--help', output_cmds)
+ self.assertIn('--kunitconfig', output_cmds)
+ self.assertIn('--jobs', output_cmds)
+ self.assertIn('--kernel_args', output_cmds)
+ self.assertIn('--raw_output', output_cmds)
+
if __name__ == '__main__':
unittest.main()
---
base-commit: b71e635feefc852405b14620a7fc58c4c80c0f73
change-id: 20260114-kunit-completion-265889f59c52
Best regards,
--
Ryota Sakamoto <sakamo.ryota@gmail.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] kunit: add bash completion
2026-01-15 14:53 [PATCH] kunit: add bash completion Ryota Sakamoto
@ 2026-01-16 9:30 ` David Gow
2026-01-16 16:58 ` Ryota Sakamoto
2026-01-16 10:10 ` Jani Nikula
1 sibling, 1 reply; 5+ messages in thread
From: David Gow @ 2026-01-16 9:30 UTC (permalink / raw)
To: Ryota Sakamoto
Cc: Brendan Higgins, Rae Moar, Jonathan Corbet, linux-kernel,
linux-kselftest, kunit-dev, workflows, linux-doc
[-- Attachment #1: Type: text/plain, Size: 8894 bytes --]
On Thu, 15 Jan 2026 at 22:54, Ryota Sakamoto <sakamo.ryota@gmail.com> wrote:
>
> Currently, kunit.py has many subcommands and options, making it difficult
> to remember them without checking the help message.
>
> Add --list-cmds and --list-opts to kunit.py to get available commands and
> options, use those outputs in kunit-completion.sh to show completion.
>
> This implementation is similar to perf and tools/perf/perf-completion.sh.
>
> Example output:
> $ source tools/testing/kunit/kunit-completion.sh
> $ ./tools/testing/kunit/kunit.py [TAB][TAB]
> build config exec parse run
> $ ./tools/testing/kunit/kunit.py run --k[TAB][TAB]
> --kconfig_add --kernel_args --kunitconfig
>
> Signed-off-by: Ryota Sakamoto <sakamo.ryota@gmail.com>
> ---
This is awesome!
Two small suggestions:
- Could we add './tools/testing/kunit/kunit.py' to the list of
commands? That's what's recommended in lots of documentation, emails,
etc.
- It'd be great to rebase this on top of kselftest/kunit -- there's a
conflict with your previous patch.
Otherwise, this is great!
Reviewed-by: David Gow <davidgow@google.com>
Cheers,
-- David
> Documentation/dev-tools/kunit/run_wrapper.rst | 9 ++++++++
> tools/testing/kunit/kunit-completion.sh | 33 +++++++++++++++++++++++++++
> tools/testing/kunit/kunit.py | 30 ++++++++++++++++++++++++
> tools/testing/kunit/kunit_tool_test.py | 21 +++++++++++++++++
> 4 files changed, 93 insertions(+)
>
> diff --git a/Documentation/dev-tools/kunit/run_wrapper.rst b/Documentation/dev-tools/kunit/run_wrapper.rst
> index 6697c71ee8ca020b8ac7e91b46e29ab082d9dea0..3c0b585dcfffbd3929d0eef1ab9376fa4f380872 100644
> --- a/Documentation/dev-tools/kunit/run_wrapper.rst
> +++ b/Documentation/dev-tools/kunit/run_wrapper.rst
> @@ -335,3 +335,12 @@ command line arguments:
>
> - ``--list_tests_attr``: If set, lists all tests that will be run and all of their
> attributes.
> +
> +Command-line completion
> +==============================
> +
> +The kunit_tool comes with a bash completion script:
> +
> +.. code-block:: bash
> +
> + source tools/testing/kunit/kunit-completion.sh
> diff --git a/tools/testing/kunit/kunit-completion.sh b/tools/testing/kunit/kunit-completion.sh
> new file mode 100644
> index 0000000000000000000000000000000000000000..3b9b68e3bc384c026f10f74b8a1df2129cb2cd50
> --- /dev/null
> +++ b/tools/testing/kunit/kunit-completion.sh
> @@ -0,0 +1,33 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# bash completion support for KUnit
> +
> +_kunit_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
> +
> +_kunit()
> +{
> + local cur prev words cword
> + _init_completion || return
> +
> + local script="${_kunit_dir}/kunit.py"
> +
> + if [[ $cword -eq 1 && "$cur" != -* ]]; then
> + local cmds=$(${script} --list-cmds 2>/dev/null)
> + COMPREPLY=($(compgen -W "${cmds}" -- "$cur"))
> + return 0
> + fi
> +
> + if [[ "$cur" == -* ]]; then
> + if [[ -n "${words[1]}" && "${words[1]}" != -* ]]; then
> + local opts=$(${script} ${words[1]} --list-opts 2>/dev/null)
> + COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
> + return 0
> + else
> + local opts=$(${script} --list-opts 2>/dev/null)
> + COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
> + return 0
> + fi
> + fi
> +}
> +
> +complete -o default -F _kunit kunit.py
> +complete -o default -F _kunit kunit
Can we add:
complete -o default -F _kunit ./tools/testing/kunit/kunit.py
as well?
> diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
> index cd99c1956331dbbfb06cf4ddf130db3dcf2a7c31..a5aee1eb88e65fa2387b2623642d2ee9a66db600 100755
> --- a/tools/testing/kunit/kunit.py
> +++ b/tools/testing/kunit/kunit.py
> @@ -323,6 +323,17 @@ def get_default_jobs() -> int:
> return ncpu
> raise RuntimeError("os.cpu_count() returned None")
>
> +def add_completion_opts(parser: argparse.ArgumentParser) -> None:
> + parser.add_argument('--list-opts',
> + help=argparse.SUPPRESS,
> + action='store_true')
> +
> +def add_root_opts(parser: argparse.ArgumentParser) -> None:
> + parser.add_argument('--list-cmds',
> + help=argparse.SUPPRESS,
> + action='store_true')
> + add_completion_opts(parser)
> +
> def add_common_opts(parser: argparse.ArgumentParser) -> None:
> parser.add_argument('--build_dir',
> help='As in the make command, it specifies the build '
> @@ -374,6 +385,8 @@ def add_common_opts(parser: argparse.ArgumentParser) -> None:
> help='Additional QEMU arguments, e.g. "-smp 8"',
> action='append', metavar='')
>
> + add_completion_opts(parser)
> +
> def add_build_opts(parser: argparse.ArgumentParser) -> None:
> parser.add_argument('--jobs',
> help='As in the make command, "Specifies the number of '
> @@ -569,6 +582,7 @@ subcommand_handlers_map = {
> def main(argv: Sequence[str]) -> None:
> parser = argparse.ArgumentParser(
> description='Helps writing and running KUnit tests.')
> + add_root_opts(parser)
> subparser = parser.add_subparsers(dest='subcommand')
>
> # The 'run' command will config, build, exec, and parse in one go.
> @@ -603,12 +617,28 @@ def main(argv: Sequence[str]) -> None:
> parse_parser.add_argument('file',
> help='Specifies the file to read results from.',
> type=str, nargs='?', metavar='input_file')
> + add_completion_opts(parse_parser)
>
> cli_args = parser.parse_args(massage_argv(argv))
>
> if get_kernel_root_path():
> os.chdir(get_kernel_root_path())
>
> + if cli_args.list_cmds:
> + print(" ".join(subparser.choices.keys()))
> + return
> +
> + if cli_args.list_opts:
> + target_parser = subparser.choices.get(cli_args.subcommand)
> + if not target_parser:
> + target_parser = parser
> +
> + # Accessing private attribute _option_string_actions to get
> + # the list of options. This is not a public API, but argparse
> + # does not provide a way to inspect options programmatically.
> + print(' '.join(target_parser._option_string_actions.keys()))
> + return
> +
> subcomand_handler = subcommand_handlers_map.get(cli_args.subcommand, None)
>
> if subcomand_handler is None:
> diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
> index bbba921e0eacb18663abfcabb2bccf330d8666f5..a7f09a6c97a473ff85e087d17c2f5faf7755b994 100755
> --- a/tools/testing/kunit/kunit_tool_test.py
> +++ b/tools/testing/kunit/kunit_tool_test.py
> @@ -11,11 +11,13 @@ from unittest import mock
>
> import tempfile, shutil # Handling test_tmpdir
>
> +import io
> import itertools
> import json
> import os
> import signal
> import subprocess
> +import sys
> from typing import Iterable
>
> import kunit_config
> @@ -855,5 +857,24 @@ class KUnitMainTest(unittest.TestCase):
> mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', filter='', filter_action=None, timeout=300),
> ])
>
> + @mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
> + def test_list_cmds(self, mock_stdout):
> + kunit.main(['--list-cmds'])
> + output = mock_stdout.getvalue()
> + output_cmds = sorted(output.split())
> + expected_cmds = sorted(['build', 'config', 'exec', 'parse', 'run'])
> + self.assertEqual(output_cmds, expected_cmds)
> +
> + @mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
> + def test_run_list_opts(self, mock_stdout):
> + kunit.main(['run', '--list-opts'])
> + output = mock_stdout.getvalue()
> + output_cmds = set(output.split())
> + self.assertIn('--help', output_cmds)
> + self.assertIn('--kunitconfig', output_cmds)
> + self.assertIn('--jobs', output_cmds)
> + self.assertIn('--kernel_args', output_cmds)
> + self.assertIn('--raw_output', output_cmds)
> +
> if __name__ == '__main__':
> unittest.main()
>
> ---
> base-commit: b71e635feefc852405b14620a7fc58c4c80c0f73
> change-id: 20260114-kunit-completion-265889f59c52
>
> Best regards,
> --
> Ryota Sakamoto <sakamo.ryota@gmail.com>
>
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5281 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] kunit: add bash completion
2026-01-15 14:53 [PATCH] kunit: add bash completion Ryota Sakamoto
2026-01-16 9:30 ` David Gow
@ 2026-01-16 10:10 ` Jani Nikula
2026-01-16 17:16 ` Ryota Sakamoto
1 sibling, 1 reply; 5+ messages in thread
From: Jani Nikula @ 2026-01-16 10:10 UTC (permalink / raw)
To: Ryota Sakamoto, Brendan Higgins, David Gow, Rae Moar, Jonathan Corbet
Cc: linux-kernel, linux-kselftest, kunit-dev, workflows, linux-doc,
Ryota Sakamoto
On Thu, 15 Jan 2026, Ryota Sakamoto <sakamo.ryota@gmail.com> wrote:
> Currently, kunit.py has many subcommands and options, making it difficult
> to remember them without checking the help message.
>
> Add --list-cmds and --list-opts to kunit.py to get available commands and
> options, use those outputs in kunit-completion.sh to show completion.
>
> This implementation is similar to perf and tools/perf/perf-completion.sh.
>
> Example output:
> $ source tools/testing/kunit/kunit-completion.sh
> $ ./tools/testing/kunit/kunit.py [TAB][TAB]
> build config exec parse run
> $ ./tools/testing/kunit/kunit.py run --k[TAB][TAB]
> --kconfig_add --kernel_args --kunitconfig
>
The alternative would be to make the tool more friendly to existing
completion tools such as shtab [1]. Since the kernel as a project is
really averse to adding external dependencies, you could take shtab's
CLI approach, and commit the completion script in the repo. Only
whoever's updating the completions would have to install and run shtab.
And the whole thing could be taken a step further, adding, say,
tools/completions/{bash,zsh,tcsh,...} directories for all the kernel
tool completions instead of spreading them around.
Anyway, just a thought to consider before doing another kernel homebrew
NIH approach.
BR,
Jani.
[1] https://github.com/iterative/shtab
> Signed-off-by: Ryota Sakamoto <sakamo.ryota@gmail.com>
> ---
> Documentation/dev-tools/kunit/run_wrapper.rst | 9 ++++++++
> tools/testing/kunit/kunit-completion.sh | 33 +++++++++++++++++++++++++++
> tools/testing/kunit/kunit.py | 30 ++++++++++++++++++++++++
> tools/testing/kunit/kunit_tool_test.py | 21 +++++++++++++++++
> 4 files changed, 93 insertions(+)
>
> diff --git a/Documentation/dev-tools/kunit/run_wrapper.rst b/Documentation/dev-tools/kunit/run_wrapper.rst
> index 6697c71ee8ca020b8ac7e91b46e29ab082d9dea0..3c0b585dcfffbd3929d0eef1ab9376fa4f380872 100644
> --- a/Documentation/dev-tools/kunit/run_wrapper.rst
> +++ b/Documentation/dev-tools/kunit/run_wrapper.rst
> @@ -335,3 +335,12 @@ command line arguments:
>
> - ``--list_tests_attr``: If set, lists all tests that will be run and all of their
> attributes.
> +
> +Command-line completion
> +==============================
> +
> +The kunit_tool comes with a bash completion script:
> +
> +.. code-block:: bash
> +
> + source tools/testing/kunit/kunit-completion.sh
> diff --git a/tools/testing/kunit/kunit-completion.sh b/tools/testing/kunit/kunit-completion.sh
> new file mode 100644
> index 0000000000000000000000000000000000000000..3b9b68e3bc384c026f10f74b8a1df2129cb2cd50
> --- /dev/null
> +++ b/tools/testing/kunit/kunit-completion.sh
> @@ -0,0 +1,33 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# bash completion support for KUnit
> +
> +_kunit_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
> +
> +_kunit()
> +{
> + local cur prev words cword
> + _init_completion || return
> +
> + local script="${_kunit_dir}/kunit.py"
> +
> + if [[ $cword -eq 1 && "$cur" != -* ]]; then
> + local cmds=$(${script} --list-cmds 2>/dev/null)
> + COMPREPLY=($(compgen -W "${cmds}" -- "$cur"))
> + return 0
> + fi
> +
> + if [[ "$cur" == -* ]]; then
> + if [[ -n "${words[1]}" && "${words[1]}" != -* ]]; then
> + local opts=$(${script} ${words[1]} --list-opts 2>/dev/null)
> + COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
> + return 0
> + else
> + local opts=$(${script} --list-opts 2>/dev/null)
> + COMPREPLY=($(compgen -W "${opts}" -- "$cur"))
> + return 0
> + fi
> + fi
> +}
> +
> +complete -o default -F _kunit kunit.py
> +complete -o default -F _kunit kunit
> diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
> index cd99c1956331dbbfb06cf4ddf130db3dcf2a7c31..a5aee1eb88e65fa2387b2623642d2ee9a66db600 100755
> --- a/tools/testing/kunit/kunit.py
> +++ b/tools/testing/kunit/kunit.py
> @@ -323,6 +323,17 @@ def get_default_jobs() -> int:
> return ncpu
> raise RuntimeError("os.cpu_count() returned None")
>
> +def add_completion_opts(parser: argparse.ArgumentParser) -> None:
> + parser.add_argument('--list-opts',
> + help=argparse.SUPPRESS,
> + action='store_true')
> +
> +def add_root_opts(parser: argparse.ArgumentParser) -> None:
> + parser.add_argument('--list-cmds',
> + help=argparse.SUPPRESS,
> + action='store_true')
> + add_completion_opts(parser)
> +
> def add_common_opts(parser: argparse.ArgumentParser) -> None:
> parser.add_argument('--build_dir',
> help='As in the make command, it specifies the build '
> @@ -374,6 +385,8 @@ def add_common_opts(parser: argparse.ArgumentParser) -> None:
> help='Additional QEMU arguments, e.g. "-smp 8"',
> action='append', metavar='')
>
> + add_completion_opts(parser)
> +
> def add_build_opts(parser: argparse.ArgumentParser) -> None:
> parser.add_argument('--jobs',
> help='As in the make command, "Specifies the number of '
> @@ -569,6 +582,7 @@ subcommand_handlers_map = {
> def main(argv: Sequence[str]) -> None:
> parser = argparse.ArgumentParser(
> description='Helps writing and running KUnit tests.')
> + add_root_opts(parser)
> subparser = parser.add_subparsers(dest='subcommand')
>
> # The 'run' command will config, build, exec, and parse in one go.
> @@ -603,12 +617,28 @@ def main(argv: Sequence[str]) -> None:
> parse_parser.add_argument('file',
> help='Specifies the file to read results from.',
> type=str, nargs='?', metavar='input_file')
> + add_completion_opts(parse_parser)
>
> cli_args = parser.parse_args(massage_argv(argv))
>
> if get_kernel_root_path():
> os.chdir(get_kernel_root_path())
>
> + if cli_args.list_cmds:
> + print(" ".join(subparser.choices.keys()))
> + return
> +
> + if cli_args.list_opts:
> + target_parser = subparser.choices.get(cli_args.subcommand)
> + if not target_parser:
> + target_parser = parser
> +
> + # Accessing private attribute _option_string_actions to get
> + # the list of options. This is not a public API, but argparse
> + # does not provide a way to inspect options programmatically.
> + print(' '.join(target_parser._option_string_actions.keys()))
> + return
> +
> subcomand_handler = subcommand_handlers_map.get(cli_args.subcommand, None)
>
> if subcomand_handler is None:
> diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
> index bbba921e0eacb18663abfcabb2bccf330d8666f5..a7f09a6c97a473ff85e087d17c2f5faf7755b994 100755
> --- a/tools/testing/kunit/kunit_tool_test.py
> +++ b/tools/testing/kunit/kunit_tool_test.py
> @@ -11,11 +11,13 @@ from unittest import mock
>
> import tempfile, shutil # Handling test_tmpdir
>
> +import io
> import itertools
> import json
> import os
> import signal
> import subprocess
> +import sys
> from typing import Iterable
>
> import kunit_config
> @@ -855,5 +857,24 @@ class KUnitMainTest(unittest.TestCase):
> mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test1', filter='', filter_action=None, timeout=300),
> ])
>
> + @mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
> + def test_list_cmds(self, mock_stdout):
> + kunit.main(['--list-cmds'])
> + output = mock_stdout.getvalue()
> + output_cmds = sorted(output.split())
> + expected_cmds = sorted(['build', 'config', 'exec', 'parse', 'run'])
> + self.assertEqual(output_cmds, expected_cmds)
> +
> + @mock.patch.object(sys, 'stdout', new_callable=io.StringIO)
> + def test_run_list_opts(self, mock_stdout):
> + kunit.main(['run', '--list-opts'])
> + output = mock_stdout.getvalue()
> + output_cmds = set(output.split())
> + self.assertIn('--help', output_cmds)
> + self.assertIn('--kunitconfig', output_cmds)
> + self.assertIn('--jobs', output_cmds)
> + self.assertIn('--kernel_args', output_cmds)
> + self.assertIn('--raw_output', output_cmds)
> +
> if __name__ == '__main__':
> unittest.main()
>
> ---
> base-commit: b71e635feefc852405b14620a7fc58c4c80c0f73
> change-id: 20260114-kunit-completion-265889f59c52
>
> Best regards,
--
Jani Nikula, Intel
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] kunit: add bash completion
2026-01-16 9:30 ` David Gow
@ 2026-01-16 16:58 ` Ryota Sakamoto
0 siblings, 0 replies; 5+ messages in thread
From: Ryota Sakamoto @ 2026-01-16 16:58 UTC (permalink / raw)
To: David Gow
Cc: Brendan Higgins, Rae Moar, Jonathan Corbet, linux-kernel,
linux-kselftest, kunit-dev, workflows, linux-doc
Hi David,
Thank you for the review.
On Fri, Jan 16, 2026 at 05:30:22PM +0800, David Gow wrote:
> Two small suggestions:
> - Could we add './tools/testing/kunit/kunit.py' to the list of
> commands? That's what's recommended in lots of documentation, emails,
> etc.
Sure, I will add the relative path of the script explicitly.
> - It'd be great to rebase this on top of kselftest/kunit -- there's a
> conflict with your previous patch.
I will rebase the patch on top of kselftest/kunit to resolve the conflict.
Regards,
Ryota Sakamoto
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] kunit: add bash completion
2026-01-16 10:10 ` Jani Nikula
@ 2026-01-16 17:16 ` Ryota Sakamoto
0 siblings, 0 replies; 5+ messages in thread
From: Ryota Sakamoto @ 2026-01-16 17:16 UTC (permalink / raw)
To: Jani Nikula
Cc: Brendan Higgins, David Gow, Rae Moar, Jonathan Corbet,
linux-kernel, linux-kselftest, kunit-dev, workflows, linux-doc
Hi Jani,
Thank you for the suggestion regarding shtab.
On Fri, Jan 16, 2026 at 12:10:27PM +0200, Jani Nikula wrote:
> The alternative would be to make the tool more friendly to existing
> completion tools such as shtab [1]. Since the kernel as a project is
> really averse to adding external dependencies, you could take shtab's
> CLI approach, and commit the completion script in the repo. Only
> whoever's updating the completions would have to install and run shtab.
I understand your point about avoiding homebrew solutions, however, a main
benefit of this approach is that the completion script does not need to be
regenerated or updated manually.
Using shtab would introduce a new dependency and maintenance where the
static completion script could easily get out of sync.
So I would like to proceed with the current approach.
> And the whole thing could be taken a step further, adding, say,
> tools/completions/{bash,zsh,tcsh,...} directories for all the kernel
> tool completions instead of spreading them around.
I agree that centralizing completions is a good idea. So it would be better
handled as a separate future effort because it is a tree-wide
reorganization.
Regards,
Ryota Sakamoto
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-01-16 17:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-15 14:53 [PATCH] kunit: add bash completion Ryota Sakamoto
2026-01-16 9:30 ` David Gow
2026-01-16 16:58 ` Ryota Sakamoto
2026-01-16 10:10 ` Jani Nikula
2026-01-16 17:16 ` Ryota Sakamoto
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox