diff --git a/command.go b/command.go new file mode 100644 index 0000000..51fdc58 --- /dev/null +++ b/command.go @@ -0,0 +1,41 @@ +package main + +import ( + "flag" + "fmt" + "strings" +) + +type Command struct { + // args does not include the command name + Run func(cmd *Command, args []string) + Flag flag.FlagSet + + Usage string // first word is the command name + Short string // `hk help` output + Long string // `hk help cmd` output +} + +func (c *Command) printUsage() { + if c.Runnable() { + fmt.Printf("Usage: hk %s\n\n", c.Usage) + } + fmt.Println(strings.Trim(c.Long, "\n")) +} + +func (c *Command) Name() string { + name := c.Usage + i := strings.Index(name, " ") + if i >= 0 { + name = name[:i] + } + return name +} + +func (c *Command) Runnable() bool { + return c.Run != nil +} + +func (c *Command) List() bool { + return c.Short != "" +} diff --git a/help.go b/help.go new file mode 100644 index 0000000..afd35ff --- /dev/null +++ b/help.go @@ -0,0 +1,57 @@ +package main + +import ( + "fmt" + "log" + "os" + "text/template" +) + +var cmdHelp = &Command{ + Usage: "help [topic]", + Long: `Help shows usage for a command or other topic.`, +} + +func init() { + cmdHelp.Run = runHelp // break init loop +} + +func runHelp(cmd *Command, args []string) { + if len(args) == 0 { + printUsage() + return + } + if len(args) != 1 { + log.Fatal("too many arguments") + } + + for _, cmd := range commands { + if cmd.Name() == args[0] { + cmd.printUsage() + return + } + } + + fmt.Fprintf(os.Stderr, "Unknown help topic: %q. Run 'forego help'.\n", args[0]) + os.Exit(2) +} + +var usageTemplate = template.Must(template.New("usage").Parse(` +Usage: forego [command] [options] [arguments] +{{range .Commands}}{{if .Runnable}}{{if .List}} + {{.Name | printf "%-8s"}} {{.Short}}{{end}}{{end}}{{end}} + +Run 'forego help [command]' for details.`[1:])) + +func printUsage() { + usageTemplate.Execute(os.Stdout, struct { + Commands []*Command + }{ + commands, + }) +} + +func usage() { + printUsage() + os.Exit(2) +} diff --git a/main.go b/main.go index 3e01557..2c1237f 100644 --- a/main.go +++ b/main.go @@ -2,10 +2,32 @@ package main import ( "github.com/kr/pretty" + "os" ) -func main() { - pf, err := OpenProcfile("example/Procfile") +var _ = pretty.Println // lol - pretty.Println("testing", pf, err); +var commands = []*Command{ + cmdStart, + cmdHelp, +} + +func main() { + args := os.Args[1:] + if len(args) < 1 { + usage() + } + + for _, cmd := range commands { + if cmd.Name() == args[0] && cmd.Run != nil { + cmd.Flag.Usage = func() { + cmd.printUsage() + } + if err := cmd.Flag.Parse(args[1:]); err != nil { + os.Exit(2) + } + cmd.Run(cmd, cmd.Flag.Args()) + return + } + } } diff --git a/start.go b/start.go new file mode 100644 index 0000000..1f2c707 --- /dev/null +++ b/start.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "github.com/kr/pretty" +) + +var flagProcfile string +var flagEnv string + +var cmdStart = &Command{ + Run: runStart, + Usage: "start [-f procfile] [-e env] [-c concurrency]", + Short: "start the app", + Long: ` +Start the application specified by a Procfile (defaults to ./Procfile) + +Examples: + + forego start + + forego start -f Procfile.test -e .env.test +`, +} + +func init() { + cmdStart.Flag.StringVar(&flagProcfile, "f", "./Procfile", "procfile") + cmdStart.Flag.StringVar(&flagEnv, "e", "", "env") +} + +func runStart(cmd *Command, args []string) { + pf, err := OpenProcfile(flagProcfile) + if err != nil { + fmt.Println("ERROR:", err) + return + } + pretty.Println("procfile", flagProcfile, pf, err) +}