Files
onyx-prebootstrap/internal/git/objects.go
Tanishq Dubey a0f80c5c7d
Some checks failed
CI / Test (pull_request) Failing after 6s
CI / Build (pull_request) Failing after 7s
CI / Lint (pull_request) Failing after 13s
milestone 2 complete
2025-10-10 19:03:31 -04:00

211 lines
5.1 KiB
Go

package git
import (
"fmt"
"time"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/filemode"
"github.com/go-git/go-git/v5/plumbing/object"
)
// GitBackend implements low-level Git object operations
type GitBackend struct {
repo *git.Repository
}
// NewGitBackend creates a new GitBackend instance
func NewGitBackend(repo *git.Repository) *GitBackend {
return &GitBackend{repo: repo}
}
// CreateBlob creates a new blob object from the given content
func (gb *GitBackend) CreateBlob(content []byte) (string, error) {
store := gb.repo.Storer
// Create a blob object
blob := store.NewEncodedObject()
blob.SetType(plumbing.BlobObject)
blob.SetSize(int64(len(content)))
writer, err := blob.Writer()
if err != nil {
return "", fmt.Errorf("failed to get blob writer: %w", err)
}
_, err = writer.Write(content)
if err != nil {
writer.Close()
return "", fmt.Errorf("failed to write blob content: %w", err)
}
if err := writer.Close(); err != nil {
return "", fmt.Errorf("failed to close blob writer: %w", err)
}
// Store the blob
hash, err := store.SetEncodedObject(blob)
if err != nil {
return "", fmt.Errorf("failed to store blob: %w", err)
}
return hash.String(), nil
}
// TreeEntry represents an entry in a Git tree
type TreeEntry struct {
Mode filemode.FileMode
Name string
Hash plumbing.Hash
}
// CreateTree creates a new tree object from the given entries
func (gb *GitBackend) CreateTree(entries []TreeEntry) (string, error) {
store := gb.repo.Storer
// Create a new tree object
tree := &object.Tree{}
treeEntries := make([]object.TreeEntry, len(entries))
for i, entry := range entries {
treeEntries[i] = object.TreeEntry{
Name: entry.Name,
Mode: entry.Mode,
Hash: entry.Hash,
}
}
tree.Entries = treeEntries
// Encode and store the tree
obj := store.NewEncodedObject()
if err := tree.Encode(obj); err != nil {
return "", fmt.Errorf("failed to encode tree: %w", err)
}
hash, err := store.SetEncodedObject(obj)
if err != nil {
return "", fmt.Errorf("failed to store tree: %w", err)
}
return hash.String(), nil
}
// CreateCommit creates a new commit object
func (gb *GitBackend) CreateCommit(treeHash, parentHash, message, author string) (string, error) {
store := gb.repo.Storer
// Parse hashes
tree := plumbing.NewHash(treeHash)
var parents []plumbing.Hash
if parentHash != "" {
parents = []plumbing.Hash{plumbing.NewHash(parentHash)}
}
// Create commit object
commit := &object.Commit{
Author: object.Signature{
Name: author,
Email: "onyx@local",
When: time.Now(),
},
Committer: object.Signature{
Name: author,
Email: "onyx@local",
When: time.Now(),
},
Message: message,
TreeHash: tree,
}
if len(parents) > 0 {
commit.ParentHashes = parents
}
// Encode and store the commit
obj := store.NewEncodedObject()
if err := commit.Encode(obj); err != nil {
return "", fmt.Errorf("failed to encode commit: %w", err)
}
hash, err := store.SetEncodedObject(obj)
if err != nil {
return "", fmt.Errorf("failed to store commit: %w", err)
}
return hash.String(), nil
}
// UpdateRef updates a Git reference to point to a new SHA
func (gb *GitBackend) UpdateRef(refName, sha string) error {
hash := plumbing.NewHash(sha)
ref := plumbing.NewHashReference(plumbing.ReferenceName(refName), hash)
if err := gb.repo.Storer.SetReference(ref); err != nil {
return fmt.Errorf("failed to update reference %s: %w", refName, err)
}
return nil
}
// GetRef retrieves the SHA that a reference points to
func (gb *GitBackend) GetRef(refName string) (string, error) {
ref, err := gb.repo.Reference(plumbing.ReferenceName(refName), true)
if err != nil {
return "", fmt.Errorf("failed to get reference %s: %w", refName, err)
}
return ref.Hash().String(), nil
}
// GetObject retrieves a Git object by its SHA
func (gb *GitBackend) GetObject(sha string) (object.Object, error) {
hash := plumbing.NewHash(sha)
obj, err := gb.repo.Object(plumbing.AnyObject, hash)
if err != nil {
return nil, fmt.Errorf("failed to get object %s: %w", sha, err)
}
return obj, nil
}
// GetBlob retrieves a blob object by its SHA
func (gb *GitBackend) GetBlob(sha string) (*object.Blob, error) {
hash := plumbing.NewHash(sha)
blob, err := gb.repo.BlobObject(hash)
if err != nil {
return nil, fmt.Errorf("failed to get blob %s: %w", sha, err)
}
return blob, nil
}
// GetTree retrieves a tree object by its SHA
func (gb *GitBackend) GetTree(sha string) (*object.Tree, error) {
hash := plumbing.NewHash(sha)
tree, err := gb.repo.TreeObject(hash)
if err != nil {
return nil, fmt.Errorf("failed to get tree %s: %w", sha, err)
}
return tree, nil
}
// GetCommit retrieves a commit object by its SHA
func (gb *GitBackend) GetCommit(sha string) (*object.Commit, error) {
hash := plumbing.NewHash(sha)
commit, err := gb.repo.CommitObject(hash)
if err != nil {
return nil, fmt.Errorf("failed to get commit %s: %w", sha, err)
}
return commit, nil
}
// HashFromString converts a string SHA to a plumbing.Hash
func HashFromString(sha string) plumbing.Hash {
return plumbing.NewHash(sha)
}