Remove dependency of go-dproxy (#746)

This change removes to dependency of go-dproxy from multus to
reducing library dependencies.
This commit is contained in:
Tomofumi Hayashi 2021-10-29 01:15:11 +09:00 committed by GitHub
parent 1e43784d4c
commit 7091831a00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 50 additions and 1325 deletions

1
go.mod
View File

@ -7,7 +7,6 @@ require (
github.com/containernetworking/plugins v0.9.1 github.com/containernetworking/plugins v0.9.1
github.com/fsnotify/fsnotify v1.4.9 github.com/fsnotify/fsnotify v1.4.9
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.1.1-0.20210510153419-66a699ae3b05 github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.1.1-0.20210510153419-66a699ae3b05
github.com/koron/go-dproxy v1.3.0
github.com/onsi/ginkgo v1.12.1 github.com/onsi/ginkgo v1.12.1
github.com/onsi/gomega v1.10.3 github.com/onsi/gomega v1.10.3
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1

2
go.sum
View File

@ -372,8 +372,6 @@ github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/koron/go-dproxy v1.3.0 h1:wE0gxsw1NJnbkk5czp3/xUtwgTeLP8p/YaSjdUOmI7k=
github.com/koron/go-dproxy v1.3.0/go.mod h1:M+lZRjGA7zf1CdgBWoL8HH1lKb6jlgR4qnX3hxRdQHs=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=

View File

@ -23,8 +23,6 @@ import (
"sort" "sort"
"strings" "strings"
"time" "time"
"github.com/koron/go-dproxy"
) )
const ( const (
@ -148,17 +146,21 @@ func WithOverriddenName(networkName string) Option {
} }
} }
func withCapabilities(cniData dproxy.Proxy) Option { func withCapabilities(cniData interface{}) Option {
var enabledCapabilities []string var enabledCapabilities []string
pluginsList, err := cniData.M(configListCapabilityKey).Array() var pluginsList []interface{}
if err != nil { cniDataMap, ok := cniData.(map[string]interface{})
pluginsList = nil if ok {
if pluginsListEntry, ok := cniDataMap[configListCapabilityKey]; ok {
pluginsList = pluginsListEntry.([]interface{})
}
} }
if len(pluginsList) > 0 { if len(pluginsList) > 0 {
for _, pluginData := range pluginsList { for _, pluginData := range pluginsList {
enabledCapabilities = append( enabledCapabilities = append(
enabledCapabilities, enabledCapabilities,
extractCapabilities(dproxy.New(pluginData))...) extractCapabilities(pluginData)...)
} }
} else { } else {
enabledCapabilities = extractCapabilities(cniData) enabledCapabilities = extractCapabilities(cniData)
@ -171,15 +173,23 @@ func withCapabilities(cniData dproxy.Proxy) Option {
} }
} }
func withDelegates(primaryCNIConfigData interface{}) Option { func withDelegates(primaryCNIConfigData map[string]interface{}) Option {
return func(conf *MultusConf) { return func(conf *MultusConf) {
conf.Delegates = []interface{}{primaryCNIConfigData} conf.Delegates = []interface{}{primaryCNIConfigData}
} }
} }
func extractCapabilities(capabilitiesProxy dproxy.Proxy) []string { func extractCapabilities(capabilitiesInterface interface{}) []string {
capabilities, err := capabilitiesProxy.M(singleConfigCapabilityKey).Map() capabilitiesMap, ok := capabilitiesInterface.(map[string]interface{})
if err != nil { if !ok {
return nil
}
capabilitiesMapEntry, ok := capabilitiesMap[singleConfigCapabilityKey]
if !ok {
return nil
}
capabilities, ok := capabilitiesMapEntry.(map[string]interface{})
if !ok {
return nil return nil
} }

View File

@ -16,9 +16,9 @@
package config package config
import ( import (
"encoding/json"
"fmt"
"testing" "testing"
"github.com/koron/go-dproxy"
) )
const ( const (
@ -127,7 +127,7 @@ func TestMultusConfigWithCapabilities(t *testing.T) {
kubeconfig, kubeconfig,
primaryCNIConfig, primaryCNIConfig,
withCapabilities( withCapabilities(
documentProxyHelper(`{"capabilities": {"portMappings": true}}`))) documentHelper(`{"capabilities": {"portMappings": true}}`)))
expectedResult := "{\"capabilities\":{\"portMappings\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}" expectedResult := "{\"capabilities\":{\"portMappings\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}"
newTestCase(t, multusConfig.Generate).assertResult(expectedResult) newTestCase(t, multusConfig.Generate).assertResult(expectedResult)
} }
@ -139,7 +139,7 @@ func TestMultusConfigWithMultipleCapabilities(t *testing.T) {
kubeconfig, kubeconfig,
primaryCNIConfig, primaryCNIConfig,
withCapabilities( withCapabilities(
documentProxyHelper(`{"capabilities": {"portMappings": true, "tuning": true}}`))) documentHelper(`{"capabilities": {"portMappings": true, "tuning": true}}`)))
expectedResult := "{\"capabilities\":{\"portMappings\":true,\"tuning\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}" expectedResult := "{\"capabilities\":{\"portMappings\":true,\"tuning\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}"
newTestCase(t, multusConfig.Generate).assertResult(expectedResult) newTestCase(t, multusConfig.Generate).assertResult(expectedResult)
} }
@ -151,7 +151,7 @@ func TestMultusConfigWithMultipleCapabilitiesFilterOnlyEnabled(t *testing.T) {
kubeconfig, kubeconfig,
primaryCNIConfig, primaryCNIConfig,
withCapabilities( withCapabilities(
documentProxyHelper(`{"capabilities": {"portMappings": true, "tuning": false}}`))) documentHelper(`{"capabilities": {"portMappings": true, "tuning": false}}`)))
expectedResult := "{\"capabilities\":{\"portMappings\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}" expectedResult := "{\"capabilities\":{\"portMappings\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}"
newTestCase(t, multusConfig.Generate).assertResult(expectedResult) newTestCase(t, multusConfig.Generate).assertResult(expectedResult)
} }
@ -163,7 +163,7 @@ func TestMultusConfigWithMultipleCapabilitiesDefinedOnAPlugin(t *testing.T) {
kubeconfig, kubeconfig,
primaryCNIConfig, primaryCNIConfig,
withCapabilities( withCapabilities(
documentProxyHelper(`{"plugins": [ {"capabilities": {"portMappings": true, "tuning": true}} ] }`))) documentHelper(`{"plugins": [ {"capabilities": {"portMappings": true, "tuning": true}} ] }`)))
expectedResult := "{\"capabilities\":{\"portMappings\":true,\"tuning\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}" expectedResult := "{\"capabilities\":{\"portMappings\":true,\"tuning\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}"
newTestCase(t, multusConfig.Generate).assertResult(expectedResult) newTestCase(t, multusConfig.Generate).assertResult(expectedResult)
} }
@ -175,7 +175,7 @@ func TestMultusConfigWithCapabilitiesDefinedOnMultiplePlugins(t *testing.T) {
kubeconfig, kubeconfig,
primaryCNIConfig, primaryCNIConfig,
withCapabilities( withCapabilities(
documentProxyHelper(`{"plugins": [ {"capabilities": { "portMappings": true }}, {"capabilities": { "tuning": true }} ]}`))) documentHelper(`{"plugins": [ {"capabilities": { "portMappings": true }}, {"capabilities": { "tuning": true }} ]}`)))
expectedResult := "{\"capabilities\":{\"portMappings\":true,\"tuning\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}" expectedResult := "{\"capabilities\":{\"portMappings\":true,\"tuning\":true},\"cniVersion\":\"0.4.0\",\"delegates\":[{\"cniVersion\":\"1.0.0\",\"dns\":\"{}\",\"ipam\":\"{}\",\"logFile\":\"/var/log/ovn-kubernetes/ovn-k8s-cni-overlay.log\",\"logLevel\":\"5\",\"logfile-maxage\":5,\"logfile-maxbackups\":5,\"logfile-maxsize\":100,\"name\":\"ovn-kubernetes\",\"type\":\"ovn-k8s-cni-overlay\"}],\"kubeconfig\":\"/a/b/c/kubeconfig.kubeconfig\",\"name\":\"multus-cni-network\",\"type\":\"myCNI\"}"
newTestCase(t, multusConfig.Generate).assertResult(expectedResult) newTestCase(t, multusConfig.Generate).assertResult(expectedResult)
} }
@ -187,7 +187,7 @@ func TestMultusConfigWithCapabilitiesDefinedOnMultiplePluginsFilterOnlyEnabled(t
kubeconfig, kubeconfig,
primaryCNIConfig, primaryCNIConfig,
withCapabilities( withCapabilities(
documentProxyHelper(` documentHelper(`
{ {
"plugins": [ "plugins": [
{ {
@ -235,7 +235,15 @@ func (tc testCase) assertResult(expectedResult string) {
} }
} }
func documentProxyHelper(pluginInfo string) dproxy.Proxy { func documentHelper(pluginInfo string) interface{} {
dp, _ := documentProxy([]byte(pluginInfo)) dp, _ := documentCNIData([]byte(pluginInfo))
return dp return dp
} }
func documentCNIData(masterCNIConfigData []byte) (interface{}, error) {
var cniData interface{}
if err := json.Unmarshal(masterCNIConfigData, &cniData); err != nil {
return nil, fmt.Errorf("failed to unmarshall the delegate CNI configuration: %w", err)
}
return cniData, nil
}

View File

@ -21,7 +21,6 @@ import (
"io/ioutil" "io/ioutil"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/koron/go-dproxy"
"gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/logging" "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/logging"
) )
@ -36,7 +35,7 @@ const (
// Manager monitors the configuration of the primary CNI plugin, and // Manager monitors the configuration of the primary CNI plugin, and
// regenerates multus configuration whenever it gets updated. // regenerates multus configuration whenever it gets updated.
type Manager struct { type Manager struct {
cniConfigData dproxy.Proxy cniConfigData map[string]interface{}
configWatcher *fsnotify.Watcher configWatcher *fsnotify.Watcher
multusConfig *MultusConf multusConfig *MultusConf
multusConfigDir string multusConfigDir string
@ -96,10 +95,12 @@ func (m *Manager) loadPrimaryCNIConfigFromFile() error {
// OverrideNetworkName overrides the name of the multus configuration with the // OverrideNetworkName overrides the name of the multus configuration with the
// name of the delegated primary CNI. // name of the delegated primary CNI.
func (m *Manager) OverrideNetworkName() error { func (m *Manager) OverrideNetworkName() error {
networkName, err := m.cniConfigData.M("name").String() name, ok := m.cniConfigData["name"]
if err != nil { if !ok {
return fmt.Errorf("failed to access delegate CNI plugin name") return fmt.Errorf("failed to access delegate CNI plugin name")
} }
networkName := name.(string)
if networkName == "" { if networkName == "" {
return fmt.Errorf("the primary CNI Configuration does not feature the network name: %v", m.cniConfigData) return fmt.Errorf("the primary CNI Configuration does not feature the network name: %v", m.cniConfigData)
} }
@ -108,11 +109,12 @@ func (m *Manager) OverrideNetworkName() error {
} }
func (m *Manager) loadPrimaryCNIConfigurationData(primaryCNIConfigData interface{}) { func (m *Manager) loadPrimaryCNIConfigurationData(primaryCNIConfigData interface{}) {
cniConfig := dproxy.New(primaryCNIConfigData) cniConfigData := primaryCNIConfigData.(map[string]interface{})
m.cniConfigData = cniConfig
m.cniConfigData = cniConfigData
m.multusConfig.Mutate( m.multusConfig.Mutate(
withDelegates(primaryCNIConfigData), withDelegates(cniConfigData),
withCapabilities(cniConfig)) withCapabilities(cniConfigData))
} }
// GenerateConfig generates a multus configuration from its current state // GenerateConfig generates a multus configuration from its current state
@ -223,11 +225,3 @@ func primaryCNIData(masterCNIPluginPath string) (interface{}, error) {
} }
return cniData, nil return cniData, nil
} }
func documentProxy(masterCNIConfigData []byte) (dproxy.Proxy, error) {
var cniData interface{}
if err := json.Unmarshal(masterCNIConfigData, &cniData); err != nil {
return nil, fmt.Errorf("failed to unmarshall the delegate CNI configuration: %w", err)
}
return dproxy.New(cniData), nil
}

View File

@ -95,9 +95,7 @@ var _ = Describe(suiteName, func() {
Op: fsnotify.Write, Op: fsnotify.Write,
})) }))
updatedConfig, err := configManager.cniConfigData.Map() bytes, err := json.Marshal(configManager.cniConfigData)
Expect(err).NotTo(HaveOccurred())
bytes, err := json.Marshal(updatedConfig)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(string(bytes)).To(Equal(newCNIConfig)) Expect(string(bytes)).To(Equal(newCNIConfig))

View File

@ -1,2 +0,0 @@
/tags
/tmp/

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 MURAOKA Taro <koron.kaoriya@gmail.com>
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.

View File

@ -1,29 +0,0 @@
default: test
test:
go test ./...
test-full:
go test -v -race ./...
lint:
go vet ./...
@echo ""
golint ./...
cyclo:
-gocyclo -top 10 -avg .
report:
@echo "misspell"
@find . -name "*.go" | xargs misspell
@echo ""
-errcheck ./...
@echo ""
-gocyclo -over 14 -avg .
@echo ""
go vet ./...
@echo ""
golint ./...
.PHONY: test test-full lint cyclo report

View File

@ -1,155 +0,0 @@
# dProxy - document proxy
[![GoDoc](https://godoc.org/github.com/koron/go-dproxy?status.svg)](https://godoc.org/github.com/koron/go-dproxy)
[![CircleCI](https://img.shields.io/circleci/project/github/koron/go-dproxy/master.svg)](https://circleci.com/gh/koron/go-dproxy/tree/master)
[![Go Report Card](https://goreportcard.com/badge/github.com/koron/go-dproxy)](https://goreportcard.com/report/github.com/koron/go-dproxy)
dProxy is a proxy to access `interface{}` (document) by simple query.
It is intented to be used with `json.Unmarshal()` or `json.NewDecorder()`.
See codes for overview.
```go
import (
"encoding/json"
"github.com/koron/go-dproxy"
)
var v interface{}
json.Unmarshal([]byte(`{
"cities": [ "tokyo", 100, "osaka", 200, "hakata", 300 ],
"data": {
"custom": [ "male", 23, "female", 24 ]
}
}`), &v)
// s == "tokyo", got a string.
s, _ := dproxy.New(v).M("cities").A(0).String()
// err != nil, type not matched.
_, err := dproxy.New(v).M("cities").A(0).Float64()
// n == 200, got a float64
n, _ := dproxy.New(v).M("cities").A(3).Float64()
// can be chained.
dproxy.New(v).M("data").M("custom").A(0).String()
// err.Error() == "not found: data.kustom", wrong query can be verified.
_, err = dproxy.New(v).M("data").M("kustom").String()
```
## Getting started
### Proxy
1. Wrap a value (`interface{}`) with `dproxy.New()` get `dproxy.Proxy`.
```go
p := dproxy.New(v) // v should be a value of interface{}
```
2. Query as a map (`map[string]interface{}`)by `M()`, returns `dproxy.Proxy`.
```go
p.M("cities")
```
3. Query as an array (`[]interface{}`) with `A()`, returns `dproxy.Proxy`.
```go
p.A(3)
```
4. Therefore, can be chained queries.
```go
p.M("cities").A(3)
```
5. Get a value finally.
```go
n, _ := p.M("cities").A(3).Int64()
```
6. You'll get an error when getting a value, if there were some mistakes.
```go
// OOPS! "kustom" is typo, must be "custom"
_, err := p.M("data").M("kustom").A(3).Int64()
// "not found: data.kustom"
fmt.Println(err)
```
7. If you tried to get a value as different type, get an error.
```go
// OOPS! "cities[3]" (=200) should be float64 or int64.
_, err := p.M("cities").A(3).String()
// "not matched types: expected=string actual=float64: cities[3]"
fmt.Println(err)
```
8. You can verify queries easily.
### Drain
Getting value and error from Proxy/ProxySet multiple times, is very awful.
It must check error when every getting values.
```go
p := dproxy.New(v)
v1, err := p.M("cities").A(3).Int64()
if err != nil {
return err
}
v2, err := p.M("data").M("kustom").A(3).Int64()
if err != nil {
return err
}
v3, err := p.M("cities").A(3).String()
if err != nil {
return err
}
```
It can be rewrite as simple like below with `dproxy.Drain`
```go
var d Drain
p := dproxy.New(v)
v1 := d.Int64(p.M("cities").A(3))
v2 := d.Int64(p.M("data").M("kustom").A(3))
v3 := d.String(p.M("cities").A(3))
if err := d.CombineErrors(); err != nil {
return err
}
```
### JSON Pointer
JSON Pointer can be used to query `interface{}`
```go
v1, err := dproxy.New(v).P("/cities/0").Int64()
```
or
```go
v1, err := dproxy.Pointer(v, "/cities/0").Int64()
```
See [RFC6901][1] for details of JSON Pointer.
## LICENSE
MIT license. See LICENSE.
[1]: https://tools.ietf.org/html/rfc6901

View File

@ -1,150 +0,0 @@
package dproxy
import "bytes"
// Drain stores errors from Proxy or ProxySet.
type Drain struct {
errors []error
}
// Has returns true if the drain stored some of errors.
func (d *Drain) Has() bool {
return d != nil && len(d.errors) > 0
}
// First returns a stored error. Returns nil if there are no errors.
func (d *Drain) First() error {
if d == nil || len(d.errors) == 0 {
return nil
}
return d.errors[0]
}
// All returns all errors which stored. Return nil if no errors stored.
func (d *Drain) All() []error {
if d == nil || len(d.errors) == 0 {
return nil
}
a := make([]error, 0, len(d.errors))
return append(a, d.errors...)
}
// CombineErrors returns an error which combined all stored errors. Return nil
// if not erros stored.
func (d *Drain) CombineErrors() error {
if d == nil || len(d.errors) == 0 {
return nil
}
return drainError(d.errors)
}
func (d *Drain) put(err error) {
if err == nil {
return
}
d.errors = append(d.errors, err)
}
// Bool returns bool value and stores an error.
func (d *Drain) Bool(p Proxy) bool {
v, err := p.Bool()
d.put(err)
return v
}
// Int64 returns int64 value and stores an error.
func (d *Drain) Int64(p Proxy) int64 {
v, err := p.Int64()
d.put(err)
return v
}
// Float64 returns float64 value and stores an error.
func (d *Drain) Float64(p Proxy) float64 {
v, err := p.Float64()
d.put(err)
return v
}
// String returns string value and stores an error.
func (d *Drain) String(p Proxy) string {
v, err := p.String()
d.put(err)
return v
}
// Array returns []interface{} value and stores an error.
func (d *Drain) Array(p Proxy) []interface{} {
v, err := p.Array()
d.put(err)
return v
}
// Map returns map[string]interface{} value and stores an error.
func (d *Drain) Map(p Proxy) map[string]interface{} {
v, err := p.Map()
d.put(err)
return v
}
// BoolArray returns []bool value and stores an error.
func (d *Drain) BoolArray(ps ProxySet) []bool {
v, err := ps.BoolArray()
d.put(err)
return v
}
// Int64Array returns []int64 value and stores an error.
func (d *Drain) Int64Array(ps ProxySet) []int64 {
v, err := ps.Int64Array()
d.put(err)
return v
}
// Float64Array returns []float64 value and stores an error.
func (d *Drain) Float64Array(ps ProxySet) []float64 {
v, err := ps.Float64Array()
d.put(err)
return v
}
// StringArray returns []string value and stores an error.
func (d *Drain) StringArray(ps ProxySet) []string {
v, err := ps.StringArray()
d.put(err)
return v
}
// ArrayArray returns [][]interface{} value and stores an error.
func (d *Drain) ArrayArray(ps ProxySet) [][]interface{} {
v, err := ps.ArrayArray()
d.put(err)
return v
}
// MapArray returns []map[string]interface{} value and stores an error.
func (d *Drain) MapArray(ps ProxySet) []map[string]interface{} {
v, err := ps.MapArray()
d.put(err)
return v
}
// ProxyArray returns []Proxy value and stores an error.
func (d *Drain) ProxyArray(ps ProxySet) []Proxy {
v, err := ps.ProxyArray()
d.put(err)
return v
}
type drainError []error
func (derr drainError) Error() string {
b := bytes.Buffer{}
for i, err := range derr {
if i > 0 {
_, _ = b.WriteString("; ")
}
_, _ = b.WriteString(err.Error())
}
return b.String()
}

View File

@ -1,253 +0,0 @@
package dproxy
import (
"fmt"
"strconv"
)
// ErrorType is type of errors
type ErrorType int
const (
// Etype means expected type is not matched with actual.
Etype ErrorType = iota + 1
// Enotfound means key or index doesn't exist.
Enotfound
// EmapNorArray means target is not a map nor an array (for JSON Pointer)
EmapNorArray
// EconvertFailure means value conversion is failed.
EconvertFailure
// EinvalidIndex means token is invalid as index (for JSON Pointer)
EinvalidIndex
// EinvalidQuery means query is invalid as JSON Pointer.
EinvalidQuery
// ErequiredType means the type mismatch against user required one.
// For example M() requires map, A() requires array.
ErequiredType
)
func (et ErrorType) String() string {
switch et {
case Etype:
return "Etype"
case Enotfound:
return "Enotfound"
case EmapNorArray:
return "EmapNorArray"
case EconvertFailure:
return "EconvertFailure"
case EinvalidIndex:
return "EinvalidIndex"
case EinvalidQuery:
return "EinvalidQuery"
case ErequiredType:
return "ErequiredType"
default:
return "Eunknown"
}
}
// Error get detail information of the errror.
type Error interface {
// ErrorType returns type of error.
ErrorType() ErrorType
// FullAddress returns query string where cause first error.
FullAddress() string
}
type errorProxy struct {
errorType ErrorType
parent frame
label string
expected Type
actual Type
infoStr string
}
// errorProxy implements error, Proxy and ProxySet.
var (
_ error = (*errorProxy)(nil)
_ Proxy = (*errorProxy)(nil)
_ ProxySet = (*errorProxy)(nil)
)
func (p *errorProxy) Nil() bool {
return false
}
func (p *errorProxy) Value() (interface{}, error) {
return nil, p
}
func (p *errorProxy) Bool() (bool, error) {
return false, p
}
func (p *errorProxy) Int64() (int64, error) {
return 0, p
}
func (p *errorProxy) Float64() (float64, error) {
return 0, p
}
func (p *errorProxy) String() (string, error) {
return "", p
}
func (p *errorProxy) Array() ([]interface{}, error) {
return nil, p
}
func (p *errorProxy) Map() (map[string]interface{}, error) {
return nil, p
}
func (p *errorProxy) A(n int) Proxy {
return p
}
func (p *errorProxy) M(k string) Proxy {
return p
}
func (p *errorProxy) P(q string) Proxy {
return p
}
func (p *errorProxy) Empty() bool {
return true
}
func (p *errorProxy) Len() int {
return 0
}
func (p *errorProxy) BoolArray() ([]bool, error) {
return nil, p
}
func (p *errorProxy) Int64Array() ([]int64, error) {
return nil, p
}
func (p *errorProxy) Float64Array() ([]float64, error) {
return nil, p
}
func (p *errorProxy) StringArray() ([]string, error) {
return nil, p
}
func (p *errorProxy) ArrayArray() ([][]interface{}, error) {
return nil, p
}
func (p *errorProxy) MapArray() ([]map[string]interface{}, error) {
return nil, p
}
func (p *errorProxy) ProxyArray() ([]Proxy, error) {
return nil, p
}
func (p *errorProxy) ProxySet() ProxySet {
return p
}
func (p *errorProxy) Q(k string) ProxySet {
return p
}
func (p *errorProxy) Qc(k string) ProxySet {
return p
}
func (p *errorProxy) findJPT(t string) Proxy {
return p
}
func (p *errorProxy) parentFrame() frame {
return p.parent
}
func (p *errorProxy) frameLabel() string {
return p.label
}
func (p *errorProxy) Error() string {
switch p.errorType {
case Etype:
return fmt.Sprintf("not matched types: expected=%s actual=%s: %s",
p.expected.String(), p.actual.String(), p.FullAddress())
case Enotfound:
return fmt.Sprintf("not found: %s", p.FullAddress())
case EmapNorArray:
// FIXME: better error message.
return fmt.Sprintf("not map nor array: actual=%s: %s",
p.actual.String(), p.FullAddress())
case EconvertFailure:
return fmt.Sprintf("convert error: %s: %s", p.infoStr, p.FullAddress())
case EinvalidIndex:
// FIXME: better error message.
return fmt.Sprintf("invalid index: %s: %s", p.infoStr, p.FullAddress())
case EinvalidQuery:
// FIXME: better error message.
return fmt.Sprintf("invalid query: %s: %s", p.infoStr, p.FullAddress())
case ErequiredType:
return fmt.Sprintf("not required types: required=%s actual=%s: %s",
p.expected.String(), p.actual.String(), p.FullAddress())
default:
return fmt.Sprintf("unexpected: %s", p.FullAddress())
}
}
func (p *errorProxy) ErrorType() ErrorType {
return p.errorType
}
func (p *errorProxy) FullAddress() string {
return fullAddress(p)
}
func typeError(p frame, expected Type, actual interface{}) *errorProxy {
return &errorProxy{
errorType: Etype,
parent: p,
expected: expected,
actual: detectType(actual),
}
}
func requiredTypeError(p frame, expected Type, actual interface{}) *errorProxy {
return &errorProxy{
errorType: ErequiredType,
parent: p,
expected: expected,
actual: detectType(actual),
}
}
func elementTypeError(p frame, index int, expected Type, actual interface{}) *errorProxy {
q := &simpleFrame{
parent: p,
label: "[" + strconv.Itoa(index) + "]",
}
return typeError(q, expected, actual)
}
func notfoundError(p frame, address string) *errorProxy {
return &errorProxy{
errorType: Enotfound,
parent: p,
label: address,
}
}

View File

@ -1,42 +0,0 @@
package dproxy
type frame interface {
// parentFrame returns parent frame.
parentFrame() frame
// frameLabel return label of frame.
frameLabel() string
}
func fullAddress(f frame) string {
x := 0
for g := f; g != nil; g = g.parentFrame() {
x += len(g.frameLabel())
}
if x == 0 {
return "(root)"
}
b := make([]byte, x)
for g := f; g != nil; g = g.parentFrame() {
x -= len(g.frameLabel())
copy(b[x:], g.frameLabel())
}
if b[0] == '.' {
return string(b[1:])
}
return string(b)
}
type simpleFrame struct {
parent frame
label string
}
var _ frame = (*simpleFrame)(nil)
func (f *simpleFrame) parentFrame() frame {
return f.parent
}
func (f *simpleFrame) frameLabel() string {
return f.label
}

View File

@ -1,3 +0,0 @@
module github.com/koron/go-dproxy
go 1.13

View File

View File

@ -1,31 +0,0 @@
package dproxy
import "strings"
var jptR = strings.NewReplacer("~1", "/", "~0", "~")
func unescapeJPT(t string) string {
return jptR.Replace(t)
}
func pointer(p Proxy, q string) Proxy {
if len(q) == 0 {
return p
}
if q[0] != '/' {
return &errorProxy{
errorType: EinvalidQuery,
parent: p,
infoStr: "not start with '/'",
}
}
for _, t := range strings.Split(q[1:], "/") {
p = p.findJPT(unescapeJPT(t))
}
return p
}
// Pointer returns a Proxy which pointed by JSON Pointer's query q
func Pointer(v interface{}, q string) Proxy {
return pointer(New(v), q)
}

View File

@ -1,102 +0,0 @@
package dproxy
// Proxy is a proxy to access a document (interface{}).
type Proxy interface {
// Nil returns true, if target value is nil.
Nil() bool
// Value returns a proxied value. If there are no values, it returns
// error.
Value() (interface{}, error)
// Bool returns its value. If value isn't the type, it returns error.
Bool() (bool, error)
// Int64 returns its value. If value isn't the type, it returns error.
Int64() (int64, error)
// Float64 returns its value. If value isn't the type, it returns error.
Float64() (float64, error)
// String returns its value. If value isn't the type, it returns error.
String() (string, error)
// Array returns its value. If value isn't the type, it returns error.
Array() ([]interface{}, error)
// Map returns its value. If value isn't the type, it returns error.
Map() (map[string]interface{}, error)
// A returns an item from value treated as the array.
A(n int) Proxy
// M returns an item from value treated as the map.
M(k string) Proxy
// P returns which pointed by JSON Pointer's query q.
P(q string) Proxy
// ProxySet returns a set which converted from its array value.
ProxySet() ProxySet
// Q returns set of all items which property matchs with k.
Q(k string) ProxySet
// findJPT returns a match of JSON Pointer's Token t.
findJPT(t string) Proxy
// Proxy implements frame.
frame
}
// ProxySet proxies to access to set.
type ProxySet interface {
// Empty returns true when the set is empty.
Empty() bool
// Len returns count of items in the set.
Len() int
// BoolArray returns []bool which converterd from the set.
BoolArray() ([]bool, error)
// Int64Array returns []int64 which converterd from the set.
Int64Array() ([]int64, error)
// Float64Array returns []float64 which converterd from the set.
Float64Array() ([]float64, error)
// StringArray returns []string which converterd from the set.
StringArray() ([]string, error)
// ArrayArray returns [][]interface{} which converterd from the set.
ArrayArray() ([][]interface{}, error)
// MapArray returns []map[string]interface{} which converterd from the set.
MapArray() ([]map[string]interface{}, error)
// ProxyArray returns []Proxy which wrap each items.
ProxyArray() ([]Proxy, error)
// A returns an proxy for index in the set.
A(n int) Proxy
// Q returns set of all items which property matchs with k.
Q(k string) ProxySet
// Qc returns set of property of all items.
Qc(k string) ProxySet
// Proxy implements frame.
frame
}
// New creates a new Proxy instance for v.
func New(v interface{}) Proxy {
return &valueProxy{value: v}
}
// NewSet create a new ProxySet instance for v.
func NewSet(v []interface{}) ProxySet {
return &setProxy{values: v}
}

View File

@ -1,193 +0,0 @@
package dproxy
import "strconv"
type setProxy struct {
values []interface{}
parent frame
label string
}
// setProxy implements ProxySet
var _ ProxySet = (*setProxy)(nil)
func (p *setProxy) Empty() bool {
return p.Len() == 0
}
func (p *setProxy) Len() int {
return len(p.values)
}
func (p *setProxy) BoolArray() ([]bool, error) {
r := make([]bool, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case bool:
r[i] = v
default:
return nil, elementTypeError(p, i, Tbool, v)
}
}
return r, nil
}
func (p *setProxy) Int64Array() ([]int64, error) {
r := make([]int64, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case int:
r[i] = int64(v)
case int32:
r[i] = int64(v)
case int64:
r[i] = v
case float32:
r[i] = int64(v)
case float64:
r[i] = int64(v)
default:
return nil, elementTypeError(p, i, Tint64, v)
}
}
return r, nil
}
func (p *setProxy) Float64Array() ([]float64, error) {
r := make([]float64, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case int:
r[i] = float64(v)
case int32:
r[i] = float64(v)
case int64:
r[i] = float64(v)
case float32:
r[i] = float64(v)
case float64:
r[i] = v
default:
return nil, elementTypeError(p, i, Tfloat64, v)
}
}
return r, nil
}
func (p *setProxy) StringArray() ([]string, error) {
r := make([]string, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case string:
r[i] = v
default:
return nil, elementTypeError(p, i, Tstring, v)
}
}
return r, nil
}
func (p *setProxy) ArrayArray() ([][]interface{}, error) {
r := make([][]interface{}, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case []interface{}:
r[i] = v
default:
return nil, elementTypeError(p, i, Tarray, v)
}
}
return r, nil
}
func (p *setProxy) MapArray() ([]map[string]interface{}, error) {
r := make([]map[string]interface{}, len(p.values))
for i, v := range p.values {
switch v := v.(type) {
case map[string]interface{}:
r[i] = v
default:
return nil, elementTypeError(p, i, Tmap, v)
}
}
return r, nil
}
func (p *setProxy) ProxyArray() ([]Proxy, error) {
r := make([]Proxy, 0, len(p.values))
for i, v := range p.values {
r = append(r, &valueProxy{
value: v,
parent: p,
label: "[" + strconv.Itoa(i) + "]",
})
}
return r, nil
}
func (p *setProxy) A(n int) Proxy {
a := "[" + strconv.Itoa(n) + "]"
if n < 0 || n >= len(p.values) {
return notfoundError(p, a)
}
return &valueProxy{
value: p.values[n],
parent: p,
label: a,
}
}
func (p *setProxy) Q(k string) ProxySet {
w := findAll(p.values, k)
return &setProxy{
values: w,
parent: p,
label: ".." + k,
}
}
func (p *setProxy) Qc(k string) ProxySet {
r := make([]interface{}, 0, len(p.values))
for _, v := range p.values {
switch v := v.(type) {
case map[string]interface{}:
if w, ok := v[k]; ok {
r = append(r, w)
}
}
}
return &setProxy{
values: r,
parent: p,
label: ".." + k,
}
}
func (p *setProxy) parentFrame() frame {
return p.parent
}
func (p *setProxy) frameLabel() string {
return p.label
}
func findAll(v interface{}, k string) []interface{} {
return findAllImpl(v, k, make([]interface{}, 0, 10))
}
func findAllImpl(v interface{}, k string, r []interface{}) []interface{} {
switch v := v.(type) {
case map[string]interface{}:
for n, w := range v {
if n == k {
r = append(r, w)
}
r = findAllImpl(w, k, r)
}
case []interface{}:
for _, w := range v {
r = findAllImpl(w, k, r)
}
}
return r
}

View File

@ -1,76 +0,0 @@
package dproxy
// Type is type of value.
type Type int
const (
// Tunknown shows value is not supported.
Tunknown Type = iota
// Tnil shows value is nil.
Tnil
// Tbool shows value is bool.
Tbool
// Tint64 shows value is int64.
Tint64
// Tfloat64 shows value is float64.
Tfloat64
// Tstring shows value is string.
Tstring
// Tarray shows value is an array ([]interface{})
Tarray
// Tmap shows value is a map (map[string]interface{})
Tmap
)
// detectType returns type of a value.
func detectType(v interface{}) Type {
if v == nil {
return Tnil
}
switch v.(type) {
case bool:
return Tbool
case int, int32, int64:
return Tint64
case float32, float64:
return Tfloat64
case string:
return Tstring
case []interface{}:
return Tarray
case map[string]interface{}:
return Tmap
default:
return Tunknown
}
}
func (t Type) String() string {
switch t {
case Tunknown:
return "unknown"
case Tnil:
return "nil"
case Tbool:
return "bool"
case Tint64:
return "int64"
case Tfloat64:
return "float64"
case Tstring:
return "string"
case Tarray:
return "array"
case Tmap:
return "map"
default:
return "unknown"
}
}

View File

@ -1,222 +0,0 @@
package dproxy
import (
"reflect"
"strconv"
)
type valueProxy struct {
value interface{}
parent frame
label string
}
// valueProxy implements Proxy.
var _ Proxy = (*valueProxy)(nil)
func (p *valueProxy) Nil() bool {
return p.value == nil
}
func (p *valueProxy) Value() (interface{}, error) {
return p.value, nil
}
func (p *valueProxy) Bool() (bool, error) {
switch v := p.value.(type) {
case bool:
return v, nil
default:
return false, typeError(p, Tbool, v)
}
}
type int64er interface {
Int64() (int64, error)
}
func (p *valueProxy) Int64() (int64, error) {
switch v := p.value.(type) {
case int:
return int64(v), nil
case int32:
return int64(v), nil
case int64:
return v, nil
case float32:
return int64(v), nil
case float64:
return int64(v), nil
case int64er:
w, err := v.Int64()
if err != nil {
return 0, &errorProxy{
errorType: EconvertFailure,
parent: p,
infoStr: err.Error(),
}
}
return w, nil
default:
return 0, typeError(p, Tint64, v)
}
}
type float64er interface {
Float64() (float64, error)
}
func (p *valueProxy) Float64() (float64, error) {
switch v := p.value.(type) {
case int:
return float64(v), nil
case int32:
return float64(v), nil
case int64:
return float64(v), nil
case float32:
return float64(v), nil
case float64:
return v, nil
case float64er:
w, err := v.Float64()
if err != nil {
return 0, &errorProxy{
errorType: EconvertFailure,
parent: p,
infoStr: err.Error(),
}
}
return w, nil
default:
return 0, typeError(p, Tfloat64, v)
}
}
func (p *valueProxy) String() (string, error) {
switch v := p.value.(type) {
case string:
return v, nil
default:
return "", typeError(p, Tstring, v)
}
}
func (p *valueProxy) Array() ([]interface{}, error) {
switch v := p.value.(type) {
case []interface{}:
return v, nil
default:
return nil, typeError(p, Tarray, v)
}
}
func (p *valueProxy) Map() (map[string]interface{}, error) {
switch v := p.value.(type) {
case map[string]interface{}:
return v, nil
default:
return nil, typeError(p, Tmap, v)
}
}
func (p *valueProxy) A(n int) Proxy {
switch v := p.value.(type) {
case []interface{}:
a := "[" + strconv.Itoa(n) + "]"
if n < 0 || n >= len(v) {
return notfoundError(p, a)
}
return &valueProxy{
value: v[n],
parent: p,
label: a,
}
default:
return requiredTypeError(p, Tarray, v)
}
}
var mapType = reflect.TypeOf(map[string]interface{}(nil))
func (p *valueProxy) m(v map[string]interface{}, k string) Proxy {
a := "." + k
w, ok := v[k]
if !ok {
return notfoundError(p, a)
}
return &valueProxy{
value: w,
parent: p,
label: a,
}
}
func (p *valueProxy) M(k string) Proxy {
if v, ok := p.value.(map[string]interface{}); ok {
return p.m(v, k)
}
if rv := reflect.ValueOf(p.value); rv.IsValid() && rv.Type().ConvertibleTo(mapType) {
v, _ := rv.Convert(mapType).Interface().(map[string]interface{})
return p.m(v, k)
}
return requiredTypeError(p, Tmap, p.value)
}
func (p *valueProxy) P(q string) Proxy {
return pointer(p, q)
}
func (p *valueProxy) ProxySet() ProxySet {
switch v := p.value.(type) {
case []interface{}:
return &setProxy{
values: v,
parent: p,
}
default:
return typeError(p, Tarray, v)
}
}
func (p *valueProxy) Q(k string) ProxySet {
w := findAll(p.value, k)
return &setProxy{
values: w,
parent: p,
label: ".." + k,
}
}
func (p *valueProxy) findJPT(t string) Proxy {
switch v := p.value.(type) {
case map[string]interface{}:
return p.M(t)
case []interface{}:
n, err := strconv.ParseUint(t, 10, 0)
if err != nil {
return &errorProxy{
errorType: EinvalidIndex,
parent: p,
infoStr: err.Error(),
}
}
return p.A(int(n))
default:
return &errorProxy{
errorType: EmapNorArray,
parent: p,
actual: detectType(v),
}
}
}
func (p *valueProxy) parentFrame() frame {
return p.parent
}
func (p *valueProxy) frameLabel() string {
return p.label
}

3
vendor/modules.txt vendored
View File

@ -63,9 +63,6 @@ github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/client/
github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/client/clientset/versioned/typed/k8s.cni.cncf.io/v1 github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/client/clientset/versioned/typed/k8s.cni.cncf.io/v1
github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/client/clientset/versioned/typed/k8s.cni.cncf.io/v1/fake github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/client/clientset/versioned/typed/k8s.cni.cncf.io/v1/fake
github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/utils github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/utils
# github.com/koron/go-dproxy v1.3.0
## explicit
github.com/koron/go-dproxy
# github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 # github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369
github.com/matttproud/golang_protobuf_extensions/pbutil github.com/matttproud/golang_protobuf_extensions/pbutil
# github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd