Imported Upstream version 2.5.1
[scm/test.git] / git / pkt_line_writer.go
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 }