gitea源码

lfs_gogit.go 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. //go:build gogit
  4. package pipeline
  5. import (
  6. "bufio"
  7. "io"
  8. "sort"
  9. "strings"
  10. "sync"
  11. "code.gitea.io/gitea/modules/git"
  12. gogit "github.com/go-git/go-git/v5"
  13. "github.com/go-git/go-git/v5/plumbing"
  14. "github.com/go-git/go-git/v5/plumbing/object"
  15. )
  16. // FindLFSFile finds commits that contain a provided pointer file hash
  17. func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) {
  18. resultsMap := map[string]*LFSResult{}
  19. results := make([]*LFSResult, 0)
  20. basePath := repo.Path
  21. gogitRepo := repo.GoGitRepo()
  22. commitsIter, err := gogitRepo.Log(&gogit.LogOptions{
  23. Order: gogit.LogOrderCommitterTime,
  24. All: true,
  25. })
  26. if err != nil {
  27. return nil, lfsError("failed to get GoGit CommitsIter", err)
  28. }
  29. err = commitsIter.ForEach(func(gitCommit *object.Commit) error {
  30. tree, err := gitCommit.Tree()
  31. if err != nil {
  32. return err
  33. }
  34. treeWalker := object.NewTreeWalker(tree, true, nil)
  35. defer treeWalker.Close()
  36. for {
  37. name, entry, err := treeWalker.Next()
  38. if err == io.EOF {
  39. break
  40. }
  41. if entry.Hash == plumbing.Hash(objectID.RawValue()) {
  42. parents := make([]git.ObjectID, len(gitCommit.ParentHashes))
  43. for i, parentCommitID := range gitCommit.ParentHashes {
  44. parents[i] = git.ParseGogitHash(parentCommitID)
  45. }
  46. result := LFSResult{
  47. Name: name,
  48. SHA: gitCommit.Hash.String(),
  49. Summary: strings.Split(strings.TrimSpace(gitCommit.Message), "\n")[0],
  50. When: gitCommit.Author.When,
  51. ParentHashes: parents,
  52. }
  53. resultsMap[gitCommit.Hash.String()+":"+name] = &result
  54. }
  55. }
  56. return nil
  57. })
  58. if err != nil && err != io.EOF {
  59. return nil, lfsError("failure in CommitIter.ForEach", err)
  60. }
  61. for _, result := range resultsMap {
  62. hasParent := false
  63. for _, parentHash := range result.ParentHashes {
  64. if _, hasParent = resultsMap[parentHash.String()+":"+result.Name]; hasParent {
  65. break
  66. }
  67. }
  68. if !hasParent {
  69. results = append(results, result)
  70. }
  71. }
  72. sort.Sort(lfsResultSlice(results))
  73. // Should really use a go-git function here but name-rev is not completed and recapitulating it is not simple
  74. shasToNameReader, shasToNameWriter := io.Pipe()
  75. nameRevStdinReader, nameRevStdinWriter := io.Pipe()
  76. errChan := make(chan error, 1)
  77. wg := sync.WaitGroup{}
  78. wg.Add(3)
  79. go func() {
  80. defer wg.Done()
  81. scanner := bufio.NewScanner(nameRevStdinReader)
  82. i := 0
  83. for scanner.Scan() {
  84. line := scanner.Text()
  85. if len(line) == 0 {
  86. continue
  87. }
  88. result := results[i]
  89. result.FullCommitName = line
  90. result.BranchName = strings.Split(line, "~")[0]
  91. i++
  92. }
  93. }()
  94. go NameRevStdin(repo.Ctx, shasToNameReader, nameRevStdinWriter, &wg, basePath)
  95. go func() {
  96. defer wg.Done()
  97. defer shasToNameWriter.Close()
  98. for _, result := range results {
  99. i := 0
  100. if i < len(result.SHA) {
  101. n, err := shasToNameWriter.Write([]byte(result.SHA)[i:])
  102. if err != nil {
  103. errChan <- err
  104. break
  105. }
  106. i += n
  107. }
  108. n := 0
  109. for n < 1 {
  110. n, err = shasToNameWriter.Write([]byte{'\n'})
  111. if err != nil {
  112. errChan <- err
  113. break
  114. }
  115. }
  116. }
  117. }()
  118. wg.Wait()
  119. select {
  120. case err, has := <-errChan:
  121. if has {
  122. return nil, lfsError("unable to obtain name for LFS files", err)
  123. }
  124. default:
  125. }
  126. return results, nil
  127. }