You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
3.3 KiB
145 lines
3.3 KiB
6 years ago
|
package object
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
||
|
"gopkg.in/src-d/go-git.v4/plumbing/storer"
|
||
|
"gopkg.in/src-d/go-git.v4/utils/ioutil"
|
||
|
)
|
||
|
|
||
|
// Blob is used to store arbitrary data - it is generally a file.
|
||
|
type Blob struct {
|
||
|
// Hash of the blob.
|
||
|
Hash plumbing.Hash
|
||
|
// Size of the (uncompressed) blob.
|
||
|
Size int64
|
||
|
|
||
|
obj plumbing.EncodedObject
|
||
|
}
|
||
|
|
||
|
// GetBlob gets a blob from an object storer and decodes it.
|
||
|
func GetBlob(s storer.EncodedObjectStorer, h plumbing.Hash) (*Blob, error) {
|
||
|
o, err := s.EncodedObject(plumbing.BlobObject, h)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return DecodeBlob(o)
|
||
|
}
|
||
|
|
||
|
// DecodeObject decodes an encoded object into a *Blob.
|
||
|
func DecodeBlob(o plumbing.EncodedObject) (*Blob, error) {
|
||
|
b := &Blob{}
|
||
|
if err := b.Decode(o); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return b, nil
|
||
|
}
|
||
|
|
||
|
// ID returns the object ID of the blob. The returned value will always match
|
||
|
// the current value of Blob.Hash.
|
||
|
//
|
||
|
// ID is present to fulfill the Object interface.
|
||
|
func (b *Blob) ID() plumbing.Hash {
|
||
|
return b.Hash
|
||
|
}
|
||
|
|
||
|
// Type returns the type of object. It always returns plumbing.BlobObject.
|
||
|
//
|
||
|
// Type is present to fulfill the Object interface.
|
||
|
func (b *Blob) Type() plumbing.ObjectType {
|
||
|
return plumbing.BlobObject
|
||
|
}
|
||
|
|
||
|
// Decode transforms a plumbing.EncodedObject into a Blob struct.
|
||
|
func (b *Blob) Decode(o plumbing.EncodedObject) error {
|
||
|
if o.Type() != plumbing.BlobObject {
|
||
|
return ErrUnsupportedObject
|
||
|
}
|
||
|
|
||
|
b.Hash = o.Hash()
|
||
|
b.Size = o.Size()
|
||
|
b.obj = o
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Encode transforms a Blob into a plumbing.EncodedObject.
|
||
|
func (b *Blob) Encode(o plumbing.EncodedObject) (err error) {
|
||
|
o.SetType(plumbing.BlobObject)
|
||
|
|
||
|
w, err := o.Writer()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
defer ioutil.CheckClose(w, &err)
|
||
|
|
||
|
r, err := b.Reader()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
defer ioutil.CheckClose(r, &err)
|
||
|
|
||
|
_, err = io.Copy(w, r)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Reader returns a reader allow the access to the content of the blob
|
||
|
func (b *Blob) Reader() (io.ReadCloser, error) {
|
||
|
return b.obj.Reader()
|
||
|
}
|
||
|
|
||
|
// BlobIter provides an iterator for a set of blobs.
|
||
|
type BlobIter struct {
|
||
|
storer.EncodedObjectIter
|
||
|
s storer.EncodedObjectStorer
|
||
|
}
|
||
|
|
||
|
// NewBlobIter takes a storer.EncodedObjectStorer and a
|
||
|
// storer.EncodedObjectIter and returns a *BlobIter that iterates over all
|
||
|
// blobs contained in the storer.EncodedObjectIter.
|
||
|
//
|
||
|
// Any non-blob object returned by the storer.EncodedObjectIter is skipped.
|
||
|
func NewBlobIter(s storer.EncodedObjectStorer, iter storer.EncodedObjectIter) *BlobIter {
|
||
|
return &BlobIter{iter, s}
|
||
|
}
|
||
|
|
||
|
// Next moves the iterator to the next blob and returns a pointer to it. If
|
||
|
// there are no more blobs, it returns io.EOF.
|
||
|
func (iter *BlobIter) Next() (*Blob, error) {
|
||
|
for {
|
||
|
obj, err := iter.EncodedObjectIter.Next()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if obj.Type() != plumbing.BlobObject {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
return DecodeBlob(obj)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ForEach call the cb function for each blob contained on this iter until
|
||
|
// an error happens or the end of the iter is reached. If ErrStop is sent
|
||
|
// the iteration is stop but no error is returned. The iterator is closed.
|
||
|
func (iter *BlobIter) ForEach(cb func(*Blob) error) error {
|
||
|
return iter.EncodedObjectIter.ForEach(func(obj plumbing.EncodedObject) error {
|
||
|
if obj.Type() != plumbing.BlobObject {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
b, err := DecodeBlob(obj)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return cb(b)
|
||
|
})
|
||
|
}
|