1
0
Fork 0
mirror of https://github.com/imjasonh/infinite-git synced 2026-07-08 17:15:37 +00:00
infinite-git/internal/pktline/reader.go
Jason Hall 30ca57dae3
Implement infinite Git HTTP server
This server generates a new commit every time someone pulls from it.
Features:
- Pure Go implementation of Git object format and protocols
- No dependency on git CLI commands
- Thread-safe commit generation
- Read-only Git HTTP smart protocol support
- Comprehensive test suite

Each pull creates a new commit with a unique file containing a timestamp
and counter, making the repository grow infinitely with each pull operation.

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-23 21:19:02 -04:00

89 lines
1.8 KiB
Go

package pktline
import (
"bufio"
"fmt"
"io"
)
// Reader implements the Git packet line protocol for reading.
type Reader struct {
r *bufio.Reader
}
// NewReader creates a new packet line reader.
func NewReader(r io.Reader) *Reader {
return &Reader{r: bufio.NewReader(r)}
}
// Read reads a single pkt-line.
// Returns io.EOF on flush packet (0000).
func (r *Reader) Read() ([]byte, error) {
// Read 4-byte length header
header := make([]byte, 4)
if _, err := io.ReadFull(r.r, header); err != nil {
return nil, err
}
// Parse length
var length int
if _, err := fmt.Sscanf(string(header), "%04x", &length); err != nil {
return nil, fmt.Errorf("invalid pkt-line header: %s", header)
}
// Handle special packets
switch length {
case 0: // flush-pkt
return nil, io.EOF
case 1: // delimiter packet (0001)
return nil, fmt.Errorf("delimiter packet not supported")
case 2: // response-end packet (0002)
return nil, fmt.Errorf("response-end packet not supported")
}
// Read data
if length < 4 {
return nil, fmt.Errorf("invalid pkt-line length: %d", length)
}
data := make([]byte, length-4)
if _, err := io.ReadFull(r.r, data); err != nil {
return nil, err
}
return data, nil
}
// ReadString reads a pkt-line as a string, trimming newline.
func (r *Reader) ReadString() (string, error) {
data, err := r.Read()
if err != nil {
return "", err
}
// Trim trailing newline if present
if len(data) > 0 && data[len(data)-1] == '\n' {
data = data[:len(data)-1]
}
return string(data), nil
}
// ReadAll reads all pkt-lines until flush packet.
func (r *Reader) ReadAll() ([][]byte, error) {
var lines [][]byte
for {
line, err := r.Read()
if err == io.EOF {
// Flush packet, we're done
break
}
if err != nil {
return nil, err
}
lines = append(lines, line)
}
return lines, nil
}