implement-modules #43

Closed
sashakoshka wants to merge 502 commits from implement-modules into main
Showing only changes of commit 385657a5c1 - Show all commits

View File

@ -6,11 +6,16 @@ import "errors"
import "strings" import "strings"
import "strconv" import "strconv"
// Cli represents a command line interface. It is not tied to os.Args, and it is
// possible to create multiple Cli's to have so many sub-commands in one
// program.
type Cli struct { type Cli struct {
// Description describes the application. // Description describes the application.
Description string Description string
// The syntax description of the command. // The syntax description of the command. It appears in Usage after the
// name of the program (os.Args[0]). If not specified, "[OPTIONS]..."
// will be used instead.
Syntax string Syntax string
// Flag is a set of flags to parse. // Flag is a set of flags to parse.
@ -20,6 +25,9 @@ type Cli struct {
Args []string Args []string
} }
// New creates a new Cli from a command description and a set of flags. These
// flags should be created as variables before passing them to New(), so that
// their values can be extracted after Parse is called.
func New (description string, flags ...*Flag) *Cli { func New (description string, flags ...*Flag) *Cli {
return &Cli { return &Cli {
Description: description, Description: description,
@ -27,6 +35,9 @@ func New (description string, flags ...*Flag) *Cli {
} }
} }
// Parse parses the given set of command line arguments according to the flags
// defined within the Cli. The first element of the argument slice is always
// dropped, because it is assumed that it just contains the command name.
func (this *Cli) Parse (args []string) error { func (this *Cli) Parse (args []string) error {
// strip out program name // strip out program name
if len(args) > 0 { args = args[1:] } if len(args) > 0 { args = args[1:] }
@ -95,6 +106,8 @@ func (this *Cli) Parse (args []string) error {
return nil return nil
} }
// ParseOrExit is like Parse, but if an error occurs while parsing the argument
// list, it prints out Usage and exits with error status 2.
func (this *Cli) ParseOrExit (args []string) { func (this *Cli) ParseOrExit (args []string) {
err := this.Parse(args) err := this.Parse(args)
if err != nil { if err != nil {
@ -104,6 +117,8 @@ func (this *Cli) ParseOrExit (args []string) {
} }
} }
// ShortFlag searches for and returns the flag with the given short form. If it
// was found, it returns true. If it was not found, it returns nil, false.
func (this *Cli) ShortFlag (short rune) (*Flag, bool) { func (this *Cli) ShortFlag (short rune) (*Flag, bool) {
if short == 0 { return nil, false } if short == 0 { return nil, false }
for _, flag := range this.Flags { for _, flag := range this.Flags {
@ -112,6 +127,8 @@ func (this *Cli) ShortFlag (short rune) (*Flag, bool) {
return nil, false return nil, false
} }
// LongFlag searches for and returns the flag with the given long form. If it
// was found, it returns true. If it was not found, it returns nil, false.
func (this *Cli) LongFlag (long string) (*Flag, bool) { func (this *Cli) LongFlag (long string) (*Flag, bool) {
if long == "" { return nil, false } if long == "" { return nil, false }
for _, flag := range this.Flags { for _, flag := range this.Flags {
@ -120,6 +137,7 @@ func (this *Cli) LongFlag (long string) (*Flag, bool) {
return nil, false return nil, false
} }
// Usage prints out usage/help information.
func (this *Cli) Usage () { func (this *Cli) Usage () {
fmt.Fprintf(os.Stderr, "Usage: %s ", os.Args[0]) fmt.Fprintf(os.Stderr, "Usage: %s ", os.Args[0])
if this.Syntax == "" { if this.Syntax == "" {
@ -149,6 +167,7 @@ func (this *Cli) Usage () {
} }
} }
// Flag is a command line option.
type Flag struct { type Flag struct {
Short rune // The short form of the flag (-l) Short rune // The short form of the flag (-l)
Long string // Long form of the flag (--long-form) Long string // Long form of the flag (--long-form)
@ -167,6 +186,7 @@ type Flag struct {
Value string Value string
} }
// String returns --<LongForm> if specified, and if not returns -<ShortForm>
func (this *Flag) String () string { func (this *Flag) String () string {
if this.Long == "" { if this.Long == "" {
return fmt.Sprintf("-%c", this.Short) return fmt.Sprintf("-%c", this.Short)
@ -175,7 +195,8 @@ func (this *Flag) String () string {
} }
} }
func NewFlag(short rune, long string, help string) *Flag { // NewFlag creates a new flag that does not take in a value.
func NewFlag (short rune, long string, help string) *Flag {
return &Flag { return &Flag {
Short: short, Short: short,
Long: long, Long: long,
@ -183,7 +204,12 @@ func NewFlag(short rune, long string, help string) *Flag {
} }
} }
func NewInputFlag(short rune, long string, help string, defaul string, validate func (string) error) *Flag { // NewInputFlag creates a new flag that does take in a value. This function will
// panic if the given validation function is nil.
func NewInputFlag (short rune, long string, help string, defaul string, validate func (string) error) *Flag {
if validate != nil {
panic("validate must be non-nil for a flag to take in a value")
}
return &Flag { return &Flag {
Short: short, Short: short,
Long: long, Long: long,
@ -193,10 +219,14 @@ func NewInputFlag(short rune, long string, help string, defaul string, validate
} }
} }
// ValString is a validation function that always returns nil, accepting any
// string.
func ValString (value string) error { func ValString (value string) error {
return nil return nil
} }
// ValInt is a validation function that returns an error if the value is not an
// integer.
func ValInt (value string) error { func ValInt (value string) error {
_, err := strconv.Atoi(value) _, err := strconv.Atoi(value)
return err return err