52
go.mod
52
go.mod
@@ -60,12 +60,15 @@ require (
|
||||
github.com/kelseyhightower/envconfig v1.4.0 // indirect
|
||||
github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0
|
||||
github.com/kubesphere/sonargo v0.0.2
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.4 // indirect
|
||||
github.com/mitchellh/mapstructure v1.2.2
|
||||
github.com/onsi/ginkgo v1.16.4
|
||||
github.com/onsi/gomega v1.14.0
|
||||
github.com/onsi/gomega v1.15.0
|
||||
github.com/open-policy-agent/opa v0.18.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/operator-framework/helm-operator-plugins v0.0.8-0.20210810182245-240cc447b3de
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/projectcalico/kube-controllers v3.8.8+incompatible
|
||||
@@ -95,11 +98,11 @@ require (
|
||||
gopkg.in/square/go-jose.v1 v1.1.2 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.4.0
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0 // indirect
|
||||
gopkg.in/src-d/go-git.v4 v4.11.0
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
gotest.tools v2.2.0+incompatible
|
||||
helm.sh/helm/v3 v3.5.0
|
||||
helm.sh/helm/v3 v3.6.3
|
||||
istio.io/api v0.0.0-20201113182140-d4b7e3fc2b44
|
||||
istio.io/client-go v0.0.0-20201113183938-0734e976e785
|
||||
istio.io/gogo-genproto v0.0.0-20201113182723-5b8563d8a012 // indirect
|
||||
@@ -113,7 +116,7 @@ require (
|
||||
k8s.io/component-base v0.21.2
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/klog/v2 v2.8.0
|
||||
k8s.io/kube-openapi v0.0.0-20210527164424-3c818078ee3d
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e
|
||||
k8s.io/kubectl v0.21.2
|
||||
k8s.io/metrics v0.21.2
|
||||
k8s.io/utils v0.0.0-20210527160623-6fdb442a123b
|
||||
@@ -130,6 +133,7 @@ require (
|
||||
)
|
||||
|
||||
replace (
|
||||
bitbucket.org/liamstask/goose => bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c
|
||||
cloud.google.com/go => cloud.google.com/go v0.56.0
|
||||
cloud.google.com/go/bigquery => cloud.google.com/go/bigquery v1.4.0
|
||||
cloud.google.com/go/bigtable => cloud.google.com/go/bigtable v1.2.0
|
||||
@@ -153,6 +157,8 @@ replace (
|
||||
github.com/BurntSushi/toml => github.com/BurntSushi/toml v0.3.1
|
||||
github.com/DATA-DOG/go-sqlmock => github.com/DATA-DOG/go-sqlmock v1.3.3
|
||||
github.com/DataDog/datadog-go => github.com/DataDog/datadog-go v3.2.0+incompatible
|
||||
github.com/GeertJohan/go.incremental => github.com/GeertJohan/go.incremental v1.0.0
|
||||
github.com/GeertJohan/go.rice => github.com/GeertJohan/go.rice v1.0.0
|
||||
github.com/Knetic/govaluate => github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
|
||||
github.com/MakeNowJust/heredoc => github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e
|
||||
github.com/Masterminds/goutils => github.com/Masterminds/goutils v1.1.0
|
||||
@@ -175,6 +181,7 @@ replace (
|
||||
github.com/afex/hystrix-go => github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
|
||||
github.com/agnivade/levenshtein => github.com/agnivade/levenshtein v1.0.1
|
||||
github.com/ajstarks/svgo => github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af
|
||||
github.com/akavel/rsrc => github.com/akavel/rsrc v0.8.0
|
||||
github.com/alcortesm/tgz => github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7
|
||||
github.com/alecthomas/template => github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/alecthomas/units => github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
|
||||
@@ -202,6 +209,7 @@ replace (
|
||||
github.com/bgentry/speakeasy => github.com/bgentry/speakeasy v0.1.0
|
||||
github.com/bitly/go-hostpool => github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932
|
||||
github.com/blang/semver => github.com/blang/semver v3.5.0+incompatible
|
||||
github.com/blang/semver/v4 => github.com/blang/semver/v4 v4.0.0
|
||||
github.com/bmizerany/assert => github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869
|
||||
github.com/bmizerany/pat => github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40
|
||||
github.com/boltdb/bolt => github.com/boltdb/bolt v1.3.1
|
||||
@@ -215,6 +223,7 @@ replace (
|
||||
github.com/casbin/casbin/v2 => github.com/casbin/casbin/v2 v2.1.2
|
||||
github.com/cenkalti/backoff => github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/census-instrumentation/opencensus-proto => github.com/census-instrumentation/opencensus-proto v0.2.1
|
||||
github.com/certifi/gocertifi => github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261
|
||||
github.com/cespare/xxhash => github.com/cespare/xxhash v1.1.0
|
||||
github.com/cespare/xxhash/v2 => github.com/cespare/xxhash/v2 v2.1.1
|
||||
github.com/chai2010/gettext-go => github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5
|
||||
@@ -226,6 +235,10 @@ replace (
|
||||
github.com/circonus-labs/circonus-gometrics => github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible
|
||||
github.com/circonus-labs/circonusllhist => github.com/circonus-labs/circonusllhist v0.1.3
|
||||
github.com/clbanning/x2j => github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec
|
||||
github.com/cloudflare/backoff => github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a
|
||||
github.com/cloudflare/cfssl => github.com/cloudflare/cfssl v1.5.0
|
||||
github.com/cloudflare/go-metrics => github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41
|
||||
github.com/cloudflare/redoctober => github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c
|
||||
github.com/cockroachdb/apd => github.com/cockroachdb/apd v1.1.0
|
||||
github.com/cockroachdb/cockroach-go => github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c
|
||||
github.com/cockroachdb/datadriven => github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa
|
||||
@@ -254,6 +267,7 @@ replace (
|
||||
github.com/cznic/sortutil => github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65
|
||||
github.com/cznic/strutil => github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186
|
||||
github.com/cznic/zappy => github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc
|
||||
github.com/daaku/go.zipexe => github.com/daaku/go.zipexe v1.0.0
|
||||
github.com/dave/jennifer => github.com/dave/jennifer v1.2.0
|
||||
github.com/davecgh/go-spew => github.com/davecgh/go-spew v1.1.1
|
||||
github.com/daviddengcn/go-colortext => github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd
|
||||
@@ -311,10 +325,12 @@ replace (
|
||||
github.com/fsouza/fake-gcs-server => github.com/fsouza/fake-gcs-server v1.7.0
|
||||
github.com/fvbommel/sortorder => github.com/fvbommel/sortorder v1.0.1
|
||||
github.com/garyburd/redigo => github.com/garyburd/redigo v1.6.0
|
||||
github.com/getsentry/raven-go => github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7
|
||||
github.com/ghodss/yaml => github.com/ghodss/yaml v1.0.0
|
||||
github.com/gliderlabs/ssh => github.com/gliderlabs/ssh v0.1.1
|
||||
github.com/glycerine/go-unsnap-stream => github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd
|
||||
github.com/glycerine/goconvey => github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31
|
||||
github.com/go-bindata/go-bindata/v3 => github.com/go-bindata/go-bindata/v3 v3.1.3
|
||||
github.com/go-errors/errors => github.com/go-errors/errors v1.0.1
|
||||
github.com/go-kit/kit => github.com/go-kit/kit v0.10.0
|
||||
github.com/go-ldap/ldap => github.com/go-ldap/ldap v3.0.3+incompatible
|
||||
@@ -377,6 +393,7 @@ replace (
|
||||
github.com/gomodule/redigo => github.com/gomodule/redigo v2.0.0+incompatible
|
||||
github.com/google/addlicense => github.com/google/addlicense v0.0.0-20200906110928-a0294312aa76
|
||||
github.com/google/btree => github.com/google/btree v1.0.0
|
||||
github.com/google/certificate-transparency-go => github.com/google/certificate-transparency-go v1.0.21
|
||||
github.com/google/flatbuffers => github.com/google/flatbuffers v1.11.0
|
||||
github.com/google/go-cmp => github.com/google/go-cmp v0.4.0
|
||||
github.com/google/go-containerregistry => github.com/google/go-containerregistry v0.6.0
|
||||
@@ -426,6 +443,7 @@ replace (
|
||||
github.com/hodgesds/perf-utils => github.com/hodgesds/perf-utils v0.0.8
|
||||
github.com/huandu/xstrings => github.com/huandu/xstrings v1.2.0
|
||||
github.com/hudl/fargo => github.com/hudl/fargo v1.3.0
|
||||
github.com/iancoleman/strcase => github.com/iancoleman/strcase v0.1.2
|
||||
github.com/ianlancetaylor/demangle => github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6
|
||||
github.com/imdario/mergo => github.com/imdario/mergo v0.3.9
|
||||
github.com/inconshreveable/mousetrap => github.com/inconshreveable/mousetrap v1.0.0
|
||||
@@ -443,7 +461,9 @@ replace (
|
||||
github.com/jbenet/go-context => github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
|
||||
github.com/jessevdk/go-flags => github.com/jessevdk/go-flags v1.4.0
|
||||
github.com/jmespath/go-jmespath => github.com/jmespath/go-jmespath v0.3.0
|
||||
github.com/jmhodges/clock => github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548
|
||||
github.com/jmoiron/sqlx => github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/joelanford/go-apidiff => github.com/joelanford/go-apidiff v0.1.0
|
||||
github.com/joeshaw/multierror => github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901
|
||||
github.com/joho/godotenv => github.com/joho/godotenv v1.3.0
|
||||
github.com/jonboulle/clockwork => github.com/jonboulle/clockwork v0.1.0
|
||||
@@ -463,6 +483,8 @@ replace (
|
||||
github.com/kevinburke/ssh_config => github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e
|
||||
github.com/kisielk/errcheck => github.com/kisielk/errcheck v1.2.0
|
||||
github.com/kisielk/gotool => github.com/kisielk/gotool v1.0.0
|
||||
github.com/kisielk/sqlstruct => github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49
|
||||
github.com/kisom/goutils => github.com/kisom/goutils v1.1.0
|
||||
github.com/klauspost/compress => github.com/klauspost/compress v1.9.5
|
||||
github.com/klauspost/cpuid => github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5
|
||||
github.com/klauspost/crc32 => github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6
|
||||
@@ -475,7 +497,10 @@ replace (
|
||||
github.com/kshvakov/clickhouse => github.com/kshvakov/clickhouse v1.3.5
|
||||
github.com/kubernetes-csi/external-snapshotter/client/v3 => github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0
|
||||
github.com/kubesphere/sonargo => github.com/kubesphere/sonargo v0.0.2
|
||||
github.com/kylelemons/go-gypsy => github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28
|
||||
github.com/kylelemons/godebug => github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb
|
||||
github.com/lann/builder => github.com/lann/builder v0.0.0-20180802200727-47ae307949d0
|
||||
github.com/lann/ps => github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0
|
||||
github.com/leanovate/gopter => github.com/leanovate/gopter v0.2.4
|
||||
github.com/leodido/go-urn => github.com/leodido/go-urn v0.0.0-20181204092800-a67a23e1c1af
|
||||
github.com/lib/pq => github.com/lib/pq v1.2.0
|
||||
@@ -505,6 +530,8 @@ replace (
|
||||
github.com/mdlayher/wifi => github.com/mdlayher/wifi v0.0.0-20190303161829-b1436901ddee
|
||||
github.com/mgutz/ansi => github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
|
||||
github.com/miekg/dns => github.com/miekg/dns v1.1.29
|
||||
github.com/mikefarah/yaml/v2 => github.com/mikefarah/yaml/v2 v2.4.0
|
||||
github.com/mikefarah/yq/v2 => github.com/mikefarah/yq/v2 v2.4.1
|
||||
github.com/minio/md5-simd => github.com/minio/md5-simd v1.1.0
|
||||
github.com/minio/minio-go/v7 => github.com/minio/minio-go/v7 v7.0.2
|
||||
github.com/minio/sha256-simd => github.com/minio/sha256-simd v0.1.1
|
||||
@@ -526,6 +553,7 @@ replace (
|
||||
github.com/morikuni/aec => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c
|
||||
github.com/mozillazg/go-cos => github.com/mozillazg/go-cos v0.13.0
|
||||
github.com/mozillazg/go-httpheader => github.com/mozillazg/go-httpheader v0.2.1
|
||||
github.com/mreiferson/go-httpclient => github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474
|
||||
github.com/mschoch/smat => github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae
|
||||
github.com/munnerz/goautoneg => github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
||||
github.com/mwitkow/go-conntrack => github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f
|
||||
@@ -538,6 +566,7 @@ replace (
|
||||
github.com/nats-io/nuid => github.com/nats-io/nuid v1.0.1
|
||||
github.com/ncw/swift => github.com/ncw/swift v1.0.50
|
||||
github.com/niemeyer/pretty => github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e
|
||||
github.com/nkovacs/streamquote => github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229
|
||||
github.com/nxadm/tail => github.com/nxadm/tail v1.4.4
|
||||
github.com/oklog/oklog => github.com/oklog/oklog v0.3.2
|
||||
github.com/oklog/run => github.com/oklog/run v1.1.0
|
||||
@@ -557,6 +586,9 @@ replace (
|
||||
github.com/opentracing/opentracing-go => github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing => github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5
|
||||
github.com/openzipkin/zipkin-go => github.com/openzipkin/zipkin-go v0.2.2
|
||||
github.com/operator-framework/api => github.com/operator-framework/api v0.4.0
|
||||
github.com/operator-framework/helm-operator-plugins => github.com/operator-framework/helm-operator-plugins v0.0.8-0.20210810182245-240cc447b3de
|
||||
github.com/operator-framework/operator-lib => github.com/operator-framework/operator-lib v0.3.0
|
||||
github.com/pact-foundation/pact-go => github.com/pact-foundation/pact-go v1.0.4
|
||||
github.com/pascaldekloe/goe => github.com/pascaldekloe/goe v0.1.0
|
||||
github.com/patrickmn/go-cache => github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
@@ -643,9 +675,12 @@ replace (
|
||||
github.com/uber/jaeger-lib => github.com/uber/jaeger-lib v2.2.0+incompatible
|
||||
github.com/ugorji/go => github.com/ugorji/go v1.1.4
|
||||
github.com/urfave/cli => github.com/urfave/cli v1.20.0
|
||||
github.com/valyala/bytebufferpool => github.com/valyala/bytebufferpool v1.0.0
|
||||
github.com/valyala/fasttemplate => github.com/valyala/fasttemplate v1.0.1
|
||||
github.com/vektah/gqlparser => github.com/vektah/gqlparser v1.1.2
|
||||
github.com/weaveworks/common => github.com/weaveworks/common v0.0.0-20200820123129-280614068c5e
|
||||
github.com/weaveworks/promrus => github.com/weaveworks/promrus v1.2.0
|
||||
github.com/weppos/publicsuffix-go => github.com/weppos/publicsuffix-go v0.13.0
|
||||
github.com/willf/bitset => github.com/willf/bitset v1.1.3
|
||||
github.com/xanzy/go-gitlab => github.com/xanzy/go-gitlab v0.15.0
|
||||
github.com/xanzy/ssh-agent => github.com/xanzy/ssh-agent v0.2.1
|
||||
@@ -663,6 +698,10 @@ replace (
|
||||
github.com/yvasiyarov/gorelic => github.com/yvasiyarov/gorelic v0.0.6
|
||||
github.com/yvasiyarov/newrelic_platform_go => github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f
|
||||
github.com/ziutek/mymysql => github.com/ziutek/mymysql v1.5.4
|
||||
github.com/zmap/rc2 => github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521
|
||||
github.com/zmap/zcertificate => github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4
|
||||
github.com/zmap/zcrypto => github.com/zmap/zcrypto v0.0.0-20200911161511-43ff0ea04f21
|
||||
github.com/zmap/zlint/v2 => github.com/zmap/zlint/v2 v2.2.1
|
||||
gitlab.com/nyarla/go-crypt => gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b
|
||||
go.elastic.co/apm => go.elastic.co/apm v1.5.0
|
||||
go.elastic.co/apm/module/apmhttp => go.elastic.co/apm/module/apmhttp v1.5.0
|
||||
@@ -716,9 +755,11 @@ replace (
|
||||
gopkg.in/go-playground/assert.v1 => gopkg.in/go-playground/assert.v1 v1.2.1
|
||||
gopkg.in/go-playground/validator.v9 => gopkg.in/go-playground/validator.v9 v9.27.0
|
||||
gopkg.in/gorp.v1 => gopkg.in/gorp.v1 v1.7.2
|
||||
gopkg.in/imdario/mergo.v0 => gopkg.in/imdario/mergo.v0 v0.3.7
|
||||
gopkg.in/inf.v0 => gopkg.in/inf.v0 v0.9.1
|
||||
gopkg.in/ini.v1 => gopkg.in/ini.v1 v1.57.0
|
||||
gopkg.in/natefinch/lumberjack.v2 => gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
gopkg.in/op/go-logging.v1 => gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||
gopkg.in/square/go-jose.v1 => gopkg.in/square/go-jose.v1 v1.1.2
|
||||
gopkg.in/square/go-jose.v2 => gopkg.in/square/go-jose.v2 v2.4.0
|
||||
gopkg.in/src-d/go-billy.v4 => gopkg.in/src-d/go-billy.v4 v4.3.0
|
||||
@@ -731,7 +772,7 @@ replace (
|
||||
gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
gotest.tools => gotest.tools v2.2.0+incompatible
|
||||
gotest.tools/v3 => gotest.tools/v3 v3.0.3
|
||||
helm.sh/helm/v3 => helm.sh/helm/v3 v3.5.0
|
||||
helm.sh/helm/v3 => helm.sh/helm/v3 v3.6.3
|
||||
honnef.co/go/tools => honnef.co/go/tools v0.0.1-2020.1.3
|
||||
howett.net/plist => howett.net/plist v0.0.0-20181124034731-591f970eefbb
|
||||
istio.io/api => istio.io/api v0.0.0-20201113182140-d4b7e3fc2b44
|
||||
@@ -767,6 +808,7 @@ replace (
|
||||
sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.9.3
|
||||
sigs.k8s.io/controller-tools => sigs.k8s.io/controller-tools v0.6.2
|
||||
sigs.k8s.io/kind => sigs.k8s.io/kind v0.8.1
|
||||
sigs.k8s.io/kubebuilder/v3 => sigs.k8s.io/kubebuilder/v3 v3.0.0-alpha.0.0.20210716121009-fde793f20067
|
||||
sigs.k8s.io/kubefed => sigs.k8s.io/kubefed v0.8.1
|
||||
sigs.k8s.io/kustomize/api => sigs.k8s.io/kustomize/api v0.8.8
|
||||
sigs.k8s.io/kustomize/cmd/config => sigs.k8s.io/kustomize/cmd/config v0.9.10
|
||||
|
||||
69
go.sum
69
go.sum
@@ -1,3 +1,4 @@
|
||||
bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
|
||||
@@ -22,15 +23,21 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm7f2FFYv7sjY7NPFi3cPkS3tv1CcrFBWA=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
|
||||
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.0.1 h1:2kKm5lb7dKVrt5TYUiAavE6oFc1cFT0057UVGT+JqLk=
|
||||
github.com/Masterminds/semver/v3 v3.0.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/sprig/v3 v3.0.0 h1:KSQz7Nb08/3VU9E4ns29dDxcczhOD1q7O1UfM4G3t3g=
|
||||
github.com/Masterminds/sprig/v3 v3.0.0/go.mod h1:NEUY/Qq8Gdm2xgYA+NwJM6wmfdRV9xkh8h/Rld20R0U=
|
||||
github.com/Masterminds/squirrel v0.0.0-20161115235646-20f192218cf5 h1:PPfYWScYacO3Q6JMCLkyh6Ea2Q/REDTMgmiTAeiV8Jg=
|
||||
github.com/Masterminds/squirrel v0.0.0-20161115235646-20f192218cf5/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM=
|
||||
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
||||
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
|
||||
@@ -56,6 +63,7 @@ github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
@@ -93,6 +101,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||
github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
@@ -109,6 +118,7 @@ github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
@@ -122,6 +132,10 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY=
|
||||
github.com/cloudflare/cfssl v1.5.0/go.mod h1:sPPkBS5L8l8sRc/IOO1jG51Xb34u+TYhL6P//JdODMQ=
|
||||
github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4=
|
||||
github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
|
||||
@@ -162,6 +176,7 @@ github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE
|
||||
github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
|
||||
github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
|
||||
github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8=
|
||||
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -247,12 +262,14 @@ github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7R
|
||||
github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
|
||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1 h1:j3L6gSLQalDETeEg/Jg0mGY0/y/N6zI2xX1978P0Uqw=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=
|
||||
@@ -297,17 +314,25 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
||||
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
|
||||
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
|
||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/flect v0.2.0 h1:EWCvMGGxOjsgwlWaP+f4+Hh6yrrte7JeFL2S6b+0hdM=
|
||||
github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
|
||||
github.com/gobuffalo/genny v0.1.1 h1:iQ0D6SpNXIxu52WESsD+KoQ7af2e3nCfnSBoSF/hKe0=
|
||||
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
|
||||
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
|
||||
github.com/gobuffalo/gogen v0.1.1 h1:dLg+zb+uOyd/mKeQUYIbwbNmfRsr9hd/WtYWepmayhI=
|
||||
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
|
||||
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
|
||||
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2 h1:8thhT+kUJMTMy3HlX4+y9Da+BNJck+p109tqqKp7WDs=
|
||||
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
|
||||
github.com/gobuffalo/mapi v1.0.2 h1:fq9WcL1BYrm36SzK6+aAnZ8hcp+SrmnDyAxhNx8dvJk=
|
||||
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
||||
github.com/gobuffalo/packd v0.1.0 h1:4sGKOD8yaYJ+dek1FDkwcxCHA40M4kfKgFHx8N2kwbU=
|
||||
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
|
||||
github.com/gobuffalo/packr/v2 v2.2.0 h1:Ir9W9XIm9j7bhhkKE9cokvtTl1vBm62A/fene/ZCj6A=
|
||||
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
|
||||
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754 h1:tpom+2CJmpzAWj5/VEHync2rJGi+epHNIeRSWjzGA+4=
|
||||
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
@@ -346,6 +371,7 @@ github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp
|
||||
github.com/google/addlicense v0.0.0-20200906110928-a0294312aa76/go.mod h1:EMjYTRimagHs1FwlIqKyX3wAM0u3rA+McvlIIWmSamA=
|
||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
|
||||
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
@@ -410,8 +436,10 @@ github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg
|
||||
github.com/hashicorp/memberlist v0.2.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/serf v0.9.0/go.mod h1:YL0HO+FifKOW2u1ke99DGVu1zhcpZzNwrLIqBC7vbYU=
|
||||
github.com/hodgesds/perf-utils v0.0.8/go.mod h1:F6TfvsbtrF88i++hou29dTXlI2sfsJv+gRZDtmTJkAs=
|
||||
github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=
|
||||
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
|
||||
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
@@ -433,8 +461,12 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
|
||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||
github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo=
|
||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/joelanford/go-apidiff v0.1.0/go.mod h1:wgVWgVCwYYkjcYpJtBnWYkyUYZfVovO3Y5pX49mJsqs=
|
||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
@@ -453,6 +485,7 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E
|
||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/karrick/godirwalk v1.10.3 h1:lOpSw2vJP0y5eLBW906QwKsUK/fe/QDyoqM5rnnuPDY=
|
||||
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||
@@ -460,6 +493,8 @@ github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
|
||||
github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw=
|
||||
github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
|
||||
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
@@ -478,7 +513,12 @@ github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0 h1:OYDCOjVcx/5wN
|
||||
github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0/go.mod h1:Q7VUue/CIrKbtpBdF04a1yjGGgsMaDws1HUxtjzgnEY=
|
||||
github.com/kubesphere/sonargo v0.0.2 h1:hsSRE3sv3mkPcUAeSABdp7rtfcNW2zzeHXzFa01CTkU=
|
||||
github.com/kubesphere/sonargo v0.0.2/go.mod h1:ww8n9ANlDXhX5PBZ18iaRnCgEkXN0GMml3/KZXOZ11w=
|
||||
github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c=
|
||||
github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8=
|
||||
github.com/leodido/go-urn v0.0.0-20181204092800-a67a23e1c1af/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
@@ -494,8 +534,10 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8=
|
||||
github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2 h1:JgVTCPf0uBVcUSWpyXmGpgOc62nK5HWUBKAGc3Qqa5k=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
|
||||
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -518,6 +560,8 @@ github.com/mdlayher/wifi v0.0.0-20190303161829-b1436901ddee/go.mod h1:Evt/EIne46
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
|
||||
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/mikefarah/yaml/v2 v2.4.0/go.mod h1:ahVqZF4n1W4NqwvVnZzC4es67xsW9uR/RRf2RRxieJU=
|
||||
github.com/mikefarah/yq/v2 v2.4.1/go.mod h1:i8SYf1XdgUvY2OFwSqGAtWOOgimD2McJ6iutoxRm4k0=
|
||||
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
|
||||
github.com/minio/minio-go/v7 v7.0.2/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
@@ -550,6 +594,7 @@ github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8d
|
||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE=
|
||||
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
|
||||
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
@@ -565,6 +610,7 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/ncw/swift v1.0.50/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
@@ -593,6 +639,11 @@ github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsq
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/operator-framework/api v0.4.0/go.mod h1:xXYReW8+PpSBHMxsf0e7uhtfQTLqIM1iz4X6zUs20+c=
|
||||
github.com/operator-framework/helm-operator-plugins v0.0.8-0.20210810182245-240cc447b3de h1:3Mwj+lME51OdXRLqfQbI1a05DuQ9qfHK/0wNd7Dphes=
|
||||
github.com/operator-framework/helm-operator-plugins v0.0.8-0.20210810182245-240cc447b3de/go.mod h1:Y/nfp35BlIMvae+nre4qUWLRl2pHKKnonrfgZUOABqY=
|
||||
github.com/operator-framework/operator-lib v0.3.0 h1:eGJv0k7dEHIT9vfArWPo6U4eVurAOqhYUzXiHEaZq9g=
|
||||
github.com/operator-framework/operator-lib v0.3.0/go.mod h1:LTp5UQd8ivq4MXqm/W/XHulHQ0RRoZXsAj73sNMAQxc=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
@@ -655,8 +706,10 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
|
||||
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 h1:HXr/qUllAWv9riaI4zh2eXWKmCSDqVS/XH1MRHLKRwk=
|
||||
github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
@@ -722,9 +775,12 @@ github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/
|
||||
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||
github.com/weaveworks/common v0.0.0-20200820123129-280614068c5e/go.mod h1:hz10LOsAdzC3K/iXaKoFxOKTDRgxJl+BTGX1GY+TzO4=
|
||||
github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA=
|
||||
github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
|
||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||
@@ -752,7 +808,12 @@ github.com/yvasiyarov/gorelic v0.0.6 h1:qMJQYPNdtJ7UNYHjX38KXZtltKTqimMuoQjNnSVI
|
||||
github.com/yvasiyarov/gorelic v0.0.6/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
|
||||
github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
|
||||
github.com/zmap/zcrypto v0.0.0-20200911161511-43ff0ea04f21/go.mod h1:TxpejqcVKQjQaVVmMGfzx5HnmFMdIU+vLtaCyPBfGI4=
|
||||
github.com/zmap/zlint/v2 v2.2.1/go.mod h1:ixPWsdq8qLxYRpNUTbcKig3R7WgmspsHGLhCCs6rFAM=
|
||||
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
|
||||
go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk=
|
||||
go.elastic.co/apm/module/apmhttp v1.5.0/go.mod h1:1FbmNuyD3ddauwzgVwFB0fqY6KbZt3JkV187tGCYYhY=
|
||||
@@ -834,12 +895,15 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v9 v9.27.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw=
|
||||
gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
|
||||
gopkg.in/imdario/mergo.v0 v0.3.7/go.mod h1:9qPP6AGrlC1G2PTNXko614FwGZvorN7MiBU0Eppok+U=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
|
||||
gopkg.in/square/go-jose.v1 v1.1.2 h1:/5jmADZB+RiKtZGr4HxsEFOEfbfsjTKsVnqpThUpE30=
|
||||
gopkg.in/square/go-jose.v1 v1.1.2/go.mod h1:QpYS+a4WhS+DTlyQIi6Ka7MS3SuR9a055rgXNEe6EiA=
|
||||
gopkg.in/square/go-jose.v2 v2.4.0 h1:0kXPskUMGAXXWJlP05ktEMOV0vmzFQUWw6d+aZJQU8A=
|
||||
@@ -863,8 +927,8 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
helm.sh/helm/v3 v3.5.0 h1:uqIT3Bh4hVEyZRThyTPik8FkiABj3VJIY+POvDFT3a4=
|
||||
helm.sh/helm/v3 v3.5.0/go.mod h1:bjwXfmGAF+SEuJZ2AtN1xmTuz4FqaNYOJrXP+vtj6Tw=
|
||||
helm.sh/helm/v3 v3.6.3 h1:0nKDyXJr23nI3JrcP7HH7NcR+CYRvro/52Dvr1KhGO0=
|
||||
helm.sh/helm/v3 v3.6.3/go.mod h1:mIIus8EOqj+obtycw3sidsR4ORr2aFDmXMSI3k+oeVY=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
|
||||
@@ -922,6 +986,7 @@ sigs.k8s.io/controller-runtime v0.9.3/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aK
|
||||
sigs.k8s.io/controller-tools v0.6.2 h1:+Y8L0UsAugDipGRw8lrkPoAi6XqlQVZuf1DQHME3PgU=
|
||||
sigs.k8s.io/controller-tools v0.6.2/go.mod h1:oaeGpjXn6+ZSEIQkUe/+3I40PNiDYp9aeawbt3xTgJ8=
|
||||
sigs.k8s.io/kind v0.8.1/go.mod h1:oNKTxUVPYkV9lWzY6CVMNluVq8cBsyq+UgPJdvA3uu4=
|
||||
sigs.k8s.io/kubebuilder/v3 v3.0.0-alpha.0.0.20210716121009-fde793f20067/go.mod h1:pUhjQx9f/+cn1OtSa5zMohY1lgk9s/9Mbcvwj82lrNk=
|
||||
sigs.k8s.io/kubefed v0.8.1 h1:xPMQAPi0L7t4MFdSGQvUuNQ1PmmyOp2QP3NSY7nr7nI=
|
||||
sigs.k8s.io/kubefed v0.8.1/go.mod h1:t383bqir7psk7VpABvlhYRldGOoDwKoVo33xAmCGueI=
|
||||
sigs.k8s.io/kustomize/api v0.8.8 h1:G2z6JPSSjtWWgMeWSoHdXqyftJNmMmyxXpwENGoOtGE=
|
||||
|
||||
18
vendor/github.com/Masterminds/goutils/.travis.yml
generated
vendored
Normal file
18
vendor/github.com/Masterminds/goutils/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/06e3328629952dabe3e0
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: never # options: [always|never|change] default: always
|
||||
8
vendor/github.com/Masterminds/goutils/CHANGELOG.md
generated
vendored
Normal file
8
vendor/github.com/Masterminds/goutils/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# 1.0.1 (2017-05-31)
|
||||
|
||||
## Fixed
|
||||
- #21: Fix generation of alphanumeric strings (thanks @dbarranco)
|
||||
|
||||
# 1.0.0 (2014-04-30)
|
||||
|
||||
- Initial release.
|
||||
202
vendor/github.com/Masterminds/goutils/LICENSE.txt
generated
vendored
Normal file
202
vendor/github.com/Masterminds/goutils/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
70
vendor/github.com/Masterminds/goutils/README.md
generated
vendored
Normal file
70
vendor/github.com/Masterminds/goutils/README.md
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
GoUtils
|
||||
===========
|
||||
[](https://masterminds.github.io/stability/maintenance.html)
|
||||
[](https://godoc.org/github.com/Masterminds/goutils) [](https://travis-ci.org/Masterminds/goutils) [](https://ci.appveyor.com/project/mattfarina/goutils)
|
||||
|
||||
|
||||
GoUtils provides users with utility functions to manipulate strings in various ways. It is a Go implementation of some
|
||||
string manipulation libraries of Java Apache Commons. GoUtils includes the following Java Apache Commons classes:
|
||||
* WordUtils
|
||||
* RandomStringUtils
|
||||
* StringUtils (partial implementation)
|
||||
|
||||
## Installation
|
||||
If you have Go set up on your system, from the GOPATH directory within the command line/terminal, enter this:
|
||||
|
||||
go get github.com/Masterminds/goutils
|
||||
|
||||
If you do not have Go set up on your system, please follow the [Go installation directions from the documenation](http://golang.org/doc/install), and then follow the instructions above to install GoUtils.
|
||||
|
||||
|
||||
## Documentation
|
||||
GoUtils doc is available here: [](https://godoc.org/github.com/Masterminds/goutils)
|
||||
|
||||
|
||||
## Usage
|
||||
The code snippets below show examples of how to use GoUtils. Some functions return errors while others do not. The first instance below, which does not return an error, is the `Initials` function (located within the `wordutils.go` file).
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Masterminds/goutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// EXAMPLE 1: A goutils function which returns no errors
|
||||
fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF"
|
||||
|
||||
}
|
||||
Some functions return errors mainly due to illegal arguements used as parameters. The code example below illustrates how to deal with function that returns an error. In this instance, the function is the `Random` function (located within the `randomstringutils.go` file).
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Masterminds/goutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// EXAMPLE 2: A goutils function which returns an error
|
||||
rand1, err1 := goutils.Random (-1, 0, 0, true, true)
|
||||
|
||||
if err1 != nil {
|
||||
fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...)
|
||||
} else {
|
||||
fmt.Println(rand1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
## License
|
||||
GoUtils is licensed under the Apache License, Version 2.0. Please check the LICENSE.txt file or visit http://www.apache.org/licenses/LICENSE-2.0 for a copy of the license.
|
||||
|
||||
## Issue Reporting
|
||||
Make suggestions or report issues using the Git issue tracker: https://github.com/Masterminds/goutils/issues
|
||||
|
||||
## Website
|
||||
* [GoUtils webpage](http://Masterminds.github.io/goutils/)
|
||||
21
vendor/github.com/Masterminds/goutils/appveyor.yml
generated
vendored
Normal file
21
vendor/github.com/Masterminds/goutils/appveyor.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
version: build-{build}.{branch}
|
||||
|
||||
clone_folder: C:\gopath\src\github.com\Masterminds\goutils
|
||||
shallow_clone: true
|
||||
|
||||
environment:
|
||||
GOPATH: C:\gopath
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
build: off
|
||||
|
||||
install:
|
||||
- go version
|
||||
- go env
|
||||
|
||||
test_script:
|
||||
- go test -v
|
||||
|
||||
deploy: off
|
||||
251
vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go
generated
vendored
Normal file
251
vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
Copyright 2014 Alexander Okoli
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package goutils
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
/*
|
||||
CryptoRandomNonAlphaNumeric creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of all characters (ASCII/Unicode values between 0 to 2,147,483,647 (math.MaxInt32)).
|
||||
|
||||
Parameter:
|
||||
count - the length of random string to create
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
|
||||
*/
|
||||
func CryptoRandomNonAlphaNumeric(count int) (string, error) {
|
||||
return CryptoRandomAlphaNumericCustom(count, false, false)
|
||||
}
|
||||
|
||||
/*
|
||||
CryptoRandomAscii creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of characters whose ASCII value is between 32 and 126 (inclusive).
|
||||
|
||||
Parameter:
|
||||
count - the length of random string to create
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
|
||||
*/
|
||||
func CryptoRandomAscii(count int) (string, error) {
|
||||
return CryptoRandom(count, 32, 127, false, false)
|
||||
}
|
||||
|
||||
/*
|
||||
CryptoRandomNumeric creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of numeric characters.
|
||||
|
||||
Parameter:
|
||||
count - the length of random string to create
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
|
||||
*/
|
||||
func CryptoRandomNumeric(count int) (string, error) {
|
||||
return CryptoRandom(count, 0, 0, false, true)
|
||||
}
|
||||
|
||||
/*
|
||||
CryptoRandomAlphabetic creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
|
||||
|
||||
Parameters:
|
||||
count - the length of random string to create
|
||||
letters - if true, generated string may include alphabetic characters
|
||||
numbers - if true, generated string may include numeric characters
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
|
||||
*/
|
||||
func CryptoRandomAlphabetic(count int) (string, error) {
|
||||
return CryptoRandom(count, 0, 0, true, false)
|
||||
}
|
||||
|
||||
/*
|
||||
CryptoRandomAlphaNumeric creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of alpha-numeric characters.
|
||||
|
||||
Parameter:
|
||||
count - the length of random string to create
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
|
||||
*/
|
||||
func CryptoRandomAlphaNumeric(count int) (string, error) {
|
||||
if count == 0 {
|
||||
return "", nil
|
||||
}
|
||||
RandomString, err := CryptoRandom(count, 0, 0, true, true)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error: %s", err)
|
||||
}
|
||||
match, err := regexp.MatchString("([0-9]+)", RandomString)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if !match {
|
||||
//Get the position between 0 and the length of the string-1 to insert a random number
|
||||
position := getCryptoRandomInt(count)
|
||||
//Insert a random number between [0-9] in the position
|
||||
RandomString = RandomString[:position] + string('0' + getCryptoRandomInt(10)) + RandomString[position + 1:]
|
||||
return RandomString, err
|
||||
}
|
||||
return RandomString, err
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
CryptoRandomAlphaNumericCustom creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
|
||||
|
||||
Parameters:
|
||||
count - the length of random string to create
|
||||
letters - if true, generated string may include alphabetic characters
|
||||
numbers - if true, generated string may include numeric characters
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
|
||||
*/
|
||||
func CryptoRandomAlphaNumericCustom(count int, letters bool, numbers bool) (string, error) {
|
||||
return CryptoRandom(count, 0, 0, letters, numbers)
|
||||
}
|
||||
|
||||
/*
|
||||
CryptoRandom creates a random string based on a variety of options, using using golang's crypto/rand source of randomness.
|
||||
If the parameters start and end are both 0, start and end are set to ' ' and 'z', the ASCII printable characters, will be used,
|
||||
unless letters and numbers are both false, in which case, start and end are set to 0 and math.MaxInt32, respectively.
|
||||
If chars is not nil, characters stored in chars that are between start and end are chosen.
|
||||
|
||||
Parameters:
|
||||
count - the length of random string to create
|
||||
start - the position in set of chars (ASCII/Unicode int) to start at
|
||||
end - the position in set of chars (ASCII/Unicode int) to end before
|
||||
letters - if true, generated string may include alphabetic characters
|
||||
numbers - if true, generated string may include numeric characters
|
||||
chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars.
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from invalid parameters: if count < 0; or the provided chars array is empty; or end <= start; or end > len(chars)
|
||||
*/
|
||||
func CryptoRandom(count int, start int, end int, letters bool, numbers bool, chars ...rune) (string, error) {
|
||||
if count == 0 {
|
||||
return "", nil
|
||||
} else if count < 0 {
|
||||
err := fmt.Errorf("randomstringutils illegal argument: Requested random string length %v is less than 0.", count) // equiv to err := errors.New("...")
|
||||
return "", err
|
||||
}
|
||||
if chars != nil && len(chars) == 0 {
|
||||
err := fmt.Errorf("randomstringutils illegal argument: The chars array must not be empty")
|
||||
return "", err
|
||||
}
|
||||
|
||||
if start == 0 && end == 0 {
|
||||
if chars != nil {
|
||||
end = len(chars)
|
||||
} else {
|
||||
if !letters && !numbers {
|
||||
end = math.MaxInt32
|
||||
} else {
|
||||
end = 'z' + 1
|
||||
start = ' '
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if end <= start {
|
||||
err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) must be greater than start (%v)", end, start)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if chars != nil && end > len(chars) {
|
||||
err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) cannot be greater than len(chars) (%v)", end, len(chars))
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
buffer := make([]rune, count)
|
||||
gap := end - start
|
||||
|
||||
// high-surrogates range, (\uD800-\uDBFF) = 55296 - 56319
|
||||
// low-surrogates range, (\uDC00-\uDFFF) = 56320 - 57343
|
||||
|
||||
for count != 0 {
|
||||
count--
|
||||
var ch rune
|
||||
if chars == nil {
|
||||
ch = rune(getCryptoRandomInt(gap) + int64(start))
|
||||
} else {
|
||||
ch = chars[getCryptoRandomInt(gap) + int64(start)]
|
||||
}
|
||||
|
||||
if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers {
|
||||
if ch >= 56320 && ch <= 57343 { // low surrogate range
|
||||
if count == 0 {
|
||||
count++
|
||||
} else {
|
||||
// Insert low surrogate
|
||||
buffer[count] = ch
|
||||
count--
|
||||
// Insert high surrogate
|
||||
buffer[count] = rune(55296 + getCryptoRandomInt(128))
|
||||
}
|
||||
} else if ch >= 55296 && ch <= 56191 { // High surrogates range (Partial)
|
||||
if count == 0 {
|
||||
count++
|
||||
} else {
|
||||
// Insert low surrogate
|
||||
buffer[count] = rune(56320 + getCryptoRandomInt(128))
|
||||
count--
|
||||
// Insert high surrogate
|
||||
buffer[count] = ch
|
||||
}
|
||||
} else if ch >= 56192 && ch <= 56319 {
|
||||
// private high surrogate, skip it
|
||||
count++
|
||||
} else {
|
||||
// not one of the surrogates*
|
||||
buffer[count] = ch
|
||||
}
|
||||
} else {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return string(buffer), nil
|
||||
}
|
||||
|
||||
func getCryptoRandomInt(count int) int64 {
|
||||
nBig, err := rand.Int(rand.Reader, big.NewInt(int64(count)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nBig.Int64()
|
||||
}
|
||||
268
vendor/github.com/Masterminds/goutils/randomstringutils.go
generated
vendored
Normal file
268
vendor/github.com/Masterminds/goutils/randomstringutils.go
generated
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright 2014 Alexander Okoli
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package goutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// RANDOM provides the time-based seed used to generate random numbers
|
||||
var RANDOM = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
/*
|
||||
RandomNonAlphaNumeric creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of all characters (ASCII/Unicode values between 0 to 2,147,483,647 (math.MaxInt32)).
|
||||
|
||||
Parameter:
|
||||
count - the length of random string to create
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
|
||||
*/
|
||||
func RandomNonAlphaNumeric(count int) (string, error) {
|
||||
return RandomAlphaNumericCustom(count, false, false)
|
||||
}
|
||||
|
||||
/*
|
||||
RandomAscii creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of characters whose ASCII value is between 32 and 126 (inclusive).
|
||||
|
||||
Parameter:
|
||||
count - the length of random string to create
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
|
||||
*/
|
||||
func RandomAscii(count int) (string, error) {
|
||||
return Random(count, 32, 127, false, false)
|
||||
}
|
||||
|
||||
/*
|
||||
RandomNumeric creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of numeric characters.
|
||||
|
||||
Parameter:
|
||||
count - the length of random string to create
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
|
||||
*/
|
||||
func RandomNumeric(count int) (string, error) {
|
||||
return Random(count, 0, 0, false, true)
|
||||
}
|
||||
|
||||
/*
|
||||
RandomAlphabetic creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
|
||||
|
||||
Parameters:
|
||||
count - the length of random string to create
|
||||
letters - if true, generated string may include alphabetic characters
|
||||
numbers - if true, generated string may include numeric characters
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
|
||||
*/
|
||||
func RandomAlphabetic(count int) (string, error) {
|
||||
return Random(count, 0, 0, true, false)
|
||||
}
|
||||
|
||||
/*
|
||||
RandomAlphaNumeric creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of alpha-numeric characters.
|
||||
|
||||
Parameter:
|
||||
count - the length of random string to create
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
|
||||
*/
|
||||
func RandomAlphaNumeric(count int) (string, error) {
|
||||
RandomString, err := Random(count, 0, 0, true, true)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error: %s", err)
|
||||
}
|
||||
match, err := regexp.MatchString("([0-9]+)", RandomString)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if !match {
|
||||
//Get the position between 0 and the length of the string-1 to insert a random number
|
||||
position := rand.Intn(count)
|
||||
//Insert a random number between [0-9] in the position
|
||||
RandomString = RandomString[:position] + string('0'+rand.Intn(10)) + RandomString[position+1:]
|
||||
return RandomString, err
|
||||
}
|
||||
return RandomString, err
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
RandomAlphaNumericCustom creates a random string whose length is the number of characters specified.
|
||||
Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
|
||||
|
||||
Parameters:
|
||||
count - the length of random string to create
|
||||
letters - if true, generated string may include alphabetic characters
|
||||
numbers - if true, generated string may include numeric characters
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
|
||||
*/
|
||||
func RandomAlphaNumericCustom(count int, letters bool, numbers bool) (string, error) {
|
||||
return Random(count, 0, 0, letters, numbers)
|
||||
}
|
||||
|
||||
/*
|
||||
Random creates a random string based on a variety of options, using default source of randomness.
|
||||
This method has exactly the same semantics as RandomSeed(int, int, int, bool, bool, []char, *rand.Rand), but
|
||||
instead of using an externally supplied source of randomness, it uses the internal *rand.Rand instance.
|
||||
|
||||
Parameters:
|
||||
count - the length of random string to create
|
||||
start - the position in set of chars (ASCII/Unicode int) to start at
|
||||
end - the position in set of chars (ASCII/Unicode int) to end before
|
||||
letters - if true, generated string may include alphabetic characters
|
||||
numbers - if true, generated string may include numeric characters
|
||||
chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars.
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
|
||||
*/
|
||||
func Random(count int, start int, end int, letters bool, numbers bool, chars ...rune) (string, error) {
|
||||
return RandomSeed(count, start, end, letters, numbers, chars, RANDOM)
|
||||
}
|
||||
|
||||
/*
|
||||
RandomSeed creates a random string based on a variety of options, using supplied source of randomness.
|
||||
If the parameters start and end are both 0, start and end are set to ' ' and 'z', the ASCII printable characters, will be used,
|
||||
unless letters and numbers are both false, in which case, start and end are set to 0 and math.MaxInt32, respectively.
|
||||
If chars is not nil, characters stored in chars that are between start and end are chosen.
|
||||
This method accepts a user-supplied *rand.Rand instance to use as a source of randomness. By seeding a single *rand.Rand instance
|
||||
with a fixed seed and using it for each call, the same random sequence of strings can be generated repeatedly and predictably.
|
||||
|
||||
Parameters:
|
||||
count - the length of random string to create
|
||||
start - the position in set of chars (ASCII/Unicode decimals) to start at
|
||||
end - the position in set of chars (ASCII/Unicode decimals) to end before
|
||||
letters - if true, generated string may include alphabetic characters
|
||||
numbers - if true, generated string may include numeric characters
|
||||
chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars.
|
||||
random - a source of randomness.
|
||||
|
||||
Returns:
|
||||
string - the random string
|
||||
error - an error stemming from invalid parameters: if count < 0; or the provided chars array is empty; or end <= start; or end > len(chars)
|
||||
*/
|
||||
func RandomSeed(count int, start int, end int, letters bool, numbers bool, chars []rune, random *rand.Rand) (string, error) {
|
||||
|
||||
if count == 0 {
|
||||
return "", nil
|
||||
} else if count < 0 {
|
||||
err := fmt.Errorf("randomstringutils illegal argument: Requested random string length %v is less than 0.", count) // equiv to err := errors.New("...")
|
||||
return "", err
|
||||
}
|
||||
if chars != nil && len(chars) == 0 {
|
||||
err := fmt.Errorf("randomstringutils illegal argument: The chars array must not be empty")
|
||||
return "", err
|
||||
}
|
||||
|
||||
if start == 0 && end == 0 {
|
||||
if chars != nil {
|
||||
end = len(chars)
|
||||
} else {
|
||||
if !letters && !numbers {
|
||||
end = math.MaxInt32
|
||||
} else {
|
||||
end = 'z' + 1
|
||||
start = ' '
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if end <= start {
|
||||
err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) must be greater than start (%v)", end, start)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if chars != nil && end > len(chars) {
|
||||
err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) cannot be greater than len(chars) (%v)", end, len(chars))
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
buffer := make([]rune, count)
|
||||
gap := end - start
|
||||
|
||||
// high-surrogates range, (\uD800-\uDBFF) = 55296 - 56319
|
||||
// low-surrogates range, (\uDC00-\uDFFF) = 56320 - 57343
|
||||
|
||||
for count != 0 {
|
||||
count--
|
||||
var ch rune
|
||||
if chars == nil {
|
||||
ch = rune(random.Intn(gap) + start)
|
||||
} else {
|
||||
ch = chars[random.Intn(gap)+start]
|
||||
}
|
||||
|
||||
if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers {
|
||||
if ch >= 56320 && ch <= 57343 { // low surrogate range
|
||||
if count == 0 {
|
||||
count++
|
||||
} else {
|
||||
// Insert low surrogate
|
||||
buffer[count] = ch
|
||||
count--
|
||||
// Insert high surrogate
|
||||
buffer[count] = rune(55296 + random.Intn(128))
|
||||
}
|
||||
} else if ch >= 55296 && ch <= 56191 { // High surrogates range (Partial)
|
||||
if count == 0 {
|
||||
count++
|
||||
} else {
|
||||
// Insert low surrogate
|
||||
buffer[count] = rune(56320 + random.Intn(128))
|
||||
count--
|
||||
// Insert high surrogate
|
||||
buffer[count] = ch
|
||||
}
|
||||
} else if ch >= 56192 && ch <= 56319 {
|
||||
// private high surrogate, skip it
|
||||
count++
|
||||
} else {
|
||||
// not one of the surrogates*
|
||||
buffer[count] = ch
|
||||
}
|
||||
} else {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return string(buffer), nil
|
||||
}
|
||||
224
vendor/github.com/Masterminds/goutils/stringutils.go
generated
vendored
Normal file
224
vendor/github.com/Masterminds/goutils/stringutils.go
generated
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
Copyright 2014 Alexander Okoli
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package goutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Typically returned by functions where a searched item cannot be found
|
||||
const INDEX_NOT_FOUND = -1
|
||||
|
||||
/*
|
||||
Abbreviate abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "Now is the time for..."
|
||||
|
||||
Specifically, the algorithm is as follows:
|
||||
|
||||
- If str is less than maxWidth characters long, return it.
|
||||
- Else abbreviate it to (str[0:maxWidth - 3] + "...").
|
||||
- If maxWidth is less than 4, return an illegal argument error.
|
||||
- In no case will it return a string of length greater than maxWidth.
|
||||
|
||||
Parameters:
|
||||
str - the string to check
|
||||
maxWidth - maximum length of result string, must be at least 4
|
||||
|
||||
Returns:
|
||||
string - abbreviated string
|
||||
error - if the width is too small
|
||||
*/
|
||||
func Abbreviate(str string, maxWidth int) (string, error) {
|
||||
return AbbreviateFull(str, 0, maxWidth)
|
||||
}
|
||||
|
||||
/*
|
||||
AbbreviateFull abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "...is the time for..."
|
||||
This function works like Abbreviate(string, int), but allows you to specify a "left edge" offset. Note that this left edge is not
|
||||
necessarily going to be the leftmost character in the result, or the first character following the ellipses, but it will appear
|
||||
somewhere in the result.
|
||||
In no case will it return a string of length greater than maxWidth.
|
||||
|
||||
Parameters:
|
||||
str - the string to check
|
||||
offset - left edge of source string
|
||||
maxWidth - maximum length of result string, must be at least 4
|
||||
|
||||
Returns:
|
||||
string - abbreviated string
|
||||
error - if the width is too small
|
||||
*/
|
||||
func AbbreviateFull(str string, offset int, maxWidth int) (string, error) {
|
||||
if str == "" {
|
||||
return "", nil
|
||||
}
|
||||
if maxWidth < 4 {
|
||||
err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width is 4")
|
||||
return "", err
|
||||
}
|
||||
if len(str) <= maxWidth {
|
||||
return str, nil
|
||||
}
|
||||
if offset > len(str) {
|
||||
offset = len(str)
|
||||
}
|
||||
if len(str)-offset < (maxWidth - 3) { // 15 - 5 < 10 - 3 = 10 < 7
|
||||
offset = len(str) - (maxWidth - 3)
|
||||
}
|
||||
abrevMarker := "..."
|
||||
if offset <= 4 {
|
||||
return str[0:maxWidth-3] + abrevMarker, nil // str.substring(0, maxWidth - 3) + abrevMarker;
|
||||
}
|
||||
if maxWidth < 7 {
|
||||
err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width with offset is 7")
|
||||
return "", err
|
||||
}
|
||||
if (offset + maxWidth - 3) < len(str) { // 5 + (10-3) < 15 = 12 < 15
|
||||
abrevStr, _ := Abbreviate(str[offset:len(str)], (maxWidth - 3))
|
||||
return abrevMarker + abrevStr, nil // abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
|
||||
}
|
||||
return abrevMarker + str[(len(str)-(maxWidth-3)):len(str)], nil // abrevMarker + str.substring(str.length() - (maxWidth - 3));
|
||||
}
|
||||
|
||||
/*
|
||||
DeleteWhiteSpace deletes all whitespaces from a string as defined by unicode.IsSpace(rune).
|
||||
It returns the string without whitespaces.
|
||||
|
||||
Parameter:
|
||||
str - the string to delete whitespace from, may be nil
|
||||
|
||||
Returns:
|
||||
the string without whitespaces
|
||||
*/
|
||||
func DeleteWhiteSpace(str string) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
sz := len(str)
|
||||
var chs bytes.Buffer
|
||||
count := 0
|
||||
for i := 0; i < sz; i++ {
|
||||
ch := rune(str[i])
|
||||
if !unicode.IsSpace(ch) {
|
||||
chs.WriteRune(ch)
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count == sz {
|
||||
return str
|
||||
}
|
||||
return chs.String()
|
||||
}
|
||||
|
||||
/*
|
||||
IndexOfDifference compares two strings, and returns the index at which the strings begin to differ.
|
||||
|
||||
Parameters:
|
||||
str1 - the first string
|
||||
str2 - the second string
|
||||
|
||||
Returns:
|
||||
the index where str1 and str2 begin to differ; -1 if they are equal
|
||||
*/
|
||||
func IndexOfDifference(str1 string, str2 string) int {
|
||||
if str1 == str2 {
|
||||
return INDEX_NOT_FOUND
|
||||
}
|
||||
if IsEmpty(str1) || IsEmpty(str2) {
|
||||
return 0
|
||||
}
|
||||
var i int
|
||||
for i = 0; i < len(str1) && i < len(str2); i++ {
|
||||
if rune(str1[i]) != rune(str2[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i < len(str2) || i < len(str1) {
|
||||
return i
|
||||
}
|
||||
return INDEX_NOT_FOUND
|
||||
}
|
||||
|
||||
/*
|
||||
IsBlank checks if a string is whitespace or empty (""). Observe the following behavior:
|
||||
|
||||
goutils.IsBlank("") = true
|
||||
goutils.IsBlank(" ") = true
|
||||
goutils.IsBlank("bob") = false
|
||||
goutils.IsBlank(" bob ") = false
|
||||
|
||||
Parameter:
|
||||
str - the string to check
|
||||
|
||||
Returns:
|
||||
true - if the string is whitespace or empty ("")
|
||||
*/
|
||||
func IsBlank(str string) bool {
|
||||
strLen := len(str)
|
||||
if str == "" || strLen == 0 {
|
||||
return true
|
||||
}
|
||||
for i := 0; i < strLen; i++ {
|
||||
if unicode.IsSpace(rune(str[i])) == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
IndexOf returns the index of the first instance of sub in str, with the search beginning from the
|
||||
index start point specified. -1 is returned if sub is not present in str.
|
||||
|
||||
An empty string ("") will return -1 (INDEX_NOT_FOUND). A negative start position is treated as zero.
|
||||
A start position greater than the string length returns -1.
|
||||
|
||||
Parameters:
|
||||
str - the string to check
|
||||
sub - the substring to find
|
||||
start - the start position; negative treated as zero
|
||||
|
||||
Returns:
|
||||
the first index where the sub string was found (always >= start)
|
||||
*/
|
||||
func IndexOf(str string, sub string, start int) int {
|
||||
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
|
||||
if len(str) < start {
|
||||
return INDEX_NOT_FOUND
|
||||
}
|
||||
|
||||
if IsEmpty(str) || IsEmpty(sub) {
|
||||
return INDEX_NOT_FOUND
|
||||
}
|
||||
|
||||
partialIndex := strings.Index(str[start:len(str)], sub)
|
||||
if partialIndex == -1 {
|
||||
return INDEX_NOT_FOUND
|
||||
}
|
||||
return partialIndex + start
|
||||
}
|
||||
|
||||
// IsEmpty checks if a string is empty (""). Returns true if empty, and false otherwise.
|
||||
func IsEmpty(str string) bool {
|
||||
return len(str) == 0
|
||||
}
|
||||
357
vendor/github.com/Masterminds/goutils/wordutils.go
generated
vendored
Normal file
357
vendor/github.com/Masterminds/goutils/wordutils.go
generated
vendored
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
Copyright 2014 Alexander Okoli
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Package goutils provides utility functions to manipulate strings in various ways.
|
||||
The code snippets below show examples of how to use goutils. Some functions return
|
||||
errors while others do not, so usage would vary as a result.
|
||||
|
||||
Example:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/aokoli/goutils"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// EXAMPLE 1: A goutils function which returns no errors
|
||||
fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF"
|
||||
|
||||
|
||||
|
||||
// EXAMPLE 2: A goutils function which returns an error
|
||||
rand1, err1 := goutils.Random (-1, 0, 0, true, true)
|
||||
|
||||
if err1 != nil {
|
||||
fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...)
|
||||
} else {
|
||||
fmt.Println(rand1)
|
||||
}
|
||||
}
|
||||
*/
|
||||
package goutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// VERSION indicates the current version of goutils
|
||||
const VERSION = "1.0.0"
|
||||
|
||||
/*
|
||||
Wrap wraps a single line of text, identifying words by ' '.
|
||||
New lines will be separated by '\n'. Very long words, such as URLs will not be wrapped.
|
||||
Leading spaces on a new line are stripped. Trailing spaces are not stripped.
|
||||
|
||||
Parameters:
|
||||
str - the string to be word wrapped
|
||||
wrapLength - the column (a column can fit only one character) to wrap the words at, less than 1 is treated as 1
|
||||
|
||||
Returns:
|
||||
a line with newlines inserted
|
||||
*/
|
||||
func Wrap(str string, wrapLength int) string {
|
||||
return WrapCustom(str, wrapLength, "", false)
|
||||
}
|
||||
|
||||
/*
|
||||
WrapCustom wraps a single line of text, identifying words by ' '.
|
||||
Leading spaces on a new line are stripped. Trailing spaces are not stripped.
|
||||
|
||||
Parameters:
|
||||
str - the string to be word wrapped
|
||||
wrapLength - the column number (a column can fit only one character) to wrap the words at, less than 1 is treated as 1
|
||||
newLineStr - the string to insert for a new line, "" uses '\n'
|
||||
wrapLongWords - true if long words (such as URLs) should be wrapped
|
||||
|
||||
Returns:
|
||||
a line with newlines inserted
|
||||
*/
|
||||
func WrapCustom(str string, wrapLength int, newLineStr string, wrapLongWords bool) string {
|
||||
|
||||
if str == "" {
|
||||
return ""
|
||||
}
|
||||
if newLineStr == "" {
|
||||
newLineStr = "\n" // TODO Assumes "\n" is seperator. Explore SystemUtils.LINE_SEPARATOR from Apache Commons
|
||||
}
|
||||
if wrapLength < 1 {
|
||||
wrapLength = 1
|
||||
}
|
||||
|
||||
inputLineLength := len(str)
|
||||
offset := 0
|
||||
|
||||
var wrappedLine bytes.Buffer
|
||||
|
||||
for inputLineLength-offset > wrapLength {
|
||||
|
||||
if rune(str[offset]) == ' ' {
|
||||
offset++
|
||||
continue
|
||||
}
|
||||
|
||||
end := wrapLength + offset + 1
|
||||
spaceToWrapAt := strings.LastIndex(str[offset:end], " ") + offset
|
||||
|
||||
if spaceToWrapAt >= offset {
|
||||
// normal word (not longer than wrapLength)
|
||||
wrappedLine.WriteString(str[offset:spaceToWrapAt])
|
||||
wrappedLine.WriteString(newLineStr)
|
||||
offset = spaceToWrapAt + 1
|
||||
|
||||
} else {
|
||||
// long word or URL
|
||||
if wrapLongWords {
|
||||
end := wrapLength + offset
|
||||
// long words are wrapped one line at a time
|
||||
wrappedLine.WriteString(str[offset:end])
|
||||
wrappedLine.WriteString(newLineStr)
|
||||
offset += wrapLength
|
||||
} else {
|
||||
// long words aren't wrapped, just extended beyond limit
|
||||
end := wrapLength + offset
|
||||
index := strings.IndexRune(str[end:len(str)], ' ')
|
||||
if index == -1 {
|
||||
wrappedLine.WriteString(str[offset:len(str)])
|
||||
offset = inputLineLength
|
||||
} else {
|
||||
spaceToWrapAt = index + end
|
||||
wrappedLine.WriteString(str[offset:spaceToWrapAt])
|
||||
wrappedLine.WriteString(newLineStr)
|
||||
offset = spaceToWrapAt + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrappedLine.WriteString(str[offset:len(str)])
|
||||
|
||||
return wrappedLine.String()
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Capitalize capitalizes all the delimiter separated words in a string. Only the first letter of each word is changed.
|
||||
To convert the rest of each word to lowercase at the same time, use CapitalizeFully(str string, delimiters ...rune).
|
||||
The delimiters represent a set of characters understood to separate words. The first string character
|
||||
and the first non-delimiter character after a delimiter will be capitalized. A "" input string returns "".
|
||||
Capitalization uses the Unicode title case, normally equivalent to upper case.
|
||||
|
||||
Parameters:
|
||||
str - the string to capitalize
|
||||
delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter
|
||||
|
||||
Returns:
|
||||
capitalized string
|
||||
*/
|
||||
func Capitalize(str string, delimiters ...rune) string {
|
||||
|
||||
var delimLen int
|
||||
|
||||
if delimiters == nil {
|
||||
delimLen = -1
|
||||
} else {
|
||||
delimLen = len(delimiters)
|
||||
}
|
||||
|
||||
if str == "" || delimLen == 0 {
|
||||
return str
|
||||
}
|
||||
|
||||
buffer := []rune(str)
|
||||
capitalizeNext := true
|
||||
for i := 0; i < len(buffer); i++ {
|
||||
ch := buffer[i]
|
||||
if isDelimiter(ch, delimiters...) {
|
||||
capitalizeNext = true
|
||||
} else if capitalizeNext {
|
||||
buffer[i] = unicode.ToTitle(ch)
|
||||
capitalizeNext = false
|
||||
}
|
||||
}
|
||||
return string(buffer)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
CapitalizeFully converts all the delimiter separated words in a string into capitalized words, that is each word is made up of a
|
||||
titlecase character and then a series of lowercase characters. The delimiters represent a set of characters understood
|
||||
to separate words. The first string character and the first non-delimiter character after a delimiter will be capitalized.
|
||||
Capitalization uses the Unicode title case, normally equivalent to upper case.
|
||||
|
||||
Parameters:
|
||||
str - the string to capitalize fully
|
||||
delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter
|
||||
|
||||
Returns:
|
||||
capitalized string
|
||||
*/
|
||||
func CapitalizeFully(str string, delimiters ...rune) string {
|
||||
|
||||
var delimLen int
|
||||
|
||||
if delimiters == nil {
|
||||
delimLen = -1
|
||||
} else {
|
||||
delimLen = len(delimiters)
|
||||
}
|
||||
|
||||
if str == "" || delimLen == 0 {
|
||||
return str
|
||||
}
|
||||
str = strings.ToLower(str)
|
||||
return Capitalize(str, delimiters...)
|
||||
}
|
||||
|
||||
/*
|
||||
Uncapitalize uncapitalizes all the whitespace separated words in a string. Only the first letter of each word is changed.
|
||||
The delimiters represent a set of characters understood to separate words. The first string character and the first non-delimiter
|
||||
character after a delimiter will be uncapitalized. Whitespace is defined by unicode.IsSpace(char).
|
||||
|
||||
Parameters:
|
||||
str - the string to uncapitalize fully
|
||||
delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter
|
||||
|
||||
Returns:
|
||||
uncapitalized string
|
||||
*/
|
||||
func Uncapitalize(str string, delimiters ...rune) string {
|
||||
|
||||
var delimLen int
|
||||
|
||||
if delimiters == nil {
|
||||
delimLen = -1
|
||||
} else {
|
||||
delimLen = len(delimiters)
|
||||
}
|
||||
|
||||
if str == "" || delimLen == 0 {
|
||||
return str
|
||||
}
|
||||
|
||||
buffer := []rune(str)
|
||||
uncapitalizeNext := true // TODO Always makes capitalize/un apply to first char.
|
||||
for i := 0; i < len(buffer); i++ {
|
||||
ch := buffer[i]
|
||||
if isDelimiter(ch, delimiters...) {
|
||||
uncapitalizeNext = true
|
||||
} else if uncapitalizeNext {
|
||||
buffer[i] = unicode.ToLower(ch)
|
||||
uncapitalizeNext = false
|
||||
}
|
||||
}
|
||||
return string(buffer)
|
||||
}
|
||||
|
||||
/*
|
||||
SwapCase swaps the case of a string using a word based algorithm.
|
||||
|
||||
Conversion algorithm:
|
||||
|
||||
Upper case character converts to Lower case
|
||||
Title case character converts to Lower case
|
||||
Lower case character after Whitespace or at start converts to Title case
|
||||
Other Lower case character converts to Upper case
|
||||
Whitespace is defined by unicode.IsSpace(char).
|
||||
|
||||
Parameters:
|
||||
str - the string to swap case
|
||||
|
||||
Returns:
|
||||
the changed string
|
||||
*/
|
||||
func SwapCase(str string) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
buffer := []rune(str)
|
||||
|
||||
whitespace := true
|
||||
|
||||
for i := 0; i < len(buffer); i++ {
|
||||
ch := buffer[i]
|
||||
if unicode.IsUpper(ch) {
|
||||
buffer[i] = unicode.ToLower(ch)
|
||||
whitespace = false
|
||||
} else if unicode.IsTitle(ch) {
|
||||
buffer[i] = unicode.ToLower(ch)
|
||||
whitespace = false
|
||||
} else if unicode.IsLower(ch) {
|
||||
if whitespace {
|
||||
buffer[i] = unicode.ToTitle(ch)
|
||||
whitespace = false
|
||||
} else {
|
||||
buffer[i] = unicode.ToUpper(ch)
|
||||
}
|
||||
} else {
|
||||
whitespace = unicode.IsSpace(ch)
|
||||
}
|
||||
}
|
||||
return string(buffer)
|
||||
}
|
||||
|
||||
/*
|
||||
Initials extracts the initial letters from each word in the string. The first letter of the string and all first
|
||||
letters after the defined delimiters are returned as a new string. Their case is not changed. If the delimiters
|
||||
parameter is excluded, then Whitespace is used. Whitespace is defined by unicode.IsSpacea(char). An empty delimiter array returns an empty string.
|
||||
|
||||
Parameters:
|
||||
str - the string to get initials from
|
||||
delimiters - set of characters to determine words, exclusion of this parameter means whitespace would be delimeter
|
||||
Returns:
|
||||
string of initial letters
|
||||
*/
|
||||
func Initials(str string, delimiters ...rune) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
if delimiters != nil && len(delimiters) == 0 {
|
||||
return ""
|
||||
}
|
||||
strLen := len(str)
|
||||
var buf bytes.Buffer
|
||||
lastWasGap := true
|
||||
for i := 0; i < strLen; i++ {
|
||||
ch := rune(str[i])
|
||||
|
||||
if isDelimiter(ch, delimiters...) {
|
||||
lastWasGap = true
|
||||
} else if lastWasGap {
|
||||
buf.WriteRune(ch)
|
||||
lastWasGap = false
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// private function (lower case func name)
|
||||
func isDelimiter(ch rune, delimiters ...rune) bool {
|
||||
if delimiters == nil {
|
||||
return unicode.IsSpace(ch)
|
||||
}
|
||||
for _, delimiter := range delimiters {
|
||||
if ch == delimiter {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
2
vendor/github.com/Masterminds/sprig/v3/.gitignore
generated
vendored
Normal file
2
vendor/github.com/Masterminds/sprig/v3/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
vendor/
|
||||
/.glide
|
||||
9
vendor/github.com/Masterminds/sprig/v3/.travis.yml
generated
vendored
Normal file
9
vendor/github.com/Masterminds/sprig/v3/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- tip
|
||||
|
||||
script:
|
||||
- make test-cover
|
||||
298
vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md
generated
vendored
Normal file
298
vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
# Changelog
|
||||
|
||||
## Release 3.0.0 (2019-10-02)
|
||||
|
||||
### Added
|
||||
|
||||
- #187: Added durationRound function (thanks @yjp20)
|
||||
- #189: Added numerous template functions that return errors rather than panic (thanks @nrvnrvn)
|
||||
- #193: Added toRawJson support (thanks @Dean-Coakley)
|
||||
- #197: Added get support to dicts (thanks @Dean-Coakley)
|
||||
|
||||
### Changed
|
||||
|
||||
- #186: Moving dependency management to Go modules
|
||||
- #186: Updated semver to v3. This has changes in the way ^ is handled
|
||||
- #194: Updated documentation on merging and how it copies. Added example using deepCopy
|
||||
- #196: trunc now supports negative values (thanks @Dean-Coakley)
|
||||
|
||||
## Release 2.22.0 (2019-10-02)
|
||||
|
||||
### Added
|
||||
|
||||
- #173: Added getHostByName function to resolve dns names to ips (thanks @fcgravalos)
|
||||
- #195: Added deepCopy function for use with dicts
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated merge and mergeOverwrite documentation to explain copying and how to
|
||||
use deepCopy with it
|
||||
|
||||
## Release 2.21.0 (2019-09-18)
|
||||
|
||||
### Added
|
||||
|
||||
- #122: Added encryptAES/decryptAES functions (thanks @n0madic)
|
||||
- #128: Added toDecimal support (thanks @Dean-Coakley)
|
||||
- #169: Added list contcat (thanks @astorath)
|
||||
- #174: Added deepEqual function (thanks @bonifaido)
|
||||
- #170: Added url parse and join functions (thanks @astorath)
|
||||
|
||||
### Changed
|
||||
|
||||
- #171: Updated glide config for Google UUID to v1 and to add ranges to semver and testify
|
||||
|
||||
### Fixed
|
||||
|
||||
- #172: Fix semver wildcard example (thanks @piepmatz)
|
||||
- #175: Fix dateInZone doc example (thanks @s3than)
|
||||
|
||||
## Release 2.20.0 (2019-06-18)
|
||||
|
||||
### Added
|
||||
|
||||
- #164: Adding function to get unix epoch for a time (@mattfarina)
|
||||
- #166: Adding tests for date_in_zone (@mattfarina)
|
||||
|
||||
### Changed
|
||||
|
||||
- #144: Fix function comments based on best practices from Effective Go (@CodeLingoTeam)
|
||||
- #150: Handles pointer type for time.Time in "htmlDate" (@mapreal19)
|
||||
- #161, #157, #160, #153, #158, #156, #155, #159, #152 documentation updates (@badeadan)
|
||||
|
||||
### Fixed
|
||||
|
||||
## Release 2.19.0 (2019-03-02)
|
||||
|
||||
IMPORTANT: This release reverts a change from 2.18.0
|
||||
|
||||
In the previous release (2.18), we prematurely merged a partial change to the crypto functions that led to creating two sets of crypto functions (I blame @technosophos -- since that's me). This release rolls back that change, and does what was originally intended: It alters the existing crypto functions to use secure random.
|
||||
|
||||
We debated whether this classifies as a change worthy of major revision, but given the proximity to the last release, we have decided that treating 2.18 as a faulty release is the correct course of action. We apologize for any inconvenience.
|
||||
|
||||
### Changed
|
||||
|
||||
- Fix substr panic 35fb796 (Alexey igrychev)
|
||||
- Remove extra period 1eb7729 (Matthew Lorimor)
|
||||
- Make random string functions use crypto by default 6ceff26 (Matthew Lorimor)
|
||||
- README edits/fixes/suggestions 08fe136 (Lauri Apple)
|
||||
|
||||
|
||||
## Release 2.18.0 (2019-02-12)
|
||||
|
||||
### Added
|
||||
|
||||
- Added mergeOverwrite function
|
||||
- cryptographic functions that use secure random (see fe1de12)
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve documentation of regexMatch function, resolves #139 90b89ce (Jan Tagscherer)
|
||||
- Handle has for nil list 9c10885 (Daniel Cohen)
|
||||
- Document behaviour of mergeOverwrite fe0dbe9 (Lukas Rieder)
|
||||
- doc: adds missing documentation. 4b871e6 (Fernandez Ludovic)
|
||||
- Replace outdated goutils imports 01893d2 (Matthew Lorimor)
|
||||
- Surface crypto secure random strings from goutils fe1de12 (Matthew Lorimor)
|
||||
- Handle untyped nil values as paramters to string functions 2b2ec8f (Morten Torkildsen)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix dict merge issue and provide mergeOverwrite .dst .src1 to overwrite from src -> dst 4c59c12 (Lukas Rieder)
|
||||
- Fix substr var names and comments d581f80 (Dean Coakley)
|
||||
- Fix substr documentation 2737203 (Dean Coakley)
|
||||
|
||||
## Release 2.17.1 (2019-01-03)
|
||||
|
||||
### Fixed
|
||||
|
||||
The 2.17.0 release did not have a version pinned for xstrings, which caused compilation failures when xstrings < 1.2 was used. This adds the correct version string to glide.yaml.
|
||||
|
||||
## Release 2.17.0 (2019-01-03)
|
||||
|
||||
### Added
|
||||
|
||||
- adds alder32sum function and test 6908fc2 (marshallford)
|
||||
- Added kebabcase function ca331a1 (Ilyes512)
|
||||
|
||||
### Changed
|
||||
|
||||
- Update goutils to 1.1.0 4e1125d (Matt Butcher)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix 'has' documentation e3f2a85 (dean-coakley)
|
||||
- docs(dict): fix typo in pick example dc424f9 (Dustin Specker)
|
||||
- fixes spelling errors... not sure how that happened 4cf188a (marshallford)
|
||||
|
||||
## Release 2.16.0 (2018-08-13)
|
||||
|
||||
### Added
|
||||
|
||||
- add splitn function fccb0b0 (Helgi Þorbjörnsson)
|
||||
- Add slice func df28ca7 (gongdo)
|
||||
- Generate serial number a3bdffd (Cody Coons)
|
||||
- Extract values of dict with values function df39312 (Lawrence Jones)
|
||||
|
||||
### Changed
|
||||
|
||||
- Modify panic message for list.slice ae38335 (gongdo)
|
||||
- Minor improvement in code quality - Removed an unreachable piece of code at defaults.go#L26:6 - Resolve formatting issues. 5834241 (Abhishek Kashyap)
|
||||
- Remove duplicated documentation 1d97af1 (Matthew Fisher)
|
||||
- Test on go 1.11 49df809 (Helgi Þormar Þorbjörnsson)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix file permissions c5f40b5 (gongdo)
|
||||
- Fix example for buildCustomCert 7779e0d (Tin Lam)
|
||||
|
||||
## Release 2.15.0 (2018-04-02)
|
||||
|
||||
### Added
|
||||
|
||||
- #68 and #69: Add json helpers to docs (thanks @arunvelsriram)
|
||||
- #66: Add ternary function (thanks @binoculars)
|
||||
- #67: Allow keys function to take multiple dicts (thanks @binoculars)
|
||||
- #89: Added sha1sum to crypto function (thanks @benkeil)
|
||||
- #81: Allow customizing Root CA that used by genSignedCert (thanks @chenzhiwei)
|
||||
- #92: Add travis testing for go 1.10
|
||||
- #93: Adding appveyor config for windows testing
|
||||
|
||||
### Changed
|
||||
|
||||
- #90: Updating to more recent dependencies
|
||||
- #73: replace satori/go.uuid with google/uuid (thanks @petterw)
|
||||
|
||||
### Fixed
|
||||
|
||||
- #76: Fixed documentation typos (thanks @Thiht)
|
||||
- Fixed rounding issue on the `ago` function. Note, the removes support for Go 1.8 and older
|
||||
|
||||
## Release 2.14.1 (2017-12-01)
|
||||
|
||||
### Fixed
|
||||
|
||||
- #60: Fix typo in function name documentation (thanks @neil-ca-moore)
|
||||
- #61: Removing line with {{ due to blocking github pages genertion
|
||||
- #64: Update the list functions to handle int, string, and other slices for compatibility
|
||||
|
||||
## Release 2.14.0 (2017-10-06)
|
||||
|
||||
This new version of Sprig adds a set of functions for generating and working with SSL certificates.
|
||||
|
||||
- `genCA` generates an SSL Certificate Authority
|
||||
- `genSelfSignedCert` generates an SSL self-signed certificate
|
||||
- `genSignedCert` generates an SSL certificate and key based on a given CA
|
||||
|
||||
## Release 2.13.0 (2017-09-18)
|
||||
|
||||
This release adds new functions, including:
|
||||
|
||||
- `regexMatch`, `regexFindAll`, `regexFind`, `regexReplaceAll`, `regexReplaceAllLiteral`, and `regexSplit` to work with regular expressions
|
||||
- `floor`, `ceil`, and `round` math functions
|
||||
- `toDate` converts a string to a date
|
||||
- `nindent` is just like `indent` but also prepends a new line
|
||||
- `ago` returns the time from `time.Now`
|
||||
|
||||
### Added
|
||||
|
||||
- #40: Added basic regex functionality (thanks @alanquillin)
|
||||
- #41: Added ceil floor and round functions (thanks @alanquillin)
|
||||
- #48: Added toDate function (thanks @andreynering)
|
||||
- #50: Added nindent function (thanks @binoculars)
|
||||
- #46: Added ago function (thanks @slayer)
|
||||
|
||||
### Changed
|
||||
|
||||
- #51: Updated godocs to include new string functions (thanks @curtisallen)
|
||||
- #49: Added ability to merge multiple dicts (thanks @binoculars)
|
||||
|
||||
## Release 2.12.0 (2017-05-17)
|
||||
|
||||
- `snakecase`, `camelcase`, and `shuffle` are three new string functions
|
||||
- `fail` allows you to bail out of a template render when conditions are not met
|
||||
|
||||
## Release 2.11.0 (2017-05-02)
|
||||
|
||||
- Added `toJson` and `toPrettyJson`
|
||||
- Added `merge`
|
||||
- Refactored documentation
|
||||
|
||||
## Release 2.10.0 (2017-03-15)
|
||||
|
||||
- Added `semver` and `semverCompare` for Semantic Versions
|
||||
- `list` replaces `tuple`
|
||||
- Fixed issue with `join`
|
||||
- Added `first`, `last`, `intial`, `rest`, `prepend`, `append`, `toString`, `toStrings`, `sortAlpha`, `reverse`, `coalesce`, `pluck`, `pick`, `compact`, `keys`, `omit`, `uniq`, `has`, `without`
|
||||
|
||||
## Release 2.9.0 (2017-02-23)
|
||||
|
||||
- Added `splitList` to split a list
|
||||
- Added crypto functions of `genPrivateKey` and `derivePassword`
|
||||
|
||||
## Release 2.8.0 (2016-12-21)
|
||||
|
||||
- Added access to several path functions (`base`, `dir`, `clean`, `ext`, and `abs`)
|
||||
- Added functions for _mutating_ dictionaries (`set`, `unset`, `hasKey`)
|
||||
|
||||
## Release 2.7.0 (2016-12-01)
|
||||
|
||||
- Added `sha256sum` to generate a hash of an input
|
||||
- Added functions to convert a numeric or string to `int`, `int64`, `float64`
|
||||
|
||||
## Release 2.6.0 (2016-10-03)
|
||||
|
||||
- Added a `uuidv4` template function for generating UUIDs inside of a template.
|
||||
|
||||
## Release 2.5.0 (2016-08-19)
|
||||
|
||||
- New `trimSuffix`, `trimPrefix`, `hasSuffix`, and `hasPrefix` functions
|
||||
- New aliases have been added for a few functions that didn't follow the naming conventions (`trimAll` and `abbrevBoth`)
|
||||
- `trimall` and `abbrevboth` (notice the case) are deprecated and will be removed in 3.0.0
|
||||
|
||||
## Release 2.4.0 (2016-08-16)
|
||||
|
||||
- Adds two functions: `until` and `untilStep`
|
||||
|
||||
## Release 2.3.0 (2016-06-21)
|
||||
|
||||
- cat: Concatenate strings with whitespace separators.
|
||||
- replace: Replace parts of a string: `replace " " "-" "Me First"` renders "Me-First"
|
||||
- plural: Format plurals: `len "foo" | plural "one foo" "many foos"` renders "many foos"
|
||||
- indent: Indent blocks of text in a way that is sensitive to "\n" characters.
|
||||
|
||||
## Release 2.2.0 (2016-04-21)
|
||||
|
||||
- Added a `genPrivateKey` function (Thanks @bacongobbler)
|
||||
|
||||
## Release 2.1.0 (2016-03-30)
|
||||
|
||||
- `default` now prints the default value when it does not receive a value down the pipeline. It is much safer now to do `{{.Foo | default "bar"}}`.
|
||||
- Added accessors for "hermetic" functions. These return only functions that, when given the same input, produce the same output.
|
||||
|
||||
## Release 2.0.0 (2016-03-29)
|
||||
|
||||
Because we switched from `int` to `int64` as the return value for all integer math functions, the library's major version number has been incremented.
|
||||
|
||||
- `min` complements `max` (formerly `biggest`)
|
||||
- `empty` indicates that a value is the empty value for its type
|
||||
- `tuple` creates a tuple inside of a template: `{{$t := tuple "a", "b" "c"}}`
|
||||
- `dict` creates a dictionary inside of a template `{{$d := dict "key1" "val1" "key2" "val2"}}`
|
||||
- Date formatters have been added for HTML dates (as used in `date` input fields)
|
||||
- Integer math functions can convert from a number of types, including `string` (via `strconv.ParseInt`).
|
||||
|
||||
## Release 1.2.0 (2016-02-01)
|
||||
|
||||
- Added quote and squote
|
||||
- Added b32enc and b32dec
|
||||
- add now takes varargs
|
||||
- biggest now takes varargs
|
||||
|
||||
## Release 1.1.0 (2015-12-29)
|
||||
|
||||
- Added #4: Added contains function. strings.Contains, but with the arguments
|
||||
switched to simplify common pipelines. (thanks krancour)
|
||||
- Added Travis-CI testing support
|
||||
|
||||
## Release 1.0.0 (2015-12-23)
|
||||
|
||||
- Initial release
|
||||
20
vendor/github.com/Masterminds/sprig/v3/LICENSE.txt
generated
vendored
Normal file
20
vendor/github.com/Masterminds/sprig/v3/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Sprig
|
||||
Copyright (C) 2013 Masterminds
|
||||
|
||||
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.
|
||||
9
vendor/github.com/Masterminds/sprig/v3/Makefile
generated
vendored
Normal file
9
vendor/github.com/Masterminds/sprig/v3/Makefile
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
.PHONY: test
|
||||
test:
|
||||
@echo "==> Running tests"
|
||||
GO111MODULE=on go test -v
|
||||
|
||||
.PHONY: test-cover
|
||||
test-cover:
|
||||
@echo "==> Running Tests with coverage"
|
||||
GO111MODULE=on go test -cover .
|
||||
91
vendor/github.com/Masterminds/sprig/v3/README.md
generated
vendored
Normal file
91
vendor/github.com/Masterminds/sprig/v3/README.md
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
# Sprig: Template functions for Go templates [](https://godoc.org/github.com/Masterminds/sprig) [](https://goreportcard.com/report/github.com/Masterminds/sprig)
|
||||
|
||||
[](https://masterminds.github.io/stability/sustained.html)
|
||||
[](https://travis-ci.org/Masterminds/sprig)
|
||||
|
||||
The Go language comes with a [built-in template
|
||||
language](http://golang.org/pkg/text/template/), but not
|
||||
very many template functions. Sprig is a library that provides more than 100 commonly
|
||||
used template functions.
|
||||
|
||||
It is inspired by the template functions found in
|
||||
[Twig](http://twig.sensiolabs.org/documentation) and in various
|
||||
JavaScript libraries, such as [underscore.js](http://underscorejs.org/).
|
||||
|
||||
## Package Versions
|
||||
|
||||
There are two active major versions of the `sprig` package.
|
||||
|
||||
* v3 is currently stable release series on the `master` branch. The Go API should
|
||||
remain compatible with v2, the current stable version. Behavior change behind
|
||||
some functions is the reason for the new major version.
|
||||
* v2 is the previous stable release series. It has been more than three years since
|
||||
the initial release of v2. You can read the documentation and see the code
|
||||
on the [release-2](https://github.com/Masterminds/sprig/tree/release-2) branch.
|
||||
Bug fixes to this major version will continue for some time.
|
||||
|
||||
## Usage
|
||||
|
||||
**Template developers**: Please use Sprig's [function documentation](http://masterminds.github.io/sprig/) for
|
||||
detailed instructions and code snippets for the >100 template functions available.
|
||||
|
||||
**Go developers**: If you'd like to include Sprig as a library in your program,
|
||||
our API documentation is available [at GoDoc.org](http://godoc.org/github.com/Masterminds/sprig).
|
||||
|
||||
For standard usage, read on.
|
||||
|
||||
### Load the Sprig library
|
||||
|
||||
To load the Sprig `FuncMap`:
|
||||
|
||||
```go
|
||||
|
||||
import (
|
||||
"github.com/Masterminds/sprig"
|
||||
"html/template"
|
||||
)
|
||||
|
||||
// This example illustrates that the FuncMap *must* be set before the
|
||||
// templates themselves are loaded.
|
||||
tpl := template.Must(
|
||||
template.New("base").Funcs(sprig.FuncMap()).ParseGlob("*.html")
|
||||
)
|
||||
|
||||
|
||||
```
|
||||
|
||||
### Calling the functions inside of templates
|
||||
|
||||
By convention, all functions are lowercase. This seems to follow the Go
|
||||
idiom for template functions (as opposed to template methods, which are
|
||||
TitleCase). For example, this:
|
||||
|
||||
```
|
||||
{{ "hello!" | upper | repeat 5 }}
|
||||
```
|
||||
|
||||
produces this:
|
||||
|
||||
```
|
||||
HELLO!HELLO!HELLO!HELLO!HELLO!
|
||||
```
|
||||
|
||||
## Principles Driving Our Function Selection
|
||||
|
||||
We followed these principles to decide which functions to add and how to implement them:
|
||||
|
||||
- Use template functions to build layout. The following
|
||||
types of operations are within the domain of template functions:
|
||||
- Formatting
|
||||
- Layout
|
||||
- Simple type conversions
|
||||
- Utilities that assist in handling common formatting and layout needs (e.g. arithmetic)
|
||||
- Template functions should not return errors unless there is no way to print
|
||||
a sensible value. For example, converting a string to an integer should not
|
||||
produce an error if conversion fails. Instead, it should display a default
|
||||
value.
|
||||
- Simple math is necessary for grid layouts, pagers, and so on. Complex math
|
||||
(anything other than arithmetic) should be done outside of templates.
|
||||
- Template functions only deal with the data passed into them. They never retrieve
|
||||
data from a source.
|
||||
- Finally, do not override core Go template functions.
|
||||
22
vendor/github.com/Masterminds/sprig/v3/appveyor.yml
generated
vendored
Normal file
22
vendor/github.com/Masterminds/sprig/v3/appveyor.yml
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
version: build-{build}.{branch}
|
||||
|
||||
shallow_clone: true
|
||||
|
||||
environment:
|
||||
GOPATH: C:\gopath
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
install:
|
||||
- go version
|
||||
- go env
|
||||
|
||||
build_script:
|
||||
- go install ./...
|
||||
|
||||
test_script:
|
||||
- go test -v
|
||||
|
||||
deploy: off
|
||||
495
vendor/github.com/Masterminds/sprig/v3/crypto.go
generated
vendored
Normal file
495
vendor/github.com/Masterminds/sprig/v3/crypto.go
generated
vendored
Normal file
@@ -0,0 +1,495 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/adler32"
|
||||
"io"
|
||||
"math/big"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
func sha256sum(input string) string {
|
||||
hash := sha256.Sum256([]byte(input))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
func sha1sum(input string) string {
|
||||
hash := sha1.Sum([]byte(input))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
func adler32sum(input string) string {
|
||||
hash := adler32.Checksum([]byte(input))
|
||||
return fmt.Sprintf("%d", hash)
|
||||
}
|
||||
|
||||
// uuidv4 provides a safe and secure UUID v4 implementation
|
||||
func uuidv4() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
||||
var masterPasswordSeed = "com.lyndir.masterpassword"
|
||||
|
||||
var passwordTypeTemplates = map[string][][]byte{
|
||||
"maximum": {[]byte("anoxxxxxxxxxxxxxxxxx"), []byte("axxxxxxxxxxxxxxxxxno")},
|
||||
"long": {[]byte("CvcvnoCvcvCvcv"), []byte("CvcvCvcvnoCvcv"), []byte("CvcvCvcvCvcvno"), []byte("CvccnoCvcvCvcv"), []byte("CvccCvcvnoCvcv"),
|
||||
[]byte("CvccCvcvCvcvno"), []byte("CvcvnoCvccCvcv"), []byte("CvcvCvccnoCvcv"), []byte("CvcvCvccCvcvno"), []byte("CvcvnoCvcvCvcc"),
|
||||
[]byte("CvcvCvcvnoCvcc"), []byte("CvcvCvcvCvccno"), []byte("CvccnoCvccCvcv"), []byte("CvccCvccnoCvcv"), []byte("CvccCvccCvcvno"),
|
||||
[]byte("CvcvnoCvccCvcc"), []byte("CvcvCvccnoCvcc"), []byte("CvcvCvccCvccno"), []byte("CvccnoCvcvCvcc"), []byte("CvccCvcvnoCvcc"),
|
||||
[]byte("CvccCvcvCvccno")},
|
||||
"medium": {[]byte("CvcnoCvc"), []byte("CvcCvcno")},
|
||||
"short": {[]byte("Cvcn")},
|
||||
"basic": {[]byte("aaanaaan"), []byte("aannaaan"), []byte("aaannaaa")},
|
||||
"pin": {[]byte("nnnn")},
|
||||
}
|
||||
|
||||
var templateCharacters = map[byte]string{
|
||||
'V': "AEIOU",
|
||||
'C': "BCDFGHJKLMNPQRSTVWXYZ",
|
||||
'v': "aeiou",
|
||||
'c': "bcdfghjklmnpqrstvwxyz",
|
||||
'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ",
|
||||
'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz",
|
||||
'n': "0123456789",
|
||||
'o': "@&%?,=[]_:-+*$#!'^~;()/.",
|
||||
'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()",
|
||||
}
|
||||
|
||||
func derivePassword(counter uint32, passwordType, password, user, site string) string {
|
||||
var templates = passwordTypeTemplates[passwordType]
|
||||
if templates == nil {
|
||||
return fmt.Sprintf("cannot find password template %s", passwordType)
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString(masterPasswordSeed)
|
||||
binary.Write(&buffer, binary.BigEndian, uint32(len(user)))
|
||||
buffer.WriteString(user)
|
||||
|
||||
salt := buffer.Bytes()
|
||||
key, err := scrypt.Key([]byte(password), salt, 32768, 8, 2, 64)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("failed to derive password: %s", err)
|
||||
}
|
||||
|
||||
buffer.Truncate(len(masterPasswordSeed))
|
||||
binary.Write(&buffer, binary.BigEndian, uint32(len(site)))
|
||||
buffer.WriteString(site)
|
||||
binary.Write(&buffer, binary.BigEndian, counter)
|
||||
|
||||
var hmacv = hmac.New(sha256.New, key)
|
||||
hmacv.Write(buffer.Bytes())
|
||||
var seed = hmacv.Sum(nil)
|
||||
var temp = templates[int(seed[0])%len(templates)]
|
||||
|
||||
buffer.Truncate(0)
|
||||
for i, element := range temp {
|
||||
passChars := templateCharacters[element]
|
||||
passChar := passChars[int(seed[i+1])%len(passChars)]
|
||||
buffer.WriteByte(passChar)
|
||||
}
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func generatePrivateKey(typ string) string {
|
||||
var priv interface{}
|
||||
var err error
|
||||
switch typ {
|
||||
case "", "rsa":
|
||||
// good enough for government work
|
||||
priv, err = rsa.GenerateKey(rand.Reader, 4096)
|
||||
case "dsa":
|
||||
key := new(dsa.PrivateKey)
|
||||
// again, good enough for government work
|
||||
if err = dsa.GenerateParameters(&key.Parameters, rand.Reader, dsa.L2048N256); err != nil {
|
||||
return fmt.Sprintf("failed to generate dsa params: %s", err)
|
||||
}
|
||||
err = dsa.GenerateKey(key, rand.Reader)
|
||||
priv = key
|
||||
case "ecdsa":
|
||||
// again, good enough for government work
|
||||
priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
default:
|
||||
return "Unknown type " + typ
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Sprintf("failed to generate private key: %s", err)
|
||||
}
|
||||
|
||||
return string(pem.EncodeToMemory(pemBlockForKey(priv)))
|
||||
}
|
||||
|
||||
// DSAKeyFormat stores the format for DSA keys.
|
||||
// Used by pemBlockForKey
|
||||
type DSAKeyFormat struct {
|
||||
Version int
|
||||
P, Q, G, Y, X *big.Int
|
||||
}
|
||||
|
||||
func pemBlockForKey(priv interface{}) *pem.Block {
|
||||
switch k := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
|
||||
case *dsa.PrivateKey:
|
||||
val := DSAKeyFormat{
|
||||
P: k.P, Q: k.Q, G: k.G,
|
||||
Y: k.Y, X: k.X,
|
||||
}
|
||||
bytes, _ := asn1.Marshal(val)
|
||||
return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes}
|
||||
case *ecdsa.PrivateKey:
|
||||
b, _ := x509.MarshalECPrivateKey(k)
|
||||
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type certificate struct {
|
||||
Cert string
|
||||
Key string
|
||||
}
|
||||
|
||||
func buildCustomCertificate(b64cert string, b64key string) (certificate, error) {
|
||||
crt := certificate{}
|
||||
|
||||
cert, err := base64.StdEncoding.DecodeString(b64cert)
|
||||
if err != nil {
|
||||
return crt, errors.New("unable to decode base64 certificate")
|
||||
}
|
||||
|
||||
key, err := base64.StdEncoding.DecodeString(b64key)
|
||||
if err != nil {
|
||||
return crt, errors.New("unable to decode base64 private key")
|
||||
}
|
||||
|
||||
decodedCert, _ := pem.Decode(cert)
|
||||
if decodedCert == nil {
|
||||
return crt, errors.New("unable to decode certificate")
|
||||
}
|
||||
_, err = x509.ParseCertificate(decodedCert.Bytes)
|
||||
if err != nil {
|
||||
return crt, fmt.Errorf(
|
||||
"error parsing certificate: decodedCert.Bytes: %s",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
decodedKey, _ := pem.Decode(key)
|
||||
if decodedKey == nil {
|
||||
return crt, errors.New("unable to decode key")
|
||||
}
|
||||
_, err = x509.ParsePKCS1PrivateKey(decodedKey.Bytes)
|
||||
if err != nil {
|
||||
return crt, fmt.Errorf(
|
||||
"error parsing prive key: decodedKey.Bytes: %s",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
crt.Cert = string(cert)
|
||||
crt.Key = string(key)
|
||||
|
||||
return crt, nil
|
||||
}
|
||||
|
||||
func generateCertificateAuthority(
|
||||
cn string,
|
||||
daysValid int,
|
||||
) (certificate, error) {
|
||||
ca := certificate{}
|
||||
|
||||
template, err := getBaseCertTemplate(cn, nil, nil, daysValid)
|
||||
if err != nil {
|
||||
return ca, err
|
||||
}
|
||||
// Override KeyUsage and IsCA
|
||||
template.KeyUsage = x509.KeyUsageKeyEncipherment |
|
||||
x509.KeyUsageDigitalSignature |
|
||||
x509.KeyUsageCertSign
|
||||
template.IsCA = true
|
||||
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return ca, fmt.Errorf("error generating rsa key: %s", err)
|
||||
}
|
||||
|
||||
ca.Cert, ca.Key, err = getCertAndKey(template, priv, template, priv)
|
||||
|
||||
return ca, err
|
||||
}
|
||||
|
||||
func generateSelfSignedCertificate(
|
||||
cn string,
|
||||
ips []interface{},
|
||||
alternateDNS []interface{},
|
||||
daysValid int,
|
||||
) (certificate, error) {
|
||||
cert := certificate{}
|
||||
|
||||
template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
|
||||
if err != nil {
|
||||
return cert, err
|
||||
}
|
||||
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return cert, fmt.Errorf("error generating rsa key: %s", err)
|
||||
}
|
||||
|
||||
cert.Cert, cert.Key, err = getCertAndKey(template, priv, template, priv)
|
||||
|
||||
return cert, err
|
||||
}
|
||||
|
||||
func generateSignedCertificate(
|
||||
cn string,
|
||||
ips []interface{},
|
||||
alternateDNS []interface{},
|
||||
daysValid int,
|
||||
ca certificate,
|
||||
) (certificate, error) {
|
||||
cert := certificate{}
|
||||
|
||||
decodedSignerCert, _ := pem.Decode([]byte(ca.Cert))
|
||||
if decodedSignerCert == nil {
|
||||
return cert, errors.New("unable to decode certificate")
|
||||
}
|
||||
signerCert, err := x509.ParseCertificate(decodedSignerCert.Bytes)
|
||||
if err != nil {
|
||||
return cert, fmt.Errorf(
|
||||
"error parsing certificate: decodedSignerCert.Bytes: %s",
|
||||
err,
|
||||
)
|
||||
}
|
||||
decodedSignerKey, _ := pem.Decode([]byte(ca.Key))
|
||||
if decodedSignerKey == nil {
|
||||
return cert, errors.New("unable to decode key")
|
||||
}
|
||||
signerKey, err := x509.ParsePKCS1PrivateKey(decodedSignerKey.Bytes)
|
||||
if err != nil {
|
||||
return cert, fmt.Errorf(
|
||||
"error parsing prive key: decodedSignerKey.Bytes: %s",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
|
||||
if err != nil {
|
||||
return cert, err
|
||||
}
|
||||
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return cert, fmt.Errorf("error generating rsa key: %s", err)
|
||||
}
|
||||
|
||||
cert.Cert, cert.Key, err = getCertAndKey(
|
||||
template,
|
||||
priv,
|
||||
signerCert,
|
||||
signerKey,
|
||||
)
|
||||
|
||||
return cert, err
|
||||
}
|
||||
|
||||
func getCertAndKey(
|
||||
template *x509.Certificate,
|
||||
signeeKey *rsa.PrivateKey,
|
||||
parent *x509.Certificate,
|
||||
signingKey *rsa.PrivateKey,
|
||||
) (string, string, error) {
|
||||
derBytes, err := x509.CreateCertificate(
|
||||
rand.Reader,
|
||||
template,
|
||||
parent,
|
||||
&signeeKey.PublicKey,
|
||||
signingKey,
|
||||
)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("error creating certificate: %s", err)
|
||||
}
|
||||
|
||||
certBuffer := bytes.Buffer{}
|
||||
if err := pem.Encode(
|
||||
&certBuffer,
|
||||
&pem.Block{Type: "CERTIFICATE", Bytes: derBytes},
|
||||
); err != nil {
|
||||
return "", "", fmt.Errorf("error pem-encoding certificate: %s", err)
|
||||
}
|
||||
|
||||
keyBuffer := bytes.Buffer{}
|
||||
if err := pem.Encode(
|
||||
&keyBuffer,
|
||||
&pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(signeeKey),
|
||||
},
|
||||
); err != nil {
|
||||
return "", "", fmt.Errorf("error pem-encoding key: %s", err)
|
||||
}
|
||||
|
||||
return certBuffer.String(), keyBuffer.String(), nil
|
||||
}
|
||||
|
||||
func getBaseCertTemplate(
|
||||
cn string,
|
||||
ips []interface{},
|
||||
alternateDNS []interface{},
|
||||
daysValid int,
|
||||
) (*x509.Certificate, error) {
|
||||
ipAddresses, err := getNetIPs(ips)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dnsNames, err := getAlternateDNSStrs(alternateDNS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serialNumberUpperBound := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serialNumber, err := rand.Int(rand.Reader, serialNumberUpperBound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &x509.Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
Subject: pkix.Name{
|
||||
CommonName: cn,
|
||||
},
|
||||
IPAddresses: ipAddresses,
|
||||
DNSNames: dnsNames,
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(daysValid)),
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageServerAuth,
|
||||
x509.ExtKeyUsageClientAuth,
|
||||
},
|
||||
BasicConstraintsValid: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getNetIPs(ips []interface{}) ([]net.IP, error) {
|
||||
if ips == nil {
|
||||
return []net.IP{}, nil
|
||||
}
|
||||
var ipStr string
|
||||
var ok bool
|
||||
var netIP net.IP
|
||||
netIPs := make([]net.IP, len(ips))
|
||||
for i, ip := range ips {
|
||||
ipStr, ok = ip.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("error parsing ip: %v is not a string", ip)
|
||||
}
|
||||
netIP = net.ParseIP(ipStr)
|
||||
if netIP == nil {
|
||||
return nil, fmt.Errorf("error parsing ip: %s", ipStr)
|
||||
}
|
||||
netIPs[i] = netIP
|
||||
}
|
||||
return netIPs, nil
|
||||
}
|
||||
|
||||
func getAlternateDNSStrs(alternateDNS []interface{}) ([]string, error) {
|
||||
if alternateDNS == nil {
|
||||
return []string{}, nil
|
||||
}
|
||||
var dnsStr string
|
||||
var ok bool
|
||||
alternateDNSStrs := make([]string, len(alternateDNS))
|
||||
for i, dns := range alternateDNS {
|
||||
dnsStr, ok = dns.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(
|
||||
"error processing alternate dns name: %v is not a string",
|
||||
dns,
|
||||
)
|
||||
}
|
||||
alternateDNSStrs[i] = dnsStr
|
||||
}
|
||||
return alternateDNSStrs, nil
|
||||
}
|
||||
|
||||
func encryptAES(password string, plaintext string) (string, error) {
|
||||
if plaintext == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
key := make([]byte, 32)
|
||||
copy(key, []byte(password))
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
content := []byte(plaintext)
|
||||
blockSize := block.BlockSize()
|
||||
padding := blockSize - len(content)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
content = append(content, padtext...)
|
||||
|
||||
ciphertext := make([]byte, aes.BlockSize+len(content))
|
||||
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(ciphertext[aes.BlockSize:], content)
|
||||
|
||||
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||
}
|
||||
|
||||
func decryptAES(password string, crypt64 string) (string, error) {
|
||||
if crypt64 == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
key := make([]byte, 32)
|
||||
copy(key, []byte(password))
|
||||
|
||||
crypt, err := base64.StdEncoding.DecodeString(crypt64)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
iv := crypt[:aes.BlockSize]
|
||||
crypt = crypt[aes.BlockSize:]
|
||||
decrypted := make([]byte, len(crypt))
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(decrypted, crypt)
|
||||
|
||||
return string(decrypted[:len(decrypted)-int(decrypted[len(decrypted)-1])]), nil
|
||||
}
|
||||
139
vendor/github.com/Masterminds/sprig/v3/date.go
generated
vendored
Normal file
139
vendor/github.com/Masterminds/sprig/v3/date.go
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Given a format and a date, format the date string.
|
||||
//
|
||||
// Date can be a `time.Time` or an `int, int32, int64`.
|
||||
// In the later case, it is treated as seconds since UNIX
|
||||
// epoch.
|
||||
func date(fmt string, date interface{}) string {
|
||||
return dateInZone(fmt, date, "Local")
|
||||
}
|
||||
|
||||
func htmlDate(date interface{}) string {
|
||||
return dateInZone("2006-01-02", date, "Local")
|
||||
}
|
||||
|
||||
func htmlDateInZone(date interface{}, zone string) string {
|
||||
return dateInZone("2006-01-02", date, zone)
|
||||
}
|
||||
|
||||
func dateInZone(fmt string, date interface{}, zone string) string {
|
||||
var t time.Time
|
||||
switch date := date.(type) {
|
||||
default:
|
||||
t = time.Now()
|
||||
case time.Time:
|
||||
t = date
|
||||
case *time.Time:
|
||||
t = *date
|
||||
case int64:
|
||||
t = time.Unix(date, 0)
|
||||
case int:
|
||||
t = time.Unix(int64(date), 0)
|
||||
case int32:
|
||||
t = time.Unix(int64(date), 0)
|
||||
}
|
||||
|
||||
loc, err := time.LoadLocation(zone)
|
||||
if err != nil {
|
||||
loc, _ = time.LoadLocation("UTC")
|
||||
}
|
||||
|
||||
return t.In(loc).Format(fmt)
|
||||
}
|
||||
|
||||
func dateModify(fmt string, date time.Time) time.Time {
|
||||
d, err := time.ParseDuration(fmt)
|
||||
if err != nil {
|
||||
return date
|
||||
}
|
||||
return date.Add(d)
|
||||
}
|
||||
|
||||
func mustDateModify(fmt string, date time.Time) (time.Time, error) {
|
||||
d, err := time.ParseDuration(fmt)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return date.Add(d), nil
|
||||
}
|
||||
|
||||
func dateAgo(date interface{}) string {
|
||||
var t time.Time
|
||||
|
||||
switch date := date.(type) {
|
||||
default:
|
||||
t = time.Now()
|
||||
case time.Time:
|
||||
t = date
|
||||
case int64:
|
||||
t = time.Unix(date, 0)
|
||||
case int:
|
||||
t = time.Unix(int64(date), 0)
|
||||
}
|
||||
// Drop resolution to seconds
|
||||
duration := time.Since(t).Round(time.Second)
|
||||
return duration.String()
|
||||
}
|
||||
|
||||
func durationRound(duration interface{}) string {
|
||||
var d time.Duration
|
||||
switch duration := duration.(type) {
|
||||
default:
|
||||
d = 0
|
||||
case string:
|
||||
d, _ = time.ParseDuration(duration)
|
||||
case int64:
|
||||
d = time.Duration(duration)
|
||||
case time.Time:
|
||||
d = time.Since(duration)
|
||||
}
|
||||
|
||||
u := uint64(d)
|
||||
neg := d < 0
|
||||
if neg {
|
||||
u = -u
|
||||
}
|
||||
|
||||
var (
|
||||
year = uint64(time.Hour) * 24 * 365
|
||||
month = uint64(time.Hour) * 24 * 30
|
||||
day = uint64(time.Hour) * 24
|
||||
hour = uint64(time.Hour)
|
||||
minute = uint64(time.Minute)
|
||||
second = uint64(time.Second)
|
||||
)
|
||||
switch {
|
||||
case u > year:
|
||||
return strconv.FormatUint(u/year, 10) + "y"
|
||||
case u > month:
|
||||
return strconv.FormatUint(u/month, 10) + "mo"
|
||||
case u > day:
|
||||
return strconv.FormatUint(u/day, 10) + "d"
|
||||
case u > hour:
|
||||
return strconv.FormatUint(u/hour, 10) + "h"
|
||||
case u > minute:
|
||||
return strconv.FormatUint(u/minute, 10) + "m"
|
||||
case u > second:
|
||||
return strconv.FormatUint(u/second, 10) + "s"
|
||||
}
|
||||
return "0s"
|
||||
}
|
||||
|
||||
func toDate(fmt, str string) time.Time {
|
||||
t, _ := time.ParseInLocation(fmt, str, time.Local)
|
||||
return t
|
||||
}
|
||||
|
||||
func mustToDate(fmt, str string) (time.Time, error) {
|
||||
return time.ParseInLocation(fmt, str, time.Local)
|
||||
}
|
||||
|
||||
func unixEpoch(date time.Time) string {
|
||||
return strconv.FormatInt(date.Unix(), 10)
|
||||
}
|
||||
122
vendor/github.com/Masterminds/sprig/v3/defaults.go
generated
vendored
Normal file
122
vendor/github.com/Masterminds/sprig/v3/defaults.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dfault checks whether `given` is set, and returns default if not set.
|
||||
//
|
||||
// This returns `d` if `given` appears not to be set, and `given` otherwise.
|
||||
//
|
||||
// For numeric types 0 is unset.
|
||||
// For strings, maps, arrays, and slices, len() = 0 is considered unset.
|
||||
// For bool, false is unset.
|
||||
// Structs are never considered unset.
|
||||
//
|
||||
// For everything else, including pointers, a nil value is unset.
|
||||
func dfault(d interface{}, given ...interface{}) interface{} {
|
||||
|
||||
if empty(given) || empty(given[0]) {
|
||||
return d
|
||||
}
|
||||
return given[0]
|
||||
}
|
||||
|
||||
// empty returns true if the given value has the zero value for its type.
|
||||
func empty(given interface{}) bool {
|
||||
g := reflect.ValueOf(given)
|
||||
if !g.IsValid() {
|
||||
return true
|
||||
}
|
||||
|
||||
// Basically adapted from text/template.isTrue
|
||||
switch g.Kind() {
|
||||
default:
|
||||
return g.IsNil()
|
||||
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
|
||||
return g.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !g.Bool()
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return g.Complex() == 0
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return g.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return g.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return g.Float() == 0
|
||||
case reflect.Struct:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// coalesce returns the first non-empty value.
|
||||
func coalesce(v ...interface{}) interface{} {
|
||||
for _, val := range v {
|
||||
if !empty(val) {
|
||||
return val
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// toJson encodes an item into a JSON string
|
||||
func toJson(v interface{}) string {
|
||||
output, _ := json.Marshal(v)
|
||||
return string(output)
|
||||
}
|
||||
|
||||
func mustToJson(v interface{}) (string, error) {
|
||||
output, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
// toPrettyJson encodes an item into a pretty (indented) JSON string
|
||||
func toPrettyJson(v interface{}) string {
|
||||
output, _ := json.MarshalIndent(v, "", " ")
|
||||
return string(output)
|
||||
}
|
||||
|
||||
func mustToPrettyJson(v interface{}) (string, error) {
|
||||
output, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
// toRawJson encodes an item into a JSON string with no escaping of HTML characters.
|
||||
func toRawJson(v interface{}) string {
|
||||
output, err := mustToRawJson(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(output)
|
||||
}
|
||||
|
||||
// mustToRawJson encodes an item into a JSON string with no escaping of HTML characters.
|
||||
func mustToRawJson(v interface{}) (string, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
err := enc.Encode(&v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSuffix(buf.String(), "\n"), nil
|
||||
}
|
||||
|
||||
// ternary returns the first value if the last value is true, otherwise returns the second value.
|
||||
func ternary(vt interface{}, vf interface{}, v bool) interface{} {
|
||||
if v {
|
||||
return vt
|
||||
}
|
||||
|
||||
return vf
|
||||
}
|
||||
148
vendor/github.com/Masterminds/sprig/v3/dict.go
generated
vendored
Normal file
148
vendor/github.com/Masterminds/sprig/v3/dict.go
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/mitchellh/copystructure"
|
||||
)
|
||||
|
||||
func get(d map[string]interface{}, key string) interface{} {
|
||||
if val, ok := d[key]; ok {
|
||||
return val
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} {
|
||||
d[key] = value
|
||||
return d
|
||||
}
|
||||
|
||||
func unset(d map[string]interface{}, key string) map[string]interface{} {
|
||||
delete(d, key)
|
||||
return d
|
||||
}
|
||||
|
||||
func hasKey(d map[string]interface{}, key string) bool {
|
||||
_, ok := d[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func pluck(key string, d ...map[string]interface{}) []interface{} {
|
||||
res := []interface{}{}
|
||||
for _, dict := range d {
|
||||
if val, ok := dict[key]; ok {
|
||||
res = append(res, val)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func keys(dicts ...map[string]interface{}) []string {
|
||||
k := []string{}
|
||||
for _, dict := range dicts {
|
||||
for key := range dict {
|
||||
k = append(k, key)
|
||||
}
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
func pick(dict map[string]interface{}, keys ...string) map[string]interface{} {
|
||||
res := map[string]interface{}{}
|
||||
for _, k := range keys {
|
||||
if v, ok := dict[k]; ok {
|
||||
res[k] = v
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func omit(dict map[string]interface{}, keys ...string) map[string]interface{} {
|
||||
res := map[string]interface{}{}
|
||||
|
||||
omit := make(map[string]bool, len(keys))
|
||||
for _, k := range keys {
|
||||
omit[k] = true
|
||||
}
|
||||
|
||||
for k, v := range dict {
|
||||
if _, ok := omit[k]; !ok {
|
||||
res[k] = v
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func dict(v ...interface{}) map[string]interface{} {
|
||||
dict := map[string]interface{}{}
|
||||
lenv := len(v)
|
||||
for i := 0; i < lenv; i += 2 {
|
||||
key := strval(v[i])
|
||||
if i+1 >= lenv {
|
||||
dict[key] = ""
|
||||
continue
|
||||
}
|
||||
dict[key] = v[i+1]
|
||||
}
|
||||
return dict
|
||||
}
|
||||
|
||||
func merge(dst map[string]interface{}, srcs ...map[string]interface{}) interface{} {
|
||||
for _, src := range srcs {
|
||||
if err := mergo.Merge(&dst, src); err != nil {
|
||||
// Swallow errors inside of a template.
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func mustMerge(dst map[string]interface{}, srcs ...map[string]interface{}) (interface{}, error) {
|
||||
for _, src := range srcs {
|
||||
if err := mergo.Merge(&dst, src); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func mergeOverwrite(dst map[string]interface{}, srcs ...map[string]interface{}) interface{} {
|
||||
for _, src := range srcs {
|
||||
if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
|
||||
// Swallow errors inside of a template.
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func mustMergeOverwrite(dst map[string]interface{}, srcs ...map[string]interface{}) (interface{}, error) {
|
||||
for _, src := range srcs {
|
||||
if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func values(dict map[string]interface{}) []interface{} {
|
||||
values := []interface{}{}
|
||||
for _, value := range dict {
|
||||
values = append(values, value)
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
func deepCopy(i interface{}) interface{} {
|
||||
c, err := mustDeepCopy(i)
|
||||
if err != nil {
|
||||
panic("deepCopy error: " + err.Error())
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func mustDeepCopy(i interface{}) (interface{}, error) {
|
||||
return copystructure.Copy(i)
|
||||
}
|
||||
19
vendor/github.com/Masterminds/sprig/v3/doc.go
generated
vendored
Normal file
19
vendor/github.com/Masterminds/sprig/v3/doc.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Package sprig provides template functions for Go.
|
||||
|
||||
This package contains a number of utility functions for working with data
|
||||
inside of Go `html/template` and `text/template` files.
|
||||
|
||||
To add these functions, use the `template.Funcs()` method:
|
||||
|
||||
t := templates.New("foo").Funcs(sprig.FuncMap())
|
||||
|
||||
Note that you should add the function map before you parse any template files.
|
||||
|
||||
In several cases, Sprig reverses the order of arguments from the way they
|
||||
appear in the standard library. This is to make it easier to pipe
|
||||
arguments into functions.
|
||||
|
||||
See http://masterminds.github.io/sprig/ for more detailed documentation on each of the available functions.
|
||||
*/
|
||||
package sprig
|
||||
336
vendor/github.com/Masterminds/sprig/v3/functions.go
generated
vendored
Normal file
336
vendor/github.com/Masterminds/sprig/v3/functions.go
generated
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"html/template"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
ttemplate "text/template"
|
||||
"time"
|
||||
|
||||
util "github.com/Masterminds/goutils"
|
||||
"github.com/huandu/xstrings"
|
||||
)
|
||||
|
||||
// FuncMap produces the function map.
|
||||
//
|
||||
// Use this to pass the functions into the template engine:
|
||||
//
|
||||
// tpl := template.New("foo").Funcs(sprig.FuncMap()))
|
||||
//
|
||||
func FuncMap() template.FuncMap {
|
||||
return HtmlFuncMap()
|
||||
}
|
||||
|
||||
// HermeticTxtFuncMap returns a 'text/template'.FuncMap with only repeatable functions.
|
||||
func HermeticTxtFuncMap() ttemplate.FuncMap {
|
||||
r := TxtFuncMap()
|
||||
for _, name := range nonhermeticFunctions {
|
||||
delete(r, name)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// HermeticHtmlFuncMap returns an 'html/template'.Funcmap with only repeatable functions.
|
||||
func HermeticHtmlFuncMap() template.FuncMap {
|
||||
r := HtmlFuncMap()
|
||||
for _, name := range nonhermeticFunctions {
|
||||
delete(r, name)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// TxtFuncMap returns a 'text/template'.FuncMap
|
||||
func TxtFuncMap() ttemplate.FuncMap {
|
||||
return ttemplate.FuncMap(GenericFuncMap())
|
||||
}
|
||||
|
||||
// HtmlFuncMap returns an 'html/template'.Funcmap
|
||||
func HtmlFuncMap() template.FuncMap {
|
||||
return template.FuncMap(GenericFuncMap())
|
||||
}
|
||||
|
||||
// GenericFuncMap returns a copy of the basic function map as a map[string]interface{}.
|
||||
func GenericFuncMap() map[string]interface{} {
|
||||
gfm := make(map[string]interface{}, len(genericMap))
|
||||
for k, v := range genericMap {
|
||||
gfm[k] = v
|
||||
}
|
||||
return gfm
|
||||
}
|
||||
|
||||
// These functions are not guaranteed to evaluate to the same result for given input, because they
|
||||
// refer to the environment or global state.
|
||||
var nonhermeticFunctions = []string{
|
||||
// Date functions
|
||||
"date",
|
||||
"date_in_zone",
|
||||
"date_modify",
|
||||
"now",
|
||||
"htmlDate",
|
||||
"htmlDateInZone",
|
||||
"dateInZone",
|
||||
"dateModify",
|
||||
|
||||
// Strings
|
||||
"randAlphaNum",
|
||||
"randAlpha",
|
||||
"randAscii",
|
||||
"randNumeric",
|
||||
"uuidv4",
|
||||
|
||||
// OS
|
||||
"env",
|
||||
"expandenv",
|
||||
|
||||
// Network
|
||||
"getHostByName",
|
||||
}
|
||||
|
||||
var genericMap = map[string]interface{}{
|
||||
"hello": func() string { return "Hello!" },
|
||||
|
||||
// Date functions
|
||||
"ago": dateAgo,
|
||||
"date": date,
|
||||
"date_in_zone": dateInZone,
|
||||
"date_modify": dateModify,
|
||||
"dateInZone": dateInZone,
|
||||
"dateModify": dateModify,
|
||||
"durationRound": durationRound,
|
||||
"htmlDate": htmlDate,
|
||||
"htmlDateInZone": htmlDateInZone,
|
||||
"must_date_modify": mustDateModify,
|
||||
"mustDateModify": mustDateModify,
|
||||
"mustToDate": mustToDate,
|
||||
"now": func() time.Time { return time.Now() },
|
||||
"toDate": toDate,
|
||||
"unixEpoch": unixEpoch,
|
||||
|
||||
// Strings
|
||||
"abbrev": abbrev,
|
||||
"abbrevboth": abbrevboth,
|
||||
"trunc": trunc,
|
||||
"trim": strings.TrimSpace,
|
||||
"upper": strings.ToUpper,
|
||||
"lower": strings.ToLower,
|
||||
"title": strings.Title,
|
||||
"untitle": untitle,
|
||||
"substr": substring,
|
||||
// Switch order so that "foo" | repeat 5
|
||||
"repeat": func(count int, str string) string { return strings.Repeat(str, count) },
|
||||
// Deprecated: Use trimAll.
|
||||
"trimall": func(a, b string) string { return strings.Trim(b, a) },
|
||||
// Switch order so that "$foo" | trimall "$"
|
||||
"trimAll": func(a, b string) string { return strings.Trim(b, a) },
|
||||
"trimSuffix": func(a, b string) string { return strings.TrimSuffix(b, a) },
|
||||
"trimPrefix": func(a, b string) string { return strings.TrimPrefix(b, a) },
|
||||
"nospace": util.DeleteWhiteSpace,
|
||||
"initials": initials,
|
||||
"randAlphaNum": randAlphaNumeric,
|
||||
"randAlpha": randAlpha,
|
||||
"randAscii": randAscii,
|
||||
"randNumeric": randNumeric,
|
||||
"swapcase": util.SwapCase,
|
||||
"shuffle": xstrings.Shuffle,
|
||||
"snakecase": xstrings.ToSnakeCase,
|
||||
"camelcase": xstrings.ToCamelCase,
|
||||
"kebabcase": xstrings.ToKebabCase,
|
||||
"wrap": func(l int, s string) string { return util.Wrap(s, l) },
|
||||
"wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) },
|
||||
// Switch order so that "foobar" | contains "foo"
|
||||
"contains": func(substr string, str string) bool { return strings.Contains(str, substr) },
|
||||
"hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) },
|
||||
"hasSuffix": func(substr string, str string) bool { return strings.HasSuffix(str, substr) },
|
||||
"quote": quote,
|
||||
"squote": squote,
|
||||
"cat": cat,
|
||||
"indent": indent,
|
||||
"nindent": nindent,
|
||||
"replace": replace,
|
||||
"plural": plural,
|
||||
"sha1sum": sha1sum,
|
||||
"sha256sum": sha256sum,
|
||||
"adler32sum": adler32sum,
|
||||
"toString": strval,
|
||||
|
||||
// Wrap Atoi to stop errors.
|
||||
"atoi": func(a string) int { i, _ := strconv.Atoi(a); return i },
|
||||
"int64": toInt64,
|
||||
"int": toInt,
|
||||
"float64": toFloat64,
|
||||
"toDecimal": toDecimal,
|
||||
|
||||
//"gt": func(a, b int) bool {return a > b},
|
||||
//"gte": func(a, b int) bool {return a >= b},
|
||||
//"lt": func(a, b int) bool {return a < b},
|
||||
//"lte": func(a, b int) bool {return a <= b},
|
||||
|
||||
// split "/" foo/bar returns map[int]string{0: foo, 1: bar}
|
||||
"split": split,
|
||||
"splitList": func(sep, orig string) []string { return strings.Split(orig, sep) },
|
||||
// splitn "/" foo/bar/fuu returns map[int]string{0: foo, 1: bar/fuu}
|
||||
"splitn": splitn,
|
||||
"toStrings": strslice,
|
||||
|
||||
"until": until,
|
||||
"untilStep": untilStep,
|
||||
|
||||
// VERY basic arithmetic.
|
||||
"add1": func(i interface{}) int64 { return toInt64(i) + 1 },
|
||||
"add": func(i ...interface{}) int64 {
|
||||
var a int64 = 0
|
||||
for _, b := range i {
|
||||
a += toInt64(b)
|
||||
}
|
||||
return a
|
||||
},
|
||||
"sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) },
|
||||
"div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) },
|
||||
"mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) },
|
||||
"mul": func(a interface{}, v ...interface{}) int64 {
|
||||
val := toInt64(a)
|
||||
for _, b := range v {
|
||||
val = val * toInt64(b)
|
||||
}
|
||||
return val
|
||||
},
|
||||
"biggest": max,
|
||||
"max": max,
|
||||
"min": min,
|
||||
"ceil": ceil,
|
||||
"floor": floor,
|
||||
"round": round,
|
||||
|
||||
// string slices. Note that we reverse the order b/c that's better
|
||||
// for template processing.
|
||||
"join": join,
|
||||
"sortAlpha": sortAlpha,
|
||||
|
||||
// Defaults
|
||||
"default": dfault,
|
||||
"empty": empty,
|
||||
"coalesce": coalesce,
|
||||
"compact": compact,
|
||||
"mustCompact": mustCompact,
|
||||
"toJson": toJson,
|
||||
"toPrettyJson": toPrettyJson,
|
||||
"toRawJson": toRawJson,
|
||||
"mustToJson": mustToJson,
|
||||
"mustToPrettyJson": mustToPrettyJson,
|
||||
"mustToRawJson": mustToRawJson,
|
||||
"ternary": ternary,
|
||||
"deepCopy": deepCopy,
|
||||
"mustDeepCopy": mustDeepCopy,
|
||||
|
||||
// Reflection
|
||||
"typeOf": typeOf,
|
||||
"typeIs": typeIs,
|
||||
"typeIsLike": typeIsLike,
|
||||
"kindOf": kindOf,
|
||||
"kindIs": kindIs,
|
||||
"deepEqual": reflect.DeepEqual,
|
||||
|
||||
// OS:
|
||||
"env": func(s string) string { return os.Getenv(s) },
|
||||
"expandenv": func(s string) string { return os.ExpandEnv(s) },
|
||||
|
||||
// Network:
|
||||
"getHostByName": getHostByName,
|
||||
|
||||
// File Paths:
|
||||
"base": path.Base,
|
||||
"dir": path.Dir,
|
||||
"clean": path.Clean,
|
||||
"ext": path.Ext,
|
||||
"isAbs": path.IsAbs,
|
||||
|
||||
// Encoding:
|
||||
"b64enc": base64encode,
|
||||
"b64dec": base64decode,
|
||||
"b32enc": base32encode,
|
||||
"b32dec": base32decode,
|
||||
|
||||
// Data Structures:
|
||||
"tuple": list, // FIXME: with the addition of append/prepend these are no longer immutable.
|
||||
"list": list,
|
||||
"dict": dict,
|
||||
"get": get,
|
||||
"set": set,
|
||||
"unset": unset,
|
||||
"hasKey": hasKey,
|
||||
"pluck": pluck,
|
||||
"keys": keys,
|
||||
"pick": pick,
|
||||
"omit": omit,
|
||||
"merge": merge,
|
||||
"mergeOverwrite": mergeOverwrite,
|
||||
"mustMerge": mustMerge,
|
||||
"mustMergeOverwrite": mustMergeOverwrite,
|
||||
"values": values,
|
||||
|
||||
"append": push, "push": push,
|
||||
"mustAppend": mustPush, "mustPush": mustPush,
|
||||
"prepend": prepend,
|
||||
"mustPrepend": mustPrepend,
|
||||
"first": first,
|
||||
"mustFirst": mustFirst,
|
||||
"rest": rest,
|
||||
"mustRest": mustRest,
|
||||
"last": last,
|
||||
"mustLast": mustLast,
|
||||
"initial": initial,
|
||||
"mustInitial": mustInitial,
|
||||
"reverse": reverse,
|
||||
"mustReverse": mustReverse,
|
||||
"uniq": uniq,
|
||||
"mustUniq": mustUniq,
|
||||
"without": without,
|
||||
"mustWithout": mustWithout,
|
||||
"has": has,
|
||||
"mustHas": mustHas,
|
||||
"slice": slice,
|
||||
"mustSlice": mustSlice,
|
||||
"concat": concat,
|
||||
|
||||
// Crypto:
|
||||
"genPrivateKey": generatePrivateKey,
|
||||
"derivePassword": derivePassword,
|
||||
"buildCustomCert": buildCustomCertificate,
|
||||
"genCA": generateCertificateAuthority,
|
||||
"genSelfSignedCert": generateSelfSignedCertificate,
|
||||
"genSignedCert": generateSignedCertificate,
|
||||
"encryptAES": encryptAES,
|
||||
"decryptAES": decryptAES,
|
||||
|
||||
// UUIDs:
|
||||
"uuidv4": uuidv4,
|
||||
|
||||
// SemVer:
|
||||
"semver": semver,
|
||||
"semverCompare": semverCompare,
|
||||
|
||||
// Flow Control:
|
||||
"fail": func(msg string) (string, error) { return "", errors.New(msg) },
|
||||
|
||||
// Regex
|
||||
"regexMatch": regexMatch,
|
||||
"mustRegexMatch": mustRegexMatch,
|
||||
"regexFindAll": regexFindAll,
|
||||
"mustRegexFindAll": mustRegexFindAll,
|
||||
"regexFind": regexFind,
|
||||
"mustRegexFind": mustRegexFind,
|
||||
"regexReplaceAll": regexReplaceAll,
|
||||
"mustRegexReplaceAll": mustRegexReplaceAll,
|
||||
"regexReplaceAllLiteral": regexReplaceAllLiteral,
|
||||
"mustRegexReplaceAllLiteral": mustRegexReplaceAllLiteral,
|
||||
"regexSplit": regexSplit,
|
||||
"mustRegexSplit": mustRegexSplit,
|
||||
|
||||
// URLs:
|
||||
"urlParse": urlParse,
|
||||
"urlJoin": urlJoin,
|
||||
}
|
||||
15
vendor/github.com/Masterminds/sprig/v3/go.mod
generated
vendored
Normal file
15
vendor/github.com/Masterminds/sprig/v3/go.mod
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
module github.com/Masterminds/sprig/v3
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/Masterminds/goutils v1.1.0
|
||||
github.com/Masterminds/semver/v3 v3.0.1
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/huandu/xstrings v1.2.0
|
||||
github.com/imdario/mergo v0.3.7
|
||||
github.com/mitchellh/copystructure v1.0.0
|
||||
github.com/spf13/cast v1.3.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7
|
||||
)
|
||||
36
vendor/github.com/Masterminds/sprig/v3/go.sum
generated
vendored
Normal file
36
vendor/github.com/Masterminds/sprig/v3/go.sum
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.0.1 h1:2kKm5lb7dKVrt5TYUiAavE6oFc1cFT0057UVGT+JqLk=
|
||||
github.com/Masterminds/semver/v3 v3.0.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=
|
||||
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
||||
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
|
||||
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
419
vendor/github.com/Masterminds/sprig/v3/list.go
generated
vendored
Normal file
419
vendor/github.com/Masterminds/sprig/v3/list.go
generated
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Reflection is used in these functions so that slices and arrays of strings,
|
||||
// ints, and other types not implementing []interface{} can be worked with.
|
||||
// For example, this is useful if you need to work on the output of regexs.
|
||||
|
||||
func list(v ...interface{}) []interface{} {
|
||||
return v
|
||||
}
|
||||
|
||||
func push(list interface{}, v interface{}) []interface{} {
|
||||
l, err := mustPush(list, v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustPush(list interface{}, v interface{}) ([]interface{}, error) {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
nl := make([]interface{}, l)
|
||||
for i := 0; i < l; i++ {
|
||||
nl[i] = l2.Index(i).Interface()
|
||||
}
|
||||
|
||||
return append(nl, v), nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot push on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func prepend(list interface{}, v interface{}) []interface{} {
|
||||
l, err := mustPrepend(list, v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustPrepend(list interface{}, v interface{}) ([]interface{}, error) {
|
||||
//return append([]interface{}{v}, list...)
|
||||
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
nl := make([]interface{}, l)
|
||||
for i := 0; i < l; i++ {
|
||||
nl[i] = l2.Index(i).Interface()
|
||||
}
|
||||
|
||||
return append([]interface{}{v}, nl...), nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot prepend on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func last(list interface{}) interface{} {
|
||||
l, err := mustLast(list)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustLast(list interface{}) (interface{}, error) {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
if l == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return l2.Index(l - 1).Interface(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find last on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func first(list interface{}) interface{} {
|
||||
l, err := mustFirst(list)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustFirst(list interface{}) (interface{}, error) {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
if l == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return l2.Index(0).Interface(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find first on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func rest(list interface{}) []interface{} {
|
||||
l, err := mustRest(list)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustRest(list interface{}) ([]interface{}, error) {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
if l == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nl := make([]interface{}, l-1)
|
||||
for i := 1; i < l; i++ {
|
||||
nl[i-1] = l2.Index(i).Interface()
|
||||
}
|
||||
|
||||
return nl, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find rest on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func initial(list interface{}) []interface{} {
|
||||
l, err := mustInitial(list)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustInitial(list interface{}) ([]interface{}, error) {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
if l == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
nl := make([]interface{}, l-1)
|
||||
for i := 0; i < l-1; i++ {
|
||||
nl[i] = l2.Index(i).Interface()
|
||||
}
|
||||
|
||||
return nl, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find initial on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func sortAlpha(list interface{}) []string {
|
||||
k := reflect.Indirect(reflect.ValueOf(list)).Kind()
|
||||
switch k {
|
||||
case reflect.Slice, reflect.Array:
|
||||
a := strslice(list)
|
||||
s := sort.StringSlice(a)
|
||||
s.Sort()
|
||||
return s
|
||||
}
|
||||
return []string{strval(list)}
|
||||
}
|
||||
|
||||
func reverse(v interface{}) []interface{} {
|
||||
l, err := mustReverse(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustReverse(v interface{}) ([]interface{}, error) {
|
||||
tp := reflect.TypeOf(v).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(v)
|
||||
|
||||
l := l2.Len()
|
||||
// We do not sort in place because the incoming array should not be altered.
|
||||
nl := make([]interface{}, l)
|
||||
for i := 0; i < l; i++ {
|
||||
nl[l-i-1] = l2.Index(i).Interface()
|
||||
}
|
||||
|
||||
return nl, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find reverse on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func compact(list interface{}) []interface{} {
|
||||
l, err := mustCompact(list)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustCompact(list interface{}) ([]interface{}, error) {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
nl := []interface{}{}
|
||||
var item interface{}
|
||||
for i := 0; i < l; i++ {
|
||||
item = l2.Index(i).Interface()
|
||||
if !empty(item) {
|
||||
nl = append(nl, item)
|
||||
}
|
||||
}
|
||||
|
||||
return nl, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot compact on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func uniq(list interface{}) []interface{} {
|
||||
l, err := mustUniq(list)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustUniq(list interface{}) ([]interface{}, error) {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
dest := []interface{}{}
|
||||
var item interface{}
|
||||
for i := 0; i < l; i++ {
|
||||
item = l2.Index(i).Interface()
|
||||
if !inList(dest, item) {
|
||||
dest = append(dest, item)
|
||||
}
|
||||
}
|
||||
|
||||
return dest, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find uniq on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func inList(haystack []interface{}, needle interface{}) bool {
|
||||
for _, h := range haystack {
|
||||
if reflect.DeepEqual(needle, h) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func without(list interface{}, omit ...interface{}) []interface{} {
|
||||
l, err := mustWithout(list, omit...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustWithout(list interface{}, omit ...interface{}) ([]interface{}, error) {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
res := []interface{}{}
|
||||
var item interface{}
|
||||
for i := 0; i < l; i++ {
|
||||
item = l2.Index(i).Interface()
|
||||
if !inList(omit, item) {
|
||||
res = append(res, item)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Cannot find without on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func has(needle interface{}, haystack interface{}) bool {
|
||||
l, err := mustHas(needle, haystack)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustHas(needle interface{}, haystack interface{}) (bool, error) {
|
||||
if haystack == nil {
|
||||
return false, nil
|
||||
}
|
||||
tp := reflect.TypeOf(haystack).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(haystack)
|
||||
var item interface{}
|
||||
l := l2.Len()
|
||||
for i := 0; i < l; i++ {
|
||||
item = l2.Index(i).Interface()
|
||||
if reflect.DeepEqual(needle, item) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
default:
|
||||
return false, fmt.Errorf("Cannot find has on type %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
// $list := [1, 2, 3, 4, 5]
|
||||
// slice $list -> list[0:5] = list[:]
|
||||
// slice $list 0 3 -> list[0:3] = list[:3]
|
||||
// slice $list 3 5 -> list[3:5]
|
||||
// slice $list 3 -> list[3:5] = list[3:]
|
||||
func slice(list interface{}, indices ...interface{}) interface{} {
|
||||
l, err := mustSlice(list, indices...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func mustSlice(list interface{}, indices ...interface{}) (interface{}, error) {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
|
||||
l := l2.Len()
|
||||
if l == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var start, end int
|
||||
if len(indices) > 0 {
|
||||
start = toInt(indices[0])
|
||||
}
|
||||
if len(indices) < 2 {
|
||||
end = l
|
||||
} else {
|
||||
end = toInt(indices[1])
|
||||
}
|
||||
|
||||
return l2.Slice(start, end).Interface(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("list should be type of slice or array but %s", tp)
|
||||
}
|
||||
}
|
||||
|
||||
func concat(lists ...interface{}) interface{} {
|
||||
var res []interface{}
|
||||
for _, list := range lists {
|
||||
tp := reflect.TypeOf(list).Kind()
|
||||
switch tp {
|
||||
case reflect.Slice, reflect.Array:
|
||||
l2 := reflect.ValueOf(list)
|
||||
for i := 0; i < l2.Len(); i++ {
|
||||
res = append(res, l2.Index(i).Interface())
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("Cannot concat type %s as list", tp))
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
12
vendor/github.com/Masterminds/sprig/v3/network.go
generated
vendored
Normal file
12
vendor/github.com/Masterminds/sprig/v3/network.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"net"
|
||||
)
|
||||
|
||||
func getHostByName(name string) string {
|
||||
addrs, _ := net.LookupHost(name)
|
||||
//TODO: add error handing when release v3 cames out
|
||||
return addrs[rand.Intn(len(addrs))]
|
||||
}
|
||||
114
vendor/github.com/Masterminds/sprig/v3/numeric.go
generated
vendored
Normal file
114
vendor/github.com/Masterminds/sprig/v3/numeric.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
// toFloat64 converts 64-bit floats
|
||||
func toFloat64(v interface{}) float64 {
|
||||
return cast.ToFloat64(v)
|
||||
}
|
||||
|
||||
func toInt(v interface{}) int {
|
||||
return cast.ToInt(v)
|
||||
}
|
||||
|
||||
// toInt64 converts integer types to 64-bit integers
|
||||
func toInt64(v interface{}) int64 {
|
||||
return cast.ToInt64(v)
|
||||
}
|
||||
|
||||
func max(a interface{}, i ...interface{}) int64 {
|
||||
aa := toInt64(a)
|
||||
for _, b := range i {
|
||||
bb := toInt64(b)
|
||||
if bb > aa {
|
||||
aa = bb
|
||||
}
|
||||
}
|
||||
return aa
|
||||
}
|
||||
|
||||
func min(a interface{}, i ...interface{}) int64 {
|
||||
aa := toInt64(a)
|
||||
for _, b := range i {
|
||||
bb := toInt64(b)
|
||||
if bb < aa {
|
||||
aa = bb
|
||||
}
|
||||
}
|
||||
return aa
|
||||
}
|
||||
|
||||
func until(count int) []int {
|
||||
step := 1
|
||||
if count < 0 {
|
||||
step = -1
|
||||
}
|
||||
return untilStep(0, count, step)
|
||||
}
|
||||
|
||||
func untilStep(start, stop, step int) []int {
|
||||
v := []int{}
|
||||
|
||||
if stop < start {
|
||||
if step >= 0 {
|
||||
return v
|
||||
}
|
||||
for i := start; i > stop; i += step {
|
||||
v = append(v, i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
if step <= 0 {
|
||||
return v
|
||||
}
|
||||
for i := start; i < stop; i += step {
|
||||
v = append(v, i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func floor(a interface{}) float64 {
|
||||
aa := toFloat64(a)
|
||||
return math.Floor(aa)
|
||||
}
|
||||
|
||||
func ceil(a interface{}) float64 {
|
||||
aa := toFloat64(a)
|
||||
return math.Ceil(aa)
|
||||
}
|
||||
|
||||
func round(a interface{}, p int, rOpt ...float64) float64 {
|
||||
roundOn := .5
|
||||
if len(rOpt) > 0 {
|
||||
roundOn = rOpt[0]
|
||||
}
|
||||
val := toFloat64(a)
|
||||
places := toFloat64(p)
|
||||
|
||||
var round float64
|
||||
pow := math.Pow(10, places)
|
||||
digit := pow * val
|
||||
_, div := math.Modf(digit)
|
||||
if div >= roundOn {
|
||||
round = math.Ceil(digit)
|
||||
} else {
|
||||
round = math.Floor(digit)
|
||||
}
|
||||
return round / pow
|
||||
}
|
||||
|
||||
// converts unix octal to decimal
|
||||
func toDecimal(v interface{}) int64 {
|
||||
result, err := strconv.ParseInt(fmt.Sprint(v), 8, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return result
|
||||
}
|
||||
28
vendor/github.com/Masterminds/sprig/v3/reflect.go
generated
vendored
Normal file
28
vendor/github.com/Masterminds/sprig/v3/reflect.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// typeIs returns true if the src is the type named in target.
|
||||
func typeIs(target string, src interface{}) bool {
|
||||
return target == typeOf(src)
|
||||
}
|
||||
|
||||
func typeIsLike(target string, src interface{}) bool {
|
||||
t := typeOf(src)
|
||||
return target == t || "*"+target == t
|
||||
}
|
||||
|
||||
func typeOf(src interface{}) string {
|
||||
return fmt.Sprintf("%T", src)
|
||||
}
|
||||
|
||||
func kindIs(target string, src interface{}) bool {
|
||||
return target == kindOf(src)
|
||||
}
|
||||
|
||||
func kindOf(src interface{}) string {
|
||||
return reflect.ValueOf(src).Kind().String()
|
||||
}
|
||||
79
vendor/github.com/Masterminds/sprig/v3/regex.go
generated
vendored
Normal file
79
vendor/github.com/Masterminds/sprig/v3/regex.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func regexMatch(regex string, s string) bool {
|
||||
match, _ := regexp.MatchString(regex, s)
|
||||
return match
|
||||
}
|
||||
|
||||
func mustRegexMatch(regex string, s string) (bool, error) {
|
||||
return regexp.MatchString(regex, s)
|
||||
}
|
||||
|
||||
func regexFindAll(regex string, s string, n int) []string {
|
||||
r := regexp.MustCompile(regex)
|
||||
return r.FindAllString(s, n)
|
||||
}
|
||||
|
||||
func mustRegexFindAll(regex string, s string, n int) ([]string, error) {
|
||||
r, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return r.FindAllString(s, n), nil
|
||||
}
|
||||
|
||||
func regexFind(regex string, s string) string {
|
||||
r := regexp.MustCompile(regex)
|
||||
return r.FindString(s)
|
||||
}
|
||||
|
||||
func mustRegexFind(regex string, s string) (string, error) {
|
||||
r, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return r.FindString(s), nil
|
||||
}
|
||||
|
||||
func regexReplaceAll(regex string, s string, repl string) string {
|
||||
r := regexp.MustCompile(regex)
|
||||
return r.ReplaceAllString(s, repl)
|
||||
}
|
||||
|
||||
func mustRegexReplaceAll(regex string, s string, repl string) (string, error) {
|
||||
r, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return r.ReplaceAllString(s, repl), nil
|
||||
}
|
||||
|
||||
func regexReplaceAllLiteral(regex string, s string, repl string) string {
|
||||
r := regexp.MustCompile(regex)
|
||||
return r.ReplaceAllLiteralString(s, repl)
|
||||
}
|
||||
|
||||
func mustRegexReplaceAllLiteral(regex string, s string, repl string) (string, error) {
|
||||
r, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return r.ReplaceAllLiteralString(s, repl), nil
|
||||
}
|
||||
|
||||
func regexSplit(regex string, s string, n int) []string {
|
||||
r := regexp.MustCompile(regex)
|
||||
return r.Split(s, n)
|
||||
}
|
||||
|
||||
func mustRegexSplit(regex string, s string, n int) ([]string, error) {
|
||||
r, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return r.Split(s, n), nil
|
||||
}
|
||||
23
vendor/github.com/Masterminds/sprig/v3/semver.go
generated
vendored
Normal file
23
vendor/github.com/Masterminds/sprig/v3/semver.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
sv2 "github.com/Masterminds/semver/v3"
|
||||
)
|
||||
|
||||
func semverCompare(constraint, version string) (bool, error) {
|
||||
c, err := sv2.NewConstraint(constraint)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
v, err := sv2.NewVersion(version)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return c.Check(v), nil
|
||||
}
|
||||
|
||||
func semver(version string) (*sv2.Version, error) {
|
||||
return sv2.NewVersion(version)
|
||||
}
|
||||
236
vendor/github.com/Masterminds/sprig/v3/strings.go
generated
vendored
Normal file
236
vendor/github.com/Masterminds/sprig/v3/strings.go
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
util "github.com/Masterminds/goutils"
|
||||
)
|
||||
|
||||
func base64encode(v string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(v))
|
||||
}
|
||||
|
||||
func base64decode(v string) string {
|
||||
data, err := base64.StdEncoding.DecodeString(v)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func base32encode(v string) string {
|
||||
return base32.StdEncoding.EncodeToString([]byte(v))
|
||||
}
|
||||
|
||||
func base32decode(v string) string {
|
||||
data, err := base32.StdEncoding.DecodeString(v)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func abbrev(width int, s string) string {
|
||||
if width < 4 {
|
||||
return s
|
||||
}
|
||||
r, _ := util.Abbreviate(s, width)
|
||||
return r
|
||||
}
|
||||
|
||||
func abbrevboth(left, right int, s string) string {
|
||||
if right < 4 || left > 0 && right < 7 {
|
||||
return s
|
||||
}
|
||||
r, _ := util.AbbreviateFull(s, left, right)
|
||||
return r
|
||||
}
|
||||
func initials(s string) string {
|
||||
// Wrap this just to eliminate the var args, which templates don't do well.
|
||||
return util.Initials(s)
|
||||
}
|
||||
|
||||
func randAlphaNumeric(count int) string {
|
||||
// It is not possible, it appears, to actually generate an error here.
|
||||
r, _ := util.CryptoRandomAlphaNumeric(count)
|
||||
return r
|
||||
}
|
||||
|
||||
func randAlpha(count int) string {
|
||||
r, _ := util.CryptoRandomAlphabetic(count)
|
||||
return r
|
||||
}
|
||||
|
||||
func randAscii(count int) string {
|
||||
r, _ := util.CryptoRandomAscii(count)
|
||||
return r
|
||||
}
|
||||
|
||||
func randNumeric(count int) string {
|
||||
r, _ := util.CryptoRandomNumeric(count)
|
||||
return r
|
||||
}
|
||||
|
||||
func untitle(str string) string {
|
||||
return util.Uncapitalize(str)
|
||||
}
|
||||
|
||||
func quote(str ...interface{}) string {
|
||||
out := make([]string, 0, len(str))
|
||||
for _, s := range str {
|
||||
if s != nil {
|
||||
out = append(out, fmt.Sprintf("%q", strval(s)))
|
||||
}
|
||||
}
|
||||
return strings.Join(out, " ")
|
||||
}
|
||||
|
||||
func squote(str ...interface{}) string {
|
||||
out := make([]string, 0, len(str))
|
||||
for _, s := range str {
|
||||
if s != nil {
|
||||
out = append(out, fmt.Sprintf("'%v'", s))
|
||||
}
|
||||
}
|
||||
return strings.Join(out, " ")
|
||||
}
|
||||
|
||||
func cat(v ...interface{}) string {
|
||||
v = removeNilElements(v)
|
||||
r := strings.TrimSpace(strings.Repeat("%v ", len(v)))
|
||||
return fmt.Sprintf(r, v...)
|
||||
}
|
||||
|
||||
func indent(spaces int, v string) string {
|
||||
pad := strings.Repeat(" ", spaces)
|
||||
return pad + strings.Replace(v, "\n", "\n"+pad, -1)
|
||||
}
|
||||
|
||||
func nindent(spaces int, v string) string {
|
||||
return "\n" + indent(spaces, v)
|
||||
}
|
||||
|
||||
func replace(old, new, src string) string {
|
||||
return strings.Replace(src, old, new, -1)
|
||||
}
|
||||
|
||||
func plural(one, many string, count int) string {
|
||||
if count == 1 {
|
||||
return one
|
||||
}
|
||||
return many
|
||||
}
|
||||
|
||||
func strslice(v interface{}) []string {
|
||||
switch v := v.(type) {
|
||||
case []string:
|
||||
return v
|
||||
case []interface{}:
|
||||
b := make([]string, 0, len(v))
|
||||
for _, s := range v {
|
||||
if s != nil {
|
||||
b = append(b, strval(s))
|
||||
}
|
||||
}
|
||||
return b
|
||||
default:
|
||||
val := reflect.ValueOf(v)
|
||||
switch val.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
l := val.Len()
|
||||
b := make([]string, 0, l)
|
||||
for i := 0; i < l; i++ {
|
||||
value := val.Index(i).Interface()
|
||||
if value != nil {
|
||||
b = append(b, strval(value))
|
||||
}
|
||||
}
|
||||
return b
|
||||
default:
|
||||
if v == nil {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
return []string{strval(v)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeNilElements(v []interface{}) []interface{} {
|
||||
newSlice := make([]interface{}, 0, len(v))
|
||||
for _, i := range v {
|
||||
if i != nil {
|
||||
newSlice = append(newSlice, i)
|
||||
}
|
||||
}
|
||||
return newSlice
|
||||
}
|
||||
|
||||
func strval(v interface{}) string {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []byte:
|
||||
return string(v)
|
||||
case error:
|
||||
return v.Error()
|
||||
case fmt.Stringer:
|
||||
return v.String()
|
||||
default:
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func trunc(c int, s string) string {
|
||||
if c < 0 && len(s)+c > 0 {
|
||||
return s[len(s)+c:]
|
||||
}
|
||||
if c >= 0 && len(s) > c {
|
||||
return s[:c]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func join(sep string, v interface{}) string {
|
||||
return strings.Join(strslice(v), sep)
|
||||
}
|
||||
|
||||
func split(sep, orig string) map[string]string {
|
||||
parts := strings.Split(orig, sep)
|
||||
res := make(map[string]string, len(parts))
|
||||
for i, v := range parts {
|
||||
res["_"+strconv.Itoa(i)] = v
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func splitn(sep string, n int, orig string) map[string]string {
|
||||
parts := strings.SplitN(orig, sep, n)
|
||||
res := make(map[string]string, len(parts))
|
||||
for i, v := range parts {
|
||||
res["_"+strconv.Itoa(i)] = v
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// substring creates a substring of the given string.
|
||||
//
|
||||
// If start is < 0, this calls string[:end].
|
||||
//
|
||||
// If start is >= 0 and end < 0 or end bigger than s length, this calls string[start:]
|
||||
//
|
||||
// Otherwise, this calls string[start, end].
|
||||
func substring(start, end int, s string) string {
|
||||
if start < 0 {
|
||||
return s[:end]
|
||||
}
|
||||
if end < 0 || end > len(s) {
|
||||
return s[start:]
|
||||
}
|
||||
return s[start:end]
|
||||
}
|
||||
66
vendor/github.com/Masterminds/sprig/v3/url.go
generated
vendored
Normal file
66
vendor/github.com/Masterminds/sprig/v3/url.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package sprig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func dictGetOrEmpty(dict map[string]interface{}, key string) string {
|
||||
value, ok := dict[key]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
tp := reflect.TypeOf(value).Kind()
|
||||
if tp != reflect.String {
|
||||
panic(fmt.Sprintf("unable to parse %s key, must be of type string, but %s found", key, tp.String()))
|
||||
}
|
||||
return reflect.ValueOf(value).String()
|
||||
}
|
||||
|
||||
// parses given URL to return dict object
|
||||
func urlParse(v string) map[string]interface{} {
|
||||
dict := map[string]interface{}{}
|
||||
parsedURL, err := url.Parse(v)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unable to parse url: %s", err))
|
||||
}
|
||||
dict["scheme"] = parsedURL.Scheme
|
||||
dict["host"] = parsedURL.Host
|
||||
dict["hostname"] = parsedURL.Hostname()
|
||||
dict["path"] = parsedURL.Path
|
||||
dict["query"] = parsedURL.RawQuery
|
||||
dict["opaque"] = parsedURL.Opaque
|
||||
dict["fragment"] = parsedURL.Fragment
|
||||
if parsedURL.User != nil {
|
||||
dict["userinfo"] = parsedURL.User.String()
|
||||
} else {
|
||||
dict["userinfo"] = ""
|
||||
}
|
||||
|
||||
return dict
|
||||
}
|
||||
|
||||
// join given dict to URL string
|
||||
func urlJoin(d map[string]interface{}) string {
|
||||
resURL := url.URL{
|
||||
Scheme: dictGetOrEmpty(d, "scheme"),
|
||||
Host: dictGetOrEmpty(d, "host"),
|
||||
Path: dictGetOrEmpty(d, "path"),
|
||||
RawQuery: dictGetOrEmpty(d, "query"),
|
||||
Opaque: dictGetOrEmpty(d, "opaque"),
|
||||
Fragment: dictGetOrEmpty(d, "fragment"),
|
||||
}
|
||||
userinfo := dictGetOrEmpty(d, "userinfo")
|
||||
var user *url.Userinfo
|
||||
if userinfo != "" {
|
||||
tempURL, err := url.Parse(fmt.Sprintf("proto://%s@host", userinfo))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unable to parse userinfo in dict: %s", err))
|
||||
}
|
||||
user = tempURL.User
|
||||
}
|
||||
|
||||
resURL.User = user
|
||||
return resURL.String()
|
||||
}
|
||||
1
vendor/github.com/Masterminds/squirrel/.gitignore
generated
vendored
Normal file
1
vendor/github.com/Masterminds/squirrel/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
squirrel.test
|
||||
22
vendor/github.com/Masterminds/squirrel/.travis.yml
generated
vendored
Normal file
22
vendor/github.com/Masterminds/squirrel/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- tip
|
||||
|
||||
# Setting sudo access to false will let Travis CI use containers rather than
|
||||
# VMs to run the tests. For more details see:
|
||||
# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/
|
||||
# - http://docs.travis-ci.com/user/workers/standard-infrastructure/
|
||||
sudo: false
|
||||
|
||||
install:
|
||||
- go get
|
||||
- go get github.com/stretchr/testify/assert
|
||||
|
||||
notifications:
|
||||
irc: "irc.freenode.net#masterminds"
|
||||
23
vendor/github.com/Masterminds/squirrel/LICENSE.txt
generated
vendored
Normal file
23
vendor/github.com/Masterminds/squirrel/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Squirrel
|
||||
The Masterminds
|
||||
Copyright (C) 2014-2015, Lann Martin
|
||||
Copyright (C) 2015-2016, Google
|
||||
Copyright (C) 2015, Matt Farina and Matt Butcher
|
||||
|
||||
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.
|
||||
118
vendor/github.com/Masterminds/squirrel/README.md
generated
vendored
Normal file
118
vendor/github.com/Masterminds/squirrel/README.md
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
# Squirrel - fluent SQL generator for Go
|
||||
|
||||
```go
|
||||
import "gopkg.in/Masterminds/squirrel.v1"
|
||||
```
|
||||
or if you prefer using `master` (which may be arbitrarily ahead of or behind `v1`):
|
||||
|
||||
**NOTE:** as of Go 1.6, `go get` correctly clones the Github default branch (which is `v1` in this repo).
|
||||
```go
|
||||
import "github.com/Masterminds/squirrel"
|
||||
```
|
||||
|
||||
[](https://godoc.org/github.com/Masterminds/squirrel)
|
||||
[](https://travis-ci.org/Masterminds/squirrel)
|
||||
|
||||
_**Note:** This project has moved from `github.com/lann/squirrel` to
|
||||
`github.com/Masterminds/squirrel`. Lann remains the architect of the
|
||||
project, but we're helping him curate.
|
||||
|
||||
**Squirrel is not an ORM.** For an application of Squirrel, check out
|
||||
[structable, a table-struct mapper](https://github.com/technosophos/structable)
|
||||
|
||||
|
||||
Squirrel helps you build SQL queries from composable parts:
|
||||
|
||||
```go
|
||||
import sq "github.com/Masterminds/squirrel"
|
||||
|
||||
users := sq.Select("*").From("users").Join("emails USING (email_id)")
|
||||
|
||||
active := users.Where(sq.Eq{"deleted_at": nil})
|
||||
|
||||
sql, args, err := active.ToSql()
|
||||
|
||||
sql == "SELECT * FROM users JOIN emails USING (email_id) WHERE deleted_at IS NULL"
|
||||
```
|
||||
|
||||
```go
|
||||
sql, args, err := sq.
|
||||
Insert("users").Columns("name", "age").
|
||||
Values("moe", 13).Values("larry", sq.Expr("? + 5", 12)).
|
||||
ToSql()
|
||||
|
||||
sql == "INSERT INTO users (name,age) VALUES (?,?),(?,? + 5)"
|
||||
```
|
||||
|
||||
Squirrel can also execute queries directly:
|
||||
|
||||
```go
|
||||
stooges := users.Where(sq.Eq{"username": []string{"moe", "larry", "curly", "shemp"}})
|
||||
three_stooges := stooges.Limit(3)
|
||||
rows, err := three_stooges.RunWith(db).Query()
|
||||
|
||||
// Behaves like:
|
||||
rows, err := db.Query("SELECT * FROM users WHERE username IN (?,?,?,?) LIMIT 3",
|
||||
"moe", "larry", "curly", "shemp")
|
||||
```
|
||||
|
||||
Squirrel makes conditional query building a breeze:
|
||||
|
||||
```go
|
||||
if len(q) > 0 {
|
||||
users = users.Where("name LIKE ?", fmt.Sprint("%", q, "%"))
|
||||
}
|
||||
```
|
||||
|
||||
Squirrel wants to make your life easier:
|
||||
|
||||
```go
|
||||
// StmtCache caches Prepared Stmts for you
|
||||
dbCache := sq.NewStmtCacher(db)
|
||||
|
||||
// StatementBuilder keeps your syntax neat
|
||||
mydb := sq.StatementBuilder.RunWith(dbCache)
|
||||
select_users := mydb.Select("*").From("users")
|
||||
```
|
||||
|
||||
Squirrel loves PostgreSQL:
|
||||
|
||||
```go
|
||||
psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
|
||||
|
||||
// You use question marks for placeholders...
|
||||
sql, _, _ := psql.Select("*").From("elephants").Where("name IN (?,?)", "Dumbo", "Verna")
|
||||
|
||||
/// ...squirrel replaces them using PlaceholderFormat.
|
||||
sql == "SELECT * FROM elephants WHERE name IN ($1,$2)"
|
||||
|
||||
|
||||
/// You can retrieve id ...
|
||||
query := sq.Insert("nodes").
|
||||
Columns("uuid", "type", "data").
|
||||
Values(node.Uuid, node.Type, node.Data).
|
||||
Suffix("RETURNING \"id\"").
|
||||
RunWith(m.db).
|
||||
PlaceholderFormat(sq.Dollar)
|
||||
|
||||
query.QueryRow().Scan(&node.id)
|
||||
```
|
||||
|
||||
You can escape question mask by inserting two question marks:
|
||||
|
||||
```sql
|
||||
SELECT * FROM nodes WHERE meta->'format' ??| array[?,?]
|
||||
```
|
||||
|
||||
will generate with the Dollar Placeholder:
|
||||
|
||||
```sql
|
||||
SELECT * FROM nodes WHERE meta->'format' ?| array[$1,$2]
|
||||
```
|
||||
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Squirrel is released under the
|
||||
[MIT License](http://www.opensource.org/licenses/MIT).
|
||||
118
vendor/github.com/Masterminds/squirrel/case.go
generated
vendored
Normal file
118
vendor/github.com/Masterminds/squirrel/case.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builder.Register(CaseBuilder{}, caseData{})
|
||||
}
|
||||
|
||||
// sqlizerBuffer is a helper that allows to write many Sqlizers one by one
|
||||
// without constant checks for errors that may come from Sqlizer
|
||||
type sqlizerBuffer struct {
|
||||
bytes.Buffer
|
||||
args []interface{}
|
||||
err error
|
||||
}
|
||||
|
||||
// WriteSql converts Sqlizer to SQL strings and writes it to buffer
|
||||
func (b *sqlizerBuffer) WriteSql(item Sqlizer) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var str string
|
||||
var args []interface{}
|
||||
str, args, b.err = item.ToSql()
|
||||
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b.WriteString(str)
|
||||
b.WriteByte(' ')
|
||||
b.args = append(b.args, args...)
|
||||
}
|
||||
|
||||
func (b *sqlizerBuffer) ToSql() (string, []interface{}, error) {
|
||||
return b.String(), b.args, b.err
|
||||
}
|
||||
|
||||
// whenPart is a helper structure to describe SQLs "WHEN ... THEN ..." expression
|
||||
type whenPart struct {
|
||||
when Sqlizer
|
||||
then Sqlizer
|
||||
}
|
||||
|
||||
func newWhenPart(when interface{}, then interface{}) whenPart {
|
||||
return whenPart{newPart(when), newPart(then)}
|
||||
}
|
||||
|
||||
// caseData holds all the data required to build a CASE SQL construct
|
||||
type caseData struct {
|
||||
What Sqlizer
|
||||
WhenParts []whenPart
|
||||
Else Sqlizer
|
||||
}
|
||||
|
||||
// ToSql implements Sqlizer
|
||||
func (d *caseData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.WhenParts) == 0 {
|
||||
err = errors.New("case expression must contain at lease one WHEN clause")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
sql := sqlizerBuffer{}
|
||||
|
||||
sql.WriteString("CASE ")
|
||||
if d.What != nil {
|
||||
sql.WriteSql(d.What)
|
||||
}
|
||||
|
||||
for _, p := range d.WhenParts {
|
||||
sql.WriteString("WHEN ")
|
||||
sql.WriteSql(p.when)
|
||||
sql.WriteString("THEN ")
|
||||
sql.WriteSql(p.then)
|
||||
}
|
||||
|
||||
if d.Else != nil {
|
||||
sql.WriteString("ELSE ")
|
||||
sql.WriteSql(d.Else)
|
||||
}
|
||||
|
||||
sql.WriteString("END")
|
||||
|
||||
return sql.ToSql()
|
||||
}
|
||||
|
||||
// CaseBuilder builds SQL CASE construct which could be used as parts of queries.
|
||||
type CaseBuilder builder.Builder
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b CaseBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(caseData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
// what sets optional value for CASE construct "CASE [value] ..."
|
||||
func (b CaseBuilder) what(expr interface{}) CaseBuilder {
|
||||
return builder.Set(b, "What", newPart(expr)).(CaseBuilder)
|
||||
}
|
||||
|
||||
// When adds "WHEN ... THEN ..." part to CASE construct
|
||||
func (b CaseBuilder) When(when interface{}, then interface{}) CaseBuilder {
|
||||
// TODO: performance hint: replace slice of WhenPart with just slice of parts
|
||||
// where even indices of the slice belong to "when"s and odd indices belong to "then"s
|
||||
return builder.Append(b, "WhenParts", newWhenPart(when, then)).(CaseBuilder)
|
||||
}
|
||||
|
||||
// What sets optional "ELSE ..." part for CASE construct
|
||||
func (b CaseBuilder) Else(expr interface{}) CaseBuilder {
|
||||
return builder.Set(b, "Else", newPart(expr)).(CaseBuilder)
|
||||
}
|
||||
152
vendor/github.com/Masterminds/squirrel/delete.go
generated
vendored
Normal file
152
vendor/github.com/Masterminds/squirrel/delete.go
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/lann/builder"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type deleteData struct {
|
||||
PlaceholderFormat PlaceholderFormat
|
||||
RunWith BaseRunner
|
||||
Prefixes exprs
|
||||
From string
|
||||
WhereParts []Sqlizer
|
||||
OrderBys []string
|
||||
Limit string
|
||||
Offset string
|
||||
Suffixes exprs
|
||||
}
|
||||
|
||||
func (d *deleteData) Exec() (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return ExecWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *deleteData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.From) == 0 {
|
||||
err = fmt.Errorf("delete statements must specify a From table")
|
||||
return
|
||||
}
|
||||
|
||||
sql := &bytes.Buffer{}
|
||||
|
||||
if len(d.Prefixes) > 0 {
|
||||
args, _ = d.Prefixes.AppendToSql(sql, " ", args)
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
sql.WriteString("DELETE FROM ")
|
||||
sql.WriteString(d.From)
|
||||
|
||||
if len(d.WhereParts) > 0 {
|
||||
sql.WriteString(" WHERE ")
|
||||
args, err = appendToSql(d.WhereParts, sql, " AND ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.OrderBys) > 0 {
|
||||
sql.WriteString(" ORDER BY ")
|
||||
sql.WriteString(strings.Join(d.OrderBys, ", "))
|
||||
}
|
||||
|
||||
if len(d.Limit) > 0 {
|
||||
sql.WriteString(" LIMIT ")
|
||||
sql.WriteString(d.Limit)
|
||||
}
|
||||
|
||||
if len(d.Offset) > 0 {
|
||||
sql.WriteString(" OFFSET ")
|
||||
sql.WriteString(d.Offset)
|
||||
}
|
||||
|
||||
if len(d.Suffixes) > 0 {
|
||||
sql.WriteString(" ")
|
||||
args, _ = d.Suffixes.AppendToSql(sql, " ", args)
|
||||
}
|
||||
|
||||
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Builder
|
||||
|
||||
// DeleteBuilder builds SQL DELETE statements.
|
||||
type DeleteBuilder builder.Builder
|
||||
|
||||
func init() {
|
||||
builder.Register(DeleteBuilder{}, deleteData{})
|
||||
}
|
||||
|
||||
// Format methods
|
||||
|
||||
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
|
||||
// query.
|
||||
func (b DeleteBuilder) PlaceholderFormat(f PlaceholderFormat) DeleteBuilder {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Runner methods
|
||||
|
||||
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
|
||||
func (b DeleteBuilder) RunWith(runner BaseRunner) DeleteBuilder {
|
||||
return setRunWith(b, runner).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Exec builds and Execs the query with the Runner set by RunWith.
|
||||
func (b DeleteBuilder) Exec() (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(deleteData)
|
||||
return data.Exec()
|
||||
}
|
||||
|
||||
// SQL methods
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b DeleteBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(deleteData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
// Prefix adds an expression to the beginning of the query
|
||||
func (b DeleteBuilder) Prefix(sql string, args ...interface{}) DeleteBuilder {
|
||||
return builder.Append(b, "Prefixes", Expr(sql, args...)).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// From sets the table to be deleted from.
|
||||
func (b DeleteBuilder) From(from string) DeleteBuilder {
|
||||
return builder.Set(b, "From", from).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Where adds WHERE expressions to the query.
|
||||
//
|
||||
// See SelectBuilder.Where for more information.
|
||||
func (b DeleteBuilder) Where(pred interface{}, args ...interface{}) DeleteBuilder {
|
||||
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// OrderBy adds ORDER BY expressions to the query.
|
||||
func (b DeleteBuilder) OrderBy(orderBys ...string) DeleteBuilder {
|
||||
return builder.Extend(b, "OrderBys", orderBys).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Limit sets a LIMIT clause on the query.
|
||||
func (b DeleteBuilder) Limit(limit uint64) DeleteBuilder {
|
||||
return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Offset sets a OFFSET clause on the query.
|
||||
func (b DeleteBuilder) Offset(offset uint64) DeleteBuilder {
|
||||
return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Suffix adds an expression to the end of the query
|
||||
func (b DeleteBuilder) Suffix(sql string, args ...interface{}) DeleteBuilder {
|
||||
return builder.Append(b, "Suffixes", Expr(sql, args...)).(DeleteBuilder)
|
||||
}
|
||||
247
vendor/github.com/Masterminds/squirrel/expr.go
generated
vendored
Normal file
247
vendor/github.com/Masterminds/squirrel/expr.go
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type expr struct {
|
||||
sql string
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
// Expr builds value expressions for InsertBuilder and UpdateBuilder.
|
||||
//
|
||||
// Ex:
|
||||
// .Values(Expr("FROM_UNIXTIME(?)", t))
|
||||
func Expr(sql string, args ...interface{}) expr {
|
||||
return expr{sql: sql, args: args}
|
||||
}
|
||||
|
||||
func (e expr) ToSql() (sql string, args []interface{}, err error) {
|
||||
return e.sql, e.args, nil
|
||||
}
|
||||
|
||||
type exprs []expr
|
||||
|
||||
func (es exprs) AppendToSql(w io.Writer, sep string, args []interface{}) ([]interface{}, error) {
|
||||
for i, e := range es {
|
||||
if i > 0 {
|
||||
_, err := io.WriteString(w, sep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
_, err := io.WriteString(w, e.sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, e.args...)
|
||||
}
|
||||
return args, nil
|
||||
}
|
||||
|
||||
// aliasExpr helps to alias part of SQL query generated with underlying "expr"
|
||||
type aliasExpr struct {
|
||||
expr Sqlizer
|
||||
alias string
|
||||
}
|
||||
|
||||
// Alias allows to define alias for column in SelectBuilder. Useful when column is
|
||||
// defined as complex expression like IF or CASE
|
||||
// Ex:
|
||||
// .Column(Alias(caseStmt, "case_column"))
|
||||
func Alias(expr Sqlizer, alias string) aliasExpr {
|
||||
return aliasExpr{expr, alias}
|
||||
}
|
||||
|
||||
func (e aliasExpr) ToSql() (sql string, args []interface{}, err error) {
|
||||
sql, args, err = e.expr.ToSql()
|
||||
if err == nil {
|
||||
sql = fmt.Sprintf("(%s) AS %s", sql, e.alias)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Eq is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(Eq{"id": 1})
|
||||
type Eq map[string]interface{}
|
||||
|
||||
func (eq Eq) toSql(useNotOpr bool) (sql string, args []interface{}, err error) {
|
||||
var (
|
||||
exprs []string
|
||||
equalOpr string = "="
|
||||
inOpr string = "IN"
|
||||
nullOpr string = "IS"
|
||||
)
|
||||
|
||||
if useNotOpr {
|
||||
equalOpr = "<>"
|
||||
inOpr = "NOT IN"
|
||||
nullOpr = "IS NOT"
|
||||
}
|
||||
|
||||
for key, val := range eq {
|
||||
expr := ""
|
||||
|
||||
switch v := val.(type) {
|
||||
case driver.Valuer:
|
||||
if val, err = v.Value(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if val == nil {
|
||||
expr = fmt.Sprintf("%s %s NULL", key, nullOpr)
|
||||
} else {
|
||||
valVal := reflect.ValueOf(val)
|
||||
if valVal.Kind() == reflect.Array || valVal.Kind() == reflect.Slice {
|
||||
if valVal.Len() == 0 {
|
||||
expr = fmt.Sprintf("%s %s (NULL)", key, inOpr)
|
||||
if args == nil {
|
||||
args = []interface{}{}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < valVal.Len(); i++ {
|
||||
args = append(args, valVal.Index(i).Interface())
|
||||
}
|
||||
expr = fmt.Sprintf("%s %s (%s)", key, inOpr, Placeholders(valVal.Len()))
|
||||
}
|
||||
} else {
|
||||
expr = fmt.Sprintf("%s %s ?", key, equalOpr)
|
||||
args = append(args, val)
|
||||
}
|
||||
}
|
||||
exprs = append(exprs, expr)
|
||||
}
|
||||
sql = strings.Join(exprs, " AND ")
|
||||
return
|
||||
}
|
||||
|
||||
func (eq Eq) ToSql() (sql string, args []interface{}, err error) {
|
||||
return eq.toSql(false)
|
||||
}
|
||||
|
||||
// NotEq is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(NotEq{"id": 1}) == "id <> 1"
|
||||
type NotEq Eq
|
||||
|
||||
func (neq NotEq) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Eq(neq).toSql(true)
|
||||
}
|
||||
|
||||
// Lt is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(Lt{"id": 1})
|
||||
type Lt map[string]interface{}
|
||||
|
||||
func (lt Lt) toSql(opposite, orEq bool) (sql string, args []interface{}, err error) {
|
||||
var (
|
||||
exprs []string
|
||||
opr string = "<"
|
||||
)
|
||||
|
||||
if opposite {
|
||||
opr = ">"
|
||||
}
|
||||
|
||||
if orEq {
|
||||
opr = fmt.Sprintf("%s%s", opr, "=")
|
||||
}
|
||||
|
||||
for key, val := range lt {
|
||||
expr := ""
|
||||
|
||||
switch v := val.(type) {
|
||||
case driver.Valuer:
|
||||
if val, err = v.Value(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if val == nil {
|
||||
err = fmt.Errorf("cannot use null with less than or greater than operators")
|
||||
return
|
||||
} else {
|
||||
valVal := reflect.ValueOf(val)
|
||||
if valVal.Kind() == reflect.Array || valVal.Kind() == reflect.Slice {
|
||||
err = fmt.Errorf("cannot use array or slice with less than or greater than operators")
|
||||
return
|
||||
} else {
|
||||
expr = fmt.Sprintf("%s %s ?", key, opr)
|
||||
args = append(args, val)
|
||||
}
|
||||
}
|
||||
exprs = append(exprs, expr)
|
||||
}
|
||||
sql = strings.Join(exprs, " AND ")
|
||||
return
|
||||
}
|
||||
|
||||
func (lt Lt) ToSql() (sql string, args []interface{}, err error) {
|
||||
return lt.toSql(false, false)
|
||||
}
|
||||
|
||||
// LtOrEq is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(LtOrEq{"id": 1}) == "id <= 1"
|
||||
type LtOrEq Lt
|
||||
|
||||
func (ltOrEq LtOrEq) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Lt(ltOrEq).toSql(false, true)
|
||||
}
|
||||
|
||||
// Gt is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(Gt{"id": 1}) == "id > 1"
|
||||
type Gt Lt
|
||||
|
||||
func (gt Gt) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Lt(gt).toSql(true, false)
|
||||
}
|
||||
|
||||
// GtOrEq is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(GtOrEq{"id": 1}) == "id >= 1"
|
||||
type GtOrEq Lt
|
||||
|
||||
func (gtOrEq GtOrEq) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Lt(gtOrEq).toSql(true, true)
|
||||
}
|
||||
|
||||
type conj []Sqlizer
|
||||
|
||||
func (c conj) join(sep string) (sql string, args []interface{}, err error) {
|
||||
var sqlParts []string
|
||||
for _, sqlizer := range c {
|
||||
partSql, partArgs, err := sqlizer.ToSql()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if partSql != "" {
|
||||
sqlParts = append(sqlParts, partSql)
|
||||
args = append(args, partArgs...)
|
||||
}
|
||||
}
|
||||
if len(sqlParts) > 0 {
|
||||
sql = fmt.Sprintf("(%s)", strings.Join(sqlParts, sep))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type And conj
|
||||
|
||||
func (a And) ToSql() (string, []interface{}, error) {
|
||||
return conj(a).join(" AND ")
|
||||
}
|
||||
|
||||
type Or conj
|
||||
|
||||
func (o Or) ToSql() (string, []interface{}, error) {
|
||||
return conj(o).join(" OR ")
|
||||
}
|
||||
207
vendor/github.com/Masterminds/squirrel/insert.go
generated
vendored
Normal file
207
vendor/github.com/Masterminds/squirrel/insert.go
generated
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/lann/builder"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type insertData struct {
|
||||
PlaceholderFormat PlaceholderFormat
|
||||
RunWith BaseRunner
|
||||
Prefixes exprs
|
||||
Options []string
|
||||
Into string
|
||||
Columns []string
|
||||
Values [][]interface{}
|
||||
Suffixes exprs
|
||||
}
|
||||
|
||||
func (d *insertData) Exec() (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return ExecWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *insertData) Query() (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return QueryWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *insertData) QueryRow() RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRower)
|
||||
if !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return QueryRowWith(queryRower, d)
|
||||
}
|
||||
|
||||
func (d *insertData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.Into) == 0 {
|
||||
err = fmt.Errorf("insert statements must specify a table")
|
||||
return
|
||||
}
|
||||
if len(d.Values) == 0 {
|
||||
err = fmt.Errorf("insert statements must have at least one set of values")
|
||||
return
|
||||
}
|
||||
|
||||
sql := &bytes.Buffer{}
|
||||
|
||||
if len(d.Prefixes) > 0 {
|
||||
args, _ = d.Prefixes.AppendToSql(sql, " ", args)
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
sql.WriteString("INSERT ")
|
||||
|
||||
if len(d.Options) > 0 {
|
||||
sql.WriteString(strings.Join(d.Options, " "))
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
sql.WriteString("INTO ")
|
||||
sql.WriteString(d.Into)
|
||||
sql.WriteString(" ")
|
||||
|
||||
if len(d.Columns) > 0 {
|
||||
sql.WriteString("(")
|
||||
sql.WriteString(strings.Join(d.Columns, ","))
|
||||
sql.WriteString(") ")
|
||||
}
|
||||
|
||||
sql.WriteString("VALUES ")
|
||||
|
||||
valuesStrings := make([]string, len(d.Values))
|
||||
for r, row := range d.Values {
|
||||
valueStrings := make([]string, len(row))
|
||||
for v, val := range row {
|
||||
e, isExpr := val.(expr)
|
||||
if isExpr {
|
||||
valueStrings[v] = e.sql
|
||||
args = append(args, e.args...)
|
||||
} else {
|
||||
valueStrings[v] = "?"
|
||||
args = append(args, val)
|
||||
}
|
||||
}
|
||||
valuesStrings[r] = fmt.Sprintf("(%s)", strings.Join(valueStrings, ","))
|
||||
}
|
||||
sql.WriteString(strings.Join(valuesStrings, ","))
|
||||
|
||||
if len(d.Suffixes) > 0 {
|
||||
sql.WriteString(" ")
|
||||
args, _ = d.Suffixes.AppendToSql(sql, " ", args)
|
||||
}
|
||||
|
||||
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
|
||||
return
|
||||
}
|
||||
|
||||
// Builder
|
||||
|
||||
// InsertBuilder builds SQL INSERT statements.
|
||||
type InsertBuilder builder.Builder
|
||||
|
||||
func init() {
|
||||
builder.Register(InsertBuilder{}, insertData{})
|
||||
}
|
||||
|
||||
// Format methods
|
||||
|
||||
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
|
||||
// query.
|
||||
func (b InsertBuilder) PlaceholderFormat(f PlaceholderFormat) InsertBuilder {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Runner methods
|
||||
|
||||
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
|
||||
func (b InsertBuilder) RunWith(runner BaseRunner) InsertBuilder {
|
||||
return setRunWith(b, runner).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Exec builds and Execs the query with the Runner set by RunWith.
|
||||
func (b InsertBuilder) Exec() (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.Exec()
|
||||
}
|
||||
|
||||
// Query builds and Querys the query with the Runner set by RunWith.
|
||||
func (b InsertBuilder) Query() (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.Query()
|
||||
}
|
||||
|
||||
// QueryRow builds and QueryRows the query with the Runner set by RunWith.
|
||||
func (b InsertBuilder) QueryRow() RowScanner {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.QueryRow()
|
||||
}
|
||||
|
||||
// Scan is a shortcut for QueryRow().Scan.
|
||||
func (b InsertBuilder) Scan(dest ...interface{}) error {
|
||||
return b.QueryRow().Scan(dest...)
|
||||
}
|
||||
|
||||
// SQL methods
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b InsertBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
// Prefix adds an expression to the beginning of the query
|
||||
func (b InsertBuilder) Prefix(sql string, args ...interface{}) InsertBuilder {
|
||||
return builder.Append(b, "Prefixes", Expr(sql, args...)).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Options adds keyword options before the INTO clause of the query.
|
||||
func (b InsertBuilder) Options(options ...string) InsertBuilder {
|
||||
return builder.Extend(b, "Options", options).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Into sets the INTO clause of the query.
|
||||
func (b InsertBuilder) Into(from string) InsertBuilder {
|
||||
return builder.Set(b, "Into", from).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Columns adds insert columns to the query.
|
||||
func (b InsertBuilder) Columns(columns ...string) InsertBuilder {
|
||||
return builder.Extend(b, "Columns", columns).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Values adds a single row's values to the query.
|
||||
func (b InsertBuilder) Values(values ...interface{}) InsertBuilder {
|
||||
return builder.Append(b, "Values", values).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Suffix adds an expression to the end of the query
|
||||
func (b InsertBuilder) Suffix(sql string, args ...interface{}) InsertBuilder {
|
||||
return builder.Append(b, "Suffixes", Expr(sql, args...)).(InsertBuilder)
|
||||
}
|
||||
|
||||
// SetMap set columns and values for insert builder from a map of column name and value
|
||||
// note that it will reset all previous columns and values was set if any
|
||||
func (b InsertBuilder) SetMap(clauses map[string]interface{}) InsertBuilder {
|
||||
cols := make([]string, 0, len(clauses))
|
||||
vals := make([]interface{}, 0, len(clauses))
|
||||
for col, val := range clauses {
|
||||
cols = append(cols, col)
|
||||
vals = append(vals, val)
|
||||
}
|
||||
|
||||
b = builder.Set(b, "Columns", cols).(InsertBuilder)
|
||||
b = builder.Set(b, "Values", [][]interface{}{vals}).(InsertBuilder)
|
||||
return b
|
||||
}
|
||||
55
vendor/github.com/Masterminds/squirrel/part.go
generated
vendored
Normal file
55
vendor/github.com/Masterminds/squirrel/part.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type part struct {
|
||||
pred interface{}
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
func newPart(pred interface{}, args ...interface{}) Sqlizer {
|
||||
return &part{pred, args}
|
||||
}
|
||||
|
||||
func (p part) ToSql() (sql string, args []interface{}, err error) {
|
||||
switch pred := p.pred.(type) {
|
||||
case nil:
|
||||
// no-op
|
||||
case Sqlizer:
|
||||
sql, args, err = pred.ToSql()
|
||||
case string:
|
||||
sql = pred
|
||||
args = p.args
|
||||
default:
|
||||
err = fmt.Errorf("expected string or Sqlizer, not %T", pred)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func appendToSql(parts []Sqlizer, w io.Writer, sep string, args []interface{}) ([]interface{}, error) {
|
||||
for i, p := range parts {
|
||||
partSql, partArgs, err := p.ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if len(partSql) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
_, err := io.WriteString(w, sep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = io.WriteString(w, partSql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, partArgs...)
|
||||
}
|
||||
return args, nil
|
||||
}
|
||||
70
vendor/github.com/Masterminds/squirrel/placeholder.go
generated
vendored
Normal file
70
vendor/github.com/Masterminds/squirrel/placeholder.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PlaceholderFormat is the interface that wraps the ReplacePlaceholders method.
|
||||
//
|
||||
// ReplacePlaceholders takes a SQL statement and replaces each question mark
|
||||
// placeholder with a (possibly different) SQL placeholder.
|
||||
type PlaceholderFormat interface {
|
||||
ReplacePlaceholders(sql string) (string, error)
|
||||
}
|
||||
|
||||
var (
|
||||
// Question is a PlaceholderFormat instance that leaves placeholders as
|
||||
// question marks.
|
||||
Question = questionFormat{}
|
||||
|
||||
// Dollar is a PlaceholderFormat instance that replaces placeholders with
|
||||
// dollar-prefixed positional placeholders (e.g. $1, $2, $3).
|
||||
Dollar = dollarFormat{}
|
||||
)
|
||||
|
||||
type questionFormat struct{}
|
||||
|
||||
func (_ questionFormat) ReplacePlaceholders(sql string) (string, error) {
|
||||
return sql, nil
|
||||
}
|
||||
|
||||
type dollarFormat struct{}
|
||||
|
||||
func (_ dollarFormat) ReplacePlaceholders(sql string) (string, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
i := 0
|
||||
for {
|
||||
p := strings.Index(sql, "?")
|
||||
if p == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
if len(sql[p:]) > 1 && sql[p:p+2] == "??" { // escape ?? => ?
|
||||
buf.WriteString(sql[:p])
|
||||
buf.WriteString("?")
|
||||
if len(sql[p:]) == 1 {
|
||||
break
|
||||
}
|
||||
sql = sql[p+2:]
|
||||
} else {
|
||||
i++
|
||||
buf.WriteString(sql[:p])
|
||||
fmt.Fprintf(buf, "$%d", i)
|
||||
sql = sql[p+1:]
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(sql)
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// Placeholders returns a string with count ? placeholders joined with commas.
|
||||
func Placeholders(count int) string {
|
||||
if count < 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.Repeat(",?", count)[1:]
|
||||
}
|
||||
22
vendor/github.com/Masterminds/squirrel/row.go
generated
vendored
Normal file
22
vendor/github.com/Masterminds/squirrel/row.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package squirrel
|
||||
|
||||
// RowScanner is the interface that wraps the Scan method.
|
||||
//
|
||||
// Scan behaves like database/sql.Row.Scan.
|
||||
type RowScanner interface {
|
||||
Scan(...interface{}) error
|
||||
}
|
||||
|
||||
// Row wraps database/sql.Row to let squirrel return new errors on Scan.
|
||||
type Row struct {
|
||||
RowScanner
|
||||
err error
|
||||
}
|
||||
|
||||
// Scan returns Row.err or calls RowScanner.Scan.
|
||||
func (r *Row) Scan(dest ...interface{}) error {
|
||||
if r.err != nil {
|
||||
return r.err
|
||||
}
|
||||
return r.RowScanner.Scan(dest...)
|
||||
}
|
||||
313
vendor/github.com/Masterminds/squirrel/select.go
generated
vendored
Normal file
313
vendor/github.com/Masterminds/squirrel/select.go
generated
vendored
Normal file
@@ -0,0 +1,313 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
type selectData struct {
|
||||
PlaceholderFormat PlaceholderFormat
|
||||
RunWith BaseRunner
|
||||
Prefixes exprs
|
||||
Options []string
|
||||
Columns []Sqlizer
|
||||
From Sqlizer
|
||||
Joins []Sqlizer
|
||||
WhereParts []Sqlizer
|
||||
GroupBys []string
|
||||
HavingParts []Sqlizer
|
||||
OrderBys []string
|
||||
Limit string
|
||||
Offset string
|
||||
Suffixes exprs
|
||||
}
|
||||
|
||||
func (d *selectData) Exec() (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return ExecWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *selectData) Query() (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return QueryWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *selectData) QueryRow() RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRower)
|
||||
if !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return QueryRowWith(queryRower, d)
|
||||
}
|
||||
|
||||
func (d *selectData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.Columns) == 0 {
|
||||
err = fmt.Errorf("select statements must have at least one result column")
|
||||
return
|
||||
}
|
||||
|
||||
sql := &bytes.Buffer{}
|
||||
|
||||
if len(d.Prefixes) > 0 {
|
||||
args, _ = d.Prefixes.AppendToSql(sql, " ", args)
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
sql.WriteString("SELECT ")
|
||||
|
||||
if len(d.Options) > 0 {
|
||||
sql.WriteString(strings.Join(d.Options, " "))
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
if len(d.Columns) > 0 {
|
||||
args, err = appendToSql(d.Columns, sql, ", ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if d.From != nil {
|
||||
sql.WriteString(" FROM ")
|
||||
args, err = appendToSql([]Sqlizer{d.From}, sql, "", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.Joins) > 0 {
|
||||
sql.WriteString(" ")
|
||||
args, err = appendToSql(d.Joins, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.WhereParts) > 0 {
|
||||
sql.WriteString(" WHERE ")
|
||||
args, err = appendToSql(d.WhereParts, sql, " AND ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.GroupBys) > 0 {
|
||||
sql.WriteString(" GROUP BY ")
|
||||
sql.WriteString(strings.Join(d.GroupBys, ", "))
|
||||
}
|
||||
|
||||
if len(d.HavingParts) > 0 {
|
||||
sql.WriteString(" HAVING ")
|
||||
args, err = appendToSql(d.HavingParts, sql, " AND ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.OrderBys) > 0 {
|
||||
sql.WriteString(" ORDER BY ")
|
||||
sql.WriteString(strings.Join(d.OrderBys, ", "))
|
||||
}
|
||||
|
||||
if len(d.Limit) > 0 {
|
||||
sql.WriteString(" LIMIT ")
|
||||
sql.WriteString(d.Limit)
|
||||
}
|
||||
|
||||
if len(d.Offset) > 0 {
|
||||
sql.WriteString(" OFFSET ")
|
||||
sql.WriteString(d.Offset)
|
||||
}
|
||||
|
||||
if len(d.Suffixes) > 0 {
|
||||
sql.WriteString(" ")
|
||||
args, _ = d.Suffixes.AppendToSql(sql, " ", args)
|
||||
}
|
||||
|
||||
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
|
||||
return
|
||||
}
|
||||
|
||||
// Builder
|
||||
|
||||
// SelectBuilder builds SQL SELECT statements.
|
||||
type SelectBuilder builder.Builder
|
||||
|
||||
func init() {
|
||||
builder.Register(SelectBuilder{}, selectData{})
|
||||
}
|
||||
|
||||
// Format methods
|
||||
|
||||
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
|
||||
// query.
|
||||
func (b SelectBuilder) PlaceholderFormat(f PlaceholderFormat) SelectBuilder {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Runner methods
|
||||
|
||||
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
|
||||
func (b SelectBuilder) RunWith(runner BaseRunner) SelectBuilder {
|
||||
return setRunWith(b, runner).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Exec builds and Execs the query with the Runner set by RunWith.
|
||||
func (b SelectBuilder) Exec() (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.Exec()
|
||||
}
|
||||
|
||||
// Query builds and Querys the query with the Runner set by RunWith.
|
||||
func (b SelectBuilder) Query() (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.Query()
|
||||
}
|
||||
|
||||
// QueryRow builds and QueryRows the query with the Runner set by RunWith.
|
||||
func (b SelectBuilder) QueryRow() RowScanner {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.QueryRow()
|
||||
}
|
||||
|
||||
// Scan is a shortcut for QueryRow().Scan.
|
||||
func (b SelectBuilder) Scan(dest ...interface{}) error {
|
||||
return b.QueryRow().Scan(dest...)
|
||||
}
|
||||
|
||||
// SQL methods
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b SelectBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
// Prefix adds an expression to the beginning of the query
|
||||
func (b SelectBuilder) Prefix(sql string, args ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "Prefixes", Expr(sql, args...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Distinct adds a DISTINCT clause to the query.
|
||||
func (b SelectBuilder) Distinct() SelectBuilder {
|
||||
return b.Options("DISTINCT")
|
||||
}
|
||||
|
||||
// Options adds select option to the query
|
||||
func (b SelectBuilder) Options(options ...string) SelectBuilder {
|
||||
return builder.Extend(b, "Options", options).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Columns adds result columns to the query.
|
||||
func (b SelectBuilder) Columns(columns ...string) SelectBuilder {
|
||||
var parts []interface{}
|
||||
for _, str := range columns {
|
||||
parts = append(parts, newPart(str))
|
||||
}
|
||||
return builder.Extend(b, "Columns", parts).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Column adds a result column to the query.
|
||||
// Unlike Columns, Column accepts args which will be bound to placeholders in
|
||||
// the columns string, for example:
|
||||
// Column("IF(col IN ("+squirrel.Placeholders(3)+"), 1, 0) as col", 1, 2, 3)
|
||||
func (b SelectBuilder) Column(column interface{}, args ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "Columns", newPart(column, args...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// From sets the FROM clause of the query.
|
||||
func (b SelectBuilder) From(from string) SelectBuilder {
|
||||
return builder.Set(b, "From", newPart(from)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// FromSelect sets a subquery into the FROM clause of the query.
|
||||
func (b SelectBuilder) FromSelect(from SelectBuilder, alias string) SelectBuilder {
|
||||
return builder.Set(b, "From", Alias(from, alias)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// JoinClause adds a join clause to the query.
|
||||
func (b SelectBuilder) JoinClause(pred interface{}, args ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "Joins", newPart(pred, args...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Join adds a JOIN clause to the query.
|
||||
func (b SelectBuilder) Join(join string, rest ...interface{}) SelectBuilder {
|
||||
return b.JoinClause("JOIN "+join, rest...)
|
||||
}
|
||||
|
||||
// LeftJoin adds a LEFT JOIN clause to the query.
|
||||
func (b SelectBuilder) LeftJoin(join string, rest ...interface{}) SelectBuilder {
|
||||
return b.JoinClause("LEFT JOIN "+join, rest...)
|
||||
}
|
||||
|
||||
// RightJoin adds a RIGHT JOIN clause to the query.
|
||||
func (b SelectBuilder) RightJoin(join string, rest ...interface{}) SelectBuilder {
|
||||
return b.JoinClause("RIGHT JOIN "+join, rest...)
|
||||
}
|
||||
|
||||
// Where adds an expression to the WHERE clause of the query.
|
||||
//
|
||||
// Expressions are ANDed together in the generated SQL.
|
||||
//
|
||||
// Where accepts several types for its pred argument:
|
||||
//
|
||||
// nil OR "" - ignored.
|
||||
//
|
||||
// string - SQL expression.
|
||||
// If the expression has SQL placeholders then a set of arguments must be passed
|
||||
// as well, one for each placeholder.
|
||||
//
|
||||
// map[string]interface{} OR Eq - map of SQL expressions to values. Each key is
|
||||
// transformed into an expression like "<key> = ?", with the corresponding value
|
||||
// bound to the placeholder. If the value is nil, the expression will be "<key>
|
||||
// IS NULL". If the value is an array or slice, the expression will be "<key> IN
|
||||
// (?,?,...)", with one placeholder for each item in the value. These expressions
|
||||
// are ANDed together.
|
||||
//
|
||||
// Where will panic if pred isn't any of the above types.
|
||||
func (b SelectBuilder) Where(pred interface{}, args ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// GroupBy adds GROUP BY expressions to the query.
|
||||
func (b SelectBuilder) GroupBy(groupBys ...string) SelectBuilder {
|
||||
return builder.Extend(b, "GroupBys", groupBys).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Having adds an expression to the HAVING clause of the query.
|
||||
//
|
||||
// See Where.
|
||||
func (b SelectBuilder) Having(pred interface{}, rest ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "HavingParts", newWherePart(pred, rest...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// OrderBy adds ORDER BY expressions to the query.
|
||||
func (b SelectBuilder) OrderBy(orderBys ...string) SelectBuilder {
|
||||
return builder.Extend(b, "OrderBys", orderBys).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Limit sets a LIMIT clause on the query.
|
||||
func (b SelectBuilder) Limit(limit uint64) SelectBuilder {
|
||||
return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Offset sets a OFFSET clause on the query.
|
||||
func (b SelectBuilder) Offset(offset uint64) SelectBuilder {
|
||||
return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Suffix adds an expression to the end of the query
|
||||
func (b SelectBuilder) Suffix(sql string, args ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "Suffixes", Expr(sql, args...)).(SelectBuilder)
|
||||
}
|
||||
166
vendor/github.com/Masterminds/squirrel/squirrel.go
generated
vendored
Normal file
166
vendor/github.com/Masterminds/squirrel/squirrel.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
// Package squirrel provides a fluent SQL generator.
|
||||
//
|
||||
// See https://github.com/lann/squirrel for examples.
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
// Sqlizer is the interface that wraps the ToSql method.
|
||||
//
|
||||
// ToSql returns a SQL representation of the Sqlizer, along with a slice of args
|
||||
// as passed to e.g. database/sql.Exec. It can also return an error.
|
||||
type Sqlizer interface {
|
||||
ToSql() (string, []interface{}, error)
|
||||
}
|
||||
|
||||
// Execer is the interface that wraps the Exec method.
|
||||
//
|
||||
// Exec executes the given query as implemented by database/sql.Exec.
|
||||
type Execer interface {
|
||||
Exec(query string, args ...interface{}) (sql.Result, error)
|
||||
}
|
||||
|
||||
// Queryer is the interface that wraps the Query method.
|
||||
//
|
||||
// Query executes the given query as implemented by database/sql.Query.
|
||||
type Queryer interface {
|
||||
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||
}
|
||||
|
||||
// QueryRower is the interface that wraps the QueryRow method.
|
||||
//
|
||||
// QueryRow executes the given query as implemented by database/sql.QueryRow.
|
||||
type QueryRower interface {
|
||||
QueryRow(query string, args ...interface{}) RowScanner
|
||||
}
|
||||
|
||||
// BaseRunner groups the Execer and Queryer interfaces.
|
||||
type BaseRunner interface {
|
||||
Execer
|
||||
Queryer
|
||||
}
|
||||
|
||||
// Runner groups the Execer, Queryer, and QueryRower interfaces.
|
||||
type Runner interface {
|
||||
Execer
|
||||
Queryer
|
||||
QueryRower
|
||||
}
|
||||
|
||||
// DBRunner wraps sql.DB to implement Runner.
|
||||
type dbRunner struct {
|
||||
*sql.DB
|
||||
}
|
||||
|
||||
func (r *dbRunner) QueryRow(query string, args ...interface{}) RowScanner {
|
||||
return r.DB.QueryRow(query, args...)
|
||||
}
|
||||
|
||||
type txRunner struct {
|
||||
*sql.Tx
|
||||
}
|
||||
|
||||
func (r *txRunner) QueryRow(query string, args ...interface{}) RowScanner {
|
||||
return r.Tx.QueryRow(query, args...)
|
||||
}
|
||||
|
||||
func setRunWith(b interface{}, baseRunner BaseRunner) interface{} {
|
||||
var runner Runner
|
||||
switch r := baseRunner.(type) {
|
||||
case Runner:
|
||||
runner = r
|
||||
case *sql.DB:
|
||||
runner = &dbRunner{r}
|
||||
case *sql.Tx:
|
||||
runner = &txRunner{r}
|
||||
}
|
||||
return builder.Set(b, "RunWith", runner)
|
||||
}
|
||||
|
||||
// RunnerNotSet is returned by methods that need a Runner if it isn't set.
|
||||
var RunnerNotSet = fmt.Errorf("cannot run; no Runner set (RunWith)")
|
||||
|
||||
// RunnerNotQueryRunner is returned by QueryRow if the RunWith value doesn't implement QueryRower.
|
||||
var RunnerNotQueryRunner = fmt.Errorf("cannot QueryRow; Runner is not a QueryRower")
|
||||
|
||||
// ExecWith Execs the SQL returned by s with db.
|
||||
func ExecWith(db Execer, s Sqlizer) (res sql.Result, err error) {
|
||||
query, args, err := s.ToSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return db.Exec(query, args...)
|
||||
}
|
||||
|
||||
// QueryWith Querys the SQL returned by s with db.
|
||||
func QueryWith(db Queryer, s Sqlizer) (rows *sql.Rows, err error) {
|
||||
query, args, err := s.ToSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return db.Query(query, args...)
|
||||
}
|
||||
|
||||
// QueryRowWith QueryRows the SQL returned by s with db.
|
||||
func QueryRowWith(db QueryRower, s Sqlizer) RowScanner {
|
||||
query, args, err := s.ToSql()
|
||||
return &Row{RowScanner: db.QueryRow(query, args...), err: err}
|
||||
}
|
||||
|
||||
// DebugSqlizer calls ToSql on s and shows the approximate SQL to be executed
|
||||
//
|
||||
// If ToSql returns an error, the result of this method will look like:
|
||||
// "[ToSql error: %s]" or "[DebugSqlizer error: %s]"
|
||||
//
|
||||
// IMPORTANT: As its name suggests, this function should only be used for
|
||||
// debugging. While the string result *might* be valid SQL, this function does
|
||||
// not try very hard to ensure it. Additionally, executing the output of this
|
||||
// function with any untrusted user input is certainly insecure.
|
||||
func DebugSqlizer(s Sqlizer) string {
|
||||
sql, args, err := s.ToSql()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[ToSql error: %s]", err)
|
||||
}
|
||||
|
||||
// TODO: dedupe this with placeholder.go
|
||||
buf := &bytes.Buffer{}
|
||||
i := 0
|
||||
for {
|
||||
p := strings.Index(sql, "?")
|
||||
if p == -1 {
|
||||
break
|
||||
}
|
||||
if len(sql[p:]) > 1 && sql[p:p+2] == "??" { // escape ?? => ?
|
||||
buf.WriteString(sql[:p])
|
||||
buf.WriteString("?")
|
||||
if len(sql[p:]) == 1 {
|
||||
break
|
||||
}
|
||||
sql = sql[p+2:]
|
||||
} else {
|
||||
if i+1 > len(args) {
|
||||
return fmt.Sprintf(
|
||||
"[DebugSqlizer error: too many placeholders in %#v for %d args]",
|
||||
sql, len(args))
|
||||
}
|
||||
buf.WriteString(sql[:p])
|
||||
fmt.Fprintf(buf, "'%v'", args[i])
|
||||
sql = sql[p+1:]
|
||||
i++
|
||||
}
|
||||
}
|
||||
if i < len(args) {
|
||||
return fmt.Sprintf(
|
||||
"[DebugSqlizer error: not enough placeholders in %#v for %d args]",
|
||||
sql, len(args))
|
||||
}
|
||||
buf.WriteString(sql)
|
||||
return buf.String()
|
||||
}
|
||||
83
vendor/github.com/Masterminds/squirrel/statement.go
generated
vendored
Normal file
83
vendor/github.com/Masterminds/squirrel/statement.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package squirrel
|
||||
|
||||
import "github.com/lann/builder"
|
||||
|
||||
// StatementBuilderType is the type of StatementBuilder.
|
||||
type StatementBuilderType builder.Builder
|
||||
|
||||
// Select returns a SelectBuilder for this StatementBuilderType.
|
||||
func (b StatementBuilderType) Select(columns ...string) SelectBuilder {
|
||||
return SelectBuilder(b).Columns(columns...)
|
||||
}
|
||||
|
||||
// Insert returns a InsertBuilder for this StatementBuilderType.
|
||||
func (b StatementBuilderType) Insert(into string) InsertBuilder {
|
||||
return InsertBuilder(b).Into(into)
|
||||
}
|
||||
|
||||
// Update returns a UpdateBuilder for this StatementBuilderType.
|
||||
func (b StatementBuilderType) Update(table string) UpdateBuilder {
|
||||
return UpdateBuilder(b).Table(table)
|
||||
}
|
||||
|
||||
// Delete returns a DeleteBuilder for this StatementBuilderType.
|
||||
func (b StatementBuilderType) Delete(from string) DeleteBuilder {
|
||||
return DeleteBuilder(b).From(from)
|
||||
}
|
||||
|
||||
// PlaceholderFormat sets the PlaceholderFormat field for any child builders.
|
||||
func (b StatementBuilderType) PlaceholderFormat(f PlaceholderFormat) StatementBuilderType {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(StatementBuilderType)
|
||||
}
|
||||
|
||||
// RunWith sets the RunWith field for any child builders.
|
||||
func (b StatementBuilderType) RunWith(runner BaseRunner) StatementBuilderType {
|
||||
return setRunWith(b, runner).(StatementBuilderType)
|
||||
}
|
||||
|
||||
// StatementBuilder is a parent builder for other builders, e.g. SelectBuilder.
|
||||
var StatementBuilder = StatementBuilderType(builder.EmptyBuilder).PlaceholderFormat(Question)
|
||||
|
||||
// Select returns a new SelectBuilder, optionally setting some result columns.
|
||||
//
|
||||
// See SelectBuilder.Columns.
|
||||
func Select(columns ...string) SelectBuilder {
|
||||
return StatementBuilder.Select(columns...)
|
||||
}
|
||||
|
||||
// Insert returns a new InsertBuilder with the given table name.
|
||||
//
|
||||
// See InsertBuilder.Into.
|
||||
func Insert(into string) InsertBuilder {
|
||||
return StatementBuilder.Insert(into)
|
||||
}
|
||||
|
||||
// Update returns a new UpdateBuilder with the given table name.
|
||||
//
|
||||
// See UpdateBuilder.Table.
|
||||
func Update(table string) UpdateBuilder {
|
||||
return StatementBuilder.Update(table)
|
||||
}
|
||||
|
||||
// Delete returns a new DeleteBuilder with the given table name.
|
||||
//
|
||||
// See DeleteBuilder.Table.
|
||||
func Delete(from string) DeleteBuilder {
|
||||
return StatementBuilder.Delete(from)
|
||||
}
|
||||
|
||||
// Case returns a new CaseBuilder
|
||||
// "what" represents case value
|
||||
func Case(what ...interface{}) CaseBuilder {
|
||||
b := CaseBuilder(builder.EmptyBuilder)
|
||||
|
||||
switch len(what) {
|
||||
case 0:
|
||||
case 1:
|
||||
b = b.what(what[0])
|
||||
default:
|
||||
b = b.what(newPart(what[0], what[1:]...))
|
||||
|
||||
}
|
||||
return b
|
||||
}
|
||||
90
vendor/github.com/Masterminds/squirrel/stmtcacher.go
generated
vendored
Normal file
90
vendor/github.com/Masterminds/squirrel/stmtcacher.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Prepareer is the interface that wraps the Prepare method.
|
||||
//
|
||||
// Prepare executes the given query as implemented by database/sql.Prepare.
|
||||
type Preparer interface {
|
||||
Prepare(query string) (*sql.Stmt, error)
|
||||
}
|
||||
|
||||
// DBProxy groups the Execer, Queryer, QueryRower, and Preparer interfaces.
|
||||
type DBProxy interface {
|
||||
Execer
|
||||
Queryer
|
||||
QueryRower
|
||||
Preparer
|
||||
}
|
||||
|
||||
type stmtCacher struct {
|
||||
prep Preparer
|
||||
cache map[string]*sql.Stmt
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewStmtCacher returns a DBProxy wrapping prep that caches Prepared Stmts.
|
||||
//
|
||||
// Stmts are cached based on the string value of their queries.
|
||||
func NewStmtCacher(prep Preparer) DBProxy {
|
||||
return &stmtCacher{prep: prep, cache: make(map[string]*sql.Stmt)}
|
||||
}
|
||||
|
||||
func (sc *stmtCacher) Prepare(query string) (*sql.Stmt, error) {
|
||||
sc.mu.Lock()
|
||||
defer sc.mu.Unlock()
|
||||
stmt, ok := sc.cache[query]
|
||||
if ok {
|
||||
return stmt, nil
|
||||
}
|
||||
stmt, err := sc.prep.Prepare(query)
|
||||
if err == nil {
|
||||
sc.cache[query] = stmt
|
||||
}
|
||||
return stmt, err
|
||||
}
|
||||
|
||||
func (sc *stmtCacher) Exec(query string, args ...interface{}) (res sql.Result, err error) {
|
||||
stmt, err := sc.Prepare(query)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return stmt.Exec(args...)
|
||||
}
|
||||
|
||||
func (sc *stmtCacher) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
stmt, err := sc.Prepare(query)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return stmt.Query(args...)
|
||||
}
|
||||
|
||||
func (sc *stmtCacher) QueryRow(query string, args ...interface{}) RowScanner {
|
||||
stmt, err := sc.Prepare(query)
|
||||
if err != nil {
|
||||
return &Row{err: err}
|
||||
}
|
||||
return stmt.QueryRow(args...)
|
||||
}
|
||||
|
||||
type DBProxyBeginner interface {
|
||||
DBProxy
|
||||
Begin() (*sql.Tx, error)
|
||||
}
|
||||
|
||||
type stmtCacheProxy struct {
|
||||
DBProxy
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewStmtCacheProxy(db *sql.DB) DBProxyBeginner {
|
||||
return &stmtCacheProxy{DBProxy: NewStmtCacher(db), db: db}
|
||||
}
|
||||
|
||||
func (sp *stmtCacheProxy) Begin() (*sql.Tx, error) {
|
||||
return sp.db.Begin()
|
||||
}
|
||||
232
vendor/github.com/Masterminds/squirrel/update.go
generated
vendored
Normal file
232
vendor/github.com/Masterminds/squirrel/update.go
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
type updateData struct {
|
||||
PlaceholderFormat PlaceholderFormat
|
||||
RunWith BaseRunner
|
||||
Prefixes exprs
|
||||
Table string
|
||||
SetClauses []setClause
|
||||
WhereParts []Sqlizer
|
||||
OrderBys []string
|
||||
Limit string
|
||||
Offset string
|
||||
Suffixes exprs
|
||||
}
|
||||
|
||||
type setClause struct {
|
||||
column string
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (d *updateData) Exec() (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return ExecWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *updateData) Query() (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return QueryWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *updateData) QueryRow() RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRower)
|
||||
if !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return QueryRowWith(queryRower, d)
|
||||
}
|
||||
|
||||
func (d *updateData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.Table) == 0 {
|
||||
err = fmt.Errorf("update statements must specify a table")
|
||||
return
|
||||
}
|
||||
if len(d.SetClauses) == 0 {
|
||||
err = fmt.Errorf("update statements must have at least one Set clause")
|
||||
return
|
||||
}
|
||||
|
||||
sql := &bytes.Buffer{}
|
||||
|
||||
if len(d.Prefixes) > 0 {
|
||||
args, _ = d.Prefixes.AppendToSql(sql, " ", args)
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
sql.WriteString("UPDATE ")
|
||||
sql.WriteString(d.Table)
|
||||
|
||||
sql.WriteString(" SET ")
|
||||
setSqls := make([]string, len(d.SetClauses))
|
||||
for i, setClause := range d.SetClauses {
|
||||
var valSql string
|
||||
e, isExpr := setClause.value.(expr)
|
||||
if isExpr {
|
||||
valSql = e.sql
|
||||
args = append(args, e.args...)
|
||||
} else {
|
||||
valSql = "?"
|
||||
args = append(args, setClause.value)
|
||||
}
|
||||
setSqls[i] = fmt.Sprintf("%s = %s", setClause.column, valSql)
|
||||
}
|
||||
sql.WriteString(strings.Join(setSqls, ", "))
|
||||
|
||||
if len(d.WhereParts) > 0 {
|
||||
sql.WriteString(" WHERE ")
|
||||
args, err = appendToSql(d.WhereParts, sql, " AND ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.OrderBys) > 0 {
|
||||
sql.WriteString(" ORDER BY ")
|
||||
sql.WriteString(strings.Join(d.OrderBys, ", "))
|
||||
}
|
||||
|
||||
if len(d.Limit) > 0 {
|
||||
sql.WriteString(" LIMIT ")
|
||||
sql.WriteString(d.Limit)
|
||||
}
|
||||
|
||||
if len(d.Offset) > 0 {
|
||||
sql.WriteString(" OFFSET ")
|
||||
sql.WriteString(d.Offset)
|
||||
}
|
||||
|
||||
if len(d.Suffixes) > 0 {
|
||||
sql.WriteString(" ")
|
||||
args, _ = d.Suffixes.AppendToSql(sql, " ", args)
|
||||
}
|
||||
|
||||
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
|
||||
return
|
||||
}
|
||||
|
||||
// Builder
|
||||
|
||||
// UpdateBuilder builds SQL UPDATE statements.
|
||||
type UpdateBuilder builder.Builder
|
||||
|
||||
func init() {
|
||||
builder.Register(UpdateBuilder{}, updateData{})
|
||||
}
|
||||
|
||||
// Format methods
|
||||
|
||||
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
|
||||
// query.
|
||||
func (b UpdateBuilder) PlaceholderFormat(f PlaceholderFormat) UpdateBuilder {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Runner methods
|
||||
|
||||
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
|
||||
func (b UpdateBuilder) RunWith(runner BaseRunner) UpdateBuilder {
|
||||
return setRunWith(b, runner).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Exec builds and Execs the query with the Runner set by RunWith.
|
||||
func (b UpdateBuilder) Exec() (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.Exec()
|
||||
}
|
||||
|
||||
func (b UpdateBuilder) Query() (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.Query()
|
||||
}
|
||||
|
||||
func (b UpdateBuilder) QueryRow() RowScanner {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.QueryRow()
|
||||
}
|
||||
|
||||
func (b UpdateBuilder) Scan(dest ...interface{}) error {
|
||||
return b.QueryRow().Scan(dest...)
|
||||
}
|
||||
|
||||
// SQL methods
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b UpdateBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
// Prefix adds an expression to the beginning of the query
|
||||
func (b UpdateBuilder) Prefix(sql string, args ...interface{}) UpdateBuilder {
|
||||
return builder.Append(b, "Prefixes", Expr(sql, args...)).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Table sets the table to be updated.
|
||||
func (b UpdateBuilder) Table(table string) UpdateBuilder {
|
||||
return builder.Set(b, "Table", table).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Set adds SET clauses to the query.
|
||||
func (b UpdateBuilder) Set(column string, value interface{}) UpdateBuilder {
|
||||
return builder.Append(b, "SetClauses", setClause{column: column, value: value}).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// SetMap is a convenience method which calls .Set for each key/value pair in clauses.
|
||||
func (b UpdateBuilder) SetMap(clauses map[string]interface{}) UpdateBuilder {
|
||||
keys := make([]string, len(clauses))
|
||||
i := 0
|
||||
for key := range clauses {
|
||||
keys[i] = key
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
val, _ := clauses[key]
|
||||
b = b.Set(key, val)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Where adds WHERE expressions to the query.
|
||||
//
|
||||
// See SelectBuilder.Where for more information.
|
||||
func (b UpdateBuilder) Where(pred interface{}, args ...interface{}) UpdateBuilder {
|
||||
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// OrderBy adds ORDER BY expressions to the query.
|
||||
func (b UpdateBuilder) OrderBy(orderBys ...string) UpdateBuilder {
|
||||
return builder.Extend(b, "OrderBys", orderBys).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Limit sets a LIMIT clause on the query.
|
||||
func (b UpdateBuilder) Limit(limit uint64) UpdateBuilder {
|
||||
return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Offset sets a OFFSET clause on the query.
|
||||
func (b UpdateBuilder) Offset(offset uint64) UpdateBuilder {
|
||||
return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Suffix adds an expression to the end of the query
|
||||
func (b UpdateBuilder) Suffix(sql string, args ...interface{}) UpdateBuilder {
|
||||
return builder.Append(b, "Suffixes", Expr(sql, args...)).(UpdateBuilder)
|
||||
}
|
||||
28
vendor/github.com/Masterminds/squirrel/where.go
generated
vendored
Normal file
28
vendor/github.com/Masterminds/squirrel/where.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type wherePart part
|
||||
|
||||
func newWherePart(pred interface{}, args ...interface{}) Sqlizer {
|
||||
return &wherePart{pred: pred, args: args}
|
||||
}
|
||||
|
||||
func (p wherePart) ToSql() (sql string, args []interface{}, err error) {
|
||||
switch pred := p.pred.(type) {
|
||||
case nil:
|
||||
// no-op
|
||||
case Sqlizer:
|
||||
return pred.ToSql()
|
||||
case map[string]interface{}:
|
||||
return Eq(pred).ToSql()
|
||||
case string:
|
||||
sql = pred
|
||||
args = p.args
|
||||
default:
|
||||
err = fmt.Errorf("expected string-keyed map or string, not %T", pred)
|
||||
}
|
||||
return
|
||||
}
|
||||
24
vendor/github.com/huandu/xstrings/.gitignore
generated
vendored
Normal file
24
vendor/github.com/huandu/xstrings/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
1
vendor/github.com/huandu/xstrings/.travis.yml
generated
vendored
Normal file
1
vendor/github.com/huandu/xstrings/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
language: go
|
||||
23
vendor/github.com/huandu/xstrings/CONTRIBUTING.md
generated
vendored
Normal file
23
vendor/github.com/huandu/xstrings/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# Contributing #
|
||||
|
||||
Thanks for your contribution in advance. No matter what you will contribute to this project, pull request or bug report or feature discussion, it's always highly appreciated.
|
||||
|
||||
## New API or feature ##
|
||||
|
||||
I want to speak more about how to add new functions to this package.
|
||||
|
||||
Package `xstring` is a collection of useful string functions which should be implemented in Go. It's a bit subject to say which function should be included and which should not. I set up following rules in order to make it clear and as objective as possible.
|
||||
|
||||
* Rule 1: Only string algorithm, which takes string as input, can be included.
|
||||
* Rule 2: If a function has been implemented in package `string`, it must not be included.
|
||||
* Rule 3: If a function is not language neutral, it must not be included.
|
||||
* Rule 4: If a function is a part of standard library in other languages, it can be included.
|
||||
* Rule 5: If a function is quite useful in some famous framework or library, it can be included.
|
||||
|
||||
New function must be discussed in project issues before submitting any code. If a pull request with new functions is sent without any ref issue, it will be rejected.
|
||||
|
||||
## Pull request ##
|
||||
|
||||
Pull request is always welcome. Just make sure you have run `go fmt` and all test cases passed before submit.
|
||||
|
||||
If the pull request is to add a new API or feature, don't forget to update README.md and add new API in function list.
|
||||
22
vendor/github.com/huandu/xstrings/LICENSE
generated
vendored
Normal file
22
vendor/github.com/huandu/xstrings/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Huan Du
|
||||
|
||||
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.
|
||||
|
||||
115
vendor/github.com/huandu/xstrings/README.md
generated
vendored
Normal file
115
vendor/github.com/huandu/xstrings/README.md
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
# xstrings #
|
||||
|
||||
[](https://travis-ci.org/huandu/xstrings)
|
||||
[](https://godoc.org/github.com/huandu/xstrings)
|
||||
|
||||
Go package [xstrings](https://godoc.org/github.com/huandu/xstrings) is a collection of string functions, which are widely used in other languages but absent in Go package [strings](http://golang.org/pkg/strings).
|
||||
|
||||
All functions are well tested and carefully tuned for performance.
|
||||
|
||||
## Propose a new function ##
|
||||
|
||||
Please review [contributing guideline](CONTRIBUTING.md) and [create new issue](https://github.com/huandu/xstrings/issues) to state why it should be included.
|
||||
|
||||
## Install ##
|
||||
|
||||
Use `go get` to install this library.
|
||||
|
||||
go get github.com/huandu/xstrings
|
||||
|
||||
## API document ##
|
||||
|
||||
See [GoDoc](https://godoc.org/github.com/huandu/xstrings) for full document.
|
||||
|
||||
## Function list ##
|
||||
|
||||
Go functions have a unique naming style. One, who has experience in other language but new in Go, may have difficulties to find out right string function to use.
|
||||
|
||||
Here is a list of functions in [strings](http://golang.org/pkg/strings) and [xstrings](https://godoc.org/github.com/huandu/xstrings) with enough extra information about how to map these functions to their friends in other languages. Hope this list could be helpful for fresh gophers.
|
||||
|
||||
### Package `xstrings` functions ###
|
||||
|
||||
*Keep this table sorted by Function in ascending order.*
|
||||
|
||||
| Function | Friends | # |
|
||||
| -------- | ------- | --- |
|
||||
| [Center](https://godoc.org/github.com/huandu/xstrings#Center) | `str.center` in Python; `String#center` in Ruby | [#30](https://github.com/huandu/xstrings/issues/30) |
|
||||
| [Count](https://godoc.org/github.com/huandu/xstrings#Count) | `String#count` in Ruby | [#16](https://github.com/huandu/xstrings/issues/16) |
|
||||
| [Delete](https://godoc.org/github.com/huandu/xstrings#Delete) | `String#delete` in Ruby | [#17](https://github.com/huandu/xstrings/issues/17) |
|
||||
| [ExpandTabs](https://godoc.org/github.com/huandu/xstrings#ExpandTabs) | `str.expandtabs` in Python | [#27](https://github.com/huandu/xstrings/issues/27) |
|
||||
| [FirstRuneToLower](https://godoc.org/github.com/huandu/xstrings#FirstRuneToLower) | `lcfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) |
|
||||
| [FirstRuneToUpper](https://godoc.org/github.com/huandu/xstrings#FirstRuneToUpper) | `String#capitalize` in Ruby; `ucfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) |
|
||||
| [Insert](https://godoc.org/github.com/huandu/xstrings#Insert) | `String#insert` in Ruby | [#18](https://github.com/huandu/xstrings/issues/18) |
|
||||
| [LastPartition](https://godoc.org/github.com/huandu/xstrings#LastPartition) | `str.rpartition` in Python; `String#rpartition` in Ruby | [#19](https://github.com/huandu/xstrings/issues/19) |
|
||||
| [LeftJustify](https://godoc.org/github.com/huandu/xstrings#LeftJustify) | `str.ljust` in Python; `String#ljust` in Ruby | [#28](https://github.com/huandu/xstrings/issues/28) |
|
||||
| [Len](https://godoc.org/github.com/huandu/xstrings#Len) | `mb_strlen` in PHP | [#23](https://github.com/huandu/xstrings/issues/23) |
|
||||
| [Partition](https://godoc.org/github.com/huandu/xstrings#Partition) | `str.partition` in Python; `String#partition` in Ruby | [#10](https://github.com/huandu/xstrings/issues/10) |
|
||||
| [Reverse](https://godoc.org/github.com/huandu/xstrings#Reverse) | `String#reverse` in Ruby; `strrev` in PHP; `reverse` in Perl | [#7](https://github.com/huandu/xstrings/issues/7) |
|
||||
| [RightJustify](https://godoc.org/github.com/huandu/xstrings#RightJustify) | `str.rjust` in Python; `String#rjust` in Ruby | [#29](https://github.com/huandu/xstrings/issues/29) |
|
||||
| [RuneWidth](https://godoc.org/github.com/huandu/xstrings#RuneWidth) | - | [#27](https://github.com/huandu/xstrings/issues/27) |
|
||||
| [Scrub](https://godoc.org/github.com/huandu/xstrings#Scrub) | `String#scrub` in Ruby | [#20](https://github.com/huandu/xstrings/issues/20) |
|
||||
| [Shuffle](https://godoc.org/github.com/huandu/xstrings#Shuffle) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) |
|
||||
| [ShuffleSource](https://godoc.org/github.com/huandu/xstrings#ShuffleSource) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) |
|
||||
| [Slice](https://godoc.org/github.com/huandu/xstrings#Slice) | `mb_substr` in PHP | [#9](https://github.com/huandu/xstrings/issues/9) |
|
||||
| [Squeeze](https://godoc.org/github.com/huandu/xstrings#Squeeze) | `String#squeeze` in Ruby | [#11](https://github.com/huandu/xstrings/issues/11) |
|
||||
| [Successor](https://godoc.org/github.com/huandu/xstrings#Successor) | `String#succ` or `String#next` in Ruby | [#22](https://github.com/huandu/xstrings/issues/22) |
|
||||
| [SwapCase](https://godoc.org/github.com/huandu/xstrings#SwapCase) | `str.swapcase` in Python; `String#swapcase` in Ruby | [#12](https://github.com/huandu/xstrings/issues/12) |
|
||||
| [ToCamelCase](https://godoc.org/github.com/huandu/xstrings#ToCamelCase) | `String#camelize` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) |
|
||||
| [ToKebab](https://godoc.org/github.com/huandu/xstrings#ToKebabCase) | - | [#41](https://github.com/huandu/xstrings/issues/41) |
|
||||
| [ToSnakeCase](https://godoc.org/github.com/huandu/xstrings#ToSnakeCase) | `String#underscore` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) |
|
||||
| [Translate](https://godoc.org/github.com/huandu/xstrings#Translate) | `str.translate` in Python; `String#tr` in Ruby; `strtr` in PHP; `tr///` in Perl | [#21](https://github.com/huandu/xstrings/issues/21) |
|
||||
| [Width](https://godoc.org/github.com/huandu/xstrings#Width) | `mb_strwidth` in PHP | [#26](https://github.com/huandu/xstrings/issues/26) |
|
||||
| [WordCount](https://godoc.org/github.com/huandu/xstrings#WordCount) | `str_word_count` in PHP | [#14](https://github.com/huandu/xstrings/issues/14) |
|
||||
| [WordSplit](https://godoc.org/github.com/huandu/xstrings#WordSplit) | - | [#14](https://github.com/huandu/xstrings/issues/14) |
|
||||
|
||||
### Package `strings` functions ###
|
||||
|
||||
*Keep this table sorted by Function in ascending order.*
|
||||
|
||||
| Function | Friends |
|
||||
| -------- | ------- |
|
||||
| [Contains](http://golang.org/pkg/strings/#Contains) | `String#include?` in Ruby |
|
||||
| [ContainsAny](http://golang.org/pkg/strings/#ContainsAny) | - |
|
||||
| [ContainsRune](http://golang.org/pkg/strings/#ContainsRune) | - |
|
||||
| [Count](http://golang.org/pkg/strings/#Count) | `str.count` in Python; `substr_count` in PHP |
|
||||
| [EqualFold](http://golang.org/pkg/strings/#EqualFold) | `stricmp` in PHP; `String#casecmp` in Ruby |
|
||||
| [Fields](http://golang.org/pkg/strings/#Fields) | `str.split` in Python; `split` in Perl; `String#split` in Ruby |
|
||||
| [FieldsFunc](http://golang.org/pkg/strings/#FieldsFunc) | - |
|
||||
| [HasPrefix](http://golang.org/pkg/strings/#HasPrefix) | `str.startswith` in Python; `String#start_with?` in Ruby |
|
||||
| [HasSuffix](http://golang.org/pkg/strings/#HasSuffix) | `str.endswith` in Python; `String#end_with?` in Ruby |
|
||||
| [Index](http://golang.org/pkg/strings/#Index) | `str.index` in Python; `String#index` in Ruby; `strpos` in PHP; `index` in Perl |
|
||||
| [IndexAny](http://golang.org/pkg/strings/#IndexAny) | - |
|
||||
| [IndexByte](http://golang.org/pkg/strings/#IndexByte) | - |
|
||||
| [IndexFunc](http://golang.org/pkg/strings/#IndexFunc) | - |
|
||||
| [IndexRune](http://golang.org/pkg/strings/#IndexRune) | - |
|
||||
| [Join](http://golang.org/pkg/strings/#Join) | `str.join` in Python; `Array#join` in Ruby; `implode` in PHP; `join` in Perl |
|
||||
| [LastIndex](http://golang.org/pkg/strings/#LastIndex) | `str.rindex` in Python; `String#rindex`; `strrpos` in PHP; `rindex` in Perl |
|
||||
| [LastIndexAny](http://golang.org/pkg/strings/#LastIndexAny) | - |
|
||||
| [LastIndexFunc](http://golang.org/pkg/strings/#LastIndexFunc) | - |
|
||||
| [Map](http://golang.org/pkg/strings/#Map) | `String#each_codepoint` in Ruby |
|
||||
| [Repeat](http://golang.org/pkg/strings/#Repeat) | operator `*` in Python and Ruby; `str_repeat` in PHP |
|
||||
| [Replace](http://golang.org/pkg/strings/#Replace) | `str.replace` in Python; `String#sub` in Ruby; `str_replace` in PHP |
|
||||
| [Split](http://golang.org/pkg/strings/#Split) | `str.split` in Python; `String#split` in Ruby; `explode` in PHP; `split` in Perl |
|
||||
| [SplitAfter](http://golang.org/pkg/strings/#SplitAfter) | - |
|
||||
| [SplitAfterN](http://golang.org/pkg/strings/#SplitAfterN) | - |
|
||||
| [SplitN](http://golang.org/pkg/strings/#SplitN) | `str.split` in Python; `String#split` in Ruby; `explode` in PHP; `split` in Perl |
|
||||
| [Title](http://golang.org/pkg/strings/#Title) | `str.title` in Python |
|
||||
| [ToLower](http://golang.org/pkg/strings/#ToLower) | `str.lower` in Python; `String#downcase` in Ruby; `strtolower` in PHP; `lc` in Perl |
|
||||
| [ToLowerSpecial](http://golang.org/pkg/strings/#ToLowerSpecial) | - |
|
||||
| [ToTitle](http://golang.org/pkg/strings/#ToTitle) | - |
|
||||
| [ToTitleSpecial](http://golang.org/pkg/strings/#ToTitleSpecial) | - |
|
||||
| [ToUpper](http://golang.org/pkg/strings/#ToUpper) | `str.upper` in Python; `String#upcase` in Ruby; `strtoupper` in PHP; `uc` in Perl |
|
||||
| [ToUpperSpecial](http://golang.org/pkg/strings/#ToUpperSpecial) | - |
|
||||
| [Trim](http://golang.org/pkg/strings/#Trim) | `str.strip` in Python; `String#strip` in Ruby; `trim` in PHP |
|
||||
| [TrimFunc](http://golang.org/pkg/strings/#TrimFunc) | - |
|
||||
| [TrimLeft](http://golang.org/pkg/strings/#TrimLeft) | `str.lstrip` in Python; `String#lstrip` in Ruby; `ltrim` in PHP |
|
||||
| [TrimLeftFunc](http://golang.org/pkg/strings/#TrimLeftFunc) | - |
|
||||
| [TrimPrefix](http://golang.org/pkg/strings/#TrimPrefix) | - |
|
||||
| [TrimRight](http://golang.org/pkg/strings/#TrimRight) | `str.rstrip` in Python; `String#rstrip` in Ruby; `rtrim` in PHP |
|
||||
| [TrimRightFunc](http://golang.org/pkg/strings/#TrimRightFunc) | - |
|
||||
| [TrimSpace](http://golang.org/pkg/strings/#TrimSpace) | `str.strip` in Python; `String#strip` in Ruby; `trim` in PHP |
|
||||
| [TrimSuffix](http://golang.org/pkg/strings/#TrimSuffix) | `String#chomp` in Ruby; `chomp` in Perl |
|
||||
|
||||
## License ##
|
||||
|
||||
This library is licensed under MIT license. See LICENSE for details.
|
||||
25
vendor/github.com/huandu/xstrings/common.go
generated
vendored
Normal file
25
vendor/github.com/huandu/xstrings/common.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2015 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package xstrings
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
const bufferMaxInitGrowSize = 2048
|
||||
|
||||
// Lazy initialize a buffer.
|
||||
func allocBuffer(orig, cur string) *bytes.Buffer {
|
||||
output := &bytes.Buffer{}
|
||||
maxSize := len(orig) * 4
|
||||
|
||||
// Avoid to reserve too much memory at once.
|
||||
if maxSize > bufferMaxInitGrowSize {
|
||||
maxSize = bufferMaxInitGrowSize
|
||||
}
|
||||
|
||||
output.Grow(maxSize)
|
||||
output.WriteString(orig[:len(orig)-len(cur)])
|
||||
return output
|
||||
}
|
||||
400
vendor/github.com/huandu/xstrings/convert.go
generated
vendored
Normal file
400
vendor/github.com/huandu/xstrings/convert.go
generated
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
// Copyright 2015 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package xstrings
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// ToCamelCase can convert all lower case characters behind underscores
|
||||
// to upper case character.
|
||||
// Underscore character will be removed in result except following cases.
|
||||
// * More than 1 underscore.
|
||||
// "a__b" => "A_B"
|
||||
// * At the beginning of string.
|
||||
// "_a" => "_A"
|
||||
// * At the end of string.
|
||||
// "ab_" => "Ab_"
|
||||
func ToCamelCase(str string) string {
|
||||
if len(str) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
var r0, r1 rune
|
||||
var size int
|
||||
|
||||
// leading '_' will appear in output.
|
||||
for len(str) > 0 {
|
||||
r0, size = utf8.DecodeRuneInString(str)
|
||||
str = str[size:]
|
||||
|
||||
if r0 != '_' {
|
||||
break
|
||||
}
|
||||
|
||||
buf.WriteRune(r0)
|
||||
}
|
||||
|
||||
if len(str) == 0 {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
r0 = unicode.ToUpper(r0)
|
||||
|
||||
for len(str) > 0 {
|
||||
r1 = r0
|
||||
r0, size = utf8.DecodeRuneInString(str)
|
||||
str = str[size:]
|
||||
|
||||
if r1 == '_' && r0 == '_' {
|
||||
buf.WriteRune(r1)
|
||||
continue
|
||||
}
|
||||
|
||||
if r1 == '_' {
|
||||
r0 = unicode.ToUpper(r0)
|
||||
} else {
|
||||
r0 = unicode.ToLower(r0)
|
||||
}
|
||||
|
||||
if r1 != '_' {
|
||||
buf.WriteRune(r1)
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteRune(r0)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ToSnakeCase can convert all upper case characters in a string to
|
||||
// snake case format.
|
||||
//
|
||||
// Some samples.
|
||||
// "FirstName" => "first_name"
|
||||
// "HTTPServer" => "http_server"
|
||||
// "NoHTTPS" => "no_https"
|
||||
// "GO_PATH" => "go_path"
|
||||
// "GO PATH" => "go_path" // space is converted to underscore.
|
||||
// "GO-PATH" => "go_path" // hyphen is converted to underscore.
|
||||
// "HTTP2XX" => "http_2xx" // insert an underscore before a number and after an alphabet.
|
||||
// "http2xx" => "http_2xx"
|
||||
// "HTTP20xOK" => "http_20x_ok"
|
||||
func ToSnakeCase(str string) string {
|
||||
return camelCaseToLowerCase(str, '_')
|
||||
}
|
||||
|
||||
// ToKebabCase can convert all upper case characters in a string to
|
||||
// kebab case format.
|
||||
//
|
||||
// Some samples.
|
||||
// "FirstName" => "first-name"
|
||||
// "HTTPServer" => "http-server"
|
||||
// "NoHTTPS" => "no-https"
|
||||
// "GO_PATH" => "go-path"
|
||||
// "GO PATH" => "go-path" // space is converted to '-'.
|
||||
// "GO-PATH" => "go-path" // hyphen is converted to '-'.
|
||||
// "HTTP2XX" => "http-2xx" // insert a '-' before a number and after an alphabet.
|
||||
// "http2xx" => "http-2xx"
|
||||
// "HTTP20xOK" => "http-20x-ok"
|
||||
func ToKebabCase(str string) string {
|
||||
return camelCaseToLowerCase(str, '-')
|
||||
}
|
||||
|
||||
func camelCaseToLowerCase(str string, connector rune) string {
|
||||
if len(str) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
var prev, r0, r1 rune
|
||||
var size int
|
||||
|
||||
r0 = connector
|
||||
|
||||
for len(str) > 0 {
|
||||
prev = r0
|
||||
r0, size = utf8.DecodeRuneInString(str)
|
||||
str = str[size:]
|
||||
|
||||
switch {
|
||||
case r0 == utf8.RuneError:
|
||||
buf.WriteRune(r0)
|
||||
|
||||
case unicode.IsUpper(r0):
|
||||
if prev != connector && !unicode.IsNumber(prev) {
|
||||
buf.WriteRune(connector)
|
||||
}
|
||||
|
||||
buf.WriteRune(unicode.ToLower(r0))
|
||||
|
||||
if len(str) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
r0, size = utf8.DecodeRuneInString(str)
|
||||
str = str[size:]
|
||||
|
||||
if !unicode.IsUpper(r0) {
|
||||
buf.WriteRune(r0)
|
||||
break
|
||||
}
|
||||
|
||||
// find next non-upper-case character and insert connector properly.
|
||||
// it's designed to convert `HTTPServer` to `http_server`.
|
||||
// if there are more than 2 adjacent upper case characters in a word,
|
||||
// treat them as an abbreviation plus a normal word.
|
||||
for len(str) > 0 {
|
||||
r1 = r0
|
||||
r0, size = utf8.DecodeRuneInString(str)
|
||||
str = str[size:]
|
||||
|
||||
if r0 == utf8.RuneError {
|
||||
buf.WriteRune(unicode.ToLower(r1))
|
||||
buf.WriteRune(r0)
|
||||
break
|
||||
}
|
||||
|
||||
if !unicode.IsUpper(r0) {
|
||||
if r0 == '_' || r0 == ' ' || r0 == '-' {
|
||||
r0 = connector
|
||||
|
||||
buf.WriteRune(unicode.ToLower(r1))
|
||||
} else if unicode.IsNumber(r0) {
|
||||
// treat a number as an upper case rune
|
||||
// so that both `http2xx` and `HTTP2XX` can be converted to `http_2xx`.
|
||||
buf.WriteRune(unicode.ToLower(r1))
|
||||
buf.WriteRune(connector)
|
||||
buf.WriteRune(r0)
|
||||
} else {
|
||||
buf.WriteRune(connector)
|
||||
buf.WriteRune(unicode.ToLower(r1))
|
||||
buf.WriteRune(r0)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
buf.WriteRune(unicode.ToLower(r1))
|
||||
}
|
||||
|
||||
if len(str) == 0 || r0 == connector {
|
||||
buf.WriteRune(unicode.ToLower(r0))
|
||||
}
|
||||
|
||||
case unicode.IsNumber(r0):
|
||||
if prev != connector && !unicode.IsNumber(prev) {
|
||||
buf.WriteRune(connector)
|
||||
}
|
||||
|
||||
buf.WriteRune(r0)
|
||||
|
||||
default:
|
||||
if r0 == ' ' || r0 == '-' || r0 == '_' {
|
||||
r0 = connector
|
||||
}
|
||||
|
||||
buf.WriteRune(r0)
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// SwapCase will swap characters case from upper to lower or lower to upper.
|
||||
func SwapCase(str string) string {
|
||||
var r rune
|
||||
var size int
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
for len(str) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(str)
|
||||
|
||||
switch {
|
||||
case unicode.IsUpper(r):
|
||||
buf.WriteRune(unicode.ToLower(r))
|
||||
|
||||
case unicode.IsLower(r):
|
||||
buf.WriteRune(unicode.ToUpper(r))
|
||||
|
||||
default:
|
||||
buf.WriteRune(r)
|
||||
}
|
||||
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// FirstRuneToUpper converts first rune to upper case if necessary.
|
||||
func FirstRuneToUpper(str string) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRuneInString(str)
|
||||
|
||||
if !unicode.IsLower(r) {
|
||||
return str
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteRune(unicode.ToUpper(r))
|
||||
buf.WriteString(str[size:])
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// FirstRuneToLower converts first rune to lower case if necessary.
|
||||
func FirstRuneToLower(str string) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRuneInString(str)
|
||||
|
||||
if !unicode.IsUpper(r) {
|
||||
return str
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteRune(unicode.ToLower(r))
|
||||
buf.WriteString(str[size:])
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Shuffle randomizes runes in a string and returns the result.
|
||||
// It uses default random source in `math/rand`.
|
||||
func Shuffle(str string) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
runes := []rune(str)
|
||||
index := 0
|
||||
|
||||
for i := len(runes) - 1; i > 0; i-- {
|
||||
index = rand.Intn(i + 1)
|
||||
|
||||
if i != index {
|
||||
runes[i], runes[index] = runes[index], runes[i]
|
||||
}
|
||||
}
|
||||
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// ShuffleSource randomizes runes in a string with given random source.
|
||||
func ShuffleSource(str string, src rand.Source) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
runes := []rune(str)
|
||||
index := 0
|
||||
r := rand.New(src)
|
||||
|
||||
for i := len(runes) - 1; i > 0; i-- {
|
||||
index = r.Intn(i + 1)
|
||||
|
||||
if i != index {
|
||||
runes[i], runes[index] = runes[index], runes[i]
|
||||
}
|
||||
}
|
||||
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// Successor returns the successor to string.
|
||||
//
|
||||
// If there is one alphanumeric rune is found in string, increase the rune by 1.
|
||||
// If increment generates a "carry", the rune to the left of it is incremented.
|
||||
// This process repeats until there is no carry, adding an additional rune if necessary.
|
||||
//
|
||||
// If there is no alphanumeric rune, the rightmost rune will be increased by 1
|
||||
// regardless whether the result is a valid rune or not.
|
||||
//
|
||||
// Only following characters are alphanumeric.
|
||||
// * a - z
|
||||
// * A - Z
|
||||
// * 0 - 9
|
||||
//
|
||||
// Samples (borrowed from ruby's String#succ document):
|
||||
// "abcd" => "abce"
|
||||
// "THX1138" => "THX1139"
|
||||
// "<<koala>>" => "<<koalb>>"
|
||||
// "1999zzz" => "2000aaa"
|
||||
// "ZZZ9999" => "AAAA0000"
|
||||
// "***" => "**+"
|
||||
func Successor(str string) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
var r rune
|
||||
var i int
|
||||
carry := ' '
|
||||
runes := []rune(str)
|
||||
l := len(runes)
|
||||
lastAlphanumeric := l
|
||||
|
||||
for i = l - 1; i >= 0; i-- {
|
||||
r = runes[i]
|
||||
|
||||
if ('a' <= r && r <= 'y') ||
|
||||
('A' <= r && r <= 'Y') ||
|
||||
('0' <= r && r <= '8') {
|
||||
runes[i]++
|
||||
carry = ' '
|
||||
lastAlphanumeric = i
|
||||
break
|
||||
}
|
||||
|
||||
switch r {
|
||||
case 'z':
|
||||
runes[i] = 'a'
|
||||
carry = 'a'
|
||||
lastAlphanumeric = i
|
||||
|
||||
case 'Z':
|
||||
runes[i] = 'A'
|
||||
carry = 'A'
|
||||
lastAlphanumeric = i
|
||||
|
||||
case '9':
|
||||
runes[i] = '0'
|
||||
carry = '0'
|
||||
lastAlphanumeric = i
|
||||
}
|
||||
}
|
||||
|
||||
// Needs to add one character for carry.
|
||||
if i < 0 && carry != ' ' {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.Grow(l + 4) // Reserve enough space for write.
|
||||
|
||||
if lastAlphanumeric != 0 {
|
||||
buf.WriteString(str[:lastAlphanumeric])
|
||||
}
|
||||
|
||||
buf.WriteRune(carry)
|
||||
|
||||
for _, r = range runes[lastAlphanumeric:] {
|
||||
buf.WriteRune(r)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// No alphanumeric character. Simply increase last rune's value.
|
||||
if lastAlphanumeric == l {
|
||||
runes[l-1]++
|
||||
}
|
||||
|
||||
return string(runes)
|
||||
}
|
||||
120
vendor/github.com/huandu/xstrings/count.go
generated
vendored
Normal file
120
vendor/github.com/huandu/xstrings/count.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright 2015 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package xstrings
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Len returns str's utf8 rune length.
|
||||
func Len(str string) int {
|
||||
return utf8.RuneCountInString(str)
|
||||
}
|
||||
|
||||
// WordCount returns number of words in a string.
|
||||
//
|
||||
// Word is defined as a locale dependent string containing alphabetic characters,
|
||||
// which may also contain but not start with `'` and `-` characters.
|
||||
func WordCount(str string) int {
|
||||
var r rune
|
||||
var size, n int
|
||||
|
||||
inWord := false
|
||||
|
||||
for len(str) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(str)
|
||||
|
||||
switch {
|
||||
case isAlphabet(r):
|
||||
if !inWord {
|
||||
inWord = true
|
||||
n++
|
||||
}
|
||||
|
||||
case inWord && (r == '\'' || r == '-'):
|
||||
// Still in word.
|
||||
|
||||
default:
|
||||
inWord = false
|
||||
}
|
||||
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
const minCJKCharacter = '\u3400'
|
||||
|
||||
// Checks r is a letter but not CJK character.
|
||||
func isAlphabet(r rune) bool {
|
||||
if !unicode.IsLetter(r) {
|
||||
return false
|
||||
}
|
||||
|
||||
switch {
|
||||
// Quick check for non-CJK character.
|
||||
case r < minCJKCharacter:
|
||||
return true
|
||||
|
||||
// Common CJK characters.
|
||||
case r >= '\u4E00' && r <= '\u9FCC':
|
||||
return false
|
||||
|
||||
// Rare CJK characters.
|
||||
case r >= '\u3400' && r <= '\u4D85':
|
||||
return false
|
||||
|
||||
// Rare and historic CJK characters.
|
||||
case r >= '\U00020000' && r <= '\U0002B81D':
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Width returns string width in monotype font.
|
||||
// Multi-byte characters are usually twice the width of single byte characters.
|
||||
//
|
||||
// Algorithm comes from `mb_strwidth` in PHP.
|
||||
// http://php.net/manual/en/function.mb-strwidth.php
|
||||
func Width(str string) int {
|
||||
var r rune
|
||||
var size, n int
|
||||
|
||||
for len(str) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(str)
|
||||
n += RuneWidth(r)
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// RuneWidth returns character width in monotype font.
|
||||
// Multi-byte characters are usually twice the width of single byte characters.
|
||||
//
|
||||
// Algorithm comes from `mb_strwidth` in PHP.
|
||||
// http://php.net/manual/en/function.mb-strwidth.php
|
||||
func RuneWidth(r rune) int {
|
||||
switch {
|
||||
case r == utf8.RuneError || r < '\x20':
|
||||
return 0
|
||||
|
||||
case '\x20' <= r && r < '\u2000':
|
||||
return 1
|
||||
|
||||
case '\u2000' <= r && r < '\uFF61':
|
||||
return 2
|
||||
|
||||
case '\uFF61' <= r && r < '\uFFA0':
|
||||
return 1
|
||||
|
||||
case '\uFFA0' <= r:
|
||||
return 2
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
8
vendor/github.com/huandu/xstrings/doc.go
generated
vendored
Normal file
8
vendor/github.com/huandu/xstrings/doc.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright 2015 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
// Package xstrings is to provide string algorithms which are useful but not included in `strings` package.
|
||||
// See project home page for details. https://github.com/huandu/xstrings
|
||||
//
|
||||
// Package xstrings assumes all strings are encoded in utf8.
|
||||
package xstrings
|
||||
170
vendor/github.com/huandu/xstrings/format.go
generated
vendored
Normal file
170
vendor/github.com/huandu/xstrings/format.go
generated
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright 2015 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package xstrings
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// ExpandTabs can expand tabs ('\t') rune in str to one or more spaces dpending on
|
||||
// current column and tabSize.
|
||||
// The column number is reset to zero after each newline ('\n') occurring in the str.
|
||||
//
|
||||
// ExpandTabs uses RuneWidth to decide rune's width.
|
||||
// For example, CJK characters will be treated as two characters.
|
||||
//
|
||||
// If tabSize <= 0, ExpandTabs panics with error.
|
||||
//
|
||||
// Samples:
|
||||
// ExpandTabs("a\tbc\tdef\tghij\tk", 4) => "a bc def ghij k"
|
||||
// ExpandTabs("abcdefg\thij\nk\tl", 4) => "abcdefg hij\nk l"
|
||||
// ExpandTabs("z中\t文\tw", 4) => "z中 文 w"
|
||||
func ExpandTabs(str string, tabSize int) string {
|
||||
if tabSize <= 0 {
|
||||
panic("tab size must be positive")
|
||||
}
|
||||
|
||||
var r rune
|
||||
var i, size, column, expand int
|
||||
var output *bytes.Buffer
|
||||
|
||||
orig := str
|
||||
|
||||
for len(str) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(str)
|
||||
|
||||
if r == '\t' {
|
||||
expand = tabSize - column%tabSize
|
||||
|
||||
if output == nil {
|
||||
output = allocBuffer(orig, str)
|
||||
}
|
||||
|
||||
for i = 0; i < expand; i++ {
|
||||
output.WriteByte(byte(' '))
|
||||
}
|
||||
|
||||
column += expand
|
||||
} else {
|
||||
if r == '\n' {
|
||||
column = 0
|
||||
} else {
|
||||
column += RuneWidth(r)
|
||||
}
|
||||
|
||||
if output != nil {
|
||||
output.WriteRune(r)
|
||||
}
|
||||
}
|
||||
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
if output == nil {
|
||||
return orig
|
||||
}
|
||||
|
||||
return output.String()
|
||||
}
|
||||
|
||||
// LeftJustify returns a string with pad string at right side if str's rune length is smaller than length.
|
||||
// If str's rune length is larger than length, str itself will be returned.
|
||||
//
|
||||
// If pad is an empty string, str will be returned.
|
||||
//
|
||||
// Samples:
|
||||
// LeftJustify("hello", 4, " ") => "hello"
|
||||
// LeftJustify("hello", 10, " ") => "hello "
|
||||
// LeftJustify("hello", 10, "123") => "hello12312"
|
||||
func LeftJustify(str string, length int, pad string) string {
|
||||
l := Len(str)
|
||||
|
||||
if l >= length || pad == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
remains := length - l
|
||||
padLen := Len(pad)
|
||||
|
||||
output := &bytes.Buffer{}
|
||||
output.Grow(len(str) + (remains/padLen+1)*len(pad))
|
||||
output.WriteString(str)
|
||||
writePadString(output, pad, padLen, remains)
|
||||
return output.String()
|
||||
}
|
||||
|
||||
// RightJustify returns a string with pad string at left side if str's rune length is smaller than length.
|
||||
// If str's rune length is larger than length, str itself will be returned.
|
||||
//
|
||||
// If pad is an empty string, str will be returned.
|
||||
//
|
||||
// Samples:
|
||||
// RightJustify("hello", 4, " ") => "hello"
|
||||
// RightJustify("hello", 10, " ") => " hello"
|
||||
// RightJustify("hello", 10, "123") => "12312hello"
|
||||
func RightJustify(str string, length int, pad string) string {
|
||||
l := Len(str)
|
||||
|
||||
if l >= length || pad == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
remains := length - l
|
||||
padLen := Len(pad)
|
||||
|
||||
output := &bytes.Buffer{}
|
||||
output.Grow(len(str) + (remains/padLen+1)*len(pad))
|
||||
writePadString(output, pad, padLen, remains)
|
||||
output.WriteString(str)
|
||||
return output.String()
|
||||
}
|
||||
|
||||
// Center returns a string with pad string at both side if str's rune length is smaller than length.
|
||||
// If str's rune length is larger than length, str itself will be returned.
|
||||
//
|
||||
// If pad is an empty string, str will be returned.
|
||||
//
|
||||
// Samples:
|
||||
// Center("hello", 4, " ") => "hello"
|
||||
// Center("hello", 10, " ") => " hello "
|
||||
// Center("hello", 10, "123") => "12hello123"
|
||||
func Center(str string, length int, pad string) string {
|
||||
l := Len(str)
|
||||
|
||||
if l >= length || pad == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
remains := length - l
|
||||
padLen := Len(pad)
|
||||
|
||||
output := &bytes.Buffer{}
|
||||
output.Grow(len(str) + (remains/padLen+1)*len(pad))
|
||||
writePadString(output, pad, padLen, remains/2)
|
||||
output.WriteString(str)
|
||||
writePadString(output, pad, padLen, (remains+1)/2)
|
||||
return output.String()
|
||||
}
|
||||
|
||||
func writePadString(output *bytes.Buffer, pad string, padLen, remains int) {
|
||||
var r rune
|
||||
var size int
|
||||
|
||||
repeats := remains / padLen
|
||||
|
||||
for i := 0; i < repeats; i++ {
|
||||
output.WriteString(pad)
|
||||
}
|
||||
|
||||
remains = remains % padLen
|
||||
|
||||
if remains != 0 {
|
||||
for i := 0; i < remains; i++ {
|
||||
r, size = utf8.DecodeRuneInString(pad)
|
||||
output.WriteRune(r)
|
||||
pad = pad[size:]
|
||||
}
|
||||
}
|
||||
}
|
||||
1
vendor/github.com/huandu/xstrings/go.mod
generated
vendored
Normal file
1
vendor/github.com/huandu/xstrings/go.mod
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/huandu/xstrings
|
||||
217
vendor/github.com/huandu/xstrings/manipulate.go
generated
vendored
Normal file
217
vendor/github.com/huandu/xstrings/manipulate.go
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
// Copyright 2015 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package xstrings
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Reverse a utf8 encoded string.
|
||||
func Reverse(str string) string {
|
||||
var size int
|
||||
|
||||
tail := len(str)
|
||||
buf := make([]byte, tail)
|
||||
s := buf
|
||||
|
||||
for len(str) > 0 {
|
||||
_, size = utf8.DecodeRuneInString(str)
|
||||
tail -= size
|
||||
s = append(s[:tail], []byte(str[:size])...)
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
// Slice a string by rune.
|
||||
//
|
||||
// Start must satisfy 0 <= start <= rune length.
|
||||
//
|
||||
// End can be positive, zero or negative.
|
||||
// If end >= 0, start and end must satisfy start <= end <= rune length.
|
||||
// If end < 0, it means slice to the end of string.
|
||||
//
|
||||
// Otherwise, Slice will panic as out of range.
|
||||
func Slice(str string, start, end int) string {
|
||||
var size, startPos, endPos int
|
||||
|
||||
origin := str
|
||||
|
||||
if start < 0 || end > len(str) || (end >= 0 && start > end) {
|
||||
panic("out of range")
|
||||
}
|
||||
|
||||
if end >= 0 {
|
||||
end -= start
|
||||
}
|
||||
|
||||
for start > 0 && len(str) > 0 {
|
||||
_, size = utf8.DecodeRuneInString(str)
|
||||
start--
|
||||
startPos += size
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
if end < 0 {
|
||||
return origin[startPos:]
|
||||
}
|
||||
|
||||
endPos = startPos
|
||||
|
||||
for end > 0 && len(str) > 0 {
|
||||
_, size = utf8.DecodeRuneInString(str)
|
||||
end--
|
||||
endPos += size
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
if len(str) == 0 && (start > 0 || end > 0) {
|
||||
panic("out of range")
|
||||
}
|
||||
|
||||
return origin[startPos:endPos]
|
||||
}
|
||||
|
||||
// Partition splits a string by sep into three parts.
|
||||
// The return value is a slice of strings with head, match and tail.
|
||||
//
|
||||
// If str contains sep, for example "hello" and "l", Partition returns
|
||||
// "he", "l", "lo"
|
||||
//
|
||||
// If str doesn't contain sep, for example "hello" and "x", Partition returns
|
||||
// "hello", "", ""
|
||||
func Partition(str, sep string) (head, match, tail string) {
|
||||
index := strings.Index(str, sep)
|
||||
|
||||
if index == -1 {
|
||||
head = str
|
||||
return
|
||||
}
|
||||
|
||||
head = str[:index]
|
||||
match = str[index : index+len(sep)]
|
||||
tail = str[index+len(sep):]
|
||||
return
|
||||
}
|
||||
|
||||
// LastPartition splits a string by last instance of sep into three parts.
|
||||
// The return value is a slice of strings with head, match and tail.
|
||||
//
|
||||
// If str contains sep, for example "hello" and "l", LastPartition returns
|
||||
// "hel", "l", "o"
|
||||
//
|
||||
// If str doesn't contain sep, for example "hello" and "x", LastPartition returns
|
||||
// "", "", "hello"
|
||||
func LastPartition(str, sep string) (head, match, tail string) {
|
||||
index := strings.LastIndex(str, sep)
|
||||
|
||||
if index == -1 {
|
||||
tail = str
|
||||
return
|
||||
}
|
||||
|
||||
head = str[:index]
|
||||
match = str[index : index+len(sep)]
|
||||
tail = str[index+len(sep):]
|
||||
return
|
||||
}
|
||||
|
||||
// Insert src into dst at given rune index.
|
||||
// Index is counted by runes instead of bytes.
|
||||
//
|
||||
// If index is out of range of dst, panic with out of range.
|
||||
func Insert(dst, src string, index int) string {
|
||||
return Slice(dst, 0, index) + src + Slice(dst, index, -1)
|
||||
}
|
||||
|
||||
// Scrub scrubs invalid utf8 bytes with repl string.
|
||||
// Adjacent invalid bytes are replaced only once.
|
||||
func Scrub(str, repl string) string {
|
||||
var buf *bytes.Buffer
|
||||
var r rune
|
||||
var size, pos int
|
||||
var hasError bool
|
||||
|
||||
origin := str
|
||||
|
||||
for len(str) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(str)
|
||||
|
||||
if r == utf8.RuneError {
|
||||
if !hasError {
|
||||
if buf == nil {
|
||||
buf = &bytes.Buffer{}
|
||||
}
|
||||
|
||||
buf.WriteString(origin[:pos])
|
||||
hasError = true
|
||||
}
|
||||
} else if hasError {
|
||||
hasError = false
|
||||
buf.WriteString(repl)
|
||||
|
||||
origin = origin[pos:]
|
||||
pos = 0
|
||||
}
|
||||
|
||||
pos += size
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
if buf != nil {
|
||||
buf.WriteString(origin)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// No invalid byte.
|
||||
return origin
|
||||
}
|
||||
|
||||
// WordSplit splits a string into words. Returns a slice of words.
|
||||
// If there is no word in a string, return nil.
|
||||
//
|
||||
// Word is defined as a locale dependent string containing alphabetic characters,
|
||||
// which may also contain but not start with `'` and `-` characters.
|
||||
func WordSplit(str string) []string {
|
||||
var word string
|
||||
var words []string
|
||||
var r rune
|
||||
var size, pos int
|
||||
|
||||
inWord := false
|
||||
|
||||
for len(str) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(str)
|
||||
|
||||
switch {
|
||||
case isAlphabet(r):
|
||||
if !inWord {
|
||||
inWord = true
|
||||
word = str
|
||||
pos = 0
|
||||
}
|
||||
|
||||
case inWord && (r == '\'' || r == '-'):
|
||||
// Still in word.
|
||||
|
||||
default:
|
||||
if inWord {
|
||||
inWord = false
|
||||
words = append(words, word[:pos])
|
||||
}
|
||||
}
|
||||
|
||||
pos += size
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
if inWord {
|
||||
words = append(words, word[:pos])
|
||||
}
|
||||
|
||||
return words
|
||||
}
|
||||
547
vendor/github.com/huandu/xstrings/translate.go
generated
vendored
Normal file
547
vendor/github.com/huandu/xstrings/translate.go
generated
vendored
Normal file
@@ -0,0 +1,547 @@
|
||||
// Copyright 2015 Huan Du. All rights reserved.
|
||||
// Licensed under the MIT license that can be found in the LICENSE file.
|
||||
|
||||
package xstrings
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type runeRangeMap struct {
|
||||
FromLo rune // Lower bound of range map.
|
||||
FromHi rune // An inclusive higher bound of range map.
|
||||
ToLo rune
|
||||
ToHi rune
|
||||
}
|
||||
|
||||
type runeDict struct {
|
||||
Dict [unicode.MaxASCII + 1]rune
|
||||
}
|
||||
|
||||
type runeMap map[rune]rune
|
||||
|
||||
// Translator can translate string with pre-compiled from and to patterns.
|
||||
// If a from/to pattern pair needs to be used more than once, it's recommended
|
||||
// to create a Translator and reuse it.
|
||||
type Translator struct {
|
||||
quickDict *runeDict // A quick dictionary to look up rune by index. Only availabe for latin runes.
|
||||
runeMap runeMap // Rune map for translation.
|
||||
ranges []*runeRangeMap // Ranges of runes.
|
||||
mappedRune rune // If mappedRune >= 0, all matched runes are translated to the mappedRune.
|
||||
reverted bool // If to pattern is empty, all matched characters will be deleted.
|
||||
hasPattern bool
|
||||
}
|
||||
|
||||
// NewTranslator creates new Translator through a from/to pattern pair.
|
||||
func NewTranslator(from, to string) *Translator {
|
||||
tr := &Translator{}
|
||||
|
||||
if from == "" {
|
||||
return tr
|
||||
}
|
||||
|
||||
reverted := from[0] == '^'
|
||||
deletion := len(to) == 0
|
||||
|
||||
if reverted {
|
||||
from = from[1:]
|
||||
}
|
||||
|
||||
var fromStart, fromEnd, fromRangeStep rune
|
||||
var toStart, toEnd, toRangeStep rune
|
||||
var fromRangeSize, toRangeSize rune
|
||||
var singleRunes []rune
|
||||
|
||||
// Update the to rune range.
|
||||
updateRange := func() {
|
||||
// No more rune to read in the to rune pattern.
|
||||
if toEnd == utf8.RuneError {
|
||||
return
|
||||
}
|
||||
|
||||
if toRangeStep == 0 {
|
||||
to, toStart, toEnd, toRangeStep = nextRuneRange(to, toEnd)
|
||||
return
|
||||
}
|
||||
|
||||
// Current range is not empty. Consume 1 rune from start.
|
||||
if toStart != toEnd {
|
||||
toStart += toRangeStep
|
||||
return
|
||||
}
|
||||
|
||||
// No more rune. Repeat the last rune.
|
||||
if to == "" {
|
||||
toEnd = utf8.RuneError
|
||||
return
|
||||
}
|
||||
|
||||
// Both start and end are used. Read two more runes from the to pattern.
|
||||
to, toStart, toEnd, toRangeStep = nextRuneRange(to, utf8.RuneError)
|
||||
}
|
||||
|
||||
if deletion {
|
||||
toStart = utf8.RuneError
|
||||
toEnd = utf8.RuneError
|
||||
} else {
|
||||
// If from pattern is reverted, only the last rune in the to pattern will be used.
|
||||
if reverted {
|
||||
var size int
|
||||
|
||||
for len(to) > 0 {
|
||||
toStart, size = utf8.DecodeRuneInString(to)
|
||||
to = to[size:]
|
||||
}
|
||||
|
||||
toEnd = utf8.RuneError
|
||||
} else {
|
||||
to, toStart, toEnd, toRangeStep = nextRuneRange(to, utf8.RuneError)
|
||||
}
|
||||
}
|
||||
|
||||
fromEnd = utf8.RuneError
|
||||
|
||||
for len(from) > 0 {
|
||||
from, fromStart, fromEnd, fromRangeStep = nextRuneRange(from, fromEnd)
|
||||
|
||||
// fromStart is a single character. Just map it with a rune in the to pattern.
|
||||
if fromRangeStep == 0 {
|
||||
singleRunes = tr.addRune(fromStart, toStart, singleRunes)
|
||||
updateRange()
|
||||
continue
|
||||
}
|
||||
|
||||
for toEnd != utf8.RuneError && fromStart != fromEnd {
|
||||
// If mapped rune is a single character instead of a range, simply shift first
|
||||
// rune in the range.
|
||||
if toRangeStep == 0 {
|
||||
singleRunes = tr.addRune(fromStart, toStart, singleRunes)
|
||||
updateRange()
|
||||
fromStart += fromRangeStep
|
||||
continue
|
||||
}
|
||||
|
||||
fromRangeSize = (fromEnd - fromStart) * fromRangeStep
|
||||
toRangeSize = (toEnd - toStart) * toRangeStep
|
||||
|
||||
// Not enough runes in the to pattern. Need to read more.
|
||||
if fromRangeSize > toRangeSize {
|
||||
fromStart, toStart = tr.addRuneRange(fromStart, fromStart+toRangeSize*fromRangeStep, toStart, toEnd, singleRunes)
|
||||
fromStart += fromRangeStep
|
||||
updateRange()
|
||||
|
||||
// Edge case: If fromRangeSize == toRangeSize + 1, the last fromStart value needs be considered
|
||||
// as a single rune.
|
||||
if fromStart == fromEnd {
|
||||
singleRunes = tr.addRune(fromStart, toStart, singleRunes)
|
||||
updateRange()
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
fromStart, toStart = tr.addRuneRange(fromStart, fromEnd, toStart, toStart+fromRangeSize*toRangeStep, singleRunes)
|
||||
updateRange()
|
||||
break
|
||||
}
|
||||
|
||||
if fromStart == fromEnd {
|
||||
fromEnd = utf8.RuneError
|
||||
continue
|
||||
}
|
||||
|
||||
fromStart, toStart = tr.addRuneRange(fromStart, fromEnd, toStart, toStart, singleRunes)
|
||||
fromEnd = utf8.RuneError
|
||||
}
|
||||
|
||||
if fromEnd != utf8.RuneError {
|
||||
singleRunes = tr.addRune(fromEnd, toStart, singleRunes)
|
||||
}
|
||||
|
||||
tr.reverted = reverted
|
||||
tr.mappedRune = -1
|
||||
tr.hasPattern = true
|
||||
|
||||
// Translate RuneError only if in deletion or reverted mode.
|
||||
if deletion || reverted {
|
||||
tr.mappedRune = toStart
|
||||
}
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
func (tr *Translator) addRune(from, to rune, singleRunes []rune) []rune {
|
||||
if from <= unicode.MaxASCII {
|
||||
if tr.quickDict == nil {
|
||||
tr.quickDict = &runeDict{}
|
||||
}
|
||||
|
||||
tr.quickDict.Dict[from] = to
|
||||
} else {
|
||||
if tr.runeMap == nil {
|
||||
tr.runeMap = make(runeMap)
|
||||
}
|
||||
|
||||
tr.runeMap[from] = to
|
||||
}
|
||||
|
||||
singleRunes = append(singleRunes, from)
|
||||
return singleRunes
|
||||
}
|
||||
|
||||
func (tr *Translator) addRuneRange(fromLo, fromHi, toLo, toHi rune, singleRunes []rune) (rune, rune) {
|
||||
var r rune
|
||||
var rrm *runeRangeMap
|
||||
|
||||
if fromLo < fromHi {
|
||||
rrm = &runeRangeMap{
|
||||
FromLo: fromLo,
|
||||
FromHi: fromHi,
|
||||
ToLo: toLo,
|
||||
ToHi: toHi,
|
||||
}
|
||||
} else {
|
||||
rrm = &runeRangeMap{
|
||||
FromLo: fromHi,
|
||||
FromHi: fromLo,
|
||||
ToLo: toHi,
|
||||
ToHi: toLo,
|
||||
}
|
||||
}
|
||||
|
||||
// If there is any single rune conflicts with this rune range, clear single rune record.
|
||||
for _, r = range singleRunes {
|
||||
if rrm.FromLo <= r && r <= rrm.FromHi {
|
||||
if r <= unicode.MaxASCII {
|
||||
tr.quickDict.Dict[r] = 0
|
||||
} else {
|
||||
delete(tr.runeMap, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tr.ranges = append(tr.ranges, rrm)
|
||||
return fromHi, toHi
|
||||
}
|
||||
|
||||
func nextRuneRange(str string, last rune) (remaining string, start, end rune, rangeStep rune) {
|
||||
var r rune
|
||||
var size int
|
||||
|
||||
remaining = str
|
||||
escaping := false
|
||||
isRange := false
|
||||
|
||||
for len(remaining) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(remaining)
|
||||
remaining = remaining[size:]
|
||||
|
||||
// Parse special characters.
|
||||
if !escaping {
|
||||
if r == '\\' {
|
||||
escaping = true
|
||||
continue
|
||||
}
|
||||
|
||||
if r == '-' {
|
||||
// Ignore slash at beginning of string.
|
||||
if last == utf8.RuneError {
|
||||
continue
|
||||
}
|
||||
|
||||
start = last
|
||||
isRange = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
escaping = false
|
||||
|
||||
if last != utf8.RuneError {
|
||||
// This is a range which start and end are the same.
|
||||
// Considier it as a normal character.
|
||||
if isRange && last == r {
|
||||
isRange = false
|
||||
continue
|
||||
}
|
||||
|
||||
start = last
|
||||
end = r
|
||||
|
||||
if isRange {
|
||||
if start < end {
|
||||
rangeStep = 1
|
||||
} else {
|
||||
rangeStep = -1
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
last = r
|
||||
}
|
||||
|
||||
start = last
|
||||
end = utf8.RuneError
|
||||
return
|
||||
}
|
||||
|
||||
// Translate str with a from/to pattern pair.
|
||||
//
|
||||
// See comment in Translate function for usage and samples.
|
||||
func (tr *Translator) Translate(str string) string {
|
||||
if !tr.hasPattern || str == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
var r rune
|
||||
var size int
|
||||
var needTr bool
|
||||
|
||||
orig := str
|
||||
|
||||
var output *bytes.Buffer
|
||||
|
||||
for len(str) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(str)
|
||||
r, needTr = tr.TranslateRune(r)
|
||||
|
||||
if needTr && output == nil {
|
||||
output = allocBuffer(orig, str)
|
||||
}
|
||||
|
||||
if r != utf8.RuneError && output != nil {
|
||||
output.WriteRune(r)
|
||||
}
|
||||
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
// No character is translated.
|
||||
if output == nil {
|
||||
return orig
|
||||
}
|
||||
|
||||
return output.String()
|
||||
}
|
||||
|
||||
// TranslateRune return translated rune and true if r matches the from pattern.
|
||||
// If r doesn't match the pattern, original r is returned and translated is false.
|
||||
func (tr *Translator) TranslateRune(r rune) (result rune, translated bool) {
|
||||
switch {
|
||||
case tr.quickDict != nil:
|
||||
if r <= unicode.MaxASCII {
|
||||
result = tr.quickDict.Dict[r]
|
||||
|
||||
if result != 0 {
|
||||
translated = true
|
||||
|
||||
if tr.mappedRune >= 0 {
|
||||
result = tr.mappedRune
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
fallthrough
|
||||
|
||||
case tr.runeMap != nil:
|
||||
var ok bool
|
||||
|
||||
if result, ok = tr.runeMap[r]; ok {
|
||||
translated = true
|
||||
|
||||
if tr.mappedRune >= 0 {
|
||||
result = tr.mappedRune
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
fallthrough
|
||||
|
||||
default:
|
||||
var rrm *runeRangeMap
|
||||
ranges := tr.ranges
|
||||
|
||||
for i := len(ranges) - 1; i >= 0; i-- {
|
||||
rrm = ranges[i]
|
||||
|
||||
if rrm.FromLo <= r && r <= rrm.FromHi {
|
||||
translated = true
|
||||
|
||||
if tr.mappedRune >= 0 {
|
||||
result = tr.mappedRune
|
||||
break
|
||||
}
|
||||
|
||||
if rrm.ToLo < rrm.ToHi {
|
||||
result = rrm.ToLo + r - rrm.FromLo
|
||||
} else if rrm.ToLo > rrm.ToHi {
|
||||
// ToHi can be smaller than ToLo if range is from higher to lower.
|
||||
result = rrm.ToLo - r + rrm.FromLo
|
||||
} else {
|
||||
result = rrm.ToLo
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tr.reverted {
|
||||
if !translated {
|
||||
result = tr.mappedRune
|
||||
}
|
||||
|
||||
translated = !translated
|
||||
}
|
||||
|
||||
if !translated {
|
||||
result = r
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// HasPattern returns true if Translator has one pattern at least.
|
||||
func (tr *Translator) HasPattern() bool {
|
||||
return tr.hasPattern
|
||||
}
|
||||
|
||||
// Translate str with the characters defined in from replaced by characters defined in to.
|
||||
//
|
||||
// From and to are patterns representing a set of characters. Pattern is defined as following.
|
||||
//
|
||||
// * Special characters
|
||||
// * '-' means a range of runes, e.g.
|
||||
// * "a-z" means all characters from 'a' to 'z' inclusive;
|
||||
// * "z-a" means all characters from 'z' to 'a' inclusive.
|
||||
// * '^' as first character means a set of all runes excepted listed, e.g.
|
||||
// * "^a-z" means all characters except 'a' to 'z' inclusive.
|
||||
// * '\' escapes special characters.
|
||||
// * Normal character represents itself, e.g. "abc" is a set including 'a', 'b' and 'c'.
|
||||
//
|
||||
// Translate will try to find a 1:1 mapping from from to to.
|
||||
// If to is smaller than from, last rune in to will be used to map "out of range" characters in from.
|
||||
//
|
||||
// Note that '^' only works in the from pattern. It will be considered as a normal character in the to pattern.
|
||||
//
|
||||
// If the to pattern is an empty string, Translate works exactly the same as Delete.
|
||||
//
|
||||
// Samples:
|
||||
// Translate("hello", "aeiou", "12345") => "h2ll4"
|
||||
// Translate("hello", "a-z", "A-Z") => "HELLO"
|
||||
// Translate("hello", "z-a", "a-z") => "svool"
|
||||
// Translate("hello", "aeiou", "*") => "h*ll*"
|
||||
// Translate("hello", "^l", "*") => "**ll*"
|
||||
// Translate("hello ^ world", `\^lo`, "*") => "he*** * w*r*d"
|
||||
func Translate(str, from, to string) string {
|
||||
tr := NewTranslator(from, to)
|
||||
return tr.Translate(str)
|
||||
}
|
||||
|
||||
// Delete runes in str matching the pattern.
|
||||
// Pattern is defined in Translate function.
|
||||
//
|
||||
// Samples:
|
||||
// Delete("hello", "aeiou") => "hll"
|
||||
// Delete("hello", "a-k") => "llo"
|
||||
// Delete("hello", "^a-k") => "he"
|
||||
func Delete(str, pattern string) string {
|
||||
tr := NewTranslator(pattern, "")
|
||||
return tr.Translate(str)
|
||||
}
|
||||
|
||||
// Count how many runes in str match the pattern.
|
||||
// Pattern is defined in Translate function.
|
||||
//
|
||||
// Samples:
|
||||
// Count("hello", "aeiou") => 3
|
||||
// Count("hello", "a-k") => 3
|
||||
// Count("hello", "^a-k") => 2
|
||||
func Count(str, pattern string) int {
|
||||
if pattern == "" || str == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
var r rune
|
||||
var size int
|
||||
var matched bool
|
||||
|
||||
tr := NewTranslator(pattern, "")
|
||||
cnt := 0
|
||||
|
||||
for len(str) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(str)
|
||||
str = str[size:]
|
||||
|
||||
if _, matched = tr.TranslateRune(r); matched {
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
|
||||
return cnt
|
||||
}
|
||||
|
||||
// Squeeze deletes adjacent repeated runes in str.
|
||||
// If pattern is not empty, only runes matching the pattern will be squeezed.
|
||||
//
|
||||
// Samples:
|
||||
// Squeeze("hello", "") => "helo"
|
||||
// Squeeze("hello", "m-z") => "hello"
|
||||
// Squeeze("hello world", " ") => "hello world"
|
||||
func Squeeze(str, pattern string) string {
|
||||
var last, r rune
|
||||
var size int
|
||||
var skipSqueeze, matched bool
|
||||
var tr *Translator
|
||||
var output *bytes.Buffer
|
||||
|
||||
orig := str
|
||||
last = -1
|
||||
|
||||
if len(pattern) > 0 {
|
||||
tr = NewTranslator(pattern, "")
|
||||
}
|
||||
|
||||
for len(str) > 0 {
|
||||
r, size = utf8.DecodeRuneInString(str)
|
||||
|
||||
// Need to squeeze the str.
|
||||
if last == r && !skipSqueeze {
|
||||
if tr != nil {
|
||||
if _, matched = tr.TranslateRune(r); !matched {
|
||||
skipSqueeze = true
|
||||
}
|
||||
}
|
||||
|
||||
if output == nil {
|
||||
output = allocBuffer(orig, str)
|
||||
}
|
||||
|
||||
if skipSqueeze {
|
||||
output.WriteRune(r)
|
||||
}
|
||||
} else {
|
||||
if output != nil {
|
||||
output.WriteRune(r)
|
||||
}
|
||||
|
||||
last = r
|
||||
skipSqueeze = false
|
||||
}
|
||||
|
||||
str = str[size:]
|
||||
}
|
||||
|
||||
if output == nil {
|
||||
return orig
|
||||
}
|
||||
|
||||
return output.String()
|
||||
}
|
||||
24
vendor/github.com/jmoiron/sqlx/.gitignore
generated
vendored
Normal file
24
vendor/github.com/jmoiron/sqlx/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
tags
|
||||
environ
|
||||
27
vendor/github.com/jmoiron/sqlx/.travis.yml
generated
vendored
Normal file
27
vendor/github.com/jmoiron/sqlx/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# vim: ft=yaml sw=2 ts=2
|
||||
|
||||
language: go
|
||||
|
||||
# enable database services
|
||||
services:
|
||||
- mysql
|
||||
- postgresql
|
||||
|
||||
# create test database
|
||||
before_install:
|
||||
- mysql -e 'CREATE DATABASE IF NOT EXISTS sqlxtest;'
|
||||
- psql -c 'create database sqlxtest;' -U postgres
|
||||
- go get github.com/mattn/goveralls
|
||||
- export SQLX_MYSQL_DSN="travis:@/sqlxtest?parseTime=true"
|
||||
- export SQLX_POSTGRES_DSN="postgres://postgres:@localhost/sqlxtest?sslmode=disable"
|
||||
- export SQLX_SQLITE_DSN="$HOME/sqlxtest.db"
|
||||
|
||||
# go versions to test
|
||||
go:
|
||||
- "1.8"
|
||||
- "1.9"
|
||||
- "1.10.x"
|
||||
|
||||
# run tests w/ coverage
|
||||
script:
|
||||
- travis_retry $GOPATH/bin/goveralls -service=travis-ci
|
||||
23
vendor/github.com/jmoiron/sqlx/LICENSE
generated
vendored
Normal file
23
vendor/github.com/jmoiron/sqlx/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Copyright (c) 2013, Jason Moiron
|
||||
|
||||
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.
|
||||
|
||||
187
vendor/github.com/jmoiron/sqlx/README.md
generated
vendored
Normal file
187
vendor/github.com/jmoiron/sqlx/README.md
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
# sqlx
|
||||
|
||||
[](https://travis-ci.org/jmoiron/sqlx) [](https://coveralls.io/github/jmoiron/sqlx?branch=master) [](https://godoc.org/github.com/jmoiron/sqlx) [](https://raw.githubusercontent.com/jmoiron/sqlx/master/LICENSE)
|
||||
|
||||
sqlx is a library which provides a set of extensions on go's standard
|
||||
`database/sql` library. The sqlx versions of `sql.DB`, `sql.TX`, `sql.Stmt`,
|
||||
et al. all leave the underlying interfaces untouched, so that their interfaces
|
||||
are a superset on the standard ones. This makes it relatively painless to
|
||||
integrate existing codebases using database/sql with sqlx.
|
||||
|
||||
Major additional concepts are:
|
||||
|
||||
* Marshal rows into structs (with embedded struct support), maps, and slices
|
||||
* Named parameter support including prepared statements
|
||||
* `Get` and `Select` to go quickly from query to struct/slice
|
||||
|
||||
In addition to the [godoc API documentation](http://godoc.org/github.com/jmoiron/sqlx),
|
||||
there is also some [standard documentation](http://jmoiron.github.io/sqlx/) that
|
||||
explains how to use `database/sql` along with sqlx.
|
||||
|
||||
## Recent Changes
|
||||
|
||||
* The [introduction](https://github.com/jmoiron/sqlx/pull/387) of `sql.ColumnType` sets the required minimum Go version to 1.8.
|
||||
|
||||
* sqlx/types.JsonText has been renamed to JSONText to follow Go naming conventions.
|
||||
|
||||
This breaks backwards compatibility, but it's in a way that is trivially fixable
|
||||
(`s/JsonText/JSONText/g`). The `types` package is both experimental and not in
|
||||
active development currently.
|
||||
|
||||
* Using Go 1.6 and below with `types.JSONText` and `types.GzippedText` can be _potentially unsafe_, **especially** when used with common auto-scan sqlx idioms like `Select` and `Get`. See [golang bug #13905](https://github.com/golang/go/issues/13905).
|
||||
|
||||
### Backwards Compatibility
|
||||
|
||||
There is no Go1-like promise of absolute stability, but I take the issue seriously
|
||||
and will maintain the library in a compatible state unless vital bugs prevent me
|
||||
from doing so. Since [#59](https://github.com/jmoiron/sqlx/issues/59) and
|
||||
[#60](https://github.com/jmoiron/sqlx/issues/60) necessitated breaking behavior,
|
||||
a wider API cleanup was done at the time of fixing. It's possible this will happen
|
||||
in future; if it does, a git tag will be provided for users requiring the old
|
||||
behavior to continue to use it until such a time as they can migrate.
|
||||
|
||||
## install
|
||||
|
||||
go get github.com/jmoiron/sqlx
|
||||
|
||||
## issues
|
||||
|
||||
Row headers can be ambiguous (`SELECT 1 AS a, 2 AS a`), and the result of
|
||||
`Columns()` does not fully qualify column names in queries like:
|
||||
|
||||
```sql
|
||||
SELECT a.id, a.name, b.id, b.name FROM foos AS a JOIN foos AS b ON a.parent = b.id;
|
||||
```
|
||||
|
||||
making a struct or map destination ambiguous. Use `AS` in your queries
|
||||
to give columns distinct names, `rows.Scan` to scan them manually, or
|
||||
`SliceScan` to get a slice of results.
|
||||
|
||||
## usage
|
||||
|
||||
Below is an example which shows some common use cases for sqlx. Check
|
||||
[sqlx_test.go](https://github.com/jmoiron/sqlx/blob/master/sqlx_test.go) for more
|
||||
usage.
|
||||
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
var schema = `
|
||||
CREATE TABLE person (
|
||||
first_name text,
|
||||
last_name text,
|
||||
email text
|
||||
);
|
||||
|
||||
CREATE TABLE place (
|
||||
country text,
|
||||
city text NULL,
|
||||
telcode integer
|
||||
)`
|
||||
|
||||
type Person struct {
|
||||
FirstName string `db:"first_name"`
|
||||
LastName string `db:"last_name"`
|
||||
Email string
|
||||
}
|
||||
|
||||
type Place struct {
|
||||
Country string
|
||||
City sql.NullString
|
||||
TelCode int
|
||||
}
|
||||
|
||||
func main() {
|
||||
// this Pings the database trying to connect, panics on error
|
||||
// use sqlx.Open() for sql.Open() semantics
|
||||
db, err := sqlx.Connect("postgres", "user=foo dbname=bar sslmode=disable")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// exec the schema or fail; multi-statement Exec behavior varies between
|
||||
// database drivers; pq will exec them all, sqlite3 won't, ymmv
|
||||
db.MustExec(schema)
|
||||
|
||||
tx := db.MustBegin()
|
||||
tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "Jason", "Moiron", "jmoiron@jmoiron.net")
|
||||
tx.MustExec("INSERT INTO person (first_name, last_name, email) VALUES ($1, $2, $3)", "John", "Doe", "johndoeDNE@gmail.net")
|
||||
tx.MustExec("INSERT INTO place (country, city, telcode) VALUES ($1, $2, $3)", "United States", "New York", "1")
|
||||
tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Hong Kong", "852")
|
||||
tx.MustExec("INSERT INTO place (country, telcode) VALUES ($1, $2)", "Singapore", "65")
|
||||
// Named queries can use structs, so if you have an existing struct (i.e. person := &Person{}) that you have populated, you can pass it in as &person
|
||||
tx.NamedExec("INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)", &Person{"Jane", "Citizen", "jane.citzen@example.com"})
|
||||
tx.Commit()
|
||||
|
||||
// Query the database, storing results in a []Person (wrapped in []interface{})
|
||||
people := []Person{}
|
||||
db.Select(&people, "SELECT * FROM person ORDER BY first_name ASC")
|
||||
jason, john := people[0], people[1]
|
||||
|
||||
fmt.Printf("%#v\n%#v", jason, john)
|
||||
// Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"}
|
||||
// Person{FirstName:"John", LastName:"Doe", Email:"johndoeDNE@gmail.net"}
|
||||
|
||||
// You can also get a single result, a la QueryRow
|
||||
jason = Person{}
|
||||
err = db.Get(&jason, "SELECT * FROM person WHERE first_name=$1", "Jason")
|
||||
fmt.Printf("%#v\n", jason)
|
||||
// Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"}
|
||||
|
||||
// if you have null fields and use SELECT *, you must use sql.Null* in your struct
|
||||
places := []Place{}
|
||||
err = db.Select(&places, "SELECT * FROM place ORDER BY telcode ASC")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
usa, singsing, honkers := places[0], places[1], places[2]
|
||||
|
||||
fmt.Printf("%#v\n%#v\n%#v\n", usa, singsing, honkers)
|
||||
// Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1}
|
||||
// Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65}
|
||||
// Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852}
|
||||
|
||||
// Loop through rows using only one struct
|
||||
place := Place{}
|
||||
rows, err := db.Queryx("SELECT * FROM place")
|
||||
for rows.Next() {
|
||||
err := rows.StructScan(&place)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Printf("%#v\n", place)
|
||||
}
|
||||
// Place{Country:"United States", City:sql.NullString{String:"New York", Valid:true}, TelCode:1}
|
||||
// Place{Country:"Hong Kong", City:sql.NullString{String:"", Valid:false}, TelCode:852}
|
||||
// Place{Country:"Singapore", City:sql.NullString{String:"", Valid:false}, TelCode:65}
|
||||
|
||||
// Named queries, using `:name` as the bindvar. Automatic bindvar support
|
||||
// which takes into account the dbtype based on the driverName on sqlx.Open/Connect
|
||||
_, err = db.NamedExec(`INSERT INTO person (first_name,last_name,email) VALUES (:first,:last,:email)`,
|
||||
map[string]interface{}{
|
||||
"first": "Bin",
|
||||
"last": "Smuth",
|
||||
"email": "bensmith@allblacks.nz",
|
||||
})
|
||||
|
||||
// Selects Mr. Smith from the database
|
||||
rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:fn`, map[string]interface{}{"fn": "Bin"})
|
||||
|
||||
// Named queries can also use structs. Their bind names follow the same rules
|
||||
// as the name -> db mapping, so struct fields are lowercased and the `db` tag
|
||||
// is taken into consideration.
|
||||
rows, err = db.NamedQuery(`SELECT * FROM person WHERE first_name=:first_name`, jason)
|
||||
}
|
||||
```
|
||||
|
||||
217
vendor/github.com/jmoiron/sqlx/bind.go
generated
vendored
Normal file
217
vendor/github.com/jmoiron/sqlx/bind.go
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
package sqlx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jmoiron/sqlx/reflectx"
|
||||
)
|
||||
|
||||
// Bindvar types supported by Rebind, BindMap and BindStruct.
|
||||
const (
|
||||
UNKNOWN = iota
|
||||
QUESTION
|
||||
DOLLAR
|
||||
NAMED
|
||||
AT
|
||||
)
|
||||
|
||||
// BindType returns the bindtype for a given database given a drivername.
|
||||
func BindType(driverName string) int {
|
||||
switch driverName {
|
||||
case "postgres", "pgx", "pq-timeouts", "cloudsqlpostgres":
|
||||
return DOLLAR
|
||||
case "mysql":
|
||||
return QUESTION
|
||||
case "sqlite3":
|
||||
return QUESTION
|
||||
case "oci8", "ora", "goracle":
|
||||
return NAMED
|
||||
case "sqlserver":
|
||||
return AT
|
||||
}
|
||||
return UNKNOWN
|
||||
}
|
||||
|
||||
// FIXME: this should be able to be tolerant of escaped ?'s in queries without
|
||||
// losing much speed, and should be to avoid confusion.
|
||||
|
||||
// Rebind a query from the default bindtype (QUESTION) to the target bindtype.
|
||||
func Rebind(bindType int, query string) string {
|
||||
switch bindType {
|
||||
case QUESTION, UNKNOWN:
|
||||
return query
|
||||
}
|
||||
|
||||
// Add space enough for 10 params before we have to allocate
|
||||
rqb := make([]byte, 0, len(query)+10)
|
||||
|
||||
var i, j int
|
||||
|
||||
for i = strings.Index(query, "?"); i != -1; i = strings.Index(query, "?") {
|
||||
rqb = append(rqb, query[:i]...)
|
||||
|
||||
switch bindType {
|
||||
case DOLLAR:
|
||||
rqb = append(rqb, '$')
|
||||
case NAMED:
|
||||
rqb = append(rqb, ':', 'a', 'r', 'g')
|
||||
case AT:
|
||||
rqb = append(rqb, '@', 'p')
|
||||
}
|
||||
|
||||
j++
|
||||
rqb = strconv.AppendInt(rqb, int64(j), 10)
|
||||
|
||||
query = query[i+1:]
|
||||
}
|
||||
|
||||
return string(append(rqb, query...))
|
||||
}
|
||||
|
||||
// Experimental implementation of Rebind which uses a bytes.Buffer. The code is
|
||||
// much simpler and should be more resistant to odd unicode, but it is twice as
|
||||
// slow. Kept here for benchmarking purposes and to possibly replace Rebind if
|
||||
// problems arise with its somewhat naive handling of unicode.
|
||||
func rebindBuff(bindType int, query string) string {
|
||||
if bindType != DOLLAR {
|
||||
return query
|
||||
}
|
||||
|
||||
b := make([]byte, 0, len(query))
|
||||
rqb := bytes.NewBuffer(b)
|
||||
j := 1
|
||||
for _, r := range query {
|
||||
if r == '?' {
|
||||
rqb.WriteRune('$')
|
||||
rqb.WriteString(strconv.Itoa(j))
|
||||
j++
|
||||
} else {
|
||||
rqb.WriteRune(r)
|
||||
}
|
||||
}
|
||||
|
||||
return rqb.String()
|
||||
}
|
||||
|
||||
// In expands slice values in args, returning the modified query string
|
||||
// and a new arg list that can be executed by a database. The `query` should
|
||||
// use the `?` bindVar. The return value uses the `?` bindVar.
|
||||
func In(query string, args ...interface{}) (string, []interface{}, error) {
|
||||
// argMeta stores reflect.Value and length for slices and
|
||||
// the value itself for non-slice arguments
|
||||
type argMeta struct {
|
||||
v reflect.Value
|
||||
i interface{}
|
||||
length int
|
||||
}
|
||||
|
||||
var flatArgsCount int
|
||||
var anySlices bool
|
||||
|
||||
meta := make([]argMeta, len(args))
|
||||
|
||||
for i, arg := range args {
|
||||
if a, ok := arg.(driver.Valuer); ok {
|
||||
arg, _ = a.Value()
|
||||
}
|
||||
v := reflect.ValueOf(arg)
|
||||
t := reflectx.Deref(v.Type())
|
||||
|
||||
// []byte is a driver.Value type so it should not be expanded
|
||||
if t.Kind() == reflect.Slice && t != reflect.TypeOf([]byte{}) {
|
||||
meta[i].length = v.Len()
|
||||
meta[i].v = v
|
||||
|
||||
anySlices = true
|
||||
flatArgsCount += meta[i].length
|
||||
|
||||
if meta[i].length == 0 {
|
||||
return "", nil, errors.New("empty slice passed to 'in' query")
|
||||
}
|
||||
} else {
|
||||
meta[i].i = arg
|
||||
flatArgsCount++
|
||||
}
|
||||
}
|
||||
|
||||
// don't do any parsing if there aren't any slices; note that this means
|
||||
// some errors that we might have caught below will not be returned.
|
||||
if !anySlices {
|
||||
return query, args, nil
|
||||
}
|
||||
|
||||
newArgs := make([]interface{}, 0, flatArgsCount)
|
||||
buf := make([]byte, 0, len(query)+len(", ?")*flatArgsCount)
|
||||
|
||||
var arg, offset int
|
||||
|
||||
for i := strings.IndexByte(query[offset:], '?'); i != -1; i = strings.IndexByte(query[offset:], '?') {
|
||||
if arg >= len(meta) {
|
||||
// if an argument wasn't passed, lets return an error; this is
|
||||
// not actually how database/sql Exec/Query works, but since we are
|
||||
// creating an argument list programmatically, we want to be able
|
||||
// to catch these programmer errors earlier.
|
||||
return "", nil, errors.New("number of bindVars exceeds arguments")
|
||||
}
|
||||
|
||||
argMeta := meta[arg]
|
||||
arg++
|
||||
|
||||
// not a slice, continue.
|
||||
// our questionmark will either be written before the next expansion
|
||||
// of a slice or after the loop when writing the rest of the query
|
||||
if argMeta.length == 0 {
|
||||
offset = offset + i + 1
|
||||
newArgs = append(newArgs, argMeta.i)
|
||||
continue
|
||||
}
|
||||
|
||||
// write everything up to and including our ? character
|
||||
buf = append(buf, query[:offset+i+1]...)
|
||||
|
||||
for si := 1; si < argMeta.length; si++ {
|
||||
buf = append(buf, ", ?"...)
|
||||
}
|
||||
|
||||
newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length)
|
||||
|
||||
// slice the query and reset the offset. this avoids some bookkeeping for
|
||||
// the write after the loop
|
||||
query = query[offset+i+1:]
|
||||
offset = 0
|
||||
}
|
||||
|
||||
buf = append(buf, query...)
|
||||
|
||||
if arg < len(meta) {
|
||||
return "", nil, errors.New("number of bindVars less than number arguments")
|
||||
}
|
||||
|
||||
return string(buf), newArgs, nil
|
||||
}
|
||||
|
||||
func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} {
|
||||
switch val := v.Interface().(type) {
|
||||
case []interface{}:
|
||||
args = append(args, val...)
|
||||
case []int:
|
||||
for i := range val {
|
||||
args = append(args, val[i])
|
||||
}
|
||||
case []string:
|
||||
for i := range val {
|
||||
args = append(args, val[i])
|
||||
}
|
||||
default:
|
||||
for si := 0; si < vlen; si++ {
|
||||
args = append(args, v.Index(si).Interface())
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
12
vendor/github.com/jmoiron/sqlx/doc.go
generated
vendored
Normal file
12
vendor/github.com/jmoiron/sqlx/doc.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Package sqlx provides general purpose extensions to database/sql.
|
||||
//
|
||||
// It is intended to seamlessly wrap database/sql and provide convenience
|
||||
// methods which are useful in the development of database driven applications.
|
||||
// None of the underlying database/sql methods are changed. Instead all extended
|
||||
// behavior is implemented through new methods defined on wrapper types.
|
||||
//
|
||||
// Additions include scanning into structs, named query support, rebinding
|
||||
// queries for different drivers, convenient shorthands for common error handling
|
||||
// and more.
|
||||
//
|
||||
package sqlx
|
||||
7
vendor/github.com/jmoiron/sqlx/go.mod
generated
vendored
Normal file
7
vendor/github.com/jmoiron/sqlx/go.mod
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
module github.com/jmoiron/sqlx
|
||||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.4.0
|
||||
github.com/lib/pq v1.0.0
|
||||
github.com/mattn/go-sqlite3 v1.9.0
|
||||
)
|
||||
6
vendor/github.com/jmoiron/sqlx/go.sum
generated
vendored
Normal file
6
vendor/github.com/jmoiron/sqlx/go.sum
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
356
vendor/github.com/jmoiron/sqlx/named.go
generated
vendored
Normal file
356
vendor/github.com/jmoiron/sqlx/named.go
generated
vendored
Normal file
@@ -0,0 +1,356 @@
|
||||
package sqlx
|
||||
|
||||
// Named Query Support
|
||||
//
|
||||
// * BindMap - bind query bindvars to map/struct args
|
||||
// * NamedExec, NamedQuery - named query w/ struct or map
|
||||
// * NamedStmt - a pre-compiled named query which is a prepared statement
|
||||
//
|
||||
// Internal Interfaces:
|
||||
//
|
||||
// * compileNamedQuery - rebind a named query, returning a query and list of names
|
||||
// * bindArgs, bindMapArgs, bindAnyArgs - given a list of names, return an arglist
|
||||
//
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"unicode"
|
||||
|
||||
"github.com/jmoiron/sqlx/reflectx"
|
||||
)
|
||||
|
||||
// NamedStmt is a prepared statement that executes named queries. Prepare it
|
||||
// how you would execute a NamedQuery, but pass in a struct or map when executing.
|
||||
type NamedStmt struct {
|
||||
Params []string
|
||||
QueryString string
|
||||
Stmt *Stmt
|
||||
}
|
||||
|
||||
// Close closes the named statement.
|
||||
func (n *NamedStmt) Close() error {
|
||||
return n.Stmt.Close()
|
||||
}
|
||||
|
||||
// Exec executes a named statement using the struct passed.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) Exec(arg interface{}) (sql.Result, error) {
|
||||
args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
|
||||
if err != nil {
|
||||
return *new(sql.Result), err
|
||||
}
|
||||
return n.Stmt.Exec(args...)
|
||||
}
|
||||
|
||||
// Query executes a named statement using the struct argument, returning rows.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) Query(arg interface{}) (*sql.Rows, error) {
|
||||
args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n.Stmt.Query(args...)
|
||||
}
|
||||
|
||||
// QueryRow executes a named statement against the database. Because sqlx cannot
|
||||
// create a *sql.Row with an error condition pre-set for binding errors, sqlx
|
||||
// returns a *sqlx.Row instead.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) QueryRow(arg interface{}) *Row {
|
||||
args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
|
||||
if err != nil {
|
||||
return &Row{err: err}
|
||||
}
|
||||
return n.Stmt.QueryRowx(args...)
|
||||
}
|
||||
|
||||
// MustExec execs a NamedStmt, panicing on error
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) MustExec(arg interface{}) sql.Result {
|
||||
res, err := n.Exec(arg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Queryx using this NamedStmt
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) Queryx(arg interface{}) (*Rows, error) {
|
||||
r, err := n.Query(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{Rows: r, Mapper: n.Stmt.Mapper, unsafe: isUnsafe(n)}, err
|
||||
}
|
||||
|
||||
// QueryRowx this NamedStmt. Because of limitations with QueryRow, this is
|
||||
// an alias for QueryRow.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) QueryRowx(arg interface{}) *Row {
|
||||
return n.QueryRow(arg)
|
||||
}
|
||||
|
||||
// Select using this NamedStmt
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) Select(dest interface{}, arg interface{}) error {
|
||||
rows, err := n.Queryx(arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if something happens here, we want to make sure the rows are Closed
|
||||
defer rows.Close()
|
||||
return scanAll(rows, dest, false)
|
||||
}
|
||||
|
||||
// Get using this NamedStmt
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) Get(dest interface{}, arg interface{}) error {
|
||||
r := n.QueryRowx(arg)
|
||||
return r.scanAny(dest, false)
|
||||
}
|
||||
|
||||
// Unsafe creates an unsafe version of the NamedStmt
|
||||
func (n *NamedStmt) Unsafe() *NamedStmt {
|
||||
r := &NamedStmt{Params: n.Params, Stmt: n.Stmt, QueryString: n.QueryString}
|
||||
r.Stmt.unsafe = true
|
||||
return r
|
||||
}
|
||||
|
||||
// A union interface of preparer and binder, required to be able to prepare
|
||||
// named statements (as the bindtype must be determined).
|
||||
type namedPreparer interface {
|
||||
Preparer
|
||||
binder
|
||||
}
|
||||
|
||||
func prepareNamed(p namedPreparer, query string) (*NamedStmt, error) {
|
||||
bindType := BindType(p.DriverName())
|
||||
q, args, err := compileNamedQuery([]byte(query), bindType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt, err := Preparex(p, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &NamedStmt{
|
||||
QueryString: q,
|
||||
Params: args,
|
||||
Stmt: stmt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func bindAnyArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
|
||||
if maparg, ok := arg.(map[string]interface{}); ok {
|
||||
return bindMapArgs(names, maparg)
|
||||
}
|
||||
return bindArgs(names, arg, m)
|
||||
}
|
||||
|
||||
// private interface to generate a list of interfaces from a given struct
|
||||
// type, given a list of names to pull out of the struct. Used by public
|
||||
// BindStruct interface.
|
||||
func bindArgs(names []string, arg interface{}, m *reflectx.Mapper) ([]interface{}, error) {
|
||||
arglist := make([]interface{}, 0, len(names))
|
||||
|
||||
// grab the indirected value of arg
|
||||
v := reflect.ValueOf(arg)
|
||||
for v = reflect.ValueOf(arg); v.Kind() == reflect.Ptr; {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
err := m.TraversalsByNameFunc(v.Type(), names, func(i int, t []int) error {
|
||||
if len(t) == 0 {
|
||||
return fmt.Errorf("could not find name %s in %#v", names[i], arg)
|
||||
}
|
||||
|
||||
val := reflectx.FieldByIndexesReadOnly(v, t)
|
||||
arglist = append(arglist, val.Interface())
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return arglist, err
|
||||
}
|
||||
|
||||
// like bindArgs, but for maps.
|
||||
func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, error) {
|
||||
arglist := make([]interface{}, 0, len(names))
|
||||
|
||||
for _, name := range names {
|
||||
val, ok := arg[name]
|
||||
if !ok {
|
||||
return arglist, fmt.Errorf("could not find name %s in %#v", name, arg)
|
||||
}
|
||||
arglist = append(arglist, val)
|
||||
}
|
||||
return arglist, nil
|
||||
}
|
||||
|
||||
// bindStruct binds a named parameter query with fields from a struct argument.
|
||||
// The rules for binding field names to parameter names follow the same
|
||||
// conventions as for StructScan, including obeying the `db` struct tags.
|
||||
func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
|
||||
bound, names, err := compileNamedQuery([]byte(query), bindType)
|
||||
if err != nil {
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
|
||||
arglist, err := bindArgs(names, arg, m)
|
||||
if err != nil {
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
|
||||
return bound, arglist, nil
|
||||
}
|
||||
|
||||
// bindMap binds a named parameter query with a map of arguments.
|
||||
func bindMap(bindType int, query string, args map[string]interface{}) (string, []interface{}, error) {
|
||||
bound, names, err := compileNamedQuery([]byte(query), bindType)
|
||||
if err != nil {
|
||||
return "", []interface{}{}, err
|
||||
}
|
||||
|
||||
arglist, err := bindMapArgs(names, args)
|
||||
return bound, arglist, err
|
||||
}
|
||||
|
||||
// -- Compilation of Named Queries
|
||||
|
||||
// Allow digits and letters in bind params; additionally runes are
|
||||
// checked against underscores, meaning that bind params can have be
|
||||
// alphanumeric with underscores. Mind the difference between unicode
|
||||
// digits and numbers, where '5' is a digit but '五' is not.
|
||||
var allowedBindRunes = []*unicode.RangeTable{unicode.Letter, unicode.Digit}
|
||||
|
||||
// FIXME: this function isn't safe for unicode named params, as a failing test
|
||||
// can testify. This is not a regression but a failure of the original code
|
||||
// as well. It should be modified to range over runes in a string rather than
|
||||
// bytes, even though this is less convenient and slower. Hopefully the
|
||||
// addition of the prepared NamedStmt (which will only do this once) will make
|
||||
// up for the slightly slower ad-hoc NamedExec/NamedQuery.
|
||||
|
||||
// compile a NamedQuery into an unbound query (using the '?' bindvar) and
|
||||
// a list of names.
|
||||
func compileNamedQuery(qs []byte, bindType int) (query string, names []string, err error) {
|
||||
names = make([]string, 0, 10)
|
||||
rebound := make([]byte, 0, len(qs))
|
||||
|
||||
inName := false
|
||||
last := len(qs) - 1
|
||||
currentVar := 1
|
||||
name := make([]byte, 0, 10)
|
||||
|
||||
for i, b := range qs {
|
||||
// a ':' while we're in a name is an error
|
||||
if b == ':' {
|
||||
// if this is the second ':' in a '::' escape sequence, append a ':'
|
||||
if inName && i > 0 && qs[i-1] == ':' {
|
||||
rebound = append(rebound, ':')
|
||||
inName = false
|
||||
continue
|
||||
} else if inName {
|
||||
err = errors.New("unexpected `:` while reading named param at " + strconv.Itoa(i))
|
||||
return query, names, err
|
||||
}
|
||||
inName = true
|
||||
name = []byte{}
|
||||
} else if inName && i > 0 && b == '=' {
|
||||
rebound = append(rebound, ':', '=')
|
||||
inName = false
|
||||
continue
|
||||
// if we're in a name, and this is an allowed character, continue
|
||||
} else if inName && (unicode.IsOneOf(allowedBindRunes, rune(b)) || b == '_' || b == '.') && i != last {
|
||||
// append the byte to the name if we are in a name and not on the last byte
|
||||
name = append(name, b)
|
||||
// if we're in a name and it's not an allowed character, the name is done
|
||||
} else if inName {
|
||||
inName = false
|
||||
// if this is the final byte of the string and it is part of the name, then
|
||||
// make sure to add it to the name
|
||||
if i == last && unicode.IsOneOf(allowedBindRunes, rune(b)) {
|
||||
name = append(name, b)
|
||||
}
|
||||
// add the string representation to the names list
|
||||
names = append(names, string(name))
|
||||
// add a proper bindvar for the bindType
|
||||
switch bindType {
|
||||
// oracle only supports named type bind vars even for positional
|
||||
case NAMED:
|
||||
rebound = append(rebound, ':')
|
||||
rebound = append(rebound, name...)
|
||||
case QUESTION, UNKNOWN:
|
||||
rebound = append(rebound, '?')
|
||||
case DOLLAR:
|
||||
rebound = append(rebound, '$')
|
||||
for _, b := range strconv.Itoa(currentVar) {
|
||||
rebound = append(rebound, byte(b))
|
||||
}
|
||||
currentVar++
|
||||
case AT:
|
||||
rebound = append(rebound, '@', 'p')
|
||||
for _, b := range strconv.Itoa(currentVar) {
|
||||
rebound = append(rebound, byte(b))
|
||||
}
|
||||
currentVar++
|
||||
}
|
||||
// add this byte to string unless it was not part of the name
|
||||
if i != last {
|
||||
rebound = append(rebound, b)
|
||||
} else if !unicode.IsOneOf(allowedBindRunes, rune(b)) {
|
||||
rebound = append(rebound, b)
|
||||
}
|
||||
} else {
|
||||
// this is a normal byte and should just go onto the rebound query
|
||||
rebound = append(rebound, b)
|
||||
}
|
||||
}
|
||||
|
||||
return string(rebound), names, err
|
||||
}
|
||||
|
||||
// BindNamed binds a struct or a map to a query with named parameters.
|
||||
// DEPRECATED: use sqlx.Named` instead of this, it may be removed in future.
|
||||
func BindNamed(bindType int, query string, arg interface{}) (string, []interface{}, error) {
|
||||
return bindNamedMapper(bindType, query, arg, mapper())
|
||||
}
|
||||
|
||||
// Named takes a query using named parameters and an argument and
|
||||
// returns a new query with a list of args that can be executed by
|
||||
// a database. The return value uses the `?` bindvar.
|
||||
func Named(query string, arg interface{}) (string, []interface{}, error) {
|
||||
return bindNamedMapper(QUESTION, query, arg, mapper())
|
||||
}
|
||||
|
||||
func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
|
||||
if maparg, ok := arg.(map[string]interface{}); ok {
|
||||
return bindMap(bindType, query, maparg)
|
||||
}
|
||||
return bindStruct(bindType, query, arg, m)
|
||||
}
|
||||
|
||||
// NamedQuery binds a named query and then runs Query on the result using the
|
||||
// provided Ext (sqlx.Tx, sqlx.Db). It works with both structs and with
|
||||
// map[string]interface{} types.
|
||||
func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) {
|
||||
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.Queryx(q, args...)
|
||||
}
|
||||
|
||||
// NamedExec uses BindStruct to get a query executable by the driver and
|
||||
// then runs Exec on the result. Returns an error from the binding
|
||||
// or the query excution itself.
|
||||
func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) {
|
||||
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.Exec(q, args...)
|
||||
}
|
||||
132
vendor/github.com/jmoiron/sqlx/named_context.go
generated
vendored
Normal file
132
vendor/github.com/jmoiron/sqlx/named_context.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
// +build go1.8
|
||||
|
||||
package sqlx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// A union interface of contextPreparer and binder, required to be able to
|
||||
// prepare named statements with context (as the bindtype must be determined).
|
||||
type namedPreparerContext interface {
|
||||
PreparerContext
|
||||
binder
|
||||
}
|
||||
|
||||
func prepareNamedContext(ctx context.Context, p namedPreparerContext, query string) (*NamedStmt, error) {
|
||||
bindType := BindType(p.DriverName())
|
||||
q, args, err := compileNamedQuery([]byte(query), bindType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt, err := PreparexContext(ctx, p, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &NamedStmt{
|
||||
QueryString: q,
|
||||
Params: args,
|
||||
Stmt: stmt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExecContext executes a named statement using the struct passed.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) ExecContext(ctx context.Context, arg interface{}) (sql.Result, error) {
|
||||
args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
|
||||
if err != nil {
|
||||
return *new(sql.Result), err
|
||||
}
|
||||
return n.Stmt.ExecContext(ctx, args...)
|
||||
}
|
||||
|
||||
// QueryContext executes a named statement using the struct argument, returning rows.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) QueryContext(ctx context.Context, arg interface{}) (*sql.Rows, error) {
|
||||
args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n.Stmt.QueryContext(ctx, args...)
|
||||
}
|
||||
|
||||
// QueryRowContext executes a named statement against the database. Because sqlx cannot
|
||||
// create a *sql.Row with an error condition pre-set for binding errors, sqlx
|
||||
// returns a *sqlx.Row instead.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) QueryRowContext(ctx context.Context, arg interface{}) *Row {
|
||||
args, err := bindAnyArgs(n.Params, arg, n.Stmt.Mapper)
|
||||
if err != nil {
|
||||
return &Row{err: err}
|
||||
}
|
||||
return n.Stmt.QueryRowxContext(ctx, args...)
|
||||
}
|
||||
|
||||
// MustExecContext execs a NamedStmt, panicing on error
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) MustExecContext(ctx context.Context, arg interface{}) sql.Result {
|
||||
res, err := n.ExecContext(ctx, arg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// QueryxContext using this NamedStmt
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) QueryxContext(ctx context.Context, arg interface{}) (*Rows, error) {
|
||||
r, err := n.QueryContext(ctx, arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{Rows: r, Mapper: n.Stmt.Mapper, unsafe: isUnsafe(n)}, err
|
||||
}
|
||||
|
||||
// QueryRowxContext this NamedStmt. Because of limitations with QueryRow, this is
|
||||
// an alias for QueryRow.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) QueryRowxContext(ctx context.Context, arg interface{}) *Row {
|
||||
return n.QueryRowContext(ctx, arg)
|
||||
}
|
||||
|
||||
// SelectContext using this NamedStmt
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) SelectContext(ctx context.Context, dest interface{}, arg interface{}) error {
|
||||
rows, err := n.QueryxContext(ctx, arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if something happens here, we want to make sure the rows are Closed
|
||||
defer rows.Close()
|
||||
return scanAll(rows, dest, false)
|
||||
}
|
||||
|
||||
// GetContext using this NamedStmt
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (n *NamedStmt) GetContext(ctx context.Context, dest interface{}, arg interface{}) error {
|
||||
r := n.QueryRowxContext(ctx, arg)
|
||||
return r.scanAny(dest, false)
|
||||
}
|
||||
|
||||
// NamedQueryContext binds a named query and then runs Query on the result using the
|
||||
// provided Ext (sqlx.Tx, sqlx.Db). It works with both structs and with
|
||||
// map[string]interface{} types.
|
||||
func NamedQueryContext(ctx context.Context, e ExtContext, query string, arg interface{}) (*Rows, error) {
|
||||
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.QueryxContext(ctx, q, args...)
|
||||
}
|
||||
|
||||
// NamedExecContext uses BindStruct to get a query executable by the driver and
|
||||
// then runs Exec on the result. Returns an error from the binding
|
||||
// or the query excution itself.
|
||||
func NamedExecContext(ctx context.Context, e ExtContext, query string, arg interface{}) (sql.Result, error) {
|
||||
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.ExecContext(ctx, q, args...)
|
||||
}
|
||||
17
vendor/github.com/jmoiron/sqlx/reflectx/README.md
generated
vendored
Normal file
17
vendor/github.com/jmoiron/sqlx/reflectx/README.md
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# reflectx
|
||||
|
||||
The sqlx package has special reflect needs. In particular, it needs to:
|
||||
|
||||
* be able to map a name to a field
|
||||
* understand embedded structs
|
||||
* understand mapping names to fields by a particular tag
|
||||
* user specified name -> field mapping functions
|
||||
|
||||
These behaviors mimic the behaviors by the standard library marshallers and also the
|
||||
behavior of standard Go accessors.
|
||||
|
||||
The first two are amply taken care of by `Reflect.Value.FieldByName`, and the third is
|
||||
addressed by `Reflect.Value.FieldByNameFunc`, but these don't quite understand struct
|
||||
tags in the ways that are vital to most marshallers, and they are slow.
|
||||
|
||||
This reflectx package extends reflect to achieve these goals.
|
||||
441
vendor/github.com/jmoiron/sqlx/reflectx/reflect.go
generated
vendored
Normal file
441
vendor/github.com/jmoiron/sqlx/reflectx/reflect.go
generated
vendored
Normal file
@@ -0,0 +1,441 @@
|
||||
// Package reflectx implements extensions to the standard reflect lib suitable
|
||||
// for implementing marshalling and unmarshalling packages. The main Mapper type
|
||||
// allows for Go-compatible named attribute access, including accessing embedded
|
||||
// struct attributes and the ability to use functions and struct tags to
|
||||
// customize field names.
|
||||
//
|
||||
package reflectx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A FieldInfo is metadata for a struct field.
|
||||
type FieldInfo struct {
|
||||
Index []int
|
||||
Path string
|
||||
Field reflect.StructField
|
||||
Zero reflect.Value
|
||||
Name string
|
||||
Options map[string]string
|
||||
Embedded bool
|
||||
Children []*FieldInfo
|
||||
Parent *FieldInfo
|
||||
}
|
||||
|
||||
// A StructMap is an index of field metadata for a struct.
|
||||
type StructMap struct {
|
||||
Tree *FieldInfo
|
||||
Index []*FieldInfo
|
||||
Paths map[string]*FieldInfo
|
||||
Names map[string]*FieldInfo
|
||||
}
|
||||
|
||||
// GetByPath returns a *FieldInfo for a given string path.
|
||||
func (f StructMap) GetByPath(path string) *FieldInfo {
|
||||
return f.Paths[path]
|
||||
}
|
||||
|
||||
// GetByTraversal returns a *FieldInfo for a given integer path. It is
|
||||
// analogous to reflect.FieldByIndex, but using the cached traversal
|
||||
// rather than re-executing the reflect machinery each time.
|
||||
func (f StructMap) GetByTraversal(index []int) *FieldInfo {
|
||||
if len(index) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
tree := f.Tree
|
||||
for _, i := range index {
|
||||
if i >= len(tree.Children) || tree.Children[i] == nil {
|
||||
return nil
|
||||
}
|
||||
tree = tree.Children[i]
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
||||
// Mapper is a general purpose mapper of names to struct fields. A Mapper
|
||||
// behaves like most marshallers in the standard library, obeying a field tag
|
||||
// for name mapping but also providing a basic transform function.
|
||||
type Mapper struct {
|
||||
cache map[reflect.Type]*StructMap
|
||||
tagName string
|
||||
tagMapFunc func(string) string
|
||||
mapFunc func(string) string
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// NewMapper returns a new mapper using the tagName as its struct field tag.
|
||||
// If tagName is the empty string, it is ignored.
|
||||
func NewMapper(tagName string) *Mapper {
|
||||
return &Mapper{
|
||||
cache: make(map[reflect.Type]*StructMap),
|
||||
tagName: tagName,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMapperTagFunc returns a new mapper which contains a mapper for field names
|
||||
// AND a mapper for tag values. This is useful for tags like json which can
|
||||
// have values like "name,omitempty".
|
||||
func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *Mapper {
|
||||
return &Mapper{
|
||||
cache: make(map[reflect.Type]*StructMap),
|
||||
tagName: tagName,
|
||||
mapFunc: mapFunc,
|
||||
tagMapFunc: tagMapFunc,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMapperFunc returns a new mapper which optionally obeys a field tag and
|
||||
// a struct field name mapper func given by f. Tags will take precedence, but
|
||||
// for any other field, the mapped name will be f(field.Name)
|
||||
func NewMapperFunc(tagName string, f func(string) string) *Mapper {
|
||||
return &Mapper{
|
||||
cache: make(map[reflect.Type]*StructMap),
|
||||
tagName: tagName,
|
||||
mapFunc: f,
|
||||
}
|
||||
}
|
||||
|
||||
// TypeMap returns a mapping of field strings to int slices representing
|
||||
// the traversal down the struct to reach the field.
|
||||
func (m *Mapper) TypeMap(t reflect.Type) *StructMap {
|
||||
m.mutex.Lock()
|
||||
mapping, ok := m.cache[t]
|
||||
if !ok {
|
||||
mapping = getMapping(t, m.tagName, m.mapFunc, m.tagMapFunc)
|
||||
m.cache[t] = mapping
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
return mapping
|
||||
}
|
||||
|
||||
// FieldMap returns the mapper's mapping of field names to reflect values. Panics
|
||||
// if v's Kind is not Struct, or v is not Indirectable to a struct kind.
|
||||
func (m *Mapper) FieldMap(v reflect.Value) map[string]reflect.Value {
|
||||
v = reflect.Indirect(v)
|
||||
mustBe(v, reflect.Struct)
|
||||
|
||||
r := map[string]reflect.Value{}
|
||||
tm := m.TypeMap(v.Type())
|
||||
for tagName, fi := range tm.Names {
|
||||
r[tagName] = FieldByIndexes(v, fi.Index)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// FieldByName returns a field by its mapped name as a reflect.Value.
|
||||
// Panics if v's Kind is not Struct or v is not Indirectable to a struct Kind.
|
||||
// Returns zero Value if the name is not found.
|
||||
func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value {
|
||||
v = reflect.Indirect(v)
|
||||
mustBe(v, reflect.Struct)
|
||||
|
||||
tm := m.TypeMap(v.Type())
|
||||
fi, ok := tm.Names[name]
|
||||
if !ok {
|
||||
return v
|
||||
}
|
||||
return FieldByIndexes(v, fi.Index)
|
||||
}
|
||||
|
||||
// FieldsByName returns a slice of values corresponding to the slice of names
|
||||
// for the value. Panics if v's Kind is not Struct or v is not Indirectable
|
||||
// to a struct Kind. Returns zero Value for each name not found.
|
||||
func (m *Mapper) FieldsByName(v reflect.Value, names []string) []reflect.Value {
|
||||
v = reflect.Indirect(v)
|
||||
mustBe(v, reflect.Struct)
|
||||
|
||||
tm := m.TypeMap(v.Type())
|
||||
vals := make([]reflect.Value, 0, len(names))
|
||||
for _, name := range names {
|
||||
fi, ok := tm.Names[name]
|
||||
if !ok {
|
||||
vals = append(vals, *new(reflect.Value))
|
||||
} else {
|
||||
vals = append(vals, FieldByIndexes(v, fi.Index))
|
||||
}
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
// TraversalsByName returns a slice of int slices which represent the struct
|
||||
// traversals for each mapped name. Panics if t is not a struct or Indirectable
|
||||
// to a struct. Returns empty int slice for each name not found.
|
||||
func (m *Mapper) TraversalsByName(t reflect.Type, names []string) [][]int {
|
||||
r := make([][]int, 0, len(names))
|
||||
m.TraversalsByNameFunc(t, names, func(_ int, i []int) error {
|
||||
if i == nil {
|
||||
r = append(r, []int{})
|
||||
} else {
|
||||
r = append(r, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
// TraversalsByNameFunc traverses the mapped names and calls fn with the index of
|
||||
// each name and the struct traversal represented by that name. Panics if t is not
|
||||
// a struct or Indirectable to a struct. Returns the first error returned by fn or nil.
|
||||
func (m *Mapper) TraversalsByNameFunc(t reflect.Type, names []string, fn func(int, []int) error) error {
|
||||
t = Deref(t)
|
||||
mustBe(t, reflect.Struct)
|
||||
tm := m.TypeMap(t)
|
||||
for i, name := range names {
|
||||
fi, ok := tm.Names[name]
|
||||
if !ok {
|
||||
if err := fn(i, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := fn(i, fi.Index); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FieldByIndexes returns a value for the field given by the struct traversal
|
||||
// for the given value.
|
||||
func FieldByIndexes(v reflect.Value, indexes []int) reflect.Value {
|
||||
for _, i := range indexes {
|
||||
v = reflect.Indirect(v).Field(i)
|
||||
// if this is a pointer and it's nil, allocate a new value and set it
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
alloc := reflect.New(Deref(v.Type()))
|
||||
v.Set(alloc)
|
||||
}
|
||||
if v.Kind() == reflect.Map && v.IsNil() {
|
||||
v.Set(reflect.MakeMap(v.Type()))
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// FieldByIndexesReadOnly returns a value for a particular struct traversal,
|
||||
// but is not concerned with allocating nil pointers because the value is
|
||||
// going to be used for reading and not setting.
|
||||
func FieldByIndexesReadOnly(v reflect.Value, indexes []int) reflect.Value {
|
||||
for _, i := range indexes {
|
||||
v = reflect.Indirect(v).Field(i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Deref is Indirect for reflect.Types
|
||||
func Deref(t reflect.Type) reflect.Type {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// -- helpers & utilities --
|
||||
|
||||
type kinder interface {
|
||||
Kind() reflect.Kind
|
||||
}
|
||||
|
||||
// mustBe checks a value against a kind, panicing with a reflect.ValueError
|
||||
// if the kind isn't that which is required.
|
||||
func mustBe(v kinder, expected reflect.Kind) {
|
||||
if k := v.Kind(); k != expected {
|
||||
panic(&reflect.ValueError{Method: methodName(), Kind: k})
|
||||
}
|
||||
}
|
||||
|
||||
// methodName returns the caller of the function calling methodName
|
||||
func methodName() string {
|
||||
pc, _, _, _ := runtime.Caller(2)
|
||||
f := runtime.FuncForPC(pc)
|
||||
if f == nil {
|
||||
return "unknown method"
|
||||
}
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
type typeQueue struct {
|
||||
t reflect.Type
|
||||
fi *FieldInfo
|
||||
pp string // Parent path
|
||||
}
|
||||
|
||||
// A copying append that creates a new slice each time.
|
||||
func apnd(is []int, i int) []int {
|
||||
x := make([]int, len(is)+1)
|
||||
for p, n := range is {
|
||||
x[p] = n
|
||||
}
|
||||
x[len(x)-1] = i
|
||||
return x
|
||||
}
|
||||
|
||||
type mapf func(string) string
|
||||
|
||||
// parseName parses the tag and the target name for the given field using
|
||||
// the tagName (eg 'json' for `json:"foo"` tags), mapFunc for mapping the
|
||||
// field's name to a target name, and tagMapFunc for mapping the tag to
|
||||
// a target name.
|
||||
func parseName(field reflect.StructField, tagName string, mapFunc, tagMapFunc mapf) (tag, fieldName string) {
|
||||
// first, set the fieldName to the field's name
|
||||
fieldName = field.Name
|
||||
// if a mapFunc is set, use that to override the fieldName
|
||||
if mapFunc != nil {
|
||||
fieldName = mapFunc(fieldName)
|
||||
}
|
||||
|
||||
// if there's no tag to look for, return the field name
|
||||
if tagName == "" {
|
||||
return "", fieldName
|
||||
}
|
||||
|
||||
// if this tag is not set using the normal convention in the tag,
|
||||
// then return the fieldname.. this check is done because according
|
||||
// to the reflect documentation:
|
||||
// If the tag does not have the conventional format,
|
||||
// the value returned by Get is unspecified.
|
||||
// which doesn't sound great.
|
||||
if !strings.Contains(string(field.Tag), tagName+":") {
|
||||
return "", fieldName
|
||||
}
|
||||
|
||||
// at this point we're fairly sure that we have a tag, so lets pull it out
|
||||
tag = field.Tag.Get(tagName)
|
||||
|
||||
// if we have a mapper function, call it on the whole tag
|
||||
// XXX: this is a change from the old version, which pulled out the name
|
||||
// before the tagMapFunc could be run, but I think this is the right way
|
||||
if tagMapFunc != nil {
|
||||
tag = tagMapFunc(tag)
|
||||
}
|
||||
|
||||
// finally, split the options from the name
|
||||
parts := strings.Split(tag, ",")
|
||||
fieldName = parts[0]
|
||||
|
||||
return tag, fieldName
|
||||
}
|
||||
|
||||
// parseOptions parses options out of a tag string, skipping the name
|
||||
func parseOptions(tag string) map[string]string {
|
||||
parts := strings.Split(tag, ",")
|
||||
options := make(map[string]string, len(parts))
|
||||
if len(parts) > 1 {
|
||||
for _, opt := range parts[1:] {
|
||||
// short circuit potentially expensive split op
|
||||
if strings.Contains(opt, "=") {
|
||||
kv := strings.Split(opt, "=")
|
||||
options[kv[0]] = kv[1]
|
||||
continue
|
||||
}
|
||||
options[opt] = ""
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// getMapping returns a mapping for the t type, using the tagName, mapFunc and
|
||||
// tagMapFunc to determine the canonical names of fields.
|
||||
func getMapping(t reflect.Type, tagName string, mapFunc, tagMapFunc mapf) *StructMap {
|
||||
m := []*FieldInfo{}
|
||||
|
||||
root := &FieldInfo{}
|
||||
queue := []typeQueue{}
|
||||
queue = append(queue, typeQueue{Deref(t), root, ""})
|
||||
|
||||
QueueLoop:
|
||||
for len(queue) != 0 {
|
||||
// pop the first item off of the queue
|
||||
tq := queue[0]
|
||||
queue = queue[1:]
|
||||
|
||||
// ignore recursive field
|
||||
for p := tq.fi.Parent; p != nil; p = p.Parent {
|
||||
if tq.fi.Field.Type == p.Field.Type {
|
||||
continue QueueLoop
|
||||
}
|
||||
}
|
||||
|
||||
nChildren := 0
|
||||
if tq.t.Kind() == reflect.Struct {
|
||||
nChildren = tq.t.NumField()
|
||||
}
|
||||
tq.fi.Children = make([]*FieldInfo, nChildren)
|
||||
|
||||
// iterate through all of its fields
|
||||
for fieldPos := 0; fieldPos < nChildren; fieldPos++ {
|
||||
|
||||
f := tq.t.Field(fieldPos)
|
||||
|
||||
// parse the tag and the target name using the mapping options for this field
|
||||
tag, name := parseName(f, tagName, mapFunc, tagMapFunc)
|
||||
|
||||
// if the name is "-", disabled via a tag, skip it
|
||||
if name == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
fi := FieldInfo{
|
||||
Field: f,
|
||||
Name: name,
|
||||
Zero: reflect.New(f.Type).Elem(),
|
||||
Options: parseOptions(tag),
|
||||
}
|
||||
|
||||
// if the path is empty this path is just the name
|
||||
if tq.pp == "" {
|
||||
fi.Path = fi.Name
|
||||
} else {
|
||||
fi.Path = tq.pp + "." + fi.Name
|
||||
}
|
||||
|
||||
// skip unexported fields
|
||||
if len(f.PkgPath) != 0 && !f.Anonymous {
|
||||
continue
|
||||
}
|
||||
|
||||
// bfs search of anonymous embedded structs
|
||||
if f.Anonymous {
|
||||
pp := tq.pp
|
||||
if tag != "" {
|
||||
pp = fi.Path
|
||||
}
|
||||
|
||||
fi.Embedded = true
|
||||
fi.Index = apnd(tq.fi.Index, fieldPos)
|
||||
nChildren := 0
|
||||
ft := Deref(f.Type)
|
||||
if ft.Kind() == reflect.Struct {
|
||||
nChildren = ft.NumField()
|
||||
}
|
||||
fi.Children = make([]*FieldInfo, nChildren)
|
||||
queue = append(queue, typeQueue{Deref(f.Type), &fi, pp})
|
||||
} else if fi.Zero.Kind() == reflect.Struct || (fi.Zero.Kind() == reflect.Ptr && fi.Zero.Type().Elem().Kind() == reflect.Struct) {
|
||||
fi.Index = apnd(tq.fi.Index, fieldPos)
|
||||
fi.Children = make([]*FieldInfo, Deref(f.Type).NumField())
|
||||
queue = append(queue, typeQueue{Deref(f.Type), &fi, fi.Path})
|
||||
}
|
||||
|
||||
fi.Index = apnd(tq.fi.Index, fieldPos)
|
||||
fi.Parent = tq.fi
|
||||
tq.fi.Children[fieldPos] = &fi
|
||||
m = append(m, &fi)
|
||||
}
|
||||
}
|
||||
|
||||
flds := &StructMap{Index: m, Tree: root, Paths: map[string]*FieldInfo{}, Names: map[string]*FieldInfo{}}
|
||||
for _, fi := range flds.Index {
|
||||
flds.Paths[fi.Path] = fi
|
||||
if fi.Name != "" && !fi.Embedded {
|
||||
flds.Names[fi.Path] = fi
|
||||
}
|
||||
}
|
||||
|
||||
return flds
|
||||
}
|
||||
1045
vendor/github.com/jmoiron/sqlx/sqlx.go
generated
vendored
Normal file
1045
vendor/github.com/jmoiron/sqlx/sqlx.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
346
vendor/github.com/jmoiron/sqlx/sqlx_context.go
generated
vendored
Normal file
346
vendor/github.com/jmoiron/sqlx/sqlx_context.go
generated
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
// +build go1.8
|
||||
|
||||
package sqlx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ConnectContext to a database and verify with a ping.
|
||||
func ConnectContext(ctx context.Context, driverName, dataSourceName string) (*DB, error) {
|
||||
db, err := Open(driverName, dataSourceName)
|
||||
if err != nil {
|
||||
return db, err
|
||||
}
|
||||
err = db.PingContext(ctx)
|
||||
return db, err
|
||||
}
|
||||
|
||||
// QueryerContext is an interface used by GetContext and SelectContext
|
||||
type QueryerContext interface {
|
||||
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
|
||||
QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
|
||||
QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row
|
||||
}
|
||||
|
||||
// PreparerContext is an interface used by PreparexContext.
|
||||
type PreparerContext interface {
|
||||
PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
|
||||
}
|
||||
|
||||
// ExecerContext is an interface used by MustExecContext and LoadFileContext
|
||||
type ExecerContext interface {
|
||||
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
|
||||
}
|
||||
|
||||
// ExtContext is a union interface which can bind, query, and exec, with Context
|
||||
// used by NamedQueryContext and NamedExecContext.
|
||||
type ExtContext interface {
|
||||
binder
|
||||
QueryerContext
|
||||
ExecerContext
|
||||
}
|
||||
|
||||
// SelectContext executes a query using the provided Queryer, and StructScans
|
||||
// each row into dest, which must be a slice. If the slice elements are
|
||||
// scannable, then the result set must have only one column. Otherwise,
|
||||
// StructScan is used. The *sql.Rows are closed automatically.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func SelectContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
|
||||
rows, err := q.QueryxContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if something happens here, we want to make sure the rows are Closed
|
||||
defer rows.Close()
|
||||
return scanAll(rows, dest, false)
|
||||
}
|
||||
|
||||
// PreparexContext prepares a statement.
|
||||
//
|
||||
// The provided context is used for the preparation of the statement, not for
|
||||
// the execution of the statement.
|
||||
func PreparexContext(ctx context.Context, p PreparerContext, query string) (*Stmt, error) {
|
||||
s, err := p.PrepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Stmt{Stmt: s, unsafe: isUnsafe(p), Mapper: mapperFor(p)}, err
|
||||
}
|
||||
|
||||
// GetContext does a QueryRow using the provided Queryer, and scans the
|
||||
// resulting row to dest. If dest is scannable, the result must only have one
|
||||
// column. Otherwise, StructScan is used. Get will return sql.ErrNoRows like
|
||||
// row.Scan would. Any placeholder parameters are replaced with supplied args.
|
||||
// An error is returned if the result set is empty.
|
||||
func GetContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
|
||||
r := q.QueryRowxContext(ctx, query, args...)
|
||||
return r.scanAny(dest, false)
|
||||
}
|
||||
|
||||
// LoadFileContext exec's every statement in a file (as a single call to Exec).
|
||||
// LoadFileContext may return a nil *sql.Result if errors are encountered
|
||||
// locating or reading the file at path. LoadFile reads the entire file into
|
||||
// memory, so it is not suitable for loading large data dumps, but can be useful
|
||||
// for initializing schemas or loading indexes.
|
||||
//
|
||||
// FIXME: this does not really work with multi-statement files for mattn/go-sqlite3
|
||||
// or the go-mysql-driver/mysql drivers; pq seems to be an exception here. Detecting
|
||||
// this by requiring something with DriverName() and then attempting to split the
|
||||
// queries will be difficult to get right, and its current driver-specific behavior
|
||||
// is deemed at least not complex in its incorrectness.
|
||||
func LoadFileContext(ctx context.Context, e ExecerContext, path string) (*sql.Result, error) {
|
||||
realpath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
contents, err := ioutil.ReadFile(realpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := e.ExecContext(ctx, string(contents))
|
||||
return &res, err
|
||||
}
|
||||
|
||||
// MustExecContext execs the query using e and panics if there was an error.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func MustExecContext(ctx context.Context, e ExecerContext, query string, args ...interface{}) sql.Result {
|
||||
res, err := e.ExecContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// PrepareNamedContext returns an sqlx.NamedStmt
|
||||
func (db *DB) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) {
|
||||
return prepareNamedContext(ctx, db, query)
|
||||
}
|
||||
|
||||
// NamedQueryContext using this DB.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (db *DB) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*Rows, error) {
|
||||
return NamedQueryContext(ctx, db, query, arg)
|
||||
}
|
||||
|
||||
// NamedExecContext using this DB.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (db *DB) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) {
|
||||
return NamedExecContext(ctx, db, query, arg)
|
||||
}
|
||||
|
||||
// SelectContext using this DB.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (db *DB) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
|
||||
return SelectContext(ctx, db, dest, query, args...)
|
||||
}
|
||||
|
||||
// GetContext using this DB.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
// An error is returned if the result set is empty.
|
||||
func (db *DB) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
|
||||
return GetContext(ctx, db, dest, query, args...)
|
||||
}
|
||||
|
||||
// PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
|
||||
//
|
||||
// The provided context is used for the preparation of the statement, not for
|
||||
// the execution of the statement.
|
||||
func (db *DB) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
|
||||
return PreparexContext(ctx, db, query)
|
||||
}
|
||||
|
||||
// QueryxContext queries the database and returns an *sqlx.Rows.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
|
||||
r, err := db.DB.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{Rows: r, unsafe: db.unsafe, Mapper: db.Mapper}, err
|
||||
}
|
||||
|
||||
// QueryRowxContext queries the database and returns an *sqlx.Row.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
|
||||
rows, err := db.DB.QueryContext(ctx, query, args...)
|
||||
return &Row{rows: rows, err: err, unsafe: db.unsafe, Mapper: db.Mapper}
|
||||
}
|
||||
|
||||
// MustBeginTx starts a transaction, and panics on error. Returns an *sqlx.Tx instead
|
||||
// of an *sql.Tx.
|
||||
//
|
||||
// The provided context is used until the transaction is committed or rolled
|
||||
// back. If the context is canceled, the sql package will roll back the
|
||||
// transaction. Tx.Commit will return an error if the context provided to
|
||||
// MustBeginContext is canceled.
|
||||
func (db *DB) MustBeginTx(ctx context.Context, opts *sql.TxOptions) *Tx {
|
||||
tx, err := db.BeginTxx(ctx, opts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return tx
|
||||
}
|
||||
|
||||
// MustExecContext (panic) runs MustExec using this database.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (db *DB) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result {
|
||||
return MustExecContext(ctx, db, query, args...)
|
||||
}
|
||||
|
||||
// BeginTxx begins a transaction and returns an *sqlx.Tx instead of an
|
||||
// *sql.Tx.
|
||||
//
|
||||
// The provided context is used until the transaction is committed or rolled
|
||||
// back. If the context is canceled, the sql package will roll back the
|
||||
// transaction. Tx.Commit will return an error if the context provided to
|
||||
// BeginxContext is canceled.
|
||||
func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
||||
tx, err := db.DB.BeginTx(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err
|
||||
}
|
||||
|
||||
// StmtxContext returns a version of the prepared statement which runs within a
|
||||
// transaction. Provided stmt can be either *sql.Stmt or *sqlx.Stmt.
|
||||
func (tx *Tx) StmtxContext(ctx context.Context, stmt interface{}) *Stmt {
|
||||
var s *sql.Stmt
|
||||
switch v := stmt.(type) {
|
||||
case Stmt:
|
||||
s = v.Stmt
|
||||
case *Stmt:
|
||||
s = v.Stmt
|
||||
case *sql.Stmt:
|
||||
s = v
|
||||
default:
|
||||
panic(fmt.Sprintf("non-statement type %v passed to Stmtx", reflect.ValueOf(stmt).Type()))
|
||||
}
|
||||
return &Stmt{Stmt: tx.StmtContext(ctx, s), Mapper: tx.Mapper}
|
||||
}
|
||||
|
||||
// NamedStmtContext returns a version of the prepared statement which runs
|
||||
// within a transaction.
|
||||
func (tx *Tx) NamedStmtContext(ctx context.Context, stmt *NamedStmt) *NamedStmt {
|
||||
return &NamedStmt{
|
||||
QueryString: stmt.QueryString,
|
||||
Params: stmt.Params,
|
||||
Stmt: tx.StmtxContext(ctx, stmt.Stmt),
|
||||
}
|
||||
}
|
||||
|
||||
// PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
|
||||
//
|
||||
// The provided context is used for the preparation of the statement, not for
|
||||
// the execution of the statement.
|
||||
func (tx *Tx) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
|
||||
return PreparexContext(ctx, tx, query)
|
||||
}
|
||||
|
||||
// PrepareNamedContext returns an sqlx.NamedStmt
|
||||
func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) {
|
||||
return prepareNamedContext(ctx, tx, query)
|
||||
}
|
||||
|
||||
// MustExecContext runs MustExecContext within a transaction.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result {
|
||||
return MustExecContext(ctx, tx, query, args...)
|
||||
}
|
||||
|
||||
// QueryxContext within a transaction and context.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
|
||||
r, err := tx.Tx.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{Rows: r, unsafe: tx.unsafe, Mapper: tx.Mapper}, err
|
||||
}
|
||||
|
||||
// SelectContext within a transaction and context.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (tx *Tx) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
|
||||
return SelectContext(ctx, tx, dest, query, args...)
|
||||
}
|
||||
|
||||
// GetContext within a transaction and context.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
// An error is returned if the result set is empty.
|
||||
func (tx *Tx) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
|
||||
return GetContext(ctx, tx, dest, query, args...)
|
||||
}
|
||||
|
||||
// QueryRowxContext within a transaction and context.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (tx *Tx) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
|
||||
rows, err := tx.Tx.QueryContext(ctx, query, args...)
|
||||
return &Row{rows: rows, err: err, unsafe: tx.unsafe, Mapper: tx.Mapper}
|
||||
}
|
||||
|
||||
// NamedExecContext using this Tx.
|
||||
// Any named placeholder parameters are replaced with fields from arg.
|
||||
func (tx *Tx) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) {
|
||||
return NamedExecContext(ctx, tx, query, arg)
|
||||
}
|
||||
|
||||
// SelectContext using the prepared statement.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error {
|
||||
return SelectContext(ctx, &qStmt{s}, dest, "", args...)
|
||||
}
|
||||
|
||||
// GetContext using the prepared statement.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
// An error is returned if the result set is empty.
|
||||
func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error {
|
||||
return GetContext(ctx, &qStmt{s}, dest, "", args...)
|
||||
}
|
||||
|
||||
// MustExecContext (panic) using this statement. Note that the query portion of
|
||||
// the error output will be blank, as Stmt does not expose its query.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (s *Stmt) MustExecContext(ctx context.Context, args ...interface{}) sql.Result {
|
||||
return MustExecContext(ctx, &qStmt{s}, "", args...)
|
||||
}
|
||||
|
||||
// QueryRowxContext using this statement.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *Row {
|
||||
qs := &qStmt{s}
|
||||
return qs.QueryRowxContext(ctx, "", args...)
|
||||
}
|
||||
|
||||
// QueryxContext using this statement.
|
||||
// Any placeholder parameters are replaced with supplied args.
|
||||
func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*Rows, error) {
|
||||
qs := &qStmt{s}
|
||||
return qs.QueryxContext(ctx, "", args...)
|
||||
}
|
||||
|
||||
func (q *qStmt) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
|
||||
return q.Stmt.QueryContext(ctx, args...)
|
||||
}
|
||||
|
||||
func (q *qStmt) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
|
||||
r, err := q.Stmt.QueryContext(ctx, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Rows{Rows: r, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}, err
|
||||
}
|
||||
|
||||
func (q *qStmt) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
|
||||
rows, err := q.Stmt.QueryContext(ctx, args...)
|
||||
return &Row{rows: rows, err: err, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}
|
||||
}
|
||||
|
||||
func (q *qStmt) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
|
||||
return q.Stmt.ExecContext(ctx, args...)
|
||||
}
|
||||
2
vendor/github.com/lann/builder/.gitignore
generated
vendored
Normal file
2
vendor/github.com/lann/builder/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*~
|
||||
\#*#
|
||||
7
vendor/github.com/lann/builder/.travis.yml
generated
vendored
Normal file
7
vendor/github.com/lann/builder/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- '1.8'
|
||||
- '1.9'
|
||||
- '1.10'
|
||||
- tip
|
||||
21
vendor/github.com/lann/builder/LICENSE
generated
vendored
Normal file
21
vendor/github.com/lann/builder/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2014-2015 Lann Martin
|
||||
|
||||
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.
|
||||
68
vendor/github.com/lann/builder/README.md
generated
vendored
Normal file
68
vendor/github.com/lann/builder/README.md
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
# Builder - fluent immutable builders for Go
|
||||
|
||||
[](https://godoc.org/github.com/lann/builder)
|
||||
[](https://travis-ci.org/lann/builder)
|
||||
|
||||
Builder was originally written for
|
||||
[Squirrel](https://github.com/lann/squirrel), a fluent SQL generator. It
|
||||
is probably the best example of Builder in action.
|
||||
|
||||
Builder helps you write **fluent** DSLs for your libraries with method chaining:
|
||||
|
||||
```go
|
||||
resp := ReqBuilder.
|
||||
Url("http://golang.org").
|
||||
Header("User-Agent", "Builder").
|
||||
Get()
|
||||
```
|
||||
|
||||
Builder uses **immutable** persistent data structures
|
||||
([these](https://github.com/mndrix/ps), specifically)
|
||||
so that each step in your method chain can be reused:
|
||||
|
||||
```go
|
||||
build := WordBuilder.AddLetters("Build")
|
||||
builder := build.AddLetters("er")
|
||||
building := build.AddLetters("ing")
|
||||
```
|
||||
|
||||
Builder makes it easy to **build** structs using the **builder** pattern
|
||||
(*surprise!*):
|
||||
|
||||
```go
|
||||
import "github.com/lann/builder"
|
||||
|
||||
type Muppet struct {
|
||||
Name string
|
||||
Friends []string
|
||||
}
|
||||
|
||||
type muppetBuilder builder.Builder
|
||||
|
||||
func (b muppetBuilder) Name(name string) muppetBuilder {
|
||||
return builder.Set(b, "Name", name).(muppetBuilder)
|
||||
}
|
||||
|
||||
func (b muppetBuilder) AddFriend(friend string) muppetBuilder {
|
||||
return builder.Append(b, "Friends", friend).(muppetBuilder)
|
||||
}
|
||||
|
||||
func (b muppetBuilder) Build() Muppet {
|
||||
return builder.GetStruct(b).(Muppet)
|
||||
}
|
||||
|
||||
var MuppetBuilder = builder.Register(muppetBuilder{}, Muppet{}).(muppetBuilder)
|
||||
```
|
||||
```go
|
||||
MuppetBuilder.
|
||||
Name("Beaker").
|
||||
AddFriend("Dr. Honeydew").
|
||||
Build()
|
||||
|
||||
=> Muppet{Name:"Beaker", Friends:[]string{"Dr. Honeydew"}}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Builder is released under the
|
||||
[MIT License](http://www.opensource.org/licenses/MIT).
|
||||
225
vendor/github.com/lann/builder/builder.go
generated
vendored
Normal file
225
vendor/github.com/lann/builder/builder.go
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
// Package builder provides a method for writing fluent immutable builders.
|
||||
package builder
|
||||
|
||||
import (
|
||||
"github.com/lann/ps"
|
||||
"go/ast"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Builder stores a set of named values.
|
||||
//
|
||||
// New types can be declared with underlying type Builder and used with the
|
||||
// functions in this package. See example.
|
||||
//
|
||||
// Instances of Builder should be treated as immutable. It is up to the
|
||||
// implementor to ensure mutable values set on a Builder are not mutated while
|
||||
// the Builder is in use.
|
||||
type Builder struct {
|
||||
builderMap ps.Map
|
||||
}
|
||||
|
||||
var (
|
||||
EmptyBuilder = Builder{ps.NewMap()}
|
||||
emptyBuilderValue = reflect.ValueOf(EmptyBuilder)
|
||||
)
|
||||
|
||||
func getBuilderMap(builder interface{}) ps.Map {
|
||||
b := convert(builder, Builder{}).(Builder)
|
||||
|
||||
if b.builderMap == nil {
|
||||
return ps.NewMap()
|
||||
}
|
||||
|
||||
return b.builderMap
|
||||
}
|
||||
|
||||
// Set returns a copy of the given builder with a new value set for the given
|
||||
// name.
|
||||
//
|
||||
// Set (and all other functions taking a builder in this package) will panic if
|
||||
// the given builder's underlying type is not Builder.
|
||||
func Set(builder interface{}, name string, v interface{}) interface{} {
|
||||
b := Builder{getBuilderMap(builder).Set(name, v)}
|
||||
return convert(b, builder)
|
||||
}
|
||||
|
||||
// Delete returns a copy of the given builder with the given named value unset.
|
||||
func Delete(builder interface{}, name string) interface{} {
|
||||
b := Builder{getBuilderMap(builder).Delete(name)}
|
||||
return convert(b, builder)
|
||||
}
|
||||
|
||||
// Append returns a copy of the given builder with new value(s) appended to the
|
||||
// named list. If the value was previously unset or set with Set (even to a e.g.
|
||||
// slice values), the new value(s) will be appended to an empty list.
|
||||
func Append(builder interface{}, name string, vs ...interface{}) interface{} {
|
||||
return Extend(builder, name, vs)
|
||||
}
|
||||
|
||||
// Extend behaves like Append, except it takes a single slice or array value
|
||||
// which will be concatenated to the named list.
|
||||
//
|
||||
// Unlike a variadic call to Append - which requires a []interface{} value -
|
||||
// Extend accepts slices or arrays of any type.
|
||||
//
|
||||
// Extend will panic if the given value is not a slice, array, or nil.
|
||||
func Extend(builder interface{}, name string, vs interface{}) interface{} {
|
||||
if vs == nil {
|
||||
return builder
|
||||
}
|
||||
|
||||
maybeList, ok := getBuilderMap(builder).Lookup(name)
|
||||
|
||||
var list ps.List
|
||||
if ok {
|
||||
list, ok = maybeList.(ps.List)
|
||||
}
|
||||
if !ok {
|
||||
list = ps.NewList()
|
||||
}
|
||||
|
||||
forEach(vs, func(v interface{}) {
|
||||
list = list.Cons(v)
|
||||
})
|
||||
|
||||
return Set(builder, name, list)
|
||||
}
|
||||
|
||||
func listToSlice(list ps.List, arrayType reflect.Type) reflect.Value {
|
||||
size := list.Size()
|
||||
slice := reflect.MakeSlice(arrayType, size, size)
|
||||
for i := size - 1; i >= 0; i-- {
|
||||
val := reflect.ValueOf(list.Head())
|
||||
slice.Index(i).Set(val)
|
||||
list = list.Tail()
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
var anyArrayType = reflect.TypeOf([]interface{}{})
|
||||
|
||||
// Get retrieves a single named value from the given builder.
|
||||
// If the value has not been set, it returns (nil, false). Otherwise, it will
|
||||
// return (value, true).
|
||||
//
|
||||
// If the named value was last set with Append or Extend, the returned value
|
||||
// will be a slice. If the given Builder has been registered with Register or
|
||||
// RegisterType and the given name is an exported field of the registered
|
||||
// struct, the returned slice will have the same type as that field. Otherwise
|
||||
// the slice will have type []interface{}. It will panic if the given name is a
|
||||
// registered struct's exported field and the value set on the Builder is not
|
||||
// assignable to the field.
|
||||
func Get(builder interface{}, name string) (interface{}, bool) {
|
||||
val, ok := getBuilderMap(builder).Lookup(name)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
list, isList := val.(ps.List)
|
||||
if isList {
|
||||
arrayType := anyArrayType
|
||||
|
||||
if ast.IsExported(name) {
|
||||
structType := getBuilderStructType(reflect.TypeOf(builder))
|
||||
if structType != nil {
|
||||
field, ok := (*structType).FieldByName(name)
|
||||
if ok {
|
||||
arrayType = field.Type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val = listToSlice(list, arrayType).Interface()
|
||||
}
|
||||
|
||||
return val, true
|
||||
}
|
||||
|
||||
// GetMap returns a map[string]interface{} of the values set in the given
|
||||
// builder.
|
||||
//
|
||||
// See notes on Get regarding returned slices.
|
||||
func GetMap(builder interface{}) map[string]interface{} {
|
||||
m := getBuilderMap(builder)
|
||||
structType := getBuilderStructType(reflect.TypeOf(builder))
|
||||
|
||||
ret := make(map[string]interface{}, m.Size())
|
||||
|
||||
m.ForEach(func(name string, val ps.Any) {
|
||||
list, isList := val.(ps.List)
|
||||
if isList {
|
||||
arrayType := anyArrayType
|
||||
|
||||
if structType != nil {
|
||||
field, ok := (*structType).FieldByName(name)
|
||||
if ok {
|
||||
arrayType = field.Type
|
||||
}
|
||||
}
|
||||
|
||||
val = listToSlice(list, arrayType).Interface()
|
||||
}
|
||||
|
||||
ret[name] = val
|
||||
})
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// GetStruct builds a new struct from the given registered builder.
|
||||
// It will return nil if the given builder's type has not been registered with
|
||||
// Register or RegisterValue.
|
||||
//
|
||||
// All values set on the builder with names that start with an uppercase letter
|
||||
// (i.e. which would be exported if they were identifiers) are assigned to the
|
||||
// corresponding exported fields of the struct.
|
||||
//
|
||||
// GetStruct will panic if any of these "exported" values are not assignable to
|
||||
// their corresponding struct fields.
|
||||
func GetStruct(builder interface{}) interface{} {
|
||||
structVal := newBuilderStruct(reflect.TypeOf(builder))
|
||||
if structVal == nil {
|
||||
return nil
|
||||
}
|
||||
return scanStruct(builder, structVal)
|
||||
}
|
||||
|
||||
// GetStructLike builds a new struct from the given builder with the same type
|
||||
// as the given struct.
|
||||
//
|
||||
// All values set on the builder with names that start with an uppercase letter
|
||||
// (i.e. which would be exported if they were identifiers) are assigned to the
|
||||
// corresponding exported fields of the struct.
|
||||
//
|
||||
// ScanStruct will panic if any of these "exported" values are not assignable to
|
||||
// their corresponding struct fields.
|
||||
func GetStructLike(builder interface{}, strct interface{}) interface{} {
|
||||
structVal := reflect.New(reflect.TypeOf(strct)).Elem()
|
||||
return scanStruct(builder, &structVal)
|
||||
}
|
||||
|
||||
func scanStruct(builder interface{}, structVal *reflect.Value) interface{} {
|
||||
getBuilderMap(builder).ForEach(func(name string, val ps.Any) {
|
||||
if ast.IsExported(name) {
|
||||
field := structVal.FieldByName(name)
|
||||
|
||||
var value reflect.Value
|
||||
switch v := val.(type) {
|
||||
case nil:
|
||||
switch field.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
value = reflect.Zero(field.Type())
|
||||
}
|
||||
// nil is not valid for this Type; Set will panic
|
||||
case ps.List:
|
||||
value = listToSlice(v, field.Type())
|
||||
default:
|
||||
value = reflect.ValueOf(val)
|
||||
}
|
||||
field.Set(value)
|
||||
}
|
||||
})
|
||||
|
||||
return structVal.Interface()
|
||||
}
|
||||
24
vendor/github.com/lann/builder/reflect.go
generated
vendored
Normal file
24
vendor/github.com/lann/builder/reflect.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package builder
|
||||
|
||||
import "reflect"
|
||||
|
||||
func convert(from interface{}, to interface{}) interface{} {
|
||||
return reflect.
|
||||
ValueOf(from).
|
||||
Convert(reflect.TypeOf(to)).
|
||||
Interface()
|
||||
}
|
||||
|
||||
func forEach(s interface{}, f func(interface{})) {
|
||||
val := reflect.ValueOf(s)
|
||||
|
||||
kind := val.Kind()
|
||||
if kind != reflect.Slice && kind != reflect.Array {
|
||||
panic(&reflect.ValueError{Method: "builder.forEach", Kind: kind})
|
||||
}
|
||||
|
||||
l := val.Len()
|
||||
for i := 0; i < l; i++ {
|
||||
f(val.Index(i).Interface())
|
||||
}
|
||||
}
|
||||
59
vendor/github.com/lann/builder/registry.go
generated
vendored
Normal file
59
vendor/github.com/lann/builder/registry.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
registry = make(map[reflect.Type]reflect.Type)
|
||||
registryMux sync.RWMutex
|
||||
)
|
||||
|
||||
// RegisterType maps the given builderType to a structType.
|
||||
// This mapping affects the type of slices returned by Get and is required for
|
||||
// GetStruct to work.
|
||||
//
|
||||
// Returns a Value containing an empty instance of the registered builderType.
|
||||
//
|
||||
// RegisterType will panic if builderType's underlying type is not Builder or
|
||||
// if structType's Kind is not Struct.
|
||||
func RegisterType(builderType reflect.Type, structType reflect.Type) *reflect.Value {
|
||||
registryMux.Lock()
|
||||
defer registryMux.Unlock()
|
||||
structType.NumField() // Panic if structType is not a struct
|
||||
registry[builderType] = structType
|
||||
emptyValue := emptyBuilderValue.Convert(builderType)
|
||||
return &emptyValue
|
||||
}
|
||||
|
||||
// Register wraps RegisterType, taking instances instead of Types.
|
||||
//
|
||||
// Returns an empty instance of the registered builder type which can be used
|
||||
// as the initial value for builder expressions. See example.
|
||||
func Register(builderProto, structProto interface{}) interface{} {
|
||||
empty := RegisterType(
|
||||
reflect.TypeOf(builderProto),
|
||||
reflect.TypeOf(structProto),
|
||||
).Interface()
|
||||
return empty
|
||||
}
|
||||
|
||||
func getBuilderStructType(builderType reflect.Type) *reflect.Type {
|
||||
registryMux.RLock()
|
||||
defer registryMux.RUnlock()
|
||||
structType, ok := registry[builderType]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return &structType
|
||||
}
|
||||
|
||||
func newBuilderStruct(builderType reflect.Type) *reflect.Value {
|
||||
structType := getBuilderStructType(builderType)
|
||||
if structType == nil {
|
||||
return nil
|
||||
}
|
||||
newStruct := reflect.New(*structType).Elem()
|
||||
return &newStruct
|
||||
}
|
||||
7
vendor/github.com/lann/ps/LICENSE
generated
vendored
Normal file
7
vendor/github.com/lann/ps/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2013 Michael Hendricks
|
||||
|
||||
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.
|
||||
10
vendor/github.com/lann/ps/README.md
generated
vendored
Normal file
10
vendor/github.com/lann/ps/README.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
**This is a stable fork of https://github.com/mndrix/ps; it will not introduce breaking changes.**
|
||||
|
||||
ps
|
||||
==
|
||||
|
||||
Persistent data structures for Go. See the [full package documentation](http://godoc.org/github.com/lann/ps)
|
||||
|
||||
Install with
|
||||
|
||||
go get github.com/lann/ps
|
||||
93
vendor/github.com/lann/ps/list.go
generated
vendored
Normal file
93
vendor/github.com/lann/ps/list.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
package ps
|
||||
|
||||
// List is a persistent list of possibly heterogenous values.
|
||||
type List interface {
|
||||
// IsNil returns true if the list is empty
|
||||
IsNil() bool
|
||||
|
||||
// Cons returns a new list with val as the head
|
||||
Cons(val Any) List
|
||||
|
||||
// Head returns the first element of the list;
|
||||
// panics if the list is empty
|
||||
Head() Any
|
||||
|
||||
// Tail returns a list with all elements except the head;
|
||||
// panics if the list is empty
|
||||
Tail() List
|
||||
|
||||
// Size returns the list's length. This takes O(1) time.
|
||||
Size() int
|
||||
|
||||
// ForEach executes a callback for each value in the list.
|
||||
ForEach(f func(Any))
|
||||
|
||||
// Reverse returns a list whose elements are in the opposite order as
|
||||
// the original list.
|
||||
Reverse() List
|
||||
}
|
||||
|
||||
// Immutable (i.e. persistent) list
|
||||
type list struct {
|
||||
depth int // the number of nodes after, and including, this one
|
||||
value Any
|
||||
tail *list
|
||||
}
|
||||
|
||||
// An empty list shared by all lists
|
||||
var nilList = &list{}
|
||||
|
||||
// NewList returns a new, empty list. The result is a singly linked
|
||||
// list implementation. All lists share an empty tail, so allocating
|
||||
// empty lists is efficient in time and memory.
|
||||
func NewList() List {
|
||||
return nilList
|
||||
}
|
||||
|
||||
func (self *list) IsNil() bool {
|
||||
return self == nilList
|
||||
}
|
||||
|
||||
func (self *list) Size() int {
|
||||
return self.depth
|
||||
}
|
||||
|
||||
func (tail *list) Cons(val Any) List {
|
||||
var xs list
|
||||
xs.depth = tail.depth + 1
|
||||
xs.value = val
|
||||
xs.tail = tail
|
||||
return &xs
|
||||
}
|
||||
|
||||
func (self *list) Head() Any {
|
||||
if self.IsNil() {
|
||||
panic("Called Head() on an empty list")
|
||||
}
|
||||
|
||||
return self.value
|
||||
}
|
||||
|
||||
func (self *list) Tail() List {
|
||||
if self.IsNil() {
|
||||
panic("Called Tail() on an empty list")
|
||||
}
|
||||
|
||||
return self.tail
|
||||
}
|
||||
|
||||
// ForEach executes a callback for each value in the list
|
||||
func (self *list) ForEach(f func(Any)) {
|
||||
if self.IsNil() {
|
||||
return
|
||||
}
|
||||
f(self.Head())
|
||||
self.Tail().ForEach(f)
|
||||
}
|
||||
|
||||
// Reverse returns a list with elements in opposite order as this list
|
||||
func (self *list) Reverse() List {
|
||||
reversed := NewList()
|
||||
self.ForEach(func(v Any) { reversed = reversed.Cons(v) })
|
||||
return reversed
|
||||
}
|
||||
311
vendor/github.com/lann/ps/map.go
generated
vendored
Normal file
311
vendor/github.com/lann/ps/map.go
generated
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
// Fully persistent data structures. A persistent data structure is a data
|
||||
// structure that always preserves the previous version of itself when
|
||||
// it is modified. Such data structures are effectively immutable,
|
||||
// as their operations do not update the structure in-place, but instead
|
||||
// always yield a new structure.
|
||||
//
|
||||
// Persistent
|
||||
// data structures typically share structure among themselves. This allows
|
||||
// operations to avoid copying the entire data structure.
|
||||
package ps
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Any is a shorthand for Go's verbose interface{} type.
|
||||
type Any interface{}
|
||||
|
||||
// A Map associates unique keys (type string) with values (type Any).
|
||||
type Map interface {
|
||||
// IsNil returns true if the Map is empty
|
||||
IsNil() bool
|
||||
|
||||
// Set returns a new map in which key and value are associated.
|
||||
// If the key didn't exist before, it's created; otherwise, the
|
||||
// associated value is changed.
|
||||
// This operation is O(log N) in the number of keys.
|
||||
Set(key string, value Any) Map
|
||||
|
||||
// Delete returns a new map with the association for key, if any, removed.
|
||||
// This operation is O(log N) in the number of keys.
|
||||
Delete(key string) Map
|
||||
|
||||
// Lookup returns the value associated with a key, if any. If the key
|
||||
// exists, the second return value is true; otherwise, false.
|
||||
// This operation is O(log N) in the number of keys.
|
||||
Lookup(key string) (Any, bool)
|
||||
|
||||
// Size returns the number of key value pairs in the map.
|
||||
// This takes O(1) time.
|
||||
Size() int
|
||||
|
||||
// ForEach executes a callback on each key value pair in the map.
|
||||
ForEach(f func(key string, val Any))
|
||||
|
||||
// Keys returns a slice with all keys in this map.
|
||||
// This operation is O(N) in the number of keys.
|
||||
Keys() []string
|
||||
|
||||
String() string
|
||||
}
|
||||
|
||||
// Immutable (i.e. persistent) associative array
|
||||
const childCount = 8
|
||||
const shiftSize = 3
|
||||
|
||||
type tree struct {
|
||||
count int
|
||||
hash uint64 // hash of the key (used for tree balancing)
|
||||
key string
|
||||
value Any
|
||||
children [childCount]*tree
|
||||
}
|
||||
|
||||
var nilMap = &tree{}
|
||||
|
||||
// Recursively set nilMap's subtrees to point at itself.
|
||||
// This eliminates all nil pointers in the map structure.
|
||||
// All map nodes are created by cloning this structure so
|
||||
// they avoid the problem too.
|
||||
func init() {
|
||||
for i := range nilMap.children {
|
||||
nilMap.children[i] = nilMap
|
||||
}
|
||||
}
|
||||
|
||||
// NewMap allocates a new, persistent map from strings to values of
|
||||
// any type.
|
||||
// This is currently implemented as a path-copying binary tree.
|
||||
func NewMap() Map {
|
||||
return nilMap
|
||||
}
|
||||
|
||||
func (self *tree) IsNil() bool {
|
||||
return self == nilMap
|
||||
}
|
||||
|
||||
// clone returns an exact duplicate of a tree node
|
||||
func (self *tree) clone() *tree {
|
||||
var m tree
|
||||
m = *self
|
||||
return &m
|
||||
}
|
||||
|
||||
// constants for FNV-1a hash algorithm
|
||||
const (
|
||||
offset64 uint64 = 14695981039346656037
|
||||
prime64 uint64 = 1099511628211
|
||||
)
|
||||
|
||||
// hashKey returns a hash code for a given string
|
||||
func hashKey(key string) uint64 {
|
||||
hash := offset64
|
||||
for _, codepoint := range key {
|
||||
hash ^= uint64(codepoint)
|
||||
hash *= prime64
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// Set returns a new map similar to this one but with key and value
|
||||
// associated. If the key didn't exist, it's created; otherwise, the
|
||||
// associated value is changed.
|
||||
func (self *tree) Set(key string, value Any) Map {
|
||||
hash := hashKey(key)
|
||||
return setLowLevel(self, hash, hash, key, value)
|
||||
}
|
||||
|
||||
func setLowLevel(self *tree, partialHash, hash uint64, key string, value Any) *tree {
|
||||
if self.IsNil() { // an empty tree is easy
|
||||
m := self.clone()
|
||||
m.count = 1
|
||||
m.hash = hash
|
||||
m.key = key
|
||||
m.value = value
|
||||
return m
|
||||
}
|
||||
|
||||
if hash != self.hash {
|
||||
m := self.clone()
|
||||
i := partialHash % childCount
|
||||
m.children[i] = setLowLevel(self.children[i], partialHash>>shiftSize, hash, key, value)
|
||||
recalculateCount(m)
|
||||
return m
|
||||
}
|
||||
|
||||
// replacing a key's previous value
|
||||
m := self.clone()
|
||||
m.value = value
|
||||
return m
|
||||
}
|
||||
|
||||
// modifies a map by recalculating its key count based on the counts
|
||||
// of its subtrees
|
||||
func recalculateCount(m *tree) {
|
||||
count := 0
|
||||
for _, t := range m.children {
|
||||
count += t.Size()
|
||||
}
|
||||
m.count = count + 1 // add one to count ourself
|
||||
}
|
||||
|
||||
func (m *tree) Delete(key string) Map {
|
||||
hash := hashKey(key)
|
||||
newMap, _ := deleteLowLevel(m, hash, hash)
|
||||
return newMap
|
||||
}
|
||||
|
||||
func deleteLowLevel(self *tree, partialHash, hash uint64) (*tree, bool) {
|
||||
// empty trees are easy
|
||||
if self.IsNil() {
|
||||
return self, false
|
||||
}
|
||||
|
||||
if hash != self.hash {
|
||||
i := partialHash % childCount
|
||||
child, found := deleteLowLevel(self.children[i], partialHash>>shiftSize, hash)
|
||||
if !found {
|
||||
return self, false
|
||||
}
|
||||
newMap := self.clone()
|
||||
newMap.children[i] = child
|
||||
recalculateCount(newMap)
|
||||
return newMap, true // ? this wasn't in the original code
|
||||
}
|
||||
|
||||
// we must delete our own node
|
||||
if self.isLeaf() { // we have no children
|
||||
return nilMap, true
|
||||
}
|
||||
/*
|
||||
if self.subtreeCount() == 1 { // only one subtree
|
||||
for _, t := range self.children {
|
||||
if t != nilMap {
|
||||
return t, true
|
||||
}
|
||||
}
|
||||
panic("Tree with 1 subtree actually had no subtrees")
|
||||
}
|
||||
*/
|
||||
|
||||
// find a node to replace us
|
||||
i := -1
|
||||
size := -1
|
||||
for j, t := range self.children {
|
||||
if t.Size() > size {
|
||||
i = j
|
||||
size = t.Size()
|
||||
}
|
||||
}
|
||||
|
||||
// make chosen leaf smaller
|
||||
replacement, child := self.children[i].deleteLeftmost()
|
||||
newMap := replacement.clone()
|
||||
for j := range self.children {
|
||||
if j == i {
|
||||
newMap.children[j] = child
|
||||
} else {
|
||||
newMap.children[j] = self.children[j]
|
||||
}
|
||||
}
|
||||
recalculateCount(newMap)
|
||||
return newMap, true
|
||||
}
|
||||
|
||||
// delete the leftmost node in a tree returning the node that
|
||||
// was deleted and the tree left over after its deletion
|
||||
func (m *tree) deleteLeftmost() (*tree, *tree) {
|
||||
if m.isLeaf() {
|
||||
return m, nilMap
|
||||
}
|
||||
|
||||
for i, t := range m.children {
|
||||
if t != nilMap {
|
||||
deleted, child := t.deleteLeftmost()
|
||||
newMap := m.clone()
|
||||
newMap.children[i] = child
|
||||
recalculateCount(newMap)
|
||||
return deleted, newMap
|
||||
}
|
||||
}
|
||||
panic("Tree isn't a leaf but also had no children. How does that happen?")
|
||||
}
|
||||
|
||||
// isLeaf returns true if this is a leaf node
|
||||
func (m *tree) isLeaf() bool {
|
||||
return m.Size() == 1
|
||||
}
|
||||
|
||||
// returns the number of child subtrees we have
|
||||
func (m *tree) subtreeCount() int {
|
||||
count := 0
|
||||
for _, t := range m.children {
|
||||
if t != nilMap {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (m *tree) Lookup(key string) (Any, bool) {
|
||||
hash := hashKey(key)
|
||||
return lookupLowLevel(m, hash, hash)
|
||||
}
|
||||
|
||||
func lookupLowLevel(self *tree, partialHash, hash uint64) (Any, bool) {
|
||||
if self.IsNil() { // an empty tree is easy
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if hash != self.hash {
|
||||
i := partialHash % childCount
|
||||
return lookupLowLevel(self.children[i], partialHash>>shiftSize, hash)
|
||||
}
|
||||
|
||||
// we found it
|
||||
return self.value, true
|
||||
}
|
||||
|
||||
func (m *tree) Size() int {
|
||||
return m.count
|
||||
}
|
||||
|
||||
func (m *tree) ForEach(f func(key string, val Any)) {
|
||||
if m.IsNil() {
|
||||
return
|
||||
}
|
||||
|
||||
// ourself
|
||||
f(m.key, m.value)
|
||||
|
||||
// children
|
||||
for _, t := range m.children {
|
||||
if t != nilMap {
|
||||
t.ForEach(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *tree) Keys() []string {
|
||||
keys := make([]string, m.Size())
|
||||
i := 0
|
||||
m.ForEach(func(k string, v Any) {
|
||||
keys[i] = k
|
||||
i++
|
||||
})
|
||||
return keys
|
||||
}
|
||||
|
||||
// make it easier to display maps for debugging
|
||||
func (m *tree) String() string {
|
||||
keys := m.Keys()
|
||||
buf := bytes.NewBufferString("{")
|
||||
for _, key := range keys {
|
||||
val, _ := m.Lookup(key)
|
||||
fmt.Fprintf(buf, "%s: %s, ", key, val)
|
||||
}
|
||||
fmt.Fprintf(buf, "}\n")
|
||||
return buf.String()
|
||||
}
|
||||
3
vendor/github.com/lann/ps/profile.sh
generated
vendored
Normal file
3
vendor/github.com/lann/ps/profile.sh
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
go test -c
|
||||
./ps.test -test.run=none -test.bench=$2 -test.$1profile=$1.profile
|
||||
4
vendor/github.com/lib/pq/.gitignore
generated
vendored
Normal file
4
vendor/github.com/lib/pq/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.db
|
||||
*.test
|
||||
*~
|
||||
*.swp
|
||||
73
vendor/github.com/lib/pq/.travis.sh
generated
vendored
Normal file
73
vendor/github.com/lib/pq/.travis.sh
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
client_configure() {
|
||||
sudo chmod 600 $PQSSLCERTTEST_PATH/postgresql.key
|
||||
}
|
||||
|
||||
pgdg_repository() {
|
||||
local sourcelist='sources.list.d/postgresql.list'
|
||||
|
||||
curl -sS 'https://www.postgresql.org/media/keys/ACCC4CF8.asc' | sudo apt-key add -
|
||||
echo deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main $PGVERSION | sudo tee "/etc/apt/$sourcelist"
|
||||
sudo apt-get -o Dir::Etc::sourcelist="$sourcelist" -o Dir::Etc::sourceparts='-' -o APT::Get::List-Cleanup='0' update
|
||||
}
|
||||
|
||||
postgresql_configure() {
|
||||
sudo tee /etc/postgresql/$PGVERSION/main/pg_hba.conf > /dev/null <<-config
|
||||
local all all trust
|
||||
hostnossl all pqgossltest 127.0.0.1/32 reject
|
||||
hostnossl all pqgosslcert 127.0.0.1/32 reject
|
||||
hostssl all pqgossltest 127.0.0.1/32 trust
|
||||
hostssl all pqgosslcert 127.0.0.1/32 cert
|
||||
host all all 127.0.0.1/32 trust
|
||||
hostnossl all pqgossltest ::1/128 reject
|
||||
hostnossl all pqgosslcert ::1/128 reject
|
||||
hostssl all pqgossltest ::1/128 trust
|
||||
hostssl all pqgosslcert ::1/128 cert
|
||||
host all all ::1/128 trust
|
||||
config
|
||||
|
||||
xargs sudo install -o postgres -g postgres -m 600 -t /var/lib/postgresql/$PGVERSION/main/ <<-certificates
|
||||
certs/root.crt
|
||||
certs/server.crt
|
||||
certs/server.key
|
||||
certificates
|
||||
|
||||
sort -VCu <<-versions ||
|
||||
$PGVERSION
|
||||
9.2
|
||||
versions
|
||||
sudo tee -a /etc/postgresql/$PGVERSION/main/postgresql.conf > /dev/null <<-config
|
||||
ssl_ca_file = 'root.crt'
|
||||
ssl_cert_file = 'server.crt'
|
||||
ssl_key_file = 'server.key'
|
||||
config
|
||||
|
||||
echo 127.0.0.1 postgres | sudo tee -a /etc/hosts > /dev/null
|
||||
|
||||
sudo service postgresql restart
|
||||
}
|
||||
|
||||
postgresql_install() {
|
||||
xargs sudo apt-get -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confnew' install <<-packages
|
||||
postgresql-$PGVERSION
|
||||
postgresql-server-dev-$PGVERSION
|
||||
postgresql-contrib-$PGVERSION
|
||||
packages
|
||||
}
|
||||
|
||||
postgresql_uninstall() {
|
||||
sudo service postgresql stop
|
||||
xargs sudo apt-get -y --purge remove <<-packages
|
||||
libpq-dev
|
||||
libpq5
|
||||
postgresql
|
||||
postgresql-client-common
|
||||
postgresql-common
|
||||
packages
|
||||
sudo rm -rf /var/lib/postgresql
|
||||
}
|
||||
|
||||
$1
|
||||
44
vendor/github.com/lib/pq/.travis.yml
generated
vendored
Normal file
44
vendor/github.com/lib/pq/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- master
|
||||
|
||||
sudo: true
|
||||
|
||||
env:
|
||||
global:
|
||||
- PGUSER=postgres
|
||||
- PQGOSSLTESTS=1
|
||||
- PQSSLCERTTEST_PATH=$PWD/certs
|
||||
- PGHOST=127.0.0.1
|
||||
matrix:
|
||||
- PGVERSION=10
|
||||
- PGVERSION=9.6
|
||||
- PGVERSION=9.5
|
||||
- PGVERSION=9.4
|
||||
|
||||
before_install:
|
||||
- ./.travis.sh postgresql_uninstall
|
||||
- ./.travis.sh pgdg_repository
|
||||
- ./.travis.sh postgresql_install
|
||||
- ./.travis.sh postgresql_configure
|
||||
- ./.travis.sh client_configure
|
||||
- go get golang.org/x/tools/cmd/goimports
|
||||
- go get golang.org/x/lint/golint
|
||||
- GO111MODULE=on go get honnef.co/go/tools/cmd/staticcheck@2019.2.1
|
||||
|
||||
before_script:
|
||||
- createdb pqgotest
|
||||
- createuser -DRS pqgossltest
|
||||
- createuser -DRS pqgosslcert
|
||||
|
||||
script:
|
||||
- >
|
||||
goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }'
|
||||
- go vet ./...
|
||||
- staticcheck -go 1.11 ./...
|
||||
- golint ./...
|
||||
- PQTEST_BINARY_PARAMETERS=no go test -race -v ./...
|
||||
- PQTEST_BINARY_PARAMETERS=yes go test -race -v ./...
|
||||
29
vendor/github.com/lib/pq/CONTRIBUTING.md
generated
vendored
Normal file
29
vendor/github.com/lib/pq/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
## Contributing to pq
|
||||
|
||||
`pq` has a backlog of pull requests, but contributions are still very
|
||||
much welcome. You can help with patch review, submitting bug reports,
|
||||
or adding new functionality. There is no formal style guide, but
|
||||
please conform to the style of existing code and general Go formatting
|
||||
conventions when submitting patches.
|
||||
|
||||
### Patch review
|
||||
|
||||
Help review existing open pull requests by commenting on the code or
|
||||
proposed functionality.
|
||||
|
||||
### Bug reports
|
||||
|
||||
We appreciate any bug reports, but especially ones with self-contained
|
||||
(doesn't depend on code outside of pq), minimal (can't be simplified
|
||||
further) test cases. It's especially helpful if you can submit a pull
|
||||
request with just the failing test case (you'll probably want to
|
||||
pattern it after the tests in
|
||||
[conn_test.go](https://github.com/lib/pq/blob/master/conn_test.go).
|
||||
|
||||
### New functionality
|
||||
|
||||
There are a number of pending patches for new functionality, so
|
||||
additional feature patches will take a while to merge. Still, patches
|
||||
are generally reviewed based on usefulness and complexity in addition
|
||||
to time-in-queue, so if you have a knockout idea, take a shot. Feel
|
||||
free to open an issue discussion your proposed patch beforehand.
|
||||
8
vendor/github.com/lib/pq/LICENSE.md
generated
vendored
Normal file
8
vendor/github.com/lib/pq/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
Copyright (c) 2011-2013, 'pq' Contributors
|
||||
Portions Copyright (C) 2011 Blake Mizerany
|
||||
|
||||
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.
|
||||
95
vendor/github.com/lib/pq/README.md
generated
vendored
Normal file
95
vendor/github.com/lib/pq/README.md
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
# pq - A pure Go postgres driver for Go's database/sql package
|
||||
|
||||
[](https://godoc.org/github.com/lib/pq)
|
||||
[](https://travis-ci.org/lib/pq)
|
||||
|
||||
## Install
|
||||
|
||||
go get github.com/lib/pq
|
||||
|
||||
## Docs
|
||||
|
||||
For detailed documentation and basic usage examples, please see the package
|
||||
documentation at <https://godoc.org/github.com/lib/pq>.
|
||||
|
||||
## Tests
|
||||
|
||||
`go test` is used for testing. See [TESTS.md](TESTS.md) for more details.
|
||||
|
||||
## Features
|
||||
|
||||
* SSL
|
||||
* Handles bad connections for `database/sql`
|
||||
* Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`)
|
||||
* Scan binary blobs correctly (i.e. `bytea`)
|
||||
* Package for `hstore` support
|
||||
* COPY FROM support
|
||||
* pq.ParseURL for converting urls to connection strings for sql.Open.
|
||||
* Many libpq compatible environment variables
|
||||
* Unix socket support
|
||||
* Notifications: `LISTEN`/`NOTIFY`
|
||||
* pgpass support
|
||||
|
||||
## Future / Things you can help with
|
||||
|
||||
* Better COPY FROM / COPY TO (see discussion in #181)
|
||||
|
||||
## Thank you (alphabetical)
|
||||
|
||||
Some of these contributors are from the original library `bmizerany/pq.go` whose
|
||||
code still exists in here.
|
||||
|
||||
* Andy Balholm (andybalholm)
|
||||
* Ben Berkert (benburkert)
|
||||
* Benjamin Heatwole (bheatwole)
|
||||
* Bill Mill (llimllib)
|
||||
* Bjørn Madsen (aeons)
|
||||
* Blake Gentry (bgentry)
|
||||
* Brad Fitzpatrick (bradfitz)
|
||||
* Charlie Melbye (cmelbye)
|
||||
* Chris Bandy (cbandy)
|
||||
* Chris Gilling (cgilling)
|
||||
* Chris Walsh (cwds)
|
||||
* Dan Sosedoff (sosedoff)
|
||||
* Daniel Farina (fdr)
|
||||
* Eric Chlebek (echlebek)
|
||||
* Eric Garrido (minusnine)
|
||||
* Eric Urban (hydrogen18)
|
||||
* Everyone at The Go Team
|
||||
* Evan Shaw (edsrzf)
|
||||
* Ewan Chou (coocood)
|
||||
* Fazal Majid (fazalmajid)
|
||||
* Federico Romero (federomero)
|
||||
* Fumin (fumin)
|
||||
* Gary Burd (garyburd)
|
||||
* Heroku (heroku)
|
||||
* James Pozdena (jpoz)
|
||||
* Jason McVetta (jmcvetta)
|
||||
* Jeremy Jay (pbnjay)
|
||||
* Joakim Sernbrant (serbaut)
|
||||
* John Gallagher (jgallagher)
|
||||
* Jonathan Rudenberg (titanous)
|
||||
* Joël Stemmer (jstemmer)
|
||||
* Kamil Kisiel (kisielk)
|
||||
* Kelly Dunn (kellydunn)
|
||||
* Keith Rarick (kr)
|
||||
* Kir Shatrov (kirs)
|
||||
* Lann Martin (lann)
|
||||
* Maciek Sakrejda (uhoh-itsmaciek)
|
||||
* Marc Brinkmann (mbr)
|
||||
* Marko Tiikkaja (johto)
|
||||
* Matt Newberry (MattNewberry)
|
||||
* Matt Robenolt (mattrobenolt)
|
||||
* Martin Olsen (martinolsen)
|
||||
* Mike Lewis (mikelikespie)
|
||||
* Nicolas Patry (Narsil)
|
||||
* Oliver Tonnhofer (olt)
|
||||
* Patrick Hayes (phayes)
|
||||
* Paul Hammond (paulhammond)
|
||||
* Ryan Smith (ryandotsmith)
|
||||
* Samuel Stauffer (samuel)
|
||||
* Timothée Peignier (cyberdelia)
|
||||
* Travis Cline (tmc)
|
||||
* TruongSinh Tran-Nguyen (truongsinh)
|
||||
* Yaismel Miranda (ympons)
|
||||
* notedit (notedit)
|
||||
33
vendor/github.com/lib/pq/TESTS.md
generated
vendored
Normal file
33
vendor/github.com/lib/pq/TESTS.md
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# Tests
|
||||
|
||||
## Running Tests
|
||||
|
||||
`go test` is used for testing. A running PostgreSQL
|
||||
server is required, with the ability to log in. The
|
||||
database to connect to test with is "pqgotest," on
|
||||
"localhost" but these can be overridden using [environment
|
||||
variables](https://www.postgresql.org/docs/9.3/static/libpq-envars.html).
|
||||
|
||||
Example:
|
||||
|
||||
PGHOST=/run/postgresql go test
|
||||
|
||||
## Benchmarks
|
||||
|
||||
A benchmark suite can be run as part of the tests:
|
||||
|
||||
go test -bench .
|
||||
|
||||
## Example setup (Docker)
|
||||
|
||||
Run a postgres container:
|
||||
|
||||
```
|
||||
docker run --expose 5432:5432 postgres
|
||||
```
|
||||
|
||||
Run tests:
|
||||
|
||||
```
|
||||
PGHOST=localhost PGPORT=5432 PGUSER=postgres PGSSLMODE=disable PGDATABASE=postgres go test
|
||||
```
|
||||
756
vendor/github.com/lib/pq/array.go
generated
vendored
Normal file
756
vendor/github.com/lib/pq/array.go
generated
vendored
Normal file
@@ -0,0 +1,756 @@
|
||||
package pq
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var typeByteSlice = reflect.TypeOf([]byte{})
|
||||
var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
|
||||
var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
|
||||
|
||||
// Array returns the optimal driver.Valuer and sql.Scanner for an array or
|
||||
// slice of any dimension.
|
||||
//
|
||||
// For example:
|
||||
// db.Query(`SELECT * FROM t WHERE id = ANY($1)`, pq.Array([]int{235, 401}))
|
||||
//
|
||||
// var x []sql.NullInt64
|
||||
// db.QueryRow('SELECT ARRAY[235, 401]').Scan(pq.Array(&x))
|
||||
//
|
||||
// Scanning multi-dimensional arrays is not supported. Arrays where the lower
|
||||
// bound is not one (such as `[0:0]={1}') are not supported.
|
||||
func Array(a interface{}) interface {
|
||||
driver.Valuer
|
||||
sql.Scanner
|
||||
} {
|
||||
switch a := a.(type) {
|
||||
case []bool:
|
||||
return (*BoolArray)(&a)
|
||||
case []float64:
|
||||
return (*Float64Array)(&a)
|
||||
case []int64:
|
||||
return (*Int64Array)(&a)
|
||||
case []string:
|
||||
return (*StringArray)(&a)
|
||||
|
||||
case *[]bool:
|
||||
return (*BoolArray)(a)
|
||||
case *[]float64:
|
||||
return (*Float64Array)(a)
|
||||
case *[]int64:
|
||||
return (*Int64Array)(a)
|
||||
case *[]string:
|
||||
return (*StringArray)(a)
|
||||
}
|
||||
|
||||
return GenericArray{a}
|
||||
}
|
||||
|
||||
// ArrayDelimiter may be optionally implemented by driver.Valuer or sql.Scanner
|
||||
// to override the array delimiter used by GenericArray.
|
||||
type ArrayDelimiter interface {
|
||||
// ArrayDelimiter returns the delimiter character(s) for this element's type.
|
||||
ArrayDelimiter() string
|
||||
}
|
||||
|
||||
// BoolArray represents a one-dimensional array of the PostgreSQL boolean type.
|
||||
type BoolArray []bool
|
||||
|
||||
// Scan implements the sql.Scanner interface.
|
||||
func (a *BoolArray) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case []byte:
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to BoolArray", src)
|
||||
}
|
||||
|
||||
func (a *BoolArray) scanBytes(src []byte) error {
|
||||
elems, err := scanLinearArray(src, []byte{','}, "BoolArray")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(BoolArray, len(elems))
|
||||
for i, v := range elems {
|
||||
if len(v) != 1 {
|
||||
return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v)
|
||||
}
|
||||
switch v[0] {
|
||||
case 't':
|
||||
b[i] = true
|
||||
case 'f':
|
||||
b[i] = false
|
||||
default:
|
||||
return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v)
|
||||
}
|
||||
}
|
||||
*a = b
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver.Valuer interface.
|
||||
func (a BoolArray) Value() (driver.Value, error) {
|
||||
if a == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if n := len(a); n > 0 {
|
||||
// There will be exactly two curly brackets, N bytes of values,
|
||||
// and N-1 bytes of delimiters.
|
||||
b := make([]byte, 1+2*n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
b[2*i] = ','
|
||||
if a[i] {
|
||||
b[1+2*i] = 't'
|
||||
} else {
|
||||
b[1+2*i] = 'f'
|
||||
}
|
||||
}
|
||||
|
||||
b[0] = '{'
|
||||
b[2*n] = '}'
|
||||
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
return "{}", nil
|
||||
}
|
||||
|
||||
// ByteaArray represents a one-dimensional array of the PostgreSQL bytea type.
|
||||
type ByteaArray [][]byte
|
||||
|
||||
// Scan implements the sql.Scanner interface.
|
||||
func (a *ByteaArray) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case []byte:
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to ByteaArray", src)
|
||||
}
|
||||
|
||||
func (a *ByteaArray) scanBytes(src []byte) error {
|
||||
elems, err := scanLinearArray(src, []byte{','}, "ByteaArray")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(ByteaArray, len(elems))
|
||||
for i, v := range elems {
|
||||
b[i], err = parseBytea(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse bytea array index %d: %s", i, err.Error())
|
||||
}
|
||||
}
|
||||
*a = b
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver.Valuer interface. It uses the "hex" format which
|
||||
// is only supported on PostgreSQL 9.0 or newer.
|
||||
func (a ByteaArray) Value() (driver.Value, error) {
|
||||
if a == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if n := len(a); n > 0 {
|
||||
// There will be at least two curly brackets, 2*N bytes of quotes,
|
||||
// 3*N bytes of hex formatting, and N-1 bytes of delimiters.
|
||||
size := 1 + 6*n
|
||||
for _, x := range a {
|
||||
size += hex.EncodedLen(len(x))
|
||||
}
|
||||
|
||||
b := make([]byte, size)
|
||||
|
||||
for i, s := 0, b; i < n; i++ {
|
||||
o := copy(s, `,"\\x`)
|
||||
o += hex.Encode(s[o:], a[i])
|
||||
s[o] = '"'
|
||||
s = s[o+1:]
|
||||
}
|
||||
|
||||
b[0] = '{'
|
||||
b[size-1] = '}'
|
||||
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
return "{}", nil
|
||||
}
|
||||
|
||||
// Float64Array represents a one-dimensional array of the PostgreSQL double
|
||||
// precision type.
|
||||
type Float64Array []float64
|
||||
|
||||
// Scan implements the sql.Scanner interface.
|
||||
func (a *Float64Array) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case []byte:
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to Float64Array", src)
|
||||
}
|
||||
|
||||
func (a *Float64Array) scanBytes(src []byte) error {
|
||||
elems, err := scanLinearArray(src, []byte{','}, "Float64Array")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(Float64Array, len(elems))
|
||||
for i, v := range elems {
|
||||
if b[i], err = strconv.ParseFloat(string(v), 64); err != nil {
|
||||
return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
*a = b
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver.Valuer interface.
|
||||
func (a Float64Array) Value() (driver.Value, error) {
|
||||
if a == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if n := len(a); n > 0 {
|
||||
// There will be at least two curly brackets, N bytes of values,
|
||||
// and N-1 bytes of delimiters.
|
||||
b := make([]byte, 1, 1+2*n)
|
||||
b[0] = '{'
|
||||
|
||||
b = strconv.AppendFloat(b, a[0], 'f', -1, 64)
|
||||
for i := 1; i < n; i++ {
|
||||
b = append(b, ',')
|
||||
b = strconv.AppendFloat(b, a[i], 'f', -1, 64)
|
||||
}
|
||||
|
||||
return string(append(b, '}')), nil
|
||||
}
|
||||
|
||||
return "{}", nil
|
||||
}
|
||||
|
||||
// GenericArray implements the driver.Valuer and sql.Scanner interfaces for
|
||||
// an array or slice of any dimension.
|
||||
type GenericArray struct{ A interface{} }
|
||||
|
||||
func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]byte, reflect.Value) error, string) {
|
||||
var assign func([]byte, reflect.Value) error
|
||||
var del = ","
|
||||
|
||||
// TODO calculate the assign function for other types
|
||||
// TODO repeat this section on the element type of arrays or slices (multidimensional)
|
||||
{
|
||||
if reflect.PtrTo(rt).Implements(typeSQLScanner) {
|
||||
// dest is always addressable because it is an element of a slice.
|
||||
assign = func(src []byte, dest reflect.Value) (err error) {
|
||||
ss := dest.Addr().Interface().(sql.Scanner)
|
||||
if src == nil {
|
||||
err = ss.Scan(nil)
|
||||
} else {
|
||||
err = ss.Scan(src)
|
||||
}
|
||||
return
|
||||
}
|
||||
goto FoundType
|
||||
}
|
||||
|
||||
assign = func([]byte, reflect.Value) error {
|
||||
return fmt.Errorf("pq: scanning to %s is not implemented; only sql.Scanner", rt)
|
||||
}
|
||||
}
|
||||
|
||||
FoundType:
|
||||
|
||||
if ad, ok := reflect.Zero(rt).Interface().(ArrayDelimiter); ok {
|
||||
del = ad.ArrayDelimiter()
|
||||
}
|
||||
|
||||
return rt, assign, del
|
||||
}
|
||||
|
||||
// Scan implements the sql.Scanner interface.
|
||||
func (a GenericArray) Scan(src interface{}) error {
|
||||
dpv := reflect.ValueOf(a.A)
|
||||
switch {
|
||||
case dpv.Kind() != reflect.Ptr:
|
||||
return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A)
|
||||
case dpv.IsNil():
|
||||
return fmt.Errorf("pq: destination %T is nil", a.A)
|
||||
}
|
||||
|
||||
dv := dpv.Elem()
|
||||
switch dv.Kind() {
|
||||
case reflect.Slice:
|
||||
case reflect.Array:
|
||||
default:
|
||||
return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A)
|
||||
}
|
||||
|
||||
switch src := src.(type) {
|
||||
case []byte:
|
||||
return a.scanBytes(src, dv)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src), dv)
|
||||
case nil:
|
||||
if dv.Kind() == reflect.Slice {
|
||||
dv.Set(reflect.Zero(dv.Type()))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type())
|
||||
}
|
||||
|
||||
func (a GenericArray) scanBytes(src []byte, dv reflect.Value) error {
|
||||
dtype, assign, del := a.evaluateDestination(dv.Type().Elem())
|
||||
dims, elems, err := parseArray(src, []byte(del))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO allow multidimensional
|
||||
|
||||
if len(dims) > 1 {
|
||||
return fmt.Errorf("pq: scanning from multidimensional ARRAY%s is not implemented",
|
||||
strings.Replace(fmt.Sprint(dims), " ", "][", -1))
|
||||
}
|
||||
|
||||
// Treat a zero-dimensional array like an array with a single dimension of zero.
|
||||
if len(dims) == 0 {
|
||||
dims = append(dims, 0)
|
||||
}
|
||||
|
||||
for i, rt := 0, dv.Type(); i < len(dims); i, rt = i+1, rt.Elem() {
|
||||
switch rt.Kind() {
|
||||
case reflect.Slice:
|
||||
case reflect.Array:
|
||||
if rt.Len() != dims[i] {
|
||||
return fmt.Errorf("pq: cannot convert ARRAY%s to %s",
|
||||
strings.Replace(fmt.Sprint(dims), " ", "][", -1), dv.Type())
|
||||
}
|
||||
default:
|
||||
// TODO handle multidimensional
|
||||
}
|
||||
}
|
||||
|
||||
values := reflect.MakeSlice(reflect.SliceOf(dtype), len(elems), len(elems))
|
||||
for i, e := range elems {
|
||||
if err := assign(e, values.Index(i)); err != nil {
|
||||
return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO handle multidimensional
|
||||
|
||||
switch dv.Kind() {
|
||||
case reflect.Slice:
|
||||
dv.Set(values.Slice(0, dims[0]))
|
||||
case reflect.Array:
|
||||
for i := 0; i < dims[0]; i++ {
|
||||
dv.Index(i).Set(values.Index(i))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver.Valuer interface.
|
||||
func (a GenericArray) Value() (driver.Value, error) {
|
||||
if a.A == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
rv := reflect.ValueOf(a.A)
|
||||
|
||||
switch rv.Kind() {
|
||||
case reflect.Slice:
|
||||
if rv.IsNil() {
|
||||
return nil, nil
|
||||
}
|
||||
case reflect.Array:
|
||||
default:
|
||||
return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A)
|
||||
}
|
||||
|
||||
if n := rv.Len(); n > 0 {
|
||||
// There will be at least two curly brackets, N bytes of values,
|
||||
// and N-1 bytes of delimiters.
|
||||
b := make([]byte, 0, 1+2*n)
|
||||
|
||||
b, _, err := appendArray(b, rv, n)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
return "{}", nil
|
||||
}
|
||||
|
||||
// Int64Array represents a one-dimensional array of the PostgreSQL integer types.
|
||||
type Int64Array []int64
|
||||
|
||||
// Scan implements the sql.Scanner interface.
|
||||
func (a *Int64Array) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case []byte:
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to Int64Array", src)
|
||||
}
|
||||
|
||||
func (a *Int64Array) scanBytes(src []byte) error {
|
||||
elems, err := scanLinearArray(src, []byte{','}, "Int64Array")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(Int64Array, len(elems))
|
||||
for i, v := range elems {
|
||||
if b[i], err = strconv.ParseInt(string(v), 10, 64); err != nil {
|
||||
return fmt.Errorf("pq: parsing array element index %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
*a = b
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver.Valuer interface.
|
||||
func (a Int64Array) Value() (driver.Value, error) {
|
||||
if a == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if n := len(a); n > 0 {
|
||||
// There will be at least two curly brackets, N bytes of values,
|
||||
// and N-1 bytes of delimiters.
|
||||
b := make([]byte, 1, 1+2*n)
|
||||
b[0] = '{'
|
||||
|
||||
b = strconv.AppendInt(b, a[0], 10)
|
||||
for i := 1; i < n; i++ {
|
||||
b = append(b, ',')
|
||||
b = strconv.AppendInt(b, a[i], 10)
|
||||
}
|
||||
|
||||
return string(append(b, '}')), nil
|
||||
}
|
||||
|
||||
return "{}", nil
|
||||
}
|
||||
|
||||
// StringArray represents a one-dimensional array of the PostgreSQL character types.
|
||||
type StringArray []string
|
||||
|
||||
// Scan implements the sql.Scanner interface.
|
||||
func (a *StringArray) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case []byte:
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to StringArray", src)
|
||||
}
|
||||
|
||||
func (a *StringArray) scanBytes(src []byte) error {
|
||||
elems, err := scanLinearArray(src, []byte{','}, "StringArray")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(StringArray, len(elems))
|
||||
for i, v := range elems {
|
||||
if b[i] = string(v); v == nil {
|
||||
return fmt.Errorf("pq: parsing array element index %d: cannot convert nil to string", i)
|
||||
}
|
||||
}
|
||||
*a = b
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver.Valuer interface.
|
||||
func (a StringArray) Value() (driver.Value, error) {
|
||||
if a == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if n := len(a); n > 0 {
|
||||
// There will be at least two curly brackets, 2*N bytes of quotes,
|
||||
// and N-1 bytes of delimiters.
|
||||
b := make([]byte, 1, 1+3*n)
|
||||
b[0] = '{'
|
||||
|
||||
b = appendArrayQuotedBytes(b, []byte(a[0]))
|
||||
for i := 1; i < n; i++ {
|
||||
b = append(b, ',')
|
||||
b = appendArrayQuotedBytes(b, []byte(a[i]))
|
||||
}
|
||||
|
||||
return string(append(b, '}')), nil
|
||||
}
|
||||
|
||||
return "{}", nil
|
||||
}
|
||||
|
||||
// appendArray appends rv to the buffer, returning the extended buffer and
|
||||
// the delimiter used between elements.
|
||||
//
|
||||
// It panics when n <= 0 or rv's Kind is not reflect.Array nor reflect.Slice.
|
||||
func appendArray(b []byte, rv reflect.Value, n int) ([]byte, string, error) {
|
||||
var del string
|
||||
var err error
|
||||
|
||||
b = append(b, '{')
|
||||
|
||||
if b, del, err = appendArrayElement(b, rv.Index(0)); err != nil {
|
||||
return b, del, err
|
||||
}
|
||||
|
||||
for i := 1; i < n; i++ {
|
||||
b = append(b, del...)
|
||||
if b, del, err = appendArrayElement(b, rv.Index(i)); err != nil {
|
||||
return b, del, err
|
||||
}
|
||||
}
|
||||
|
||||
return append(b, '}'), del, nil
|
||||
}
|
||||
|
||||
// appendArrayElement appends rv to the buffer, returning the extended buffer
|
||||
// and the delimiter to use before the next element.
|
||||
//
|
||||
// When rv's Kind is neither reflect.Array nor reflect.Slice, it is converted
|
||||
// using driver.DefaultParameterConverter and the resulting []byte or string
|
||||
// is double-quoted.
|
||||
//
|
||||
// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO
|
||||
func appendArrayElement(b []byte, rv reflect.Value) ([]byte, string, error) {
|
||||
if k := rv.Kind(); k == reflect.Array || k == reflect.Slice {
|
||||
if t := rv.Type(); t != typeByteSlice && !t.Implements(typeDriverValuer) {
|
||||
if n := rv.Len(); n > 0 {
|
||||
return appendArray(b, rv, n)
|
||||
}
|
||||
|
||||
return b, "", nil
|
||||
}
|
||||
}
|
||||
|
||||
var del = ","
|
||||
var err error
|
||||
var iv interface{} = rv.Interface()
|
||||
|
||||
if ad, ok := iv.(ArrayDelimiter); ok {
|
||||
del = ad.ArrayDelimiter()
|
||||
}
|
||||
|
||||
if iv, err = driver.DefaultParameterConverter.ConvertValue(iv); err != nil {
|
||||
return b, del, err
|
||||
}
|
||||
|
||||
switch v := iv.(type) {
|
||||
case nil:
|
||||
return append(b, "NULL"...), del, nil
|
||||
case []byte:
|
||||
return appendArrayQuotedBytes(b, v), del, nil
|
||||
case string:
|
||||
return appendArrayQuotedBytes(b, []byte(v)), del, nil
|
||||
}
|
||||
|
||||
b, err = appendValue(b, iv)
|
||||
return b, del, err
|
||||
}
|
||||
|
||||
func appendArrayQuotedBytes(b, v []byte) []byte {
|
||||
b = append(b, '"')
|
||||
for {
|
||||
i := bytes.IndexAny(v, `"\`)
|
||||
if i < 0 {
|
||||
b = append(b, v...)
|
||||
break
|
||||
}
|
||||
if i > 0 {
|
||||
b = append(b, v[:i]...)
|
||||
}
|
||||
b = append(b, '\\', v[i])
|
||||
v = v[i+1:]
|
||||
}
|
||||
return append(b, '"')
|
||||
}
|
||||
|
||||
func appendValue(b []byte, v driver.Value) ([]byte, error) {
|
||||
return append(b, encode(nil, v, 0)...), nil
|
||||
}
|
||||
|
||||
// parseArray extracts the dimensions and elements of an array represented in
|
||||
// text format. Only representations emitted by the backend are supported.
|
||||
// Notably, whitespace around brackets and delimiters is significant, and NULL
|
||||
// is case-sensitive.
|
||||
//
|
||||
// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO
|
||||
func parseArray(src, del []byte) (dims []int, elems [][]byte, err error) {
|
||||
var depth, i int
|
||||
|
||||
if len(src) < 1 || src[0] != '{' {
|
||||
return nil, nil, fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '{', 0)
|
||||
}
|
||||
|
||||
Open:
|
||||
for i < len(src) {
|
||||
switch src[i] {
|
||||
case '{':
|
||||
depth++
|
||||
i++
|
||||
case '}':
|
||||
elems = make([][]byte, 0)
|
||||
goto Close
|
||||
default:
|
||||
break Open
|
||||
}
|
||||
}
|
||||
dims = make([]int, i)
|
||||
|
||||
Element:
|
||||
for i < len(src) {
|
||||
switch src[i] {
|
||||
case '{':
|
||||
if depth == len(dims) {
|
||||
break Element
|
||||
}
|
||||
depth++
|
||||
dims[depth-1] = 0
|
||||
i++
|
||||
case '"':
|
||||
var elem = []byte{}
|
||||
var escape bool
|
||||
for i++; i < len(src); i++ {
|
||||
if escape {
|
||||
elem = append(elem, src[i])
|
||||
escape = false
|
||||
} else {
|
||||
switch src[i] {
|
||||
default:
|
||||
elem = append(elem, src[i])
|
||||
case '\\':
|
||||
escape = true
|
||||
case '"':
|
||||
elems = append(elems, elem)
|
||||
i++
|
||||
break Element
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
for start := i; i < len(src); i++ {
|
||||
if bytes.HasPrefix(src[i:], del) || src[i] == '}' {
|
||||
elem := src[start:i]
|
||||
if len(elem) == 0 {
|
||||
return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
|
||||
}
|
||||
if bytes.Equal(elem, []byte("NULL")) {
|
||||
elem = nil
|
||||
}
|
||||
elems = append(elems, elem)
|
||||
break Element
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i < len(src) {
|
||||
if bytes.HasPrefix(src[i:], del) && depth > 0 {
|
||||
dims[depth-1]++
|
||||
i += len(del)
|
||||
goto Element
|
||||
} else if src[i] == '}' && depth > 0 {
|
||||
dims[depth-1]++
|
||||
depth--
|
||||
i++
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
|
||||
}
|
||||
}
|
||||
|
||||
Close:
|
||||
for i < len(src) {
|
||||
if src[i] == '}' && depth > 0 {
|
||||
depth--
|
||||
i++
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i)
|
||||
}
|
||||
}
|
||||
if depth > 0 {
|
||||
err = fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '}', i)
|
||||
}
|
||||
if err == nil {
|
||||
for _, d := range dims {
|
||||
if (len(elems) % d) != 0 {
|
||||
err = fmt.Errorf("pq: multidimensional arrays must have elements with matching dimensions")
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func scanLinearArray(src, del []byte, typ string) (elems [][]byte, err error) {
|
||||
dims, elems, err := parseArray(src, del)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(dims) > 1 {
|
||||
return nil, fmt.Errorf("pq: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), typ)
|
||||
}
|
||||
return elems, err
|
||||
}
|
||||
91
vendor/github.com/lib/pq/buf.go
generated
vendored
Normal file
91
vendor/github.com/lib/pq/buf.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package pq
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/lib/pq/oid"
|
||||
)
|
||||
|
||||
type readBuf []byte
|
||||
|
||||
func (b *readBuf) int32() (n int) {
|
||||
n = int(int32(binary.BigEndian.Uint32(*b)))
|
||||
*b = (*b)[4:]
|
||||
return
|
||||
}
|
||||
|
||||
func (b *readBuf) oid() (n oid.Oid) {
|
||||
n = oid.Oid(binary.BigEndian.Uint32(*b))
|
||||
*b = (*b)[4:]
|
||||
return
|
||||
}
|
||||
|
||||
// N.B: this is actually an unsigned 16-bit integer, unlike int32
|
||||
func (b *readBuf) int16() (n int) {
|
||||
n = int(binary.BigEndian.Uint16(*b))
|
||||
*b = (*b)[2:]
|
||||
return
|
||||
}
|
||||
|
||||
func (b *readBuf) string() string {
|
||||
i := bytes.IndexByte(*b, 0)
|
||||
if i < 0 {
|
||||
errorf("invalid message format; expected string terminator")
|
||||
}
|
||||
s := (*b)[:i]
|
||||
*b = (*b)[i+1:]
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func (b *readBuf) next(n int) (v []byte) {
|
||||
v = (*b)[:n]
|
||||
*b = (*b)[n:]
|
||||
return
|
||||
}
|
||||
|
||||
func (b *readBuf) byte() byte {
|
||||
return b.next(1)[0]
|
||||
}
|
||||
|
||||
type writeBuf struct {
|
||||
buf []byte
|
||||
pos int
|
||||
}
|
||||
|
||||
func (b *writeBuf) int32(n int) {
|
||||
x := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(x, uint32(n))
|
||||
b.buf = append(b.buf, x...)
|
||||
}
|
||||
|
||||
func (b *writeBuf) int16(n int) {
|
||||
x := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(x, uint16(n))
|
||||
b.buf = append(b.buf, x...)
|
||||
}
|
||||
|
||||
func (b *writeBuf) string(s string) {
|
||||
b.buf = append(append(b.buf, s...), '\000')
|
||||
}
|
||||
|
||||
func (b *writeBuf) byte(c byte) {
|
||||
b.buf = append(b.buf, c)
|
||||
}
|
||||
|
||||
func (b *writeBuf) bytes(v []byte) {
|
||||
b.buf = append(b.buf, v...)
|
||||
}
|
||||
|
||||
func (b *writeBuf) wrap() []byte {
|
||||
p := b.buf[b.pos:]
|
||||
binary.BigEndian.PutUint32(p, uint32(len(p)))
|
||||
return b.buf
|
||||
}
|
||||
|
||||
func (b *writeBuf) next(c byte) {
|
||||
p := b.buf[b.pos:]
|
||||
binary.BigEndian.PutUint32(p, uint32(len(p)))
|
||||
b.pos = len(b.buf) + 1
|
||||
b.buf = append(b.buf, c, 0, 0, 0, 0)
|
||||
}
|
||||
1923
vendor/github.com/lib/pq/conn.go
generated
vendored
Normal file
1923
vendor/github.com/lib/pq/conn.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user