From 07330be10b6676e58c875141ca0705dd54180840 Mon Sep 17 00:00:00 2001 From: lew Date: Wed, 11 Feb 2026 13:17:23 +0000 Subject: [PATCH] feat: include summary of omitted binary data --- README.md | 10 +++---- cmd/get.go | 6 ++-- cmd/list.go | 6 ++-- cmd/shared.go | 35 +++++++++++++++++++++--- testdata/get__missing__err__with__any.ct | 6 ++-- testdata/get__ok__with__binary.ct | 2 +- testdata/get__ok__with__binary_run.ct | 2 +- testdata/help__get__ok.ct | 16 +++++------ testdata/help__list__ok.ct | 4 +-- 9 files changed, 57 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 679f0ae..146eba4 100644 --- a/README.md +++ b/README.md @@ -563,15 +563,15 @@ pda get logo > output.png

-`list` and `get` will omit binary data whenever it's a human reading it. If it's being piped somewhere or ran outside of a TTY, it'll output the whole data. +`list` and `get` will show a summary for binary data on a TTY. If it's being piped somewhere or ran outside of a TTY, it'll output the raw bytes. -`include-binary` to show the full binary data regardless. +`--base64`/`-b` to view binary data as base64 on a TTY. ```bash pda get logo -# (omitted binary data) +# (binary: 4.2 KB, image/png) -pda get logo --include-binary -# 89504E470D0A1A0A0000000D4948445200000001000000010802000000 +pda get logo --base64 +# iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADklEQVQI12... ```

