buildr/internal/logging/task_output.go
Peter 1261932bdc
All checks were successful
continuous-integration/drone/push Build is passing
refactor: apply golangci-lint findings
2023-06-22 19:16:00 +02:00

103 lines
2.1 KiB
Go

package logging
import (
"errors"
"io"
"os"
"path/filepath"
"code.icb4dc0.de/buildr/buildr/internal/ioutils"
)
type OutputSource string
const (
OutputSourceStdout OutputSource = "stdout"
OutputSourceStderr OutputSource = "stderr"
)
type LogFileNameFormatter interface {
LogFileName(src OutputSource) string
}
type LogFileNameFormatterFunc func(src OutputSource) string
func (f LogFileNameFormatterFunc) LogFileName(src OutputSource) string {
return f(src)
}
func NewTaskOutputSink(logsDirectory string, logToStdErr bool, formatter LogFileNameFormatter) (sink TaskOutputSink, err error) {
fileSink := fileOutputSink{
logToStdErr: logToStdErr,
}
if logToStdErr {
if fileSink.stdOut, err = os.CreateTemp(os.TempDir(), "buildr-*.stdout.log"); err != nil {
return nil, err
}
if fileSink.stdErr, err = os.CreateTemp(os.TempDir(), "buildr-*.stderr.log"); err != nil {
return nil, err
}
} else {
if fileSink.stdOut, err = os.Create(filepath.Join(logsDirectory, formatter.LogFileName(OutputSourceStdout))); err != nil {
return nil, err
}
if fileSink.stdErr, err = os.Create(filepath.Join(logsDirectory, formatter.LogFileName(OutputSourceStderr))); err != nil {
return nil, err
}
}
return fileSink, nil
}
var _ TaskOutputSink = (*fileOutputSink)(nil)
type file interface {
Name() string
io.ReadWriter
io.Seeker
io.Closer
}
type fileOutputSink struct {
stdOut file
stdErr file
logToStdErr bool
}
func (f fileOutputSink) StdOut() io.Writer {
return f.stdOut
}
func (f fileOutputSink) StdErr() io.Writer {
return f.stdErr
}
func (f fileOutputSink) Close() error {
if f.logToStdErr {
return errors.Join(
f.copyToStdErrAndClose(f.stdOut),
f.copyToStdErrAndClose(f.stdErr),
)
}
return errors.Join(
f.stdOut.Close(),
f.stdErr.Close(),
)
}
func (f fileOutputSink) copyToStdErrAndClose(src file) error {
return AcquireStdErr(func(stdErr io.Writer) error {
if _, err := src.Seek(0, 0); err != nil {
return err
}
if _, err := ioutils.CopyWithPooledBuffer(stdErr, src); err != nil {
return err
}
return errors.Join(src.Close(), os.Remove(src.Name()))
})
}