Lindenii Project Forge
Login

server

Lindenii Forge’s main backend daemon

Warning: Due to various recent migrations, viewing non-HEAD refs may be broken.

/forged/internal/ipc/git2c/extra.go (raw)

// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>

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
}