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