blob: df06fa5495bc9510e0fa26b44685f6260895ed0b [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmdline
import (
"fmt"
"io"
"os"
"strconv"
"v.io/x/lib/envvar"
"v.io/x/lib/textutil"
)
// NewEnv returns a new environment with defaults based on the operating system.
func NewEnv() *Env {
return &Env{
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
Vars: envvar.SliceToMap(os.Environ()),
}
}
// Env represents the environment for command parsing and running. Typically
// NewEnv is used to produce a default environment. The environment may be
// explicitly set for finer control; e.g. in tests.
type Env struct {
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
Vars map[string]string // Environment variables
// Usage is a function that prints usage information to w. Typically set by
// calls to Main or Parse to print usage of the leaf command.
Usage func(w io.Writer)
}
// UsageErrorf prints the error message represented by the printf-style format
// and args, followed by the output of the Usage function. Returns ErrUsage to
// make it easy to use from within the Runner.Run function.
func (e *Env) UsageErrorf(format string, args ...interface{}) error {
return usageErrorf(e.Stderr, e.Usage, format, args...)
}
func usageErrorf(w io.Writer, usage func(io.Writer), format string, args ...interface{}) error {
fmt.Fprint(w, "ERROR: ")
fmt.Fprintf(w, format, args...)
fmt.Fprint(w, "\n\n")
if usage != nil {
usage(w)
} else {
fmt.Fprint(w, "usage error\n")
}
return ErrUsage
}
// defaultWidth is a reasonable default for the output width in runes.
const defaultWidth = 80
func (e *Env) width() int {
if width, err := strconv.Atoi(e.Vars["CMDLINE_WIDTH"]); err == nil && width != 0 {
return width
}
if _, width, err := textutil.TerminalSize(); err == nil && width != 0 {
return width
}
return defaultWidth
}
func (e *Env) style() style {
style := styleCompact
style.Set(e.Vars["CMDLINE_STYLE"])
return style
}
// style describes the formatting style for usage descriptions.
type style int
const (
styleCompact style = iota // Default style, good for compact cmdline output.
styleFull // Similar to compact but shows global flags.
styleGoDoc // Style good for godoc processing.
)
func (s *style) String() string {
switch *s {
case styleCompact:
return "compact"
case styleFull:
return "full"
case styleGoDoc:
return "godoc"
default:
panic(fmt.Errorf("unhandled style %d", *s))
}
}
// Set implements the flag.Value interface method.
func (s *style) Set(value string) error {
switch value {
case "compact":
*s = styleCompact
case "full":
*s = styleFull
case "godoc":
*s = styleGoDoc
default:
return fmt.Errorf("unknown style %q", value)
}
return nil
}