github.com/ungtb10d/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 }