From 81c7ff67373c4ce6a05433ee6d47122aee67e93a Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sun, 11 Oct 2026 20:58:23 +0200 Subject: [PATCH] Name each line of a joined error under the command, test the command name as a pure function, and pin the version line's fallback --- cli/cli.go | 17 ++++++++++++----- cli/cli_test.go | 21 ++++++++++++++++++++- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index 55dd7e2..e8e5836 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -569,14 +569,20 @@ func Main(modules ...fs.FS) int { if fi, err := os.Stdin.Stat(); err == nil && fi.Mode()&os.ModeCharDevice != 0 { stdin = nil } - name := filepath.Base(os.Args[0]) + return run(commandName(os.Args[0]), modules, os.Args[1:], stdin, os.Stdout, os.Stderr) +} + +// commandName is the name the command runs under: the file arg0 names, less a Windows +// .exe, or fejkdata where arg0 names none. +func commandName(arg0 string) string { + name := filepath.Base(arg0) if ext := filepath.Ext(name); strings.EqualFold(ext, ".exe") { name = strings.TrimSuffix(name, ext) } if name == "." || name == "" { - name = "fejkdata" + return "fejkdata" } - return run(name, modules, os.Args[1:], stdin, os.Stdout, os.Stderr) + return name } // run is Main over the given streams, run as the command name. A nil stdin is a terminal, @@ -657,9 +663,10 @@ func misuse(stderr io.Writer, name string, err error) int { return 2 } -// report writes err under the command name, in place of the library's own. +// report writes err under the command name, in place of the library's own on each line. func report(stderr io.Writer, name string, err error) { - fmt.Fprintf(stderr, "%s: %s\n", name, strings.TrimPrefix(err.Error(), "fejkdata: ")) + msg := strings.ReplaceAll(strings.TrimPrefix(err.Error(), "fejkdata: "), "\nfejkdata: ", "\n"+name+": ") + fmt.Fprintf(stderr, "%s: %s\n", name, msg) } // fejkdataModule is the path of the module holding the library; the root package's path is diff --git a/cli/cli_test.go b/cli/cli_test.go index 9f09896..fb86048 100644 --- a/cli/cli_test.go +++ b/cli/cli_test.go @@ -456,6 +456,7 @@ func TestVersionLineNamesFejkdatasVersion(t *testing.T) { {&debug.BuildInfo{Main: mycli, Deps: []*debug.Module{fejkdata("v0.1.0", nil)}}, "mycli v9.0.0, fejkdata v0.1.0"}, {&debug.BuildInfo{Main: mycli, Deps: []*debug.Module{fejkdata("v0.1.0", &debug.Module{Path: "../fejkdata"})}}, "mycli v9.0.0, fejkdata devel"}, {&debug.BuildInfo{Main: mycli, Deps: []*debug.Module{fejkdata("v0.1.0", &debug.Module{Path: "example.com/fork", Version: "v0.1.1"})}}, "mycli v9.0.0, fejkdata v0.1.1"}, + {&debug.BuildInfo{Main: mycli}, "mycli v9.0.0, fejkdata devel"}, {nil, "fejkdata devel"}, } { if got := versionLine("mycli", c.info); got != c.want { @@ -464,6 +465,20 @@ func TestVersionLineNamesFejkdatasVersion(t *testing.T) { } } +func TestCommandNameIsTheFileItRunsFrom(t *testing.T) { + for arg0, want := range map[string]string{ + "/usr/local/bin/mycli": "mycli", + "mycli.EXE": "mycli", + "mycli.exe": "mycli", + "my.cli": "my.cli", + "": "fejkdata", + } { + if got := commandName(arg0); got != want { + t.Errorf("commandName(%q) = %q, want %q", arg0, got, want) + } + } +} + func TestRunNamesItselfByTheCommandName(t *testing.T) { var out, errb bytes.Buffer if code := run("mycli", shipped, []string{"--nope"}, nil, &out, &errb); code != 2 || errb.String() != "mycli: unknown flag --nope\ntry 'mycli --help'\n" { @@ -474,7 +489,11 @@ func TestRunNamesItselfByTheCommandName(t *testing.T) { t.Errorf("mycli with nothing piped = %d, %q, want a pipe into mycli", code, errb.String()) } errb.Reset() - if code := run("mycli", shipped, []string{"-d", "/nope"}, strings.NewReader("{/sv_SE.person}"), &out, &errb); code != 1 || !strings.HasPrefix(errb.String(), "mycli: ") { + if code := run("mycli", []fs.FS{nil, nil}, nil, strings.NewReader("x"), &out, &errb); code != 1 || strings.Count(errb.String(), "mycli: ") != 2 || strings.Contains(errb.String(), "fejkdata") { + t.Errorf("mycli over two nil modules = %d, %q, want each line under mycli", code, errb.String()) + } + errb.Reset() + if code := run("mycli", shipped, []string{"-d", "/nope"}, strings.NewReader("{/sv_SE.person}"), &out, &errb); code != 1 || !strings.HasPrefix(errb.String(), "mycli: ") || strings.Contains(errb.String(), "fejkdata") { t.Errorf("mycli -d /nope = %d, %q, want a load error under mycli", code, errb.String()) } if code := run("mycli", shipped, []string{"--help"}, nil, &out, &errb); code != 0 || !strings.HasPrefix(out.String(), "Usage: