diff options
| author | 2026-02-20 19:06:13 +0800 | |
|---|---|---|
| committer | 2026-02-20 19:07:14 +0800 | |
| commit | aa513c069c1418734aea894dc944e27c6a78a3bb (patch) | |
| tree | 687f0a11bb550fa088fd82a98ceb8979bbc35f69 /obj.go | |
| parent | Comment on prior reverts removing the pack writing API (diff) | |
| signature | No signature | |
Delete everything, I'm redesigning this.
I'll stop using a flat package and make things much more modular.
And also experiment with streaming APIs so large blobs don't OOM us.
Diffstat (limited to 'obj.go')
| -rw-r--r-- | obj.go | 168 |
1 files changed, 0 insertions, 168 deletions
diff --git a/obj.go b/obj.go deleted file mode 100644 index f3ed8bfa..00000000 --- a/obj.go +++ /dev/null @@ -1,168 +0,0 @@ -package furgit - -import ( - "bytes" - "errors" - "fmt" - "strconv" -) - -// ObjectType mirrors Git's object type tags. -type ObjectType uint8 - -const ( - // An invalid object. - ObjectTypeInvalid ObjectType = 0 - // A commit object. - ObjectTypeCommit ObjectType = 1 - // A tree object. - ObjectTypeTree ObjectType = 2 - // A blob object. - ObjectTypeBlob ObjectType = 3 - // An annotated tag object. - ObjectTypeTag ObjectType = 4 - // An object type reserved for future use. - ObjectTypeFuture ObjectType = 5 - // A packfile offset delta object. This is not typically exposed. - ObjectTypeOfsDelta ObjectType = 6 - // A packfile reference delta object. This is not typically exposed. - ObjectTypeRefDelta ObjectType = 7 -) - -const ( - objectTypeNameBlob = "blob" - objectTypeNameTree = "tree" - objectTypeNameCommit = "commit" - objectTypeNameTag = "tag" -) - -// Object represents a Git object. -type Object interface { - // ObjectType returns the object's type. - ObjectType() ObjectType - // Serialize renders the object into its raw byte representation, - // including the header (i.e., "type size\0"). - Serialize() ([]byte, error) -} - -// StoredObject describes a Git object with a known hash, such as -// one read from storage. -type StoredObject interface { - Object - // Hash returns the object's hash. - Hash() Hash -} - -func headerForType(ty ObjectType, body []byte) ([]byte, error) { - var tyStr string - switch ty { - case ObjectTypeBlob: - tyStr = objectTypeNameBlob - case ObjectTypeTree: - tyStr = objectTypeNameTree - case ObjectTypeCommit: - tyStr = objectTypeNameCommit - case ObjectTypeTag: - tyStr = objectTypeNameTag - case ObjectTypeInvalid, ObjectTypeFuture, ObjectTypeOfsDelta, ObjectTypeRefDelta: - return nil, fmt.Errorf("furgit: object: unsupported type %d", ty) - default: - return nil, fmt.Errorf("furgit: object: unsupported type %d", ty) - } - size := strconv.Itoa(len(body)) - var buf bytes.Buffer - buf.Grow(len(tyStr) + len(size) + 1) - buf.WriteString(tyStr) - buf.WriteByte(' ') - buf.WriteString(size) - buf.WriteByte(0) - return buf.Bytes(), nil -} - -func parseObjectBody(ty ObjectType, id Hash, body []byte, repo *Repository) (StoredObject, error) { - switch ty { - case ObjectTypeBlob: - return parseBlob(id, body) - case ObjectTypeTree: - return parseTree(id, body, repo) - case ObjectTypeCommit: - return parseCommit(id, body, repo) - case ObjectTypeTag: - return parseTag(id, body, repo) - case ObjectTypeInvalid, ObjectTypeFuture, ObjectTypeOfsDelta, ObjectTypeRefDelta: - return nil, fmt.Errorf("furgit: object: unsupported type %d", ty) - default: - return nil, fmt.Errorf("furgit: object: unknown type %d", ty) - } -} - -// ReadObject resolves an ID. -func (repo *Repository) ReadObject(id Hash) (StoredObject, error) { - ty, body, err := repo.looseRead(id) - if err == nil { - obj, parseErr := parseObjectBody(ty, id, body.Bytes(), repo) - body.Release() - return obj, parseErr - } - if !errors.Is(err, ErrNotFound) { - return nil, err - } - ty, body, err = repo.packRead(id) - if errors.Is(err, ErrNotFound) { - return nil, ErrNotFound - } - if err != nil { - return nil, err - } - obj, parseErr := parseObjectBody(ty, id, body.Bytes(), repo) - body.Release() - return obj, parseErr -} - -// ReadObjectTypeRaw reads the object type and raw body. -func (repo *Repository) ReadObjectTypeRaw(id Hash) (ObjectType, []byte, error) { - ty, body, err := repo.looseRead(id) - if err == nil { - return ty, body.Bytes(), nil - } - if !errors.Is(err, ErrNotFound) { - return ObjectTypeInvalid, nil, err - } - ty, body, err = repo.packRead(id) - if errors.Is(err, ErrNotFound) { - return ObjectTypeInvalid, nil, ErrNotFound - } - if err != nil { - return ObjectTypeInvalid, nil, err - } - return ty, body.Bytes(), nil - // note to self: It always feels wrong to not call .Release in places like - // this but this is actually correct; we're returning the underlying buffer - // to the user who should not be aware of our internal buffer pooling. - // Releasing this buffer back to the pool would lead to a use-after-free; - // not releasing it as we do here, means it gets GC'ed. - // Copying into a newly allocated buffer is even worse as it incurs - // unnecessary copy overhead. -} - -// ReadObjectTypeSize reports the object type and size. -// -// Typicall, this is more efficient than reading the full object, -// as it avoids decompressing the entire object body. -func (repo *Repository) ReadObjectTypeSize(id Hash) (ObjectType, int64, error) { - ty, size, err := repo.looseTypeSize(id) - if err == nil { - return ty, size, nil - } - if !errors.Is(err, ErrNotFound) { - return ObjectTypeInvalid, 0, err - } - loc, err := repo.packIndexFind(id) - if err != nil { - if errors.Is(err, ErrNotFound) { - return ObjectTypeInvalid, 0, ErrInvalidObject - } - return ObjectTypeInvalid, 0, err - } - return repo.packTypeSizeAtLocation(loc, nil) -} |
