Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

storage/dotgit: use fs capabilities in setRef #1036

Merged
merged 2 commits into from
Dec 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions storage/filesystem/dotgit/dotgit_setref.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
// +build !norwfs

package dotgit

import (
"fmt"
"os"

"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/utils/ioutil"

"gopkg.in/src-d/go-billy.v4"
)

func (d *DotGit) setRef(fileName, content string, old *plumbing.Reference) (err error) {
if billy.CapabilityCheck(d.fs, billy.ReadAndWriteCapability) {
return d.setRefRwfs(fileName, content, old)
}

return d.setRefNorwfs(fileName, content, old)
}

func (d *DotGit) setRefRwfs(fileName, content string, old *plumbing.Reference) (err error) {
// If we are not checking an old ref, just truncate the file.
mode := os.O_RDWR | os.O_CREATE
if old == nil {
Expand Down Expand Up @@ -41,3 +50,41 @@ func (d *DotGit) setRef(fileName, content string, old *plumbing.Reference) (err
_, err = f.Write([]byte(content))
return err
}

// There are some filesystems that don't support opening files in RDWD mode.
// In these filesystems the standard SetRef function can not be used as it
// reads the reference file to check that it's not modified before updating it.
//
// This version of the function writes the reference without extra checks
// making it compatible with these simple filesystems. This is usually not
// a problem as they should be accessed by only one process at a time.
func (d *DotGit) setRefNorwfs(fileName, content string, old *plumbing.Reference) error {
_, err := d.fs.Stat(fileName)
if err == nil && old != nil {
fRead, err := d.fs.Open(fileName)
if err != nil {
return err
}

ref, err := d.readReferenceFrom(fRead, old.Name().String())
fRead.Close()

if err != nil {
return err
}

if ref.Hash() != old.Hash() {
return fmt.Errorf("reference has changed concurrently")
}
}

f, err := d.fs.Create(fileName)
if err != nil {
return err
}

defer f.Close()

_, err = f.Write([]byte(content))
return err
}
47 changes: 0 additions & 47 deletions storage/filesystem/dotgit/dotgit_setref_norwfs.go

This file was deleted.

25 changes: 24 additions & 1 deletion storage/filesystem/dotgit/dotgit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,26 @@ func (s *SuiteDotGit) TestSetRefs(c *C) {
fs := osfs.New(tmp)
dir := New(fs)

testSetRefs(c, dir)
}

func (s *SuiteDotGit) TestSetRefsNorwfs(c *C) {
tmp, err := ioutil.TempDir("", "dot-git")
c.Assert(err, IsNil)
defer os.RemoveAll(tmp)

fs := osfs.New(tmp)
dir := New(&norwfs{fs})

testSetRefs(c, dir)
}

func testSetRefs(c *C, dir *DotGit) {
firstFoo := plumbing.NewReferenceFromStrings(
"refs/heads/foo",
"e8d3ffab552895c19b9fcf7aa264d277cde33881",
)
err = dir.SetRef(firstFoo, nil)
err := dir.SetRef(firstFoo, nil)

c.Assert(err, IsNil)

Expand Down Expand Up @@ -795,3 +810,11 @@ func (s *SuiteDotGit) TestAlternates(c *C) {
}
c.Assert(dotgits[1].fs.Root(), Equals, expectedPath)
}

type norwfs struct {
billy.Filesystem
}

func (f *norwfs) Capabilities() billy.Capability {
return billy.Capabilities(f.Filesystem) &^ billy.ReadAndWriteCapability
}