// SPDX-License-Identifier: AGPL-3.0-only // SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu package git2c import ( "encoding/hex" "fmt" "time" ) func (c *Client) ResolveRef(repoPath, refType, refName string) (string, error) { if err := c.writer.WriteData([]byte(repoPath)); err != nil { return "", fmt.Errorf("sending repo path failed: %w", err) } if err := c.writer.WriteUint(3); err != nil { return "", fmt.Errorf("sending command failed: %w", err) } if err := c.writer.WriteData([]byte(refType)); err != nil { return "", fmt.Errorf("sending ref type failed: %w", err) } if err := c.writer.WriteData([]byte(refName)); err != nil { return "", fmt.Errorf("sending ref name failed: %w", err) } status, err := c.reader.ReadUint() if err != nil { return "", fmt.Errorf("reading status failed: %w", err) } if status != 0 { return "", Perror(status) } id, err := c.reader.ReadData() if err != nil { return "", fmt.Errorf("reading oid failed: %w", err) } return hex.EncodeToString(id), nil } func (c *Client) ListBranches(repoPath string) ([]string, error) { if err := c.writer.WriteData([]byte(repoPath)); err != nil { return nil, fmt.Errorf("sending repo path failed: %w", err) } if err := c.writer.WriteUint(4); err != nil { return nil, fmt.Errorf("sending command failed: %w", err) } status, err := c.reader.ReadUint() if err != nil { return nil, fmt.Errorf("reading status failed: %w", err) } if status != 0 { return nil, Perror(status) } count, err := c.reader.ReadUint() if err != nil { return nil, fmt.Errorf("reading count failed: %w", err) } branches := make([]string, 0, count) for range count { name, err := c.reader.ReadData() if err != nil { return nil, fmt.Errorf("reading branch name failed: %w", err) } branches = append(branches, string(name)) } return branches, nil } func (c *Client) FormatPatch(repoPath, commitHex string) (string, error) { if err := c.writer.WriteData([]byte(repoPath)); err != nil { return "", fmt.Errorf("sending repo path failed: %w", err) } if err := c.writer.WriteUint(5); err != nil { return "", fmt.Errorf("sending command failed: %w", err) } if err := c.writer.WriteData([]byte(commitHex)); err != nil { return "", fmt.Errorf("sending commit failed: %w", err) } status, err := c.reader.ReadUint() if err != nil { return "", fmt.Errorf("reading status failed: %w", err) } if status != 0 { return "", Perror(status) } buf, err := c.reader.ReadData() if err != nil { return "", fmt.Errorf("reading patch failed: %w", err) } return string(buf), nil } func (c *Client) CommitPatch(repoPath, commitHex string) (parentHex string, stats string, patch string, err error) { if err = c.writer.WriteData([]byte(repoPath)); err != nil { return "", "", "", fmt.Errorf("sending repo path failed: %w", err) } if err = c.writer.WriteUint(6); err != nil { return "", "", "", fmt.Errorf("sending command failed: %w", err) } if err = c.writer.WriteData([]byte(commitHex)); err != nil { return "", "", "", fmt.Errorf("sending commit failed: %w", err) } status, err2 := c.reader.ReadUint() if err2 != nil { return "", "", "", fmt.Errorf("reading status failed: %w", err2) } if status != 0 { return "", "", "", Perror(status) } id, err2 := c.reader.ReadData() if err2 != nil { return "", "", "", fmt.Errorf("reading parent oid failed: %w", err2) } statsBytes, err2 := c.reader.ReadData() if err2 != nil { return "", "", "", fmt.Errorf("reading stats failed: %w", err2) } patchBytes, err2 := c.reader.ReadData() if err2 != nil { return "", "", "", fmt.Errorf("reading patch failed: %w", err2) } return hex.EncodeToString(id), string(statsBytes), string(patchBytes), nil } func (c *Client) MergeBase(repoPath, hexA, hexB string) (string, error) { if err := c.writer.WriteData([]byte(repoPath)); err != nil { return "", fmt.Errorf("sending repo path failed: %w", err) } if err := c.writer.WriteUint(7); err != nil { return "", fmt.Errorf("sending command failed: %w", err) } if err := c.writer.WriteData([]byte(hexA)); err != nil { return "", fmt.Errorf("sending oid A failed: %w", err) } if err := c.writer.WriteData([]byte(hexB)); err != nil { return "", fmt.Errorf("sending oid B failed: %w", err) } status, err := c.reader.ReadUint() if err != nil { return "", fmt.Errorf("reading status failed: %w", err) } if status != 0 { return "", Perror(status) } base, err := c.reader.ReadData() if err != nil { return "", fmt.Errorf("reading base oid failed: %w", err) } return hex.EncodeToString(base), nil } func (c *Client) Log(repoPath, refSpec string, n uint) ([]Commit, error) { if err := c.writer.WriteData([]byte(repoPath)); err != nil { return nil, fmt.Errorf("sending repo path failed: %w", err) } if err := c.writer.WriteUint(8); err != nil { return nil, fmt.Errorf("sending command failed: %w", err) } if err := c.writer.WriteData([]byte(refSpec)); err != nil { return nil, fmt.Errorf("sending refspec failed: %w", err) } if err := c.writer.WriteUint(uint64(n)); err != nil { return nil, fmt.Errorf("sending limit failed: %w", err) } status, err := c.reader.ReadUint() if err != nil { return nil, fmt.Errorf("reading status failed: %w", err) } if status != 0 { return nil, Perror(status) } var out []Commit for { id, err := c.reader.ReadData() if err != nil { break } title, _ := c.reader.ReadData() authorName, _ := c.reader.ReadData() authorEmail, _ := c.reader.ReadData() date, _ := c.reader.ReadData() out = append(out, Commit{ Hash: hex.EncodeToString(id), Author: string(authorName), Email: string(authorEmail), Date: string(date), Message: string(title), }) } return out, nil } func (c *Client) CommitTreeOID(repoPath, commitHex string) (string, error) { if err := c.writer.WriteData([]byte(repoPath)); err != nil { return "", fmt.Errorf("sending repo path failed: %w", err) } if err := c.writer.WriteUint(12); err != nil { return "", fmt.Errorf("sending command failed: %w", err) } if err := c.writer.WriteData([]byte(commitHex)); err != nil { return "", fmt.Errorf("sending oid failed: %w", err) } status, err := c.reader.ReadUint() if err != nil { return "", fmt.Errorf("reading status failed: %w", err) } if status != 0 { return "", Perror(status) } id, err := c.reader.ReadData() if err != nil { return "", fmt.Errorf("reading tree oid failed: %w", err) } return hex.EncodeToString(id), nil } func (c *Client) CommitCreate(repoPath, treeHex string, parents []string, authorName, authorEmail string, when time.Time, message string) (string, error) { if err := c.writer.WriteData([]byte(repoPath)); err != nil { return "", fmt.Errorf("sending repo path failed: %w", err) } if err := c.writer.WriteUint(13); err != nil { return "", fmt.Errorf("sending command failed: %w", err) } if err := c.writer.WriteData([]byte(treeHex)); err != nil { return "", fmt.Errorf("sending tree oid failed: %w", err) } if err := c.writer.WriteUint(uint64(len(parents))); err != nil { return "", fmt.Errorf("sending parents count failed: %w", err) } for _, p := range parents { if err := c.writer.WriteData([]byte(p)); err != nil { return "", fmt.Errorf("sending parent oid failed: %w", err) } } if err := c.writer.WriteData([]byte(authorName)); err != nil { return "", fmt.Errorf("sending author name failed: %w", err) } if err := c.writer.WriteData([]byte(authorEmail)); err != nil { return "", fmt.Errorf("sending author email failed: %w", err) } if err := c.writer.WriteInt(when.Unix()); err != nil { return "", fmt.Errorf("sending when failed: %w", err) } _, offset := when.Zone() if err := c.writer.WriteInt(int64(offset / 60)); err != nil { return "", fmt.Errorf("sending tz offset failed: %w", err) } if err := c.writer.WriteData([]byte(message)); err != nil { return "", fmt.Errorf("sending message failed: %w", err) } status, err := c.reader.ReadUint() if err != nil { return "", fmt.Errorf("reading status failed: %w", err) } if status != 0 { return "", Perror(status) } id, err := c.reader.ReadData() if err != nil { return "", fmt.Errorf("reading commit oid failed: %w", err) } return hex.EncodeToString(id), nil } func (c *Client) UpdateRef(repoPath, refName, commitHex string) error { if err := c.writer.WriteData([]byte(repoPath)); err != nil { return fmt.Errorf("sending repo path failed: %w", err) } if err := c.writer.WriteUint(14); err != nil { return fmt.Errorf("sending command failed: %w", err) } if err := c.writer.WriteData([]byte(refName)); err != nil { return fmt.Errorf("sending ref name failed: %w", err) } if err := c.writer.WriteData([]byte(commitHex)); err != nil { return fmt.Errorf("sending commit oid failed: %w", err) } status, err := c.reader.ReadUint() if err != nil { return fmt.Errorf("reading status failed: %w", err) } if status != 0 { return Perror(status) } return nil }