Added default_account and Find function

This commit is contained in:
Blallo 2021-01-31 01:14:00 +01:00
parent 4b283db0f1
commit 5fb994bd68
No known key found for this signature in database
GPG key ID: 0CBE577C9B72DC3F
7 changed files with 112 additions and 11 deletions

View file

@ -14,14 +14,39 @@ import (
var ErrPortOutOfRange = errors.New("port out of range") var ErrPortOutOfRange = errors.New("port out of range")
var ErrMissingPassword = errors.New("password has not been set") var ErrMissingPassword = errors.New("password has not been set")
var ErrMissingDefaultAccount = errors.New("default_account is missing from config")
// CastingErrors is a simple wrapper around map[string]error. It's endowed with a utility // CastingErrors is a simple wrapper around map[string]error. It's endowed with a utility
// function to check if there are any errors. // function to check if there are any errors.
type CastingErrors map[string]error type CastingErrors struct {
GeneralErrors []error
AccountErrors map[string]error
}
func initCastingErrors() *CastingErrors {
c := CastingErrors{}
c.AccountErrors = make(map[string]error)
return &c
}
func (c *CastingErrors) appendGeneralError(e error) {
c.GeneralErrors = append(c.GeneralErrors, e)
}
func (c *CastingErrors) String() string {
out := "CastingErrors{"
out += fmt.Sprintf("GeneralErrors: %s, ", c.GeneralErrors)
out += fmt.Sprintf("AccountErrors: %s", c.AccountErrors)
out += "}"
return out
}
// Check if there are any errors, i.e. if any value of the map is not nil. // Check if there are any errors, i.e. if any value of the map is not nil.
func (c CastingErrors) Check() bool { func (c CastingErrors) Check() bool {
for _, err := range c { if len(c.GeneralErrors) != 0 {
return false
}
for _, err := range c.GeneralErrors {
if err != nil { if err != nil {
return false return false
} }
@ -32,6 +57,7 @@ func (c CastingErrors) Check() bool {
// MemConfig is the data structure that will be used program-wise. It holds all the // MemConfig is the data structure that will be used program-wise. It holds all the
// necessary information to authenticate and manage each provided account. // necessary information to authenticate and manage each provided account.
type MemConfig struct { type MemConfig struct {
Default string
Accounts map[string]*AccountData Accounts map[string]*AccountData
Workers map[string]*worker.Worker Workers map[string]*worker.Worker
} }
@ -68,18 +94,23 @@ func (a *AccountData) String() string {
} }
// parseConfig translates a *fileConfig, as obtained from a file read, into a usable // parseConfig translates a *fileConfig, as obtained from a file read, into a usable
// *MemConfig that could be used in computation, together with a custom CastingErrors // *MemConfig that could be used in computation, together with a custom *CastingErrors
// type, that holds the translation errors for each account. // type, that holds the translation errors for each account.
func parseConfig(fileConfig *fileConfig) (*MemConfig, CastingErrors) { func parseConfig(fileConfig *fileConfig) (*MemConfig, *CastingErrors) {
errors := initCastingErrors()
outConfig := initMemConfig() outConfig := initMemConfig()
defaultAccount := fileConfig.Default
if defaultAccount == "" {
errors.appendGeneralError(ErrMissingDefaultAccount)
}
outConfig.Default = defaultAccount
basePath, err := getOrDefaultMailbox(fileConfig.MailboxPath) basePath, err := getOrDefaultMailbox(fileConfig.MailboxPath)
defaultMessages := getOrDefaultMessages(fileConfig.DefaultMessages) defaultMessages := getOrDefaultMessages(fileConfig.DefaultMessages)
if err != nil { if err != nil {
log.Fatal("Could not determine base path") log.Fatal("Could not determine base path")
} }
errors := make(map[string]error)
for _, account := range fileConfig.Accounts { for _, account := range fileConfig.Accounts {
outConfig.Accounts[account.Name], errors[account.Name] = parseData(&account, basePath, defaultMessages) outConfig.Accounts[account.Name], errors.AccountErrors[account.Name] = parseData(&account, basePath, defaultMessages)
outConfig.Workers[account.Name] = &worker.Worker{} outConfig.Workers[account.Name] = &worker.Worker{}
} }
return &outConfig, errors return &outConfig, errors
@ -165,7 +196,6 @@ func getPassword(connection *connectionInfo) (string, error) {
} }
func getMailboxPath(name, configPath, basePath string) string { func getMailboxPath(name, configPath, basePath string) string {
log.Printf("name: %s,\tconfig_path: %s,\tbase_path: %s\n", name, configPath, basePath)
if configPath != "" { if configPath != "" {
if info, err := os.Stat(configPath); err == nil || err != os.ErrNotExist && info != nil { if info, err := os.Stat(configPath); err == nil || err != os.ErrNotExist && info != nil {
if info.IsDir() { if info.IsDir() {

View file

@ -9,8 +9,9 @@ import (
func TestParseConfig(t *testing.T) { func TestParseConfig(t *testing.T) {
expected := &MemConfig{ expected := &MemConfig{
Default: "First Account",
Accounts: map[string]*AccountData{ Accounts: map[string]*AccountData{
"First Account": &AccountData{ "First Account": {
Host: "mx.example.com", Host: "mx.example.com",
Port: 993, Port: 993,
Username: "first@example.com", Username: "first@example.com",
@ -19,7 +20,7 @@ func TestParseConfig(t *testing.T) {
MailboxPath: "/opt", MailboxPath: "/opt",
Messages: 30, Messages: 30,
}, },
"Other Account": &AccountData{ "Other Account": {
Host: "mail.personal.me", Host: "mail.personal.me",
Port: 666, Port: 666,
Username: "h4x0R@personal.me", Username: "h4x0R@personal.me",
@ -30,8 +31,8 @@ func TestParseConfig(t *testing.T) {
}, },
}, },
Workers: map[string]*worker.Worker{ Workers: map[string]*worker.Worker{
"First Account": &worker.Worker{}, "First Account": {},
"Other Account": &worker.Worker{}, "Other Account": {},
}, },
} }
file := writeToTempFile(t, "papero.*.toml", testConfig) file := writeToTempFile(t, "papero.*.toml", testConfig)
@ -46,6 +47,10 @@ func TestParseConfig(t *testing.T) {
t.Fatal(errs) t.Fatal(errs)
} }
if result.Default != expected.Default {
t.Errorf("Default account does not match. Expected: %s\tResult:\t%s\n", expected.Default, result.Default)
}
if !cmp.Equal(result.Accounts, expected.Accounts) { if !cmp.Equal(result.Accounts, expected.Accounts) {
t.Errorf("Result and expected result differ: %+v\n", cmp.Diff(result.Accounts, expected.Accounts)) t.Errorf("Result and expected result differ: %+v\n", cmp.Diff(result.Accounts, expected.Accounts))
} }

View file

@ -41,6 +41,7 @@ func (m *maybeInt) UnmarshalText(text []byte) error {
} }
type fileConfig struct { type fileConfig struct {
Default string `toml:"default_account"`
MailboxPath string `toml:"mailbox_path"` MailboxPath string `toml:"mailbox_path"`
Accounts []account `toml:"account"` Accounts []account `toml:"account"`
DefaultMessages maybeInt `toml:"default_messages"` DefaultMessages maybeInt `toml:"default_messages"`

View file

@ -26,6 +26,7 @@ func TestShellScriptRunExecutableWithArgs(t *testing.T) {
func TestParseFile(t *testing.T) { func TestParseFile(t *testing.T) {
expected := &fileConfig{ expected := &fileConfig{
Default: "First Account",
MailboxPath: "../base/mailbox", MailboxPath: "../base/mailbox",
DefaultMessages: initMaybeInt(50), DefaultMessages: initMaybeInt(50),
Accounts: []account{ Accounts: []account{

View file

@ -7,6 +7,7 @@ import (
) )
const testConfig = ` const testConfig = `
default_account = "First Account"
mailbox_path = "../base/mailbox" mailbox_path = "../base/mailbox"
default_messages = 50 default_messages = 50

View file

@ -2,9 +2,16 @@ package config
import ( import (
"errors" "errors"
"fmt"
"log" "log"
"os"
"path"
"github.com/mitchellh/go-homedir"
) )
var confFileName = "papero.toml"
var ErrConfigNotFound = errors.New("unable to find configuration")
var ErrFailedToParseConfig = errors.New("unable to cast into usable configuration") var ErrFailedToParseConfig = errors.New("unable to cast into usable configuration")
func Parse(filePath string) (*MemConfig, error) { func Parse(filePath string) (*MemConfig, error) {
@ -19,3 +26,37 @@ func Parse(filePath string) (*MemConfig, error) {
} }
return memConfig, nil return memConfig, nil
} }
// Find looks for the configuration file in the following order:
// - $PWD/papero.toml
// - ~/.config/papero/papero.toml
// - ~/.papero.toml
// - /etc/papero.toml
// returns and error if no file has been found
func Find() (string, error) {
var paths []string
// Try to append $PWD/papero.toml
cwd, err := os.Getwd()
if err == nil {
paths = append(paths, path.Join(cwd, confFileName))
}
// Try to append ~/.config/papero/papero.toml and ~/.papero.toml
home, err := homedir.Dir()
if err == nil {
paths = append(paths, path.Join(home, ".config", "papero", confFileName))
paths = append(paths, path.Join(home, fmt.Sprintf(".%s", confFileName)))
}
// Append /etc/papero.toml
paths = append(paths, path.Join("/etc", confFileName))
for _, file := range paths {
info, err := os.Stat(file)
if err == nil && !info.IsDir() {
return file, nil
}
}
return "", ErrConfigNotFound
}

View file

@ -0,0 +1,22 @@
default_account = "First Account"
mailbox_path = "../base/mailbox"
default_messages = 50
[[account]]
name = "First Account"
mailbox_path = "/opt"
messages = 30
excluded_folders = ["Draft", "Junk"]
[account.connection]
hostname = "mx.example.com"
port = 993
username = "first@example.com"
password_exec = "echo -n 123qweasdzxc"
[[account]]
name = "Other Account"
[account.connection]
hostname = "mail.personal.me"
port = 666
username = "h4x0R@personal.me"
password = "mySup3r5ekre7p4ssw0rd123"