gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // Copyright 2016 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package gitgraph
  4. import (
  5. "bufio"
  6. "bytes"
  7. "context"
  8. "os"
  9. "strings"
  10. "code.gitea.io/gitea/modules/git"
  11. "code.gitea.io/gitea/modules/git/gitcmd"
  12. "code.gitea.io/gitea/modules/setting"
  13. )
  14. // GetCommitGraph return a list of commit (GraphItems) from all branches
  15. func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bool, branches, files []string) (*Graph, error) {
  16. format := "DATA:%D|%H|%ad|%h|%s"
  17. if page == 0 {
  18. page = 1
  19. }
  20. graphCmd := gitcmd.NewCommand("log", "--graph", "--date-order", "--decorate=full")
  21. if hidePRRefs {
  22. graphCmd.AddArguments("--exclude=" + git.PullPrefix + "*")
  23. }
  24. if len(branches) == 0 {
  25. graphCmd.AddArguments("--tags", "--branches")
  26. }
  27. graphCmd.AddArguments("-C", "-M", "--date=iso-strict").
  28. AddOptionFormat("-n %d", setting.UI.GraphMaxCommitNum*page).
  29. AddOptionFormat("--pretty=format:%s", format)
  30. if len(branches) > 0 {
  31. graphCmd.AddDynamicArguments(branches...)
  32. }
  33. if len(files) > 0 {
  34. graphCmd.AddDashesAndList(files...)
  35. }
  36. graph := NewGraph()
  37. stderr := new(strings.Builder)
  38. stdoutReader, stdoutWriter, err := os.Pipe()
  39. if err != nil {
  40. return nil, err
  41. }
  42. commitsToSkip := setting.UI.GraphMaxCommitNum * (page - 1)
  43. scanner := bufio.NewScanner(stdoutReader)
  44. if err := graphCmd.Run(r.Ctx, &gitcmd.RunOpts{
  45. Dir: r.Path,
  46. Stdout: stdoutWriter,
  47. Stderr: stderr,
  48. PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
  49. _ = stdoutWriter.Close()
  50. defer stdoutReader.Close()
  51. parser := &Parser{}
  52. parser.firstInUse = -1
  53. parser.maxAllowedColors = maxAllowedColors
  54. if maxAllowedColors > 0 {
  55. parser.availableColors = make([]int, maxAllowedColors)
  56. for i := range parser.availableColors {
  57. parser.availableColors[i] = i + 1
  58. }
  59. } else {
  60. parser.availableColors = []int{1, 2}
  61. }
  62. for commitsToSkip > 0 && scanner.Scan() {
  63. line := scanner.Bytes()
  64. dataIdx := bytes.Index(line, []byte("DATA:"))
  65. if dataIdx < 0 {
  66. dataIdx = len(line)
  67. }
  68. starIdx := bytes.IndexByte(line, '*')
  69. if starIdx >= 0 && starIdx < dataIdx {
  70. commitsToSkip--
  71. }
  72. parser.ParseGlyphs(line[:dataIdx])
  73. }
  74. row := 0
  75. // Skip initial non-commit lines
  76. for scanner.Scan() {
  77. line := scanner.Bytes()
  78. if bytes.IndexByte(line, '*') >= 0 {
  79. if err := parser.AddLineToGraph(graph, row, line); err != nil {
  80. cancel()
  81. return err
  82. }
  83. break
  84. }
  85. parser.ParseGlyphs(line)
  86. }
  87. for scanner.Scan() {
  88. row++
  89. line := scanner.Bytes()
  90. if err := parser.AddLineToGraph(graph, row, line); err != nil {
  91. cancel()
  92. return err
  93. }
  94. }
  95. return scanner.Err()
  96. },
  97. }); err != nil {
  98. return graph, err
  99. }
  100. return graph, nil
  101. }