107 lines
2.5 KiB
Go
107 lines
2.5 KiB
Go
package gitnaturalapi
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Person struct {
|
|
Name string
|
|
Email string
|
|
Timestamp int64
|
|
Timezone string
|
|
}
|
|
|
|
type Commit struct {
|
|
Hash string
|
|
Tree string
|
|
Parents []string
|
|
Author Person
|
|
Committer Person
|
|
Message string
|
|
}
|
|
|
|
func ParseCommit(data []byte, hash string) (*Commit, error) {
|
|
content := string(data)
|
|
|
|
headerEndIndex := strings.Index(content, "\n\n")
|
|
if headerEndIndex == -1 {
|
|
return nil, fmt.Errorf("invalid commit format for %s: no message separator found", hash)
|
|
}
|
|
|
|
header := content[:headerEndIndex]
|
|
message := content[headerEndIndex+2:]
|
|
|
|
lines := strings.Split(header, "\n")
|
|
result := &Commit{
|
|
Hash: hash,
|
|
Parents: []string{},
|
|
Message: message,
|
|
}
|
|
|
|
for _, line := range lines {
|
|
if strings.HasPrefix(line, "tree ") {
|
|
result.Tree = line[5:]
|
|
} else if strings.HasPrefix(line, "parent ") {
|
|
result.Parents = append(result.Parents, line[7:])
|
|
} else if strings.HasPrefix(line, "author ") {
|
|
person, err := parsePerson(line[7:])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid author in commit %s: %w", hash, err)
|
|
}
|
|
result.Author = person
|
|
} else if strings.HasPrefix(line, "committer ") {
|
|
person, err := parsePerson(line[10:])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid committer in commit %s: %w", hash, err)
|
|
}
|
|
result.Committer = person
|
|
}
|
|
}
|
|
|
|
if result.Tree == "" {
|
|
return nil, fmt.Errorf("invalid commit format for %s: missing tree", hash)
|
|
}
|
|
if result.Author.Name == "" {
|
|
return nil, fmt.Errorf("invalid commit format for %s: missing author", hash)
|
|
}
|
|
if result.Committer.Name == "" {
|
|
return nil, fmt.Errorf("invalid commit format for %s: missing committer", hash)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func parsePerson(line string) (Person, error) {
|
|
emailStart := strings.Index(line, " <")
|
|
if emailStart == -1 {
|
|
return Person{}, fmt.Errorf("invalid person format: %s", line)
|
|
}
|
|
name := line[:emailStart]
|
|
|
|
emailEnd := strings.Index(line[emailStart+2:], ">")
|
|
if emailEnd == -1 {
|
|
return Person{}, fmt.Errorf("invalid person format: %s", line)
|
|
}
|
|
email := line[emailStart+2 : emailStart+2+emailEnd]
|
|
|
|
rest := strings.TrimSpace(line[emailStart+2+emailEnd+1:])
|
|
parts := strings.SplitN(rest, " ", 2)
|
|
if len(parts) != 2 {
|
|
return Person{}, fmt.Errorf("invalid person format: %s", line)
|
|
}
|
|
|
|
timestamp, err := strconv.ParseInt(parts[0], 10, 64)
|
|
if err != nil {
|
|
return Person{}, fmt.Errorf("invalid timestamp in person: %s", parts[0])
|
|
}
|
|
|
|
return Person{
|
|
Name: name,
|
|
Email: email,
|
|
Timestamp: timestamp,
|
|
Timezone: parts[1],
|
|
}, nil
|
|
}
|