Move the command tree into internal/cli #9

Merged
clawbot merged 2 commits from issue-8-cli-package into next 2026-09-29 01:51:35 +02:00
3 changed files with 31 additions and 18 deletions
Showing only changes of commit 54596ef54b - Show all commits
+11 -12
View File
@@ -4,8 +4,8 @@ package cli
import ( import (
"fmt" "fmt"
"io"
"os" "github.com/spf13/cobra"
) )
// appname is the name the program reports in its logs and its version. // appname is the name the program reports in its logs and its version.
@@ -13,23 +13,22 @@ const appname = "simplexcalc"
// Main runs the command named on the command line and returns the exit // Main runs the command named on the command line and returns the exit
// status for main to pass to os.Exit. // status for main to pass to os.Exit.
//
// It leaves cobra's output streams at their defaults. cobra writes the
// usage and an unknown help topic to stderr, but SetOut moves them onto
// the stream it is given.
func Main(version string) int { func Main(version string) int {
return execute(version, os.Args[1:], os.Stdout, os.Stderr) return execute(rootCmd(version))
} }
// execute is Main with the arguments and the output passed in, so that // execute runs root and returns the exit status. It takes the command
// a test can supply them. // so that a test can set its arguments and output streams first.
func execute(version string, args []string, stdout, stderr io.Writer) int { func execute(root *cobra.Command) int {
root := rootCmd(version)
root.SetArgs(args)
root.SetOut(stdout)
root.SetErr(stderr)
err := root.Execute() err := root.Execute()
if err != nil { if err != nil {
// cobra has already printed the error; this only sets the exit // cobra has already printed the error; this only sets the exit
// status, which is what a supervisor and a shell script read. // status, which is what a supervisor and a shell script read.
_, _ = fmt.Fprintln(stderr, "exiting: "+err.Error()) _, _ = fmt.Fprintln(root.ErrOrStderr(), "exiting: "+err.Error())
return 1 return 1
} }
+12 -2
View File
@@ -14,7 +14,12 @@ func TestVersionPrintsVersion(t *testing.T) {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
status := cli.Execute("1.2.3", []string{"version"}, &stdout, &stderr) root := cli.RootCmd("1.2.3")
root.SetArgs([]string{"version"})
root.SetOut(&stdout)
root.SetErr(&stderr)
status := cli.Execute(root)
if status != 0 { if status != 0 {
t.Fatalf("status = %d, want 0; stderr: %q", status, stderr.String()) t.Fatalf("status = %d, want 0; stderr: %q", status, stderr.String())
} }
@@ -30,7 +35,12 @@ func TestUnknownCommandFails(t *testing.T) {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
status := cli.Execute("1.2.3", []string{"frobnicate"}, &stdout, &stderr) root := cli.RootCmd("1.2.3")
root.SetArgs([]string{"frobnicate"})
root.SetOut(&stdout)
root.SetErr(&stderr)
status := cli.Execute(root)
if status == 0 { if status == 0 {
t.Fatal("status = 0, want non-zero") t.Fatal("status = 0, want non-zero")
} }
+8 -4
View File
@@ -1,7 +1,11 @@
package cli package cli
// Execute is execute, exported for the external test package, which // RootCmd and Execute are rootCmd and execute, exported for the external
// needs to supply the arguments and read the output. // test package, which builds the command tree itself so that it can
// supply the arguments and read the output.
// //
//nolint:gochecknoglobals // a test seam, not mutable state. //nolint:gochecknoglobals // test seams, not mutable state.
var Execute = execute var (
RootCmd = rootCmd
Execute = execute
)