aboutsummaryrefslogtreecommitdiffstats
path: root/storage
diff options
context:
space:
mode:
Diffstat (limited to 'storage')
-rw-r--r--storage/filesystem/internal/dotgit/dotgit.go92
-rw-r--r--storage/filesystem/internal/dotgit/dotgit_test.go99
-rw-r--r--storage/filesystem/reference.go4
-rw-r--r--storage/memory/storage.go14
-rw-r--r--storage/storer.go3
-rw-r--r--storage/test/storage_suite.go32
6 files changed, 225 insertions, 19 deletions
diff --git a/storage/filesystem/internal/dotgit/dotgit.go b/storage/filesystem/internal/dotgit/dotgit.go
index 360b3d1..b46f827 100644
--- a/storage/filesystem/internal/dotgit/dotgit.go
+++ b/storage/filesystem/internal/dotgit/dotgit.go
@@ -5,11 +5,12 @@ import (
"bufio"
"errors"
"fmt"
- "io/ioutil"
+ stdioutil "io/ioutil"
"os"
"strings"
"srcd.works/go-git.v4/plumbing"
+ "srcd.works/go-git.v4/utils/ioutil"
"srcd.works/go-billy.v1"
)
@@ -25,6 +26,8 @@ const (
packPath = "pack"
refsPath = "refs"
+ tmpPackedRefsPrefix = "._packed-refs"
+
packExt = ".pack"
idxExt = ".idx"
)
@@ -269,6 +272,21 @@ func (d *DotGit) Ref(name plumbing.ReferenceName) (*plumbing.Reference, error) {
return nil, plumbing.ErrReferenceNotFound
}
+// RemoveRef removes a reference by name.
+func (d *DotGit) RemoveRef(name plumbing.ReferenceName) error {
+ path := d.fs.Join(".", name.String())
+ _, err := d.fs.Stat(path)
+ if err == nil {
+ return d.fs.Remove(path)
+ }
+
+ if err != nil && !os.IsNotExist(err) {
+ return err
+ }
+
+ return d.rewritePackedRefsWithoutRef(name)
+}
+
func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference) (err error) {
f, err := d.fs.Open(packedRefsPath)
if err != nil {
@@ -277,12 +295,7 @@ func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference) (err error)
}
return err
}
-
- defer func() {
- if errClose := f.Close(); err == nil {
- err = errClose
- }
- }()
+ defer ioutil.CheckClose(f, &err)
s := bufio.NewScanner(f)
for s.Scan() {
@@ -299,8 +312,64 @@ func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference) (err error)
return s.Err()
}
+func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err error) {
+ f, err := d.fs.Open(packedRefsPath)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil
+ }
+
+ return err
+ }
+ defer ioutil.CheckClose(f, &err)
+
+ // Creating the temp file in the same directory as the target file
+ // improves our chances for rename operation to be atomic.
+ tmp, err := d.fs.TempFile("", tmpPackedRefsPrefix)
+ if err != nil {
+ return err
+ }
+
+ tmpPath := tmp.Filename()
+ defer ioutil.CheckClose(tmp, &err)
+ defer d.fs.Remove(tmpPath)
+
+ s := bufio.NewScanner(f)
+ found := false
+ for s.Scan() {
+ line := s.Text()
+ ref, err := d.processLine(line)
+ if err != nil {
+ return err
+ }
+
+ if ref != nil && ref.Name() == name {
+ found = true
+ continue
+ }
+
+ if _, err := fmt.Fprintln(tmp, line); err != nil {
+ return err
+ }
+ }
+
+ if err := s.Err(); err != nil {
+ return err
+ }
+
+ if !found {
+ return nil
+ }
+
+ return d.fs.Rename(tmpPath, packedRefsPath)
+}
+
// process lines from a packed-refs file
func (d *DotGit) processLine(line string) (*plumbing.Reference, error) {
+ if len(line) == 0 {
+ return nil, nil
+ }
+
switch line[0] {
case '#': // comment - ignore
return nil, nil
@@ -374,14 +443,9 @@ func (d *DotGit) readReferenceFile(refsPath, refFile string) (ref *plumbing.Refe
if err != nil {
return nil, err
}
+ defer ioutil.CheckClose(f, &err)
- defer func() {
- if errClose := f.Close(); err == nil {
- err = errClose
- }
- }()
-
- b, err := ioutil.ReadAll(f)
+ b, err := stdioutil.ReadAll(f)
if err != nil {
return nil, err
}
diff --git a/storage/filesystem/internal/dotgit/dotgit_test.go b/storage/filesystem/internal/dotgit/dotgit_test.go
index a335e5f..57dfb53 100644
--- a/storage/filesystem/internal/dotgit/dotgit_test.go
+++ b/storage/filesystem/internal/dotgit/dotgit_test.go
@@ -1,6 +1,7 @@
package dotgit
import (
+ "bufio"
"io/ioutil"
"os"
"path/filepath"
@@ -108,6 +109,96 @@ func (s *SuiteDotGit) TestRefsFromReferenceFile(c *C) {
}
+func (s *SuiteDotGit) TestRemoveRefFromReferenceFile(c *C) {
+ fs := fixtures.Basic().ByTag(".git").One().DotGit()
+ dir := New(fs)
+
+ name := plumbing.ReferenceName("refs/remotes/origin/HEAD")
+ err := dir.RemoveRef(name)
+ c.Assert(err, IsNil)
+
+ refs, err := dir.Refs()
+ c.Assert(err, IsNil)
+
+ ref := findReference(refs, string(name))
+ c.Assert(ref, IsNil)
+}
+
+func (s *SuiteDotGit) TestRemoveRefFromPackedRefs(c *C) {
+ fs := fixtures.Basic().ByTag(".git").One().DotGit()
+ dir := New(fs)
+
+ name := plumbing.ReferenceName("refs/remotes/origin/master")
+ err := dir.RemoveRef(name)
+ c.Assert(err, IsNil)
+
+ b, err := ioutil.ReadFile(filepath.Join(fs.Base(), packedRefsPath))
+ c.Assert(err, IsNil)
+
+ c.Assert(string(b), Equals, ""+
+ "# pack-refs with: peeled fully-peeled \n"+
+ "6ecf0ef2c2dffb796033e5a02219af86ec6584e5 refs/heads/master\n"+
+ "e8d3ffab552895c19b9fcf7aa264d277cde33881 refs/remotes/origin/branch\n")
+}
+
+func (s *SuiteDotGit) TestRemoveRefNonExistent(c *C) {
+ fs := fixtures.Basic().ByTag(".git").One().DotGit()
+ dir := New(fs)
+
+ packedRefs := filepath.Join(fs.Base(), packedRefsPath)
+ before, err := ioutil.ReadFile(packedRefs)
+ c.Assert(err, IsNil)
+
+ name := plumbing.ReferenceName("refs/heads/nonexistent")
+ err = dir.RemoveRef(name)
+ c.Assert(err, IsNil)
+
+ after, err := ioutil.ReadFile(packedRefs)
+ c.Assert(err, IsNil)
+
+ c.Assert(string(before), Equals, string(after))
+}
+
+func (s *SuiteDotGit) TestRemoveRefInvalidPackedRefs(c *C) {
+ fs := fixtures.Basic().ByTag(".git").One().DotGit()
+ dir := New(fs)
+
+ packedRefs := filepath.Join(fs.Base(), packedRefsPath)
+ brokenContent := "BROKEN STUFF REALLY BROKEN"
+
+ err := ioutil.WriteFile(packedRefs, []byte(brokenContent), os.FileMode(0755))
+ c.Assert(err, IsNil)
+
+ name := plumbing.ReferenceName("refs/heads/nonexistent")
+ err = dir.RemoveRef(name)
+ c.Assert(err, NotNil)
+
+ after, err := ioutil.ReadFile(filepath.Join(fs.Base(), packedRefsPath))
+ c.Assert(err, IsNil)
+
+ c.Assert(brokenContent, Equals, string(after))
+}
+
+func (s *SuiteDotGit) TestRemoveRefInvalidPackedRefs2(c *C) {
+ fs := fixtures.Basic().ByTag(".git").One().DotGit()
+ dir := New(fs)
+
+ packedRefs := filepath.Join(fs.Base(), packedRefsPath)
+ brokenContent := strings.Repeat("a", bufio.MaxScanTokenSize*2)
+
+ err := ioutil.WriteFile(packedRefs, []byte(brokenContent), os.FileMode(0755))
+ c.Assert(err, IsNil)
+
+ name := plumbing.ReferenceName("refs/heads/nonexistent")
+ err = dir.RemoveRef(name)
+ c.Assert(err, NotNil)
+
+ after, err := ioutil.ReadFile(filepath.Join(fs.Base(), packedRefsPath))
+ c.Assert(err, IsNil)
+
+ c.Assert(brokenContent, Equals, string(after))
+}
+
func (s *SuiteDotGit) TestRefsFromHEADFile(c *C) {
fs := fixtures.Basic().ByTag(".git").One().DotGit()
dir := New(fs)
@@ -343,3 +434,11 @@ func (s *SuiteDotGit) TestObjectNotFound(c *C) {
c.Assert(err, NotNil)
c.Assert(file, IsNil)
}
+
+func (s *SuiteDotGit) TestSubmodules(c *C) {
+ fs := fixtures.ByTag("submodule").One().DotGit()
+ dir := New(fs)
+
+ m := dir.Module("basic")
+ c.Assert(strings.HasSuffix(m.Base(), ".git/module/basic"), Equals, true)
+}
diff --git a/storage/filesystem/reference.go b/storage/filesystem/reference.go
index ee87830..cff00c9 100644
--- a/storage/filesystem/reference.go
+++ b/storage/filesystem/reference.go
@@ -26,3 +26,7 @@ func (r *ReferenceStorage) IterReferences() (storer.ReferenceIter, error) {
return storer.NewReferenceSliceIter(refs), nil
}
+
+func (r *ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error {
+ return r.dir.RemoveRef(n)
+}
diff --git a/storage/memory/storage.go b/storage/memory/storage.go
index fa9a4fa..92aeec9 100644
--- a/storage/memory/storage.go
+++ b/storage/memory/storage.go
@@ -220,6 +220,11 @@ func (r ReferenceStorage) IterReferences() (storer.ReferenceIter, error) {
return storer.NewReferenceSliceIter(refs), nil
}
+func (r ReferenceStorage) RemoveReference(n plumbing.ReferenceName) error {
+ delete(r, n)
+ return nil
+}
+
type ShallowStorage []plumbing.Hash
func (s *ShallowStorage) SetShallow(commits []plumbing.Hash) error {
@@ -234,9 +239,12 @@ func (s ShallowStorage) Shallow() ([]plumbing.Hash, error) {
type ModuleStorage map[string]*Storage
func (s ModuleStorage) Module(name string) (storage.Storer, error) {
- if _, ok := s[name]; !ok {
- s[name] = NewStorage()
+ if m, ok := s[name]; ok {
+ return m, nil
}
- return s[name], nil
+ m := NewStorage()
+ s[name] = m
+
+ return m, nil
}
diff --git a/storage/storer.go b/storage/storer.go
index 0a2c256..d217209 100644
--- a/storage/storer.go
+++ b/storage/storer.go
@@ -18,6 +18,9 @@ type Storer interface {
ModuleStorer
}
+// ModuleStorer allows interact with the modules' Storers
type ModuleStorer interface {
+ // Module returns a Storer reprensting a submodule, if not exists returns a
+ // new empty Storer is returned
Module(name string) (Storer, error)
}
diff --git a/storage/test/storage_suite.go b/storage/test/storage_suite.go
index d6c8afa..2a10c78 100644
--- a/storage/test/storage_suite.go
+++ b/storage/test/storage_suite.go
@@ -22,7 +22,6 @@ type Storer interface {
storer.ShallowStorer
storer.IndexStorer
config.ConfigStorer
-
storage.ModuleStorer
}
@@ -245,6 +244,33 @@ func (s *BaseStorageSuite) TestSetReferenceAndGetReference(c *C) {
c.Assert(e.Hash().String(), Equals, "bc9968d75e48de59f0870ffb71f5e160bbbdcf52")
}
+func (s *BaseStorageSuite) TestRemoveReference(c *C) {
+ err := s.Storer.SetReference(
+ plumbing.NewReferenceFromStrings("foo", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52"),
+ )
+ c.Assert(err, IsNil)
+
+ err = s.Storer.RemoveReference(plumbing.ReferenceName("foo"))
+ c.Assert(err, IsNil)
+
+ _, err = s.Storer.Reference(plumbing.ReferenceName("foo"))
+ c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
+}
+
+func (s *BaseStorageSuite) TestRemoveReferenceNonExistent(c *C) {
+ err := s.Storer.SetReference(
+ plumbing.NewReferenceFromStrings("foo", "bc9968d75e48de59f0870ffb71f5e160bbbdcf52"),
+ )
+ c.Assert(err, IsNil)
+
+ err = s.Storer.RemoveReference(plumbing.ReferenceName("nonexistent"))
+ c.Assert(err, IsNil)
+
+ e, err := s.Storer.Reference(plumbing.ReferenceName("foo"))
+ c.Assert(err, IsNil)
+ c.Assert(e.Hash().String(), Equals, "bc9968d75e48de59f0870ffb71f5e160bbbdcf52")
+}
+
func (s *BaseStorageSuite) TestGetReferenceNotFound(c *C) {
r, err := s.Storer.Reference(plumbing.ReferenceName("bar"))
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
@@ -297,7 +323,9 @@ func (s *BaseStorageSuite) TestSetConfigAndConfig(c *C) {
cfg, err := s.Storer.Config()
c.Assert(err, IsNil)
- c.Assert(cfg, DeepEquals, expected)
+
+ c.Assert(cfg.Core.IsBare, DeepEquals, expected.Core.IsBare)
+ c.Assert(cfg.Remotes, DeepEquals, expected.Remotes)
}
func (s *BaseStorageSuite) TestIndex(c *C) {