gitech

Форк
0
165 строк · 3.8 Кб
1
// Copyright 2020 The Gitea Authors. All rights reserved.
2
// SPDX-License-Identifier: MIT
3

4
//go:build gogit
5

6
package pipeline
7

8
import (
9
	"bufio"
10
	"fmt"
11
	"io"
12
	"sort"
13
	"strings"
14
	"sync"
15
	"time"
16

17
	"code.gitea.io/gitea/modules/git"
18

19
	gogit "github.com/go-git/go-git/v5"
20
	"github.com/go-git/go-git/v5/plumbing"
21
	"github.com/go-git/go-git/v5/plumbing/object"
22
)
23

24
// LFSResult represents commits found using a provided pointer file hash
25
type LFSResult struct {
26
	Name           string
27
	SHA            string
28
	Summary        string
29
	When           time.Time
30
	ParentHashes   []git.ObjectID
31
	BranchName     string
32
	FullCommitName string
33
}
34

35
type lfsResultSlice []*LFSResult
36

37
func (a lfsResultSlice) Len() int           { return len(a) }
38
func (a lfsResultSlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
39
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
40

41
// FindLFSFile finds commits that contain a provided pointer file hash
42
func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) {
43
	resultsMap := map[string]*LFSResult{}
44
	results := make([]*LFSResult, 0)
45

46
	basePath := repo.Path
47
	gogitRepo := repo.GoGitRepo()
48

49
	commitsIter, err := gogitRepo.Log(&gogit.LogOptions{
50
		Order: gogit.LogOrderCommitterTime,
51
		All:   true,
52
	})
53
	if err != nil {
54
		return nil, fmt.Errorf("Failed to get GoGit CommitsIter. Error: %w", err)
55
	}
56

57
	err = commitsIter.ForEach(func(gitCommit *object.Commit) error {
58
		tree, err := gitCommit.Tree()
59
		if err != nil {
60
			return err
61
		}
62
		treeWalker := object.NewTreeWalker(tree, true, nil)
63
		defer treeWalker.Close()
64
		for {
65
			name, entry, err := treeWalker.Next()
66
			if err == io.EOF {
67
				break
68
			}
69
			if entry.Hash == plumbing.Hash(objectID.RawValue()) {
70
				parents := make([]git.ObjectID, len(gitCommit.ParentHashes))
71
				for i, parentCommitID := range gitCommit.ParentHashes {
72
					parents[i] = git.ParseGogitHash(parentCommitID)
73
				}
74

75
				result := LFSResult{
76
					Name:         name,
77
					SHA:          gitCommit.Hash.String(),
78
					Summary:      strings.Split(strings.TrimSpace(gitCommit.Message), "\n")[0],
79
					When:         gitCommit.Author.When,
80
					ParentHashes: parents,
81
				}
82
				resultsMap[gitCommit.Hash.String()+":"+name] = &result
83
			}
84
		}
85
		return nil
86
	})
87
	if err != nil && err != io.EOF {
88
		return nil, fmt.Errorf("Failure in CommitIter.ForEach: %w", err)
89
	}
90

91
	for _, result := range resultsMap {
92
		hasParent := false
93
		for _, parentHash := range result.ParentHashes {
94
			if _, hasParent = resultsMap[parentHash.String()+":"+result.Name]; hasParent {
95
				break
96
			}
97
		}
98
		if !hasParent {
99
			results = append(results, result)
100
		}
101
	}
102

103
	sort.Sort(lfsResultSlice(results))
104

105
	// Should really use a go-git function here but name-rev is not completed and recapitulating it is not simple
106
	shasToNameReader, shasToNameWriter := io.Pipe()
107
	nameRevStdinReader, nameRevStdinWriter := io.Pipe()
108
	errChan := make(chan error, 1)
109
	wg := sync.WaitGroup{}
110
	wg.Add(3)
111

112
	go func() {
113
		defer wg.Done()
114
		scanner := bufio.NewScanner(nameRevStdinReader)
115
		i := 0
116
		for scanner.Scan() {
117
			line := scanner.Text()
118
			if len(line) == 0 {
119
				continue
120
			}
121
			result := results[i]
122
			result.FullCommitName = line
123
			result.BranchName = strings.Split(line, "~")[0]
124
			i++
125
		}
126
	}()
127
	go NameRevStdin(repo.Ctx, shasToNameReader, nameRevStdinWriter, &wg, basePath)
128
	go func() {
129
		defer wg.Done()
130
		defer shasToNameWriter.Close()
131
		for _, result := range results {
132
			i := 0
133
			if i < len(result.SHA) {
134
				n, err := shasToNameWriter.Write([]byte(result.SHA)[i:])
135
				if err != nil {
136
					errChan <- err
137
					break
138
				}
139
				i += n
140
			}
141
			n := 0
142
			for n < 1 {
143
				n, err = shasToNameWriter.Write([]byte{'\n'})
144
				if err != nil {
145
					errChan <- err
146
					break
147
				}
148

149
			}
150

151
		}
152
	}()
153

154
	wg.Wait()
155

156
	select {
157
	case err, has := <-errChan:
158
		if has {
159
			return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err)
160
		}
161
	default:
162
	}
163

164
	return results, nil
165
}
166

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.