Import upstream version 0.0~git20220113.b1b626a
Debian Janitor
2 years ago
0 | github: [alecthomas] |
0 | on: | |
1 | push: | |
2 | branches: | |
3 | - master | |
4 | pull_request: | |
5 | name: CI | |
6 | jobs: | |
7 | test: | |
8 | name: Test | |
9 | runs-on: ubuntu-latest | |
10 | steps: | |
11 | - name: Checkout code | |
12 | uses: actions/checkout@v2 | |
13 | - name: Init Hermit | |
14 | run: ./bin/hermit env -r >> $GITHUB_ENV | |
15 | - name: Test | |
16 | run: go test ./... | |
17 | lint: | |
18 | name: Lint | |
19 | runs-on: ubuntu-latest | |
20 | steps: | |
21 | - name: Checkout code | |
22 | uses: actions/checkout@v2 | |
23 | - name: Init Hermit | |
24 | run: ./bin/hermit env -r >> $GITHUB_ENV | |
25 | - name: golangci-lint | |
26 | run: golangci-lint run |
0 | # Python's repr() for Go [![](https://godoc.org/github.com/alecthomas/repr?status.svg)](http://godoc.org/github.com/alecthomas/repr) [![Build Status](https://travis-ci.org/alecthomas/repr.png)](https://travis-ci.org/alecthomas/repr) | |
0 | # Python's repr() for Go [![](https://godoc.org/github.com/alecthomas/repr?status.svg)](http://godoc.org/github.com/alecthomas/repr) [![CircleCI](https://img.shields.io/circleci/project/github/alecthomas/repr.svg)](https://circleci.com/gh/alecthomas/repr) | |
1 | 1 | |
2 | 2 | This package attempts to represent Go values in a form that can be used almost directly in Go source |
3 | 3 | code. |
0 | hermit⏎ |
0 | hermit⏎ |
0 | # Hermit environment | |
1 | ||
2 | This is a [Hermit](https://github.com/cashapp/hermit) bin directory. | |
3 | ||
4 | The symlinks in this directory are managed by Hermit and will automatically | |
5 | download and install Hermit itself as well as packages. These packages are | |
6 | local to this environment. |
0 | #!/bin/bash | |
1 | # This file must be used with "source bin/activate-hermit" from bash or zsh. | |
2 | # You cannot run it directly | |
3 | ||
4 | if [ "${BASH_SOURCE-}" = "$0" ]; then | |
5 | echo "You must source this script: \$ source $0" >&2 | |
6 | exit 33 | |
7 | fi | |
8 | ||
9 | BIN_DIR="$(dirname "${BASH_SOURCE[0]:-${(%):-%x}}")" | |
10 | if "${BIN_DIR}/hermit" noop > /dev/null; then | |
11 | eval "$("${BIN_DIR}/hermit" activate "${BIN_DIR}/..")" | |
12 | ||
13 | if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ]; then | |
14 | hash -r 2>/dev/null | |
15 | fi | |
16 | ||
17 | echo "Hermit environment $("${HERMIT_ENV}"/bin/hermit env HERMIT_ENV) activated" | |
18 | fi |
0 | .golangci-lint-1.26.0.pkg⏎ |
0 | #!/bin/bash | |
1 | ||
2 | set -eo pipefail | |
3 | ||
4 | if [ -z "${HERMIT_STATE_DIR}" ]; then | |
5 | case "$(uname -s)" in | |
6 | Darwin) | |
7 | export HERMIT_STATE_DIR="${HOME}/Library/Caches/hermit" | |
8 | ;; | |
9 | Linux) | |
10 | export HERMIT_STATE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/hermit" | |
11 | ;; | |
12 | esac | |
13 | fi | |
14 | ||
15 | export HERMIT_DIST_URL="${HERMIT_DIST_URL:-https://github.com/cashapp/hermit/releases/download/stable}" | |
16 | HERMIT_CHANNEL="$(basename "${HERMIT_DIST_URL}")" | |
17 | export HERMIT_CHANNEL | |
18 | export HERMIT_EXE=${HERMIT_EXE:-${HERMIT_STATE_DIR}/pkg/hermit@${HERMIT_CHANNEL}/hermit} | |
19 | ||
20 | if [ ! -x "${HERMIT_EXE}" ]; then | |
21 | echo "Bootstrapping ${HERMIT_EXE} from ${HERMIT_DIST_URL}" 1>&2 | |
22 | curl -fsSL "${HERMIT_DIST_URL}/install.sh" | /bin/bash 1>&2 | |
23 | fi | |
24 | ||
25 | exec "${HERMIT_EXE}" --level=fatal exec "$0" -- "$@" |
10 | 10 | "io" |
11 | 11 | "os" |
12 | 12 | "reflect" |
13 | "sort" | |
14 | "time" | |
13 | 15 | "unsafe" |
14 | 16 | ) |
15 | 17 | |
60 | 62 | // OmitEmpty sets whether empty field members should be omitted from output. |
61 | 63 | func OmitEmpty(omitEmpty bool) Option { return func(o *Printer) { o.omitEmpty = omitEmpty } } |
62 | 64 | |
65 | // ExplicitTypes adds explicit typing to slice and map struct values that would normally be inferred by Go. | |
66 | func ExplicitTypes(ok bool) Option { return func(o *Printer) { o.explicitTypes = true } } | |
67 | ||
63 | 68 | // IgnoreGoStringer disables use of the .GoString() method. |
64 | 69 | func IgnoreGoStringer() Option { return func(o *Printer) { o.ignoreGoStringer = true } } |
65 | 70 | |
82 | 87 | omitEmpty bool |
83 | 88 | ignoreGoStringer bool |
84 | 89 | alwaysIncludeType bool |
90 | explicitTypes bool | |
85 | 91 | exclude map[reflect.Type]bool |
86 | 92 | w io.Writer |
87 | 93 | } |
120 | 126 | if i > 0 { |
121 | 127 | fmt.Fprint(p.w, " ") |
122 | 128 | } |
123 | p.reprValue(map[reflect.Value]bool{}, reflect.ValueOf(v), "") | |
129 | p.reprValue(map[reflect.Value]bool{}, reflect.ValueOf(v), "", true) | |
124 | 130 | } |
125 | 131 | } |
126 | 132 | |
130 | 136 | if i > 0 { |
131 | 137 | fmt.Fprint(p.w, " ") |
132 | 138 | } |
133 | p.reprValue(map[reflect.Value]bool{}, reflect.ValueOf(v), "") | |
139 | p.reprValue(map[reflect.Value]bool{}, reflect.ValueOf(v), "", true) | |
134 | 140 | } |
135 | 141 | fmt.Fprintln(p.w) |
136 | 142 | } |
137 | 143 | |
138 | func (p *Printer) reprValue(seen map[reflect.Value]bool, v reflect.Value, indent string) { // nolint: gocyclo | |
144 | func (p *Printer) reprValue(seen map[reflect.Value]bool, v reflect.Value, indent string, showType bool) { // nolint: gocyclo | |
139 | 145 | if seen[v] { |
140 | 146 | fmt.Fprint(p.w, "...") |
141 | 147 | return |
154 | 160 | t := v.Type() |
155 | 161 | |
156 | 162 | if t == byteSliceType { |
157 | fmt.Fprintf(p.w, "[]byte(%q)", v.Interface()) | |
163 | fmt.Fprintf(p.w, "[]byte(%q)", v.Bytes()) | |
158 | 164 | return |
159 | 165 | } |
160 | 166 | |
174 | 180 | ni := p.nextIndent(indent) |
175 | 181 | switch v.Kind() { |
176 | 182 | case reflect.Slice, reflect.Array: |
177 | if p.omitEmpty && v.Len() == 0 { | |
178 | return | |
179 | } | |
180 | 183 | fmt.Fprintf(p.w, "%s{", v.Type()) |
181 | 184 | if v.Len() == 0 { |
182 | 185 | fmt.Fprint(p.w, "}") |
187 | 190 | for i := 0; i < v.Len(); i++ { |
188 | 191 | e := v.Index(i) |
189 | 192 | fmt.Fprintf(p.w, "%s", ni) |
190 | p.reprValue(seen, e, ni) | |
193 | p.reprValue(seen, e, ni, p.alwaysIncludeType || p.explicitTypes) | |
191 | 194 | if p.indent != "" { |
192 | 195 | fmt.Fprintf(p.w, ",\n") |
193 | 196 | } else if i < v.Len()-1 { |
207 | 210 | if p.indent != "" && v.Len() != 0 { |
208 | 211 | fmt.Fprintf(p.w, "\n") |
209 | 212 | } |
210 | for i, k := range v.MapKeys() { | |
213 | keys := v.MapKeys() | |
214 | sort.Slice(keys, func(i, j int) bool { | |
215 | return fmt.Sprint(keys[i]) < fmt.Sprint(keys[j]) | |
216 | }) | |
217 | for i, k := range keys { | |
211 | 218 | kv := v.MapIndex(k) |
212 | 219 | fmt.Fprintf(p.w, "%s", ni) |
213 | p.reprValue(seen, k, ni) | |
220 | p.reprValue(seen, k, ni, p.alwaysIncludeType || p.explicitTypes) | |
214 | 221 | fmt.Fprintf(p.w, ": ") |
215 | p.reprValue(seen, kv, ni) | |
222 | p.reprValue(seen, kv, ni, true) | |
216 | 223 | if p.indent != "" { |
217 | 224 | fmt.Fprintf(p.w, ",\n") |
218 | 225 | } else if i < v.Len()-1 { |
222 | 229 | fmt.Fprintf(p.w, "%s}", in) |
223 | 230 | |
224 | 231 | case reflect.Struct: |
225 | fmt.Fprintf(p.w, "%s{", v.Type()) | |
226 | if p.indent != "" && v.NumField() != 0 { | |
227 | fmt.Fprintf(p.w, "\n") | |
228 | } | |
229 | for i := 0; i < v.NumField(); i++ { | |
230 | t := v.Type().Field(i) | |
231 | f := v.Field(i) | |
232 | if p.omitEmpty && isZero(f) { | |
233 | continue | |
234 | } | |
235 | fmt.Fprintf(p.w, "%s%s: ", ni, t.Name) | |
236 | p.reprValue(seen, f, ni) | |
237 | if p.indent != "" { | |
238 | fmt.Fprintf(p.w, ",\n") | |
239 | } else if i < v.NumField()-1 { | |
240 | fmt.Fprintf(p.w, ", ") | |
241 | } | |
242 | } | |
243 | fmt.Fprintf(p.w, "%s}", indent) | |
244 | ||
232 | if td, ok := v.Interface().(time.Time); ok { | |
233 | timeToGo(p.w, td) | |
234 | } else { | |
235 | if showType { | |
236 | fmt.Fprintf(p.w, "%s{", v.Type()) | |
237 | } else { | |
238 | fmt.Fprint(p.w, "{") | |
239 | } | |
240 | if p.indent != "" && v.NumField() != 0 { | |
241 | fmt.Fprintf(p.w, "\n") | |
242 | } | |
243 | for i := 0; i < v.NumField(); i++ { | |
244 | t := v.Type().Field(i) | |
245 | f := v.Field(i) | |
246 | if p.omitEmpty && isZero(f) { | |
247 | continue | |
248 | } | |
249 | fmt.Fprintf(p.w, "%s%s: ", ni, t.Name) | |
250 | p.reprValue(seen, f, ni, true) | |
251 | if p.indent != "" { | |
252 | fmt.Fprintf(p.w, ",\n") | |
253 | } else if i < v.NumField()-1 { | |
254 | fmt.Fprintf(p.w, ", ") | |
255 | } | |
256 | } | |
257 | fmt.Fprintf(p.w, "%s}", indent) | |
258 | } | |
245 | 259 | case reflect.Ptr: |
246 | 260 | if v.IsNil() { |
247 | 261 | fmt.Fprintf(p.w, "nil") |
248 | 262 | return |
249 | 263 | } |
250 | fmt.Fprintf(p.w, "&") | |
251 | p.reprValue(seen, v.Elem(), indent) | |
264 | if showType { | |
265 | fmt.Fprintf(p.w, "&") | |
266 | } | |
267 | p.reprValue(seen, v.Elem(), indent, showType) | |
252 | 268 | |
253 | 269 | case reflect.String: |
254 | 270 | if t.Name() != "string" || p.alwaysIncludeType { |
261 | 277 | if v.IsNil() { |
262 | 278 | fmt.Fprintf(p.w, "interface {}(nil)") |
263 | 279 | } else { |
264 | p.reprValue(seen, v.Elem(), indent) | |
280 | p.reprValue(seen, v.Elem(), indent, true) | |
265 | 281 | } |
266 | 282 | |
267 | 283 | default: |
322 | 338 | } |
323 | 339 | return false |
324 | 340 | } |
341 | ||
342 | func timeToGo(w io.Writer, t time.Time) { | |
343 | if t.IsZero() { | |
344 | fmt.Fprint(w, "time.Time{}") | |
345 | return | |
346 | } | |
347 | ||
348 | var zone string | |
349 | switch loc := t.Location(); loc { | |
350 | case nil: | |
351 | zone = "nil" | |
352 | case time.UTC: | |
353 | zone = "time.UTC" | |
354 | case time.Local: | |
355 | zone = "time.Local" | |
356 | default: | |
357 | n, off := t.Zone() | |
358 | zone = fmt.Sprintf("time.FixedZone(%q, %d)", n, off) | |
359 | } | |
360 | y, m, d := t.Date() | |
361 | fmt.Fprintf(w, `time.Date(%d, %d, %d, %d, %d, %d, %d, %s)`, y, m, d, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), zone) | |
362 | } |
0 | 0 | package repr |
1 | 1 | |
2 | 2 | import ( |
3 | "bytes" | |
4 | "runtime" | |
3 | 5 | "strings" |
4 | 6 | "testing" |
5 | ||
6 | "github.com/stretchr/testify/assert" | |
7 | 7 | ) |
8 | ||
9 | func equal(t *testing.T, want, have string) { | |
10 | t.Helper() | |
11 | if want != have { | |
12 | t.Errorf("\nWant: %q\nHave: %q", want, have) | |
13 | } | |
14 | } | |
8 | 15 | |
9 | 16 | type anotherStruct struct { |
10 | 17 | A []int |
17 | 24 | } |
18 | 25 | |
19 | 26 | func TestReprEmptyArray(t *testing.T) { |
20 | assert.Equal(t, "[]string{}", String([]string{}, OmitEmpty(false))) | |
27 | equal(t, "[]string{}", String([]string{}, OmitEmpty(false))) | |
21 | 28 | } |
22 | 29 | |
23 | 30 | func TestReprStringArray(t *testing.T) { |
24 | assert.Equal(t, "[]string{\"a\", \"b\"}", String([]string{"a", "b"})) | |
31 | equal(t, "[]string{\"a\", \"b\"}", String([]string{"a", "b"})) | |
25 | 32 | } |
26 | 33 | |
27 | 34 | func TestReprIntArray(t *testing.T) { |
28 | assert.Equal(t, "[]int{1, 2}", String([]int{1, 2})) | |
35 | equal(t, "[]int{1, 2}", String([]int{1, 2})) | |
29 | 36 | } |
30 | 37 | |
31 | 38 | func TestReprPointerToInt(t *testing.T) { |
32 | 39 | pi := new(int) |
33 | 40 | *pi = 13 |
34 | assert.Equal(t, `&13`, String(pi)) | |
41 | equal(t, `&13`, String(pi)) | |
35 | 42 | } |
36 | 43 | |
37 | 44 | func TestReprChannel(t *testing.T) { |
38 | 45 | ch := make(<-chan map[string]*testStruct, 1) |
39 | assert.Equal(t, `make(<-chan map[string]*repr.testStruct, 1)`, String(ch)) | |
46 | equal(t, `make(<-chan map[string]*repr.testStruct, 1)`, String(ch)) | |
40 | 47 | } |
41 | 48 | |
42 | 49 | func TestReprEmptyMap(t *testing.T) { |
43 | assert.Equal(t, "map[string]bool{}", String(map[string]bool{})) | |
50 | equal(t, "map[string]bool{}", String(map[string]bool{})) | |
44 | 51 | } |
45 | 52 | |
46 | 53 | func TestReprMap(t *testing.T) { |
47 | m := map[string]int{"a": 1} | |
48 | assert.Equal(t, "map[string]int{\"a\": 1}", String(m)) | |
54 | m := map[string]int{"b": 3, "a": 1, "c": 5} | |
55 | for i := 0; i < 1000; i++ { | |
56 | equal(t, "map[string]int{\"a\": 1, \"b\": 3, \"c\": 5}", String(m)) | |
57 | } | |
58 | } | |
59 | ||
60 | func TestReprIntMap(t *testing.T) { | |
61 | m := map[int]string{3: "b", 1: "a", 5: "c"} | |
62 | for i := 0; i < 1000; i++ { | |
63 | equal(t, "map[int]string{1: \"a\", 3: \"b\", 5: \"c\"}", String(m)) | |
64 | } | |
49 | 65 | } |
50 | 66 | |
51 | 67 | func TestReprStructWithIndent(t *testing.T) { |
58 | 74 | A: []int{1, 2, 3}, |
59 | 75 | }, |
60 | 76 | } |
61 | assert.Equal(t, `&repr.testStruct{ | |
77 | equal(t, `&repr.testStruct{ | |
62 | 78 | S: "String", |
63 | 79 | I: &13, |
64 | 80 | A: repr.anotherStruct{ |
69 | 85 | }, |
70 | 86 | }, |
71 | 87 | }`, String(s, Indent(" "))) |
72 | ||
73 | 88 | } |
74 | 89 | |
75 | 90 | func TestReprByteArray(t *testing.T) { |
76 | 91 | b := []byte{1, 2, 3} |
77 | assert.Equal(t, "[]byte(\"\\x01\\x02\\x03\")", String(b)) | |
92 | equal(t, "[]byte(\"\\x01\\x02\\x03\")", String(b)) | |
78 | 93 | } |
79 | 94 | |
80 | 95 | type privateTestStruct struct { |
83 | 98 | |
84 | 99 | func TestReprPrivateField(t *testing.T) { |
85 | 100 | s := privateTestStruct{"hello"} |
86 | assert.Equal(t, `repr.privateTestStruct{a: "hello"}`, String(s)) | |
101 | equal(t, `repr.privateTestStruct{a: "hello"}`, String(s)) | |
87 | 102 | } |
88 | 103 | |
89 | 104 | func TestReprNilAlone(t *testing.T) { |
90 | 105 | var err error |
91 | 106 | s := String(err) |
92 | assert.Equal(t, "nil", s) | |
107 | equal(t, "nil", s) | |
108 | } | |
109 | ||
110 | func TestExplicitTypes(t *testing.T) { | |
111 | arr := []*privateTestStruct{{"hello"}, nil} | |
112 | s := String(arr, ExplicitTypes(true)) | |
113 | equal(t, "[]*repr.privateTestStruct{&repr.privateTestStruct{a: \"hello\"}, nil}", s) | |
93 | 114 | } |
94 | 115 | |
95 | 116 | func TestReprNilInsideArray(t *testing.T) { |
96 | 117 | arr := []*privateTestStruct{{"hello"}, nil} |
97 | 118 | s := String(arr) |
98 | assert.Equal(t, "[]*repr.privateTestStruct{&repr.privateTestStruct{a: \"hello\"}, nil}", s) | |
119 | equal(t, "[]*repr.privateTestStruct{{a: \"hello\"}, nil}", s) | |
120 | } | |
121 | ||
122 | func TestReprEmptySlice(t *testing.T) { | |
123 | a := []int{} | |
124 | s := String(a) | |
125 | equal(t, "[]int{}", s) | |
126 | } | |
127 | ||
128 | func TestReprNilSlice(t *testing.T) { | |
129 | var a []int | |
130 | s := String(a) | |
131 | equal(t, "nil", s) | |
132 | } | |
133 | ||
134 | type intSliceStruct struct{ f []int } | |
135 | ||
136 | func TestReprEmptySliceStruct(t *testing.T) { | |
137 | a := intSliceStruct{f: []int{}} | |
138 | s := String(a) | |
139 | equal(t, "repr.intSliceStruct{f: []int{}}", s) | |
140 | } | |
141 | ||
142 | func TestReprNilSliceStruct(t *testing.T) { | |
143 | var a intSliceStruct | |
144 | s := String(a) | |
145 | equal(t, "repr.intSliceStruct{}", s) | |
99 | 146 | } |
100 | 147 | |
101 | 148 | type Enum int |
107 | 154 | func TestEnum(t *testing.T) { |
108 | 155 | v := Enum(1) |
109 | 156 | s := String(v) |
110 | assert.Equal(t, "repr.Enum(Value)", s) | |
157 | equal(t, "repr.Enum(Value)", s) | |
111 | 158 | } |
112 | 159 | |
113 | 160 | func TestShowType(t *testing.T) { |
114 | 161 | a := map[string]privateTestStruct{"foo": {"bar"}} |
115 | 162 | s := String(a, AlwaysIncludeType(), Indent(" ")) |
116 | t.Log(s) | |
117 | assert.Equal(t, strings.TrimSpace(` | |
163 | equal(t, strings.TrimSpace(` | |
118 | 164 | map[string]repr.privateTestStruct{ |
119 | 165 | string("foo"): repr.privateTestStruct{ |
120 | 166 | a: string("bar"), |
122 | 168 | } |
123 | 169 | `), s) |
124 | 170 | } |
171 | ||
172 | func TestRecursiveIssue3(t *testing.T) { | |
173 | type data struct { | |
174 | parent *data | |
175 | children []*data | |
176 | } | |
177 | child := &data{} | |
178 | root := &data{children: []*data{child}} | |
179 | child.parent = root | |
180 | want := "&repr.data{children: []*repr.data{{parent: &..., }}}" | |
181 | have := String(root) | |
182 | equal(t, want, have) | |
183 | } | |
184 | ||
185 | type MyBuffer struct { | |
186 | buf *bytes.Buffer | |
187 | } | |
188 | ||
189 | func TestReprPrivateBytes(t *testing.T) { | |
190 | mb := MyBuffer{ | |
191 | buf: bytes.NewBufferString("Hi th3re!"), | |
192 | } | |
193 | s := String(mb) | |
194 | ||
195 | switch v := runtime.Version(); { | |
196 | case strings.Contains(v, "go1.9"): | |
197 | equal(t, "repr.MyBuffer{buf: &bytes.Buffer{buf: []byte(\"Hi th3re!\"), bootstrap: [64]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}", s) | |
198 | case strings.Contains(v, "go1.10"), strings.Contains(v, "go1.11"): | |
199 | equal(t, "repr.MyBuffer{buf: &bytes.Buffer{buf: []byte(\"Hi th3re!\"), bootstrap: [64]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }}", s) | |
200 | default: | |
201 | equal(t, "repr.MyBuffer{buf: &bytes.Buffer{buf: []byte(\"Hi th3re!\"), }}", s) | |
202 | } | |
203 | } |