A virtual jailed shell environment for Go apps backed by an io/fs#FS.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(command): port whoami from just-bash

Assisted-by: Claude Opus 4.7 via Claude Code
Signed-off-by: Xe Iaso <me@xeiaso.net>

Xe Iaso 3990f1c9 d956a16c

+150
+56
command/internal/whoami/whoami.go
··· 1 + package whoami 2 + 3 + import ( 4 + "context" 5 + "errors" 6 + "fmt" 7 + "io" 8 + 9 + "github.com/pborman/getopt/v2" 10 + "mvdan.cc/sh/v3/interp" 11 + "tangled.org/xeiaso.net/kefka/command" 12 + ) 13 + 14 + type Impl struct{} 15 + 16 + func (Impl) Exec(ctx context.Context, ec *command.ExecContext, args []string) error { 17 + if ec == nil { 18 + return errors.New("whoami: nil ExecContext") 19 + } 20 + 21 + stdout := ec.Stdout 22 + if stdout == nil { 23 + stdout = io.Discard 24 + } 25 + stderr := ec.Stderr 26 + if stderr == nil { 27 + stderr = io.Discard 28 + } 29 + 30 + set := getopt.New() 31 + set.SetProgram("whoami") 32 + set.SetParameters("") 33 + 34 + usage := func() { 35 + fmt.Fprint(stderr, "Usage: whoami [OPTION]...\n") 36 + fmt.Fprint(stderr, "Print the user name associated with the current effective user ID.\n\n") 37 + fmt.Fprint(stderr, " --help display this help and exit\n") 38 + } 39 + set.SetUsage(usage) 40 + 41 + help := set.BoolLong("help", 0, "display this help and exit") 42 + 43 + if err := set.Getopt(append([]string{"whoami"}, args...), nil); err != nil { 44 + fmt.Fprintf(stderr, "whoami: %s\n", err) 45 + usage() 46 + return interp.ExitStatus(1) 47 + } 48 + 49 + if *help { 50 + usage() 51 + return nil 52 + } 53 + 54 + io.WriteString(stdout, "user\n") 55 + return nil 56 + }
+94
command/internal/whoami/whoami_test.go
··· 1 + package whoami 2 + 3 + import ( 4 + "bytes" 5 + "context" 6 + "strings" 7 + "testing" 8 + 9 + "tangled.org/xeiaso.net/kefka/command" 10 + ) 11 + 12 + func run(t *testing.T, args []string) (string, string, error) { 13 + t.Helper() 14 + var stdout, stderr bytes.Buffer 15 + ec := &command.ExecContext{ 16 + Stdout: &stdout, 17 + Stderr: &stderr, 18 + Dir: ".", 19 + } 20 + err := Impl{}.Exec(context.Background(), ec, args) 21 + return stdout.String(), stderr.String(), err 22 + } 23 + 24 + func TestWhoami(t *testing.T) { 25 + tests := []struct { 26 + name string 27 + args []string 28 + wantStdout string 29 + wantErr bool 30 + }{ 31 + { 32 + name: "no args prints user", 33 + args: []string{}, 34 + wantStdout: "user\n", 35 + }, 36 + { 37 + name: "extra positional args are ignored", 38 + args: []string{"foo", "bar"}, 39 + wantStdout: "user\n", 40 + }, 41 + { 42 + name: "unknown flag returns error", 43 + args: []string{"--no-such-flag"}, 44 + wantErr: true, 45 + }, 46 + } 47 + 48 + for _, tt := range tests { 49 + t.Run(tt.name, func(t *testing.T) { 50 + stdout, stderr, err := run(t, tt.args) 51 + if tt.wantErr { 52 + if err == nil { 53 + t.Fatalf("expected error, got nil; stdout=%q stderr=%q", stdout, stderr) 54 + } 55 + return 56 + } 57 + if err != nil { 58 + t.Fatalf("unexpected error: %v; stderr=%q", err, stderr) 59 + } 60 + if stdout != tt.wantStdout { 61 + t.Errorf("stdout = %q, want %q", stdout, tt.wantStdout) 62 + } 63 + }) 64 + } 65 + } 66 + 67 + func TestHelp(t *testing.T) { 68 + stdout, stderr, err := run(t, []string{"--help"}) 69 + if err != nil { 70 + t.Fatalf("unexpected error: %v", err) 71 + } 72 + if stdout != "" { 73 + t.Errorf("expected empty stdout, got %q", stdout) 74 + } 75 + if !strings.Contains(stderr, "Usage: whoami [OPTION]...") { 76 + t.Errorf("usage line missing from stderr: %q", stderr) 77 + } 78 + if !strings.Contains(stderr, "--help") { 79 + t.Errorf("help flag missing from help text: %q", stderr) 80 + } 81 + } 82 + 83 + func TestNilStdout(t *testing.T) { 84 + ec := &command.ExecContext{Dir: "."} 85 + if err := (Impl{}).Exec(context.Background(), ec, nil); err != nil { 86 + t.Fatalf("unexpected error with nil stdout/stderr: %v", err) 87 + } 88 + } 89 + 90 + func TestNilExecContext(t *testing.T) { 91 + if err := (Impl{}).Exec(context.Background(), nil, nil); err == nil { 92 + t.Fatal("expected error with nil ExecContext, got nil") 93 + } 94 + }