2
Copyright 2016 The go4 Authors
4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
8
http://www.apache.org/licenses/LICENSE-2.0
10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
17
// Package writerutil contains io.Writer types.
18
package writerutil // import "github.com/juju/go4/writerutil"
25
// PrefixSuffixSaver is an io.Writer which retains the first N bytes
26
// and the last N bytes written to it. The Bytes method reconstructs
27
// it with a pretty error message.
28
// It is copied from os/exec/exec.go of the Go stdlib.
29
type PrefixSuffixSaver struct {
30
N int // max size of prefix or suffix
32
suffix []byte // ring buffer once len(suffix) == N
33
suffixOff int // offset to write into suffix
36
// TODO(bradfitz): we could keep one large []byte and use part of it for
37
// the prefix, reserve space for the '... Omitting N bytes ...' message,
38
// then the ring buffer suffix, and just rearrange the ring buffer
39
// suffix when Bytes() is called, but it doesn't seem worth it for
40
// now just for error messages. It's only ~64KB anyway.
43
func (w *PrefixSuffixSaver) Write(p []byte) (n int, err error) {
45
p = w.fill(&w.prefix, p)
47
// Only keep the last w.N bytes of suffix data.
48
if overage := len(p) - w.N; overage > 0 {
50
w.skipped += int64(overage)
52
p = w.fill(&w.suffix, p)
54
// w.suffix is full now if p is non-empty. Overwrite it in a circle.
55
for len(p) > 0 { // 0, 1, or 2 iterations.
56
n := copy(w.suffix[w.suffixOff:], p)
60
if w.suffixOff == w.N {
67
// fill appends up to len(p) bytes of p to *dst, such that *dst does not
68
// grow larger than w.N. It returns the un-appended suffix of p.
69
func (w *PrefixSuffixSaver) fill(dst *[]byte, p []byte) (pRemain []byte) {
70
if remain := w.N - len(*dst); remain > 0 {
71
add := minInt(len(p), remain)
72
*dst = append(*dst, p[:add]...)
78
// Bytes returns a slice of the bytes, or a copy of the bytes, retained by w.
79
// If more bytes than could be retained were written to w, it returns a
80
// concatenation of the N first bytes, a message for how many bytes were dropped,
81
// and the N last bytes.
82
func (w *PrefixSuffixSaver) Bytes() []byte {
87
return append(w.prefix, w.suffix...)
90
buf.Grow(len(w.prefix) + len(w.suffix) + 50)
92
buf.WriteString("\n... omitting ")
93
buf.WriteString(strconv.FormatInt(w.skipped, 10))
94
buf.WriteString(" bytes ...\n")
95
buf.Write(w.suffix[w.suffixOff:])
96
buf.Write(w.suffix[:w.suffixOff])
100
func minInt(a, b int) int {