spearated commands

This commit is contained in:
Erik Winter 2021-07-09 09:42:44 +02:00
parent b3fbabd4e7
commit 7845f32aae
7 changed files with 250 additions and 104 deletions

View File

@ -1,27 +1,13 @@
package command package command
import ( import (
"errors"
"fmt" "fmt"
"git.ewintr.nl/gte/internal/configuration" "git.ewintr.nl/gte/internal/configuration"
"git.ewintr.nl/gte/internal/process"
"git.ewintr.nl/gte/internal/storage"
"git.ewintr.nl/gte/internal/task"
"git.ewintr.nl/gte/pkg/mstore"
) )
var (
ErrInitCommand = errors.New("could not initialize command")
ErrFailedCommand = errors.New("could not execute command")
)
type Result struct {
Message string
}
type Command interface { type Command interface {
Do() (Result, error) Do() string
} }
func Parse(args []string, conf *configuration.Configuration) (Command, error) { func Parse(args []string, conf *configuration.Configuration) (Command, error) {
@ -40,87 +26,6 @@ func Parse(args []string, conf *configuration.Configuration) (Command, error) {
} }
} }
type Empty struct{} func FormatError(err error) string {
return fmt.Sprintf("could not perform command.\n\nerror: %s\n", err.Error())
func NewEmpty() (*Empty, error) {
return &Empty{}, nil
}
func (cmd *Empty) Do() (Result, error) {
return Result{
Message: "did nothing\n",
}, nil
}
type Sync struct {
syncer *process.Sync
}
func NewSync(conf *configuration.Configuration) (*Sync, error) {
msgStore := mstore.NewIMAP(conf.IMAP())
remote := storage.NewRemoteRepository(msgStore)
local, err := storage.NewSqlite(conf.Sqlite())
if err != nil {
return &Sync{}, fmt.Errorf("%w: %v", ErrInitCommand, err)
}
syncer := process.NewSync(remote, local)
return &Sync{
syncer: syncer,
}, nil
}
func (s *Sync) Do() (Result, error) {
result, err := s.syncer.Process()
if err != nil {
return Result{}, fmt.Errorf("%w: %v", ErrFailedCommand, err)
}
return Result{
Message: fmt.Sprintf("synced %d tasks\n", result.Count),
}, nil
}
type Today struct {
local storage.LocalRepository
}
func NewToday(conf *configuration.Configuration) (*Today, error) {
local, err := storage.NewSqlite(conf.Sqlite())
if err != nil {
return &Today{}, fmt.Errorf("%w: %v", ErrInitCommand, err)
}
return &Today{
local: local,
}, nil
}
func (t *Today) Do() (Result, error) {
tasks, err := t.local.FindAllInFolder(task.FOLDER_PLANNED)
if err != nil {
return Result{}, fmt.Errorf("%w: %v", ErrFailedCommand, err)
}
todayTasks := []*task.Task{}
for _, t := range tasks {
if t.Due == task.Today || task.Today.After(t.Due) {
todayTasks = append(todayTasks, t)
}
}
if len(todayTasks) == 0 {
return Result{
Message: "nothing left",
}, nil
}
var msg string
for _, t := range todayTasks {
msg += fmt.Sprintf("%s - %s\n", t.Project, t.Action)
}
return Result{
Message: msg,
}, nil
} }

11
cmd/cli/command/empty.go Normal file
View File

@ -0,0 +1,11 @@
package command
type Empty struct{}
func NewEmpty() (*Empty, error) {
return &Empty{}, nil
}
func (cmd *Empty) Do() string {
return "did nothing\n"
}

37
cmd/cli/command/sync.go Normal file
View File

@ -0,0 +1,37 @@
package command
import (
"fmt"
"git.ewintr.nl/gte/internal/configuration"
"git.ewintr.nl/gte/internal/process"
"git.ewintr.nl/gte/internal/storage"
"git.ewintr.nl/gte/pkg/mstore"
)
type Sync struct {
syncer *process.Sync
}
func NewSync(conf *configuration.Configuration) (*Sync, error) {
msgStore := mstore.NewIMAP(conf.IMAP())
remote := storage.NewRemoteRepository(msgStore)
local, err := storage.NewSqlite(conf.Sqlite())
if err != nil {
return &Sync{}, err
}
syncer := process.NewSync(remote, local)
return &Sync{
syncer: syncer,
}, nil
}
func (s *Sync) Do() string {
result, err := s.syncer.Process()
if err != nil {
return FormatError(err)
}
return fmt.Sprintf("synced %d tasks\n", result.Count)
}

47
cmd/cli/command/today.go Normal file
View File

