code.gitea.io/gitea@v1.22.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, objectID ObjectID, reader io.Reader) (*Commit, error) { 18 commit := &Commit{ 19 ID: objectID, 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 } 53 pgpsig = false 54 } 55 56 if !message { 57 // This is probably not correct but is copied from go-gits interpretation... 58 trimmed := bytes.TrimSpace(line) 59 if len(trimmed) == 0 { 60 message = true 61 _, _ = payloadSB.Write(line) 62 continue 63 } 64 65 split := bytes.SplitN(trimmed, []byte{' '}, 2) 66 var data []byte 67 if len(split) > 1 { 68 data = split[1] 69 } 70 71 switch string(split[0]) { 72 case "tree": 73 commit.Tree = *NewTree(gitRepo, MustIDFromString(string(data))) 74 _, _ = payloadSB.Write(line) 75 case "parent": 76 commit.Parents = append(commit.Parents, MustIDFromString(string(data))) 77 _, _ = payloadSB.Write(line) 78 case "author": 79 commit.Author = &Signature{} 80 commit.Author.Decode(data) 81 _, _ = payloadSB.Write(line) 82 case "committer": 83 commit.Committer = &Signature{} 84 commit.Committer.Decode(data) 85 _, _ = payloadSB.Write(line) 86 case "encoding": 87 _, _ = payloadSB.Write(line) 88 case "gpgsig": 89 fallthrough 90 case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present. 91 _, _ = signatureSB.Write(data) 92 _ = signatureSB.WriteByte('\n') 93 pgpsig = true 94 } 95 } else { 96 _, _ = messageSB.Write(line) 97 _, _ = payloadSB.Write(line) 98 } 99 } 100 commit.CommitMessage = messageSB.String() 101 commit.Signature = &CommitSignature{ 102 Signature: signatureSB.String(), 103 Payload: payloadSB.String(), 104 } 105 if len(commit.Signature.Signature) == 0 { 106 commit.Signature = nil 107 } 108 109 return commit, nil 110 }