Added default_account and Find function
This commit is contained in:
parent
4b283db0f1
commit
5fb994bd68
7 changed files with 112 additions and 11 deletions
|
@ -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() {
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
|
@ -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{
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
22
example/example_config.toml
Normal file
22
example/example_config.toml
Normal 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"
|
Loading…
Reference in a new issue