mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-03 21:08:25 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			101 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			101 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2020 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package git
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	commitHeaderGpgsig       = "gpgsig"
 | 
						|
	commitHeaderGpgsigSha256 = "gpgsig-sha256"
 | 
						|
)
 | 
						|
 | 
						|
func assignCommitFields(gitRepo *Repository, commit *Commit, headerKey string, headerValue []byte) error {
 | 
						|
	if len(headerValue) > 0 && headerValue[len(headerValue)-1] == '\n' {
 | 
						|
		headerValue = headerValue[:len(headerValue)-1] // remove trailing newline
 | 
						|
	}
 | 
						|
	switch headerKey {
 | 
						|
	case "tree":
 | 
						|
		objID, err := NewIDFromString(string(headerValue))
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("invalid tree ID %q: %w", string(headerValue), err)
 | 
						|
		}
 | 
						|
		commit.Tree = *NewTree(gitRepo, objID)
 | 
						|
	case "parent":
 | 
						|
		objID, err := NewIDFromString(string(headerValue))
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("invalid parent ID %q: %w", string(headerValue), err)
 | 
						|
		}
 | 
						|
		commit.Parents = append(commit.Parents, objID)
 | 
						|
	case "author":
 | 
						|
		commit.Author.Decode(headerValue)
 | 
						|
	case "committer":
 | 
						|
		commit.Committer.Decode(headerValue)
 | 
						|
	case commitHeaderGpgsig, commitHeaderGpgsigSha256:
 | 
						|
		// if there are duplicate "gpgsig" and "gpgsig-sha256" headers, then the signature must have already been invalid
 | 
						|
		// so we don't need to handle duplicate headers here
 | 
						|
		commit.Signature = &CommitSignature{Signature: string(headerValue)}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// 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{},
 | 
						|
	}
 | 
						|
 | 
						|
	bufReader := bufio.NewReader(reader)
 | 
						|
	inHeader := true
 | 
						|
	var payloadSB, messageSB bytes.Buffer
 | 
						|
	var headerKey string
 | 
						|
	var headerValue []byte
 | 
						|
	for {
 | 
						|
		line, err := bufReader.ReadBytes('\n')
 | 
						|
		if err != nil && err != io.EOF {
 | 
						|
			return nil, fmt.Errorf("unable to read commit %q: %w", objectID.String(), err)
 | 
						|
		}
 | 
						|
		if len(line) == 0 {
 | 
						|
			break
 | 
						|
		}
 | 
						|
 | 
						|
		if inHeader {
 | 
						|
			inHeader = !(len(line) == 1 && line[0] == '\n') // still in header if line is not just a newline
 | 
						|
			k, v, _ := bytes.Cut(line, []byte{' '})
 | 
						|
			if len(k) != 0 || !inHeader {
 | 
						|
				if headerKey != "" {
 | 
						|
					if err = assignCommitFields(gitRepo, commit, headerKey, headerValue); err != nil {
 | 
						|
						return nil, fmt.Errorf("unable to parse commit %q: %w", objectID.String(), err)
 | 
						|
					}
 | 
						|
				}
 | 
						|
				headerKey = string(k) // it also resets the headerValue to empty string if not inHeader
 | 
						|
				headerValue = v
 | 
						|
			} else {
 | 
						|
				headerValue = append(headerValue, v...)
 | 
						|
			}
 | 
						|
			if headerKey != commitHeaderGpgsig && headerKey != commitHeaderGpgsigSha256 {
 | 
						|
				_, _ = payloadSB.Write(line)
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			_, _ = messageSB.Write(line)
 | 
						|
			_, _ = payloadSB.Write(line)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	commit.CommitMessage = messageSB.String()
 | 
						|
	if commit.Signature != nil {
 | 
						|
		commit.Signature.Payload = payloadSB.String()
 | 
						|
	}
 | 
						|
	return commit, nil
 | 
						|
}
 |