Refactor cli interface
This commit is contained in:
parent
d49b77b459
commit
cc2efed9a6
100
cmd/config.go
100
cmd/config.go
@ -3,22 +3,13 @@ package cmd
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.iamthefij.com/iamthefij/slog"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
ConfigDirPerms = 0o755
|
||||
ConfigFilePerms = 0o600
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMissingExpectedArguments = errors.New("missing expected arguments")
|
||||
)
|
||||
var ErrMissingExpectedArguments = errors.New("missing expected arguments")
|
||||
|
||||
const (
|
||||
ConfigHostname = "hostname"
|
||||
@ -26,33 +17,6 @@ const (
|
||||
ConfigPassword = "password"
|
||||
)
|
||||
|
||||
func addConfigPaths() {
|
||||
if configFile != "" {
|
||||
viper.SetConfigFile(configFile)
|
||||
} else {
|
||||
viper.SetConfigName("config")
|
||||
viper.SetConfigType("toml")
|
||||
|
||||
userConfigDir, err := os.UserConfigDir()
|
||||
if err == nil {
|
||||
userConfigPath := filepath.Join(userConfigDir, "imap-notes")
|
||||
_ = os.MkdirAll(userConfigPath, ConfigDirPerms)
|
||||
viper.AddConfigPath(userConfigPath)
|
||||
}
|
||||
|
||||
viper.AddConfigPath("$HOME/.imap-notes")
|
||||
}
|
||||
}
|
||||
|
||||
func initializeConfig() {
|
||||
addConfigPaths()
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
slog.OnErrFatalf(viper.SafeWriteConfig(), "failed writing default config")
|
||||
slog.OnErrFatalf(viper.ReadInConfig(), "failed to read config")
|
||||
}
|
||||
}
|
||||
|
||||
var configCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Configure imap-notes",
|
||||
@ -62,41 +26,41 @@ var configCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var configGetCmd = &cobra.Command{
|
||||
Use: "get",
|
||||
Short: "Get a config value",
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("missing config name to retrieve: %w", ErrMissingExpectedArguments)
|
||||
}
|
||||
|
||||
return nil
|
||||
var configGetCmd = WrapPositionalArgs(
|
||||
&cobra.Command{
|
||||
Use: "get",
|
||||
Short: "Get a config value",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
for _, arg := range args {
|
||||
fmt.Printf("%s: %s\n", arg, viper.Get(arg))
|
||||
}
|
||||
},
|
||||
},
|
||||
[]string{"key1", "key2", "..."},
|
||||
1,
|
||||
)
|
||||
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
for _, arg := range args {
|
||||
fmt.Printf("%s: %s", arg, viper.Get(arg))
|
||||
}
|
||||
fmt.Println("")
|
||||
var configSetCmd = WrapPositionalArgs(
|
||||
&cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Set a config value",
|
||||
ValidArgs: []string{
|
||||
ConfigHostname,
|
||||
ConfigUsername,
|
||||
ConfigPassword,
|
||||
},
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
viper.Set(args[0], args[1])
|
||||
slog.OnErrFatalf(viper.WriteConfig(), "failed writing value to config")
|
||||
},
|
||||
},
|
||||
}
|
||||
[]string{"key", "value"},
|
||||
2,
|
||||
)
|
||||
|
||||
var configSetCmd = &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Set a config value",
|
||||
ValidArgs: []string{
|
||||
ConfigHostname,
|
||||
ConfigUsername,
|
||||
ConfigPassword,
|
||||
},
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
viper.Set(args[0], args[1])
|
||||
slog.OnErrFatalf(viper.WriteConfig(), "failed writing value to config")
|
||||
},
|
||||
}
|
||||
|
||||
func addConfigSubcommands() {
|
||||
func addConfigCmd() {
|
||||
rootCmd.AddCommand(configCmd)
|
||||
configCmd.AddCommand(configGetCmd)
|
||||
configCmd.AddCommand(configSetCmd)
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ var foldersCmd = &cobra.Command{
|
||||
var foldersListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List folders",
|
||||
Args: cobra.NoArgs,
|
||||
Aliases: []string{"ls"},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client, err := lib.GetClient()
|
||||
|
40
cmd/login.go
40
cmd/login.go
@ -1,15 +1,53 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"git.iamthefij.com/iamthefij/slog"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
func readPrompt(prompt string, reader *bufio.Reader, secret bool) string {
|
||||
fmt.Printf("%s? ", prompt)
|
||||
|
||||
var value string
|
||||
|
||||
var err error
|
||||
|
||||
if secret {
|
||||
byteValue, err := term.ReadPassword(syscall.Stdin)
|
||||
if err == nil {
|
||||
value = string(byteValue)
|
||||
}
|
||||
} else {
|
||||
value, err = reader.ReadString('\n')
|
||||
}
|
||||
|
||||
slog.OnErrFatalf(err, "failed reading %s from input", prompt)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func promptConfig(configKey string, reader *bufio.Reader, secret bool) {
|
||||
hostname := readPrompt(configKey, reader, secret)
|
||||
viper.Set(configKey, hostname)
|
||||
}
|
||||
|
||||
var loginCmd = &cobra.Command{
|
||||
Use: "login",
|
||||
Short: "Login to an imap server",
|
||||
Long: `Login to an imap server and store configuration`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
slog.Infof("Running login cobra command!")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
promptConfig("hostname", reader, false)
|
||||
promptConfig("username", reader, false)
|
||||
promptConfig("password", reader, true)
|
||||
},
|
||||
}
|
||||
|
140
cmd/notes.go
140
cmd/notes.go
@ -17,88 +17,104 @@ var notesCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var notesListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List notes",
|
||||
Aliases: []string{"ls"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client, err := lib.GetClient()
|
||||
slog.OnErrFatalf(err, "failed to logon")
|
||||
var notesListCmd = WrapPositionalArgs(
|
||||
&cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List notes",
|
||||
Aliases: []string{"ls"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client, err := lib.GetClient()
|
||||
slog.OnErrFatalf(err, "failed to logon")
|
||||
|
||||
folder, err := client.GetNoteFolder(args[0])
|
||||
slog.OnErrFatalf(err, "failed to select folder")
|
||||
folder, err := client.GetNoteFolder(args[0])
|
||||
slog.OnErrFatalf(err, "failed to select folder")
|
||||
|
||||
notes, err := folder.ListNotes()
|
||||
slog.OnErrFatalf(err, "failed to get notes from folder %s", args[0])
|
||||
notes, err := folder.ListNotes()
|
||||
slog.OnErrFatalf(err, "failed to get notes from folder %s", args[0])
|
||||
|
||||
for _, note := range notes {
|
||||
fmt.Println(note.Name)
|
||||
}
|
||||
for _, note := range notes {
|
||||
fmt.Println(note.Name)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
[]string{"folder"},
|
||||
1,
|
||||
)
|
||||
|
||||
var notesGetCmd = &cobra.Command{
|
||||
Use: "get",
|
||||
Short: "Print content of a note",
|
||||
Aliases: []string{"print"},
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// TODO: refactor a bit of this duplicate here
|
||||
client, err := lib.GetClient()
|
||||
slog.OnErrFatalf(err, "failed to logon")
|
||||
var notesGetCmd = WrapPositionalArgs(
|
||||
&cobra.Command{
|
||||
Use: "get",
|
||||
Short: "Print content of a note",
|
||||
Aliases: []string{"print"},
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// TODO: refactor a bit of this duplicate here
|
||||
client, err := lib.GetClient()
|
||||
slog.OnErrFatalf(err, "failed to logon")
|
||||
|
||||
folder, err := client.GetNoteFolder(args[0])
|
||||
slog.OnErrFatalf(err, "failed to select folder")
|
||||
folder, err := client.GetNoteFolder(args[0])
|
||||
slog.OnErrFatalf(err, "failed to select folder")
|
||||
|
||||
notes, err := folder.FindNotesByName(args[1])
|
||||
slog.OnErrFatalf(err, "failed to get notes from folder %s", args[0])
|
||||
notes, err := folder.FindNotesByName(args[1])
|
||||
slog.OnErrFatalf(err, "failed to get notes from folder %s", args[0])
|
||||
|
||||
note := notes[0]
|
||||
body, err := note.ReadMarkdown()
|
||||
slog.OnErrFatalf(err, "failed to read note")
|
||||
note := notes[0]
|
||||
body, err := note.ReadMarkdown()
|
||||
slog.OnErrFatalf(err, "failed to read note")
|
||||
|
||||
fmt.Println(body)
|
||||
fmt.Println(body)
|
||||
},
|
||||
},
|
||||
}
|
||||
[]string{"folder", "note"},
|
||||
2,
|
||||
)
|
||||
|
||||
var notesViewCmd = &cobra.Command{
|
||||
Use: "view",
|
||||
Short: "View content of a note",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client, err := lib.GetClient()
|
||||
slog.OnErrFatalf(err, "failed to logon")
|
||||
var notesViewCmd = WrapPositionalArgs(
|
||||
&cobra.Command{
|
||||
Use: "view",
|
||||
Short: "View content of a note",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client, err := lib.GetClient()
|
||||
slog.OnErrFatalf(err, "failed to logon")
|
||||
|
||||
folder, err := client.GetNoteFolder(args[0])
|
||||
slog.OnErrFatalf(err, "failed to select folder")
|
||||
folder, err := client.GetNoteFolder(args[0])
|
||||
slog.OnErrFatalf(err, "failed to select folder")
|
||||
|
||||
notes, err := folder.FindNotesByName(args[1])
|
||||
slog.OnErrFatalf(err, "failed to get notes from folder %s", args[0])
|
||||
notes, err := folder.FindNotesByName(args[1])
|
||||
slog.OnErrFatalf(err, "failed to get notes from folder %s", args[0])
|
||||
|
||||
note := notes[0]
|
||||
slog.OnErrFatalf(note.OpenMarkdownInPager(), "failed to open note")
|
||||
note := notes[0]
|
||||
slog.OnErrFatalf(note.OpenMarkdownInPager(), "failed to open note")
|
||||
},
|
||||
},
|
||||
}
|
||||
[]string{"folder", "note"},
|
||||
2,
|
||||
)
|
||||
|
||||
var notesEditCmd = &cobra.Command{
|
||||
Use: "edit",
|
||||
Short: "Edit content of a note",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client, err := lib.GetClient()
|
||||
slog.OnErrFatalf(err, "failed to logon")
|
||||
var notesEditCmd = WrapPositionalArgs(
|
||||
&cobra.Command{
|
||||
Use: "edit",
|
||||
Short: "Edit content of a note",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client, err := lib.GetClient()
|
||||
slog.OnErrFatalf(err, "failed to logon")
|
||||
|
||||
folder, err := client.GetNoteFolder(args[0])
|
||||
slog.OnErrFatalf(err, "failed to select folder")
|
||||
folder, err := client.GetNoteFolder(args[0])
|
||||
slog.OnErrFatalf(err, "failed to select folder")
|
||||
|
||||
notes, err := folder.FindNotesByName(args[1])
|
||||
slog.OnErrFatalf(err, "failed to get notes from folder %s", args[0])
|
||||
notes, err := folder.FindNotesByName(args[1])
|
||||
slog.OnErrFatalf(err, "failed to get notes from folder %s", args[0])
|
||||
|
||||
note := notes[0]
|
||||
slog.OnErrFatalf(note.EditMarkdown(), "failed to open note")
|
||||
note := notes[0]
|
||||
slog.OnErrFatalf(note.EditMarkdown(), "failed to open note")
|
||||
},
|
||||
},
|
||||
}
|
||||
[]string{"folder", "note"},
|
||||
2,
|
||||
)
|
||||
|
||||
func addNotesCmd() {
|
||||
rootCmd.AddCommand(notesCmd)
|
||||
|
17
cmd/root.go
17
cmd/root.go
@ -3,7 +3,8 @@ package cmd
|
||||
import (
|
||||
"git.iamthefij.com/iamthefij/slog"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"git.iamthefij.com/iamthefij/imap-notes/lib"
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
@ -18,18 +19,10 @@ var rootCmd = &cobra.Command{
|
||||
|
||||
var configFile string
|
||||
|
||||
func bindFlag(flagname string) {
|
||||
slog.OnErrFatalf(viper.BindPFlag(
|
||||
flagname,
|
||||
rootCmd.PersistentFlags().Lookup(flagname),
|
||||
), "failed binding flag: "+flagname)
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
cobra.OnInitialize(initializeConfig)
|
||||
cobra.OnInitialize(func() { lib.InitializeConfig(configFile) })
|
||||
rootCmd.AddCommand(loginCmd)
|
||||
rootCmd.AddCommand(configCmd)
|
||||
addConfigSubcommands()
|
||||
addConfigCmd()
|
||||
addFoldersCmd()
|
||||
addNotesCmd()
|
||||
|
||||
@ -39,7 +32,7 @@ func Execute() {
|
||||
"config",
|
||||
"c",
|
||||
"",
|
||||
"config file (default to .config/imap-notes/config.toml or ~/.imap-notes.toml",
|
||||
"config file (default to .config/imap-notes/config.toml or ~/.imap-notes.toml)",
|
||||
)
|
||||
rootCmd.PersistentFlags().StringP("hostname", "s", "", "IMAP server hostname and port (requires SSL. eg :993)")
|
||||
rootCmd.PersistentFlags().StringP("username", "u", "", "IMAP username")
|
||||
|
56
cmd/utils.go
Normal file
56
cmd/utils.go
Normal file
@ -0,0 +1,56 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.iamthefij.com/iamthefij/slog"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMissingArgument = errors.New("missing positional argument")
|
||||
ErrTooManyRequiredArgs = errors.New("more args specified as required than provided")
|
||||
)
|
||||
|
||||
func bindFlag(flagname string) {
|
||||
slog.OnErrFatalf(
|
||||
viper.BindPFlag(flagname, rootCmd.PersistentFlags().Lookup(flagname)),
|
||||
"failed binding flag: "+flagname,
|
||||
)
|
||||
}
|
||||
|
||||
func WrapPositionalArgs(cmd *cobra.Command, positionalArgs []string, numRequired int) *cobra.Command {
|
||||
// TODO: Find a better place for this validation
|
||||
if numRequired > len(positionalArgs) {
|
||||
panic(ErrTooManyRequiredArgs)
|
||||
}
|
||||
|
||||
// Add required args to Use
|
||||
if numRequired > 0 {
|
||||
cmd.Use = fmt.Sprintf("%s <%s>", cmd.Use, strings.Join(positionalArgs[0:numRequired], "> <"))
|
||||
}
|
||||
// Add optional args to Use
|
||||
optionalArgs := positionalArgs[numRequired:]
|
||||
if len(optionalArgs) > 0 {
|
||||
cmd.Use = fmt.Sprintf("%s [%s]", cmd.Use, strings.Join(optionalArgs, "] ["))
|
||||
}
|
||||
|
||||
oldArgs := cmd.Args
|
||||
cmd.Args = func(cmd *cobra.Command, args []string) error {
|
||||
lastArgPos := len(args)
|
||||
if lastArgPos < numRequired {
|
||||
return fmt.Errorf("missing argument `%s` in position %d: %w", positionalArgs[lastArgPos], lastArgPos, ErrMissingArgument)
|
||||
}
|
||||
|
||||
if oldArgs != nil {
|
||||
return oldArgs(cmd, args)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
16
go.mod
16
go.mod
@ -3,11 +3,18 @@ module git.iamthefij.com/iamthefij/imap-notes
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
git.iamthefij.com/iamthefij/slog v1.3.0 // indirect
|
||||
github.com/JohannesKaufmann/html-to-markdown v1.3.3 // indirect
|
||||
git.iamthefij.com/iamthefij/slog v1.3.0
|
||||
github.com/JohannesKaufmann/html-to-markdown v1.3.3
|
||||
github.com/emersion/go-imap v1.2.0
|
||||
github.com/russross/blackfriday/v2 v2.1.0
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/spf13/viper v1.10.1
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.5.1 // indirect
|
||||
github.com/andybalholm/cascadia v1.1.0 // indirect
|
||||
github.com/emersion/go-imap v1.2.0 // indirect
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
@ -15,13 +22,10 @@ require (
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/cobra v1.3.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.10.1 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
|
||||
|
17
go.sum
17
go.sum
@ -97,6 +97,7 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emersion/go-imap v1.2.0 h1:lyUQ3+EVM21/qbWE/4Ya5UG9r5+usDxlg4yfp3TgHFA=
|
||||
github.com/emersion/go-imap v1.2.0/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
|
||||
@ -205,6 +206,7 @@ github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pf
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
|
||||
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
@ -253,8 +255,10 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||
@ -294,6 +298,7 @@ github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
@ -315,9 +320,12 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||
github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sebdah/goldie/v2 v2.5.1 h1:hh70HvG4n3T3MNRJN2z/baxPR8xutxo7JVxyi2svl+s=
|
||||
github.com/sebdah/goldie/v2 v2.5.1/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
@ -343,6 +351,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
@ -352,6 +361,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.0/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
@ -436,7 +446,6 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8 h1:1+zQlQqEEhUeStBTi653GZAnAuivZq/2hz+Iz+OP7rg=
|
||||
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
@ -554,6 +563,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -657,6 +668,7 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr
|
||||
google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
|
||||
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
||||
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
|
||||
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@ -754,6 +766,7 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
@ -771,6 +784,7 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
|
||||
@ -784,6 +798,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -1,9 +1,18 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.iamthefij.com/iamthefij/slog"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
ConfigDirPerms = 0o755
|
||||
ConfigFilePerms = 0o600
|
||||
)
|
||||
|
||||
var singleClient *Client
|
||||
|
||||
func GetClient() (*Client, error) {
|
||||
@ -24,3 +33,30 @@ func GetClient() (*Client, error) {
|
||||
|
||||
return singleClient, nil
|
||||
}
|
||||
|
||||
func AddConfigPaths(configFile string) {
|
||||
if configFile != "" {
|
||||
viper.SetConfigFile(configFile)
|
||||
} else {
|
||||
viper.SetConfigName("config")
|
||||
viper.SetConfigType("toml")
|
||||
|
||||
userConfigDir, err := os.UserConfigDir()
|
||||
if err == nil {
|
||||
userConfigPath := filepath.Join(userConfigDir, "imap-notes")
|
||||
_ = os.MkdirAll(userConfigPath, ConfigDirPerms)
|
||||
viper.AddConfigPath(userConfigPath)
|
||||
}
|
||||
|
||||
viper.AddConfigPath("$HOME/.imap-notes")
|
||||
}
|
||||
}
|
||||
|
||||
func InitializeConfig(configFile string) {
|
||||
AddConfigPaths(configFile)
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
slog.OnErrFatalf(viper.SafeWriteConfig(), "failed writing default config")
|
||||
slog.OnErrFatalf(viper.ReadInConfig(), "failed to read config")
|
||||
}
|
||||
}
|
||||
|
12
lib/notes.go
12
lib/notes.go
@ -20,7 +20,6 @@ var (
|
||||
// Note represents an IMAP note.
|
||||
type Note struct {
|
||||
message *imap.Message
|
||||
Name string
|
||||
Folder *NoteFolder
|
||||
deleted bool
|
||||
}
|
||||
@ -166,12 +165,21 @@ func (n Note) EditMarkdown() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n Note) Name() string {
|
||||
return n.message.Envelope.Subject
|
||||
}
|
||||
|
||||
/*
|
||||
* func (n Note) Preview() string {
|
||||
* m.GetBody()
|
||||
* }
|
||||
*/
|
||||
|
||||
// NewNote creates a new note from an imap message.
|
||||
func NewNote(folder *NoteFolder, message *imap.Message) *Note {
|
||||
// TODO: should this be private? See NewNoteFolder
|
||||
return &Note{
|
||||
message: message,
|
||||
Name: message.Envelope.Subject,
|
||||
Folder: folder,
|
||||
deleted: false,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user