aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/object
diff options
context:
space:
mode:
Diffstat (limited to 'plumbing/object')
-rw-r--r--plumbing/object/blob_test.go7
-rw-r--r--plumbing/object/change.go2
-rw-r--r--plumbing/object/commit.go18
-rw-r--r--plumbing/object/commit_test.go75
-rw-r--r--plumbing/object/common.go12
-rw-r--r--plumbing/object/object_test.go3
-rw-r--r--plumbing/object/rename.go13
-rw-r--r--plumbing/object/signature.go101
-rw-r--r--plumbing/object/signature_test.go180
-rw-r--r--plumbing/object/tag.go45
-rw-r--r--plumbing/object/tag_test.go24
-rw-r--r--plumbing/object/tree.go8
12 files changed, 415 insertions, 73 deletions
diff --git a/plumbing/object/blob_test.go b/plumbing/object/blob_test.go
index 4461343..9481dbe 100644
--- a/plumbing/object/blob_test.go
+++ b/plumbing/object/blob_test.go
@@ -3,7 +3,6 @@ package object
import (
"bytes"
"io"
- "io/ioutil"
"github.com/go-git/go-git/v5/plumbing"
@@ -37,7 +36,7 @@ func (s *BlobsSuite) TestBlobHash(c *C) {
c.Assert(err, IsNil)
defer func() { c.Assert(reader.Close(), IsNil) }()
- data, err := ioutil.ReadAll(reader)
+ data, err := io.ReadAll(reader)
c.Assert(err, IsNil)
c.Assert(string(data), Equals, "FOO")
}
@@ -96,14 +95,14 @@ func (s *BlobsSuite) TestBlobIter(c *C) {
r1, err := b.Reader()
c.Assert(err, IsNil)
- b1, err := ioutil.ReadAll(r1)
+ b1, err := io.ReadAll(r1)
c.Assert(err, IsNil)
c.Assert(r1.Close(), IsNil)
r2, err := blobs[i].Reader()
c.Assert(err, IsNil)
- b2, err := ioutil.ReadAll(r2)
+ b2, err := io.ReadAll(r2)
c.Assert(err, IsNil)
c.Assert(r2.Close(), IsNil)
diff --git a/plumbing/object/change.go b/plumbing/object/change.go
index 8b119bc..3c619df 100644
--- a/plumbing/object/change.go
+++ b/plumbing/object/change.go
@@ -39,7 +39,7 @@ func (c *Change) Action() (merkletrie.Action, error) {
return merkletrie.Modify, nil
}
-// Files return the files before and after a change.
+// Files returns the files before and after a change.
// For insertions from will be nil. For deletions to will be nil.
func (c *Change) Files() (from, to *File, err error) {
action, err := c.Action()
diff --git a/plumbing/object/commit.go b/plumbing/object/commit.go
index 7a1b8e5..8a0f35c 100644
--- a/plumbing/object/commit.go
+++ b/plumbing/object/commit.go
@@ -1,7 +1,6 @@
package object
import (
- "bufio"
"bytes"
"context"
"errors"
@@ -14,6 +13,7 @@ import (
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/storer"
"github.com/go-git/go-git/v5/utils/ioutil"
+ "github.com/go-git/go-git/v5/utils/sync"
)
const (
@@ -180,9 +180,8 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
}
defer ioutil.CheckClose(reader, &err)
- r := bufPool.Get().(*bufio.Reader)
- defer bufPool.Put(r)
- r.Reset(reader)
+ r := sync.GetBufioReader(reader)
+ defer sync.PutBufioReader(r)
var message bool
var pgpsig bool
@@ -377,6 +376,17 @@ func (c *Commit) Verify(armoredKeyRing string) (*openpgp.Entity, error) {
return openpgp.CheckArmoredDetachedSignature(keyring, er, signature, nil)
}
+// Less defines a compare function to determine which commit is 'earlier' by:
+// - First use Committer.When
+// - If Committer.When are equal then use Author.When
+// - If Author.When also equal then compare the string value of the hash
+func (c *Commit) Less(rhs *Commit) bool {
+ return c.Committer.When.Before(rhs.Committer.When) ||
+ (c.Committer.When.Equal(rhs.Committer.When) &&
+ (c.Author.When.Before(rhs.Author.When) ||
+ (c.Author.When.Equal(rhs.Author.When) && bytes.Compare(c.Hash[:], rhs.Hash[:]) < 0)))
+}
+
func indent(t string) string {
var output []string
for _, line := range strings.Split(t, "\n") {
diff --git a/plumbing/object/commit_test.go b/plumbing/object/commit_test.go
index 468a751..4b0f6b4 100644
--- a/plumbing/object/commit_test.go
+++ b/plumbing/object/commit_test.go
@@ -4,7 +4,6 @@ import (
"bytes"
"context"
"io"
- "io/ioutil"
"strings"
"time"
@@ -449,7 +448,7 @@ YIefGtzXfldDxg4=
`
e, err := commit.Verify(armoredKeyRing)
- c.Assert(err, IsNil)
+ c.Assert(err, IsNil)
_, ok := e.Identities["go-git test key"]
c.Assert(ok, Equals, true)
@@ -492,7 +491,7 @@ func (s *SuiteCommit) TestEncodeWithoutSignature(c *C) {
c.Assert(err, IsNil)
er, err := encoded.Reader()
c.Assert(err, IsNil)
- payload, err := ioutil.ReadAll(er)
+ payload, err := io.ReadAll(er)
c.Assert(err, IsNil)
c.Assert(string(payload), Equals, ""+
@@ -504,3 +503,73 @@ func (s *SuiteCommit) TestEncodeWithoutSignature(c *C) {
"\n"+
"Merge branch 'master' of github.com:tyba/git-fixture\n")
}
+
+func (s *SuiteCommit) TestLess(c *C) {
+ when1 := time.Now()
+ when2 := when1.Add(time.Hour)
+
+ hash1 := plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea")
+ hash2 := plumbing.NewHash("2669dce138d9b841a518c64b10914d88f5e488ea")
+
+ commitLessTests := []struct {
+ Committer1When, Committer2When time.Time
+ Author1When, Author2When time.Time
+ Hash1, Hash2 plumbing.Hash
+ Exp bool
+ }{
+ {when1, when1, when1, when1, hash1, hash2, true},
+ {when1, when1, when1, when1, hash2, hash1, false},
+ {when1, when1, when1, when2, hash1, hash2, true},
+ {when1, when1, when1, when2, hash2, hash1, true},
+ {when1, when1, when2, when1, hash1, hash2, false},
+ {when1, when1, when2, when1, hash2, hash1, false},
+ {when1, when1, when2, when2, hash1, hash2, true},
+ {when1, when1, when2, when2, hash2, hash1, false},
+ {when1, when2, when1, when1, hash1, hash2, true},
+ {when1, when2, when1, when1, hash2, hash1, true},
+ {when1, when2, when1, when2, hash1, hash2, true},
+ {when1, when2, when1, when2, hash2, hash1, true},
+ {when1, when2, when2, when1, hash1, hash2, true},
+ {when1, when2, when2, when1, hash2, hash1, true},
+ {when1, when2, when2, when2, hash1, hash2, true},
+ {when1, when2, when2, when2, hash2, hash1, true},
+ {when2, when1, when1, when1, hash1, hash2, false},
+ {when2, when1, when1, when1, hash2, hash1, false},
+ {when2, when1, when1, when2, hash1, hash2, false},
+ {when2, when1, when1, when2, hash2, hash1, false},
+ {when2, when1, when2, when1, hash1, hash2, false},
+ {when2, when1, when2, when1, hash2, hash1, false},
+ {when2, when1, when2, when2, hash1, hash2, false},
+ {when2, when1, when2, when2, hash2, hash1, false},
+ {when2, when2, when1, when1, hash1, hash2, true},
+ {when2, when2, when1, when1, hash2, hash1, false},
+ {when2, when2, when1, when2, hash1, hash2, true},
+ {when2, when2, when1, when2, hash2, hash1, true},
+ {when2, when2, when2, when1, hash1, hash2, false},
+ {when2, when2, when2, when1, hash2, hash1, false},
+ {when2, when2, when2, when2, hash1, hash2, true},
+ {when2, when2, when2, when2, hash2, hash1, false},
+ }
+
+ for _, t := range commitLessTests {
+ commit1 := &Commit{
+ Hash: t.Hash1,
+ Author: Signature{
+ When: t.Author1When,
+ },
+ Committer: Signature{
+ When: t.Committer1When,
+ },
+ }
+ commit2 := &Commit{
+ Hash: t.Hash2,
+ Author: Signature{
+ When: t.Author2When,
+ },
+ Committer: Signature{
+ When: t.Committer2When,
+ },
+ }
+ c.Assert(commit1.Less(commit2), Equals, t.Exp)
+ }
+}
diff --git a/plumbing/object/common.go b/plumbing/object/common.go
deleted file mode 100644
index 3591f5f..0000000
--- a/plumbing/object/common.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package object
-
-import (
- "bufio"
- "sync"
-)
-
-var bufPool = sync.Pool{
- New: func() interface{} {
- return bufio.NewReader(nil)
- },
-}
diff --git a/plumbing/object/object_test.go b/plumbing/object/object_test.go
index 6c95eef..c4fdb4c 100644
--- a/plumbing/object/object_test.go
+++ b/plumbing/object/object_test.go
@@ -2,7 +2,6 @@ package object
import (
"io"
- "io/ioutil"
"testing"
"time"
@@ -103,7 +102,7 @@ func (s *ObjectsSuite) TestParseTree(c *C) {
reader, err := f.Reader()
c.Assert(err, IsNil)
defer func() { c.Assert(reader.Close(), IsNil) }()
- content, _ := ioutil.ReadAll(reader)
+ content, _ := io.ReadAll(reader)
c.Assert(content, HasLen, 2780)
}
}
diff --git a/plumbing/object/rename.go b/plumbing/object/rename.go
index 7fed72c..ad2b902 100644
--- a/plumbing/object/rename.go
+++ b/plumbing/object/rename.go
@@ -403,10 +403,16 @@ func min(a, b int) int {
return b
}
+const maxMatrixSize = 10000
+
func buildSimilarityMatrix(srcs, dsts []*Change, renameScore int) (similarityMatrix, error) {
// Allocate for the worst-case scenario where every pair has a score
// that we need to consider. We might not need that many.
- matrix := make(similarityMatrix, 0, len(srcs)*len(dsts))
+ matrixSize := len(srcs) * len(dsts)
+ if matrixSize > maxMatrixSize {
+ matrixSize = maxMatrixSize
+ }
+ matrix := make(similarityMatrix, 0, matrixSize)
srcSizes := make([]int64, len(srcs))
dstSizes := make([]int64, len(dsts))
dstTooLarge := make(map[int]bool)
@@ -735,10 +741,7 @@ func (i *similarityIndex) add(key int, cnt uint64) error {
// It's the same key, so increment the counter.
var err error
i.hashes[j], err = newKeyCountPair(key, v.count()+cnt)
- if err != nil {
- return err
- }
- return nil
+ return err
} else if j+1 >= len(i.hashes) {
j = 0
} else {
diff --git a/plumbing/object/signature.go b/plumbing/object/signature.go
new file mode 100644
index 0000000..91cf371
--- /dev/null
+++ b/plumbing/object/signature.go
@@ -0,0 +1,101 @@
+package object
+
+import "bytes"
+
+const (
+ signatureTypeUnknown signatureType = iota
+ signatureTypeOpenPGP
+ signatureTypeX509
+ signatureTypeSSH
+)
+
+var (
+ // openPGPSignatureFormat is the format of an OpenPGP signature.
+ openPGPSignatureFormat = signatureFormat{
+ []byte("-----BEGIN PGP SIGNATURE-----"),
+ []byte("-----BEGIN PGP MESSAGE-----"),
+ }
+ // x509SignatureFormat is the format of an X509 signature, which is
+ // a PKCS#7 (S/MIME) signature.
+ x509SignatureFormat = signatureFormat{
+ []byte("-----BEGIN CERTIFICATE-----"),
+ }
+
+ // sshSignatureFormat is the format of an SSH signature.
+ sshSignatureFormat = signatureFormat{
+ []byte("-----BEGIN SSH SIGNATURE-----"),
+ }
+)
+
+var (
+ // knownSignatureFormats is a map of known signature formats, indexed by
+ // their signatureType.
+ knownSignatureFormats = map[signatureType]signatureFormat{
+ signatureTypeOpenPGP: openPGPSignatureFormat,
+ signatureTypeX509: x509SignatureFormat,
+ signatureTypeSSH: sshSignatureFormat,
+ }
+)
+
+// signatureType represents the type of the signature.
+type signatureType int8
+
+// signatureFormat represents the beginning of a signature.
+type signatureFormat [][]byte
+
+// typeForSignature returns the type of the signature based on its format.
+func typeForSignature(b []byte) signatureType {
+ for t, i := range knownSignatureFormats {
+ for _, begin := range i {
+ if bytes.HasPrefix(b, begin) {
+ return t
+ }
+ }
+ }
+ return signatureTypeUnknown
+}
+
+// parseSignedBytes returns the position of the last signature block found in
+// the given bytes. If no signature block is found, it returns -1.
+//
+// When multiple signature blocks are found, the position of the last one is
+// returned. Any tailing bytes after this signature block start should be
+// considered part of the signature.
+//
+// Given this, it would be safe to use the returned position to split the bytes
+// into two parts: the first part containing the message, the second part
+// containing the signature.
+//
+// Example:
+//
+// message := []byte(`Message with signature
+//
+// -----BEGIN SSH SIGNATURE-----
+// ...`)
+//
+// var signature string
+// if pos, _ := parseSignedBytes(message); pos != -1 {
+// signature = string(message[pos:])
+// message = message[:pos]
+// }
+//
+// This logic is on par with git's gpg-interface.c:parse_signed_buffer().
+// https://github.com/git/git/blob/7c2ef319c52c4997256f5807564523dfd4acdfc7/gpg-interface.c#L668
+func parseSignedBytes(b []byte) (int, signatureType) {
+ var n, match = 0, -1
+ var t signatureType
+ for n < len(b) {
+ var i = b[n:]
+ if st := typeForSignature(i); st != signatureTypeUnknown {
+ match = n
+ t = st
+ }
+ if eol := bytes.IndexByte(i, '\n'); eol >= 0 {
+ n += eol + 1
+ continue
+ }
+ // If we reach this point, we've reached the end.
+ break
+ }
+ return match, t
+}
diff --git a/plumbing/object/signature_test.go b/plumbing/object/signature_test.go
new file mode 100644
index 0000000..1bdb1d1
--- /dev/null
+++ b/plumbing/object/signature_test.go
@@ -0,0 +1,180 @@
+package object
+
+import (
+ "bytes"
+ "testing"
+)
+
+func Test_typeForSignature(t *testing.T) {
+ tests := []struct {
+ name string
+ b []byte
+ want signatureType
+ }{
+ {
+ name: "known signature format (PGP)",
+ b: []byte(`-----BEGIN PGP SIGNATURE-----
+
+iHUEABYKAB0WIQTMqU0ycQ3f6g3PMoWMmmmF4LuV8QUCYGebVwAKCRCMmmmF4LuV
+8VtyAP9LbuXAhtK6FQqOjKybBwlV70rLcXVP24ubDuz88VVwSgD+LuObsasWq6/U
+TssDKHUR2taa53bQYjkZQBpvvwOrLgc=
+=YQUf
+-----END PGP SIGNATURE-----`),
+ want: signatureTypeOpenPGP,
+ },
+ {
+ name: "known signature format (SSH)",
+ b: []byte(`-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgij/EfHS8tCjolj5uEANXgKzFfp
+0D7wOhjWVbYZH6KugAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
+AAAAQIYHMhSVV9L2xwJuV8eWMLjThya8yXgCHDzw3p01D19KirrabW0veiichPB5m+Ihtr
+MKEQruIQWJb+8HVXwssA4=
+-----END SSH SIGNATURE-----`),
+ want: signatureTypeSSH,
+ },
+ {
+ name: "known signature format (X509)",
+ b: []byte(`-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIJALZ9Z3Z9Z3Z9MA0GCSqGSIb3DQEBCwUAMIGIMQswCQYD
+VQQGEwJTRTEOMAwGA1UECAwFVGV4YXMxDjAMBgNVBAcMBVRleGFzMQ4wDAYDVQQK
+DAVUZXhhczEOMAwGA1UECwwFVGV4YXMxGDAWBgNVBAMMD1RleGFzIENlcnRpZmlj
+YXRlMB4XDTE3MDUyNjE3MjY0MloXDTI3MDUyNDE3MjY0MlowgYgxCzAJBgNVBAYT
+AlNFMQ4wDAYDVQQIDAVUZXhhczEOMAwGA1UEBwwFVGV4YXMxDjAMBgNVBAoMBVRl
+eGFzMQ4wDAYDVQQLDAVUZXhhczEYMBYGA1UEAwwPVGV4YXMgQ2VydGlmaWNhdGUw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQZ9Z3Z9Z3Z9Z3Z9Z3Z9Z3
+-----END CERTIFICATE-----`),
+ want: signatureTypeX509,
+ },
+ {
+ name: "unknown signature format",
+ b: []byte(`-----BEGIN ARBITRARY SIGNATURE-----
+U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgij/EfHS8tCjolj5uEANXgKzFfp
+-----END UNKNOWN SIGNATURE-----`),
+ want: signatureTypeUnknown,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := typeForSignature(tt.b); got != tt.want {
+ t.Errorf("typeForSignature() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func Test_parseSignedBytes(t *testing.T) {
+ tests := []struct {
+ name string
+ b []byte
+ wantSignature []byte
+ wantType signatureType
+ }{
+ {
+ name: "detects signature and type",
+ b: []byte(`signed tag
+-----BEGIN PGP SIGNATURE-----
+
+iQGzBAABCAAdFiEE/h5sbbqJFh9j1AdUSqtFFGopTmwFAmB5XFkACgkQSqtFFGop
+TmxvgAv+IPjX5WCLFUIMx8hquMZp1VkhQrseE7rljUYaYpga8gZ9s4kseTGhy7Un
+61U3Ro6cTPEiQF/FkAGzSdPuGqv0ARBqHDX2tUI9+Zs/K8aG8tN+JTaof0gBcTyI
+BLbZVYDTxbS9whxSDewQd0OvBG1m9ISLUhjXo6mbaVvrKXNXTHg40MPZ8ZxjR/vN
+hxXXoUVnFyEDo+v6nK56mYtapThDaQQHHzD6D3VaCq3Msog7qAh9/ZNBmgb88aQ3
+FoK8PHMyr5elsV3mE9bciZBUc+dtzjOvp94uQ5ZKUXaPusXaYXnKpVnzhyer6RBI
+gJLWtPwAinqmN41rGJ8jDAGrpPNjaRrMhGtbyVUPUf19OxuUIroe77sIIKTP0X2o
+Wgp56dYpTst0JcGv/FYCeau/4pTRDfwHAOcDiBQ/0ag9IrZp9P8P9zlKmzNPEraV
+pAe1/EFuhv2UDLucAiWM8iDZIcw8iN0OYMOGUmnk0WuGIo7dzLeqMGY+ND5n5Z8J
+sZC//k6m
+=VhHy
+-----END PGP SIGNATURE-----`),
+ wantSignature: []byte(`-----BEGIN PGP SIGNATURE-----
+
+iQGzBAABCAAdFiEE/h5sbbqJFh9j1AdUSqtFFGopTmwFAmB5XFkACgkQSqtFFGop
+TmxvgAv+IPjX5WCLFUIMx8hquMZp1VkhQrseE7rljUYaYpga8gZ9s4kseTGhy7Un
+61U3Ro6cTPEiQF/FkAGzSdPuGqv0ARBqHDX2tUI9+Zs/K8aG8tN+JTaof0gBcTyI
+BLbZVYDTxbS9whxSDewQd0OvBG1m9ISLUhjXo6mbaVvrKXNXTHg40MPZ8ZxjR/vN
+hxXXoUVnFyEDo+v6nK56mYtapThDaQQHHzD6D3VaCq3Msog7qAh9/ZNBmgb88aQ3
+FoK8PHMyr5elsV3mE9bciZBUc+dtzjOvp94uQ5ZKUXaPusXaYXnKpVnzhyer6RBI
+gJLWtPwAinqmN41rGJ8jDAGrpPNjaRrMhGtbyVUPUf19OxuUIroe77sIIKTP0X2o
+Wgp56dYpTst0JcGv/FYCeau/4pTRDfwHAOcDiBQ/0ag9IrZp9P8P9zlKmzNPEraV
+pAe1/EFuhv2UDLucAiWM8iDZIcw8iN0OYMOGUmnk0WuGIo7dzLeqMGY+ND5n5Z8J
+sZC//k6m
+=VhHy
+-----END PGP SIGNATURE-----`),
+ wantType: signatureTypeOpenPGP,
+ },
+ {
+ name: "last signature for multiple signatures",
+ b: []byte(`signed tag
+-----BEGIN PGP SIGNATURE-----
+
+iQGzBAABCAAdFiEE/h5sbbqJFh9j1AdUSqtFFGopTmwFAmB5XFkACgkQSqtFFGop
+TmxvgAv+IPjX5WCLFUIMx8hquMZp1VkhQrseE7rljUYaYpga8gZ9s4kseTGhy7Un
+61U3Ro6cTPEiQF/FkAGzSdPuGqv0ARBqHDX2tUI9+Zs/K8aG8tN+JTaof0gBcTyI
+BLbZVYDTxbS9whxSDewQd0OvBG1m9ISLUhjXo6mbaVvrKXNXTHg40MPZ8ZxjR/vN
+hxXXoUVnFyEDo+v6nK56mYtapThDaQQHHzD6D3VaCq3Msog7qAh9/ZNBmgb88aQ3
+FoK8PHMyr5elsV3mE9bciZBUc+dtzjOvp94uQ5ZKUXaPusXaYXnKpVnzhyer6RBI
+gJLWtPwAinqmN41rGJ8jDAGrpPNjaRrMhGtbyVUPUf19OxuUIroe77sIIKTP0X2o
+Wgp56dYpTst0JcGv/FYCeau/4pTRDfwHAOcDiBQ/0ag9IrZp9P8P9zlKmzNPEraV
+pAe1/EFuhv2UDLucAiWM8iDZIcw8iN0OYMOGUmnk0WuGIo7dzLeqMGY+ND5n5Z8J
+sZC//k6m
+=VhHy
+-----END PGP SIGNATURE-----
+-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgij/EfHS8tCjolj5uEANXgKzFfp
+0D7wOhjWVbYZH6KugAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
+AAAAQIYHMhSVV9L2xwJuV8eWMLjThya8yXgCHDzw3p01D19KirrabW0veiichPB5m+Ihtr
+MKEQruIQWJb+8HVXwssA4=
+-----END SSH SIGNATURE-----`),
+ wantSignature: []byte(`-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgij/EfHS8tCjolj5uEANXgKzFfp
+0D7wOhjWVbYZH6KugAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
+AAAAQIYHMhSVV9L2xwJuV8eWMLjThya8yXgCHDzw3p01D19KirrabW0veiichPB5m+Ihtr
+MKEQruIQWJb+8HVXwssA4=
+-----END SSH SIGNATURE-----`),
+ wantType: signatureTypeSSH,
+ },
+ {
+ name: "signature with trailing data",
+ b: []byte(`An invalid
+
+-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgij/EfHS8tCjolj5uEANXgKzFfp
+0D7wOhjWVbYZH6KugAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
+AAAAQIYHMhSVV9L2xwJuV8eWMLjThya8yXgCHDzw3p01D19KirrabW0veiichPB5m+Ihtr
+MKEQruIQWJb+8HVXwssA4=
+-----END SSH SIGNATURE-----
+
+signed tag`),
+ wantSignature: []byte(`-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgij/EfHS8tCjolj5uEANXgKzFfp
+0D7wOhjWVbYZH6KugAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
+AAAAQIYHMhSVV9L2xwJuV8eWMLjThya8yXgCHDzw3p01D19KirrabW0veiichPB5m+Ihtr
+MKEQruIQWJb+8HVXwssA4=
+-----END SSH SIGNATURE-----
+
+signed tag`),
+ wantType: signatureTypeSSH,
+ },
+ {
+ name: "data without signature",
+ b: []byte(`Some message`),
+ wantSignature: []byte(``),
+ wantType: signatureTypeUnknown,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ pos, st := parseSignedBytes(tt.b)
+ var signature []byte
+ if pos >= 0 {
+ signature = tt.b[pos:]
+ }
+ if !bytes.Equal(signature, tt.wantSignature) {
+ t.Errorf("parseSignedBytes() got = %s for pos = %v, want %s", signature, pos, tt.wantSignature)
+ }
+ if st != tt.wantType {
+ t.Errorf("parseSignedBytes() got1 = %v, want %v", st, tt.wantType)
+ }
+ })
+ }
+}
diff --git a/plumbing/object/tag.go b/plumbing/object/tag.go
index 216010d..cf46c08 100644
--- a/plumbing/object/tag.go
+++ b/plumbing/object/tag.go
@@ -1,18 +1,16 @@
package object
import (
- "bufio"
"bytes"
"fmt"
"io"
- stdioutil "io/ioutil"
"strings"
"github.com/ProtonMail/go-crypto/openpgp"
-
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/storer"
"github.com/go-git/go-git/v5/utils/ioutil"
+ "github.com/go-git/go-git/v5/utils/sync"
)
// Tag represents an annotated tag object. It points to a single git object of
@@ -93,9 +91,9 @@ func (t *Tag) Decode(o plumbing.EncodedObject) (err error) {
}
defer ioutil.CheckClose(reader, &err)
- r := bufPool.Get().(*bufio.Reader)
- defer bufPool.Put(r)
- r.Reset(reader)
+ r := sync.GetBufioReader(reader)
+ defer sync.PutBufioReader(r)
+
for {
var line []byte
line, err = r.ReadBytes('\n')
@@ -128,40 +126,15 @@ func (t *Tag) Decode(o plumbing.EncodedObject) (err error) {
}
}
- data, err := stdioutil.ReadAll(r)
+ data, err := io.ReadAll(r)
if err != nil {
return err
}
-
- var pgpsig bool
- // Check if data contains PGP signature.
- if bytes.Contains(data, []byte(beginpgp)) {
- // Split the lines at newline.
- messageAndSig := bytes.Split(data, []byte("\n"))
-
- for _, l := range messageAndSig {
- if pgpsig {
- if bytes.Contains(l, []byte(endpgp)) {
- t.PGPSignature += endpgp + "\n"
- break
- } else {
- t.PGPSignature += string(l) + "\n"
- }
- continue
- }
-
- // Check if it's the beginning of a PGP signature.
- if bytes.Contains(l, []byte(beginpgp)) {
- t.PGPSignature += beginpgp + "\n"
- pgpsig = true
- continue
- }
-
- t.Message += string(l) + "\n"
- }
- } else {
- t.Message = string(data)
+ if sm, _ := parseSignedBytes(data); sm >= 0 {
+ t.PGPSignature = string(data[sm:])
+ data = data[:sm]
}
+ t.Message = string(data)
return nil
}
diff --git a/plumbing/object/tag_test.go b/plumbing/object/tag_test.go
index cd1d15d..d374c6c 100644
--- a/plumbing/object/tag_test.go
+++ b/plumbing/object/tag_test.go
@@ -3,7 +3,6 @@ package object
import (
"fmt"
"io"
- "io/ioutil"
"strings"
"time"
@@ -312,6 +311,27 @@ RUysgqjcpT8+iQM1PblGfHR4XAhuOqN5Fx06PSaFZhqvWFezJ28/CLyX5q+oIVk=
c.Assert(decoded.PGPSignature, Equals, pgpsignature)
}
+func (s *TagSuite) TestSSHSignatureSerialization(c *C) {
+ encoded := &plumbing.MemoryObject{}
+ decoded := &Tag{}
+ tag := s.tag(c, plumbing.NewHash("b742a2a9fa0afcfa9a6fad080980fbc26b007c69"))
+
+ signature := `-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgij/EfHS8tCjolj5uEANXgKzFfp
+0D7wOhjWVbYZH6KugAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
+AAAAQIYHMhSVV9L2xwJuV8eWMLjThya8yXgCHDzw3p01D19KirrabW0veiichPB5m+Ihtr
+MKEQruIQWJb+8HVXwssA4=
+-----END SSH SIGNATURE-----`
+ tag.PGPSignature = signature
+
+ err := tag.Encode(encoded)
+ c.Assert(err, IsNil)
+
+ err = decoded.Decode(encoded)
+ c.Assert(err, IsNil)
+ c.Assert(decoded.PGPSignature, Equals, signature)
+}
+
func (s *TagSuite) TestVerify(c *C) {
ts := time.Unix(1617403017, 0)
loc, _ := time.LoadLocation("UTC")
@@ -445,7 +465,7 @@ func (s *TagSuite) TestEncodeWithoutSignature(c *C) {
c.Assert(err, IsNil)
er, err := encoded.Reader()
c.Assert(err, IsNil)
- payload, err := ioutil.ReadAll(er)
+ payload, err := io.ReadAll(er)
c.Assert(err, IsNil)
c.Assert(string(payload), Equals, ""+
diff --git a/plumbing/object/tree.go b/plumbing/object/tree.go
index 5e6378c..e9f7666 100644
--- a/plumbing/object/tree.go
+++ b/plumbing/object/tree.go
@@ -1,7 +1,6 @@
package object
import (
- "bufio"
"context"
"errors"
"fmt"
@@ -14,6 +13,7 @@ import (
"github.com/go-git/go-git/v5/plumbing/filemode"
"github.com/go-git/go-git/v5/plumbing/storer"
"github.com/go-git/go-git/v5/utils/ioutil"
+ "github.com/go-git/go-git/v5/utils/sync"
)
const (
@@ -230,9 +230,9 @@ func (t *Tree) Decode(o plumbing.EncodedObject) (err error) {
}
defer ioutil.CheckClose(reader, &err)
- r := bufPool.Get().(*bufio.Reader)
- defer bufPool.Put(r)
- r.Reset(reader)
+ r := sync.GetBufioReader(reader)
+ defer sync.PutBufioReader(r)
+
for {
str, err := r.ReadString(' ')
if err != nil {