mirror of https://github.com/perkeep/perkeep.git
vendor: update go4.org
rev 40a0492aa096a3be30c750c4e2216de52a6cf2e3 adds writerutil package Change-Id: Ia771e38283afb9750a8dad0cd462ca12ce42dd15
This commit is contained in:
parent
134c276cd9
commit
1a90fe806d
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
Copyright 2016 The go4 Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package writerutil contains io.Writer types.
|
||||
package writerutil // import "go4.org/writerutil"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// PrefixSuffixSaver is an io.Writer which retains the first N bytes
|
||||
// and the last N bytes written to it. The Bytes method reconstructs
|
||||
// it with a pretty error message.
|
||||
// It is copied from os/exec/exec.go of the Go stdlib.
|
||||
type PrefixSuffixSaver struct {
|
||||
N int // max size of prefix or suffix
|
||||
prefix []byte
|
||||
suffix []byte // ring buffer once len(suffix) == N
|
||||
suffixOff int // offset to write into suffix
|
||||
skipped int64
|
||||
|
||||
// TODO(bradfitz): we could keep one large []byte and use part of it for
|
||||
// the prefix, reserve space for the '... Omitting N bytes ...' message,
|
||||
// then the ring buffer suffix, and just rearrange the ring buffer
|
||||
// suffix when Bytes() is called, but it doesn't seem worth it for
|
||||
// now just for error messages. It's only ~64KB anyway.
|
||||
}
|
||||
|
||||
func (w *PrefixSuffixSaver) Write(p []byte) (n int, err error) {
|
||||
lenp := len(p)
|
||||
p = w.fill(&w.prefix, p)
|
||||
|
||||
// Only keep the last w.N bytes of suffix data.
|
||||
if overage := len(p) - w.N; overage > 0 {
|
||||
p = p[overage:]
|
||||
w.skipped += int64(overage)
|
||||
}
|
||||
p = w.fill(&w.suffix, p)
|
||||
|
||||
// w.suffix is full now if p is non-empty. Overwrite it in a circle.
|
||||
for len(p) > 0 { // 0, 1, or 2 iterations.
|
||||
n := copy(w.suffix[w.suffixOff:], p)
|
||||
p = p[n:]
|
||||
w.skipped += int64(n)
|
||||
w.suffixOff += n
|
||||
if w.suffixOff == w.N {
|
||||
w.suffixOff = 0
|
||||
}
|
||||
}
|
||||
return lenp, nil
|
||||
}
|
||||
|
||||
// fill appends up to len(p) bytes of p to *dst, such that *dst does not
|
||||
// grow larger than w.N. It returns the un-appended suffix of p.
|
||||
func (w *PrefixSuffixSaver) fill(dst *[]byte, p []byte) (pRemain []byte) {
|
||||
if remain := w.N - len(*dst); remain > 0 {
|
||||
add := minInt(len(p), remain)
|
||||
*dst = append(*dst, p[:add]...)
|
||||
p = p[add:]
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Bytes returns a slice of the bytes, or a copy of the bytes, retained by w.
|
||||
// If more bytes than could be retained were written to w, it returns a
|
||||
// concatenation of the N first bytes, a message for how many bytes were dropped,
|
||||
// and the N last bytes.
|
||||
func (w *PrefixSuffixSaver) Bytes() []byte {
|
||||
if w.suffix == nil {
|
||||
return w.prefix
|
||||
}
|
||||
if w.skipped == 0 {
|
||||
return append(w.prefix, w.suffix...)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
buf.Grow(len(w.prefix) + len(w.suffix) + 50)
|
||||
buf.Write(w.prefix)
|
||||
buf.WriteString("\n... omitting ")
|
||||
buf.WriteString(strconv.FormatInt(w.skipped, 10))
|
||||
buf.WriteString(" bytes ...\n")
|
||||
buf.Write(w.suffix[w.suffixOff:])
|
||||
buf.Write(w.suffix[:w.suffixOff])
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func minInt(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
Copyright 2016 The go4 Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package writerutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPrefixSuffixSaver(t *testing.T) {
|
||||
tests := []struct {
|
||||
N int
|
||||
writes []string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
N: 2,
|
||||
writes: nil,
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
N: 2,
|
||||
writes: []string{"a"},
|
||||
want: "a",
|
||||
},
|
||||
{
|
||||
N: 2,
|
||||
writes: []string{"abc", "d"},
|
||||
want: "abcd",
|
||||
},
|
||||
{
|
||||
N: 2,
|
||||
writes: []string{"abc", "d", "e"},
|
||||
want: "ab\n... omitting 1 bytes ...\nde",
|
||||
},
|
||||
{
|
||||
N: 2,
|
||||
writes: []string{"ab______________________yz"},
|
||||
want: "ab\n... omitting 22 bytes ...\nyz",
|
||||
},
|
||||
{
|
||||
N: 2,
|
||||
writes: []string{"ab_______________________y", "z"},
|
||||
want: "ab\n... omitting 23 bytes ...\nyz",
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
w := &PrefixSuffixSaver{N: tt.N}
|
||||
for _, s := range tt.writes {
|
||||
n, err := io.WriteString(w, s)
|
||||
if err != nil || n != len(s) {
|
||||
t.Errorf("%d. WriteString(%q) = %v, %v; want %v, %v", i, s, n, err, len(s), nil)
|
||||
}
|
||||
}
|
||||
if got := string(w.Bytes()); got != tt.want {
|
||||
t.Errorf("%d. Bytes = %q; want %q", i, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue