From edd37bb4fd3aa08eda39303fd5628a554a8c3aeb Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Sun, 16 Nov 2025 00:00:00 +0000 Subject: Separate stored object types from types that the user is expected to construct. --- obj.go | 8 +++++++- obj_blob.go | 23 +++++++++++++++++------ obj_commit.go | 20 +++++++++++++++----- obj_tag.go | 20 +++++++++++++++----- obj_tree.go | 22 +++++++++++++++++----- objects_test.go | 4 ++-- repo_test.go | 20 ++++++++++---------- 7 files changed, 83 insertions(+), 34 deletions(-) diff --git a/obj.go b/obj.go index de847607..ee11a024 100644 --- a/obj.go +++ b/obj.go @@ -33,6 +33,12 @@ type Object interface { ObjectType() ObjectType } +// StoredObject describes a Git object with a known hash. +type StoredObject interface { + Object + Hash() Hash +} + func headerForType(ty ObjectType, body []byte) ([]byte, error) { var tyStr string switch ty { @@ -59,7 +65,7 @@ func headerForType(ty ObjectType, body []byte) ([]byte, error) { return buf.Bytes(), nil } -func parseObjectBody(ty ObjectType, id Hash, body []byte, repo *Repository) (Object, error) { +func parseObjectBody(ty ObjectType, id Hash, body []byte, repo *Repository) (StoredObject, error) { switch ty { case ObjectTypeBlob: return parseBlob(id, body) diff --git a/obj_blob.go b/obj_blob.go index c25f88eb..6a987604 100644 --- a/obj_blob.go +++ b/obj_blob.go @@ -2,22 +2,33 @@ package furgit // Blob represents the contents of a Git blob. type Blob struct { - Hash Hash - Data []byte } +// StoredBlob represents a blob stored in the object database. +type StoredBlob struct { + Blob + hash Hash +} + +// Hash returns the hash of the stored blob. +func (sBlob *StoredBlob) Hash() Hash { + return sBlob.hash +} + // ObjectType allows Blob to satisfy the Object interface. func (blob *Blob) ObjectType() ObjectType { _ = blob return ObjectTypeBlob } -func parseBlob(id Hash, body []byte) (*Blob, error) { +func parseBlob(id Hash, body []byte) (*StoredBlob, error) { data := append([]byte(nil), body...) - return &Blob{ - Hash: id, - Data: data, + return &StoredBlob{ + hash: id, + Blob: Blob{ + Data: data, + }, }, nil } diff --git a/obj_commit.go b/obj_commit.go index f1616fba..c3a4e5db 100644 --- a/obj_commit.go +++ b/obj_commit.go @@ -6,9 +6,8 @@ import ( "fmt" ) -// Commit mirrors the structure of a Git commit object. +// Commit represents a Git commit object. type Commit struct { - Hash Hash Tree Hash Parents []Hash Author Ident @@ -17,15 +16,26 @@ type Commit struct { ExtraHeaders []ExtraHeader } +// StoredCommit represents a commit stored in the object database. +type StoredCommit struct { + Commit + hash Hash +} + +// Hash returns the hash of the stored commit. +func (sCommit *StoredCommit) Hash() Hash { + return sCommit.hash +} + // ObjectType allows Commit to satisfy the Object interface. func (commit *Commit) ObjectType() ObjectType { _ = commit return ObjectTypeCommit } -func parseCommit(id Hash, body []byte, repo *Repository) (*Commit, error) { - c := new(Commit) - c.Hash = id +func parseCommit(id Hash, body []byte, repo *Repository) (*StoredCommit, error) { + c := new(StoredCommit) + c.hash = id i := 0 for i < len(body) { rel := bytes.IndexByte(body[i:], '\n') diff --git a/obj_tag.go b/obj_tag.go index 20088f17..2157e251 100644 --- a/obj_tag.go +++ b/obj_tag.go @@ -6,9 +6,8 @@ import ( "fmt" ) -// Tag models an annotated Git tag object. +// Tag represents an annotated Git tag object. type Tag struct { - Hash Hash Target Hash TargetType ObjectType Name []byte @@ -16,6 +15,17 @@ type Tag struct { Message []byte } +// StoredTag represents a tag stored in the object database. +type StoredTag struct { + Tag + hash Hash +} + +// Hash returns the hash of the stored tag. +func (sTag *StoredTag) Hash() Hash { + return sTag.hash +} + // ObjectType allows Tag to satisfy the Object interface. func (tag *Tag) ObjectType() ObjectType { _ = tag @@ -23,9 +33,9 @@ func (tag *Tag) ObjectType() ObjectType { } // parseTag parses a tag object body. -func parseTag(id Hash, body []byte, repo *Repository) (*Tag, error) { - t := new(Tag) - t.Hash = id +func parseTag(id Hash, body []byte, repo *Repository) (*StoredTag, error) { + t := new(StoredTag) + t.hash = id i := 0 var haveTarget, haveType bool diff --git a/obj_tree.go b/obj_tree.go index 36c98950..eb926832 100644 --- a/obj_tree.go +++ b/obj_tree.go @@ -9,10 +9,20 @@ import ( // Tree represents a Git tree object. type Tree struct { - Hash Hash Entries []TreeEntry } +// StoredTree represents a tree stored in the object database. +type StoredTree struct { + Tree + hash Hash +} + +// Hash returns the hash of the stored tree. +func (sTree *StoredTree) Hash() Hash { + return sTree.hash +} + // TreeEntry represents a single entry in a Git tree. type TreeEntry struct { Mode uint32 @@ -27,7 +37,7 @@ func (tree *Tree) ObjectType() ObjectType { } // parseTree decodes a tree body. -func parseTree(id Hash, body []byte, repo *Repository) (*Tree, error) { +func parseTree(id Hash, body []byte, repo *Repository) (*StoredTree, error) { var entries []TreeEntry i := 0 for i < len(body) { @@ -66,9 +76,11 @@ func parseTree(id Hash, body []byte, repo *Repository) (*Tree, error) { entries = append(entries, entry) } - return &Tree{ - Hash: id, - Entries: entries, + return &StoredTree{ + hash: id, + Tree: Tree{ + Entries: entries, + }, }, nil } diff --git a/objects_test.go b/objects_test.go index 141ba1d7..b191b865 100644 --- a/objects_test.go +++ b/objects_test.go @@ -58,8 +58,8 @@ func TestParseBlobAndSerialize(t *testing.T) { if !bytes.Equal(blob.Data, data) { t.Fatalf("blob data mismatch: %q", blob.Data) } - if blob.Hash != id { - t.Fatalf("blob hash mismatch: %v", blob.Hash) + if blob.Hash() != id { + t.Fatalf("blob hash mismatch: %v", blob.Hash()) } raw, err := blob.Serialize() if err != nil { diff --git a/repo_test.go b/repo_test.go index 4f43f33d..b1b48df4 100644 --- a/repo_test.go +++ b/repo_test.go @@ -37,9 +37,9 @@ func TestOpenRepositoryAndLooseRead(t *testing.T) { if err != nil { t.Fatalf("looseRead error: %v", err) } - blob, ok := obj.(*Blob) + blob, ok := obj.(*StoredBlob) if !ok { - t.Fatalf("expected Blob, got %T", obj) + t.Fatalf("expected StoredBlob, got %T", obj) } if string(blob.Data) != "loose blob payload" { t.Fatalf("blob data mismatch: %q", blob.Data) @@ -225,8 +225,8 @@ func TestWriteLooseObjectAllTypes(t *testing.T) { if err != nil { t.Fatalf("ReadObject Blob error: %v", err) } - if rb, ok := readBlob.(*Blob); !ok { - t.Fatalf("expected Blob, got %T", readBlob) + if rb, ok := readBlob.(*StoredBlob); !ok { + t.Fatalf("expected StoredBlob, got %T", readBlob) } else if string(rb.Data) != "test blob data" { t.Fatalf("blob data mismatch: %q", rb.Data) } @@ -245,8 +245,8 @@ func TestWriteLooseObjectAllTypes(t *testing.T) { if err != nil { t.Fatalf("ReadObject Tree error: %v", err) } - if rt, ok := readTree.(*Tree); !ok { - t.Fatalf("expected Tree, got %T", readTree) + if rt, ok := readTree.(*StoredTree); !ok { + t.Fatalf("expected StoredTree, got %T", readTree) } else if len(rt.Entries) != 1 { t.Fatalf("tree entries mismatch: %d", len(rt.Entries)) } @@ -276,8 +276,8 @@ func TestWriteLooseObjectAllTypes(t *testing.T) { if err != nil { t.Fatalf("ReadObject Commit error: %v", err) } - if rc, ok := readCommit.(*Commit); !ok { - t.Fatalf("expected Commit, got %T", readCommit) + if rc, ok := readCommit.(*StoredCommit); !ok { + t.Fatalf("expected StoredCommit, got %T", readCommit) } else if rc.Tree != treeID { t.Fatalf("commit tree mismatch") } @@ -303,8 +303,8 @@ func TestWriteLooseObjectAllTypes(t *testing.T) { if err != nil { t.Fatalf("ReadObject Tag error: %v", err) } - if rtag, ok := readTag.(*Tag); !ok { - t.Fatalf("expected Tag, got %T", readTag) + if rtag, ok := readTag.(*StoredTag); !ok { + t.Fatalf("expected StoredTag, got %T", readTag) } else if rtag.Target != commitID { t.Fatalf("tag target mismatch") } -- cgit v1.3.1-10-gc9f91