github.com/saracen/git-lfs@v2.5.2+incompatible/git/pkt_line_writer.go (about)

     1  package git
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/git-lfs/git-lfs/tools"
     7  )
     8  
     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
    14  	// flush.
    15  	buf []byte
    16  	// pl is the place where packets get written.
    17  	pl *pktline
    18  }
    19  
    20  var _ io.Writer = new(PktlineWriter)
    21  
    22  // NewPktlineWriter returns a new *PktlineWriter, which will write to the
    23  // underlying data stream "w". The internal buffer is initialized with the given
    24  // capacity, "c".
    25  //
    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 {
    29  		return pw
    30  	}
    31  
    32  	return &PktlineWriter{
    33  		buf: make([]byte, 0, c),
    34  		pl:  newPktline(nil, w),
    35  	}
    36  }
    37  
    38  // Write implements the io.Writer interface's `Write` method by providing a
    39  // packet-based backend to the given buffer "p".
    40  //
    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.
    45  //
    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.
    49  //
    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.
    53  //
    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) {
    58  	var n int
    59  
    60  	for len(p[n:]) > 0 {
    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))
    65  
    66  		// Append on all of the data that we could into the internal
    67  		// buffer.
    68  		w.buf = append(w.buf, p[n:n+m]...)
    69  
    70  		n += m
    71  
    72  		if len(w.buf) == MaxPacketLength {
    73  			// If we were able to grab an entire packet's worth of
    74  			// data, flush the buffer.
    75  
    76  			if _, err := w.flush(); err != nil {
    77  				return n, err
    78  			}
    79  
    80  		}
    81  	}
    82  
    83  	return n, nil
    84  }
    85  
    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
    88  // chunk of data.
    89  func (w *PktlineWriter) Flush() error {
    90  	if w == nil {
    91  		return nil
    92  	}
    93  
    94  	if _, err := w.flush(); err != nil {
    95  		return err
    96  	}
    97  
    98  	if err := w.pl.writeFlush(); err != nil {
    99  		return err
   100  	}
   101  
   102  	return nil
   103  }
   104  
   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.
   108  //
   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) {
   112  	var n int
   113  
   114  	for len(w.buf) > 0 {
   115  		if err := w.pl.writePacket(w.buf); err != nil {
   116  			return 0, err
   117  		}
   118  
   119  		m := tools.MinInt(len(w.buf), MaxPacketLength)
   120  
   121  		w.buf = w.buf[m:]
   122  
   123  		n = n + m
   124  	}
   125  
   126  	return n, nil
   127  }