You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

graph_models.go 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package gitgraph
  5. import (
  6. "bytes"
  7. "fmt"
  8. )
  9. // NewGraph creates a basic graph
  10. func NewGraph() *Graph {
  11. graph := &Graph{}
  12. graph.relationCommit = &Commit{
  13. Row: -1,
  14. Column: -1,
  15. }
  16. graph.Flows = map[int64]*Flow{}
  17. return graph
  18. }
  19. // Graph represents a collection of flows
  20. type Graph struct {
  21. Flows map[int64]*Flow
  22. Commits []*Commit
  23. MinRow int
  24. MinColumn int
  25. MaxRow int
  26. MaxColumn int
  27. relationCommit *Commit
  28. }
  29. // Width returns the width of the graph
  30. func (graph *Graph) Width() int {
  31. return graph.MaxColumn - graph.MinColumn + 1
  32. }
  33. // Height returns the height of the graph
  34. func (graph *Graph) Height() int {
  35. return graph.MaxRow - graph.MinRow + 1
  36. }
  37. // AddGlyph adds glyph to flows
  38. func (graph *Graph) AddGlyph(row, column int, flowID int64, color int, glyph byte) {
  39. flow, ok := graph.Flows[flowID]
  40. if !ok {
  41. flow = NewFlow(flowID, color, row, column)
  42. graph.Flows[flowID] = flow
  43. }
  44. flow.AddGlyph(row, column, glyph)
  45. if row < graph.MinRow {
  46. graph.MinRow = row
  47. }
  48. if row > graph.MaxRow {
  49. graph.MaxRow = row
  50. }
  51. if column < graph.MinColumn {
  52. graph.MinColumn = column
  53. }
  54. if column > graph.MaxColumn {
  55. graph.MaxColumn = column
  56. }
  57. }
  58. // AddCommit adds a commit at row, column on flowID with the provided data
  59. func (graph *Graph) AddCommit(row, column int, flowID int64, data []byte) error {
  60. commit, err := NewCommit(row, column, data)
  61. if err != nil {
  62. return err
  63. }
  64. commit.Flow = flowID
  65. graph.Commits = append(graph.Commits, commit)
  66. graph.Flows[flowID].Commits = append(graph.Flows[flowID].Commits, commit)
  67. return nil
  68. }
  69. // NewFlow creates a new flow
  70. func NewFlow(flowID int64, color, row, column int) *Flow {
  71. return &Flow{
  72. ID: flowID,
  73. ColorNumber: color,
  74. MinRow: row,
  75. MinColumn: column,
  76. MaxRow: row,
  77. MaxColumn: column,
  78. }
  79. }
  80. // Flow represents a series of glyphs
  81. type Flow struct {
  82. ID int64
  83. ColorNumber int
  84. Glyphs []Glyph
  85. Commits []*Commit
  86. MinRow int
  87. MinColumn int
  88. MaxRow int
  89. MaxColumn int
  90. }
  91. // Color16 wraps the color numbers around mod 16
  92. func (flow *Flow) Color16() int {
  93. return flow.ColorNumber % 16
  94. }
  95. // AddGlyph adds glyph at row and column
  96. func (flow *Flow) AddGlyph(row, column int, glyph byte) {
  97. if row < flow.MinRow {
  98. flow.MinRow = row
  99. }
  100. if row > flow.MaxRow {
  101. flow.MaxRow = row
  102. }
  103. if column < flow.MinColumn {
  104. flow.MinColumn = column
  105. }
  106. if column > flow.MaxColumn {
  107. flow.MaxColumn = column
  108. }
  109. flow.Glyphs = append(flow.Glyphs, Glyph{
  110. row,
  111. column,
  112. glyph,
  113. })
  114. }
  115. // Glyph represents a co-ordinate and glyph
  116. type Glyph struct {
  117. Row int
  118. Column int
  119. Glyph byte
  120. }
  121. // RelationCommit represents an empty relation commit
  122. var RelationCommit = &Commit{
  123. Row: -1,
  124. }
  125. // NewCommit creates a new commit from a provided line
  126. func NewCommit(row, column int, line []byte) (*Commit, error) {
  127. data := bytes.SplitN(line, []byte("|"), 7)
  128. if len(data) < 7 {
  129. return nil, fmt.Errorf("malformed data section on line %d with commit: %s", row, string(line))
  130. }
  131. return &Commit{
  132. Row: row,
  133. Column: column,
  134. // 0 matches git log --pretty=format:%d => ref names, like the --decorate option of git-log(1)
  135. Branch: string(data[0]),
  136. // 1 matches git log --pretty=format:%H => commit hash
  137. Rev: string(data[1]),
  138. // 2 matches git log --pretty=format:%ad => author date (format respects --date= option)
  139. Date: string(data[2]),
  140. // 3 matches git log --pretty=format:%an => author name
  141. Author: string(data[3]),
  142. // 4 matches git log --pretty=format:%ae => author email
  143. AuthorEmail: string(data[4]),
  144. // 5 matches git log --pretty=format:%h => abbreviated commit hash
  145. ShortRev: string(data[5]),
  146. // 6 matches git log --pretty=format:%s => subject
  147. Subject: string(data[6]),
  148. }, nil
  149. }
  150. // Commit represents a commit at co-ordinate X, Y with the data
  151. type Commit struct {
  152. Flow int64
  153. Row int
  154. Column int
  155. Branch string
  156. Rev string
  157. Date string
  158. Author string
  159. AuthorEmail string
  160. ShortRev string
  161. Subject string
  162. }
  163. // OnlyRelation returns whether this a relation only commit
  164. func (c *Commit) OnlyRelation() bool {
  165. return c.Row == -1
  166. }