blob: a391e7e10642da62cba2e436f753150853ea2390 [file] [log] [blame]
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04001package tasks
2
gioe72b54f2024-04-22 10:44:41 +04003import (
4 "fmt"
5)
6
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04007type Status int
8
9const (
10 StatusPending Status = 0
11 StatusRunning = 1
12 StatusFailed = 2
13 StatusDone = 3
14)
15
gio268787a2025-04-24 21:18:06 +040016func StatusString(s Status) string {
17 switch s {
18 case StatusPending:
19 return "pending"
20 case StatusRunning:
21 return "running"
22 case StatusFailed:
23 return "failed"
24 case StatusDone:
25 return "done"
26 }
27 panic("MUST NOT REACH")
28}
29
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040030type TaskDoneListener func(err error)
31
gio1cd65152024-08-16 08:18:49 +040032type Subtasks interface {
33 Tasks() []Task
34}
35
gio268787a2025-04-24 21:18:06 +040036type ResourceId struct {
37 Type string
38 Name string
39}
40
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040041type Task interface {
gio268787a2025-04-24 21:18:06 +040042 Resource() *ResourceId
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040043 Title() string
44 Start()
45 Status() Status
46 Err() error
47 Subtasks() []Task
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040048 OnDone(l TaskDoneListener)
49}
50
51type basicTask struct {
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040052 title string
gio268787a2025-04-24 21:18:06 +040053 rid *ResourceId
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040054 status Status
55 err error
56 listeners []TaskDoneListener
57 beforeStart func()
58 afterDone func()
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040059}
60
gio268787a2025-04-24 21:18:06 +040061func newBasicTask(title string, rid *ResourceId) basicTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040062 return basicTask{
gio268787a2025-04-24 21:18:06 +040063 rid: rid,
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040064 title: title,
65 status: StatusPending,
66 err: nil,
67 listeners: make([]TaskDoneListener, 0),
68 }
69}
70
gio268787a2025-04-24 21:18:06 +040071func (b *basicTask) Resource() *ResourceId {
72 return b.rid
73}
74
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040075func (b *basicTask) Title() string {
76 return b.title
77}
78
79func (b *basicTask) Status() Status {
80 return b.status
81}
82
83func (b *basicTask) Err() error {
84 return b.err
85}
86
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040087func (b *basicTask) OnDone(l TaskDoneListener) {
88 b.listeners = append(b.listeners, l)
89}
90
91func (b *basicTask) callDoneListeners(err error) {
gioe72b54f2024-04-22 10:44:41 +040092 if err != nil {
93 fmt.Printf("%s %s\n", b.title, err.Error())
94 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040095 for _, l := range b.listeners {
96 go l(err)
97 }
98 if err == nil {
99 b.status = StatusDone
100 } else {
101 b.status = StatusFailed
102 b.err = err
103 }
104}
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400105
106type leafTask struct {
107 basicTask
108 start func() error
109}
110
111func newLeafTask(title string, start func() error) leafTask {
112 return leafTask{
gio268787a2025-04-24 21:18:06 +0400113 basicTask: newBasicTask(title, nil),
114 start: start,
115 }
116}
117
118func newResourceLeafTask(title string, rid *ResourceId, start func() error) leafTask {
119 return leafTask{
120 basicTask: newBasicTask(title, rid),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400121 start: start,
122 }
123}
124
125func (b *leafTask) Subtasks() []Task {
126 return make([]Task, 0)
127}
128
129func (b *leafTask) Start() {
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +0400130 b.status = StatusRunning
131 if b.beforeStart != nil {
132 b.beforeStart()
133 }
134 err := b.start()
135 defer b.callDoneListeners(err)
136 if b.afterDone != nil {
137 b.afterDone()
138 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400139}
140
141type parentTask struct {
142 leafTask
gio1cd65152024-08-16 08:18:49 +0400143 subtasks Subtasks
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400144 showChildren bool
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400145}
146
gio1cd65152024-08-16 08:18:49 +0400147type TaskSlice []Task
148
149func (s TaskSlice) Tasks() []Task {
150 return s
151}
152
153func newParentTask(title string, showChildren bool, start func() error, subtasks Subtasks) parentTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400154 return parentTask{
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400155 leafTask: newLeafTask(title, start),
156 subtasks: subtasks,
157 showChildren: showChildren,
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400158 }
159}
160
161func (t *parentTask) Subtasks() []Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400162 if t.showChildren {
gio1cd65152024-08-16 08:18:49 +0400163 return t.subtasks.Tasks()
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400164 } else {
165 return make([]Task, 0)
166 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400167}
168
gio1cd65152024-08-16 08:18:49 +0400169func newSequentialParentTask(title string, showChildren bool, subtasks ...Task) *parentTask {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400170 start := func() error {
171 errCh := make(chan error)
172 for i := range subtasks[:len(subtasks)-1] {
173 next := i + 1
174 subtasks[i].OnDone(func(err error) {
175 if err == nil {
176 go subtasks[next].Start()
177 } else {
178 errCh <- err
179 }
180 })
181 }
182 subtasks[len(subtasks)-1].OnDone(func(err error) {
183 errCh <- err
184 })
185 go subtasks[0].Start()
186 return <-errCh
187 }
gio1cd65152024-08-16 08:18:49 +0400188 t := newParentTask(title, showChildren, start, TaskSlice(subtasks))
189 return &t
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400190}
191
gio1cd65152024-08-16 08:18:49 +0400192func newConcurrentParentTask(title string, showChildren bool, subtasks ...Task) *parentTask {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400193 start := func() error {
194 errCh := make(chan error)
195 for i := range subtasks {
196 subtasks[i].OnDone(func(err error) {
197 errCh <- err
198 })
199 go subtasks[i].Start()
200 }
Giorgi Lekveishvili0a0ca0e2024-04-01 09:07:41 +0400201 cnt := 0
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400202 for _ = range subtasks {
203 err := <-errCh
204 if err != nil {
205 return err
206 }
Giorgi Lekveishvili0a0ca0e2024-04-01 09:07:41 +0400207 cnt++
208 if cnt == len(subtasks) {
209 break
210 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400211 }
212 return nil
213 }
gio1cd65152024-08-16 08:18:49 +0400214 t := newParentTask(title, showChildren, start, TaskSlice(subtasks))
215 return &t
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400216}