git-lfs/git/pkt_line_writer.go

128 lines
3.5 KiB
Go
Raw Normal View History

package git
import (
"io"
2016-11-15 17:01:18 +00:00
"github.com/git-lfs/git-lfs/tools"
)
2016-11-09 01:49:19 +00:00
// PktlineWriter is an implementation of `io.Writer` which writes data buffers
// "p" to an underlying pkt-line stream for use with the Git pkt-line format.
type PktlineWriter struct {
// buf is an internal buffer used to store data until enough has been
// collected to write a full packet, or the buffer was instructed to
// flush.
buf []byte
2016-11-08 20:45:38 +00:00
// pl is the place where packets get written.
pl *pktline
}
2016-11-09 01:49:19 +00:00
var _ io.Writer = new(PktlineWriter)
2016-11-09 01:49:19 +00:00
// NewPktlineWriter returns a new *PktlineWriter, which will write to the
// underlying data stream "w". The internal buffer is initialized with the given
// capacity, "c".
//
2016-11-09 01:49:19 +00:00
// If "w" is already a `*PktlineWriter`, it will be returned as-is.
func NewPktlineWriter(w io.Writer, c int) *PktlineWriter {
if pw, ok := w.(*PktlineWriter); ok {
return pw
}
2016-11-09 01:49:19 +00:00
return &PktlineWriter{
2016-11-08 20:45:38 +00:00
buf: make([]byte, 0, c),
pl: newPktline(nil, w),
}
}
// Write implements the io.Writer interface's `Write` method by providing a
// packet-based backend to the given buffer "p".
//
// As many bytes are removed from "p" as possible and stored in an internal
// buffer until the amount of data in the internal buffer is enough to write a
// single packet. Once the internal buffer is full, a packet is written to the
// underlying stream of data, and the process repeats.
//
// When the caller has no more data to write in the given chunk of packets, a
2016-11-11 19:53:40 +00:00
// subsequent call to `Flush()` SHOULD be made in order to signify that the
// current pkt sequence has terminated, and a new one can begin.
//
// Write returns the number of bytes in "p" accepted into the writer, which
// _MAY_ be written to the underlying protocol stream, or may be written into
// the internal buffer.
//
// If any error was encountered while either buffering or writing, that
// error is returned, along with the number of bytes written to the underlying
// protocol stream, as described above.
2016-11-09 01:49:19 +00:00
func (w *PktlineWriter) Write(p []byte) (int, error) {
var n int
2016-11-10 22:25:28 +00:00
for len(p[n:]) > 0 {
// While there is still data left to process in "p", grab as
// much of it as we can while not allowing the internal buffer
// to exceed the MaxPacketLength const.
2016-11-10 22:25:28 +00:00
m := tools.MinInt(len(p[n:]), MaxPacketLength-len(w.buf))
// Append on all of the data that we could into the internal
// buffer.
2016-11-10 22:25:28 +00:00
w.buf = append(w.buf, p[n:n+m]...)
n += m
if len(w.buf) == MaxPacketLength {
// If we were able to grab an entire packet's worth of
// data, flush the buffer.
if _, err := w.flush(); err != nil {
return n, err
}
}
}
return n, nil
}
// Flush empties the internal buffer used to store data temporarily and then
// writes the pkt-line's FLUSH packet, to signal that it is done writing this
// chunk of data.
2016-11-09 01:49:19 +00:00
func (w *PktlineWriter) Flush() error {
if w == nil {
return nil
}
if _, err := w.flush(); err != nil {
return err
}
2016-11-08 20:45:38 +00:00
if err := w.pl.writeFlush(); err != nil {
return err
}
return nil
}
// flush writes any data in the internal buffer out to the underlying protocol
// stream. If the amount of data in the internal buffer exceeds the
// MaxPacketLength, the data will be written in multiple packets to accommodate.
//
// flush returns the number of bytes written to the underlying packet stream,
// and any error that it encountered along the way.
2016-11-09 01:49:19 +00:00
func (w *PktlineWriter) flush() (int, error) {
var n int
for len(w.buf) > 0 {
2016-11-08 20:45:38 +00:00
if err := w.pl.writePacket(w.buf); err != nil {
return 0, err
}
m := tools.MinInt(len(w.buf), MaxPacketLength)
w.buf = w.buf[m:]
n = n + m
}
return n, nil
}