aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/format
diff options
context:
space:
mode:
Diffstat (limited to 'plumbing/format')
-rw-r--r--plumbing/format/commitgraph/encoder.go14
-rw-r--r--plumbing/format/commitgraph/file.go2
-rw-r--r--plumbing/format/commitgraph/memory.go2
-rw-r--r--plumbing/format/diff/unified_encoder.go25
-rw-r--r--plumbing/format/diff/unified_encoder_test.go90
-rw-r--r--plumbing/format/gitattributes/pattern.go2
-rw-r--r--plumbing/format/idxfile/decoder.go6
-rw-r--r--plumbing/format/idxfile/writer.go2
-rw-r--r--plumbing/format/index/decoder_test.go2
-rw-r--r--plumbing/format/index/doc.go4
-rw-r--r--plumbing/format/index/encoder_test.go6
-rw-r--r--plumbing/format/index/index.go2
-rw-r--r--plumbing/format/packfile/diff_delta.go13
-rw-r--r--plumbing/format/packfile/packfile.go8
-rw-r--r--plumbing/format/packfile/parser.go99
-rw-r--r--plumbing/format/packfile/patch_delta.go53
-rw-r--r--plumbing/format/packfile/scanner_test.go1
17 files changed, 202 insertions, 129 deletions
diff --git a/plumbing/format/commitgraph/encoder.go b/plumbing/format/commitgraph/encoder.go
index a06871c..615e833 100644
--- a/plumbing/format/commitgraph/encoder.go
+++ b/plumbing/format/commitgraph/encoder.go
@@ -24,8 +24,6 @@ func NewEncoder(w io.Writer) *Encoder {
// Encode writes an index into the commit-graph file
func (e *Encoder) Encode(idx Index) error {
- var err error
-
// Get all the hashes in the input index
hashes := idx.Hashes()
@@ -39,26 +37,26 @@ func (e *Encoder) Encode(idx Index) error {
chunkSizes = append(chunkSizes, uint64(extraEdgesCount)*4)
}
- if err = e.encodeFileHeader(len(chunkSignatures)); err != nil {
+ if err := e.encodeFileHeader(len(chunkSignatures)); err != nil {
return err
}
- if err = e.encodeChunkHeaders(chunkSignatures, chunkSizes); err != nil {
+ if err := e.encodeChunkHeaders(chunkSignatures, chunkSizes); err != nil {
return err
}
- if err = e.encodeFanout(fanout); err != nil {
+ if err := e.encodeFanout(fanout); err != nil {
return err
}
- if err = e.encodeOidLookup(hashes); err != nil {
+ if err := e.encodeOidLookup(hashes); err != nil {
return err
}
if extraEdges, err := e.encodeCommitData(hashes, hashToIndex, idx); err == nil {
if err = e.encodeExtraEdges(extraEdges); err != nil {
return err
}
- }
- if err != nil {
+ } else {
return err
}
+
return e.encodeChecksum()
}
diff --git a/plumbing/format/commitgraph/file.go b/plumbing/format/commitgraph/file.go
index 175d279..1f82abd 100644
--- a/plumbing/format/commitgraph/file.go
+++ b/plumbing/format/commitgraph/file.go
@@ -249,7 +249,7 @@ func (fi *fileIndex) getHashesFromIndexes(indexes []int) ([]plumbing.Hash, error
// Hashes returns all the hashes that are available in the index
func (fi *fileIndex) Hashes() []plumbing.Hash {
hashes := make([]plumbing.Hash, fi.fanout[0xff])
- for i := 0; i < int(fi.fanout[0xff]); i++ {
+ for i := 0; i < fi.fanout[0xff]; i++ {
offset := fi.oidLookupOffset + int64(i)*20
if n, err := fi.reader.ReadAt(hashes[i][:], offset); err != nil || n < 20 {
return nil
diff --git a/plumbing/format/commitgraph/memory.go b/plumbing/format/commitgraph/memory.go
index a4a96e9..f5afd4c 100644
--- a/plumbing/format/commitgraph/memory.go
+++ b/plumbing/format/commitgraph/memory.go
@@ -31,7 +31,7 @@ func (mi *MemoryIndex) GetIndexByHash(h plumbing.Hash) (int, error) {
// GetCommitDataByIndex gets the commit node from the commit graph using index
// obtained from child node, if available
func (mi *MemoryIndex) GetCommitDataByIndex(i int) (*CommitData, error) {
- if int(i) >= len(mi.commitData) {
+ if i >= len(mi.commitData) {
return nil, plumbing.ErrObjectNotFound
}
diff --git a/plumbing/format/diff/unified_encoder.go b/plumbing/format/diff/unified_encoder.go
index 8bd6d8a..ce3bc7c 100644
--- a/plumbing/format/diff/unified_encoder.go
+++ b/plumbing/format/diff/unified_encoder.go
@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"io"
+ "regexp"
"strings"
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -25,9 +26,10 @@ const (
tPath = "+++ %s\n"
binary = "Binary files %s and %s differ\n"
- addLine = "+%s\n"
- deleteLine = "-%s\n"
- equalLine = " %s\n"
+ addLine = "+%s%s"
+ deleteLine = "-%s%s"
+ equalLine = " %s%s"
+ noNewLine = "\n\\ No newline at end of file\n"
oldMode = "old mode %o\n"
newMode = "new mode %o\n"
@@ -94,7 +96,7 @@ func (e *UnifiedEncoder) printMessage(message string) {
isEmpty := message == ""
hasSuffix := strings.HasSuffix(message, "\n")
if !isEmpty && !hasSuffix {
- message = message + "\n"
+ message += "\n"
}
e.buf.WriteString(message)
@@ -216,7 +218,7 @@ func (c *hunksGenerator) processHunk(i int, op Operation) {
linesBefore = c.ctxLines
}
- c.current = &hunk{ctxPrefix: ctxPrefix}
+ c.current = &hunk{ctxPrefix: strings.TrimSuffix(ctxPrefix, "\n")}
c.current.AddOp(Equal, c.beforeContext...)
switch op {
@@ -279,12 +281,13 @@ func (c *hunksGenerator) processEqualsLines(ls []string, i int) {
}
}
+var splitLinesRE = regexp.MustCompile(`[^\n]*(\n|$)`)
+
func splitLines(s string) []string {
- out := strings.Split(s, "\n")
+ out := splitLinesRE.FindAllString(s, -1)
if out[len(out)-1] == "" {
out = out[:len(out)-1]
}
-
return out
}
@@ -346,7 +349,7 @@ type op struct {
}
func (o *op) String() string {
- var prefix string
+ var prefix, suffix string
switch o.t {
case Add:
prefix = addLine
@@ -355,6 +358,10 @@ func (o *op) String() string {
case Equal:
prefix = equalLine
}
+ n := len(o.text)
+ if n > 0 && o.text[n-1] != '\n' {
+ suffix = noNewLine
+ }
- return fmt.Sprintf(prefix, o.text)
+ return fmt.Sprintf(prefix, o.text, suffix)
}
diff --git a/plumbing/format/diff/unified_encoder_test.go b/plumbing/format/diff/unified_encoder_test.go
index 7736af1..091a96a 100644
--- a/plumbing/format/diff/unified_encoder_test.go
+++ b/plumbing/format/diff/unified_encoder_test.go
@@ -83,7 +83,7 @@ var oneChunkPatch Patch = testPatch{
content: "A\n",
op: Delete,
}, {
- content: "B\nC\nD\nE\nF\nG",
+ content: "B\nC\nD\nE\nF\nG\n",
op: Equal,
}, {
content: "H\n",
@@ -125,7 +125,7 @@ var oneChunkPatchInverted Patch = testPatch{
content: "A\n",
op: Add,
}, {
- content: "B\nC\nD\nE\nF\nG",
+ content: "B\nC\nD\nE\nF\nG\n",
op: Equal,
}, {
content: "H\n",
@@ -164,13 +164,13 @@ var fixtures []*fixture = []*fixture{{
seed: "hello\nbug\n",
},
chunks: []testChunk{{
- content: "hello",
+ content: "hello\n",
op: Equal,
}, {
- content: "world",
+ content: "world\n",
op: Delete,
}, {
- content: "bug",
+ content: "bug\n",
op: Add,
}},
}},
@@ -239,18 +239,18 @@ rename to test1.txt
from: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test",
+ seed: "test\n",
},
to: &testFile{
mode: filemode.Regular,
path: "test1.txt",
- seed: "test1",
+ seed: "test1\n",
},
chunks: []testChunk{{
- content: "test",
+ content: "test\n",
op: Delete,
}, {
- content: "test1",
+ content: "test1\n",
op: Add,
}},
}},
@@ -260,7 +260,7 @@ rename to test1.txt
diff: `diff --git a/test.txt b/test1.txt
rename from test.txt
rename to test1.txt
-index 30d74d258442c7c65512eafab474568dd706c430..f079749c42ffdcc5f52ed2d3a6f15b09307e975e 100644
+index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..a5bce3fd2565d8f458555a0c6f42d0504a848bd5 100644
--- a/test.txt
+++ b/test1.txt
@@ -1 +1 @@
@@ -299,19 +299,19 @@ rename to test1.txt
from: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test",
+ seed: "test\n",
},
to: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test2",
+ seed: "test2\n",
},
chunks: []testChunk{{
- content: "test",
+ content: "test\n",
op: Delete,
}, {
- content: "test2",
+ content: "test2\n",
op: Add,
}},
}},
@@ -320,7 +320,7 @@ rename to test1.txt
desc: "one line change",
context: 1,
diff: `diff --git a/test.txt b/test.txt
-index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d55b2ae9d 100644
+index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..180cf8328022becee9aaa2577a8f84ea2b9f3827 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
@@ -334,19 +334,19 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
from: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test",
+ seed: "test\n",
},
to: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test2",
+ seed: "test2\n",
},
chunks: []testChunk{{
- content: "test",
+ content: "test\n",
op: Delete,
}, {
- content: "test2",
+ content: "test2\n",
op: Add,
}},
}},
@@ -356,7 +356,7 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
context: 1,
diff: `this is the message
diff --git a/test.txt b/test.txt
-index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d55b2ae9d 100644
+index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..180cf8328022becee9aaa2577a8f84ea2b9f3827 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
@@ -397,7 +397,9 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
+++ b/test.txt
@@ -1 +1 @@
-test
+\ No newline at end of file
+test2
+\ No newline at end of file
`,
}, {
patch: testPatch{
@@ -407,7 +409,7 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
to: &testFile{
mode: filemode.Regular,
path: "new.txt",
- seed: "test\ntest2\test3",
+ seed: "test\ntest2\ntest3",
},
chunks: []testChunk{{
@@ -421,13 +423,14 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
context: 1,
diff: `diff --git a/new.txt b/new.txt
new file mode 100644
-index 0000000000000000000000000000000000000000..65c8dd02a42273038658a22b1cb29c8d9457ca12
+index 0000000000000000000000000000000000000000..3ceaab5442b64a0c2b33dd25fae67ccdb4fd1ea8
--- /dev/null
+++ b/new.txt
@@ -0,0 +1,3 @@
+test
+test2
+test3
+\ No newline at end of file
`,
}, {
patch: testPatch{
@@ -456,6 +459,7 @@ index 30d74d258442c7c65512eafab474568dd706c430..00000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-test
+\ No newline at end of file
`,
}, {
patch: oneChunkPatch,
@@ -548,6 +552,7 @@ index ab5eed5d4a2c33aeef67e0188ee79bed666bde6f..0adddcde4fd38042c354518351820eb0
X
Y
Z
+\ No newline at end of file
`,
}, {
patch: oneChunkPatch,
@@ -813,6 +818,47 @@ index 0adddcde4fd38042c354518351820eb06c417c82..553ae669c7a9303cf848fcc749a25692
+++ b/onechunk.txt
@@ -23 +22,0 @@ Y
-Z
+\ No newline at end of file
+`,
+}, {
+ patch: testPatch{
+ message: "",
+ filePatches: []testFilePatch{{
+ from: &testFile{
+ mode: filemode.Regular,
+ path: "onechunk.txt",
+ seed: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\nZ",
+ },
+ to: &testFile{
+ mode: filemode.Regular,
+ path: "onechunk.txt",
+ seed: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY",
+ },
+
+ chunks: []testChunk{{
+ content: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\n",
+ op: Equal,
+ }, {
+ content: "Y\nZ",
+ op: Delete,
+ }, {
+ content: "Y",
+ op: Add,
+ }},
+ }},
+ },
+ desc: "remove last letter and no newline at end of file",
+ context: 0,
+ diff: `diff --git a/onechunk.txt b/onechunk.txt
+index 0adddcde4fd38042c354518351820eb06c417c82..d39ae38aad7ba9447b5e7998b2e4714f26c9218d 100644
+--- a/onechunk.txt
++++ b/onechunk.txt
+@@ -22,2 +21 @@ X
+-Y
+-Z
+\ No newline at end of file
++Y
+\ No newline at end of file
`,
}}
diff --git a/plumbing/format/gitattributes/pattern.go b/plumbing/format/gitattributes/pattern.go
index c5ca0c7..d961aba 100644
--- a/plumbing/format/gitattributes/pattern.go
+++ b/plumbing/format/gitattributes/pattern.go
@@ -66,7 +66,7 @@ func (p *pattern) Match(path []string) bool {
doublestar = true
}
- switch true {
+ switch {
case strings.Contains(pattern[0], "**"):
return false
diff --git a/plumbing/format/idxfile/decoder.go b/plumbing/format/idxfile/decoder.go
index 5b92782..d1a8a2c 100644
--- a/plumbing/format/idxfile/decoder.go
+++ b/plumbing/format/idxfile/decoder.go
@@ -12,7 +12,7 @@ import (
var (
// ErrUnsupportedVersion is returned by Decode when the idx file version
// is not supported.
- ErrUnsupportedVersion = errors.New("Unsuported version")
+ ErrUnsupportedVersion = errors.New("Unsupported version")
// ErrMalformedIdxFile is returned by Decode when the idx file is corrupted.
ErrMalformedIdxFile = errors.New("Malformed IDX file")
)
@@ -110,10 +110,6 @@ func readObjectNames(idx *MemoryIndex, r io.Reader) error {
continue
}
- if buckets < 0 {
- return ErrMalformedIdxFile
- }
-
idx.FanoutMapping[k] = len(idx.Names)
nameLen := int(buckets * objectIDLength)
diff --git a/plumbing/format/idxfile/writer.go b/plumbing/format/idxfile/writer.go
index aa919e7..fcc78c5 100644
--- a/plumbing/format/idxfile/writer.go
+++ b/plumbing/format/idxfile/writer.go
@@ -147,7 +147,7 @@ func (w *Writer) createIndex() (*MemoryIndex, error) {
idx.Offset32[bucket] = append(idx.Offset32[bucket], buf.Bytes()...)
buf.Truncate(0)
- binary.WriteUint32(buf, uint32(o.CRC32))
+ binary.WriteUint32(buf, o.CRC32)
idx.CRC32[bucket] = append(idx.CRC32[bucket], buf.Bytes()...)
}
diff --git a/plumbing/format/index/decoder_test.go b/plumbing/format/index/decoder_test.go
index 7468ad0..92d312d 100644
--- a/plumbing/format/index/decoder_test.go
+++ b/plumbing/format/index/decoder_test.go
@@ -115,7 +115,7 @@ func (s *IndexSuite) TestDecodeMergeConflict(c *C) {
{TheirMode, "14f8e368114f561c38e134f6e68ea6fea12d77ed"},
}
- // stagged files
+ // staged files
for i, e := range idx.Entries[4:7] {
c.Assert(e.Stage, Equals, expected[i].Stage)
c.Assert(e.CreatedAt.IsZero(), Equals, true)
diff --git a/plumbing/format/index/doc.go b/plumbing/format/index/doc.go
index f2b3d76..39ae6ad 100644
--- a/plumbing/format/index/doc.go
+++ b/plumbing/format/index/doc.go
@@ -320,7 +320,7 @@
// == End of Index Entry
//
// The End of Index Entry (EOIE) is used to locate the end of the variable
-// length index entries and the begining of the extensions. Code can take
+// length index entries and the beginning of the extensions. Code can take
// advantage of this to quickly locate the index extensions without having
// to parse through all of the index entries.
//
@@ -353,7 +353,7 @@
//
// - A number of index offset entries each consisting of:
//
-// - 32-bit offset from the begining of the file to the first cache entry
+// - 32-bit offset from the beginning of the file to the first cache entry
// in this block of entries.
//
// - 32-bit count of cache entries in this blockpackage index
diff --git a/plumbing/format/index/encoder_test.go b/plumbing/format/index/encoder_test.go
index 78cbbba..ea121fc 100644
--- a/plumbing/format/index/encoder_test.go
+++ b/plumbing/format/index/encoder_test.go
@@ -55,7 +55,7 @@ func (s *IndexSuite) TestEncode(c *C) {
}
-func (s *IndexSuite) TestEncodeUnsuportedVersion(c *C) {
+func (s *IndexSuite) TestEncodeUnsupportedVersion(c *C) {
idx := &Index{Version: 3}
buf := bytes.NewBuffer(nil)
@@ -64,7 +64,7 @@ func (s *IndexSuite) TestEncodeUnsuportedVersion(c *C) {
c.Assert(err, Equals, ErrUnsupportedVersion)
}
-func (s *IndexSuite) TestEncodeWithIntentToAddUnsuportedVersion(c *C) {
+func (s *IndexSuite) TestEncodeWithIntentToAddUnsupportedVersion(c *C) {
idx := &Index{
Version: 2,
Entries: []*Entry{{IntentToAdd: true}},
@@ -76,7 +76,7 @@ func (s *IndexSuite) TestEncodeWithIntentToAddUnsuportedVersion(c *C) {
c.Assert(err, Equals, ErrUnsupportedVersion)
}
-func (s *IndexSuite) TestEncodeWithSkipWorktreeUnsuportedVersion(c *C) {
+func (s *IndexSuite) TestEncodeWithSkipWorktreeUnsupportedVersion(c *C) {
idx := &Index{
Version: 2,
Entries: []*Entry{{SkipWorktree: true}},
diff --git a/plumbing/format/index/index.go b/plumbing/format/index/index.go
index 6c4b7ca..6653c91 100644
--- a/plumbing/format/index/index.go
+++ b/plumbing/format/index/index.go
@@ -198,7 +198,7 @@ type ResolveUndoEntry struct {
}
// EndOfIndexEntry is the End of Index Entry (EOIE) is used to locate the end of
-// the variable length index entries and the begining of the extensions. Code
+// the variable length index entries and the beginning of the extensions. Code
// can take advantage of this to quickly locate the index extensions without
// having to parse through all of the index entries.
//
diff --git a/plumbing/format/packfile/diff_delta.go b/plumbing/format/packfile/diff_delta.go
index d35e78a..43f87a0 100644
--- a/plumbing/format/packfile/diff_delta.go
+++ b/plumbing/format/packfile/diff_delta.go
@@ -40,8 +40,8 @@ func getDelta(index *deltaIndex, base, target plumbing.EncodedObject) (plumbing.
defer tr.Close()
bb := bufPool.Get().(*bytes.Buffer)
- bb.Reset()
defer bufPool.Put(bb)
+ bb.Reset()
_, err = bb.ReadFrom(br)
if err != nil {
@@ -49,8 +49,8 @@ func getDelta(index *deltaIndex, base, target plumbing.EncodedObject) (plumbing.
}
tb := bufPool.Get().(*bytes.Buffer)
- tb.Reset()
defer bufPool.Put(tb)
+ tb.Reset()
_, err = tb.ReadFrom(tr)
if err != nil {
@@ -77,6 +77,7 @@ func DiffDelta(src, tgt []byte) []byte {
func diffDelta(index *deltaIndex, src []byte, tgt []byte) []byte {
buf := bufPool.Get().(*bytes.Buffer)
+ defer bufPool.Put(buf)
buf.Reset()
buf.Write(deltaEncodeSize(len(src)))
buf.Write(deltaEncodeSize(len(tgt)))
@@ -86,6 +87,7 @@ func diffDelta(index *deltaIndex, src []byte, tgt []byte) []byte {
}
ibuf := bufPool.Get().(*bytes.Buffer)
+ defer bufPool.Put(ibuf)
ibuf.Reset()
for i := 0; i < len(tgt); i++ {
offset, l := index.findMatch(src, tgt, i)
@@ -127,12 +129,9 @@ func diffDelta(index *deltaIndex, src []byte, tgt []byte) []byte {
}
encodeInsertOperation(ibuf, buf)
- bytes := buf.Bytes()
-
- bufPool.Put(buf)
- bufPool.Put(ibuf)
- return bytes
+ // buf.Bytes() is only valid until the next modifying operation on the buffer. Copy it.
+ return append([]byte{}, buf.Bytes()...)
}
func encodeInsertOperation(ibuf, buf *bytes.Buffer) {
diff --git a/plumbing/format/packfile/packfile.go b/plumbing/format/packfile/packfile.go
index f528073..21a15de 100644
--- a/plumbing/format/packfile/packfile.go
+++ b/plumbing/format/packfile/packfile.go
@@ -133,8 +133,8 @@ func (p *Packfile) getObjectSize(h *ObjectHeader) (int64, error) {
return h.Length, nil
case plumbing.REFDeltaObject, plumbing.OFSDeltaObject:
buf := bufPool.Get().(*bytes.Buffer)
- buf.Reset()
defer bufPool.Put(buf)
+ buf.Reset()
if _, _, err := p.s.NextObject(buf); err != nil {
return 0, err
@@ -222,11 +222,11 @@ func (p *Packfile) getNextObject(h *ObjectHeader, hash plumbing.Hash) (plumbing.
// optimization only if the expanded version of the object still meets
// the small object threshold condition.
buf := bufPool.Get().(*bytes.Buffer)
+ defer bufPool.Put(buf)
buf.Reset()
if _, _, err := p.s.NextObject(buf); err != nil {
return nil, err
}
- defer bufPool.Put(buf)
size = p.getDeltaObjectSize(buf)
if size <= smallObjectThreshold {
@@ -321,12 +321,12 @@ func (p *Packfile) fillRegularObjectContent(obj plumbing.EncodedObject) error {
func (p *Packfile) fillREFDeltaObjectContent(obj plumbing.EncodedObject, ref plumbing.Hash) error {
buf := bufPool.Get().(*bytes.Buffer)
+ defer bufPool.Put(buf)
buf.Reset()
_, _, err := p.s.NextObject(buf)
if err != nil {
return err
}
- defer bufPool.Put(buf)
return p.fillREFDeltaObjectContentWithBuffer(obj, ref, buf)
}
@@ -351,12 +351,12 @@ func (p *Packfile) fillREFDeltaObjectContentWithBuffer(obj plumbing.EncodedObjec
func (p *Packfile) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset int64) error {
buf := bufPool.Get().(*bytes.Buffer)
+ defer bufPool.Put(buf)
buf.Reset()
_, _, err := p.s.NextObject(buf)
if err != nil {
return err
}
- defer bufPool.Put(buf)
return p.fillOFSDeltaObjectContentWithBuffer(obj, offset, buf)
}
diff --git a/plumbing/format/packfile/parser.go b/plumbing/format/packfile/parser.go
index 71cbba9..d8c0f75 100644
--- a/plumbing/format/packfile/parser.go
+++ b/plumbing/format/packfile/parser.go
@@ -4,6 +4,7 @@ import (
"bytes"
"errors"
"io"
+ "io/ioutil"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/cache"
@@ -263,11 +264,14 @@ func (p *Parser) indexObjects() error {
}
func (p *Parser) resolveDeltas() error {
+ buf := &bytes.Buffer{}
for _, obj := range p.oi {
- content, err := p.get(obj)
+ buf.Reset()
+ err := p.get(obj, buf)
if err != nil {
return err
}
+ content := buf.Bytes()
if err := p.onInflatedObjectHeader(obj.Type, obj.Length, obj.Offset); err != nil {
return err
@@ -279,7 +283,7 @@ func (p *Parser) resolveDeltas() error {
if !obj.IsDelta() && len(obj.Children) > 0 {
for _, child := range obj.Children {
- if _, err := p.resolveObject(child, content); err != nil {
+ if err := p.resolveObject(ioutil.Discard, child, content); err != nil {
return err
}
}
@@ -294,82 +298,87 @@ func (p *Parser) resolveDeltas() error {
return nil
}
-func (p *Parser) get(o *objectInfo) (b []byte, err error) {
- var ok bool
+func (p *Parser) get(o *objectInfo, buf *bytes.Buffer) error {
if !o.ExternalRef { // skip cache check for placeholder parents
- b, ok = p.cache.Get(o.Offset)
+ b, ok := p.cache.Get(o.Offset)
+ if ok {
+ _, err := buf.Write(b)
+ return err
+ }
}
// If it's not on the cache and is not a delta we can try to find it in the
// storage, if there's one. External refs must enter here.
- if !ok && p.storage != nil && !o.Type.IsDelta() {
+ if p.storage != nil && !o.Type.IsDelta() {
e, err := p.storage.EncodedObject(plumbing.AnyObject, o.SHA1)
if err != nil {
- return nil, err
+ return err
}
o.Type = e.Type()
r, err := e.Reader()
if err != nil {
- return nil, err
- }
-
- b = make([]byte, e.Size())
- if _, err = r.Read(b); err != nil {
- return nil, err
+ return err
}
- }
- if b != nil {
- return b, nil
+ _, err = buf.ReadFrom(io.LimitReader(r, e.Size()))
+ return err
}
if o.ExternalRef {
// we were not able to resolve a ref in a thin pack
- return nil, ErrReferenceDeltaNotFound
+ return ErrReferenceDeltaNotFound
}
- var data []byte
if o.DiskType.IsDelta() {
- base, err := p.get(o.Parent)
+ b := bufPool.Get().(*bytes.Buffer)
+ defer bufPool.Put(b)
+ b.Reset()
+ err := p.get(o.Parent, b)
if err != nil {
- return nil, err
+ return err
}
+ base := b.Bytes()
- data, err = p.resolveObject(o, base)
+ err = p.resolveObject(buf, o, base)
if err != nil {
- return nil, err
+ return err
}
} else {
- data, err = p.readData(o)
+ err := p.readData(buf, o)
if err != nil {
- return nil, err
+ return err
}
}
if len(o.Children) > 0 {
+ data := make([]byte, buf.Len())
+ copy(data, buf.Bytes())
p.cache.Put(o.Offset, data)
}
-
- return data, nil
+ return nil
}
func (p *Parser) resolveObject(
+ w io.Writer,
o *objectInfo,
base []byte,
-) ([]byte, error) {
+) error {
if !o.DiskType.IsDelta() {
- return nil, nil
+ return nil
}
-
- data, err := p.readData(o)
+ buf := bufPool.Get().(*bytes.Buffer)
+ defer bufPool.Put(buf)
+ buf.Reset()
+ err := p.readData(buf, o)
if err != nil {
- return nil, err
+ return err
}
+ data := buf.Bytes()
data, err = applyPatchBase(o, data, base)
if err != nil {
- return nil, err
+ return err
}
if p.storage != nil {
@@ -377,37 +386,35 @@ func (p *Parser) resolveObject(
obj.SetSize(o.Size())
obj.SetType(o.Type)
if _, err := obj.Write(data); err != nil {
- return nil, err
+ return err
}
if _, err := p.storage.SetEncodedObject(obj); err != nil {
- return nil, err
+ return err
}
}
-
- return data, nil
+ _, err = w.Write(data)
+ return err
}
-func (p *Parser) readData(o *objectInfo) ([]byte, error) {
+func (p *Parser) readData(w io.Writer, o *objectInfo) error {
if !p.scanner.IsSeekable && o.DiskType.IsDelta() {
data, ok := p.deltas[o.Offset]
if !ok {
- return nil, ErrDeltaNotCached
+ return ErrDeltaNotCached
}
-
- return data, nil
+ _, err := w.Write(data)
+ return err
}
if _, err := p.scanner.SeekObjectHeader(o.Offset); err != nil {
- return nil, err
+ return err
}
- buf := new(bytes.Buffer)
- if _, _, err := p.scanner.NextObject(buf); err != nil {
- return nil, err
+ if _, _, err := p.scanner.NextObject(w); err != nil {
+ return err
}
-
- return buf.Bytes(), nil
+ return nil
}
func applyPatchBase(ota *objectInfo, data, base []byte) ([]byte, error) {
diff --git a/plumbing/format/packfile/patch_delta.go b/plumbing/format/packfile/patch_delta.go
index a972f1c..e1a5141 100644
--- a/plumbing/format/packfile/patch_delta.go
+++ b/plumbing/format/packfile/patch_delta.go
@@ -1,8 +1,9 @@
package packfile
import (
+ "bytes"
"errors"
- "io/ioutil"
+ "io"
"gopkg.in/src-d/go-git.v4/plumbing"
)
@@ -26,19 +27,29 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) error {
return err
}
- src, err := ioutil.ReadAll(r)
+ buf := bufPool.Get().(*bytes.Buffer)
+ defer bufPool.Put(buf)
+ buf.Reset()
+ _, err = buf.ReadFrom(r)
if err != nil {
return err
}
+ src := buf.Bytes()
- dst, err := PatchDelta(src, delta)
+ dst := bufPool.Get().(*bytes.Buffer)
+ defer bufPool.Put(dst)
+ dst.Reset()
+ err = patchDelta(dst, src, delta)
if err != nil {
return err
}
- target.SetSize(int64(len(dst)))
- _, err = w.Write(dst)
+ target.SetSize(int64(dst.Len()))
+
+ b := byteSlicePool.Get().([]byte)
+ _, err = io.CopyBuffer(w, dst, b)
+ byteSlicePool.Put(b)
return err
}
@@ -51,23 +62,31 @@ var (
// An error will be returned if delta is corrupted (ErrDeltaLen) or an action command
// is not copy from source or copy from delta (ErrDeltaCmd).
func PatchDelta(src, delta []byte) ([]byte, error) {
+ b := &bytes.Buffer{}
+ if err := patchDelta(b, src, delta); err != nil {
+ return nil, err
+ }
+ return b.Bytes(), nil
+}
+
+func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
if len(delta) < deltaSizeMin {
- return nil, ErrInvalidDelta
+ return ErrInvalidDelta
}
srcSz, delta := decodeLEB128(delta)
if srcSz != uint(len(src)) {
- return nil, ErrInvalidDelta
+ return ErrInvalidDelta
}
targetSz, delta := decodeLEB128(delta)
remainingTargetSz := targetSz
var cmd byte
- dest := make([]byte, 0, targetSz)
+ dst.Grow(int(targetSz))
for {
if len(delta) == 0 {
- return nil, ErrInvalidDelta
+ return ErrInvalidDelta
}
cmd = delta[0]
@@ -77,35 +96,35 @@ func PatchDelta(src, delta []byte) ([]byte, error) {
var err error
offset, delta, err = decodeOffset(cmd, delta)
if err != nil {
- return nil, err
+ return err
}
sz, delta, err = decodeSize(cmd, delta)
if err != nil {
- return nil, err
+ return err
}
if invalidSize(sz, targetSz) ||
invalidOffsetSize(offset, sz, srcSz) {
break
}
- dest = append(dest, src[offset:offset+sz]...)
+ dst.Write(src[offset:offset+sz])
remainingTargetSz -= sz
} else if isCopyFromDelta(cmd) {
sz := uint(cmd) // cmd is the size itself
if invalidSize(sz, targetSz) {
- return nil, ErrInvalidDelta
+ return ErrInvalidDelta
}
if uint(len(delta)) < sz {
- return nil, ErrInvalidDelta
+ return ErrInvalidDelta
}
- dest = append(dest, delta[0:sz]...)
+ dst.Write(delta[0:sz])
remainingTargetSz -= sz
delta = delta[sz:]
} else {
- return nil, ErrDeltaCmd
+ return ErrDeltaCmd
}
if remainingTargetSz <= 0 {
@@ -113,7 +132,7 @@ func PatchDelta(src, delta []byte) ([]byte, error) {
}
}
- return dest, nil
+ return nil
}
// Decodes a number encoded as an unsigned LEB128 at the start of some
diff --git a/plumbing/format/packfile/scanner_test.go b/plumbing/format/packfile/scanner_test.go
index a401d6d..3078477 100644
--- a/plumbing/format/packfile/scanner_test.go
+++ b/plumbing/format/packfile/scanner_test.go
@@ -140,6 +140,7 @@ func (s *ScannerSuite) TestReaderReset(c *C) {
p := NewScanner(r)
version, objects, err := p.Header()
+ c.Assert(err, IsNil)
c.Assert(version, Equals, VersionSupported)
c.Assert(objects, Equals, uint32(31))