From 87c86a8090d14c90c06e9cc9ac71c9a347887c5c Mon Sep 17 00:00:00 2001 From: Blallo Date: Sun, 31 Jan 2021 01:15:07 +0100 Subject: [PATCH] Added cli module with first papero subcommand --- cli/papero/info.go | 137 +++++++++++++++++++++++++++++++++++++++++++++ cli/papero/main.go | 85 ++++++++++++++++++++++++++++ cli/utils.go | 38 +++++++++++++ go.mod | 4 +- go.sum | 12 ++++ 5 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 cli/papero/info.go create mode 100644 cli/papero/main.go create mode 100644 cli/utils.go diff --git a/cli/papero/info.go b/cli/papero/info.go new file mode 100644 index 0000000..725a213 --- /dev/null +++ b/cli/papero/info.go @@ -0,0 +1,137 @@ +package main + +import ( + "flag" + "fmt" + "io" + "os" + + "git.lattuga.net/blallo/papero/cli" + "git.lattuga.net/blallo/papero/imaputils" +) + +var infoVerbs cli.CommandMap + +func init() { + lsMailbox := LsMailboxCmd{} + lsMessages := LsMsgCmd{} + catMessage := CatMsgCmd{} + infoVerbs = cli.CommandMap{ + "list-mailboxes": lsMailbox, + "list-messages": lsMessages, + "display-message": catMessage, + } +} + +type InfoCmd struct{} + +func (i InfoCmd) Func(args []string) error { + flagset := flag.NewFlagSet(args[0], flag.ExitOnError) + flagset.Usage = func() { i.Help(os.Stdout, flagset) } + flagset.Parse(args[1:]) + subArgs := flagset.Args() + if len(subArgs) == 0 { + i.Help(os.Stderr, flagset) + os.Exit(1) + } + cmd := subArgs[0] + if Session.Info.Opts.Debug { + Log.Debug("info verb:", cmd) + } + + return infoVerbs[cmd].Func(subArgs) +} + +func (i InfoCmd) Help(w io.Writer, set *flag.FlagSet) { + fmt.Fprintf(w, "USAGE: %s info VERB [verb opts]\n", Session.Info.Name) + fmt.Fprintf(w, "\nVERBS:\n") + for verb := range infoVerbs { + fmt.Fprintf(w, "\t%s\n", verb) + } +} + +// VERBS + +type LsMailboxCmd struct{} + +func (l LsMailboxCmd) Func(args []string) error { + if Session.Info.Opts.Debug { + Log.Debug("enter info list-mailboxes") + } + var withAttributes bool + flagset := flag.NewFlagSet(args[0], flag.ExitOnError) + flagset.BoolVar(&withAttributes, "with-attrs", false, "toggle attributes display") + flagset.Usage = func() { l.Help(os.Stdout, flagset) } + flagset.Parse(args[1:]) + + mboxInfo, err := imaputils.ListMailboxes(Session.Config, Session.Info.Opts.Debug) + if err != nil { + return err + } + if Session.Info.Opts.Debug { + Log.Debug(mboxInfo) + } + for _, box := range mboxInfo { + if withAttributes { + attrs := fmt.Sprint(box.Attributes) + fmt.Printf("%s (attrs: %s)", box.Name, attrs) + } else { + fmt.Println(box.Name) + } + } + return nil +} + +func (l LsMailboxCmd) Help(w io.Writer, set *flag.FlagSet) { + fmt.Fprintf(w, "USAGE: %s info list-mailboxes\n", Session.Info.Name) + set.PrintDefaults() +} + +type LsMsgCmd struct{} + +func (l LsMsgCmd) Func(args []string) error { + if Session.Info.Opts.Debug { + Log.Debug("enter info list-messages") + } + var limit uint + flagset := flag.NewFlagSet(args[0], flag.ExitOnError) + flagset.UintVar(&limit, "limit", 0, "maximum number of messages to display (0 means no limit)") + flagset.Usage = func() { l.Help(os.Stdout, flagset) } + flagset.Parse(args[1:]) + + subArgs := flagset.Args() + if len(subArgs) != 1 { + l.Help(os.Stderr, flagset) + os.Exit(1) + } + return nil +} + +func (l LsMsgCmd) Help(w io.Writer, set *flag.FlagSet) { + fmt.Fprintf(w, "USAGE: %s info list-messages [opts] MAILBOX_NAME\n", Session.Info.Name) + fmt.Fprintf(w, "\nOPTS:\n") + set.PrintDefaults() +} + +type CatMsgCmd struct{} + +func (c CatMsgCmd) Func(args []string) error { + if Session.Info.Opts.Debug { + Log.Debug("enter info display-message") + } + flagset := flag.NewFlagSet(args[0], flag.ExitOnError) + flagset.Usage = func() { c.Help(os.Stdout, flagset) } + flagset.Parse(args[1:]) + + subArgs := flagset.Args() + if len(subArgs) != 1 { + c.Help(os.Stderr, flagset) + os.Exit(1) + } + return nil +} + +func (c CatMsgCmd) Help(w io.Writer, set *flag.FlagSet) { + fmt.Fprintf(w, "USAGE: %s info display-message MAILBOX_NAME MESSAGE_ID\n", Session.Info.Name) + set.PrintDefaults() +} diff --git a/cli/papero/main.go b/cli/papero/main.go new file mode 100644 index 0000000..8c54dd5 --- /dev/null +++ b/cli/papero/main.go @@ -0,0 +1,85 @@ +package main + +import ( + "flag" + "os" + + "git.lattuga.net/blallo/papero/cli" + "git.lattuga.net/blallo/papero/config" + "github.com/withmandala/go-log" +) + +var Session struct { + Info cli.ProgramInfo + Config *config.AccountData +} +var Log *log.Logger + +func init() { + info := InfoCmd{} + Session.Info.Commands = cli.CommandMap{ + "info": info, + } + Session.Info.Name = "papero" + flag.Usage = func() { cli.Usage(os.Stdout, Session.Info) } + Log = log.New(os.Stdout) +} + +func main() { + var configPath string + flag.StringVar(&Session.Info.Opts.ConfigPath, "config", "", "path to the configuration") + flag.BoolVar(&Session.Info.Opts.Debug, "debug", false, "execute in debug mode") + flag.StringVar(&Session.Info.Opts.ConfigStanza, "account", "", "specify which account to use") + flag.Parse() + + args := flag.Args() + if len(args) == 0 { + cli.Usage(os.Stderr, Session.Info) + os.Exit(1) + } + + if Session.Info.Opts.Debug { + Log.WithDebug() + Log.Debugf( + "opts -> config: %s\tdebug: %v\taccount: %s\n", + Session.Info.Opts.ConfigPath, + Session.Info.Opts.Debug, + Session.Info.Opts.ConfigStanza, + ) + } + + if Session.Info.Opts.ConfigPath == "" { + var err error + configPath, err = config.Find() + if err != nil { + Log.Fatal(err) + } + } else { + configPath = Session.Info.Opts.ConfigPath + } + + fullConfig, err := config.Parse(configPath) + if err != nil { + os.Exit(2) + } + + var ok bool + var account string + if Session.Info.Opts.ConfigStanza != "" { + account = Session.Info.Opts.ConfigStanza + Session.Config, ok = fullConfig.Accounts[account] + } else { + account = fullConfig.Default + Session.Config, ok = fullConfig.Accounts[account] + } + if !ok { + Log.Error("Account not found in config:", account) + os.Exit(2) + } + + err = Session.Info.Commands[args[0]].Func(args) + if err != nil { + Log.Error(err) + os.Exit(-1) + } +} diff --git a/cli/utils.go b/cli/utils.go new file mode 100644 index 0000000..d808595 --- /dev/null +++ b/cli/utils.go @@ -0,0 +1,38 @@ +package cli + +import ( + "flag" + "fmt" + "io" +) + +type GlobalOpts struct { + ConfigPath string + Debug bool + ConfigStanza string +} + +func (o GlobalOpts) String() string { + return "--config --debug --account" +} + +type Command interface { + Func([]string) error + Help(io.Writer, *flag.FlagSet) +} + +type CommandMap map[string]Command + +type ProgramInfo struct { + Name string + Opts GlobalOpts + Commands CommandMap +} + +func Usage(w io.Writer, info ProgramInfo) { + fmt.Fprintf(w, "USAGE: %s [%s] SUBCOMMAND [subcommand opts]\n", info.Name, info.Opts) + fmt.Fprintf(w, "\nSUBCOMMANDS:\n") + for command := range info.Commands { + fmt.Fprintf(w, "\t%s\n", command) + } +} diff --git a/go.mod b/go.mod index cf73901..112f50d 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,9 @@ go 1.15 require ( github.com/BurntSushi/toml v0.3.1 - github.com/emersion/go-imap v1.0.6 // indirect + github.com/emersion/go-imap v1.0.6 github.com/google/go-cmp v0.5.4 github.com/mitchellh/go-homedir v1.1.0 + github.com/withmandala/go-log v0.1.0 + golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect ) diff --git a/go.sum b/go.sum index ebfcbf8..a41ab98 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,18 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/withmandala/go-log v0.1.0 h1:wINmTEe7BQ6zEA8sE7lSsYeaxCLluK6RFjF/IB5tzkA= +github.com/withmandala/go-log v0.1.0/go.mod h1:/V9xQUTW74VjYm3u2Liv/bIUGLWoL9z2GlHwtscp4vg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=