diff options
| author | 2026-06-08 07:03:38 +0000 | |
|---|---|---|
| committer | 2026-06-08 07:03:38 +0000 | |
| commit | ca96826ecc39c463f43039fc78d362fde97ce20c (patch) | |
| tree | 35df2332e6cc53594f84ac3fc2b4eca7f5e81881 /object/fetch | |
| parent | object/fetch: Begin by adding package doc (diff) | |
object/fetch: Finish blob
Diffstat (limited to 'object/fetch')
| -rw-r--r-- | object/fetch/blob.go | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/object/fetch/blob.go b/object/fetch/blob.go new file mode 100644 index 00000000..ee5bae1c --- /dev/null +++ b/object/fetch/blob.go @@ -0,0 +1,97 @@ +package fetch + +import ( + "io" + + "lindenii.org/go/furgit/errs" + "lindenii.org/go/furgit/object/blob" + oid "lindenii.org/go/furgit/object/id" + "lindenii.org/go/furgit/object/stored" + "lindenii.org/go/furgit/object/tag" + "lindenii.org/go/furgit/object/typ" +) + +// ExactBlob reads, parses, and wraps the blob at id. +// +// Labels: Life-Parent. +func (r *Fetcher) ExactBlob(id oid.ObjectID) (*stored.Stored[*blob.Blob], error) { + parsed, err := r.parseObject(id) + if err != nil { + return nil, err + } + + blob, ok := parsed.(*blob.Blob) + if !ok { + return nil, &errs.ObjectTypeError{OID: id, Got: parsed.ObjectType(), Want: typ.TypeBlob} + } + + return stored.New(id, blob), nil +} + +// ExactBlobReader returns a reader for the content of the blob at id, +// together with its content size in bytes. +// +// Labels: Life-Parent, Close-Caller. +func (r *Fetcher) ExactBlobReader(id oid.ObjectID) (io.ReadCloser, int64, error) { + return r.exactReader(id, typ.TypeBlob) +} + +// PeelToBlob peels tags until it reaches a blob. +// +// Labels: Life-Parent. +func (r *Fetcher) PeelToBlob(id oid.ObjectID) (*stored.Stored[*blob.Blob], error) { + for { + obj, err := r.ExactObject(id) + if err != nil { + return nil, err + } + + switch parsed := obj.Object().(type) { + case *blob.Blob: + return stored.New(id, parsed), nil + case *tag.Tag: + id = parsed.TargetID + default: + return nil, &errs.ObjectTypeError{OID: id, Got: parsed.ObjectType(), Want: typ.TypeBlob} + } + } +} + +// PeelToBlobID peels tags until it reaches a blob object ID. +func (r *Fetcher) PeelToBlobID(id oid.ObjectID) (oid.ObjectID, error) { + for { + ty, _, err := r.Header(id) + if err != nil { + return oid.ObjectID{}, err + } + + switch ty { + case typ.TypeBlob: + return id, nil + case typ.TypeTag: + tag, err := r.ExactTag(id) + if err != nil { + return oid.ObjectID{}, err + } + + id = tag.Object().TargetID + case typ.TypeUnknown, typ.TypeCommit, typ.TypeTree: + return oid.ObjectID{}, &errs.ObjectTypeError{OID: id, Got: ty, Want: typ.TypeBlob} + default: + return oid.ObjectID{}, &errs.ObjectTypeError{OID: id, Got: ty, Want: typ.TypeBlob} + } + } +} + +// PeelToBlobReader returns a reader for the content of the peeled blob at id, +// together with its content size in bytes. +// +// Labels: Life-Parent, Close-Caller. +func (r *Fetcher) PeelToBlobReader(id oid.ObjectID) (io.ReadCloser, int64, error) { + blobID, err := r.PeelToBlobID(id) + if err != nil { + return nil, 0, err + } + + return r.ExactBlobReader(blobID) +} |
