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