refactor(10.2-01): nest framework packages under modules
- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
This commit is contained in:
170
modules/bonfire/output.go
Normal file
170
modules/bonfire/output.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package bonfire
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
const (
|
||||
ansiReset = "\x1b[0m"
|
||||
ansiRed = "\x1b[31m"
|
||||
ansiGreen = "\x1b[32m"
|
||||
ansiYellow = "\x1b[33m"
|
||||
ansiCyan = "\x1b[36m"
|
||||
ansiDim = "\x1b[90m"
|
||||
|
||||
symCheck = "✓"
|
||||
symCross = "✗"
|
||||
symWarn = "⚠"
|
||||
symInfo = "ℹ"
|
||||
symArrow = "→"
|
||||
symPrompt = "?"
|
||||
)
|
||||
|
||||
// Output is the injected console used by commands. Tests supply streams.
|
||||
type Output interface {
|
||||
io.Writer
|
||||
Println(a ...any)
|
||||
Printf(format string, a ...any)
|
||||
Info(message string)
|
||||
Success(message string)
|
||||
Error(message string)
|
||||
Warning(message string)
|
||||
Table(headers []string, rows [][]string)
|
||||
Spinner(message string, fn func() error) error
|
||||
Progress(total int, fn func(Progress) error) error
|
||||
Ask(question, def string) (string, error)
|
||||
Confirm(question string, def bool) (bool, error)
|
||||
Choice(question string, choices []string, def int) (string, error)
|
||||
Secret(question string) (string, error)
|
||||
}
|
||||
|
||||
// Progress is a single progress bar advanced from a command.
|
||||
type Progress interface {
|
||||
Advance(step int)
|
||||
}
|
||||
|
||||
type console struct {
|
||||
in io.Reader
|
||||
out io.Writer
|
||||
err io.Writer
|
||||
lookup func(string) string
|
||||
tty bool
|
||||
interactive bool
|
||||
color bool
|
||||
}
|
||||
|
||||
// NewOutput builds Output from injected streams and the process color policy.
|
||||
func NewOutput(in io.Reader, out, errW io.Writer) Output {
|
||||
return newConsole(in, out, errW, os.Getenv, nil, nil)
|
||||
}
|
||||
|
||||
func newConsole(in io.Reader, out, errW io.Writer, lookup func(string) string, tty, interactive *bool) *console {
|
||||
if in == nil {
|
||||
in = os.Stdin
|
||||
}
|
||||
if out == nil {
|
||||
out = os.Stdout
|
||||
}
|
||||
if errW == nil {
|
||||
errW = out
|
||||
}
|
||||
if lookup == nil {
|
||||
lookup = os.Getenv
|
||||
}
|
||||
c := &console{in: in, out: out, err: errW, lookup: lookup}
|
||||
if tty != nil {
|
||||
c.tty = *tty
|
||||
} else {
|
||||
c.tty = isTerminal(out)
|
||||
}
|
||||
if interactive != nil {
|
||||
c.interactive = *interactive
|
||||
} else {
|
||||
c.interactive = isTerminal(in) && c.tty
|
||||
}
|
||||
c.color = supportsColor(lookup, c.tty)
|
||||
return c
|
||||
}
|
||||
|
||||
func supportsColor(lookup func(string) string, tty bool) bool {
|
||||
if lookup == nil {
|
||||
lookup = os.Getenv
|
||||
}
|
||||
if lookup("NO_COLOR") != "" || lookup("TERM") == "dumb" {
|
||||
return false
|
||||
}
|
||||
if lookup("FORCE_COLOR") != "" {
|
||||
return true
|
||||
}
|
||||
return tty
|
||||
}
|
||||
|
||||
func isTerminal(rw any) bool {
|
||||
type fd interface{ Fd() uintptr }
|
||||
f, ok := rw.(fd)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return term.IsTerminal(int(f.Fd()))
|
||||
}
|
||||
|
||||
func (c *console) Write(p []byte) (int, error) {
|
||||
if c.out == nil {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
return c.out.Write(p)
|
||||
}
|
||||
|
||||
func (c *console) Println(a ...any) {
|
||||
if c.out == nil {
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(c.out, a...)
|
||||
}
|
||||
|
||||
func (c *console) Printf(format string, a ...any) {
|
||||
if c.out == nil {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(c.out, format, a...)
|
||||
}
|
||||
|
||||
func (c *console) Info(message string) {
|
||||
c.Println(c.style(ansiCyan, symInfo) + " " + message)
|
||||
}
|
||||
|
||||
func (c *console) Success(message string) {
|
||||
c.Println(c.style(ansiGreen, symCheck) + " " + message)
|
||||
}
|
||||
|
||||
func (c *console) Error(message string) {
|
||||
w := c.err
|
||||
if w == nil {
|
||||
w = c.out
|
||||
}
|
||||
if w == nil {
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(w, c.style(ansiRed, symCross)+" "+message)
|
||||
}
|
||||
|
||||
func (c *console) Warning(message string) {
|
||||
c.Println(c.style(ansiYellow, symWarn) + " " + message)
|
||||
}
|
||||
|
||||
func (c *console) style(code, s string) string {
|
||||
if !c.color {
|
||||
return s
|
||||
}
|
||||
return code + s + ansiReset
|
||||
}
|
||||
|
||||
func (c *console) dim(s string) string {
|
||||
return c.style(ansiDim, s)
|
||||
}
|
||||
|
||||
func boolPtr(v bool) *bool { return &v }
|
||||
Reference in New Issue
Block a user