2018-11-27 21:52:20 +00:00
|
|
|
package packfile
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
|
|
|
|
billy "gopkg.in/src-d/go-billy.v4"
|
|
|
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
|
|
|
"gopkg.in/src-d/go-git.v4/plumbing/cache"
|
|
|
|
"gopkg.in/src-d/go-git.v4/plumbing/format/idxfile"
|
|
|
|
)
|
|
|
|
|
|
|
|
// FSObject is an object from the packfile on the filesystem.
|
|
|
|
type FSObject struct {
|
|
|
|
hash plumbing.Hash
|
|
|
|
h *ObjectHeader
|
|
|
|
offset int64
|
|
|
|
size int64
|
|
|
|
typ plumbing.ObjectType
|
|
|
|
index idxfile.Index
|
|
|
|
fs billy.Filesystem
|
|
|
|
path string
|
|
|
|
cache cache.Object
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewFSObject creates a new filesystem object.
|
|
|
|
func NewFSObject(
|
|
|
|
hash plumbing.Hash,
|
|
|
|
finalType plumbing.ObjectType,
|
|
|
|
offset int64,
|
|
|
|
contentSize int64,
|
|
|
|
index idxfile.Index,
|
|
|
|
fs billy.Filesystem,
|
|
|
|
path string,
|
|
|
|
cache cache.Object,
|
|
|
|
) *FSObject {
|
|
|
|
return &FSObject{
|
|
|
|
hash: hash,
|
|
|
|
offset: offset,
|
|
|
|
size: contentSize,
|
|
|
|
typ: finalType,
|
|
|
|
index: index,
|
|
|
|
fs: fs,
|
|
|
|
path: path,
|
|
|
|
cache: cache,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reader implements the plumbing.EncodedObject interface.
|
|
|
|
func (o *FSObject) Reader() (io.ReadCloser, error) {
|
|
|
|
obj, ok := o.cache.Get(o.hash)
|
2019-04-17 02:04:23 +00:00
|
|
|
if ok && obj != o {
|
2018-11-27 21:52:20 +00:00
|
|
|
reader, err := obj.Reader()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return reader, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
f, err := o.fs.Open(o.path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
p := NewPackfileWithCache(o.index, nil, f, o.cache)
|
|
|
|
r, err := p.getObjectContent(o.offset)
|
|
|
|
if err != nil {
|
|
|
|
_ = f.Close()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := f.Close(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return r, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetSize implements the plumbing.EncodedObject interface. This method
|
|
|
|
// is a noop.
|
|
|
|
func (o *FSObject) SetSize(int64) {}
|
|
|
|
|
|
|
|
// SetType implements the plumbing.EncodedObject interface. This method is
|
|
|
|
// a noop.
|
|
|
|
func (o *FSObject) SetType(plumbing.ObjectType) {}
|
|
|
|
|
|
|
|
// Hash implements the plumbing.EncodedObject interface.
|
|
|
|
func (o *FSObject) Hash() plumbing.Hash { return o.hash }
|
|
|
|
|
|
|
|
// Size implements the plumbing.EncodedObject interface.
|
|
|
|
func (o *FSObject) Size() int64 { return o.size }
|
|
|
|
|
|
|
|
// Type implements the plumbing.EncodedObject interface.
|
|
|
|
func (o *FSObject) Type() plumbing.ObjectType {
|
|
|
|
return o.typ
|
|
|
|
}
|
|
|
|
|
|
|
|
// Writer implements the plumbing.EncodedObject interface. This method always
|
|
|
|
// returns a nil writer.
|
|
|
|
func (o *FSObject) Writer() (io.WriteCloser, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type objectReader struct {
|
|
|
|
io.ReadCloser
|
|
|
|
f billy.File
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *objectReader) Close() error {
|
|
|
|
if err := r.ReadCloser.Close(); err != nil {
|
|
|
|
_ = r.f.Close()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return r.f.Close()
|
|
|
|
}
|