aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlberto Cortés <alcortesm@gmail.com>2016-10-19 22:08:59 +0200
committerMáximo Cuadros <mcuadros@gmail.com>2016-10-19 22:08:59 +0200
commit8cd772a53e8ecd2687b739eea110fa9b179f1e0f (patch)
tree37911e19713b8f562c801efc172244795655cb8e
parent176cdac72c9c6eb8d875c90664a433d94e968438 (diff)
downloadgo-git-8cd772a53e8ecd2687b739eea110fa9b179f1e0f.tar.gz
Fix pktline api (#89)v4.0.0-rc1
* Change pktline API so you can add payloads The old pktline API only had one method: New, that receives the payloads and return the new PktLine, that was an io.Reader. This means you have to prepare the contents beforehand, in a [][]byte and then call the ctor to build the pktlines. Now, the construction of the pktlines and the method to add payloads are separated: New() // creates an empty PktLines AddFlush() Add(pp ...[]byte) AddString(pp ...string) and a PktLines has a public member R, which is the io.Reader of the pktlines added. * metalinter * change package name from pktlines to pktline * change package name from pktlines to pktline for true * make pktlines a reader instead of have a reader
-rw-r--r--clients/common/common.go30
-rw-r--r--formats/packp/pktline/pktline.go114
-rw-r--r--formats/packp/pktline/pktline_test.go199
-rw-r--r--formats/packp/pktline/pktlines.go140
-rw-r--r--formats/packp/pktline/pktlines_test.go231
-rw-r--r--formats/packp/pktline/scanner_test.go43
6 files changed, 408 insertions, 349 deletions
diff --git a/clients/common/common.go b/clients/common/common.go
index df1c233..0179bfd 100644
--- a/clients/common/common.go
+++ b/clients/common/common.go
@@ -293,14 +293,14 @@ func (r *GitUploadPackInfo) String() string {
}
func (r *GitUploadPackInfo) Bytes() []byte {
- payloads := []string{}
- payloads = append(payloads, "# service=git-upload-pack\n")
+ p := pktline.New()
+ _ = p.AddString("# service=git-upload-pack\n")
// inserting a flush-pkt here violates the protocol spec, but some
// servers do it, like Github.com
- payloads = append(payloads, "")
+ p.AddFlush()
firstLine := fmt.Sprintf("%s HEAD\x00%s\n", r.Head().Hash(), r.Capabilities.String())
- payloads = append(payloads, firstLine)
+ _ = p.AddString(firstLine)
for _, ref := range r.Refs {
if ref.Type() != core.HashReference {
@@ -308,12 +308,11 @@ func (r *GitUploadPackInfo) Bytes() []byte {
}
ref := fmt.Sprintf("%s %s\n", ref.Hash(), ref.Name())
- payloads = append(payloads, ref)
+ _ = p.AddString(ref)
}
- payloads = append(payloads, "")
- pktlines, _ := pktline.NewFromStrings(payloads...)
- b, _ := ioutil.ReadAll(pktlines)
+ p.AddFlush()
+ b, _ := ioutil.ReadAll(p)
return b
}
@@ -338,25 +337,24 @@ func (r *GitUploadPackRequest) String() string {
}
func (r *GitUploadPackRequest) Reader() *strings.Reader {
- payloads := []string{}
+ p := pktline.New()
for _, want := range r.Wants {
- payloads = append(payloads, fmt.Sprintf("want %s\n", want))
+ _ = p.AddString(fmt.Sprintf("want %s\n", want))
}
for _, have := range r.Haves {
- payloads = append(payloads, fmt.Sprintf("have %s\n", have))
+ _ = p.AddString(fmt.Sprintf("have %s\n", have))
}
if r.Depth != 0 {
- payloads = append(payloads, fmt.Sprintf("deepen %d\n", r.Depth))
+ _ = p.AddString(fmt.Sprintf("deepen %d\n", r.Depth))
}
- payloads = append(payloads, "")
- payloads = append(payloads, "done\n")
+ p.AddFlush()
+ _ = p.AddString("done\n")
- pktlines, _ := pktline.NewFromStrings(payloads...)
- b, _ := ioutil.ReadAll(pktlines)
+ b, _ := ioutil.ReadAll(p)
return strings.NewReader(string(b))
}
diff --git a/formats/packp/pktline/pktline.go b/formats/packp/pktline/pktline.go
deleted file mode 100644
index 58c36fe..0000000
--- a/formats/packp/pktline/pktline.go
+++ /dev/null
@@ -1,114 +0,0 @@
-// Package pktline implements reading and creating pkt-lines as per
-// https://github.com/git/git/blob/master/Documentation/technical/protocol-common.txt.
-package pktline
-
-import (
- "bytes"
- "errors"
- "io"
- "strings"
-)
-
-const (
- // MaxPayloadSize is the maximum payload size of a pkt-line in bytes.
- MaxPayloadSize = 65516
-)
-
-var (
- flush = []byte{'0', '0', '0', '0'}
-)
-
-// PktLine values represent a succession of pkt-lines.
-// Values from this type are not zero-value safe, see the functions New
-// and NewFromString below.
-type PktLine struct {
- io.Reader
-}
-
-// ErrPayloadTooLong is returned by New and NewFromString when any of
-// the provided payloads is bigger than MaxPayloadSize.
-var ErrPayloadTooLong = errors.New("payload is too long")
-
-// New returns the concatenation of several pkt-lines, each of them with
-// the payload specified by the contents of each input byte slice. An
-// empty payload byte slice will produce a flush-pkt.
-func New(payloads ...[]byte) (PktLine, error) {
- ret := []io.Reader{}
- for _, p := range payloads {
- if err := add(&ret, p); err != nil {
- return PktLine{}, err
- }
- }
-
- return PktLine{io.MultiReader(ret...)}, nil
-}
-
-func add(dst *[]io.Reader, e []byte) error {
- if len(e) > MaxPayloadSize {
- return ErrPayloadTooLong
- }
-
- if len(e) == 0 {
- *dst = append(*dst, bytes.NewReader(flush))
- return nil
- }
-
- n := len(e) + 4
- *dst = append(*dst, bytes.NewReader(int16ToHex(n)))
- *dst = append(*dst, bytes.NewReader(e))
-
- return nil
-}
-
-// susbtitutes fmt.Sprintf("%04x", n) to avoid memory garbage
-// generation.
-func int16ToHex(n int) []byte {
- var ret [4]byte
- ret[0] = byteToAsciiHex(byte(n & 0xf000 >> 12))
- ret[1] = byteToAsciiHex(byte(n & 0x0f00 >> 8))
- ret[2] = byteToAsciiHex(byte(n & 0x00f0 >> 4))
- ret[3] = byteToAsciiHex(byte(n & 0x000f))
-
- return ret[:]
-}
-
-// turns a byte into its hexadecimal ascii representation. Example:
-// from 11 (0xb) into 'b'.
-func byteToAsciiHex(n byte) byte {
- if n < 10 {
- return byte('0' + n)
- }
-
- return byte('a' - 10 + n)
-}
-
-// NewFromStrings returns the concatenation of several pkt-lines, each
-// of them with the payload specified by the contents of each input
-// string. An empty payload string will produce a flush-pkt.
-func NewFromStrings(payloads ...string) (PktLine, error) {
- ret := []io.Reader{}
- for _, p := range payloads {
- if err := addString(&ret, p); err != nil {
- return PktLine{}, err
- }
- }
-
- return PktLine{io.MultiReader(ret...)}, nil
-}
-
-func addString(dst *[]io.Reader, s string) error {
- if len(s) > MaxPayloadSize {
- return ErrPayloadTooLong
- }
-
- if len(s) == 0 {
- *dst = append(*dst, bytes.NewReader(flush))
- return nil
- }
-
- n := len(s) + 4
- *dst = append(*dst, bytes.NewReader(int16ToHex(n)))
- *dst = append(*dst, strings.NewReader(s))
-
- return nil
-}
diff --git a/formats/packp/pktline/pktline_test.go b/formats/packp/pktline/pktline_test.go
deleted file mode 100644
index 3c18f53..0000000
--- a/formats/packp/pktline/pktline_test.go
+++ /dev/null
@@ -1,199 +0,0 @@
-package pktline_test
-
-import (
- "io"
- "io/ioutil"
- "os"
- "strings"
- "testing"
-
- "gopkg.in/src-d/go-git.v4/formats/packp/pktline"
-
- . "gopkg.in/check.v1"
-)
-
-func Test(t *testing.T) { TestingT(t) }
-
-type SuitePktLine struct {
-}
-
-var _ = Suite(&SuitePktLine{})
-
-func (s *SuitePktLine) TestNew(c *C) {
- for i, test := range [...]struct {
- input [][]byte
- expected []byte
- }{
- {
- input: [][]byte{},
- expected: []byte{},
- }, {
- input: [][]byte{
- []byte(nil),
- },
- expected: []byte("0000"),
- }, {
- input: [][]byte{
- []byte{},
- },
- expected: []byte("0000"),
- }, {
- input: [][]byte{
- []byte(""),
- },
- expected: []byte("0000"),
- }, {
- input: [][]byte{
- []byte("hello\n"),
- },
- expected: []byte("000ahello\n"),
- }, {
- input: [][]byte{
- []byte("hello\n"),
- []byte("world!\n"),
- []byte(""),
- []byte("foo"),
- []byte(""),
- },
- expected: []byte("000ahello\n000bworld!\n00000007foo0000"),
- }, {
- input: [][]byte{
- []byte(strings.Repeat("a", pktline.MaxPayloadSize)),
- },
- expected: []byte("fff0" + strings.Repeat("a", pktline.MaxPayloadSize)),
- },
- } {
- r, err := pktline.New(test.input...)
- c.Assert(err, IsNil, Commentf("input %d = %v", i, test.input))
-
- obtained, err := ioutil.ReadAll(r)
- c.Assert(err, IsNil, Commentf("input %d = %v", i, test.input))
-
- c.Assert(obtained, DeepEquals, test.expected,
- Commentf("input %d = %v", i, test.input))
- }
-}
-
-func (s *SuitePktLine) TestNewErrPayloadTooLong(c *C) {
- for _, input := range [...][][]byte{
- [][]byte{
- []byte(strings.Repeat("a", pktline.MaxPayloadSize+1)),
- },
- [][]byte{
- []byte("hello world!"),
- []byte(""),
- []byte(strings.Repeat("a", pktline.MaxPayloadSize+1)),
- },
- [][]byte{
- []byte("hello world!"),
- []byte(strings.Repeat("a", pktline.MaxPayloadSize+1)),
- []byte("foo"),
- },
- } {
- _, err := pktline.New(input...)
-
- c.Assert(err, Equals, pktline.ErrPayloadTooLong,
- Commentf("%v\n", input))
- }
-}
-
-func (s *SuitePktLine) TestNewFromStrings(c *C) {
- for _, test := range [...]struct {
- input []string
- expected []byte
- }{
- {
- input: []string(nil),
- expected: []byte{},
- }, {
- input: []string{},
- expected: []byte{},
- }, {
- input: []string{""},
- expected: []byte("0000"),
- }, {
- input: []string{"hello\n"},
- expected: []byte("000ahello\n"),
- }, {
- input: []string{"hello\n", "world!\n", "", "foo", ""},
- expected: []byte("000ahello\n000bworld!\n00000007foo0000"),
- }, {
- input: []string{
- strings.Repeat("a", pktline.MaxPayloadSize),
- },
- expected: []byte("fff0" + strings.Repeat("a", pktline.MaxPayloadSize)),
- },
- } {
- r, err := pktline.NewFromStrings(test.input...)
- c.Assert(err, IsNil)
-
- obtained, err := ioutil.ReadAll(r)
- c.Assert(err, IsNil)
-
- c.Assert(obtained, DeepEquals, test.expected,
- Commentf("input = %v\n", test.input))
- }
-}
-
-func (s *SuitePktLine) TestNewFromStringsErrPayloadTooLong(c *C) {
- for _, input := range [...][]string{
- []string{
- strings.Repeat("a", pktline.MaxPayloadSize+1),
- },
- []string{
- "hello world!",
- "",
- strings.Repeat("a", pktline.MaxPayloadSize+1),
- },
- []string{
- "hello world!",
- strings.Repeat("a", pktline.MaxPayloadSize+1),
- "foo",
- },
- } {
- _, err := pktline.NewFromStrings(input...)
-
- c.Assert(err, Equals, pktline.ErrPayloadTooLong,
- Commentf("%v\n", input))
- }
-}
-
-func ExampleNew() {
- // These are the payloads we want to turn into pkt-lines,
- // the empty slice at the end will generate a flush-pkt.
- payloads := [][]byte{
- []byte{'h', 'e', 'l', 'l', 'o', '\n'},
- []byte{'w', 'o', 'r', 'l', 'd', '!', '\n'},
- []byte{},
- }
-
- // Create the pkt-lines, ignoring errors...
- pktlines, _ := pktline.New(payloads...)
-
- // Send the raw data to stdout, ignoring errors...
- _, _ = io.Copy(os.Stdout, pktlines)
-
- // Output: 000ahello
- // 000bworld!
- // 0000
-}
-
-func ExampleNewFromStrings() {
- // These are the payloads we want to turn into pkt-lines,
- // the empty string at the end will generate a flush-pkt.
- payloads := []string{
- "hello\n",
- "world!\n",
- "",
- }
-
- // Create the pkt-lines, ignoring errors...
- pktlines, _ := pktline.NewFromStrings(payloads...)
-
- // Send the raw data to stdout, ignoring errors...
- _, _ = io.Copy(os.Stdout, pktlines)
-
- // Output: 000ahello
- // 000bworld!
- // 0000
-}
diff --git a/formats/packp/pktline/pktlines.go b/formats/packp/pktline/pktlines.go
new file mode 100644
index 0000000..c19aa2e
--- /dev/null
+++ b/formats/packp/pktline/pktlines.go
@@ -0,0 +1,140 @@
+// Package pktline implements reading payloads form pkt-lines and creating pkt-lines from payloads.
+package pktline
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "strings"
+)
+
+const (
+ // MaxPayloadSize is the maximum payload size of a pkt-line in bytes.
+ MaxPayloadSize = 65516
+)
+
+var (
+ flush = []byte{'0', '0', '0', '0'}
+)
+
+// PktLines values represent a succession of pkt-lines. Values from
+// this type are not zero-value safe, use the New function instead.
+type PktLines struct {
+ r io.Reader
+}
+
+var (
+ // ErrPayloadTooLong is returned by the Add methods when any of the
+ // provided payloads is bigger than MaxPayloadSize.
+ ErrPayloadTooLong = errors.New("payload is too long")
+ // ErrEmptyPayload is returned by the Add methods when an empty
+ // payload is provided.
+ ErrEmptyPayload = errors.New("cannot add empty payloads")
+)
+
+// New returns an empty PktLines (with no payloads) ready to be used.
+func New() *PktLines {
+ return &PktLines{
+ r: bytes.NewReader(nil),
+ }
+}
+
+// AddFlush adds a flush-pkt to p.
+func (p *PktLines) AddFlush() {
+ p.r = io.MultiReader(p.r, bytes.NewReader(flush))
+}
+
+// Add adds the slices in pp as the payloads of a
+// corresponding number of pktlines.
+func (p *PktLines) Add(pp ...[]byte) error {
+ tmp := []io.Reader{p.r}
+ for _, p := range pp {
+ if err := add(&tmp, p); err != nil {
+ return err
+ }
+ }
+ p.r = io.MultiReader(tmp...)
+
+ return nil
+}
+
+func add(dst *[]io.Reader, e []byte) error {
+ if err := checkPayloadLength(len(e)); err != nil {
+ return err
+ }
+
+ n := len(e) + 4
+ *dst = append(*dst, bytes.NewReader(asciiHex16(n)))
+ *dst = append(*dst, bytes.NewReader(e))
+
+ return nil
+}
+
+func checkPayloadLength(n int) error {
+ switch {
+ case n < 0:
+ panic("unexpected negative payload length")
+ case n == 0:
+ return ErrEmptyPayload
+ case n > MaxPayloadSize:
+ return ErrPayloadTooLong
+ default:
+ return nil
+ }
+}
+
+// Returns the hexadecimal ascii representation of the 16 less
+// significant bits of n. The length of the returned slice will always
+// be 4. Example: if n is 1234 (0x4d2), the return value will be
+// []byte{'0', '4', 'd', '2'}.
+func asciiHex16(n int) []byte {
+ var ret [4]byte
+ ret[0] = byteToASCIIHex(byte(n & 0xf000 >> 12))
+ ret[1] = byteToASCIIHex(byte(n & 0x0f00 >> 8))
+ ret[2] = byteToASCIIHex(byte(n & 0x00f0 >> 4))
+ ret[3] = byteToASCIIHex(byte(n & 0x000f))
+
+ return ret[:]
+}
+
+// turns a byte into its hexadecimal ascii representation. Example:
+// from 11 (0xb) to 'b'.
+func byteToASCIIHex(n byte) byte {
+ if n < 10 {
+ return '0' + n
+ }
+
+ return 'a' - 10 + n
+}
+
+// AddString adds the strings in pp as payloads of a
+// corresponding number of pktlines.
+func (p *PktLines) AddString(pp ...string) error {
+ tmp := []io.Reader{p.r}
+ for _, p := range pp {
+ if err := addString(&tmp, p); err != nil {
+ return err
+ }
+ }
+
+ p.r = io.MultiReader(tmp...)
+
+ return nil
+}
+
+func addString(dst *[]io.Reader, s string) error {
+ if err := checkPayloadLength(len(s)); err != nil {
+ return err
+ }
+
+ n := len(s) + 4
+ *dst = append(*dst, bytes.NewReader(asciiHex16(n)))
+ *dst = append(*dst, strings.NewReader(s))
+
+ return nil
+}
+
+// Read reads the pktlines for the payloads added so far.
+func (p *PktLines) Read(b []byte) (n int, err error) {
+ return p.r.Read(b)
+}
diff --git a/formats/packp/pktline/pktlines_test.go b/formats/packp/pktline/pktlines_test.go
new file mode 100644
index 0000000..e0ba16b
--- /dev/null
+++ b/formats/packp/pktline/pktlines_test.go
@@ -0,0 +1,231 @@
+package pktline_test
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+
+ "gopkg.in/src-d/go-git.v4/formats/packp/pktline"
+
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) { TestingT(t) }
+
+type SuitePktLine struct {
+}
+
+var _ = Suite(&SuitePktLine{})
+
+func (s *SuitePktLine) TestNewIsEmpty(c *C) {
+ p := pktline.New()
+
+ b, err := ioutil.ReadAll(p)
+ c.Assert(err, IsNil)
+ c.Assert(b, DeepEquals, []byte{})
+}
+
+func (s *SuitePktLine) TestAddFlush(c *C) {
+ p := pktline.New()
+ p.AddFlush()
+
+ b, err := ioutil.ReadAll(p)
+ c.Assert(err, IsNil)
+ c.Assert(string(b), DeepEquals, "0000")
+}
+
+func (s *SuitePktLine) TestAdd(c *C) {
+ for i, test := range [...]struct {
+ input [][]byte
+ expected []byte
+ }{
+ {
+ input: [][]byte{
+ []byte("hello\n"),
+ },
+ expected: []byte("000ahello\n"),
+ }, {
+ input: [][]byte{
+ []byte("hello\n"),
+ []byte("world!\n"),
+ []byte("foo"),
+ },
+ expected: []byte("000ahello\n000bworld!\n0007foo"),
+ }, {
+ input: [][]byte{
+ []byte(strings.Repeat("a", pktline.MaxPayloadSize)),
+ },
+ expected: []byte(
+ "fff0" + strings.Repeat("a", pktline.MaxPayloadSize)),
+ }, {
+ input: [][]byte{
+ []byte(strings.Repeat("a", pktline.MaxPayloadSize)),
+ []byte(strings.Repeat("b", pktline.MaxPayloadSize)),
+ },
+ expected: []byte(
+ "fff0" + strings.Repeat("a", pktline.MaxPayloadSize) +
+ "fff0" + strings.Repeat("b", pktline.MaxPayloadSize)),
+ },
+ } {
+ p := pktline.New()
+ err := p.Add(test.input...)
+ c.Assert(err, IsNil, Commentf("input %d = %v", i, test.input))
+
+ obtained, err := ioutil.ReadAll(p)
+ c.Assert(err, IsNil, Commentf("input %d = %v", i, test.input))
+
+ c.Assert(obtained, DeepEquals, test.expected,
+ Commentf("input %d = %v", i, test.input))
+ }
+}
+
+func (s *SuitePktLine) TestAddErrEmptyPayload(c *C) {
+ for _, input := range [...][][]byte{
+ [][]byte{
+ []byte{},
+ },
+ [][]byte{
+ []byte(nil),
+ },
+ [][]byte{
+ []byte("hello world!"),
+ []byte{},
+ },
+ [][]byte{
+ []byte{},
+ []byte("hello world!"),
+ },
+ } {
+ p := pktline.New()
+ err := p.Add(input...)
+ c.Assert(err, Equals, pktline.ErrEmptyPayload)
+ }
+}
+
+func (s *SuitePktLine) TestAddErrPayloadTooLong(c *C) {
+ for _, input := range [...][][]byte{
+ [][]byte{
+ []byte(strings.Repeat("a", pktline.MaxPayloadSize+1)),
+ },
+ [][]byte{
+ []byte("hello world!"),
+ []byte(strings.Repeat("a", pktline.MaxPayloadSize+1)),
+ },
+ [][]byte{
+ []byte("hello world!"),
+ []byte(strings.Repeat("a", pktline.MaxPayloadSize+1)),
+ []byte("foo"),
+ },
+ } {
+ p := pktline.New()
+ err := p.Add(input...)
+ c.Assert(err, Equals, pktline.ErrPayloadTooLong,
+ Commentf("%v\n", input))
+ }
+}
+
+func (s *SuitePktLine) TestAddString(c *C) {
+ for i, test := range [...]struct {
+ input []string
+ expected []byte
+ }{
+ {
+ input: []string{
+ "hello\n",
+ },
+ expected: []byte("000ahello\n"),
+ }, {
+ input: []string{
+ "hello\n",
+ "world!\n",
+ "foo",
+ },
+ expected: []byte("000ahello\n000bworld!\n0007foo"),
+ }, {
+ input: []string{
+ strings.Repeat("a", pktline.MaxPayloadSize),
+ },
+ expected: []byte(
+ "fff0" + strings.Repeat("a", pktline.MaxPayloadSize)),
+ }, {
+ input: []string{
+ strings.Repeat("a", pktline.MaxPayloadSize),
+ strings.Repeat("b", pktline.MaxPayloadSize),
+ },
+ expected: []byte(
+ "fff0" + strings.Repeat("a", pktline.MaxPayloadSize) +
+ "fff0" + strings.Repeat("b", pktline.MaxPayloadSize)),
+ },
+ } {
+ p := pktline.New()
+ err := p.AddString(test.input...)
+ c.Assert(err, IsNil, Commentf("input %d = %v", i, test.input))
+
+ obtained, err := ioutil.ReadAll(p)
+ c.Assert(err, IsNil, Commentf("input %d = %v", i, test.input))
+
+ c.Assert(obtained, DeepEquals, test.expected,
+ Commentf("input %d = %v", i, test.input))
+ }
+}
+
+func (s *SuitePktLine) TestAddStringErrEmptyPayload(c *C) {
+ for _, input := range [...][]string{
+ []string{""},
+ []string{"hello world!", ""},
+ []string{"", "hello world!"},
+ } {
+ p := pktline.New()
+ err := p.AddString(input...)
+ c.Assert(err, Equals, pktline.ErrEmptyPayload)
+ }
+}
+
+func (s *SuitePktLine) TestAddStringErrPayloadTooLong(c *C) {
+ for _, input := range [...][]string{
+ []string{
+ strings.Repeat("a", pktline.MaxPayloadSize+1),
+ },
+ []string{
+ "hello world!",
+ strings.Repeat("a", pktline.MaxPayloadSize+1),
+ },
+ []string{
+ "hello world!",
+ strings.Repeat("a", pktline.MaxPayloadSize+1),
+ "foo",
+ },
+ } {
+ p := pktline.New()
+ err := p.AddString(input...)
+ c.Assert(err, Equals, pktline.ErrPayloadTooLong,
+ Commentf("%v\n", input))
+ }
+}
+
+func ExamplePktLines() {
+ // Create an empty collection of pktlines.
+ p := pktline.New()
+
+ // Add two strings as payloads ("foo\n" and "bar\n"), they will
+ // end up as two consecutive pktlines.
+ p.AddString("foo\n", "bar\n") // error checks removed for brevity
+
+ // You can also add byte slices as payloads...
+ p.Add([]byte("hello\n"), []byte("world!\n"))
+
+ // Add a flush-pkt.
+ p.AddFlush()
+
+ // PktLines are Readers, so you can directly read the full sequence.
+ io.Copy(os.Stdout, p)
+
+ // Output:
+ // 0008foo
+ // 0008bar
+ // 000ahello
+ // 000bworld!
+ // 0000
+}
diff --git a/formats/packp/pktline/scanner_test.go b/formats/packp/pktline/scanner_test.go
index 08ca51f..de0f8df 100644
--- a/formats/packp/pktline/scanner_test.go
+++ b/formats/packp/pktline/scanner_test.go
@@ -41,9 +41,10 @@ func (s *SuiteScanner) TestEmptyReader(c *C) {
}
func (s *SuiteScanner) TestFlush(c *C) {
- r, err := pktline.NewFromStrings("")
- c.Assert(err, IsNil)
- sc := pktline.NewScanner(r)
+ p := pktline.New()
+ p.AddFlush()
+ sc := pktline.NewScanner(p)
+
c.Assert(sc.Scan(), Equals, true)
payload := sc.Bytes()
c.Assert(len(payload), Equals, 0)
@@ -69,9 +70,11 @@ func (s *SuiteScanner) TestScanAndPayload(c *C) {
strings.Repeat("a", pktline.MaxPayloadSize),
strings.Repeat("a", pktline.MaxPayloadSize-1) + "\n",
} {
- r, err := pktline.NewFromStrings(test)
- c.Assert(err, IsNil, Commentf("input len=%x, contents=%.10q\n", len(test), test))
- sc := pktline.NewScanner(r)
+ p := pktline.New()
+ err := p.AddString(test)
+ c.Assert(err, IsNil,
+ Commentf("input len=%x, contents=%.10q\n", len(test), test))
+ sc := pktline.NewScanner(p)
c.Assert(sc.Scan(), Equals, true,
Commentf("test = %.20q...", test))
@@ -91,8 +94,7 @@ func (s *SuiteScanner) TestSkip(c *C) {
input: []string{
"first",
"second",
- "third",
- ""},
+ "third"},
n: 1,
expected: []byte("second"),
},
@@ -100,15 +102,15 @@ func (s *SuiteScanner) TestSkip(c *C) {
input: []string{
"first",
"second",
- "third",
- ""},
+ "third"},
n: 2,
expected: []byte("third"),
},
} {
- r, err := pktline.NewFromStrings(test.input...)
+ p := pktline.New()
+ err := p.AddString(test.input...)
c.Assert(err, IsNil)
- sc := pktline.NewScanner(r)
+ sc := pktline.NewScanner(p)
for i := 0; i < test.n; i++ {
c.Assert(sc.Scan(), Equals, true,
Commentf("scan error = %s", sc.Err()))
@@ -123,9 +125,10 @@ func (s *SuiteScanner) TestSkip(c *C) {
}
func (s *SuiteScanner) TestEOF(c *C) {
- r, err := pktline.NewFromStrings("first", "second")
+ p := pktline.New()
+ err := p.AddString("first", "second")
c.Assert(err, IsNil)
- sc := pktline.NewScanner(r)
+ sc := pktline.NewScanner(p)
for sc.Scan() {
}
c.Assert(sc.Err(), IsNil)
@@ -161,19 +164,19 @@ func (s *SuiteScanner) TestReadSomeSections(c *C) {
// 0000
// and so on
func sectionsExample(c *C, nSections, nLines int) io.Reader {
- ss := []string{}
+ p := pktline.New()
for section := 0; section < nSections; section++ {
+ ss := []string{}
for line := 0; line < nLines; line++ {
line := fmt.Sprintf(" %d.%d\n", section, line)
ss = append(ss, line)
}
- ss = append(ss, "")
+ err := p.AddString(ss...)
+ c.Assert(err, IsNil)
+ p.AddFlush()
}
- ret, err := pktline.NewFromStrings(ss...)
- c.Assert(err, IsNil)
-
- return ret
+ return p
}
func ExampleScanner() {