1package output 2 3import ( 4 "fmt" 5 "io" 6 7 "github.com/taskctl/taskctl/pkg/task" 8) 9 10// Output types 11const ( 12 FormatRaw = "raw" 13 FormatPrefixed = "prefixed" 14 FormatCockpit = "cockpit" 15) 16 17var closed = false 18var closeCh = make(chan bool) 19 20// DecoratedOutputWriter is a decorator for task output. 21// It extends io.Writer with methods to write header before output starts and footer after execution completes 22type DecoratedOutputWriter interface { 23 io.Writer 24 WriteHeader() error 25 WriteFooter() error 26} 27 28// TaskOutput connects given task with requested decorator 29type TaskOutput struct { 30 t *task.Task 31 decorator DecoratedOutputWriter 32} 33 34// NewTaskOutput creates new TaskOutput instance for given task. 35func NewTaskOutput(t *task.Task, format string, stdout, stderr io.Writer) (*TaskOutput, error) { 36 o := &TaskOutput{ 37 t: t, 38 } 39 40 switch format { 41 case FormatRaw: 42 o.decorator = newRawOutputWriter(stdout) 43 case FormatPrefixed: 44 o.decorator = newPrefixedOutputWriter(t, stdout) 45 case FormatCockpit: 46 o.decorator = newCockpitOutputWriter(t, stdout, closeCh) 47 default: 48 return nil, fmt.Errorf("unknown decorator \"%s\" requested", format) 49 } 50 51 return o, nil 52} 53 54// Stdout returns io.Writer that can be used for Job's STDOUT 55func (o *TaskOutput) Stdout() io.Writer { 56 return io.MultiWriter(o.decorator, &o.t.Log.Stdout) 57} 58 59// Stderr returns io.Writer that can be used for Job's STDERR 60func (o *TaskOutput) Stderr() io.Writer { 61 return io.MultiWriter(o.decorator, &o.t.Log.Stderr) 62} 63 64// Start should be called before task's output starts 65func (o TaskOutput) Start() error { 66 return o.decorator.WriteHeader() 67} 68 69// Finish should be called after task completes 70func (o TaskOutput) Finish() error { 71 return o.decorator.WriteFooter() 72} 73 74// Close releases resources and closes underlying decorators 75func Close() { 76 if !closed { 77 closed = true 78 close(closeCh) 79 } 80} 81