code.gitea.io/gitea@v1.19.3/modules/git/commit_reader.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package git 5 6 import ( 7 "bufio" 8 "bytes" 9 "io" 10 "strings" 11 ) 12 13 // CommitFromReader will generate a Commit from a provided reader 14 // We need this to interpret commits from cat-file or cat-file --batch 15 // 16 // If used as part of a cat-file --batch stream you need to limit the reader to the correct size 17 func CommitFromReader(gitRepo *Repository, sha SHA1, reader io.Reader) (*Commit, error) { 18 commit := &Commit{ 19 ID: sha, 20 Author: &Signature{}, 21 Committer: &Signature{}, 22 } 23 24 payloadSB := new(strings.Builder) 25 signatureSB := new(strings.Builder) 26 messageSB := new(strings.Builder) 27 message := false 28 pgpsig := false 29 30 bufReader, ok := reader.(*bufio.Reader) 31 if !ok { 32 bufReader = bufio.NewReader(reader) 33 } 34 35 readLoop: 36 for { 37 line, err := bufReader.ReadBytes('\n') 38 if err != nil { 39 if err == io.EOF { 40 if message { 41 _, _ = messageSB.Write(line) 42 } 43 _, _ = payloadSB.Write(line) 44 break readLoop 45 } 46 return nil, err 47 } 48 if pgpsig { 49 if len(line) > 0 && line[0] == ' ' { 50 _, _ = signatureSB.Write(line[1:]) 51 continue 52 } else { 53 pgpsig = false 54 } 55 } 56 57 if !message { 58 // This is probably not correct but is copied from go-gits interpretation... 59 trimmed := bytes.TrimSpace(line) 60 if len(trimmed) == 0 { 61 message = true 62 _, _ = payloadSB.Write(line) 63 continue 64 } 65 66 split := bytes.SplitN(trimmed, []byte{' '}, 2) 67 var data []byte 68 if len(split) > 1 { 69 data = split[1] 70 } 71 72 switch string(split[0]) { 73 case "tree": 74 commit.Tree = *NewTree(gitRepo, MustIDFromString(string(data))) 75 _, _ = payloadSB.Write(line) 76 case "parent": 77 commit.Parents = append(commit.Parents, MustIDFromString(string(data))) 78 _, _ = payloadSB.Write(line) 79 case "author": 80 commit.Author = &Signature{} 81 commit.Author.Decode(data) 82 _, _ = payloadSB.Write(line) 83 case "committer": 84 commit.Committer = &Signature{} 85 commit.Committer.Decode(data) 86 _, _ = payloadSB.Write(line) 87 case "gpgsig": 88 _, _ = signatureSB.Write(data) 89 _ = signatureSB.WriteByte('\n') 90 pgpsig = true 91 } 92 } else { 93 _, _ = messageSB.Write(line) 94 _, _ = payloadSB.Write(line) 95 } 96 } 97 commit.CommitMessage = messageSB.String() 98 commit.Signature = &CommitGPGSignature{ 99 Signature: signatureSB.String(), 100 Payload: payloadSB.String(), 101 } 102 if len(commit.Signature.Signature) == 0 { 103 commit.Signature = nil 104 } 105 106 return commit, nil 107 }