diff options
-rw-r--r-- | plumbing/storer/object.go | 5 | ||||
-rw-r--r-- | plumbing/storer/object_test.go | 4 | ||||
-rw-r--r-- | repository.go | 62 | ||||
-rw-r--r-- | storage/filesystem/internal/dotgit/dotgit.go | 34 | ||||
-rw-r--r-- | storage/filesystem/object.go | 8 | ||||
-rw-r--r-- | storage/memory/storage.go | 7 |
6 files changed, 107 insertions, 13 deletions
diff --git a/plumbing/storer/object.go b/plumbing/storer/object.go index bd34be8..29e0090 100644 --- a/plumbing/storer/object.go +++ b/plumbing/storer/object.go @@ -52,6 +52,11 @@ type EncodedObjectStorer interface { LooseObjectTime(plumbing.Hash) (time.Time, error) // DeleteLooseObject deletes a loose object if it exists. DeleteLooseObject(plumbing.Hash) error + // ObjectPacks returns hashes of object packs if the underlying + // implementation has pack files. + ObjectPacks() ([]plumbing.Hash, error) + // DeleteObjectPackAndIndex deletes an object pack and the corresponding index file if they exist. + DeleteObjectPackAndIndex(plumbing.Hash) error } // DeltaObjectStorer is an EncodedObjectStorer that can return delta diff --git a/plumbing/storer/object_test.go b/plumbing/storer/object_test.go index f8b1f73..68e8e10 100644 --- a/plumbing/storer/object_test.go +++ b/plumbing/storer/object_test.go @@ -161,3 +161,7 @@ func (o *MockObjectStorage) LooseObjectTime(plumbing.Hash) (time.Time, error) { func (o *MockObjectStorage) DeleteLooseObject(plumbing.Hash) error { return plumbing.ErrObjectNotFound } + +func (o *MockObjectStorage) ObjectPacks() ([]plumbing.Hash, error) { + return nil, nil +} diff --git a/repository.go b/repository.go index b159ff0..51cd077 100644 --- a/repository.go +++ b/repository.go @@ -12,6 +12,7 @@ import ( "gopkg.in/src-d/go-git.v4/config" "gopkg.in/src-d/go-git.v4/internal/revision" "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/format/packfile" "gopkg.in/src-d/go-git.v4/plumbing/object" "gopkg.in/src-d/go-git.v4/plumbing/storer" "gopkg.in/src-d/go-git.v4/storage" @@ -1011,3 +1012,64 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err return &commit.Hash, nil } + +func (r *Repository) RepackObjects() (err error) { + // Get the existing object packs. + hs, err := r.Storer.ObjectPacks() + if err != nil { + return err + } + + // Create a new pack. + nh, err := r.createNewObjectPack() + if err != nil { + return err + } + + // Delete old packs. + for _, h := range hs { + // Skip if new hash is the same as an old one. + if h == nh { + continue + } + err = r.Storer.DeleteObjectPackAndIndex(h) + if err != nil { + return err + } + } + + return nil +} + +// createNewObjectPack is a helper for RepackObjects taking care +// of creating a new pack. It is used so the the PackfileWriter +// deferred close has the right scope. +func (r *Repository) createNewObjectPack() (h plumbing.Hash, err error) { + pfw, ok := r.Storer.(storer.PackfileWriter) + if !ok { + return h, fmt.Errorf("Repository storer is not a storer.PackfileWriter") + } + wc, err := pfw.PackfileWriter(nil) + if err != nil { + return h, err + } + defer ioutil.CheckClose(wc, &err) + var objs []plumbing.Hash + iter, err := r.Storer.IterEncodedObjects(plumbing.AnyObject) + if err != nil { + return h, err + } + err = iter.ForEach(func(obj plumbing.EncodedObject) error { + objs = append(objs, obj.Hash()) + return nil + }) + if err != nil { + return h, err + } + enc := packfile.NewEncoder(wc, r.Storer, false) + h, err = enc.Encode(objs, 10, nil) + if err != nil { + return h, err + } + return h, err +} diff --git a/storage/filesystem/internal/dotgit/dotgit.go b/storage/filesystem/internal/dotgit/dotgit.go index 83fe159..09688c1 100644 --- a/storage/filesystem/internal/dotgit/dotgit.go +++ b/storage/filesystem/internal/dotgit/dotgit.go @@ -166,11 +166,12 @@ func (d *DotGit) ObjectPacks() ([]plumbing.Hash, error) { return packs, nil } -// ObjectPack returns a fs.File of the given packfile -func (d *DotGit) ObjectPack(hash plumbing.Hash) (billy.File, error) { - file := d.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s.pack", hash.String())) +func (d *DotGit) objectPackPath(hash plumbing.Hash, extension string) string { + return d.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s.%s", hash.String(), extension)) +} - pack, err := d.fs.Open(file) +func (d *DotGit) objectPackOpen(hash plumbing.Hash, extension string) (billy.File, error) { + pack, err := d.fs.Open(d.objectPackPath(hash, extension)) if err != nil { if os.IsNotExist(err) { return nil, ErrPackfileNotFound @@ -182,19 +183,26 @@ func (d *DotGit) ObjectPack(hash plumbing.Hash) (billy.File, error) { return pack, nil } +// ObjectPack returns a fs.File of the given packfile +func (d *DotGit) ObjectPack(hash plumbing.Hash) (billy.File, error) { + return d.objectPackOpen(hash, `pack`) +} + // ObjectPackIdx returns a fs.File of the index file for a given packfile func (d *DotGit) ObjectPackIdx(hash plumbing.Hash) (billy.File, error) { - file := d.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s.idx", hash.String())) - idx, err := d.fs.Open(file) - if err != nil { - if os.IsNotExist(err) { - return nil, ErrPackfileNotFound - } + return d.objectPackOpen(hash, `idx`) +} - return nil, err +func (d *DotGit) DeleteObjectPackAndIndex(hash plumbing.Hash) error { + err := d.fs.Remove(d.objectPackPath(hash, `pack`)) + if err != nil { + return err } - - return idx, nil + err = d.fs.Remove(d.objectPackPath(hash, `idx`)) + if err != nil { + return err + } + return nil } // NewObject return a writer for a new object file. diff --git a/storage/filesystem/object.go b/storage/filesystem/object.go index 9b2790f..f235204 100644 --- a/storage/filesystem/object.go +++ b/storage/filesystem/object.go @@ -503,3 +503,11 @@ func (s *ObjectStorage) LooseObjectTime(hash plumbing.Hash) (time.Time, error) { func (s *ObjectStorage) DeleteLooseObject(hash plumbing.Hash) error { return s.dir.ObjectDelete(hash) } + +func (s *ObjectStorage) ObjectPacks() ([]plumbing.Hash, error) { + return s.dir.ObjectPacks() +} + +func (s *ObjectStorage) DeleteObjectPackAndIndex(h plumbing.Hash) error { + return s.dir.DeleteObjectPackAndIndex(h) +} diff --git a/storage/memory/storage.go b/storage/memory/storage.go index bfcad34..5049036 100644 --- a/storage/memory/storage.go +++ b/storage/memory/storage.go @@ -170,6 +170,13 @@ func (o *ObjectStorage) ForEachObjectHash(fun func(plumbing.Hash) error) error { return nil } +func (o *ObjectStorage) ObjectPacks() ([]plumbing.Hash, error) { + return nil, nil +} +func (o *ObjectStorage) DeleteObjectPackAndIndex(plumbing.Hash) error { + return errNotSupported +} + var errNotSupported = fmt.Errorf("Not supported") func (s *ObjectStorage) LooseObjectTime(hash plumbing.Hash) (time.Time, error) { |