aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing
diff options
context:
space:
mode:
Diffstat (limited to 'plumbing')
-rw-r--r--plumbing/format/idxfile/idxfile.go69
-rw-r--r--plumbing/format/idxfile/idxfile_test.go15
-rw-r--r--plumbing/format/packfile/fsobject.go10
-rw-r--r--plumbing/format/packfile/packfile.go17
-rw-r--r--plumbing/object/commit.go16
-rw-r--r--plumbing/object/commit_test.go34
6 files changed, 155 insertions, 6 deletions
diff --git a/plumbing/format/idxfile/idxfile.go b/plumbing/format/idxfile/idxfile.go
index c977bee..5fed278 100644
--- a/plumbing/format/idxfile/idxfile.go
+++ b/plumbing/format/idxfile/idxfile.go
@@ -3,6 +3,7 @@ package idxfile
import (
"bytes"
"io"
+ "sort"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/utils/binary"
@@ -34,6 +35,9 @@ type Index interface {
Count() (int64, error)
// Entries returns an iterator to retrieve all index entries.
Entries() (EntryIter, error)
+ // EntriesByOffset returns an iterator to retrieve all index entries ordered
+ // by offset.
+ EntriesByOffset() (EntryIter, error)
}
// MemoryIndex is the in memory representation of an idx file.
@@ -215,6 +219,36 @@ func (idx *MemoryIndex) Entries() (EntryIter, error) {
return &idxfileEntryIter{idx, 0, 0, 0}, nil
}
+// EntriesByOffset implements the Index interface.
+func (idx *MemoryIndex) EntriesByOffset() (EntryIter, error) {
+ count, err := idx.Count()
+ if err != nil {
+ return nil, err
+ }
+
+ iter := &idxfileEntryOffsetIter{
+ entries: make(entriesByOffset, count),
+ }
+
+ entries, err := idx.Entries()
+ if err != nil {
+ return nil, err
+ }
+
+ for pos := 0; int64(pos) < count; pos++ {
+ entry, err := entries.Next()
+ if err != nil {
+ return nil, err
+ }
+
+ iter.entries[pos] = entry
+ }
+
+ sort.Sort(iter.entries)
+
+ return iter, nil
+}
+
// EntryIter is an iterator that will return the entries in a packfile index.
type EntryIter interface {
// Next returns the next entry in the packfile index.
@@ -276,3 +310,38 @@ type Entry struct {
CRC32 uint32
Offset uint64
}
+
+type idxfileEntryOffsetIter struct {
+ entries entriesByOffset
+ pos int
+}
+
+func (i *idxfileEntryOffsetIter) Next() (*Entry, error) {
+ if i.pos >= len(i.entries) {
+ return nil, io.EOF
+ }
+
+ entry := i.entries[i.pos]
+ i.pos++
+
+ return entry, nil
+}
+
+func (i *idxfileEntryOffsetIter) Close() error {
+ i.pos = len(i.entries) + 1
+ return nil
+}
+
+type entriesByOffset []*Entry
+
+func (o entriesByOffset) Len() int {
+ return len(o)
+}
+
+func (o entriesByOffset) Less(i int, j int) bool {
+ return o[i].Offset < o[j].Offset
+}
+
+func (o entriesByOffset) Swap(i int, j int) {
+ o[i], o[j] = o[j], o[i]
+}
diff --git a/plumbing/format/idxfile/idxfile_test.go b/plumbing/format/idxfile/idxfile_test.go
index d15accf..0e0ca2a 100644
--- a/plumbing/format/idxfile/idxfile_test.go
+++ b/plumbing/format/idxfile/idxfile_test.go
@@ -115,6 +115,21 @@ func (s *IndexSuite) TestFindHash(c *C) {
}
}
+func (s *IndexSuite) TestEntriesByOffset(c *C) {
+ idx, err := fixtureIndex()
+ c.Assert(err, IsNil)
+
+ entries, err := idx.EntriesByOffset()
+ c.Assert(err, IsNil)
+
+ for _, pos := range fixtureOffsets {
+ e, err := entries.Next()
+ c.Assert(err, IsNil)
+
+ c.Assert(e.Offset, Equals, uint64(pos))
+ }
+}
+
var fixtureHashes = []plumbing.Hash{
plumbing.NewHash("303953e5aa461c203a324821bc1717f9b4fff895"),
plumbing.NewHash("5296768e3d9f661387ccbff18c4dea6c997fd78c"),
diff --git a/plumbing/format/packfile/fsobject.go b/plumbing/format/packfile/fsobject.go
index 6fd3ca5..330cb73 100644
--- a/plumbing/format/packfile/fsobject.go
+++ b/plumbing/format/packfile/fsobject.go
@@ -47,6 +47,16 @@ func NewFSObject(
// Reader implements the plumbing.EncodedObject interface.
func (o *FSObject) Reader() (io.ReadCloser, error) {
+ obj, ok := o.cache.Get(o.hash)
+ if ok {
+ reader, err := obj.Reader()
+ if err != nil {
+ return nil, err
+ }
+
+ return reader, nil
+ }
+
f, err := o.fs.Open(o.path)
if err != nil {
return nil, err
diff --git a/plumbing/format/packfile/packfile.go b/plumbing/format/packfile/packfile.go
index 5feb781..852a834 100644
--- a/plumbing/format/packfile/packfile.go
+++ b/plumbing/format/packfile/packfile.go
@@ -258,6 +258,19 @@ func (p *Packfile) nextObject() (plumbing.EncodedObject, error) {
}
func (p *Packfile) getObjectContent(offset int64) (io.ReadCloser, error) {
+ ref, err := p.FindHash(offset)
+ if err == nil {
+ obj, ok := p.cacheGet(ref)
+ if ok {
+ reader, err := obj.Reader()
+ if err != nil {
+ return nil, err
+ }
+
+ return reader, nil
+ }
+ }
+
if _, err := p.s.SeekFromStart(offset); err != nil {
return nil, err
}
@@ -306,6 +319,8 @@ func (p *Packfile) fillRegularObjectContent(obj plumbing.EncodedObject) error {
}
_, _, err = p.s.NextObject(w)
+ p.cachePut(obj)
+
return err
}
@@ -394,7 +409,7 @@ func (p *Packfile) GetByType(typ plumbing.ObjectType) (storer.EncodedObjectIter,
plumbing.TreeObject,
plumbing.CommitObject,
plumbing.TagObject:
- entries, err := p.Entries()
+ entries, err := p.EntriesByOffset()
if err != nil {
return nil, err
}
diff --git a/plumbing/object/commit.go b/plumbing/object/commit.go
index 00ae3f1..e254342 100644
--- a/plumbing/object/commit.go
+++ b/plumbing/object/commit.go
@@ -199,17 +199,23 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
}
split := bytes.SplitN(line, []byte{' '}, 2)
+
+ var data []byte
+ if len(split) == 2 {
+ data = split[1]
+ }
+
switch string(split[0]) {
case "tree":
- c.TreeHash = plumbing.NewHash(string(split[1]))
+ c.TreeHash = plumbing.NewHash(string(data))
case "parent":
- c.ParentHashes = append(c.ParentHashes, plumbing.NewHash(string(split[1])))
+ c.ParentHashes = append(c.ParentHashes, plumbing.NewHash(string(data)))
case "author":
- c.Author.Decode(split[1])
+ c.Author.Decode(data)
case "committer":
- c.Committer.Decode(split[1])
+ c.Committer.Decode(data)
case headerpgp:
- c.PGPSignature += string(split[1]) + "\n"
+ c.PGPSignature += string(data) + "\n"
pgpsig = true
}
} else {
diff --git a/plumbing/object/commit_test.go b/plumbing/object/commit_test.go
index b5dfbe3..e72b703 100644
--- a/plumbing/object/commit_test.go
+++ b/plumbing/object/commit_test.go
@@ -325,6 +325,22 @@ RUysgqjcpT8+iQM1PblGfHR4XAhuOqN5Fx06PSaFZhqvWFezJ28/CLyX5q+oIVk=
c.Assert(err, IsNil)
c.Assert(decoded.PGPSignature, Equals, pgpsignature)
+ // signature with extra empty line, it caused "index out of range" when
+ // parsing it
+
+ pgpsignature2 := "\n" + pgpsignature
+
+ commit.PGPSignature = pgpsignature2
+ encoded = &plumbing.MemoryObject{}
+ decoded = &Commit{}
+
+ err = commit.Encode(encoded)
+ c.Assert(err, IsNil)
+
+ err = decoded.Decode(encoded)
+ c.Assert(err, IsNil)
+ c.Assert(decoded.PGPSignature, Equals, pgpsignature2)
+
// signature in author name
commit.PGPSignature = ""
@@ -461,3 +477,21 @@ func (s *SuiteCommit) TestPatchCancel(c *C) {
c.Assert(err, ErrorMatches, "operation canceled")
}
+
+func (s *SuiteCommit) TestMalformedHeader(c *C) {
+ encoded := &plumbing.MemoryObject{}
+ decoded := &Commit{}
+ commit := *s.Commit
+
+ commit.PGPSignature = "\n"
+ commit.Author.Name = "\n"
+ commit.Author.Email = "\n"
+ commit.Committer.Name = "\n"
+ commit.Committer.Email = "\n"
+
+ err := commit.Encode(encoded)
+ c.Assert(err, IsNil)
+
+ err = decoded.Decode(encoded)
+ c.Assert(err, IsNil)
+}