prefixed.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package output
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "strings"
  7. "github.com/go-task/task/v3/internal/logger"
  8. "github.com/go-task/task/v3/internal/templater"
  9. )
  10. type Prefixed struct {
  11. logger *logger.Logger
  12. seen map[string]uint
  13. counter *uint
  14. }
  15. func NewPrefixed(logger *logger.Logger) Prefixed {
  16. var counter uint
  17. return Prefixed{
  18. seen: make(map[string]uint),
  19. counter: &counter,
  20. logger: logger,
  21. }
  22. }
  23. func (p Prefixed) WrapWriter(stdOut, _ io.Writer, prefix string, _ *templater.Cache) (io.Writer, io.Writer, CloseFunc) {
  24. pw := &prefixWriter{writer: stdOut, prefix: prefix, prefixed: &p}
  25. return pw, pw, func(error) error { return pw.close() }
  26. }
  27. type prefixWriter struct {
  28. writer io.Writer
  29. prefixed *Prefixed
  30. prefix string
  31. buff bytes.Buffer
  32. }
  33. func (pw *prefixWriter) Write(p []byte) (int, error) {
  34. n, err := pw.buff.Write(p)
  35. if err != nil {
  36. return n, err
  37. }
  38. return n, pw.writeOutputLines(false)
  39. }
  40. func (pw *prefixWriter) close() error {
  41. return pw.writeOutputLines(true)
  42. }
  43. func (pw *prefixWriter) writeOutputLines(force bool) error {
  44. for {
  45. switch line, err := pw.buff.ReadString('\n'); err {
  46. case nil:
  47. if err = pw.writeLine(line); err != nil {
  48. return err
  49. }
  50. case io.EOF:
  51. // if this line was not a complete line, re-add to the buffer
  52. if !force && !strings.HasSuffix(line, "\n") {
  53. _, err = pw.buff.WriteString(line)
  54. return err
  55. }
  56. return pw.writeLine(line)
  57. default:
  58. return err
  59. }
  60. }
  61. }
  62. var PrefixColorSequence = []logger.Color{
  63. logger.Yellow, logger.Blue, logger.Magenta, logger.Cyan, logger.Green, logger.Red,
  64. logger.BrightYellow, logger.BrightBlue, logger.BrightMagenta, logger.BrightCyan, logger.BrightGreen, logger.BrightRed,
  65. }
  66. func (pw *prefixWriter) writeLine(line string) error {
  67. if line == "" {
  68. return nil
  69. }
  70. if !strings.HasSuffix(line, "\n") {
  71. line += "\n"
  72. }
  73. idx, ok := pw.prefixed.seen[pw.prefix]
  74. if !ok {
  75. idx = *pw.prefixed.counter
  76. pw.prefixed.seen[pw.prefix] = idx
  77. *pw.prefixed.counter++
  78. }
  79. if _, err := fmt.Fprint(pw.writer, "["); err != nil {
  80. return nil
  81. }
  82. color := PrefixColorSequence[idx%uint(len(PrefixColorSequence))]
  83. pw.prefixed.logger.FOutf(pw.writer, color, pw.prefix)
  84. if _, err := fmt.Fprint(pw.writer, "] "); err != nil {
  85. return nil
  86. }
  87. _, err := fmt.Fprint(pw.writer, line)
  88. return err
  89. }