117 lines · 2.9 KB · Go
RawDownload
// 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 sizefunc 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)	firstLine := true	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 "gpgsig":				fallthrough			case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present.				_, _ = signatureSB.Write(data)				_ = signatureSB.WriteByte('\n')				pgpsig = true			default:				// If the first line is not any of the known headers, then it is probably the prefix added when git cat-file is called with --batch, and that is not part of the payload				if !firstLine {					// Every subsequent header field is added to the payload					_, _ = payloadSB.Write(line)				}			}		} else {			_, _ = messageSB.Write(line)			_, _ = payloadSB.Write(line)		} 		firstLine = false	}	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}