-
Notifications
You must be signed in to change notification settings - Fork 33
/
task.go
162 lines (128 loc) · 3.37 KB
/
task.go
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package project
import (
"context"
"regexp"
"github.com/pkg/errors"
"github.com/stateful/runme/v3/pkg/document"
)
// Task is struct representing a [document.CodeBlock] within the context of a project.
// Instance of [document.Document] can be retrieved from [Task]'s code block.
// [Task] contains absolute and relative path to the document.
type Task struct {
CodeBlock *document.CodeBlock `json:"code_block"`
DocumentPath string `json:"document_path"`
RelDocumentPath string `json:"rel_document_path"`
}
func (t Task) ID() string {
return t.RelDocumentPath + ":" + t.CodeBlock.Name()
}
// LoadFiles returns a list of file names found in the project.
func LoadFiles(ctx context.Context, p *Project) ([]string, error) {
eventc := make(chan LoadEvent)
go p.Load(ctx, eventc, true)
var (
result []string
err error
)
for event := range eventc {
switch event.Type {
case LoadEventError:
data := ExtractDataFromLoadEvent[LoadEventErrorData](event)
if err != nil {
err = data.Err
}
case LoadEventFoundFile:
data := ExtractDataFromLoadEvent[LoadEventFoundFileData](event)
result = append(result, data.Path)
}
}
return result, err
}
func LoadTasks(ctx context.Context, p *Project) ([]Task, error) {
eventc := make(chan LoadEvent)
go p.Load(ctx, eventc, false)
var (
result []Task
err error
)
for event := range eventc {
switch event.Type {
case LoadEventError:
data := ExtractDataFromLoadEvent[LoadEventErrorData](event)
if err != nil {
err = data.Err
}
case LoadEventFoundTask:
data := ExtractDataFromLoadEvent[LoadEventFoundTaskData](event)
result = append(result, data.Task)
}
}
return result, err
}
type Filter func(Task) (bool, error)
var ErrReturnEarly = errors.New("return early")
func FilterTasksByFn(tasks []Task, fns ...Filter) (result []Task, err error) {
for _, task := range tasks {
var errFn error
include := true
for _, fn := range fns {
var ok bool
ok, errFn = fn(task)
if !ok {
include = false
break
}
if errFn != nil {
break
}
}
if include {
result = append(result, task)
}
if errFn != nil {
if !errors.Is(errFn, ErrReturnEarly) {
err = errFn
}
return
}
}
return
}
func FilterTasksByID(tasks []Task, expr string) (result []Task, err error) {
matcher, err := compileRegex(expr)
if err != nil {
return nil, err
}
return FilterTasksByFn(tasks, func(task Task) (bool, error) {
return matcher.MatchString(task.ID()), nil
})
}
func FilterTasksByFilename(tasks []Task, expr string) (result []Task, err error) {
matcher, err := compileRegex(expr)
if err != nil {
return nil, err
}
return FilterTasksByFn(tasks, func(task Task) (bool, error) {
return matcher.MatchString(task.DocumentPath), nil
})
}
func FilterTasksByExactTaskName(tasks []Task, name string) (result []Task, err error) {
return FilterTasksByFn(tasks, func(task Task) (bool, error) {
return task.CodeBlock.Name() == name, nil
})
}
func CompileRegex(query string) (Matcher, error) {
return compileRegex(query)
}
func compileRegex(query string) (Matcher, error) {
if query == "" {
return &matchAll{}, nil
}
reg, err := regexp.Compile(query)
return reg, errors.Wrapf(err, "invalid regexp %q", query)
}
type Matcher interface {
MatchString(string) bool
}
type matchAll struct{}
func (matchAll) MatchString(string) bool { return true }