From 200f3b74cb64df5751c8896e0a20336b6ee4a796 Mon Sep 17 00:00:00 2001 From: Jussi Maki Date: Tue, 3 Dec 2024 12:19:29 +0100 Subject: [PATCH 1/2] script: Fix crash when help called with unknown command 'help some-unknown-command' crashed as ListCmds wasn't checking if the command was actually found from the commands map. Signed-off-by: Jussi Maki --- script/engine.go | 6 +++++- script/scripttest/testdata/basic.txt | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/script/engine.go b/script/engine.go index 75293cb..c1f937c 100644 --- a/script/engine.go +++ b/script/engine.go @@ -766,7 +766,11 @@ func (e *Engine) ListCmds(w io.Writer, verbose bool, names ...string) error { } for _, name := range names { - cmd := e.Cmds[name] + cmd, ok := e.Cmds[name] + if !ok { + fmt.Fprintf(w, "command %q not found\n", name) + continue + } usage := cmd.Usage() suffix := "" diff --git a/script/scripttest/testdata/basic.txt b/script/scripttest/testdata/basic.txt index a137da1..57981fe 100644 --- a/script/scripttest/testdata/basic.txt +++ b/script/scripttest/testdata/basic.txt @@ -18,5 +18,11 @@ echo hello wait +# Test help in various ways +help +help wait +help -v wait +help unknowncommand + -- hello.txt -- hello world From 211950c3804e39dbb42dc6d449e6076ad6204214 Mon Sep 17 00:00:00 2001 From: Jussi Maki Date: Tue, 3 Dec 2024 12:27:36 +0100 Subject: [PATCH 2/2] script: Implement regexp filtering for help Filter the commands shown by 'help' with a regexp instead of searching by name. This will become useful when there are many commands sharing the same prefix, for example StateDB has 11 commands and with this we can dump the help for all of them with 'help ^db'. Signed-off-by: Jussi Maki --- script/cmds.go | 6 ++++-- script/engine.go | 28 +++++++++++++++------------- script/scripttest/testdata/basic.txt | 6 ++++++ 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/script/cmds.go b/script/cmds.go index 7ae0a79..1e180ae 100644 --- a/script/cmds.go +++ b/script/cmds.go @@ -716,11 +716,13 @@ func Help() Cmd { return Command( CmdUsage{ Summary: "log help text for commands and conditions", - Args: "[-v] name...", + Args: "[-v] (regexp)", Detail: []string{ "To display help for a specific condition, enclose it in brackets: 'help [amd64]'.", "To display complete documentation when listing all commands, pass the -v flag.", + "Commands can be filtered with a regexp: 'help ^db'", }, + RegexpArgs: firstNonFlag, }, func(s *State, args ...string) (WaitFunc, error) { if s.engine == nil { @@ -757,7 +759,7 @@ func Help() Cmd { if len(args) == 0 { out.WriteString("\ncommands:\n\n") } - s.engine.ListCmds(out, verbose, cmds...) + s.engine.ListCmds(out, verbose, strings.Join(cmds, " ")) } wait := func(*State) (stdout, stderr string, err error) { diff --git a/script/engine.go b/script/engine.go index c1f937c..8dcda17 100644 --- a/script/engine.go +++ b/script/engine.go @@ -58,6 +58,7 @@ import ( "errors" "fmt" "io" + "regexp" "sort" "strings" "time" @@ -752,25 +753,26 @@ func checkStatus(cmd *command, err error) error { // ListCmds prints to w a list of the named commands, // annotating each with its arguments and a short usage summary. // If verbose is true, ListCmds prints full details for each command. -// -// Each of the name arguments should be a command name. -// If no names are passed as arguments, ListCmds lists all the -// commands registered in e. -func (e *Engine) ListCmds(w io.Writer, verbose bool, names ...string) error { - if names == nil { - names = make([]string, 0, len(e.Cmds)) - for name := range e.Cmds { - names = append(names, name) +func (e *Engine) ListCmds(w io.Writer, verbose bool, regexMatch string) error { + var re *regexp.Regexp + if regexMatch != "" { + var err error + re, err = regexp.Compile(regexMatch) + if err != nil { + return err } - sort.Strings(names) } + names := make([]string, 0, len(e.Cmds)) + for name := range e.Cmds { + names = append(names, name) + } + sort.Strings(names) for _, name := range names { - cmd, ok := e.Cmds[name] - if !ok { - fmt.Fprintf(w, "command %q not found\n", name) + if re != nil && !re.MatchString(name) { continue } + cmd := e.Cmds[name] usage := cmd.Usage() suffix := "" diff --git a/script/scripttest/testdata/basic.txt b/script/scripttest/testdata/basic.txt index 57981fe..5278cec 100644 --- a/script/scripttest/testdata/basic.txt +++ b/script/scripttest/testdata/basic.txt @@ -21,8 +21,14 @@ wait # Test help in various ways help help wait +grep wait help -v wait +grep wait help unknowncommand +help ^e +! grep wait +grep ^exec +grep ^exists -- hello.txt -- hello world