Documentation ¶
Overview ¶
Package cli provides simple tools for command line applications.
ExitHandler provides an enhanced sync.WaitGroup, along with the ability to coordinate the shutdown of multiple goroutines in long-running processes.
TermPrinter provides convenience functions to print output to Stdout and Stderr, including a simple "live writer" for status output.
Example ¶
package main import ( "errors" "os" "time" "kreklow.us/go/cli" ) func main() { cmd := cli.NewCmd() host := cmd.FlagSet.String("host", "localhost", "host name") user := cmd.FlagSet.String("user", "", "user name") err := cmd.FlagSet.Parse([]string{"-user", "test"}) if err != nil { cmd.Eprintln("unexpected error:", err) } msgs := make(chan []byte, 1) cmd.Add(1) // message receiver go func() { err := errors.New("unexpected shutdown") defer cmd.Done() // deferring Done() and Exit() helps ensure a clean defer cmd.Exit(err) // shutdown if the goroutine returns unexpectedly loop: for { select { case <-cmd.C: // exit signal, go to cleanup break loop case m := <-msgs: // processing tasks cmd.Printf("%s\n", m) } } // cleanup tasks cmd.Println("Cleaned up") }() // message sender go func() { cmd.Printf("connecting: %s@%s\n", *user, *host) time.Sleep(time.Second) msgs <- []byte("Message") cmd.Exit(nil) }() err = cmd.Wait() if err != nil { cmd.Eprintln(err) os.Exit(1) } }
Output: connecting: test@localhost Message Cleaned up
Index ¶
- type Cmd
- type ExitHandler
- type TermPrinter
- func (tp *TermPrinter) Eprint(v ...interface{}) (int, error)
- func (tp *TermPrinter) Eprintf(f string, v ...interface{}) (int, error)
- func (tp *TermPrinter) Eprintln(v ...interface{}) (int, error)
- func (tp *TermPrinter) Lprintf(f string, v ...interface{}) (int, error)
- func (tp *TermPrinter) Print(v ...interface{}) (int, error)
- func (tp *TermPrinter) Printf(f string, v ...interface{}) (int, error)
- func (tp *TermPrinter) Println(v ...interface{}) (int, error)
- func (tp *TermPrinter) SetStderr(w io.Writer)
- func (tp *TermPrinter) SetStdout(w io.Writer)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Cmd ¶
type Cmd struct { *ExitHandler *TermPrinter FlagSet *flag.FlagSet }
Cmd is a simple structure for building an application. It includes the functionality of ExitHandler and TermPrinter, along with a flag.FlagSet for parsing command line arguments.
type ExitHandler ¶ added in v0.5.0
type ExitHandler struct { // C is the exit channel. Must call Add or Watch before attempting // to receive from C. C <-chan bool // contains filtered or unexported fields }
ExitHandler provides the ability to gracefully shut down an application, expanding on the functionality of sync.WaitGroup.
Calling Exit will close the exit channel C, providing the ability for any goroutines watching C to perform clean up tasks and return.
Calling Watch with a list of signals will set up a goroutine to receive those signals and call Exit, allowing for simple trapping of Ctrl-C and kill by passing os.SIGINT and os.SIGTERM.
If a timeout has been set, the closure of the exit channel will also trigger a timer which calls os.Exit upon expiration. Sending an exit signal during the timeout will abort the timer and call os.Exit immediately.
If an error is passed to Exit, the error will be returned to the caller of Wait once all the goroutines being awaited call Done. If a timeout or signal based forced exit occurs, the error message will be printed to os.Stderr before os.Exit is called.
Example ¶
package main import ( "errors" "fmt" "os" "time" "kreklow.us/go/cli" ) func main() { eh := new(cli.ExitHandler) msgs := make(chan []byte, 1) eh.Add(1) // message receiver go func() { err := errors.New("unexpected shutdown") defer eh.Done() // deferring Done() and Exit() helps ensure a clean defer eh.Exit(err) // shutdown if the goroutine returns unexpectedly loop: for { select { case <-eh.C: // exit signal, go to cleanup break loop case m := <-msgs: // do some work fmt.Printf("%s\n", m) } } // cleanup tasks fmt.Println("Cleaned up") }() // message sender go func() { msgs <- []byte("Message") time.Sleep(50 * time.Millisecond) // do some work eh.Exit(nil) }() err := eh.Wait() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }
Output: Message Cleaned up
func (*ExitHandler) Add ¶ added in v0.5.0
func (e *ExitHandler) Add(n int)
Add updates the WaitGroup counter, adding or subtracting as appropriate. Add will panic if the counter goes negative.
Add also initializes exit channel C if it has not been initialized previously.
func (*ExitHandler) Done ¶ added in v0.5.0
func (e *ExitHandler) Done()
Done removes one from the WaitGroup counter.
func (*ExitHandler) Exit ¶ added in v0.5.0
func (e *ExitHandler) Exit(err error)
Exit closes the exit channel and starts the timeout timer, if applicable. The error value passed to the first Exit call will be passed as the return value of Wait. Exit is safe to call multiple times, all calls after the first are ignored.
func (*ExitHandler) SetTimeout ¶ added in v0.5.0
func (e *ExitHandler) SetTimeout(t time.Duration)
SetTimeout sets the timeout duration. A zero or negative value waits indefinitely.
func (*ExitHandler) Wait ¶ added in v0.5.0
func (e *ExitHandler) Wait() error
Wait blocks until the WaitGroup counter is zero. The return value is the first error value passed to Exit.
func (*ExitHandler) Watch ¶ added in v0.5.0
func (e *ExitHandler) Watch(signals ...os.Signal)
Watch takes a list of signals to receive from the operating system which will trigger Exit. Watch can be called multiple times, each call to Watch will replace the previous list of signals with the new list. An empty list will stop receiving signals from the OS.
type TermPrinter ¶ added in v0.5.0
type TermPrinter struct {
// contains filtered or unexported fields
}
TermPrinter provides printing functions based on a standard unix terminal. The Print* functions direct output to os.Stdout, while the Eprint* functions direct output to os.Stderr.
TermPrinter also includes a "live printing" function in Lprintf which provides a non-scrolling output for continuously-updating status information. Messages printed via Print* or Eprint* will not be overwritten by Lprintf.
TermPrinter provides locking over the output writers, so it is safe to call concurrently from multiple goroutines.
If TermPrinter is not created with NewTermPrinter, SetStdout and SetStderr must be called before use.
func NewTermPrinter ¶ added in v0.5.0
func NewTermPrinter() *TermPrinter
NewTermPrinter returns a TermPrinter set to output to os.Stdout and os.Stderr.
func (*TermPrinter) Eprint ¶ added in v0.5.0
func (tp *TermPrinter) Eprint(v ...interface{}) (int, error)
Eprint operates in the manner of fmt.Print, writing to Stderr.
func (*TermPrinter) Eprintf ¶ added in v0.5.0
func (tp *TermPrinter) Eprintf(f string, v ...interface{}) (int, error)
Eprintf operates in the manner of fmt.Printf, writing to Stderr.
func (*TermPrinter) Eprintln ¶ added in v0.5.0
func (tp *TermPrinter) Eprintln(v ...interface{}) (int, error)
Eprintln operates in the manner of fmt.Println, writing to Stderr.
func (*TermPrinter) Lprintf ¶ added in v0.5.0
func (tp *TermPrinter) Lprintf(f string, v ...interface{}) (int, error)
Lprintf implements a "live update" version of fmt.Printf. If Stdout appears to be a terminal, the previously output line(s) will be cleared before the new line(s) are written.
While Lprintf is safe for concurrent use with Print* and Eprint*, concurrent use of Lprintf will conflict, overwriting the previous output.
func (*TermPrinter) Print ¶ added in v0.5.0
func (tp *TermPrinter) Print(v ...interface{}) (int, error)
Print operates in the manner of fmt.Print, writing to Stdout.
func (*TermPrinter) Printf ¶ added in v0.5.0
func (tp *TermPrinter) Printf(f string, v ...interface{}) (int, error)
Printf operates in the manner of fmt.Printf, writing to Stdout.
func (*TermPrinter) Println ¶ added in v0.5.0
func (tp *TermPrinter) Println(v ...interface{}) (int, error)
Println operates in the manner of fmt.Println, writing to Stdout.
func (*TermPrinter) SetStderr ¶ added in v0.5.0
func (tp *TermPrinter) SetStderr(w io.Writer)
SetStderr sets the destination for calls to EPrint, EPrintf and EPrintln.
func (*TermPrinter) SetStdout ¶ added in v0.5.0
func (tp *TermPrinter) SetStdout(w io.Writer)
SetStdout sets the destination for calls to Print, Printf, Println and Lprintf.