-
Notifications
You must be signed in to change notification settings - Fork 534
remote: support for non-force, fast-forward-only fetches #665
Changes from 5 commits
702718f
3834e57
c4766ff
77482f9
d3f5eaf
83e7046
cbab840
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ var ErrMaxResolveRecursion = errors.New("max. recursion level reached") | |
// ReferenceStorer is a generic storage of references. | ||
type ReferenceStorer interface { | ||
SetReference(*plumbing.Reference) error | ||
CheckAndSetReference(new, old *plumbing.Reference) error | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe it is a good time to add doc comments to the other methods in this interface? |
||
Reference(plumbing.ReferenceName) (*plumbing.Reference, error) | ||
IterReferences() (ReferenceIter, error) | ||
RemoveReference(plumbing.ReferenceName) error | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import ( | |
"bufio" | ||
"errors" | ||
"fmt" | ||
"io" | ||
stdioutil "io/ioutil" | ||
"os" | ||
"strings" | ||
|
@@ -239,7 +240,39 @@ func (d *DotGit) Object(h plumbing.Hash) (billy.File, error) { | |
return d.fs.Open(file) | ||
} | ||
|
||
func (d *DotGit) SetRef(r *plumbing.Reference) error { | ||
func (d *DotGit) readReferenceFrom(rd io.Reader, name string) (ref *plumbing.Reference, err error) { | ||
b, err := stdioutil.ReadAll(rd) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
line := strings.TrimSpace(string(b)) | ||
return plumbing.NewReferenceFromStrings(name, line), nil | ||
} | ||
|
||
func (d *DotGit) checkReferenceAndTruncate(f billy.File, old *plumbing.Reference) error { | ||
if old == nil { | ||
return nil | ||
} | ||
ref, err := d.readReferenceFrom(f, old.Name().String()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is not covered by the test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if err != nil { | ||
return err | ||
} | ||
if ref.Hash() != old.Hash() { | ||
return fmt.Errorf("reference has changed concurrently") | ||
} | ||
_, err = f.Seek(0, io.SeekStart) | ||
if err != nil { | ||
return err | ||
} | ||
err = f.Truncate(0) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (d *DotGit) SetRef(r, old *plumbing.Reference) error { | ||
var content string | ||
switch r.Type() { | ||
case plumbing.SymbolicReference: | ||
|
@@ -248,13 +281,34 @@ func (d *DotGit) SetRef(r *plumbing.Reference) error { | |
content = fmt.Sprintln(r.Hash().String()) | ||
} | ||
|
||
f, err := d.fs.Create(r.Name().String()) | ||
// If we are not checking an old ref, just truncate the file. | ||
mode := os.O_RDWR | os.O_CREATE | ||
if old == nil { | ||
mode |= os.O_TRUNC | ||
} | ||
|
||
f, err := d.fs.OpenFile(r.Name().String(), mode, 0666) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer ioutil.CheckClose(f, &err) | ||
|
||
// Lock is unlocked by the deferred Close above. This is because Unlock | ||
// does not imply a fsync and thus there would be a race between | ||
// Unlock+Close and other concurrent writers. Adding Sync to go-billy | ||
// could work, but this is better (and avoids superfluous syncs). | ||
err = f.Lock() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// this is a no-op to call even when old is nil. | ||
err = d.checkReferenceAndTruncate(f, old) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = f.Write([]byte(content)) | ||
return err | ||
} | ||
|
@@ -493,13 +547,7 @@ func (d *DotGit) readReferenceFile(path, name string) (ref *plumbing.Reference, | |
} | ||
defer ioutil.CheckClose(f, &err) | ||
|
||
b, err := stdioutil.ReadAll(f) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
line := strings.TrimSpace(string(b)) | ||
return plumbing.NewReferenceFromStrings(name, line), nil | ||
return d.readReferenceFrom(f, name) | ||
} | ||
|
||
// Module return a billy.Filesystem poiting to the module folder | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ import ( | |
) | ||
|
||
var ErrUnsupportedObjectType = fmt.Errorf("unsupported object type") | ||
var ErrRefHasChanged = fmt.Errorf("reference has changed concurrently") | ||
|
||
// Storage is an implementation of git.Storer that stores data on memory, being | ||
// ephemeral. The use of this storage should be done in controlled envoriments, | ||
|
@@ -202,6 +203,20 @@ func (r ReferenceStorage) SetReference(ref *plumbing.Reference) error { | |
return nil | ||
} | ||
|
||
func (r ReferenceStorage) CheckAndSetReference(ref, old *plumbing.Reference) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is not covered by the tests. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I didn't notice that the remote tests don't use filesystem storage. I'll add a test. |
||
if ref != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be change this to:
|
||
if old != nil { | ||
tmp := r[ref.Name()] | ||
if tmp != nil && tmp.Hash() != old.Hash() { | ||
return ErrRefHasChanged | ||
} | ||
} | ||
r[ref.Name()] = ref | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (r ReferenceStorage) Reference(n plumbing.ReferenceName) (*plumbing.Reference, error) { | ||
ref, ok := r[n] | ||
if !ok { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that the order methods are updocumented too, I belive because looks like obviuos (even with that we should document the behaviour at some point), but we should document this one now, sinse for me it`s not a obviuos the goal.