// Copyright 2016 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package gitgraph import ( "bufio" "bytes" "context" "fmt" "os" "strings" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" ) // GetCommitGraph return a list of commit (GraphItems) from all branches func GetCommitGraph(r *git.Repository, page int, maxAllowedColors int, hidePRRefs bool, branches, files []string) (*Graph, error) { format := "DATA:%D|%H|%ad|%h|%s" if page == 0 { page = 1 } args := make([]string, 0, 12+len(branches)+len(files)) args = append(args, "--graph", "--date-order", "--decorate=full") if hidePRRefs { args = append(args, "--exclude=refs/pull/*") } if len(branches) == 0 { args = append(args, "--all") } args = append(args, "-C", "-M", fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page), "--date=iso", fmt.Sprintf("--pretty=format:%s", format)) if len(branches) > 0 { args = append(args, branches...) } args = append(args, "--") if len(files) > 0 { args = append(args, files...) } graphCmd := git.NewCommand("log") graphCmd.AddArguments(args...) graph := NewGraph() stderr := new(strings.Builder) stdoutReader, stdoutWriter, err := os.Pipe() if err != nil { return nil, err } commitsToSkip := setting.UI.GraphMaxCommitNum * (page - 1) scanner := bufio.NewScanner(stdoutReader) if err := graphCmd.RunInDirTimeoutEnvFullPipelineFunc(nil, -1, r.Path, stdoutWriter, stderr, nil, func(ctx context.Context, cancel context.CancelFunc) error { _ = stdoutWriter.Close() defer stdoutReader.Close() parser := &Parser{} parser.firstInUse = -1 parser.maxAllowedColors = maxAllowedColors if maxAllowedColors > 0 { parser.availableColors = make([]int, maxAllowedColors) for i := range parser.availableColors { parser.availableColors[i] = i + 1 } } else { parser.availableColors = []int{1, 2} } for commitsToSkip > 0 && scanner.Scan() { line := scanner.Bytes() dataIdx := bytes.Index(line, []byte("DATA:")) if dataIdx < 0 { dataIdx = len(line) } starIdx := bytes.IndexByte(line, '*') if starIdx >= 0 && starIdx < dataIdx { commitsToSkip-- } parser.ParseGlyphs(line[:dataIdx]) } row := 0 // Skip initial non-commit lines for scanner.Scan() { line := scanner.Bytes() if bytes.IndexByte(line, '*') >= 0 { if err := parser.AddLineToGraph(graph, row, line); err != nil { cancel() return err } break } parser.ParseGlyphs(line) } for scanner.Scan() { row++ line := scanner.Bytes() if err := parser.AddLineToGraph(graph, row, line); err != nil { cancel() return err } } return scanner.Err() }); err != nil { return graph, err } return graph, nil }