Implement Phase 0
This commit is contained in:
205
internal/git/objects.go
Normal file
205
internal/git/objects.go
Normal file
@ -0,0 +1,205 @@
|
||||
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
|
||||
}
|
Reference in New Issue
Block a user