gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package git
  4. import (
  5. "bufio"
  6. "bytes"
  7. "fmt"
  8. "io"
  9. )
  10. const (
  11. commitHeaderGpgsig = "gpgsig"
  12. commitHeaderGpgsigSha256 = "gpgsig-sha256"
  13. )
  14. func assignCommitFields(gitRepo *Repository, commit *Commit, headerKey string, headerValue []byte) error {
  15. if len(headerValue) > 0 && headerValue[len(headerValue)-1] == '\n' {
  16. headerValue = headerValue[:len(headerValue)-1] // remove trailing newline
  17. }
  18. switch headerKey {
  19. case "tree":
  20. objID, err := NewIDFromString(string(headerValue))
  21. if err != nil {
  22. return fmt.Errorf("invalid tree ID %q: %w", string(headerValue), err)
  23. }
  24. commit.Tree = *NewTree(gitRepo, objID)
  25. case "parent":
  26. objID, err := NewIDFromString(string(headerValue))
  27. if err != nil {
  28. return fmt.Errorf("invalid parent ID %q: %w", string(headerValue), err)
  29. }
  30. commit.Parents = append(commit.Parents, objID)
  31. case "author":
  32. commit.Author.Decode(headerValue)
  33. case "committer":
  34. commit.Committer.Decode(headerValue)
  35. case commitHeaderGpgsig, commitHeaderGpgsigSha256:
  36. // if there are duplicate "gpgsig" and "gpgsig-sha256" headers, then the signature must have already been invalid
  37. // so we don't need to handle duplicate headers here
  38. commit.Signature = &CommitSignature{Signature: string(headerValue)}
  39. }
  40. return nil
  41. }
  42. // CommitFromReader will generate a Commit from a provided reader
  43. // We need this to interpret commits from cat-file or cat-file --batch
  44. //
  45. // If used as part of a cat-file --batch stream you need to limit the reader to the correct size
  46. func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader) (*Commit, error) {
  47. commit := &Commit{
  48. ID: objectID,
  49. Author: &Signature{},
  50. Committer: &Signature{},
  51. }
  52. bufReader := bufio.NewReader(reader)
  53. inHeader := true
  54. var payloadSB, messageSB bytes.Buffer
  55. var headerKey string
  56. var headerValue []byte
  57. for {
  58. line, err := bufReader.ReadBytes('\n')
  59. if err != nil && err != io.EOF {
  60. return nil, fmt.Errorf("unable to read commit %q: %w", objectID.String(), err)
  61. }
  62. if len(line) == 0 {
  63. break
  64. }
  65. if inHeader {
  66. inHeader = !(len(line) == 1 && line[0] == '\n') // still in header if line is not just a newline
  67. k, v, _ := bytes.Cut(line, []byte{' '})
  68. if len(k) != 0 || !inHeader {
  69. if headerKey != "" {
  70. if err = assignCommitFields(gitRepo, commit, headerKey, headerValue); err != nil {
  71. return nil, fmt.Errorf("unable to parse commit %q: %w", objectID.String(), err)
  72. }
  73. }
  74. headerKey = string(k) // it also resets the headerValue to empty string if not inHeader
  75. headerValue = v
  76. } else {
  77. headerValue = append(headerValue, v...)
  78. }
  79. if headerKey != commitHeaderGpgsig && headerKey != commitHeaderGpgsigSha256 {
  80. _, _ = payloadSB.Write(line)
  81. }
  82. } else {
  83. _, _ = messageSB.Write(line)
  84. _, _ = payloadSB.Write(line)
  85. }
  86. }
  87. commit.CommitMessage = messageSB.String()
  88. if commit.Signature != nil {
  89. commit.Signature.Payload = payloadSB.String()
  90. }
  91. return commit, nil
  92. }