diff --git a/cmd/get.go b/cmd/get.go index eeead61..54c3b7c 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -100,7 +100,7 @@ func get(cmd *cobra.Command, args []string) error { } v := entry.Value - binary, err := cmd.Flags().GetBool("include-binary") + binary, err := cmd.Flags().GetBool("base64") if err != nil { return fmt.Errorf("cannot get '%s': %v", args[0], err) } @@ -235,12 +235,12 @@ func run(cmd *cobra.Command, args []string) error { var runFlag bool func init() { - getCmd.Flags().BoolP("include-binary", "b", false, "include binary data in text output") + getCmd.Flags().BoolP("base64", "b", false, "view binary data as base64") getCmd.Flags().BoolVarP(&runFlag, "run", "c", false, "execute the result as a shell command") getCmd.Flags().Bool("no-template", false, "directly output template syntax") rootCmd.AddCommand(getCmd) - runCmd.Flags().BoolP("include-binary", "b", false, "include binary data in text output") + runCmd.Flags().BoolP("base64", "b", false, "view binary data as base64") runCmd.Flags().Bool("no-template", false, "directly output template syntax") rootCmd.AddCommand(runCmd) } diff --git a/cmd/list.go b/cmd/list.go index 7166a80..b9b4bee 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -55,7 +55,7 @@ func (e *formatEnum) Set(v string) error { func (e *formatEnum) Type() string { return "format" } var ( - listBinary bool + listBase64 bool listNoKeys bool listNoValues bool listTTL bool @@ -194,7 +194,7 @@ func list(cmd *cobra.Command, args []string) error { if e.Locked { valueStr = "locked (identity file missing)" } else { - valueStr = store.FormatBytes(listBinary, e.Value) + valueStr = store.FormatBytes(listBase64, e.Value) } } row := make(table.Row, 0, len(columns)) @@ -315,7 +315,7 @@ func renderTable(tw table.Writer) { } func init() { - listCmd.Flags().BoolVarP(&listBinary, "binary", "b", false, "include binary data in text output") + listCmd.Flags().BoolVarP(&listBase64, "base64", "b", false, "view binary data as base64") listCmd.Flags().BoolVar(&listNoKeys, "no-keys", false, "suppress the key column") listCmd.Flags().BoolVar(&listNoValues, "no-values", false, "suppress the value column") listCmd.Flags().BoolVarP(&listTTL, "ttl", "t", false, "append a TTL column when entries expire") diff --git a/cmd/shared.go b/cmd/shared.go index 3b72ad2..76fb1cd 100644 --- a/cmd/shared.go +++ b/cmd/shared.go @@ -23,8 +23,10 @@ THE SOFTWARE. package cmd import ( + "encoding/base64" "fmt" "io" + "net/http" "os" "path/filepath" "strings" @@ -67,14 +69,39 @@ func (s *Store) FormatBytes(includeBinary bool, v []byte) string { return s.formatBytes(includeBinary, v) } -func (s *Store) formatBytes(includeBinary bool, v []byte) string { - tty := term.IsTerminal(int(os.Stdout.Fd())) - if tty && !includeBinary && !utf8.Valid(v) { - return "(omitted binary data)" +func (s *Store) formatBytes(base64Flag bool, v []byte) string { + if !utf8.Valid(v) { + tty := term.IsTerminal(int(os.Stdout.Fd())) + if !tty { + return string(v) + } + if base64Flag { + return base64.StdEncoding.EncodeToString(v) + } + mime := http.DetectContentType(v) + return fmt.Sprintf("(binary: %s, %s)", formatSize(len(v)), mime) } return string(v) } +func formatSize(n int) string { + const ( + kb = 1024 + mb = 1024 * kb + gb = 1024 * mb + ) + switch { + case n < kb: + return fmt.Sprintf("%d B", n) + case n < mb: + return fmt.Sprintf("%.1f KB", float64(n)/float64(kb)) + case n < gb: + return fmt.Sprintf("%.1f MB", float64(n)/float64(mb)) + default: + return fmt.Sprintf("%.1f GB", float64(n)/float64(gb)) + } +} + func (s *Store) storePath(name string) (string, error) { if name == "" { name = config.Store.DefaultStoreName diff --git a/testdata/get__missing__err__with__any.ct b/testdata/get__missing__err__with__any.ct index 5f03ce9..b4fe45a 100644 --- a/testdata/get__missing__err__with__any.ct +++ b/testdata/get__missing__err__with__any.ct @@ -1,7 +1,7 @@ $ pda get foobar --> FAIL -$ pda get foobar --include-binary --> FAIL -$ pda get foobar --include-binary --run --> FAIL -$ pda get foobar --include-binary --run --secret --> FAIL +$ pda get foobar --base64 --> FAIL +$ pda get foobar --base64 --run --> FAIL +$ pda get foobar --base64 --run --secret --> FAIL $ pda get foobar --run --> FAIL $ pda get foobar --run --secret --> FAIL $ pda get foobar --secret --> FAIL diff --git a/testdata/get__ok__with__binary.ct b/testdata/get__ok__with__binary.ct index ce97ada..67be970 100644 --- a/testdata/get__ok__with__binary.ct +++ b/testdata/get__ok__with__binary.ct @@ -1,3 +1,3 @@ $ pda set a b -$ pda get a --include-binary +$ pda get a --base64 b diff --git a/testdata/get__ok__with__binary_run.ct b/testdata/get__ok__with__binary_run.ct index a398a54..bcc3bc5 100644 --- a/testdata/get__ok__with__binary_run.ct +++ b/testdata/get__ok__with__binary_run.ct @@ -1,4 +1,4 @@ $ fecho cmd echo hello $ pda set foo < cmd -$ pda get foo --include-binary --run +$ pda get foo --base64 --run hello diff --git a/testdata/help__get__ok.ct b/testdata/help__get__ok.ct index 46a269d..c429da8 100644 --- a/testdata/help__get__ok.ct +++ b/testdata/help__get__ok.ct @@ -16,10 +16,10 @@ Aliases: get, g Flags: - -h, --help help for get - -b, --include-binary include binary data in text output - --no-template directly output template syntax - -c, --run execute the result as a shell command + -b, --base64 view binary data as base64 + -h, --help help for get + --no-template directly output template syntax + -c, --run execute the result as a shell command Get the value of a key. Optionally specify a store. {{ .TEMPLATES }} can be filled by passing TEMPLATE=VALUE as an @@ -36,7 +36,7 @@ Aliases: get, g Flags: - -h, --help help for get - -b, --include-binary include binary data in text output - --no-template directly output template syntax - -c, --run execute the result as a shell command + -b, --base64 view binary data as base64 + -h, --help help for get + --no-template directly output template syntax + -c, --run execute the result as a shell command diff --git a/testdata/help__list__ok.ct b/testdata/help__list__ok.ct index 40658c4..2201bd3 100644 --- a/testdata/help__list__ok.ct +++ b/testdata/help__list__ok.ct @@ -9,7 +9,7 @@ Aliases: list, ls Flags: - -b, --binary include binary data in text output + -b, --base64 view binary data as base64 -o, --format format output format (table|tsv|csv|markdown|html|ndjson) (default table) -g, --glob strings Filter keys with glob pattern (repeatable) --glob-sep string Characters treated as separators for globbing (default '/-_.@: ') @@ -27,7 +27,7 @@ Aliases: list, ls Flags: - -b, --binary include binary data in text output + -b, --base64 view binary data as base64 -o, --format format output format (table|tsv|csv|markdown|html|ndjson) (default table) -g, --glob strings Filter keys with glob pattern (repeatable) --glob-sep string Characters treated as separators for globbing (default '/-_.@: ')