1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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 (fetcher *Fetcher) ExactBlob(id oid.ObjectID) (*stored.Stored[*blob.Blob], error) {
parsed, err := fetcher.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.Blob}
}
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 (fetcher *Fetcher) ExactBlobReader(id oid.ObjectID) (io.ReadCloser, int, error) {
return fetcher.exactReader(id, typ.Blob)
}
// PeelToBlob peels tags until it reaches a blob.
//
// Labels: Life-Parent.
func (fetcher *Fetcher) PeelToBlob(id oid.ObjectID) (*stored.Stored[*blob.Blob], error) {
for {
obj, err := fetcher.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.Blob}
}
}
}
// PeelToBlobID peels tags until it reaches a blob object ID.
func (fetcher *Fetcher) PeelToBlobID(id oid.ObjectID) (oid.ObjectID, error) {
for {
ty, _, err := fetcher.Header(id)
if err != nil {
return oid.ObjectID{}, err
}
switch ty {
case typ.Blob:
return id, nil
case typ.Tag:
tag, err := fetcher.ExactTag(id)
if err != nil {
return oid.ObjectID{}, err
}
id = tag.Object().TargetID
case typ.Unknown, typ.Commit, typ.Tree:
return oid.ObjectID{}, &errs.ObjectTypeError{OID: id, Got: ty, Want: typ.Blob}
default:
return oid.ObjectID{}, &errs.ObjectTypeError{OID: id, Got: ty, Want: typ.Blob}
}
}
}
// 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 (fetcher *Fetcher) PeelToBlobReader(id oid.ObjectID) (io.ReadCloser, int, error) {
blobID, err := fetcher.PeelToBlobID(id)
if err != nil {
return nil, 0, err
}
return fetcher.ExactBlobReader(blobID)
}
|