github.com/vektra/tachyon@v0.0.0-20150921164542-0da4f3861aef/runner.go (about) 1 package tachyon 2 3 import ( 4 "os" 5 "sync" 6 "time" 7 ) 8 9 type RunResult struct { 10 Task *Task 11 Result *Result 12 Runtime time.Duration 13 } 14 15 type Runner struct { 16 env *Environment 17 plays []*Play 18 wait sync.WaitGroup 19 to_notify map[string]struct{} 20 async chan *AsyncAction 21 report Reporter 22 23 Results []RunResult 24 Start time.Time 25 Runtime time.Duration 26 } 27 28 func NewRunner(env *Environment, plays []*Play) *Runner { 29 r := &Runner{ 30 env: env, 31 plays: plays, 32 to_notify: make(map[string]struct{}), 33 async: make(chan *AsyncAction), 34 report: env.report, 35 } 36 37 go r.handleAsync() 38 39 return r 40 } 41 42 func (r *Runner) SetReport(rep Reporter) { 43 r.report = rep 44 } 45 46 func (r *Runner) AddNotify(n string) { 47 r.to_notify[n] = struct{}{} 48 } 49 50 func (r *Runner) ShouldRunHandler(name string) bool { 51 _, ok := r.to_notify[name] 52 53 return ok 54 } 55 56 func (r *Runner) AsyncChannel() chan *AsyncAction { 57 return r.async 58 } 59 60 func (r *Runner) Run(env *Environment) error { 61 start := time.Now() 62 r.Start = start 63 64 defer func() { 65 r.Runtime = time.Since(start) 66 }() 67 68 r.report.StartTasks(r) 69 70 for _, play := range r.plays { 71 fs := NewFutureScope(play.Vars) 72 73 for _, task := range play.Tasks { 74 err := r.runTask(env, play, task, fs, fs) 75 if err != nil { 76 return err 77 } 78 } 79 80 r.Results = append(r.Results, fs.Results()...) 81 } 82 83 r.report.FinishTasks(r) 84 85 r.wait.Wait() 86 87 r.report.StartHandlers(r) 88 89 for _, play := range r.plays { 90 fs := NewFutureScope(play.Vars) 91 92 for _, task := range play.Handlers { 93 if r.ShouldRunHandler(task.Name()) { 94 err := r.runTask(env, play, task, fs, fs) 95 96 if err != nil { 97 return err 98 } 99 } 100 } 101 102 fs.Wait() 103 } 104 105 r.report.FinishHandlers(r) 106 107 return nil 108 } 109 110 func RunAdhocTask(cmd, args string) (*Result, error) { 111 env := NewEnv(NewNestedScope(nil), &Config{}) 112 defer env.Cleanup() 113 114 task := AdhocTask(cmd, args) 115 116 str, err := ExpandVars(env.Vars, task.Args()) 117 if err != nil { 118 return nil, err 119 } 120 121 obj, _, err := MakeCommand(env.Vars, task, str) 122 if err != nil { 123 return nil, err 124 } 125 126 ar := &AdhocProgress{out: os.Stdout, Start: time.Now()} 127 128 ce := &CommandEnv{Env: env, Paths: env.Paths, progress: ar} 129 130 return obj.Run(ce) 131 } 132 133 func RunAdhocTaskVars(td TaskData) (*Result, error) { 134 env := NewEnv(NewNestedScope(nil), &Config{}) 135 defer env.Cleanup() 136 137 task := &Task{data: td} 138 task.Init(env) 139 140 obj, _, err := MakeCommand(env.Vars, task, "") 141 if err != nil { 142 return nil, err 143 } 144 145 ar := &AdhocProgress{out: os.Stdout, Start: time.Now()} 146 147 ce := &CommandEnv{Env: env, Paths: env.Paths, progress: ar} 148 149 return obj.Run(ce) 150 } 151 152 func RunAdhocCommand(cmd Command, args string) (*Result, error) { 153 env := NewEnv(NewNestedScope(nil), &Config{}) 154 defer env.Cleanup() 155 156 ar := &AdhocProgress{out: os.Stdout, Start: time.Now()} 157 158 ce := &CommandEnv{Env: env, Paths: env.Paths, progress: ar} 159 160 return cmd.Run(ce) 161 } 162 163 type PriorityScope struct { 164 task Vars 165 rest Scope 166 } 167 168 func (p *PriorityScope) Get(key string) (Value, bool) { 169 if p.task != nil { 170 if v, ok := p.task[key]; ok { 171 return Any(v), true 172 } 173 } 174 175 return p.rest.Get(key) 176 } 177 178 func (p *PriorityScope) Set(key string, val interface{}) { 179 p.rest.Set(key, val) 180 } 181 182 func boolify(str string) bool { 183 switch str { 184 case "", "false", "no": 185 return false 186 default: 187 return true 188 } 189 } 190 191 type ModuleRun struct { 192 Play *Play 193 Task *Task 194 Module *Module 195 Runner *Runner 196 Scope Scope 197 FutureScope *FutureScope 198 Vars Vars 199 } 200 201 func (m *ModuleRun) Run(env *CommandEnv) (*Result, error) { 202 for _, task := range m.Module.ModTasks { 203 ns := NewNestedScope(m.Scope) 204 205 for k, v := range m.Vars { 206 ns.Set(k, v) 207 } 208 209 err := m.Runner.runTask(env.Env, m.Play, task, ns, m.FutureScope) 210 if err != nil { 211 return nil, err 212 } 213 } 214 215 return NewResult(true), nil 216 } 217 218 func (r *Runner) runTaskItems(env *Environment, play *Play, task *Task, s Scope, fs *FutureScope, start time.Time) error { 219 220 for _, item := range task.Items() { 221 ns := NewNestedScope(s) 222 ns.Set("item", item) 223 224 name, err := ExpandVars(ns, task.Name()) 225 if err != nil { 226 return err 227 } 228 229 str, err := ExpandVars(ns, task.Args()) 230 if err != nil { 231 return err 232 } 233 234 cmd, sm, err := MakeCommand(ns, task, str) 235 if err != nil { 236 return err 237 } 238 239 r.report.StartTask(task, name, str, sm) 240 241 ce := NewCommandEnv(env, task) 242 243 res, err := cmd.Run(ce) 244 245 if name := task.Register(); name != "" { 246 fs.Set(name, res) 247 } 248 249 runtime := time.Since(start) 250 251 if err != nil { 252 res = FailureResult(err) 253 } 254 255 r.Results = append(r.Results, RunResult{task, res, runtime}) 256 257 r.report.FinishTask(task, res) 258 259 if err == nil { 260 for _, x := range task.Notify() { 261 r.AddNotify(x) 262 } 263 } else { 264 return err 265 } 266 } 267 268 return nil 269 } 270 271 func (r *Runner) runTask(env *Environment, play *Play, task *Task, s Scope, fs *FutureScope) error { 272 ps := &PriorityScope{task.IncludeVars, s} 273 274 start := time.Now() 275 276 if when := task.When(); when != "" { 277 when, err := ExpandVars(ps, when) 278 279 if err != nil { 280 return err 281 } 282 283 if !boolify(when) { 284 return nil 285 } 286 } 287 288 if items := task.Items(); items != nil { 289 return r.runTaskItems(env, play, task, s, fs, start) 290 } 291 292 name, err := ExpandVars(ps, task.Name()) 293 if err != nil { 294 return err 295 } 296 297 str, err := ExpandVars(ps, task.Args()) 298 if err != nil { 299 return err 300 } 301 302 var cmd Command 303 304 var argVars Vars 305 306 if mod, ok := play.Modules[task.Command()]; ok { 307 sm, err := ParseSimpleMap(s, str) 308 if err != nil { 309 return err 310 } 311 312 for ik, iv := range task.Vars { 313 if str, ok := iv.Read().(string); ok { 314 exp, err := ExpandVars(s, str) 315 if err != nil { 316 return err 317 } 318 319 sm[ik] = Any(exp) 320 } else { 321 sm[ik] = iv 322 } 323 } 324 325 cmd = &ModuleRun{ 326 Play: play, 327 Task: task, 328 Module: mod, 329 Runner: r, 330 Scope: s, 331 FutureScope: NewFutureScope(s), 332 Vars: sm, 333 } 334 335 argVars = sm 336 } else { 337 cmd, argVars, err = MakeCommand(ps, task, str) 338 339 if err != nil { 340 return err 341 } 342 } 343 344 r.report.StartTask(task, name, str, argVars) 345 346 ce := NewCommandEnv(env, task) 347 348 if name := task.Future(); name != "" { 349 future := NewFuture(start, task, func() (*Result, error) { 350 return cmd.Run(ce) 351 }) 352 353 fs.AddFuture(name, future) 354 355 return nil 356 } 357 358 if task.Async() { 359 asyncAction := &AsyncAction{Task: task} 360 asyncAction.Init(r) 361 362 go func() { 363 asyncAction.Finish(cmd.Run(ce)) 364 }() 365 } else { 366 res, err := cmd.Run(ce) 367 368 if name := task.Register(); name != "" { 369 fs.Set(name, res) 370 } 371 372 runtime := time.Since(start) 373 374 if err != nil { 375 res = FailureResult(err) 376 } 377 378 r.Results = append(r.Results, RunResult{task, res, runtime}) 379 380 r.report.FinishTask(task, res) 381 382 if err == nil { 383 for _, x := range task.Notify() { 384 r.AddNotify(x) 385 } 386 } else { 387 return err 388 } 389 } 390 391 return err 392 }