aboutsummaryrefslogtreecommitdiffstats
path: root/storage
diff options
context:
space:
mode:
Diffstat (limited to 'storage')
-rw-r--r--storage/filesystem/object.go73
-rw-r--r--storage/filesystem/object_test.go38
-rw-r--r--storage/memory/storage.go10
3 files changed, 121 insertions, 0 deletions
diff --git a/storage/filesystem/object.go b/storage/filesystem/object.go
index 68bd140..6cd2d4c 100644
--- a/storage/filesystem/object.go
+++ b/storage/filesystem/object.go
@@ -160,6 +160,79 @@ func (s *ObjectStorage) HasEncodedObject(h plumbing.Hash) (err error) {
return nil
}
+func (s *ObjectStorage) encodedObjectSizeFromUnpacked(h plumbing.Hash) (
+ size int64, err error) {
+ f, err := s.dir.Object(h)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return 0, plumbing.ErrObjectNotFound
+ }
+
+ return 0, err
+ }
+
+ r, err := objfile.NewReader(f)
+ if err != nil {
+ return 0, err
+ }
+ defer ioutil.CheckClose(r, &err)
+
+ _, size, err = r.Header()
+ return size, err
+}
+
+func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
+ size int64, err error) {
+ if err := s.requireIndex(); err != nil {
+ return 0, err
+ }
+
+ pack, _, offset := s.findObjectInPackfile(h)
+ if offset == -1 {
+ return 0, plumbing.ErrObjectNotFound
+ }
+
+ f, err := s.dir.ObjectPack(pack)
+ if err != nil {
+ return 0, err
+ }
+ defer ioutil.CheckClose(f, &err)
+
+ idx := s.index[pack]
+ hash, err := idx.FindHash(offset)
+ if err == nil {
+ obj, ok := s.deltaBaseCache.Get(hash)
+ if ok {
+ return obj.Size(), nil
+ }
+ } else if err != nil && err != plumbing.ErrObjectNotFound {
+ return 0, err
+ }
+
+ var p *packfile.Packfile
+ if s.deltaBaseCache != nil {
+ p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.deltaBaseCache)
+ } else {
+ p = packfile.NewPackfile(idx, s.dir.Fs(), f)
+ }
+
+ return p.GetSizeByOffset(offset)
+}
+
+// EncodedObjectSize returns the plaintext size of the given object,
+// without actually reading the full object data from storage.
+func (s *ObjectStorage) EncodedObjectSize(h plumbing.Hash) (
+ size int64, err error) {
+ size, err = s.encodedObjectSizeFromUnpacked(h)
+ if err != nil && err != plumbing.ErrObjectNotFound {
+ return 0, err
+ } else if err == nil {
+ return size, nil
+ }
+
+ return s.encodedObjectSizeFromPackfile(h)
+}
+
// EncodedObject returns the object with the given hash, by searching for it in
// the packfile and the git object directories.
func (s *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) {
diff --git a/storage/filesystem/object_test.go b/storage/filesystem/object_test.go
index 407abf2..4e6bbfb 100644
--- a/storage/filesystem/object_test.go
+++ b/storage/filesystem/object_test.go
@@ -83,6 +83,44 @@ func (s *FsSuite) TestGetFromPackfileKeepDescriptors(c *C) {
})
}
+func (s *FsSuite) TestGetSizeOfObjectFile(c *C) {
+ fs := fixtures.ByTag(".git").ByTag("unpacked").One().DotGit()
+ o := NewObjectStorage(dotgit.New(fs), cache.NewObjectLRUDefault())
+
+ // Get the size of `tree_walker.go`.
+ expected := plumbing.NewHash("cbd81c47be12341eb1185b379d1c82675aeded6a")
+ size, err := o.EncodedObjectSize(expected)
+ c.Assert(err, IsNil)
+ c.Assert(size, Equals, int64(2412))
+}
+
+func (s *FsSuite) TestGetSizeFromPackfile(c *C) {
+ fixtures.Basic().ByTag(".git").Test(c, func(f *fixtures.Fixture) {
+ fs := f.DotGit()
+ o := NewObjectStorage(dotgit.New(fs), cache.NewObjectLRUDefault())
+
+ // Get the size of `binary.jpg`.
+ expected := plumbing.NewHash("d5c0f4ab811897cadf03aec358ae60d21f91c50d")
+ size, err := o.EncodedObjectSize(expected)
+ c.Assert(err, IsNil)
+ c.Assert(size, Equals, int64(76110))
+ })
+}
+
+func (s *FsSuite) TestGetSizeOfAllObjectFiles(c *C) {
+ fs := fixtures.ByTag(".git").One().DotGit()
+ o := NewObjectStorage(dotgit.New(fs), cache.NewObjectLRUDefault())
+
+ // Get the size of `tree_walker.go`.
+ err := o.ForEachObjectHash(func(h plumbing.Hash) error {
+ size, err := o.EncodedObjectSize(h)
+ c.Assert(err, IsNil)
+ c.Assert(size, Not(Equals), int64(0))
+ return nil
+ })
+ c.Assert(err, IsNil)
+}
+
func (s *FsSuite) TestGetFromPackfileMultiplePackfiles(c *C) {
fs := fixtures.ByTag(".git").ByTag("multi-packfile").One().DotGit()
o := NewObjectStorage(dotgit.New(fs), cache.NewObjectLRUDefault())
diff --git a/storage/memory/storage.go b/storage/memory/storage.go
index 2e32509..6e11742 100644
--- a/storage/memory/storage.go
+++ b/storage/memory/storage.go
@@ -122,6 +122,16 @@ func (o *ObjectStorage) HasEncodedObject(h plumbing.Hash) (err error) {
return nil
}
+func (o *ObjectStorage) EncodedObjectSize(h plumbing.Hash) (
+ size int64, err error) {
+ obj, ok := o.Objects[h]
+ if !ok {
+ return 0, plumbing.ErrObjectNotFound
+ }
+
+ return obj.Size(), nil
+}
+
func (o *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) {
obj, ok := o.Objects[h]
if !ok || (plumbing.AnyObject != t && obj.Type() != t) {