kati.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright 2018 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package status
  15. import (
  16. "bufio"
  17. "fmt"
  18. "io"
  19. "regexp"
  20. "strconv"
  21. "strings"
  22. )
  23. var katiError = regexp.MustCompile(`^(\033\[1m)?[^ ]+:[0-9]+: (\033\[31m)?error:`)
  24. var katiIncludeRe = regexp.MustCompile(`^(\[(\d+)/(\d+)] )?((including [^ ]+|initializing (legacy Make module parser|packaging system)|finishing (legacy Make module parsing|packaging rules)|writing (legacy Make module|packaging) rules) ...)$`)
  25. var katiLogRe = regexp.MustCompile(`^\*kati\*: `)
  26. var katiNinjaMissing = regexp.MustCompile("^[^ ]+ is missing, regenerating...$")
  27. type katiOutputParser struct {
  28. st ToolStatus
  29. count int
  30. total int
  31. extra int
  32. action *Action
  33. buf strings.Builder
  34. hasError bool
  35. }
  36. func (k *katiOutputParser) flushAction() {
  37. if k.action == nil {
  38. return
  39. }
  40. var err error
  41. if k.hasError {
  42. err = fmt.Errorf("makefile error")
  43. }
  44. k.st.FinishAction(ActionResult{
  45. Action: k.action,
  46. Output: k.buf.String(),
  47. Error: err,
  48. })
  49. k.buf.Reset()
  50. k.hasError = false
  51. }
  52. func (k *katiOutputParser) parseLine(line string) {
  53. // Only put kati debug/stat lines in our verbose log
  54. if katiLogRe.MatchString(line) {
  55. k.st.Verbose(line)
  56. return
  57. }
  58. if matches := katiIncludeRe.FindStringSubmatch(line); len(matches) > 0 {
  59. k.flushAction()
  60. k.count += 1
  61. matches := katiIncludeRe.FindStringSubmatch(line)
  62. if matches[2] != "" {
  63. idx, err := strconv.Atoi(matches[2])
  64. if err == nil && idx+k.extra != k.count {
  65. k.extra = k.count - idx
  66. k.st.SetTotalActions(k.total + k.extra)
  67. }
  68. } else {
  69. k.extra += 1
  70. k.st.SetTotalActions(k.total + k.extra)
  71. }
  72. if matches[3] != "" {
  73. tot, err := strconv.Atoi(matches[3])
  74. if err == nil && tot != k.total {
  75. k.total = tot
  76. k.st.SetTotalActions(k.total + k.extra)
  77. }
  78. }
  79. k.action = &Action{
  80. Description: matches[4],
  81. }
  82. k.st.StartAction(k.action)
  83. } else if k.action != nil {
  84. if katiError.MatchString(line) {
  85. k.hasError = true
  86. }
  87. k.buf.WriteString(line)
  88. k.buf.WriteString("\n")
  89. } else {
  90. // Before we've started executing actions from Kati
  91. if line == "No need to regenerate ninja file" || katiNinjaMissing.MatchString(line) {
  92. k.st.Status(line)
  93. } else {
  94. k.st.Print(line)
  95. }
  96. }
  97. }
  98. // KatiReader reads the output from Kati, and turns it into Actions and
  99. // messages that are passed into the ToolStatus API.
  100. func KatiReader(st ToolStatus, pipe io.ReadCloser) {
  101. parser := &katiOutputParser{
  102. st: st,
  103. }
  104. scanner := bufio.NewScanner(pipe)
  105. scanner.Buffer(nil, 2*1024*1024)
  106. for scanner.Scan() {
  107. parser.parseLine(scanner.Text())
  108. }
  109. parser.flushAction()
  110. if err := scanner.Err(); err != nil {
  111. var buf strings.Builder
  112. io.Copy(&buf, pipe)
  113. st.Print(fmt.Sprintf("Error from kati parser: %s", err))
  114. st.Print(buf.String())
  115. }
  116. st.Finish()
  117. }