aboutsummaryrefslogtreecommitdiff
path: root/cmd/cmd.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/cmd.go')
-rw-r--r--cmd/cmd.go146
1 files changed, 124 insertions, 22 deletions
diff --git a/cmd/cmd.go b/cmd/cmd.go
index 725aaea..945e945 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -27,18 +27,69 @@
// to use for other commands.
package cmd
-import "os"
+import (
+ "fmt"
+ "io"
+ "os"
+ "text/template"
+ "time"
-// Command represents a command with many potential top-level commands. This is
-// transformed into a cli.Command in Run().
-type Command struct {
- Name string
- UsageLines []string
- SubCmds []*Command
- Arguments []*Argument
- Flags []Flag
- ManPage *ManEntry
- Action CommandFunc
+ "github.com/blang/semver"
+)
+
+// Context represents the state of a running application, and is the only thing
+// passed to a CommandFunc.
+type Context struct {
+ Command *Command
+ Parent *Context
+ Info *Info
+ Args []string
+ flagArgs []string
+}
+
+// FullName returns the space-separated name of the command and all parents.
+func (ctx *Context) FullName() string {
+ if ctx.Parent == nil {
+ return ctx.Command.Name
+ }
+ return fmt.Sprintf("%s %s", ctx.Parent.FullName(), ctx.Command.Name)
+}
+
+// ManPage returns the man page entry for this context. It is either the ManPage
+// for the the current command or the closet Parent.
+func (ctx *Context) ManPage() *ManPage {
+ if ctx.Command.ManPage.Section != 0 || ctx.Parent == nil {
+ return ctx.Command.ManPage
+ }
+ return ctx.Parent.ManPage()
+}
+
+// Creates an anonymous template from the text, and runs it with the provided
+// Context and writer. Panics if text has a bad format or execution fails.
+func (ctx *Context) executeTemplate(w io.Writer, text string) {
+ tmpl := template.Must(template.New("").Parse(text))
+ if err := tmpl.Execute(w, ctx); err != nil {
+ panic(err)
+ }
+}
+
+func (ctx *Context) execute() {
+ fmt.Printf("%+v\n", ctx)
+ return
+}
+
+// Info is a parsed view of the corresponding global variables.
+type Info struct {
+ Version semver.Version
+ BuildTime time.Time
+ Authors []Author
+ Copyright string
+}
+
+// Author contains the contact information for a contributor.
+type Author struct {
+ Name string
+ Email string
}
// Argument represents a parameter passed to a function. It has an optional
@@ -48,19 +99,35 @@ type Argument struct {
Usage string
}
-// ManEntry represents an entry in a man page with a name, section, and title.
-type ManEntry struct {
- Name string
- Section int
+func (a *Argument) String() string { return fmt.Sprintf("<%s>", a.ArgName) }
+
+// ManPage a man page with a title and section.
+type ManPage struct {
Title string
+ Section int
}
-// CommandFunc contains the implementation of a command. The provided args have
-// the flags and leading command names removed. If a normal error is returned,
-// it is printed out (with an optional explanation) and exits with FailureCode.
-// If a usage error is returned, it is printed out with the command's usage and
-// exits with UsageFailureCode. Returning nil causes an exit with success.
-type CommandFunc func(args []string) error
+// CommandFunc contains the implementation of a command. If a normal error is
+// returned, the error will be printed out (with an optional explanation) and
+// Run will exit with FailureCode. If a usage error is returned, the error and
+// the commnd's usage are printed out and Run will exit with UsageFailureCode.
+// Returning nil causes Run to return.
+type CommandFunc func(ctx *Context) error
+
+// Command represents a command with many potential top-level commands. This is
+// transformed into a cli.Command in Run().
+type Command struct {
+ Name string
+ Title string
+ UsageLines []string
+ SubCommands []*Command
+ InheritArguments bool
+ Arguments []*Argument
+ InheritFlags bool
+ Flags []Flag
+ ManPage *ManPage
+ Action CommandFunc
+}
// Run executes the command with os.Args, equivalent to c.RunArgs(os.Args).
func (c *Command) Run() {
@@ -71,5 +138,40 @@ func (c *Command) Run() {
// empty, args[0]'s basename is used instead. If the command fails, this method
// will not return.
func (c *Command) RunArgs(args []string) {
- // TODO(joerichey): Implement conversion to cli.Command
+ binaryName, args := args[0], args[1:]
+ if c.Name == "" {
+ c.Name = binaryName
+ }
+
+ // Create our initial context by sorting the args and parsing the tags.
+ ctx := &Context{
+ Command: c,
+ Info: parseInfo(),
+ }
+ ctx.Args, ctx.flagArgs = sortArgs(args)
+
+ ctx.execute()
+}
+
+// Divide the arguments into flag arguments (those starting with "-") and normal
+// arguments. If "--" appears in the list, it will classified as a normal
+// argument as well as all arguments following it. Also removes empty args.
+func sortArgs(args []string) (normalArgs, flagArgs []string) {
+ var arg string
+ for len(args) > 0 {
+ arg, args = args[0], args[1:]
+ if arg == "" {
+ continue
+ }
+ if arg == "--" {
+ normalArgs = append(normalArgs, arg)
+ normalArgs = append(normalArgs, args...)
+ return
+ } else if arg[0] == '-' {
+ flagArgs = append(flagArgs, arg)
+ } else {
+ normalArgs = append(normalArgs, arg)
+ }
+ }
+ return
}