sourcereader.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package sentry
  2. import (
  3. "bytes"
  4. "io/ioutil"
  5. "sync"
  6. )
  7. type sourceReader struct {
  8. mu sync.Mutex
  9. cache map[string][][]byte
  10. }
  11. func newSourceReader() sourceReader {
  12. return sourceReader{
  13. cache: make(map[string][][]byte),
  14. }
  15. }
  16. func (sr *sourceReader) readContextLines(filename string, line, context int) ([][]byte, int) {
  17. sr.mu.Lock()
  18. defer sr.mu.Unlock()
  19. lines, ok := sr.cache[filename]
  20. if !ok {
  21. data, err := ioutil.ReadFile(filename)
  22. if err != nil {
  23. sr.cache[filename] = nil
  24. return nil, 0
  25. }
  26. lines = bytes.Split(data, []byte{'\n'})
  27. sr.cache[filename] = lines
  28. }
  29. return sr.calculateContextLines(lines, line, context)
  30. }
  31. // `contextLine` points to a line that caused an issue itself, in relation to returned slice
  32. func (sr *sourceReader) calculateContextLines(lines [][]byte, line, context int) ([][]byte, int) {
  33. // Stacktrace lines are 1-indexed, slices are 0-indexed
  34. line--
  35. contextLine := context
  36. if lines == nil || line >= len(lines) || line < 0 {
  37. return nil, 0
  38. }
  39. if context < 0 {
  40. context = 0
  41. contextLine = 0
  42. }
  43. start := line - context
  44. if start < 0 {
  45. contextLine += start
  46. start = 0
  47. }
  48. end := line + context + 1
  49. if end > len(lines) {
  50. end = len(lines)
  51. }
  52. return lines[start:end], contextLine
  53. }