-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathlimitwriter.go
120 lines (98 loc) · 2.13 KB
/
limitwriter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package xio
import (
"bytes"
"io"
"strings"
)
// PrefixSuffixWriter wraps an io.Writer such that the output is limited
// to a certain number of bytes. Flush must be called in order to write
// the suffix to the underlying writer.
type PrefixSuffixWriter struct {
W io.Writer
// N is the max size of the prefix or suffix. The total number of bytes
// retained is N*2.
N int
// prefix is the number of bytes written to the prefix.
prefix int
// suffix is a circular slice of the last bytes to be written.
suffix []byte
suffixOff int
skipped bool
}
// Flush flushes the suffix to the underlying writer.
func (p *PrefixSuffixWriter) Flush() error {
_, err := io.Copy(p.W, bytes.NewReader(p.suffix[p.suffixOff:]))
if err != nil {
return err
}
_, err = io.Copy(p.W, bytes.NewReader(p.suffix[:p.suffixOff]))
return err
}
func (p *PrefixSuffixWriter) Write(b []byte) (int, error) {
lenb := len(b)
n, err := p.writePrefix(b)
if err != nil {
return n, err
}
if n == lenb {
return lenb, nil
}
b = b[n:]
b = p.fillSuffix(b)
if len(b) > 0 {
err = p.writeSkipMessageOnce()
if err != nil {
return 0, err
}
}
p.overwriteSuffix(b)
return lenb, nil
}
func (p *PrefixSuffixWriter) fillSuffix(b []byte) []byte {
if len(p.suffix) == p.N {
return b
}
if remain := p.N - len(p.suffix); remain > 0 {
add := minInt(len(b), remain)
p.suffix = append(p.suffix, b[:add]...)
b = b[add:]
}
return b
}
func (p *PrefixSuffixWriter) overwriteSuffix(b []byte) {
for len(b) > 0 {
n := copy(p.suffix[p.suffixOff:], b)
b = b[n:]
p.suffixOff += n
if p.suffixOff == p.N {
p.suffixOff = 0
}
}
}
const skipMessage = "\nTruncating output...\n\n"
func (p *PrefixSuffixWriter) writeSkipMessageOnce() error {
if p.skipped {
return nil
}
p.skipped = true
_, err := io.Copy(p.W, strings.NewReader(skipMessage))
return err
}
func (p *PrefixSuffixWriter) writePrefix(b []byte) (int, error) {
limit := p.N - p.prefix
if limit <= 0 {
return 0, nil
}
if limit > len(b) {
limit = len(b)
}
n, err := p.W.Write(b[:limit])
p.prefix += n
return n, err
}
func minInt(a, b int) int {
if a < b {
return a
}
return b
}