6 "github.com/git-lfs/git-lfs/tools"
9 // PktlineWriter is an implementation of `io.Writer` which writes data buffers
10 // "p" to an underlying pkt-line stream for use with the Git pkt-line format.
11 type PktlineWriter struct {
12 // buf is an internal buffer used to store data until enough has been
13 // collected to write a full packet, or the buffer was instructed to
16 // pl is the place where packets get written.
20 var _ io.Writer = new(PktlineWriter)
22 // NewPktlineWriter returns a new *PktlineWriter, which will write to the
23 // underlying data stream "w". The internal buffer is initialized with the given
26 // If "w" is already a `*PktlineWriter`, it will be returned as-is.
27 func NewPktlineWriter(w io.Writer, c int) *PktlineWriter {
28 if pw, ok := w.(*PktlineWriter); ok {
32 return &PktlineWriter{
33 buf: make([]byte, 0, c),
34 pl: newPktline(nil, w),
38 // Write implements the io.Writer interface's `Write` method by providing a
39 // packet-based backend to the given buffer "p".
41 // As many bytes are removed from "p" as possible and stored in an internal
42 // buffer until the amount of data in the internal buffer is enough to write a
43 // single packet. Once the internal buffer is full, a packet is written to the
44 // underlying stream of data, and the process repeats.
46 // When the caller has no more data to write in the given chunk of packets, a
47 // subsequent call to `Flush()` SHOULD be made in order to signify that the
48 // current pkt sequence has terminated, and a new one can begin.
50 // Write returns the number of bytes in "p" accepted into the writer, which
51 // _MAY_ be written to the underlying protocol stream, or may be written into
52 // the internal buffer.
54 // If any error was encountered while either buffering or writing, that
55 // error is returned, along with the number of bytes written to the underlying
56 // protocol stream, as described above.
57 func (w *PktlineWriter) Write(p []byte) (int, error) {
61 // While there is still data left to process in "p", grab as
62 // much of it as we can while not allowing the internal buffer
63 // to exceed the MaxPacketLength const.
64 m := tools.MinInt(len(p[n:]), MaxPacketLength-len(w.buf))
66 // Append on all of the data that we could into the internal
68 w.buf = append(w.buf, p[n:n+m]...)
72 if len(w.buf) == MaxPacketLength {
73 // If we were able to grab an entire packet's worth of
74 // data, flush the buffer.
76 if _, err := w.flush(); err != nil {
86 // Flush empties the internal buffer used to store data temporarily and then
87 // writes the pkt-line's FLUSH packet, to signal that it is done writing this
89 func (w *PktlineWriter) Flush() error {
94 if _, err := w.flush(); err != nil {
98 if err := w.pl.writeFlush(); err != nil {
105 // flush writes any data in the internal buffer out to the underlying protocol
106 // stream. If the amount of data in the internal buffer exceeds the
107 // MaxPacketLength, the data will be written in multiple packets to accommodate.
109 // flush returns the number of bytes written to the underlying packet stream,
110 // and any error that it encountered along the way.
111 func (w *PktlineWriter) flush() (int, error) {
115 if err := w.pl.writePacket(w.buf); err != nil {
119 m := tools.MinInt(len(w.buf), MaxPacketLength)