Files

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
}