From 498dbf7dc92e288641f1af1acc52704150e8a6c0 Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Sun, 12 Feb 2017 23:03:30 +0100 Subject: storage: git.Storer move to storage.Storer and module handling --- storage/filesystem/internal/dotgit/dotgit.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'storage/filesystem/internal') diff --git a/storage/filesystem/internal/dotgit/dotgit.go b/storage/filesystem/internal/dotgit/dotgit.go index accf9ca..360b3d1 100644 --- a/storage/filesystem/internal/dotgit/dotgit.go +++ b/storage/filesystem/internal/dotgit/dotgit.go @@ -20,10 +20,10 @@ const ( configPath = "config" indexPath = "index" shallowPath = "shallow" - - objectsPath = "objects" - packPath = "pack" - refsPath = "refs" + modulePath = "module" + objectsPath = "objects" + packPath = "pack" + refsPath = "refs" packExt = ".pack" idxExt = ".idx" @@ -390,6 +390,11 @@ func (d *DotGit) readReferenceFile(refsPath, refFile string) (ref *plumbing.Refe return plumbing.NewReferenceFromStrings(refFile, line), nil } +// Module return a billy.Filesystem poiting to the module folder +func (d *DotGit) Module(name string) billy.Filesystem { + return d.fs.Dir(d.fs.Join(modulePath, name)) +} + func isHex(s string) bool { for _, b := range []byte(s) { if isNum(b) { -- cgit From ed288b30de1ac3dcb3ce675c4b9af89eb4e6fcba Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Tue, 21 Feb 2017 16:03:39 +0100 Subject: documentation and API improvements --- storage/filesystem/internal/dotgit/dotgit.go | 92 +++++++++++++++++---- storage/filesystem/internal/dotgit/dotgit_test.go | 99 +++++++++++++++++++++++ 2 files changed, 177 insertions(+), 14 deletions(-) (limited to 'storage/filesystem/internal') 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) +} -- cgit