@ -0,0 +1,47 @@
package command
import (
"fmt"
"git.ewintr.nl/gte/internal/configuration"
"git.ewintr.nl/gte/internal/process"
"git.ewintr.nl/gte/internal/storage"
"git.ewintr.nl/gte/internal/task"
)
type Today struct {
todayer *process.List
}
func NewToday(conf *configuration.Configuration) (*Today, error) {
local, err := storage.NewSqlite(conf.Sqlite())
if err != nil {
return &Today{}, err
}
reqs := process.ListReqs{
Due: task.Today,
IncludeBefore: true,
}
todayer := process.NewList(local, reqs)
return &Today{
todayer: todayer,
}, nil
}
func (t *Today) Do() string {
res, err := t.todayer.Process()
if err != nil {
return FormatError(err)
}
if len(res.Tasks) == 0 {
return "nothing left\n"
}
var msg string
for _, t := range res.Tasks {
msg += fmt.Sprintf("%s - %s\n", t.Project, t.Action)
}
return msg
}

View File

@ -25,10 +25,5 @@ func main() {
fmt.Println(err, "could not initialize command") fmt.Println(err, "could not initialize command")
os.Exit(1) os.Exit(1)
} }
result, err := cmd.Do() fmt.Printf("%s\n", cmd.Do())
if err != nil {
fmt.Println(err, "could not perform command")
os.Exit(1)
}
fmt.Printf("%s\n", result.Message)
} }

66
internal/process/list.go Normal file
View File

@ -0,0 +1,66 @@
package process
import (
"errors"
"fmt"
"git.ewintr.nl/gte/internal/storage"
"git.ewintr.nl/gte/internal/task"
)
var (
ErrInvalidReqs = errors.New("could not make sense of requirements")
ErrListProcess = errors.New("could not fetch task list")
)
// ListReqs specifies the requirements in AND fashion for a list of tasks
type ListReqs struct {
Due task.Date
IncludeBefore bool
}
func (lr ListReqs) Valid() bool {
return !lr.Due.IsZero()
}
// List finds all tasks that satisfy the given requirements
type List struct {
local storage.LocalRepository
reqs ListReqs
}
type ListResult struct {
Tasks []*task.Task
}
func NewList(local storage.LocalRepository, reqs ListReqs) *List {
return &List{
local: local,
reqs: reqs,
}
}
func (l *List) Process() (*ListResult, error) {
if !l.reqs.Valid() {
return &ListResult{}, ErrInvalidReqs
}
potentialTasks, err := l.local.FindAllInFolder(task.FOLDER_PLANNED)
if err != nil {
return &ListResult{}, fmt.Errorf("%w: %v", ErrListProcess, err)
}
dueTasks := []*task.Task{}
for _, t := range potentialTasks {
switch {
case t.Due.Equal(l.reqs.Due):
dueTasks = append(dueTasks, t)
case l.reqs.IncludeBefore && l.reqs.Due.After(t.Due):
dueTasks = append(dueTasks, t)
}
}
return &ListResult{
Tasks: dueTasks,
}, nil
}

View File

@ -0,0 +1,85 @@
package process_test
import (
"errors"
"testing"
"git.ewintr.nl/go-kit/test"
"git.ewintr.nl/gte/internal/process"
"git.ewintr.nl/gte/internal/storage"
"git.ewintr.nl/gte/internal/task"
)
func TestListProcess(t *testing.T) {
date1 := task.NewDate(2021, 7, 9)
date2 := task.NewDate(2021, 7, 10)
date3 := task.NewDate(2021, 7, 11)
task1 := &task.Task{
Id: "id1",
Version: 1,
Action: "action1",
Folder: task.FOLDER_NEW,
}
task2 := &task.Task{
Id: "id2",
Version: 1,
Action: "action2",
Due: date1,
Folder: task.FOLDER_PLANNED,
}
task3 := &task.Task{
Id: "id3",
Version: 1,
Action: "action3",
Due: date2,
Folder: task.FOLDER_PLANNED,
}
task4 := &task.Task{
Id: "id4",
Version: 1,
Action: "action4",
Due: date3,
Folder: task.FOLDER_PLANNED,
}
allTasks := []*task.Task{task1, task2, task3, task4}
local := storage.NewMemory()
test.OK(t, local.SetTasks(allTasks))
t.Run("invalid reqs", func(t *testing.T) {
list := process.NewList(local, process.ListReqs{})
_, actErr := list.Process()
test.Assert(t, errors.Is(actErr, process.ErrInvalidReqs), "expected invalid reqs err")
})
for _, tc := range []struct {
name string
reqs process.ListReqs
exp []*task.Task
}{
{
name: "due",
reqs: process.ListReqs{
Due: date2,
},
exp: []*task.Task{task3},
},
{
name: "due and before",
reqs: process.ListReqs{
Due: date2,
IncludeBefore: true,
},
exp: []*task.Task{task2, task3},
},
} {
t.Run(tc.name, func(t *testing.T) {
list := process.NewList(local, tc.reqs)
act, err := list.Process()
test.OK(t, err)
test.Equals(t, tc.exp, act.Tasks)
})
}
}