diff options
Diffstat (limited to 'modules/git/commit_reader.go')
-rw-r--r-- | modules/git/commit_reader.go | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/modules/git/commit_reader.go b/modules/git/commit_reader.go new file mode 100644 index 00000000..8e2523d7 --- /dev/null +++ b/modules/git/commit_reader.go @@ -0,0 +1,110 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "bufio" + "bytes" + "io" + "strings" +) + +// CommitFromReader will generate a Commit from a provided reader +// We need this to interpret commits from cat-file or cat-file --batch +// +// If used as part of a cat-file --batch stream you need to limit the reader to the correct size +func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader) (*Commit, error) { + commit := &Commit{ + ID: objectID, + Author: &Signature{}, + Committer: &Signature{}, + } + + payloadSB := new(strings.Builder) + signatureSB := new(strings.Builder) + messageSB := new(strings.Builder) + message := false + pgpsig := false + + bufReader, ok := reader.(*bufio.Reader) + if !ok { + bufReader = bufio.NewReader(reader) + } + +readLoop: + for { + line, err := bufReader.ReadBytes('\n') + if err != nil { + if err == io.EOF { + if message { + _, _ = messageSB.Write(line) + } + _, _ = payloadSB.Write(line) + break readLoop + } + return nil, err + } + if pgpsig { + if len(line) > 0 && line[0] == ' ' { + _, _ = signatureSB.Write(line[1:]) + continue + } + pgpsig = false + } + + if !message { + // This is probably not correct but is copied from go-gits interpretation... + trimmed := bytes.TrimSpace(line) + if len(trimmed) == 0 { + message = true + _, _ = payloadSB.Write(line) + continue + } + + split := bytes.SplitN(trimmed, []byte{' '}, 2) + var data []byte + if len(split) > 1 { + data = split[1] + } + + switch string(split[0]) { + case "tree": + commit.Tree = *NewTree(gitRepo, MustIDFromString(string(data))) + _, _ = payloadSB.Write(line) + case "parent": + commit.Parents = append(commit.Parents, MustIDFromString(string(data))) + _, _ = payloadSB.Write(line) + case "author": + commit.Author = &Signature{} + commit.Author.Decode(data) + _, _ = payloadSB.Write(line) + case "committer": + commit.Committer = &Signature{} + commit.Committer.Decode(data) + _, _ = payloadSB.Write(line) + case "encoding": + _, _ = payloadSB.Write(line) + case "gpgsig": + fallthrough + case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present. + _, _ = signatureSB.Write(data) + _ = signatureSB.WriteByte('\n') + pgpsig = true + } + } else { + _, _ = messageSB.Write(line) + _, _ = payloadSB.Write(line) + } + } + commit.CommitMessage = messageSB.String() + commit.Signature = &ObjectSignature{ + Signature: signatureSB.String(), + Payload: payloadSB.String(), + } + if len(commit.Signature.Signature) == 0 { + commit.Signature = nil + } + + return commit, nil +} |