diff --git a/cmd/camtool/debug.go b/cmd/camtool/debug.go index eca8947c4..583fc4199 100644 --- a/cmd/camtool/debug.go +++ b/cmd/camtool/debug.go @@ -53,6 +53,10 @@ func init() { }) } +func (c *debugCmd) Describe() string { + return "Show misc meta-info from the given file." +} + func (c *debugCmd) Usage() { var subModes, docs string for k, v := range debugSubModes { diff --git a/cmd/camgsinit/camgsinit.go b/cmd/camtool/gsinit.go similarity index 85% rename from cmd/camgsinit/camgsinit.go rename to cmd/camtool/gsinit.go index 60f7419e3..610259532 100644 --- a/cmd/camgsinit/camgsinit.go +++ b/cmd/camtool/gsinit.go @@ -19,15 +19,33 @@ package main import ( "bufio" "encoding/json" + "flag" "fmt" "os" "strings" "camlistore.org/pkg/blobserver/google" + "camlistore.org/pkg/cmdmain" "camlistore.org/third_party/code.google.com/p/goauth2/oauth" ) -func main() { +type gsinitCmd struct{} + +func init() { + cmdmain.RegisterCommand("gsinit", func(flags *flag.FlagSet) cmdmain.CommandRunner { + return new(gsinitCmd) + }) +} + +func (c *gsinitCmd) Describe() string { + return "Init Google Storage." +} + +func (c *gsinitCmd) Usage() { + fmt.Fprintf(os.Stderr, "Usage: camtool [globalopts] gsinit \n") +} + +func (c *gsinitCmd) RunCommand(args []string) error { var ( err error clientId string @@ -35,16 +53,16 @@ func main() { ) if clientId, clientSecret, err = getClientInfo(); err != nil { - panic(err) + return err } transport := google.MakeOauthTransport(clientId, clientSecret, "") var accessCode string if accessCode, err = getAccessCode(transport.Config); err != nil { - panic(err) + return err } if _, err = transport.Exchange(accessCode); err != nil { - panic(err) + return err } fmt.Printf("\nYour Google Storage auth object:\n\n") @@ -56,6 +74,7 @@ func main() { } enc.Encode(authObj) fmt.Print("\n") + return nil } // Prompt the user for an input line. Return the given input. diff --git a/cmd/camtool/sync.go b/cmd/camtool/sync.go index 8a993443b..ef2cb56d2 100644 --- a/cmd/camtool/sync.go +++ b/cmd/camtool/sync.go @@ -56,6 +56,10 @@ func init() { }) } +func (c *syncCmd) Describe() string { + return "Synchronize blobs from a source to a destination." +} + func (c *syncCmd) Usage() { fmt.Fprintf(os.Stderr, "Usage: camtool [globalopts] sync [syncopts] \n") } diff --git a/pkg/cmdmain/cmdmain.go b/pkg/cmdmain/cmdmain.go index d72739e9a..74685864c 100644 --- a/pkg/cmdmain/cmdmain.go +++ b/pkg/cmdmain/cmdmain.go @@ -81,6 +81,10 @@ type exampler interface { Examples() []string } +type describer interface { + Describe() string +} + // RegisterCommand adds a mode to the list of modes for the main command. // It is meant to be called in init() for each subcommand. func RegisterCommand(mode string, makeCmd func(Flags *flag.FlagSet) CommandRunner) { @@ -149,16 +153,21 @@ func usage(msg string) { Errf(` Usage: ` + cmdName + ` [globalopts] [commandopts] [commandargs] -Examples: +Modes: + `) for mode, cmd := range modeCommand { - Errf("\n") + if des, ok := cmd.(describer); ok { + Errf(" %s: %s\n", mode, des.Describe()) + } + } + Errf("\nExamples:\n") + for mode, cmd := range modeCommand { if ex, ok := cmd.(exampler); ok { + Errf("\n") for _, example := range ex.Examples() { Errf(" %s %s %s\n", cmdName, mode, example) } - } else { - Errf(" %s %s ...\n", cmdName, mode) } } @@ -173,6 +182,27 @@ Global options: Exit(1) } +func help(mode string) { + cmdName := os.Args[0] + // We can skip all the checks as they're done in Main + cmd := modeCommand[mode] + cmdFlags := modeFlags[mode] + if des, ok := cmd.(describer); ok { + Errf("%s\n", des.Describe()) + } + Errf("\n") + cmd.Usage() + if hasFlags(cmdFlags) { + cmdFlags.PrintDefaults() + } + if ex, ok := cmd.(exampler); ok { + Errf("\nExamples:\n") + for _, example := range ex.Examples() { + Errf(" %s %s %s\n", cmdName, mode, example) + } + } +} + // Main is meant to be the core of a command that has // subcommands (modes), such as camput or camtool. func Main() error { @@ -180,7 +210,7 @@ func Main() error { flag.Parse() args := flag.Args() if *FlagVersion { - fmt.Fprintf(Stderr, "camput version: %s\n", buildinfo.Version()) + fmt.Fprintf(Stderr, "%s version: %s\n", os.Args[0], buildinfo.Version()) return nil } if *FlagHelp { @@ -197,10 +227,16 @@ func Main() error { } cmdFlags := modeFlags[mode] + var cmdHelp bool + cmdFlags.BoolVar(&cmdHelp, "help", false, "Help for this mode.") err := cmdFlags.Parse(args[1:]) if err != nil { err = ErrUsage } else { + if cmdHelp { + help(mode) + return nil + } err = cmd.RunCommand(cmdFlags.Args()) } if ue, isUsage := err.(UsageError); isUsage {