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  }