mirror of
https://github.com/openshift/installer.git
synced 2026-02-05 15:47:14 +01:00
84 lines
2.3 KiB
Go
84 lines
2.3 KiB
Go
// Package lineprinter wraps a Print implementation to provide an io.WriteCloser.
|
|
package lineprinter
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"sync"
|
|
)
|
|
|
|
// Print is a type that can hold fmt.Print and other implementations
|
|
// which match that signature. For example, you can use:
|
|
//
|
|
// trimmer := &lineprinter.Trimmer{WrappedPrint: logrus.StandardLogger().Debug}
|
|
// linePrinter := &linePrinter{Print: trimmer.Print}
|
|
//
|
|
// to connect the line printer to logrus at the debug level.
|
|
type Print func(args ...interface{})
|
|
|
|
// LinePrinter is an io.WriteCloser that buffers written bytes.
|
|
// During each Write, newline-terminated lines are removed from the
|
|
// buffer and passed to Print. On Close, any content remaining in the
|
|
// buffer is also passed to Print.
|
|
//
|
|
// One use-case is connecting a subprocess's standard streams to a
|
|
// logger:
|
|
//
|
|
// linePrinter := &linePrinter{
|
|
// Print: &Trimmer{WrappedPrint: logrus.StandardLogger().Debug}.Print,
|
|
// }
|
|
// defer linePrinter.Close()
|
|
// cmd := exec.Command(...)
|
|
// cmd.Stdout = linePrinter
|
|
//
|
|
// LinePrinter buffers the subcommand's byte stream and splits it into
|
|
// lines for the logger. Sometimes we might have a partial line
|
|
// written to the buffer. We don't want to push that partial line into
|
|
// the logs if the next read attempt will pull in the remainder of the
|
|
// line. But we do want to push that partial line into the logs if there
|
|
// will never be a next read. So LinePrinter.Write pushes any
|
|
// complete lines to the wrapped printer, and LinePrinter.Close pushes
|
|
// any remaining partial line.
|
|
type LinePrinter struct {
|
|
buf bytes.Buffer
|
|
Print Print
|
|
|
|
sync.Mutex
|
|
}
|
|
|
|
// Write writes len(p) bytes from p to an internal buffer. Then it
|
|
// retrieves any newline-terminated lines from the internal buffer and
|
|
// prints them with lp.Print. Partial lines are left in the internal
|
|
// buffer.
|
|
func (lp *LinePrinter) Write(p []byte) (int, error) {
|
|
lp.Lock()
|
|
defer lp.Unlock()
|
|
n, err := lp.buf.Write(p)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
|
|
for {
|
|
line, err := lp.buf.ReadString(byte('\n'))
|
|
if err == io.EOF {
|
|
_, err = lp.buf.Write([]byte(line))
|
|
return n, err
|
|
} else if err != nil {
|
|
return n, err
|
|
}
|
|
|
|
lp.Print(line)
|
|
}
|
|
}
|
|
|
|
// Close prints anything that remains in the buffer.
|
|
func (lp *LinePrinter) Close() error {
|
|
lp.Lock()
|
|
defer lp.Unlock()
|
|
line := lp.buf.String()
|
|
if len(line) > 0 {
|
|
lp.Print(line)
|
|
}
|
|
return nil
|
|
}
|