-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtask.go
More file actions
140 lines (112 loc) · 3.64 KB
/
task.go
File metadata and controls
140 lines (112 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package main
import (
"encoding/json"
"errors"
"fmt"
"os/exec"
"time"
"google.golang.org/api/calendar/v3"
)
const twTimeFormat = "20060102T150405Z"
type taskWarrior struct {
path string
}
func findTaskwarrior() (*taskWarrior, error) {
for _, path := range []string{"task", "taskw"} {
s, err := exec.LookPath(path)
if err == nil {
return &taskWarrior{path: s}, nil
}
}
return nil, errors.New("Could not find taskwarrior")
}
func (tw *taskWarrior) runTask(args ...string) ([]byte, error) {
return exec.Command(tw.path, args...).Output()
}
// runs the command and attempts to read the tasks. `export` argument
// is required in your args stanza.
// f.e.: `export all`
func (tw *taskWarrior) exportTasksByCommand(args ...string) (taskWarriorItems, error) {
out, err := tw.runTask(args...)
if err != nil {
return nil, fmt.Errorf("Could not export tasks: %w", err)
}
items := taskWarriorItems{}
return items, items.unmarshalItems(out)
}
func (tw *taskWarrior) importTasks(items taskWarriorItems) error {
cmd := exec.Command(tw.path, "import")
pipe, err := cmd.StdinPipe()
if err != nil {
return fmt.Errorf("Trouble establishing stdin pipe: %w", err)
}
if err := cmd.Start(); err != nil {
return fmt.Errorf("Could not start 'task import': %w", err)
}
defer cmd.Process.Kill()
out, err := json.Marshal(items)
if err != nil {
return fmt.Errorf("Could not marshal items: %w", err)
}
if _, err := pipe.Write(out); err != nil {
return fmt.Errorf("Could not write json to pipe: %w", err)
}
pipe.Close()
return cmd.Wait()
}
type taskWarriorTime string
func (twt taskWarriorTime) ToTime() (time.Time, error) {
if twt == "" {
return time.Time{}, errors.New("time is blank")
}
return time.Parse(twTimeFormat, string(twt))
}
func (twt taskWarriorTime) ToGCal() (*calendar.EventDateTime, error) {
t, err := twt.ToTime()
if err != nil {
return nil, err
}
return &calendar.EventDateTime{DateTime: string(toCalendarTime(t)), TimeZone: time.Local.String()}, nil
}
func toTaskWarriorTime(t time.Time) taskWarriorTime {
return taskWarriorTime(t.Format(twTimeFormat))
}
type taskWarriorItems []*taskWarriorItem
type taskWarriorItem struct {
ID int `json:"id"`
Status string `json:"status"`
UUID string `json:"uuid"`
Entry taskWarriorTime `json:"entry"`
Description string `json:"description"`
Start taskWarriorTime `json:"start,omitempty"`
End taskWarriorTime `json:"end,omitempty"`
Due taskWarriorTime `json:"due,omitempty"`
Until taskWarriorTime `json:"until,omitempty"`
Wait taskWarriorTime `json:"wait,omitempty"`
Modified taskWarriorTime `json:"modified,omitempty"`
Scheduled taskWarriorTime `json:"scheduled,omitempty"`
Recur string `json:"recur,omitempty"`
Mask string `json:"mask,omitempty"`
IMask float64 `json:"imask,omitempty"`
Parent string `json:"parent,omitempty"`
Project string `json:"project,omitempty"`
Priority string `json:"priority,omitempty"`
Depends string `json:"depends,omitempty"`
Tags []string `json:"tags,omitempty"`
Annotation []string `json:"annotation,omitempty"`
CalendarID string `json:"udf.calwarrior.id,omitempty"`
}
func (twi *taskWarriorItems) unmarshalItems(out []byte) error {
if err := json.Unmarshal(out, twi); err != nil {
return fmt.Errorf("Could not parse JSON: %w", err)
}
return nil
}
type taskWarriorTags []string
func (twt taskWarriorTags) decorate() []string {
tags := []string{}
for i := range twt {
tags = append(tags, "+"+twt[i])
}
return tags
}