Files
mcr/cmd/mcrctl/output.go
Kyle Isom 593da3975d Phases 11, 12: mcrctl CLI tool and mcr-web UI
Phase 11 implements the admin CLI with dual REST/gRPC transport,
global flags (--server, --grpc, --token, --ca-cert, --json), and
all commands: status, repo list/delete, policy CRUD, audit tail,
gc trigger/status/reconcile, and snapshot.

Phase 12 implements the HTMX web UI with chi router, session-based
auth (HttpOnly/Secure/SameSite=Strict cookies), CSRF protection
(HMAC-SHA256 signed double-submit), and pages for dashboard,
repositories, manifest detail, policy management, and audit log.

Security: CSRF via signed double-submit cookie, session cookies
with HttpOnly/Secure/SameSite=Strict, TLS 1.3 minimum on all
connections, form body size limits via http.MaxBytesReader.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:14:38 -07:00

66 lines
1.4 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io"
"os"
"text/tabwriter"
)
// formatSize returns a human-friendly representation of a byte count.
func formatSize(bytes int64) string {
const (
kb = 1024
mb = kb * 1024
gb = mb * 1024
tb = gb * 1024
)
switch {
case bytes >= tb:
return fmt.Sprintf("%.1f TB", float64(bytes)/float64(tb))
case bytes >= gb:
return fmt.Sprintf("%.1f GB", float64(bytes)/float64(gb))
case bytes >= mb:
return fmt.Sprintf("%.1f MB", float64(bytes)/float64(mb))
case bytes >= kb:
return fmt.Sprintf("%.1f KB", float64(bytes)/float64(kb))
default:
return fmt.Sprintf("%d B", bytes)
}
}
// printJSON marshals v as indented JSON and writes it to stdout.
func printJSON(v any) error {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(v)
}
// printTable writes a table with the given headers and rows.
// Each row must have the same number of columns as headers.
func printTable(w io.Writer, headers []string, rows [][]string) {
tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)
// Print header.
for i, h := range headers {
if i > 0 {
_, _ = fmt.Fprint(tw, "\t")
}
_, _ = fmt.Fprint(tw, h)
}
_, _ = fmt.Fprintln(tw)
// Print rows.
for _, row := range rows {
for i, col := range row {
if i > 0 {
_, _ = fmt.Fprint(tw, "\t")
}
_, _ = fmt.Fprint(tw, col)
}
_, _ = fmt.Fprintln(tw)
}
_ = tw.Flush()
}