mirror of https://github.com/go-gitea/gitea.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
3.0 KiB
100 lines
3.0 KiB
// 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 |
|
}
|
|
|