206 lines
4.9 KiB
Go
206 lines
4.9 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
|
|
}
|