Vendor + test fixes
This commit is contained in:
parent
556fb2562f
commit
b5995c6cd7
|
@ -193,6 +193,12 @@ func setupTaskEnv(t *testing.T, driver string) (*allocdir.TaskDir, map[string]st
|
|||
"NOMAD_META_ELB_CHECK_TYPE": "http",
|
||||
"NOMAD_META_ELB_CHECK_MIN": "3",
|
||||
"NOMAD_META_OWNER": "armon",
|
||||
"NOMAD_META_chocolate": "cake",
|
||||
"NOMAD_META_strawberry": "icecream",
|
||||
"NOMAD_META_elb_check_interval": "30s",
|
||||
"NOMAD_META_elb_check_type": "http",
|
||||
"NOMAD_META_elb_check_min": "3",
|
||||
"NOMAD_META_owner": "armon",
|
||||
"HELLO": "world",
|
||||
"lorem": "ipsum",
|
||||
"NOMAD_ALLOC_ID": alloc.ID,
|
||||
|
|
|
@ -157,6 +157,7 @@ func TestEnvironment_AsList(t *testing.T) {
|
|||
"NOMAD_HOST_PORT_http=80",
|
||||
"NOMAD_HOST_PORT_https=8080",
|
||||
"NOMAD_META_FOO=baz",
|
||||
"NOMAD_META_foo=baz",
|
||||
"NOMAD_ADDR_web_main=192.168.0.100:5000",
|
||||
"NOMAD_ADDR_web_http=192.168.0.100:2000",
|
||||
"NOMAD_TASK_NAME=taskA",
|
||||
|
|
|
@ -99,10 +99,10 @@ func TestClient_ServerList(t *testing.T) {
|
|||
if err := client.SetServers(nil); err != noServersErr {
|
||||
t.Fatalf("expected setting an empty list to return a 'no servers' error but received %v", err)
|
||||
}
|
||||
if err := client.SetServers([]string{"not-a-real-domain.fake"}); err == nil {
|
||||
if err := client.SetServers([]string{"123.456.13123.123.13:80"}); err == nil {
|
||||
t.Fatalf("expected setting a bad server to return an error")
|
||||
}
|
||||
if err := client.SetServers([]string{"bad.fake", "127.0.0.1:1234", "127.0.0.1"}); err != nil {
|
||||
if err := client.SetServers([]string{"123.456.13123.123.13:80", "127.0.0.1:1234", "127.0.0.1"}); err != nil {
|
||||
t.Fatalf("expected setting at least one good server to succeed but received: %v", err)
|
||||
}
|
||||
s := client.GetServers()
|
||||
|
|
|
@ -18,10 +18,10 @@ func TestHTTP_JobsList(t *testing.T) {
|
|||
httpTest(t, nil, func(s *TestServer) {
|
||||
for i := 0; i < 3; i++ {
|
||||
// Create the job
|
||||
job := api.MockJob()
|
||||
args := api.JobRegisterRequest{
|
||||
job := mock.Job()
|
||||
args := structs.JobRegisterRequest{
|
||||
Job: job,
|
||||
WriteRequest: api.WriteRequest{Region: "global"},
|
||||
WriteRequest: structs.WriteRequest{Region: "global"},
|
||||
}
|
||||
var resp structs.JobRegisterResponse
|
||||
if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil {
|
||||
|
@ -70,12 +70,12 @@ func TestHTTP_PrefixJobsList(t *testing.T) {
|
|||
httpTest(t, nil, func(s *TestServer) {
|
||||
for i := 0; i < 3; i++ {
|
||||
// Create the job
|
||||
job := api.MockJob()
|
||||
job.ID = &ids[i]
|
||||
*job.TaskGroups[0].Count = 1
|
||||
args := api.JobRegisterRequest{
|
||||
job := mock.Job()
|
||||
job.ID = ids[i]
|
||||
job.TaskGroups[0].Count = 1
|
||||
args := structs.JobRegisterRequest{
|
||||
Job: job,
|
||||
WriteRequest: api.WriteRequest{Region: "global"},
|
||||
WriteRequest: structs.WriteRequest{Region: "global"},
|
||||
}
|
||||
var resp structs.JobRegisterResponse
|
||||
if err := s.Agent.RPC("Job.Register", &args, &resp); err != nil {
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/hashicorp/nomad/api"
|
||||
"github.com/hashicorp/nomad/helper"
|
||||
"github.com/hashicorp/nomad/helper/flatmap"
|
||||
"github.com/kr/pretty"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
|
@ -214,8 +215,6 @@ const (
|
|||
var (
|
||||
expectedApiJob = &api.Job{
|
||||
ID: helper.StringToPtr("job1"),
|
||||
Region: helper.StringToPtr("global"),
|
||||
Priority: helper.IntToPtr(50),
|
||||
Name: helper.StringToPtr("job1"),
|
||||
Type: helper.StringToPtr("service"),
|
||||
Datacenters: []string{"dc1"},
|
||||
|
@ -228,20 +227,12 @@ var (
|
|||
Interval: helper.TimeToPtr(15 * time.Second),
|
||||
Mode: helper.StringToPtr("delay"),
|
||||
},
|
||||
EphemeralDisk: &api.EphemeralDisk{
|
||||
SizeMB: helper.IntToPtr(300),
|
||||
},
|
||||
|
||||
Tasks: []*api.Task{
|
||||
{
|
||||
Driver: "exec",
|
||||
Name: "task1",
|
||||
Resources: &api.Resources{
|
||||
CPU: helper.IntToPtr(100),
|
||||
MemoryMB: helper.IntToPtr(10),
|
||||
IOPS: helper.IntToPtr(0),
|
||||
},
|
||||
LogConfig: api.DefaultLogConfig(),
|
||||
Resources: &api.Resources{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -290,8 +281,9 @@ func TestJobGetter_HTTPServer(t *testing.T) {
|
|||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(expectedApiJob, aj) {
|
||||
eflat := flatmap.Flatten(expectedApiJob, nil, false)
|
||||
aflat := flatmap.Flatten(aj, nil, false)
|
||||
t.Fatalf("got:\n%v\nwant:\n%v", aflat, eflat)
|
||||
for _, d := range pretty.Diff(expectedApiJob, aj) {
|
||||
t.Logf(d)
|
||||
}
|
||||
t.Fatalf("Unexpected file")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ job "job1" {
|
|||
if code := cmd.Run([]string{"-output", fh.Name()}); code != 0 {
|
||||
t.Fatalf("expected exit code 0, got: %d", code)
|
||||
}
|
||||
if out := ui.OutputWriter.String(); !strings.Contains(out, `"Region": "global",`) {
|
||||
if out := ui.OutputWriter.String(); !strings.Contains(out, `"Type": "service",`) {
|
||||
t.Fatalf("Expected JSON output: %v", out)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright 2012 Keith Rarick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,9 @@
|
|||
package pretty
|
||||
|
||||
import "github.com/kr/pretty"
|
||||
|
||||
Package pretty provides pretty-printing for Go values.
|
||||
|
||||
Documentation
|
||||
|
||||
http://godoc.org/github.com/kr/pretty
|
|
@ -0,0 +1,265 @@
|
|||
package pretty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type sbuf []string
|
||||
|
||||
func (p *sbuf) Printf(format string, a ...interface{}) {
|
||||
s := fmt.Sprintf(format, a...)
|
||||
*p = append(*p, s)
|
||||
}
|
||||
|
||||
// Diff returns a slice where each element describes
|
||||
// a difference between a and b.
|
||||
func Diff(a, b interface{}) (desc []string) {
|
||||
Pdiff((*sbuf)(&desc), a, b)
|
||||
return desc
|
||||
}
|
||||
|
||||
// wprintfer calls Fprintf on w for each Printf call
|
||||
// with a trailing newline.
|
||||
type wprintfer struct{ w io.Writer }
|
||||
|
||||
func (p *wprintfer) Printf(format string, a ...interface{}) {
|
||||
fmt.Fprintf(p.w, format+"\n", a...)
|
||||
}
|
||||
|
||||
// Fdiff writes to w a description of the differences between a and b.
|
||||
func Fdiff(w io.Writer, a, b interface{}) {
|
||||
Pdiff(&wprintfer{w}, a, b)
|
||||
}
|
||||
|
||||
type Printfer interface {
|
||||
Printf(format string, a ...interface{})
|
||||
}
|
||||
|
||||
// Pdiff prints to p a description of the differences between a and b.
|
||||
// It calls Printf once for each difference, with no trailing newline.
|
||||
// The standard library log.Logger is a Printfer.
|
||||
func Pdiff(p Printfer, a, b interface{}) {
|
||||
diffPrinter{w: p}.diff(reflect.ValueOf(a), reflect.ValueOf(b))
|
||||
}
|
||||
|
||||
type Logfer interface {
|
||||
Logf(format string, a ...interface{})
|
||||
}
|
||||
|
||||
// logprintfer calls Fprintf on w for each Printf call
|
||||
// with a trailing newline.
|
||||
type logprintfer struct{ l Logfer }
|
||||
|
||||
func (p *logprintfer) Printf(format string, a ...interface{}) {
|
||||
p.l.Logf(format, a...)
|
||||
}
|
||||
|
||||
// Ldiff prints to l a description of the differences between a and b.
|
||||
// It calls Logf once for each difference, with no trailing newline.
|
||||
// The standard library testing.T and testing.B are Logfers.
|
||||
func Ldiff(l Logfer, a, b interface{}) {
|
||||
Pdiff(&logprintfer{l}, a, b)
|
||||
}
|
||||
|
||||
type diffPrinter struct {
|
||||
w Printfer
|
||||
l string // label
|
||||
}
|
||||
|
||||
func (w diffPrinter) printf(f string, a ...interface{}) {
|
||||
var l string
|
||||
if w.l != "" {
|
||||
l = w.l + ": "
|
||||
}
|
||||
w.w.Printf(l+f, a...)
|
||||
}
|
||||
|
||||
func (w diffPrinter) diff(av, bv reflect.Value) {
|
||||
if !av.IsValid() && bv.IsValid() {
|
||||
w.printf("nil != %# v", formatter{v: bv, quote: true})
|
||||
return
|
||||
}
|
||||
if av.IsValid() && !bv.IsValid() {
|
||||
w.printf("%# v != nil", formatter{v: av, quote: true})
|
||||
return
|
||||
}
|
||||
if !av.IsValid() && !bv.IsValid() {
|
||||
return
|
||||
}
|
||||
|
||||
at := av.Type()
|
||||
bt := bv.Type()
|
||||
if at != bt {
|
||||
w.printf("%v != %v", at, bt)
|
||||
return
|
||||
}
|
||||
|
||||
switch kind := at.Kind(); kind {
|
||||
case reflect.Bool:
|
||||
if a, b := av.Bool(), bv.Bool(); a != b {
|
||||
w.printf("%v != %v", a, b)
|
||||
}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if a, b := av.Int(), bv.Int(); a != b {
|
||||
w.printf("%d != %d", a, b)
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
if a, b := av.Uint(), bv.Uint(); a != b {
|
||||
w.printf("%d != %d", a, b)
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if a, b := av.Float(), bv.Float(); a != b {
|
||||
w.printf("%v != %v", a, b)
|
||||
}
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
if a, b := av.Complex(), bv.Complex(); a != b {
|
||||
w.printf("%v != %v", a, b)
|
||||
}
|
||||
case reflect.Array:
|
||||
n := av.Len()
|
||||
for i := 0; i < n; i++ {
|
||||
w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
|
||||
}
|
||||
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
|
||||
if a, b := av.Pointer(), bv.Pointer(); a != b {
|
||||
w.printf("%#x != %#x", a, b)
|
||||
}
|
||||
case reflect.Interface:
|
||||
w.diff(av.Elem(), bv.Elem())
|
||||
case reflect.Map:
|
||||
ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys())
|
||||
for _, k := range ak {
|
||||
w := w.relabel(fmt.Sprintf("[%#v]", k))
|
||||
w.printf("%q != (missing)", av.MapIndex(k))
|
||||
}
|
||||
for _, k := range both {
|
||||
w := w.relabel(fmt.Sprintf("[%#v]", k))
|
||||
w.diff(av.MapIndex(k), bv.MapIndex(k))
|
||||
}
|
||||
for _, k := range bk {
|
||||
w := w.relabel(fmt.Sprintf("[%#v]", k))
|
||||
w.printf("(missing) != %q", bv.MapIndex(k))
|
||||
}
|
||||
case reflect.Ptr:
|
||||
switch {
|
||||
case av.IsNil() && !bv.IsNil():
|
||||
w.printf("nil != %# v", formatter{v: bv, quote: true})
|
||||
case !av.IsNil() && bv.IsNil():
|
||||
w.printf("%# v != nil", formatter{v: av, quote: true})
|
||||
case !av.IsNil() && !bv.IsNil():
|
||||
w.diff(av.Elem(), bv.Elem())
|
||||
}
|
||||
case reflect.Slice:
|
||||
lenA := av.Len()
|
||||
lenB := bv.Len()
|
||||
if lenA != lenB {
|
||||
w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB)
|
||||
break
|
||||
}
|
||||
for i := 0; i < lenA; i++ {
|
||||
w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
|
||||
}
|
||||
case reflect.String:
|
||||
if a, b := av.String(), bv.String(); a != b {
|
||||
w.printf("%q != %q", a, b)
|
||||
}
|
||||
case reflect.Struct:
|
||||
for i := 0; i < av.NumField(); i++ {
|
||||
w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
|
||||
}
|
||||
default:
|
||||
panic("unknown reflect Kind: " + kind.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (d diffPrinter) relabel(name string) (d1 diffPrinter) {
|
||||
d1 = d
|
||||
if d.l != "" && name[0] != '[' {
|
||||
d1.l += "."
|
||||
}
|
||||
d1.l += name
|
||||
return d1
|
||||
}
|
||||
|
||||
// keyEqual compares a and b for equality.
|
||||
// Both a and b must be valid map keys.
|
||||
func keyEqual(av, bv reflect.Value) bool {
|
||||
if !av.IsValid() && !bv.IsValid() {
|
||||
return true
|
||||
}
|
||||
if !av.IsValid() || !bv.IsValid() || av.Type() != bv.Type() {
|
||||
return false
|
||||
}
|
||||
switch kind := av.Kind(); kind {
|
||||
case reflect.Bool:
|
||||
a, b := av.Bool(), bv.Bool()
|
||||
return a == b
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
a, b := av.Int(), bv.Int()
|
||||
return a == b
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
a, b := av.Uint(), bv.Uint()
|
||||
return a == b
|
||||
case reflect.Float32, reflect.Float64:
|
||||
a, b := av.Float(), bv.Float()
|
||||
return a == b
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
a, b := av.Complex(), bv.Complex()
|
||||
return a == b
|
||||
case reflect.Array:
|
||||
for i := 0; i < av.Len(); i++ {
|
||||
if !keyEqual(av.Index(i), bv.Index(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case reflect.Chan, reflect.UnsafePointer, reflect.Ptr:
|
||||
a, b := av.Pointer(), bv.Pointer()
|
||||
return a == b
|
||||
case reflect.Interface:
|
||||
return keyEqual(av.Elem(), bv.Elem())
|
||||
case reflect.String:
|
||||
a, b := av.String(), bv.String()
|
||||
return a == b
|
||||
case reflect.Struct:
|
||||
for i := 0; i < av.NumField(); i++ {
|
||||
if !keyEqual(av.Field(i), bv.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
panic("invalid map key type " + av.Type().String())
|
||||
}
|
||||
}
|
||||
|
||||
func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) {
|
||||
for _, av := range a {
|
||||
inBoth := false
|
||||
for _, bv := range b {
|
||||
if keyEqual(av, bv) {
|
||||
inBoth = true
|
||||
both = append(both, av)
|
||||
break
|
||||
}
|
||||
}
|
||||
if !inBoth {
|
||||
ak = append(ak, av)
|
||||
}
|
||||
}
|
||||
for _, bv := range b {
|
||||
inBoth := false
|
||||
for _, av := range a {
|
||||
if keyEqual(av, bv) {
|
||||
inBoth = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !inBoth {
|
||||
bk = append(bk, bv)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,328 @@
|
|||
package pretty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/kr/text"
|
||||
)
|
||||
|
||||
type formatter struct {
|
||||
v reflect.Value
|
||||
force bool
|
||||
quote bool
|
||||
}
|
||||
|
||||
// Formatter makes a wrapper, f, that will format x as go source with line
|
||||
// breaks and tabs. Object f responds to the "%v" formatting verb when both the
|
||||
// "#" and " " (space) flags are set, for example:
|
||||
//
|
||||
// fmt.Sprintf("%# v", Formatter(x))
|
||||
//
|
||||
// If one of these two flags is not set, or any other verb is used, f will
|
||||
// format x according to the usual rules of package fmt.
|
||||
// In particular, if x satisfies fmt.Formatter, then x.Format will be called.
|
||||
func Formatter(x interface{}) (f fmt.Formatter) {
|
||||
return formatter{v: reflect.ValueOf(x), quote: true}
|
||||
}
|
||||
|
||||
func (fo formatter) String() string {
|
||||
return fmt.Sprint(fo.v.Interface()) // unwrap it
|
||||
}
|
||||
|
||||
func (fo formatter) passThrough(f fmt.State, c rune) {
|
||||
s := "%"
|
||||
for i := 0; i < 128; i++ {
|
||||
if f.Flag(i) {
|
||||
s += string(i)
|
||||
}
|
||||
}
|
||||
if w, ok := f.Width(); ok {
|
||||
s += fmt.Sprintf("%d", w)
|
||||
}
|
||||
if p, ok := f.Precision(); ok {
|
||||
s += fmt.Sprintf(".%d", p)
|
||||
}
|
||||
s += string(c)
|
||||
fmt.Fprintf(f, s, fo.v.Interface())
|
||||
}
|
||||
|
||||
func (fo formatter) Format(f fmt.State, c rune) {
|
||||
if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') {
|
||||
w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0)
|
||||
p := &printer{tw: w, Writer: w, visited: make(map[visit]int)}
|
||||
p.printValue(fo.v, true, fo.quote)
|
||||
w.Flush()
|
||||
return
|
||||
}
|
||||
fo.passThrough(f, c)
|
||||
}
|
||||
|
||||
type printer struct {
|
||||
io.Writer
|
||||
tw *tabwriter.Writer
|
||||
visited map[visit]int
|
||||
depth int
|
||||
}
|
||||
|
||||
func (p *printer) indent() *printer {
|
||||
q := *p
|
||||
q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0)
|
||||
q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'})
|
||||
return &q
|
||||
}
|
||||
|
||||
func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) {
|
||||
if showType {
|
||||
io.WriteString(p, v.Type().String())
|
||||
fmt.Fprintf(p, "(%#v)", x)
|
||||
} else {
|
||||
fmt.Fprintf(p, "%#v", x)
|
||||
}
|
||||
}
|
||||
|
||||
// printValue must keep track of already-printed pointer values to avoid
|
||||
// infinite recursion.
|
||||
type visit struct {
|
||||
v uintptr
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (p *printer) printValue(v reflect.Value, showType, quote bool) {
|
||||
if p.depth > 10 {
|
||||
io.WriteString(p, "!%v(DEPTH EXCEEDED)")
|
||||
return
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
p.printInline(v, v.Bool(), showType)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
p.printInline(v, v.Int(), showType)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
p.printInline(v, v.Uint(), showType)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
p.printInline(v, v.Float(), showType)
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
fmt.Fprintf(p, "%#v", v.Complex())
|
||||
case reflect.String:
|
||||
p.fmtString(v.String(), quote)
|
||||
case reflect.Map:
|
||||
t := v.Type()
|
||||
if showType {
|
||||
io.WriteString(p, t.String())
|
||||
}
|
||||
writeByte(p, '{')
|
||||
if nonzero(v) {
|
||||
expand := !canInline(v.Type())
|
||||
pp := p
|
||||
if expand {
|
||||
writeByte(p, '\n')
|
||||
pp = p.indent()
|
||||
}
|
||||
keys := v.MapKeys()
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
showTypeInStruct := true
|
||||
k := keys[i]
|
||||
mv := v.MapIndex(k)
|
||||
pp.printValue(k, false, true)
|
||||
writeByte(pp, ':')
|
||||
if expand {
|
||||
writeByte(pp, '\t')
|
||||
}
|
||||
showTypeInStruct = t.Elem().Kind() == reflect.Interface
|
||||
pp.printValue(mv, showTypeInStruct, true)
|
||||
if expand {
|
||||
io.WriteString(pp, ",\n")
|
||||
} else if i < v.Len()-1 {
|
||||
io.WriteString(pp, ", ")
|
||||
}
|
||||
}
|
||||
if expand {
|
||||
pp.tw.Flush()
|
||||
}
|
||||
}
|
||||
writeByte(p, '}')
|
||||
case reflect.Struct:
|
||||
t := v.Type()
|
||||
if v.CanAddr() {
|
||||
addr := v.UnsafeAddr()
|
||||
vis := visit{addr, t}
|
||||
if vd, ok := p.visited[vis]; ok && vd < p.depth {
|
||||
p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false)
|
||||
break // don't print v again
|
||||
}
|
||||
p.visited[vis] = p.depth
|
||||
}
|
||||
|
||||
if showType {
|
||||
io.WriteString(p, t.String())
|
||||
}
|
||||
writeByte(p, '{')
|
||||
if nonzero(v) {
|
||||
expand := !canInline(v.Type())
|
||||
pp := p
|
||||
if expand {
|
||||
writeByte(p, '\n')
|
||||
pp = p.indent()
|
||||
}
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
showTypeInStruct := true
|
||||
if f := t.Field(i); f.Name != "" {
|
||||
io.WriteString(pp, f.Name)
|
||||
writeByte(pp, ':')
|
||||
if expand {
|
||||
writeByte(pp, '\t')
|
||||
}
|
||||
showTypeInStruct = labelType(f.Type)
|
||||
}
|
||||
pp.printValue(getField(v, i), showTypeInStruct, true)
|
||||
if expand {
|
||||
io.WriteString(pp, ",\n")
|
||||
} else if i < v.NumField()-1 {
|
||||
io.WriteString(pp, ", ")
|
||||
}
|
||||
}
|
||||
if expand {
|
||||
pp.tw.Flush()
|
||||
}
|
||||
}
|
||||
writeByte(p, '}')
|
||||
case reflect.Interface:
|
||||
switch e := v.Elem(); {
|
||||
case e.Kind() == reflect.Invalid:
|
||||
io.WriteString(p, "nil")
|
||||
case e.IsValid():
|
||||
pp := *p
|
||||
pp.depth++
|
||||
pp.printValue(e, showType, true)
|
||||
default:
|
||||
io.WriteString(p, v.Type().String())
|
||||
io.WriteString(p, "(nil)")
|
||||
}
|
||||
case reflect.Array, reflect.Slice:
|
||||
t := v.Type()
|
||||
if showType {
|
||||
io.WriteString(p, t.String())
|
||||
}
|
||||
if v.Kind() == reflect.Slice && v.IsNil() && showType {
|
||||
io.WriteString(p, "(nil)")
|
||||
break
|
||||
}
|
||||
if v.Kind() == reflect.Slice && v.IsNil() {
|
||||
io.WriteString(p, "nil")
|
||||
break
|
||||
}
|
||||
writeByte(p, '{')
|
||||
expand := !canInline(v.Type())
|
||||
pp := p
|
||||
if expand {
|
||||
writeByte(p, '\n')
|
||||
pp = p.indent()
|
||||
}
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
showTypeInSlice := t.Elem().Kind() == reflect.Interface
|
||||
pp.printValue(v.Index(i), showTypeInSlice, true)
|
||||
if expand {
|
||||
io.WriteString(pp, ",\n")
|
||||
} else if i < v.Len()-1 {
|
||||
io.WriteString(pp, ", ")
|
||||
}
|
||||
}
|
||||
if expand {
|
||||
pp.tw.Flush()
|
||||
}
|
||||
writeByte(p, '}')
|
||||
case reflect.Ptr:
|
||||
e := v.Elem()
|
||||
if !e.IsValid() {
|
||||
writeByte(p, '(')
|
||||
io.WriteString(p, v.Type().String())
|
||||
io.WriteString(p, ")(nil)")
|
||||
} else {
|
||||
pp := *p
|
||||
pp.depth++
|
||||
writeByte(pp, '&')
|
||||
pp.printValue(e, true, true)
|
||||
}
|
||||
case reflect.Chan:
|
||||
x := v.Pointer()
|
||||
if showType {
|
||||
writeByte(p, '(')
|
||||
io.WriteString(p, v.Type().String())
|
||||
fmt.Fprintf(p, ")(%#v)", x)
|
||||
} else {
|
||||
fmt.Fprintf(p, "%#v", x)
|
||||
}
|
||||
case reflect.Func:
|
||||
io.WriteString(p, v.Type().String())
|
||||
io.WriteString(p, " {...}")
|
||||
case reflect.UnsafePointer:
|
||||
p.printInline(v, v.Pointer(), showType)
|
||||
case reflect.Invalid:
|
||||
io.WriteString(p, "nil")
|
||||
}
|
||||
}
|
||||
|
||||
func canInline(t reflect.Type) bool {
|
||||
switch t.Kind() {
|
||||
case reflect.Map:
|
||||
return !canExpand(t.Elem())
|
||||
case reflect.Struct:
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
if canExpand(t.Field(i).Type) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case reflect.Interface:
|
||||
return false
|
||||
case reflect.Array, reflect.Slice:
|
||||
return !canExpand(t.Elem())
|
||||
case reflect.Ptr:
|
||||
return false
|
||||
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func canExpand(t reflect.Type) bool {
|
||||
switch t.Kind() {
|
||||
case reflect.Map, reflect.Struct,
|
||||
reflect.Interface, reflect.Array, reflect.Slice,
|
||||
reflect.Ptr:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func labelType(t reflect.Type) bool {
|
||||
switch t.Kind() {
|
||||
case reflect.Interface, reflect.Struct:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *printer) fmtString(s string, quote bool) {
|
||||
if quote {
|
||||
s = strconv.Quote(s)
|
||||
}
|
||||
io.WriteString(p, s)
|
||||
}
|
||||
|
||||
func writeByte(w io.Writer, b byte) {
|
||||
w.Write([]byte{b})
|
||||
}
|
||||
|
||||
func getField(v reflect.Value, i int) reflect.Value {
|
||||
val := v.Field(i)
|
||||
if val.Kind() == reflect.Interface && !val.IsNil() {
|
||||
val = val.Elem()
|
||||
}
|
||||
return val
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
// Package pretty provides pretty-printing for Go values. This is
|
||||
// useful during debugging, to avoid wrapping long output lines in
|
||||
// the terminal.
|
||||
//
|
||||
// It provides a function, Formatter, that can be used with any
|
||||
// function that accepts a format string. It also provides
|
||||
// convenience wrappers for functions in packages fmt and log.
|
||||
package pretty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Errorf is a convenience wrapper for fmt.Errorf.
|
||||
//
|
||||
// Calling Errorf(f, x, y) is equivalent to
|
||||
// fmt.Errorf(f, Formatter(x), Formatter(y)).
|
||||
func Errorf(format string, a ...interface{}) error {
|
||||
return fmt.Errorf(format, wrap(a, false)...)
|
||||
}
|
||||
|
||||
// Fprintf is a convenience wrapper for fmt.Fprintf.
|
||||
//
|
||||
// Calling Fprintf(w, f, x, y) is equivalent to
|
||||
// fmt.Fprintf(w, f, Formatter(x), Formatter(y)).
|
||||
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error error) {
|
||||
return fmt.Fprintf(w, format, wrap(a, false)...)
|
||||
}
|
||||
|
||||
// Log is a convenience wrapper for log.Printf.
|
||||
//
|
||||
// Calling Log(x, y) is equivalent to
|
||||
// log.Print(Formatter(x), Formatter(y)), but each operand is
|
||||
// formatted with "%# v".
|
||||
func Log(a ...interface{}) {
|
||||
log.Print(wrap(a, true)...)
|
||||
}
|
||||
|
||||
// Logf is a convenience wrapper for log.Printf.
|
||||
//
|
||||
// Calling Logf(f, x, y) is equivalent to
|
||||
// log.Printf(f, Formatter(x), Formatter(y)).
|
||||
func Logf(format string, a ...interface{}) {
|
||||
log.Printf(format, wrap(a, false)...)
|
||||
}
|
||||
|
||||
// Logln is a convenience wrapper for log.Printf.
|
||||
//
|
||||
// Calling Logln(x, y) is equivalent to
|
||||
// log.Println(Formatter(x), Formatter(y)), but each operand is
|
||||
// formatted with "%# v".
|
||||
func Logln(a ...interface{}) {
|
||||
log.Println(wrap(a, true)...)
|
||||
}
|
||||
|
||||
// Print pretty-prints its operands and writes to standard output.
|
||||
//
|
||||
// Calling Print(x, y) is equivalent to
|
||||
// fmt.Print(Formatter(x), Formatter(y)), but each operand is
|
||||
// formatted with "%# v".
|
||||
func Print(a ...interface{}) (n int, errno error) {
|
||||
return fmt.Print(wrap(a, true)...)
|
||||
}
|
||||
|
||||
// Printf is a convenience wrapper for fmt.Printf.
|
||||
//
|
||||
// Calling Printf(f, x, y) is equivalent to
|
||||
// fmt.Printf(f, Formatter(x), Formatter(y)).
|
||||
func Printf(format string, a ...interface{}) (n int, errno error) {
|
||||
return fmt.Printf(format, wrap(a, false)...)
|
||||
}
|
||||
|
||||
// Println pretty-prints its operands and writes to standard output.
|
||||
//
|
||||
// Calling Print(x, y) is equivalent to
|
||||
// fmt.Println(Formatter(x), Formatter(y)), but each operand is
|
||||
// formatted with "%# v".
|
||||
func Println(a ...interface{}) (n int, errno error) {
|
||||
return fmt.Println(wrap(a, true)...)
|
||||
}
|
||||
|
||||
// Sprint is a convenience wrapper for fmt.Sprintf.
|
||||
//
|
||||
// Calling Sprint(x, y) is equivalent to
|
||||
// fmt.Sprint(Formatter(x), Formatter(y)), but each operand is
|
||||
// formatted with "%# v".
|
||||
func Sprint(a ...interface{}) string {
|
||||
return fmt.Sprint(wrap(a, true)...)
|
||||
}
|
||||
|
||||
// Sprintf is a convenience wrapper for fmt.Sprintf.
|
||||
//
|
||||
// Calling Sprintf(f, x, y) is equivalent to
|
||||
// fmt.Sprintf(f, Formatter(x), Formatter(y)).
|
||||
func Sprintf(format string, a ...interface{}) string {
|
||||
return fmt.Sprintf(format, wrap(a, false)...)
|
||||
}
|
||||
|
||||
func wrap(a []interface{}, force bool) []interface{} {
|
||||
w := make([]interface{}, len(a))
|
||||
for i, x := range a {
|
||||
w[i] = formatter{v: reflect.ValueOf(x), force: force}
|
||||
}
|
||||
return w
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package pretty
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func nonzero(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
return v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() != 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() != 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() != 0
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return v.Complex() != complex(0, 0)
|
||||
case reflect.String:
|
||||
return v.String() != ""
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if nonzero(getField(v, i)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case reflect.Array:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if nonzero(v.Index(i)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case reflect.Map, reflect.Interface, reflect.Slice, reflect.Ptr, reflect.Chan, reflect.Func:
|
||||
return !v.IsNil()
|
||||
case reflect.UnsafePointer:
|
||||
return v.Pointer() != 0
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
Copyright 2012 Keith Rarick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,3 @@
|
|||
This is a Go package for manipulating paragraphs of text.
|
||||
|
||||
See http://go.pkgdoc.org/github.com/kr/text for full documentation.
|
|
@ -0,0 +1,3 @@
|
|||
// Package text provides rudimentary functions for manipulating text in
|
||||
// paragraphs.
|
||||
package text
|
|
@ -0,0 +1,74 @@
|
|||
package text
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Indent inserts prefix at the beginning of each non-empty line of s. The
|
||||
// end-of-line marker is NL.
|
||||
func Indent(s, prefix string) string {
|
||||
return string(IndentBytes([]byte(s), []byte(prefix)))
|
||||
}
|
||||
|
||||
// IndentBytes inserts prefix at the beginning of each non-empty line of b.
|
||||
// The end-of-line marker is NL.
|
||||
func IndentBytes(b, prefix []byte) []byte {
|
||||
var res []byte
|
||||
bol := true
|
||||
for _, c := range b {
|
||||
if bol && c != '\n' {
|
||||
res = append(res, prefix...)
|
||||
}
|
||||
res = append(res, c)
|
||||
bol = c == '\n'
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Writer indents each line of its input.
|
||||
type indentWriter struct {
|
||||
w io.Writer
|
||||
bol bool
|
||||
pre [][]byte
|
||||
sel int
|
||||
off int
|
||||
}
|
||||
|
||||
// NewIndentWriter makes a new write filter that indents the input
|
||||
// lines. Each line is prefixed in order with the corresponding
|
||||
// element of pre. If there are more lines than elements, the last
|
||||
// element of pre is repeated for each subsequent line.
|
||||
func NewIndentWriter(w io.Writer, pre ...[]byte) io.Writer {
|
||||
return &indentWriter{
|
||||
w: w,
|
||||
pre: pre,
|
||||
bol: true,
|
||||
}
|
||||
}
|
||||
|
||||
// The only errors returned are from the underlying indentWriter.
|
||||
func (w *indentWriter) Write(p []byte) (n int, err error) {
|
||||
for _, c := range p {
|
||||
if w.bol {
|
||||
var i int
|
||||
i, err = w.w.Write(w.pre[w.sel][w.off:])
|
||||
w.off += i
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
_, err = w.w.Write([]byte{c})
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
n++
|
||||
w.bol = c == '\n'
|
||||
if w.bol {
|
||||
w.off = 0
|
||||
if w.sel < len(w.pre)-1 {
|
||||
w.sel++
|
||||
}
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package text
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
)
|
||||
|
||||
var (
|
||||
nl = []byte{'\n'}
|
||||
sp = []byte{' '}
|
||||
)
|
||||
|
||||
const defaultPenalty = 1e5
|
||||
|
||||
// Wrap wraps s into a paragraph of lines of length lim, with minimal
|
||||
// raggedness.
|
||||
func Wrap(s string, lim int) string {
|
||||
return string(WrapBytes([]byte(s), lim))
|
||||
}
|
||||
|
||||
// WrapBytes wraps b into a paragraph of lines of length lim, with minimal
|
||||
// raggedness.
|
||||
func WrapBytes(b []byte, lim int) []byte {
|
||||
words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp)
|
||||
var lines [][]byte
|
||||
for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
|
||||
lines = append(lines, bytes.Join(line, sp))
|
||||
}
|
||||
return bytes.Join(lines, nl)
|
||||
}
|
||||
|
||||
// WrapWords is the low-level line-breaking algorithm, useful if you need more
|
||||
// control over the details of the text wrapping process. For most uses, either
|
||||
// Wrap or WrapBytes will be sufficient and more convenient.
|
||||
//
|
||||
// WrapWords splits a list of words into lines with minimal "raggedness",
|
||||
// treating each byte as one unit, accounting for spc units between adjacent
|
||||
// words on each line, and attempting to limit lines to lim units. Raggedness
|
||||
// is the total error over all lines, where error is the square of the
|
||||
// difference of the length of the line and lim. Too-long lines (which only
|
||||
// happen when a single word is longer than lim units) have pen penalty units
|
||||
// added to the error.
|
||||
func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte {
|
||||
n := len(words)
|
||||
|
||||
length := make([][]int, n)
|
||||
for i := 0; i < n; i++ {
|
||||
length[i] = make([]int, n)
|
||||
length[i][i] = len(words[i])
|
||||
for j := i + 1; j < n; j++ {
|
||||
length[i][j] = length[i][j-1] + spc + len(words[j])
|
||||
}
|
||||
}
|
||||
|
||||
nbrk := make([]int, n)
|
||||
cost := make([]int, n)
|
||||
for i := range cost {
|
||||
cost[i] = math.MaxInt32
|
||||
}
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
if length[i][n-1] <= lim || i == n-1 {
|
||||
cost[i] = 0
|
||||
nbrk[i] = n
|
||||
} else {
|
||||
for j := i + 1; j < n; j++ {
|
||||
d := lim - length[i][j-1]
|
||||
c := d*d + cost[j]
|
||||
if length[i][j-1] > lim {
|
||||
c += pen // too-long lines get a worse penalty
|
||||
}
|
||||
if c < cost[i] {
|
||||
cost[i] = c
|
||||
nbrk[i] = j
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lines [][][]byte
|
||||
i := 0
|
||||
for i < n {
|
||||
lines = append(lines, words[i:nbrk[i]])
|
||||
i = nbrk[i]
|
||||
}
|
||||
return lines
|
||||
}
|
|
@ -962,6 +962,18 @@
|
|||
"path": "github.com/kardianos/osext",
|
||||
"revision": "29ae4ffbc9a6fe9fb2bc5029050ce6996ea1d3bc"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "eOXF2PEvYLMeD8DSzLZJWbjYzco=",
|
||||
"path": "github.com/kr/pretty",
|
||||
"revision": "cfb55aafdaf3ec08f0db22699ab822c50091b1c4",
|
||||
"revisionTime": "2016-08-23T17:07:15Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "uulQHQ7IsRKqDudBC8Go9J0gtAc=",
|
||||
"path": "github.com/kr/text",
|
||||
"revision": "7cafcd837844e784b526369c9bce262804aebc60",
|
||||
"revisionTime": "2016-05-04T02:26:26Z"
|
||||
},
|
||||
{
|
||||
"path": "github.com/mattn/go-isatty",
|
||||
"revision": "56b76bdf51f7708750eac80fa38b952bb9f32639"
|
||||
|
|
Loading…
Reference in New Issue