Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
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.
108 lines
2.6 KiB
108 lines
2.6 KiB
// Copyright 2020 The Gitea Authors. All rights reserved. |
|
// Use of this source code is governed by a MIT-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package git |
|
|
|
import ( |
|
"bufio" |
|
"bytes" |
|
"io" |
|
"strings" |
|
|
|
"github.com/go-git/go-git/v5/plumbing" |
|
) |
|
|
|
// CommitFromReader will generate a Commit from a provided reader |
|
// We will need this to interpret commits from cat-file |
|
func CommitFromReader(gitRepo *Repository, sha plumbing.Hash, reader io.Reader) (*Commit, error) { |
|
commit := &Commit{ |
|
ID: sha, |
|
} |
|
|
|
payloadSB := new(strings.Builder) |
|
signatureSB := new(strings.Builder) |
|
messageSB := new(strings.Builder) |
|
message := false |
|
pgpsig := false |
|
|
|
scanner := bufio.NewScanner(reader) |
|
// Split by '\n' but include the '\n' |
|
scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) { |
|
if atEOF && len(data) == 0 { |
|
return 0, nil, nil |
|
} |
|
if i := bytes.IndexByte(data, '\n'); i >= 0 { |
|
// We have a full newline-terminated line. |
|
return i + 1, data[0 : i+1], nil |
|
} |
|
// If we're at EOF, we have a final, non-terminated line. Return it. |
|
if atEOF { |
|
return len(data), data, nil |
|
} |
|
// Request more data. |
|
return 0, nil, nil |
|
}) |
|
|
|
for scanner.Scan() { |
|
line := scanner.Bytes() |
|
if pgpsig { |
|
if len(line) > 0 && line[0] == ' ' { |
|
_, _ = signatureSB.Write(line[1:]) |
|
continue |
|
} else { |
|
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, plumbing.NewHash(string(data))) |
|
_, _ = payloadSB.Write(line) |
|
case "parent": |
|
commit.Parents = append(commit.Parents, plumbing.NewHash(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": |
|
_, _ = signatureSB.Write(data) |
|
_ = signatureSB.WriteByte('\n') |
|
pgpsig = true |
|
} |
|
} else { |
|
_, _ = messageSB.Write(line) |
|
} |
|
} |
|
commit.CommitMessage = messageSB.String() |
|
_, _ = payloadSB.WriteString(commit.CommitMessage) |
|
commit.Signature = &CommitGPGSignature{ |
|
Signature: signatureSB.String(), |
|
Payload: payloadSB.String(), |
|
} |
|
if len(commit.Signature.Signature) == 0 { |
|
commit.Signature = nil |
|
} |
|
|
|
return commit, scanner.Err() |
|
}
|
|
|