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